-*.a
-*.aux
-*.bc
-*.boot
-*.bz2
-*.cmi
-*.cmo
-*.cmx
-*.cp
-*.cps
-*.d
-*.dSYM
-*.def
-*.diff
-*.dll
-*.dylib
-*.elc
-*.epub
-*.exe
-*.fn
-*.html
-*.kdev4
-*.ky
-*.ll
-*.llvm
-*.log
-*.o
-*.orig
-*.out
-*.patch
-*.pdb
-*.pdf
-*.pg
-*.pot
-*.pyc
-*.rej
-*.rlib
-*.rustc
-*.so
-*.swo
-*.swp
-*.tmp
-*.toc
-*.tp
-*.vr
-*.x86
*~
.#*
.DS_Store
[submodule "src/tools/lldb"]
path = src/tools/lldb
url = https://github.com/rust-lang-nursery/lldb/
- branch = rust-release-70
+ branch = rust-release-80-v1
[submodule "src/tools/clang"]
path = src/tools/clang
url = https://github.com/rust-lang-nursery/clang/
- branch = release_70
+ branch = rust-release-80-v1
[breaking-tools-built-with-the-compiler]: #breaking-tools-built-with-the-compiler
Rust's build system builds a number of tools that make use of the
-internals of the compiler. This includes clippy,
+internals of the compiler. This includes
+[Clippy](https://github.com/rust-lang-nursery/rust-clippy),
[RLS](https://github.com/rust-lang-nursery/rls) and
[rustfmt](https://github.com/rust-lang-nursery/rustfmt). If these tools
break because of your changes, you may run into a sort of "chicken and egg"
--- /dev/null
+*.a
+*.aux
+*.bc
+*.boot
+*.bz2
+*.cmi
+*.cmo
+*.cmx
+*.cp
+*.cps
+*.d
+*.dSYM
+*.def
+*.diff
+*.dll
+*.dylib
+*.elc
+*.epub
+*.exe
+*.fn
+*.html
+*.kdev4
+*.ky
+*.ll
+*.llvm
+*.log
+*.o
+*.orig
+*.out
+*.patch
+*.pdb
+*.pdf
+*.pg
+*.pot
+*.pyc
+*.rej
+*.rlib
+*.rustc
+*.so
+*.swo
+*.swp
+*.tmp
+*.toc
+*.tp
+*.vr
+*.x86
dependencies = [
"compiler_builtins 0.0.0",
"core 0.0.0",
- "rand 0.4.3 (registry+https://github.com/rust-lang/crates.io-index)",
+ "rand 0.5.4 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
"libc 0.2.43 (registry+https://github.com/rust-lang/crates.io-index)",
"log 0.4.4 (registry+https://github.com/rust-lang/crates.io-index)",
"miow 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)",
- "regex 0.2.11 (registry+https://github.com/rust-lang/crates.io-index)",
+ "regex 1.0.4 (registry+https://github.com/rust-lang/crates.io-index)",
"rustfix 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)",
"serde 1.0.75 (registry+https://github.com/rust-lang/crates.io-index)",
"serde_derive 1.0.75 (registry+https://github.com/rust-lang/crates.io-index)",
name = "core"
version = "0.0.0"
dependencies = [
- "rand 0.4.3 (registry+https://github.com/rust-lang/crates.io-index)",
+ "rand 0.5.4 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "linkchecker"
version = "0.1.0"
+[[package]]
+name = "lock_api"
+version = "0.1.3"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+dependencies = [
+ "owning_ref 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)",
+ "scopeguard 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)",
+]
+
[[package]]
name = "log"
version = "0.3.9"
"libc 0.2.43 (registry+https://github.com/rust-lang/crates.io-index)",
]
+[[package]]
+name = "memmap"
+version = "0.6.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+dependencies = [
+ "libc 0.2.43 (registry+https://github.com/rust-lang/crates.io-index)",
+ "winapi 0.3.5 (registry+https://github.com/rust-lang/crates.io-index)",
+]
+
[[package]]
name = "memoffset"
version = "0.2.1"
"parking_lot_core 0.2.14 (registry+https://github.com/rust-lang/crates.io-index)",
]
+[[package]]
+name = "parking_lot"
+version = "0.6.4"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+dependencies = [
+ "lock_api 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)",
+ "parking_lot_core 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)",
+]
+
[[package]]
name = "parking_lot_core"
version = "0.2.14"
"winapi 0.3.5 (registry+https://github.com/rust-lang/crates.io-index)",
]
+[[package]]
+name = "parking_lot_core"
+version = "0.3.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+dependencies = [
+ "libc 0.2.43 (registry+https://github.com/rust-lang/crates.io-index)",
+ "rand 0.5.4 (registry+https://github.com/rust-lang/crates.io-index)",
+ "smallvec 0.6.5 (registry+https://github.com/rust-lang/crates.io-index)",
+ "winapi 0.3.5 (registry+https://github.com/rust-lang/crates.io-index)",
+]
+
[[package]]
name = "percent-encoding"
version = "1.0.1"
[[package]]
name = "racer"
-version = "2.1.4"
+version = "2.1.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"bitflags 1.0.4 (registry+https://github.com/rust-lang/crates.io-index)",
"lazy_static 1.1.0 (registry+https://github.com/rust-lang/crates.io-index)",
"log 0.4.4 (registry+https://github.com/rust-lang/crates.io-index)",
"rls-span 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)",
- "rustc-ap-syntax 218.0.0 (registry+https://github.com/rust-lang/crates.io-index)",
+ "rustc-ap-syntax 237.0.0 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
"log 0.4.4 (registry+https://github.com/rust-lang/crates.io-index)",
"num_cpus 1.8.0 (registry+https://github.com/rust-lang/crates.io-index)",
"ordslice 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)",
- "racer 2.1.4 (registry+https://github.com/rust-lang/crates.io-index)",
+ "racer 2.1.5 (registry+https://github.com/rust-lang/crates.io-index)",
"rayon 1.0.1 (registry+https://github.com/rust-lang/crates.io-index)",
"regex 1.0.4 (registry+https://github.com/rust-lang/crates.io-index)",
"rls-analysis 0.16.0 (registry+https://github.com/rust-lang/crates.io-index)",
"rls-rustc 0.5.0 (registry+https://github.com/rust-lang/crates.io-index)",
"rls-span 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)",
"rls-vfs 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)",
+ "rustc-serialize 0.3.24 (registry+https://github.com/rust-lang/crates.io-index)",
"rustc-workspace-hack 1.0.0",
- "rustfmt-nightly 0.99.2",
+ "rustfmt-nightly 0.99.4",
"serde 1.0.75 (registry+https://github.com/rust-lang/crates.io-index)",
"serde_derive 1.0.75 (registry+https://github.com/rust-lang/crates.io-index)",
"serde_json 1.0.26 (registry+https://github.com/rust-lang/crates.io-index)",
"jobserver 0.1.11 (registry+https://github.com/rust-lang/crates.io-index)",
"lazy_static 1.1.0 (registry+https://github.com/rust-lang/crates.io-index)",
"log 0.4.4 (registry+https://github.com/rust-lang/crates.io-index)",
- "parking_lot 0.5.5 (registry+https://github.com/rust-lang/crates.io-index)",
+ "parking_lot 0.6.4 (registry+https://github.com/rust-lang/crates.io-index)",
"polonius-engine 0.5.0 (registry+https://github.com/rust-lang/crates.io-index)",
"proc_macro 0.0.0",
"rustc-rayon 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)",
[[package]]
name = "rustc-ap-arena"
-version = "218.0.0"
+version = "237.0.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
- "rustc-ap-rustc_data_structures 218.0.0 (registry+https://github.com/rust-lang/crates.io-index)",
+ "rustc-ap-rustc_data_structures 237.0.0 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "rustc-ap-rustc_cratesio_shim"
-version = "218.0.0"
+version = "237.0.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"bitflags 1.0.4 (registry+https://github.com/rust-lang/crates.io-index)",
[[package]]
name = "rustc-ap-rustc_data_structures"
-version = "218.0.0"
+version = "237.0.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"cfg-if 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)",
"log 0.4.4 (registry+https://github.com/rust-lang/crates.io-index)",
"parking_lot 0.5.5 (registry+https://github.com/rust-lang/crates.io-index)",
"parking_lot_core 0.2.14 (registry+https://github.com/rust-lang/crates.io-index)",
- "rustc-ap-rustc_cratesio_shim 218.0.0 (registry+https://github.com/rust-lang/crates.io-index)",
- "rustc-ap-serialize 218.0.0 (registry+https://github.com/rust-lang/crates.io-index)",
+ "rustc-ap-rustc_cratesio_shim 237.0.0 (registry+https://github.com/rust-lang/crates.io-index)",
+ "rustc-ap-serialize 237.0.0 (registry+https://github.com/rust-lang/crates.io-index)",
"rustc-hash 1.0.1 (registry+https://github.com/rust-lang/crates.io-index)",
"rustc-rayon 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)",
"rustc-rayon-core 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)",
+ "smallvec 0.6.5 (registry+https://github.com/rust-lang/crates.io-index)",
"stable_deref_trait 1.1.0 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "rustc-ap-rustc_errors"
-version = "218.0.0"
+version = "237.0.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"atty 0.2.11 (registry+https://github.com/rust-lang/crates.io-index)",
- "rustc-ap-rustc_data_structures 218.0.0 (registry+https://github.com/rust-lang/crates.io-index)",
- "rustc-ap-serialize 218.0.0 (registry+https://github.com/rust-lang/crates.io-index)",
- "rustc-ap-syntax_pos 218.0.0 (registry+https://github.com/rust-lang/crates.io-index)",
+ "rustc-ap-rustc_data_structures 237.0.0 (registry+https://github.com/rust-lang/crates.io-index)",
+ "rustc-ap-serialize 237.0.0 (registry+https://github.com/rust-lang/crates.io-index)",
+ "rustc-ap-syntax_pos 237.0.0 (registry+https://github.com/rust-lang/crates.io-index)",
"termcolor 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)",
"unicode-width 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "rustc-ap-rustc_target"
-version = "218.0.0"
+version = "237.0.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"bitflags 1.0.4 (registry+https://github.com/rust-lang/crates.io-index)",
"log 0.4.4 (registry+https://github.com/rust-lang/crates.io-index)",
- "rustc-ap-rustc_cratesio_shim 218.0.0 (registry+https://github.com/rust-lang/crates.io-index)",
- "rustc-ap-serialize 218.0.0 (registry+https://github.com/rust-lang/crates.io-index)",
+ "rustc-ap-rustc_cratesio_shim 237.0.0 (registry+https://github.com/rust-lang/crates.io-index)",
+ "rustc-ap-serialize 237.0.0 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "rustc-ap-serialize"
-version = "218.0.0"
+version = "237.0.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
+dependencies = [
+ "smallvec 0.6.5 (registry+https://github.com/rust-lang/crates.io-index)",
+]
[[package]]
name = "rustc-ap-syntax"
-version = "218.0.0"
+version = "237.0.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"bitflags 1.0.4 (registry+https://github.com/rust-lang/crates.io-index)",
"log 0.4.4 (registry+https://github.com/rust-lang/crates.io-index)",
- "rustc-ap-rustc_data_structures 218.0.0 (registry+https://github.com/rust-lang/crates.io-index)",
- "rustc-ap-rustc_errors 218.0.0 (registry+https://github.com/rust-lang/crates.io-index)",
- "rustc-ap-rustc_target 218.0.0 (registry+https://github.com/rust-lang/crates.io-index)",
- "rustc-ap-serialize 218.0.0 (registry+https://github.com/rust-lang/crates.io-index)",
- "rustc-ap-syntax_pos 218.0.0 (registry+https://github.com/rust-lang/crates.io-index)",
+ "rustc-ap-rustc_data_structures 237.0.0 (registry+https://github.com/rust-lang/crates.io-index)",
+ "rustc-ap-rustc_errors 237.0.0 (registry+https://github.com/rust-lang/crates.io-index)",
+ "rustc-ap-rustc_target 237.0.0 (registry+https://github.com/rust-lang/crates.io-index)",
+ "rustc-ap-serialize 237.0.0 (registry+https://github.com/rust-lang/crates.io-index)",
+ "rustc-ap-syntax_pos 237.0.0 (registry+https://github.com/rust-lang/crates.io-index)",
"scoped-tls 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)",
+ "smallvec 0.6.5 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "rustc-ap-syntax_pos"
-version = "218.0.0"
+version = "237.0.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"cfg-if 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)",
- "rustc-ap-arena 218.0.0 (registry+https://github.com/rust-lang/crates.io-index)",
- "rustc-ap-rustc_data_structures 218.0.0 (registry+https://github.com/rust-lang/crates.io-index)",
- "rustc-ap-serialize 218.0.0 (registry+https://github.com/rust-lang/crates.io-index)",
+ "rustc-ap-arena 237.0.0 (registry+https://github.com/rust-lang/crates.io-index)",
+ "rustc-ap-rustc_data_structures 237.0.0 (registry+https://github.com/rust-lang/crates.io-index)",
+ "rustc-ap-serialize 237.0.0 (registry+https://github.com/rust-lang/crates.io-index)",
"scoped-tls 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)",
"unicode-width 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)",
]
version = "0.0.0"
dependencies = [
"cc 1.0.22 (registry+https://github.com/rust-lang/crates.io-index)",
+ "memmap 0.6.2 (registry+https://github.com/rust-lang/crates.io-index)",
"num_cpus 1.8.0 (registry+https://github.com/rust-lang/crates.io-index)",
"rustc-demangle 0.1.9 (registry+https://github.com/rust-lang/crates.io-index)",
"rustc_llvm 0.0.0",
dependencies = [
"bitflags 1.0.4 (registry+https://github.com/rust-lang/crates.io-index)",
"log 0.4.4 (registry+https://github.com/rust-lang/crates.io-index)",
+ "unicode-width 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
"cfg-if 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)",
"ena 0.9.3 (registry+https://github.com/rust-lang/crates.io-index)",
"log 0.4.4 (registry+https://github.com/rust-lang/crates.io-index)",
- "parking_lot 0.5.5 (registry+https://github.com/rust-lang/crates.io-index)",
+ "parking_lot 0.6.4 (registry+https://github.com/rust-lang/crates.io-index)",
"parking_lot_core 0.2.14 (registry+https://github.com/rust-lang/crates.io-index)",
"rustc-hash 1.0.1 (registry+https://github.com/rust-lang/crates.io-index)",
"rustc-rayon 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)",
version = "0.0.0"
dependencies = [
"atty 0.2.11 (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",
- "termcolor 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)",
+ "termcolor 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)",
"unicode-width 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)",
]
dependencies = [
"graphviz 0.0.0",
"log 0.4.4 (registry+https://github.com/rust-lang/crates.io-index)",
- "rand 0.4.3 (registry+https://github.com/rust-lang/crates.io-index)",
+ "rand 0.5.4 (registry+https://github.com/rust-lang/crates.io-index)",
"rustc 0.0.0",
"rustc_data_structures 0.0.0",
"rustc_fs_util 0.0.0",
[[package]]
name = "rustfmt-nightly"
-version = "0.99.2"
+version = "0.99.4"
dependencies = [
"assert_cli 0.6.2 (registry+https://github.com/rust-lang/crates.io-index)",
"cargo_metadata 0.6.0 (registry+https://github.com/rust-lang/crates.io-index)",
"lazy_static 1.1.0 (registry+https://github.com/rust-lang/crates.io-index)",
"log 0.4.4 (registry+https://github.com/rust-lang/crates.io-index)",
"regex 1.0.4 (registry+https://github.com/rust-lang/crates.io-index)",
- "rustc-ap-rustc_target 218.0.0 (registry+https://github.com/rust-lang/crates.io-index)",
- "rustc-ap-syntax 218.0.0 (registry+https://github.com/rust-lang/crates.io-index)",
- "rustc-ap-syntax_pos 218.0.0 (registry+https://github.com/rust-lang/crates.io-index)",
+ "rustc-ap-rustc_target 237.0.0 (registry+https://github.com/rust-lang/crates.io-index)",
+ "rustc-ap-syntax 237.0.0 (registry+https://github.com/rust-lang/crates.io-index)",
+ "rustc-ap-syntax_pos 237.0.0 (registry+https://github.com/rust-lang/crates.io-index)",
"serde 1.0.75 (registry+https://github.com/rust-lang/crates.io-index)",
"serde_derive 1.0.75 (registry+https://github.com/rust-lang/crates.io-index)",
"serde_json 1.0.26 (registry+https://github.com/rust-lang/crates.io-index)",
"panic_abort 0.0.0",
"panic_unwind 0.0.0",
"profiler_builtins 0.0.0",
- "rand 0.4.3 (registry+https://github.com/rust-lang/crates.io-index)",
+ "rand 0.5.4 (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.0.0"
dependencies = [
"fmt_macros 0.0.0",
+ "log 0.4.4 (registry+https://github.com/rust-lang/crates.io-index)",
"proc_macro 0.0.0",
"rustc_data_structures 0.0.0",
"rustc_errors 0.0.0",
"checksum libgit2-sys 0.7.7 (registry+https://github.com/rust-lang/crates.io-index)" = "6ab62b46003ba97701554631fa570d9f7e7947e2480ae3d941e555a54a2c0f05"
"checksum libssh2-sys 0.2.10 (registry+https://github.com/rust-lang/crates.io-index)" = "10dbc0957a27626444f5a3f523e6b97a70c3d702999bf1c7161cfbe7a25a9368"
"checksum libz-sys 1.0.20 (registry+https://github.com/rust-lang/crates.io-index)" = "f5f9aba969b3c45fe9c94bec65895868a9ceca9a600699f4054b75747a19c7c6"
+"checksum lock_api 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)" = "949826a5ccf18c1b3a7c3d57692778d21768b79e46eb9dd07bfc4c2160036c54"
"checksum log 0.3.9 (registry+https://github.com/rust-lang/crates.io-index)" = "e19e8d5c34a3e0e2223db8e060f9e8264aeeb5c5fc64a4ee9965c062211c024b"
"checksum log 0.4.4 (registry+https://github.com/rust-lang/crates.io-index)" = "cba860f648db8e6f269df990180c2217f333472b4a6e901e97446858487971e2"
"checksum log_settings 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)" = "19af41f0565d7c19b2058153ad0b42d4d5ce89ec4dbf06ed6741114a8b63e7cd"
"checksum matches 0.1.8 (registry+https://github.com/rust-lang/crates.io-index)" = "7ffc5c5338469d4d3ea17d269fa8ea3512ad247247c30bd2df69e68309ed0a08"
"checksum mdbook 0.1.7 (registry+https://github.com/rust-lang/crates.io-index)" = "90b5a8d7e341ceee5db3882a06078d42661ddcfa2b3687319cc5da76ec4e782f"
"checksum memchr 2.0.2 (registry+https://github.com/rust-lang/crates.io-index)" = "a3b4142ab8738a78c51896f704f83c11df047ff1bda9a92a661aa6361552d93d"
+"checksum memmap 0.6.2 (registry+https://github.com/rust-lang/crates.io-index)" = "e2ffa2c986de11a9df78620c01eeaaf27d94d3ff02bf81bfcca953102dd0c6ff"
"checksum memoffset 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)" = "0f9dc261e2b62d7a622bf416ea3c5245cdd5d9a7fcc428c0d06804dfce1775b3"
"checksum minifier 0.0.19 (registry+https://github.com/rust-lang/crates.io-index)" = "9908ed7c62f990c21ab41fdca53a864a3ada0da69d8729c4de727b397e27bc11"
"checksum miniz-sys 0.1.10 (registry+https://github.com/rust-lang/crates.io-index)" = "609ce024854aeb19a0ef7567d348aaa5a746b32fb72e336df7fcc16869d7e2b4"
"checksum ordslice 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)" = "dd20eec3dbe4376829cb7d80ae6ac45e0a766831dca50202ff2d40db46a8a024"
"checksum owning_ref 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)" = "cdf84f41639e037b484f93433aa3897863b561ed65c6e59c7073d7c561710f37"
"checksum parking_lot 0.5.5 (registry+https://github.com/rust-lang/crates.io-index)" = "d4d05f1349491390b1730afba60bb20d55761bef489a954546b58b4b34e1e2ac"
+"checksum parking_lot 0.6.4 (registry+https://github.com/rust-lang/crates.io-index)" = "f0802bff09003b291ba756dc7e79313e51cc31667e94afbe847def490424cde5"
"checksum parking_lot_core 0.2.14 (registry+https://github.com/rust-lang/crates.io-index)" = "4db1a8ccf734a7bce794cc19b3df06ed87ab2f3907036b693c68f56b4d4537fa"
+"checksum parking_lot_core 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)" = "06a2b6aae052309c2fd2161ef58f5067bc17bb758377a0de9d4b279d603fdd8a"
"checksum percent-encoding 1.0.1 (registry+https://github.com/rust-lang/crates.io-index)" = "31010dd2e1ac33d5b46a5b413495239882813e0369f8ed8a5e266f173602f831"
"checksum pest 1.0.6 (registry+https://github.com/rust-lang/crates.io-index)" = "0fce5d8b5cc33983fc74f78ad552b5522ab41442c4ca91606e4236eb4b5ceefc"
"checksum pest_derive 1.0.7 (registry+https://github.com/rust-lang/crates.io-index)" = "ab94faafeb93f4c5e3ce81ca0e5a779529a602ad5d09ae6d21996bfb8b6a52bf"
"checksum quote 0.3.15 (registry+https://github.com/rust-lang/crates.io-index)" = "7a6e920b65c65f10b2ae65c831a81a073a89edd28c7cce89475bff467ab4167a"
"checksum quote 0.5.2 (registry+https://github.com/rust-lang/crates.io-index)" = "9949cfe66888ffe1d53e6ec9d9f3b70714083854be20fd5e271b232a017401e8"
"checksum quote 0.6.8 (registry+https://github.com/rust-lang/crates.io-index)" = "dd636425967c33af890042c483632d33fa7a18f19ad1d7ea72e8998c6ef8dea5"
-"checksum racer 2.1.4 (registry+https://github.com/rust-lang/crates.io-index)" = "dcbc5ababaffee8d8f34910f925287c8f716b1ead48561c4278a152d08264f7c"
+"checksum racer 2.1.5 (registry+https://github.com/rust-lang/crates.io-index)" = "1e4bc3847329b20ff5ba56c298938c179ae9911af15c9c10553f683b65164533"
"checksum rand 0.4.3 (registry+https://github.com/rust-lang/crates.io-index)" = "8356f47b32624fef5b3301c1be97e5944ecdd595409cc5da11d05f211db6cfbd"
"checksum rand 0.5.4 (registry+https://github.com/rust-lang/crates.io-index)" = "12397506224b2f93e6664ffc4f664b29be8208e5157d3d90b44f09b5fae470ea"
"checksum rand_core 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)" = "edecf0f94da5551fc9b492093e30b041a891657db7940ee221f9d2f66e82eef2"
"checksum rls-rustc 0.5.0 (registry+https://github.com/rust-lang/crates.io-index)" = "2f9dba7390427aefa953608429701e3665192ca810ba8ae09301e001b7c7bed0"
"checksum rls-span 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "5d7c7046dc6a92f2ae02ed302746db4382e75131b9ce20ce967259f6b5867a6a"
"checksum rls-vfs 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)" = "ecbc8541b4c341d6271eae10f869dd9d36db871afe184f5b6f9bffbd6ed0373f"
-"checksum rustc-ap-arena 218.0.0 (registry+https://github.com/rust-lang/crates.io-index)" = "6e905467184ce31ccdbd33ac33b9ba377f8cc7aefb340a733ab7e5efe34cddda"
-"checksum rustc-ap-rustc_cratesio_shim 218.0.0 (registry+https://github.com/rust-lang/crates.io-index)" = "c2a1a45817e78d0c1e2800fb933c526747ef2c5ee4b2dc0946e0c2d901329b88"
-"checksum rustc-ap-rustc_data_structures 218.0.0 (registry+https://github.com/rust-lang/crates.io-index)" = "17b4e9e5588883318e0e58bb7ea7cde2a66eaca55b25e32908f0982365988657"
-"checksum rustc-ap-rustc_errors 218.0.0 (registry+https://github.com/rust-lang/crates.io-index)" = "1d233c0d9beda42a52d329a5df865c8f20c64773d2ab7aa6b4ae4248bacf3188"
-"checksum rustc-ap-rustc_target 218.0.0 (registry+https://github.com/rust-lang/crates.io-index)" = "eec0bc13feecf9e88e39439b24b4b3ca54db8caf12fb7172d0c430451c8b377c"
-"checksum rustc-ap-serialize 218.0.0 (registry+https://github.com/rust-lang/crates.io-index)" = "ffcfb1102cd7cbf5f25c008a00f7253427af9dfac8989ede48c19bd47f556893"
-"checksum rustc-ap-syntax 218.0.0 (registry+https://github.com/rust-lang/crates.io-index)" = "3a2ca0ef078a735c81a0d33589e04148dcf41f80ee7ebe30e72904a631b7c669"
-"checksum rustc-ap-syntax_pos 218.0.0 (registry+https://github.com/rust-lang/crates.io-index)" = "b1bbd31d1bbc7210983c3bbbcb9ee35bac443c6c899f979b8114e58bb7101c28"
+"checksum rustc-ap-arena 237.0.0 (registry+https://github.com/rust-lang/crates.io-index)" = "2d24c8b3c1437fad023cb9472381216a1d41d82dbb2d2e6c7858bd6f50317719"
+"checksum rustc-ap-rustc_cratesio_shim 237.0.0 (registry+https://github.com/rust-lang/crates.io-index)" = "9c5b02c76cd1ee4e9c97c8228701796d6b7431e8f100dea2d8af1d6c2c2bad56"
+"checksum rustc-ap-rustc_data_structures 237.0.0 (registry+https://github.com/rust-lang/crates.io-index)" = "4076388154497fb9a007e3badd78e415402a5594111cd6bc7ce1420dd1b1818b"
+"checksum rustc-ap-rustc_errors 237.0.0 (registry+https://github.com/rust-lang/crates.io-index)" = "c6c11e4789cbc276ceaa87d326c234b1a2d1e0fe6017b88a8a25903200060acb"
+"checksum rustc-ap-rustc_target 237.0.0 (registry+https://github.com/rust-lang/crates.io-index)" = "25f711bb152b9d7cdd69410cfe6d99aeb1409c959e0fdf3c8ca4d220e568aa52"
+"checksum rustc-ap-serialize 237.0.0 (registry+https://github.com/rust-lang/crates.io-index)" = "57638db658d4942d3f30a12566836f9a67a636ed8002c8cae1c9231214e39929"
+"checksum rustc-ap-syntax 237.0.0 (registry+https://github.com/rust-lang/crates.io-index)" = "d6dbcf07abf7a9957dce8d34353d55dfb4cd882153181f24349f4690facb58f0"
+"checksum rustc-ap-syntax_pos 237.0.0 (registry+https://github.com/rust-lang/crates.io-index)" = "0915cb5e166cabe588a129dec2d47357077e96fb1f9b57318fbe217eac4ce508"
"checksum rustc-demangle 0.1.9 (registry+https://github.com/rust-lang/crates.io-index)" = "bcfe5b13211b4d78e5c2cadfebd7769197d95c639c35a50057eb4c05de811395"
"checksum rustc-hash 1.0.1 (registry+https://github.com/rust-lang/crates.io-index)" = "7540fc8b0c49f096ee9c961cda096467dce8084bec6bdca2fc83895fd9b28cb8"
"checksum rustc-rayon 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "8c6d5a683c6ba4ed37959097e88d71c9e8e26659a3cb5be8b389078e7ad45306"
let mut dylib_path = bootstrap::util::dylib_path();
dylib_path.insert(0, PathBuf::from(libdir.clone()));
+ //FIXME(misdreavus): once stdsimd uses cfg(rustdoc) instead of cfg(dox), remove the `--cfg dox`
+ //arguments here
let mut cmd = Command::new(rustdoc);
cmd.args(&args)
.arg("--cfg")
t!(fs::create_dir_all(&backends_dst));
builder.cp_r(&backends_src, &backends_dst);
+ // Copy libLLVM.so to the lib dir as well, if needed. While not
+ // technically needed by rustc itself it's needed by lots of other
+ // components like the llvm tools and LLD. LLD is included below and
+ // tools/LLDB come later, so let's just throw it in the rustc
+ // component for now.
+ maybe_install_llvm_dylib(builder, host, image);
+
// Copy over lld if it's there
if builder.config.lld_enabled {
let exe = exe("rust-lld", &compiler.host);
let src_libdir = builder
.llvm_out(target)
.join("lib");
+ let dst_libdir = image.join("lib/rustlib").join(&*target).join("lib");
+ t!(fs::create_dir_all(&dst_libdir));
+
+ if target.contains("apple-darwin") {
+ let llvm_dylib_path = src_libdir.join("libLLVM.dylib");
+ if llvm_dylib_path.exists() {
+ builder.install(&llvm_dylib_path, &dst_libdir, 0o644);
+ }
+ return
+ }
// Usually libLLVM.so is a symlink to something like libLLVM-6.0.so.
// Since tools link to the latter rather than the former, we have to
llvm_dylib_path.display(), e);
});
- let dst_libdir = image.join("lib");
- t!(fs::create_dir_all(&dst_libdir));
builder.install(&llvm_dylib_path, &dst_libdir, 0o644);
}
let src_bindir = builder
.llvm_out(target)
.join("bin");
- let dst_bindir = image.join("bin");
+ let dst_bindir = image.join("lib/rustlib")
+ .join(&*target)
+ .join("bin");
t!(fs::create_dir_all(&dst_bindir));
for tool in LLVM_TOOLS {
let exe = src_bindir.join(exe(tool, &target));
builder.install(&exe, &dst_bindir, 0o755);
}
- maybe_install_llvm_dylib(builder, target, &image);
-
// Prepare the overlay
let overlay = tmp.join("llvm-tools-overlay");
drop(fs::remove_dir_all(&overlay));
}
}
- // Copy libLLVM.so to the lib dir as well, if needed.
- maybe_install_llvm_dylib(builder, target, &image);
-
// Prepare the overlay
let overlay = tmp.join("lldb-overlay");
drop(fs::remove_dir_all(&overlay));
"stage to build (indicates compiler to use/test, e.g. stage 0 uses the \
bootstrap compiler, stage 1 the stage 0 rustc artifacts, etc.)",
"N");
- opts.optmulti("", "keep-stage", "stage(s) to keep without recompiling", "N");
+ opts.optmulti("", "keep-stage", "stage(s) to keep without recompiling \
+ (pass multiple times to keep e.g. both stages 0 and 1)", "N");
opts.optopt("", "src", "path to the root of the rust checkout", "DIR");
opts.optopt("j", "jobs", "number of jobs to run in parallel", "JOBS");
opts.optflag("h", "help", "print this help message");
//! Note that this module has a #[cfg(windows)] above it as none of this logic
//! is required on Unix.
-#![allow(bad_style, dead_code)]
+#![allow(nonstandard_style, dead_code)]
use std::env;
use std::io;
"llvm-objcopy", // used to transform ELFs into binary format which flashing tools consume
"llvm-objdump", // used to disassemble programs
"llvm-profdata", // used to inspect and merge files generated by profiles
+ "llvm-readobj", // used to get information from ELFs/objects that the other tools don't provide
"llvm-size", // used to prints the size of the linker sections of a program
"llvm-strip", // used to discard symbols from binary files to reduce their size
];
.define("LLVM_INCLUDE_EXAMPLES", "OFF")
.define("LLVM_INCLUDE_TESTS", "OFF")
.define("LLVM_INCLUDE_DOCS", "OFF")
+ .define("LLVM_INCLUDE_BENCHMARKS", "OFF")
.define("LLVM_ENABLE_ZLIB", "OFF")
.define("WITH_POLLY", "OFF")
.define("LLVM_ENABLE_TERMINFO", "OFF")
//
// Copied from std
#[cfg(windows)]
- #[allow(bad_style)]
+ #[allow(nonstandard_style)]
fn symlink_dir_inner(target: &Path, junction: &Path) -> io::Result<()> {
use std::ptr;
use std::ffi::OsStr;
ENV TARGETS=$TARGETS,thumbv7m-none-eabi
ENV TARGETS=$TARGETS,thumbv7em-none-eabi
ENV TARGETS=$TARGETS,thumbv7em-none-eabihf
+ENV TARGETS=$TARGETS,riscv32imc-unknown-none-elf
ENV TARGETS=$TARGETS,riscv32imac-unknown-none-elf
ENV TARGETS=$TARGETS,armebv7r-none-eabi
ENV TARGETS=$TARGETS,armebv7r-none-eabihf
item, it will be accompanied by a banner explaining that the item is only available on certain
platforms.
-As mentioned earlier, getting the items to Rustdoc requires some extra preparation. The standard
-library adds a `--cfg dox` flag to every Rustdoc command, but the same thing can be accomplished by
-adding a feature to your Cargo.toml and adding `--feature dox` (or whatever you choose to name the
-feature) to your `cargo doc` calls.
+For Rustdoc to document an item, it needs to see it, regardless of what platform it's currently
+running on. To aid this, Rustdoc sets the flag `#[cfg(rustdoc)]` when running on your crate.
+Combining this with the target platform of a given item allows it to appear when building your crate
+normally on that platform, as well as when building documentation anywhere.
-Either way, once you create an environment for the documentation, you can start to augment your
-`#[cfg]` attributes to allow both the target platform *and* the documentation configuration to leave
-the item in. For example, `#[cfg(any(windows, feature = "dox"))]` will preserve the item either on
-Windows or during the documentation process. Then, adding a new attribute `#[doc(cfg(windows))]`
-will tell Rustdoc that the item is supposed to be used on Windows. For example:
+For example, `#[cfg(any(windows, rustdoc))]` will preserve the item either on Windows or during the
+documentation process. Then, adding a new attribute `#[doc(cfg(windows))]` will tell Rustdoc that
+the item is supposed to be used on Windows. For example:
```rust
#![feature(doc_cfg)]
/// Token struct that can only be used on Windows.
-#[cfg(any(windows, feature = "dox"))]
+#[cfg(any(windows, rustdoc))]
#[doc(cfg(windows))]
pub struct WindowsToken;
/// Token struct that can only be used on Unix.
-#[cfg(any(unix, feature = "dox"))]
+#[cfg(any(unix, rustdoc))]
#[doc(cfg(unix))]
pub struct UnixToken;
```
the given edition as well. As with `rustc`, the default edition that `rustdoc` will use is `2015`
(the first edition).
+### `--extern-html-root-url`: control how rustdoc links to non-local crates
+
+Using this flag looks like this:
+
+```bash
+$ rustdoc src/lib.rs -Z unstable-options --extern-html-root-url some-crate=https://example.com/some-crate/1.0.1
+```
+
+Ordinarily, when rustdoc wants to link to a type from a different crate, it looks in two places:
+docs that already exist in the output directory, or the `#![doc(doc_html_root)]` set in the other
+crate. However, if you want to link to docs that exist in neither of those places, you can use these
+flags to control that behavior. When the `--extern-html-root-url` flag is given with a name matching
+one of your dependencies, rustdoc use that URL for those docs. Keep in mind that if those docs exist
+in the output directory, those local docs will still override this flag.
+
### `-Z force-unstable-if-unmarked`
Using this flag looks like this:
--- /dev/null
+# `custom_test_frameworks`
+
+The tracking issue for this feature is: [#50297]
+
+[#50297]: https://github.com/rust-lang/rust/issues/50297
+
+------------------------
+
+The `custom_test_frameworks` feature allows the use of `#[test_case]` and `#![test_runner]`.
+Any function, const, or static can be annotated with `#[test_case]` causing it to be aggregated (like `#[test]`)
+and be passed to the test runner determined by the `#![test_runner]` crate attribute.
+
+```rust
+#![feature(custom_test_frameworks)]
+#![test_runner(my_runner)]
+
+fn my_runner(tests: &[&i32]) {
+ for t in tests {
+ if **t == 0 {
+ println!("PASSED");
+ } else {
+ println!("FAILED");
+ }
+ }
+}
+
+#[test_case]
+const WILL_PASS: i32 = 0;
+
+#[test_case]
+const WILL_FAIL: i32 = 4;
+```
+
2. The item's doc-tests will only run on the specific platform.
+In addition to allowing the use of the `#[doc(cfg)]` attribute, this feature enables the use of a
+special conditional compilation flag, `#[cfg(rustdoc)]`, set whenever building documentation on your
+crate.
+
This feature was introduced as part of PR [#43348] to allow the platform-specific parts of the
standard library be documented.
```rust
#![feature(doc_cfg)]
-#[cfg(any(windows, feature = "documentation"))]
+#[cfg(any(windows, rustdoc))]
#[doc(cfg(windows))]
/// The application's icon in the notification area (a.k.a. system tray).
///
```
[#43781]: https://github.com/rust-lang/rust/issues/43781
-[#43348]: https://github.com/rust-lang/rust/issues/43348
\ No newline at end of file
+[#43348]: https://github.com/rust-lang/rust/issues/43348
--- /dev/null
+#!/bin/sh
+# Copyright 2014 The Rust Project Developers. See the COPYRIGHT
+# file at the top-level directory of this distribution and at
+# http://rust-lang.org/COPYRIGHT.
+#
+# Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+# http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+# <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+# option. This file may not be copied, modified, or distributed
+# except according to those terms.
+
+# Exit if anything fails
+set -e
+
+if [ $# -eq 0 ] || [ "$1" = "-h" ] || [ "$1" = "-help" ] || [ "$1" = "--help" ]; then
+ echo "
+rust-gdbgui
+===========
+gdbgui - https://gdbgui.com - is a graphical front-end to GDB
+that runs in a browser. This script invokes gdbgui with the Rust
+pretty printers loaded.
+
+Simple usage : rust-gdbgui target/debug/myprog
+With arguments: rust-gdbgui 'target/debug/myprog arg1 arg2...'
+ (note the quotes)
+
+
+Hints
+=====
+gdbgui won't be able to find the rust 'main' method automatically, so
+in its options make sure to disable the 'Add breakpoint to main after
+loading executable' setting to avoid a 'File not found: main' warning
+on startup.
+
+Instead, type 'main' into gdbgui's file browser and you should get
+auto-completion on the filename. Just pick 'main.rs', add a breakpoint
+by clicking in the line number gutter, and type 'r' or hit the Restart
+icon to start your program running.
+"
+ exit 0
+fi
+
+# Find out where the pretty printer Python module is
+RUSTC_SYSROOT=`rustc --print=sysroot`
+GDB_PYTHON_MODULE_DIRECTORY="$RUSTC_SYSROOT/lib/rustlib/etc"
+
+# Set the environment variable `RUST_GDB` to overwrite the call to a
+# different/specific command (defaults to `gdb`).
+RUST_GDB="${RUST_GDB:-gdb}"
+
+# Set the environment variable `RUST_GDBGUI` to overwrite the call to a
+# different/specific command (defaults to `gdbgui`).
+RUST_GDBGUI="${RUST_GDBGUI:-gdbgui}"
+
+# These arguments get passed through to GDB and make it load the
+# Rust pretty printers.
+GDB_ARGS="--directory=\"$GDB_PYTHON_MODULE_DIRECTORY\" -iex \"add-auto-load-safe-path $GDB_PYTHON_MODULE_DIRECTORY\""
+
+# Finally we execute gdbgui.
+PYTHONPATH="$PYTHONPATH:$GDB_PYTHON_MODULE_DIRECTORY" \
+ exec ${RUST_GDBGUI} \
+ --gdb ${RUST_GDB} \
+ --gdb-args "${GDB_ARGS}" \
+ "${@}"
+
compiler_builtins = { path = "../rustc/compiler_builtins_shim" }
[dev-dependencies]
-rand = "0.4"
+rand = "0.5"
[[test]]
name = "collectionstests"
/// let mut input = Cow::from(vec![-1, 0, 1]);
/// abs_all(&mut input);
/// ```
+///
+/// Another example showing how to keep `Cow` in a struct:
+///
+/// ```
+/// use std::borrow::{Cow, ToOwned};
+///
+/// struct Items<'a, X: 'a> where [X]: ToOwned<Owned=Vec<X>> {
+/// values: Cow<'a, [X]>,
+/// }
+///
+/// impl<'a, X: Clone + 'a> Items<'a, X> where [X]: ToOwned<Owned=Vec<X>> {
+/// fn new(v: Cow<'a, [X]>) -> Self {
+/// Items { values: v }
+/// }
+/// }
+///
+/// // Creates a container from borrowed values of a slice
+/// let readonly = [1, 2];
+/// let borrowed = Items::new((&readonly[..]).into());
+/// match borrowed {
+/// Items { values: Cow::Borrowed(b) } => println!("borrowed {:?}", b),
+/// _ => panic!("expect borrowed value"),
+/// }
+///
+/// let mut clone_on_write = borrowed;
+/// // Mutates the data from slice into owned vec and pushes a new value on top
+/// clone_on_write.values.to_mut().push(3);
+/// println!("clone_on_write = {:?}", clone_on_write.values);
+///
+/// // The data was mutated. Let check it out.
+/// match clone_on_write {
+/// Items { values: Cow::Owned(_) } => println!("clone_on_write contains owned data"),
+/// _ => panic!("expect owned data"),
+/// }
+/// ```
#[stable(feature = "rust1", since = "1.0.0")]
pub enum Cow<'a, B: ?Sized + 'a>
where B: ToOwned
use std::thread;
use std::vec::Vec;
- use rand::{thread_rng, Rng};
+ use rand::{thread_rng, RngCore};
use super::{LinkedList, Node};
#![feature(box_syntax)]
#![feature(cfg_target_has_atomic)]
#![feature(coerce_unsized)]
-#![feature(const_fn)]
+#![cfg_attr(stage0, feature(const_fn))]
+#![cfg_attr(not(stage0), feature(min_const_fn))]
#![feature(core_intrinsics)]
#![feature(custom_attribute)]
#![feature(dropck_eyepatch)]
///
/// The type `Arc<T>` provides shared ownership of a value of type `T`,
/// allocated in the heap. Invoking [`clone`][clone] on `Arc` produces
-/// a new pointer to the same value in the heap. When the last `Arc`
-/// pointer to a given value is destroyed, the pointed-to value is
-/// also destroyed.
+/// a new `Arc` instance, which points to the same value on the heap as the
+/// source `Arc`, while increasing a reference count. When the last `Arc`
+/// pointer to a given value is destroyed, the pointed-to value is also
+/// destroyed.
///
/// Shared references in Rust disallow mutation by default, and `Arc` is no
/// exception: you cannot generally obtain a mutable reference to something
/// // The two syntaxes below are equivalent.
/// let a = foo.clone();
/// let b = Arc::clone(&foo);
-/// // a and b both point to the same memory location as foo.
+/// // a, b, and foo are all Arcs that point to the same memory location
/// ```
///
/// The [`Arc::clone(&from)`] syntax is the most idiomatic because it conveys more explicitly
#![feature(allocator_api)]
#![feature(alloc_system)]
#![feature(box_syntax)]
-#![feature(const_fn)]
+#![cfg_attr(stage0, feature(const_fn))]
+#![cfg_attr(not(stage0), feature(min_const_fn))]
#![feature(drain_filter)]
#![feature(exact_size_is_empty)]
#![feature(pattern)]
use std::sync::atomic::{ATOMIC_USIZE_INIT, AtomicUsize};
use std::thread;
-use rand::{Rng, thread_rng};
+use rand::{Rng, RngCore, thread_rng};
+use rand::distributions::Standard;
fn square(n: usize) -> usize {
n * n
for len in (2..25).chain(500..510) {
for &modulus in &[5, 10, 100, 1000] {
for _ in 0..10 {
- let orig: Vec<_> = rng.gen_iter::<i32>()
+ let orig: Vec<_> = rng.sample_iter::<i32, _>(&Standard)
.map(|x| x % modulus)
.take(len)
.collect();
}
#[test]
-fn test_trim_left_matches() {
+fn test_trim_start_matches() {
let v: &[char] = &[];
- assert_eq!(" *** foo *** ".trim_left_matches(v), " *** foo *** ");
+ assert_eq!(" *** foo *** ".trim_start_matches(v), " *** foo *** ");
let chars: &[char] = &['*', ' '];
- assert_eq!(" *** foo *** ".trim_left_matches(chars), "foo *** ");
- assert_eq!(" *** *** ".trim_left_matches(chars), "");
- assert_eq!("foo *** ".trim_left_matches(chars), "foo *** ");
+ assert_eq!(" *** foo *** ".trim_start_matches(chars), "foo *** ");
+ assert_eq!(" *** *** ".trim_start_matches(chars), "");
+ assert_eq!("foo *** ".trim_start_matches(chars), "foo *** ");
- assert_eq!("11foo1bar11".trim_left_matches('1'), "foo1bar11");
+ assert_eq!("11foo1bar11".trim_start_matches('1'), "foo1bar11");
let chars: &[char] = &['1', '2'];
- assert_eq!("12foo1bar12".trim_left_matches(chars), "foo1bar12");
- assert_eq!("123foo1bar123".trim_left_matches(|c: char| c.is_numeric()), "foo1bar123");
+ assert_eq!("12foo1bar12".trim_start_matches(chars), "foo1bar12");
+ assert_eq!("123foo1bar123".trim_start_matches(|c: char| c.is_numeric()), "foo1bar123");
}
#[test]
-fn test_trim_right_matches() {
+fn test_trim_end_matches() {
let v: &[char] = &[];
- assert_eq!(" *** foo *** ".trim_right_matches(v), " *** foo *** ");
+ assert_eq!(" *** foo *** ".trim_end_matches(v), " *** foo *** ");
let chars: &[char] = &['*', ' '];
- assert_eq!(" *** foo *** ".trim_right_matches(chars), " *** foo");
- assert_eq!(" *** *** ".trim_right_matches(chars), "");
- assert_eq!(" *** foo".trim_right_matches(chars), " *** foo");
+ assert_eq!(" *** foo *** ".trim_end_matches(chars), " *** foo");
+ assert_eq!(" *** *** ".trim_end_matches(chars), "");
+ assert_eq!(" *** foo".trim_end_matches(chars), " *** foo");
- assert_eq!("11foo1bar11".trim_right_matches('1'), "11foo1bar");
+ assert_eq!("11foo1bar11".trim_end_matches('1'), "11foo1bar");
let chars: &[char] = &['1', '2'];
- assert_eq!("12foo1bar12".trim_right_matches(chars), "12foo1bar");
- assert_eq!("123foo1bar123".trim_right_matches(|c: char| c.is_numeric()), "123foo1bar");
+ assert_eq!("12foo1bar12".trim_end_matches(chars), "12foo1bar");
+ assert_eq!("123foo1bar123".trim_end_matches(|c: char| c.is_numeric()), "123foo1bar");
}
#[test]
}
#[test]
-fn test_trim_left() {
- assert_eq!("".trim_left(), "");
- assert_eq!("a".trim_left(), "a");
- assert_eq!(" ".trim_left(), "");
- assert_eq!(" blah".trim_left(), "blah");
- assert_eq!(" \u{3000} wut".trim_left(), "wut");
- assert_eq!("hey ".trim_left(), "hey ");
+fn test_trim_start() {
+ assert_eq!("".trim_start(), "");
+ assert_eq!("a".trim_start(), "a");
+ assert_eq!(" ".trim_start(), "");
+ assert_eq!(" blah".trim_start(), "blah");
+ assert_eq!(" \u{3000} wut".trim_start(), "wut");
+ assert_eq!("hey ".trim_start(), "hey ");
}
#[test]
-fn test_trim_right() {
- assert_eq!("".trim_right(), "");
- assert_eq!("a".trim_right(), "a");
- assert_eq!(" ".trim_right(), "");
- assert_eq!("blah ".trim_right(), "blah");
- assert_eq!("wut \u{3000} ".trim_right(), "wut");
- assert_eq!(" hey".trim_right(), " hey");
+fn test_trim_end() {
+ assert_eq!("".trim_end(), "");
+ assert_eq!("a".trim_end(), "a");
+ assert_eq!(" ".trim_end(), "");
+ assert_eq!("blah ".trim_end(), "blah");
+ assert_eq!("wut \u{3000} ".trim_end(), "wut");
+ assert_eq!(" hey".trim_end(), " hey");
}
#[test]
"a \t ");
assert_eq!(" \t a \t ".trim_right_matches(|c: char| c.is_whitespace()),
" \t a");
+ assert_eq!(" \t a \t ".trim_start_matches(|c: char| c.is_whitespace()),
+ "a \t ");
+ assert_eq!(" \t a \t ".trim_end_matches(|c: char| c.is_whitespace()),
+ " \t a");
assert_eq!(" \t a \t ".trim_matches(|c: char| c.is_whitespace()),
"a");
assert_eq!(" \t \t ".trim_left_matches(|c: char| c.is_whitespace()),
"");
assert_eq!(" \t \t ".trim_right_matches(|c: char| c.is_whitespace()),
"");
+ assert_eq!(" \t \t ".trim_start_matches(|c: char| c.is_whitespace()),
+ "");
+ assert_eq!(" \t \t ".trim_end_matches(|c: char| c.is_whitespace()),
+ "");
assert_eq!(" \t \t ".trim_matches(|c: char| c.is_whitespace()),
"");
}
}
#[cfg(windows)]
-#[allow(bad_style)]
+#[allow(nonstandard_style)]
mod platform {
use MIN_ALIGN;
use System;
-Subproject commit d549d85b1735dc5066b2973f8549557a813bb9c8
+Subproject commit 0703bfa72524e01e414477657ca9b64794c5c1c3
path = "../libcore/benches/lib.rs"
[dev-dependencies]
-rand = "0.4"
+rand = "0.5"
fn bench_downcast_ref(b: &mut Bencher) {
b.iter(|| {
let mut x = 0;
- let mut y = &mut x as &mut Any;
+ let mut y = &mut x as &mut dyn Any;
black_box(&mut y);
black_box(y.downcast_ref::<isize>() == Some(&0));
});
/// the same book if their ISBN matches, even if the formats differ:
///
/// ```
-/// enum BookFormat { Paperback, Hardback, Ebook }
+/// enum BookFormat {
+/// Paperback,
+/// Hardback,
+/// Ebook,
+/// }
+///
/// struct Book {
/// isbn: i32,
/// format: BookFormat,
/// assert!(b1 != b3);
/// ```
///
+/// ## How can I compare two different types?
+///
+/// The type you can compare with is controlled by `PartialEq`'s type parameter.
+/// For example, let's tweak our previous code a bit:
+///
+/// ```
+/// enum BookFormat {
+/// Paperback,
+/// Hardback,
+/// Ebook,
+/// }
+///
+/// struct Book {
+/// isbn: i32,
+/// format: BookFormat,
+/// }
+///
+/// impl PartialEq<BookFormat> for Book {
+/// fn eq(&self, other: &BookFormat) -> bool {
+/// match (&self.format, other) {
+/// (BookFormat::Paperback, BookFormat::Paperback) => true,
+/// (BookFormat::Hardback, BookFormat::Hardback) => true,
+/// (BookFormat::Ebook, BookFormat::Ebook) => true,
+/// (_, _) => false,
+/// }
+/// }
+/// }
+///
+/// let b1 = Book { isbn: 3, format: BookFormat::Paperback };
+///
+/// assert!(b1 == BookFormat::Paperback);
+/// assert!(b1 != BookFormat::Ebook);
+/// ```
+///
+/// By changing `impl PartialEq for Book` to `impl PartialEq<BookFormat> for Book`,
+/// we've changed what type we can use on the right side of the `==` operator.
+/// This lets us use it in the `assert!` statements at the bottom.
+///
+/// You can also combine these implementations to let the `==` operator work with
+/// two different types:
+///
+/// ```
+/// enum BookFormat {
+/// Paperback,
+/// Hardback,
+/// Ebook,
+/// }
+///
+/// struct Book {
+/// isbn: i32,
+/// format: BookFormat,
+/// }
+///
+/// impl PartialEq<BookFormat> for Book {
+/// fn eq(&self, other: &BookFormat) -> bool {
+/// match (&self.format, other) {
+/// (&BookFormat::Paperback, &BookFormat::Paperback) => true,
+/// (&BookFormat::Hardback, &BookFormat::Hardback) => true,
+/// (&BookFormat::Ebook, &BookFormat::Ebook) => true,
+/// (_, _) => false,
+/// }
+/// }
+/// }
+///
+/// impl PartialEq for Book {
+/// fn eq(&self, other: &Book) -> bool {
+/// self.isbn == other.isbn
+/// }
+/// }
+///
+/// let b1 = Book { isbn: 3, format: BookFormat::Paperback };
+/// let b2 = Book { isbn: 3, format: BookFormat::Ebook };
+///
+/// assert!(b1 == BookFormat::Paperback);
+/// assert!(b1 != BookFormat::Ebook);
+/// assert!(b1 == b2);
+/// ```
+///
/// # Examples
///
/// ```
)*)
}
-step_impl_unsigned!(usize u8 u16 u32);
-step_impl_signed!([isize: usize] [i8: u8] [i16: u16] [i32: u32]);
+step_impl_unsigned!(usize u8 u16);
+#[cfg(not(target_pointer_witdth = "16"))]
+step_impl_unsigned!(u32);
+#[cfg(target_pointer_witdth = "16")]
+step_impl_no_between!(u32);
+step_impl_signed!([isize: usize] [i8: u8] [i16: u16]);
+#[cfg(not(target_pointer_witdth = "16"))]
+step_impl_signed!([i32: u32]);
+#[cfg(target_pointer_witdth = "16")]
+step_impl_no_between!(i32);
#[cfg(target_pointer_width = "64")]
step_impl_unsigned!(u64);
#[cfg(target_pointer_width = "64")]
#![feature(const_slice_len)]
#![feature(const_str_as_bytes)]
#![feature(const_str_len)]
+#![feature(const_let)]
+#![feature(const_int_rotate)]
+#![feature(const_int_wrapping)]
+#![feature(const_int_sign)]
+#![feature(const_int_conversion)]
+#![feature(const_transmute)]
+#![feature(reverse_bits)]
#![feature(non_exhaustive)]
#[prelude_import]
/// into libsyntax itself.
///
/// For more information, see documentation for `std`'s macros.
-#[cfg(dox)]
+#[cfg(rustdoc)]
mod builtin {
/// Unconditionally causes compilation to fail with the given error message when encountered.
/// [alignment]: ./fn.align_of.html
#[inline]
#[stable(feature = "rust1", since = "1.0.0")]
+#[cfg(not(stage0))]
+pub const fn size_of<T>() -> usize {
+ intrinsics::size_of::<T>()
+}
+
+#[inline]
+#[stable(feature = "rust1", since = "1.0.0")]
+#[cfg(stage0)]
+/// Ceci n'est pas la documentation
pub const fn size_of<T>() -> usize {
unsafe { intrinsics::size_of::<T>() }
}
#[inline]
#[stable(feature = "rust1", since = "1.0.0")]
#[rustc_deprecated(reason = "use `align_of` instead", since = "1.2.0")]
+#[cfg(not(stage0))]
+pub fn min_align_of<T>() -> usize {
+ intrinsics::min_align_of::<T>()
+}
+
+#[inline]
+#[stable(feature = "rust1", since = "1.0.0")]
+#[rustc_deprecated(reason = "use `align_of` instead", since = "1.2.0")]
+#[cfg(stage0)]
+/// Ceci n'est pas la documentation
pub fn min_align_of<T>() -> usize {
unsafe { intrinsics::min_align_of::<T>() }
}
/// ```
#[inline]
#[stable(feature = "rust1", since = "1.0.0")]
+#[cfg(not(stage0))]
+pub const fn align_of<T>() -> usize {
+ intrinsics::min_align_of::<T>()
+}
+
+#[inline]
+#[stable(feature = "rust1", since = "1.0.0")]
+#[cfg(stage0)]
+/// Ceci n'est pas la documentation
pub const fn align_of<T>() -> usize {
unsafe { intrinsics::min_align_of::<T>() }
}
}
}
+ /// no docs here
+ #[stable(feature = "rust1", since = "1.0.0")]
+ #[inline]
+ #[cfg(stage0)]
+ pub fn rotate_left(self, n: u32) -> Self {
+ (self as $UnsignedT).rotate_left(n) as Self
+ }
+
doc_comment! {
concat!("Shifts the bits to the left by a specified amount, `n`,
wrapping the truncated bits to the end of the resulting integer.
assert_eq!(n.rotate_left(", $rot, "), m);
```"),
#[stable(feature = "rust1", since = "1.0.0")]
+ #[rustc_const_unstable(feature = "const_int_rotate")]
#[inline]
- pub fn rotate_left(self, n: u32) -> Self {
+ #[cfg(not(stage0))]
+ pub const fn rotate_left(self, n: u32) -> Self {
(self as $UnsignedT).rotate_left(n) as Self
}
}
+ /// no docs here
+ #[stable(feature = "rust1", since = "1.0.0")]
+ #[inline]
+ #[cfg(stage0)]
+ pub fn rotate_right(self, n: u32) -> Self {
+ (self as $UnsignedT).rotate_right(n) as Self
+ }
+
doc_comment! {
concat!("Shifts the bits to the right by a specified amount, `n`,
wrapping the truncated bits to the beginning of the resulting
assert_eq!(n.rotate_right(", $rot, "), m);
```"),
#[stable(feature = "rust1", since = "1.0.0")]
+ #[rustc_const_unstable(feature = "const_int_rotate")]
#[inline]
- pub fn rotate_right(self, n: u32) -> Self {
+ #[cfg(not(stage0))]
+ pub const fn rotate_right(self, n: u32) -> Self {
(self as $UnsignedT).rotate_right(n) as Self
}
}
+
doc_comment! {
concat!("Reverses the byte order of the integer.
}
}
+ /// no docs here
+ #[unstable(feature = "reverse_bits", issue = "48763")]
+ #[inline]
+ #[cfg(stage0)]
+ pub fn reverse_bits(self) -> Self {
+ (self as $UnsignedT).reverse_bits() as Self
+ }
+
doc_comment! {
concat!("Reverses the bit pattern of the integer.
assert_eq!(m, ", $reversed, ");
```"),
#[unstable(feature = "reverse_bits", issue = "48763")]
+ #[rustc_const_unstable(feature = "const_int_conversion")]
#[inline]
- pub fn reverse_bits(self) -> Self {
+ #[cfg(not(stage0))]
+ pub const fn reverse_bits(self) -> Self {
(self as $UnsignedT).reverse_bits() as Self
}
}
}
}
+ /// no docs here
+ #[stable(feature = "rust1", since = "1.0.0")]
+ #[inline]
+ #[cfg(stage0)]
+ pub fn wrapping_add(self, rhs: Self) -> Self {
+ unsafe {
+ intrinsics::overflowing_add(self, rhs)
+ }
+ }
+
doc_comment! {
concat!("Wrapping (modular) addition. Computes `self + rhs`, wrapping around at the
boundary of the type.
$EndFeature, "
```"),
#[stable(feature = "rust1", since = "1.0.0")]
+ #[rustc_const_unstable(feature = "const_int_wrapping")]
#[inline]
- pub fn wrapping_add(self, rhs: Self) -> Self {
+ #[cfg(not(stage0))]
+ pub const fn wrapping_add(self, rhs: Self) -> Self {
unsafe {
intrinsics::overflowing_add(self, rhs)
}
}
}
+ /// no docs here
+ #[stable(feature = "rust1", since = "1.0.0")]
+ #[inline]
+ #[cfg(stage0)]
+ pub fn wrapping_sub(self, rhs: Self) -> Self {
+ unsafe {
+ intrinsics::overflowing_sub(self, rhs)
+ }
+ }
+
doc_comment! {
concat!("Wrapping (modular) subtraction. Computes `self - rhs`, wrapping around at the
boundary of the type.
$EndFeature, "
```"),
#[stable(feature = "rust1", since = "1.0.0")]
+ #[rustc_const_unstable(feature = "const_int_wrapping")]
#[inline]
- pub fn wrapping_sub(self, rhs: Self) -> Self {
+ #[cfg(not(stage0))]
+ pub const fn wrapping_sub(self, rhs: Self) -> Self {
unsafe {
intrinsics::overflowing_sub(self, rhs)
}
}
}
+ /// no docs here
+ #[stable(feature = "rust1", since = "1.0.0")]
+ #[inline]
+ #[cfg(stage0)]
+ pub fn wrapping_mul(self, rhs: Self) -> Self {
+ unsafe {
+ intrinsics::overflowing_mul(self, rhs)
+ }
+ }
+
doc_comment! {
concat!("Wrapping (modular) multiplication. Computes `self * rhs`, wrapping around at
the boundary of the type.
$EndFeature, "
```"),
#[stable(feature = "rust1", since = "1.0.0")]
+ #[rustc_const_unstable(feature = "const_int_wrapping")]
#[inline]
- pub fn wrapping_mul(self, rhs: Self) -> Self {
+ #[cfg(not(stage0))]
+ pub const fn wrapping_mul(self, rhs: Self) -> Self {
unsafe {
intrinsics::overflowing_mul(self, rhs)
}
}
}
+ /// no docs here
+ #[stable(feature = "num_wrapping", since = "1.2.0")]
+ #[inline]
+ #[cfg(stage0)]
+ pub fn wrapping_shl(self, rhs: u32) -> Self {
+ unsafe {
+ intrinsics::unchecked_shl(self, (rhs & ($BITS - 1)) as $SelfT)
+ }
+ }
+
doc_comment! {
concat!("Panic-free bitwise shift-left; yields `self << mask(rhs)`, where `mask` removes
any high-order bits of `rhs` that would cause the shift to exceed the bitwidth of the type.
$EndFeature, "
```"),
#[stable(feature = "num_wrapping", since = "1.2.0")]
+ #[rustc_const_unstable(feature = "const_int_wrapping")]
#[inline]
- pub fn wrapping_shl(self, rhs: u32) -> Self {
+ #[cfg(not(stage0))]
+ pub const fn wrapping_shl(self, rhs: u32) -> Self {
unsafe {
intrinsics::unchecked_shl(self, (rhs & ($BITS - 1)) as $SelfT)
}
}
}
+ /// no docs here
+ #[stable(feature = "num_wrapping", since = "1.2.0")]
+ #[inline]
+ #[cfg(stage0)]
+ pub fn wrapping_shr(self, rhs: u32) -> Self {
+ unsafe {
+ intrinsics::unchecked_shr(self, (rhs & ($BITS - 1)) as $SelfT)
+ }
+ }
+
doc_comment! {
concat!("Panic-free bitwise shift-right; yields `self >> mask(rhs)`, where `mask`
removes any high-order bits of `rhs` that would cause the shift to exceed the bitwidth of the type.
$EndFeature, "
```"),
#[stable(feature = "num_wrapping", since = "1.2.0")]
+ #[rustc_const_unstable(feature = "const_int_wrapping")]
#[inline]
- pub fn wrapping_shr(self, rhs: u32) -> Self {
+ #[cfg(not(stage0))]
+ pub const fn wrapping_shr(self, rhs: u32) -> Self {
unsafe {
intrinsics::unchecked_shr(self, (rhs & ($BITS - 1)) as $SelfT)
}
}
}
+ /// no docs here
+ #[stable(feature = "wrapping", since = "1.7.0")]
+ #[inline]
+ #[cfg(stage0)]
+ pub fn overflowing_add(self, rhs: Self) -> (Self, bool) {
+ let (a, b) = unsafe {
+ intrinsics::add_with_overflow(self as $ActualT,
+ rhs as $ActualT)
+ };
+ (a as Self, b)
+ }
+
doc_comment! {
concat!("Calculates `self` + `rhs`
assert_eq!(", stringify!($SelfT), "::MAX.overflowing_add(1), (", stringify!($SelfT),
"::MIN, true));", $EndFeature, "
```"),
- #[inline]
#[stable(feature = "wrapping", since = "1.7.0")]
- pub fn overflowing_add(self, rhs: Self) -> (Self, bool) {
+ #[rustc_const_unstable(feature = "const_int_overflowing")]
+ #[inline]
+ #[cfg(not(stage0))]
+ pub const fn overflowing_add(self, rhs: Self) -> (Self, bool) {
let (a, b) = unsafe {
intrinsics::add_with_overflow(self as $ActualT,
rhs as $ActualT)
}
}
+ /// no docs here
+ #[stable(feature = "wrapping", since = "1.7.0")]
+ #[inline]
+ #[cfg(stage0)]
+ pub fn overflowing_sub(self, rhs: Self) -> (Self, bool) {
+ let (a, b) = unsafe {
+ intrinsics::sub_with_overflow(self as $ActualT,
+ rhs as $ActualT)
+ };
+ (a as Self, b)
+ }
+
doc_comment! {
concat!("Calculates `self` - `rhs`
assert_eq!(", stringify!($SelfT), "::MIN.overflowing_sub(1), (", stringify!($SelfT),
"::MAX, true));", $EndFeature, "
```"),
- #[inline]
#[stable(feature = "wrapping", since = "1.7.0")]
- pub fn overflowing_sub(self, rhs: Self) -> (Self, bool) {
+ #[rustc_const_unstable(feature = "const_int_overflowing")]
+ #[inline]
+ #[cfg(not(stage0))]
+ pub const fn overflowing_sub(self, rhs: Self) -> (Self, bool) {
let (a, b) = unsafe {
intrinsics::sub_with_overflow(self as $ActualT,
rhs as $ActualT)
}
}
+ /// no docs here
+ #[stable(feature = "wrapping", since = "1.7.0")]
+ #[inline]
+ #[cfg(stage0)]
+ pub fn overflowing_mul(self, rhs: Self) -> (Self, bool) {
+ let (a, b) = unsafe {
+ intrinsics::mul_with_overflow(self as $ActualT,
+ rhs as $ActualT)
+ };
+ (a as Self, b)
+ }
+
doc_comment! {
concat!("Calculates the multiplication of `self` and `rhs`.
assert_eq!(1_000_000_000i32.overflowing_mul(10), (1410065408, true));",
$EndFeature, "
```"),
- #[inline]
#[stable(feature = "wrapping", since = "1.7.0")]
- pub fn overflowing_mul(self, rhs: Self) -> (Self, bool) {
+ #[rustc_const_unstable(feature = "const_int_overflowing")]
+ #[inline]
+ #[cfg(not(stage0))]
+ pub const fn overflowing_mul(self, rhs: Self) -> (Self, bool) {
let (a, b) = unsafe {
intrinsics::mul_with_overflow(self as $ActualT,
rhs as $ActualT)
}
}
+ /// no docs here
+ #[stable(feature = "wrapping", since = "1.7.0")]
+ #[inline]
+ #[cfg(stage0)]
+ pub fn overflowing_shl(self, rhs: u32) -> (Self, bool) {
+ (self.wrapping_shl(rhs), (rhs > ($BITS - 1)))
+ }
+
doc_comment! {
concat!("Shifts self left by `rhs` bits.
assert_eq!(0x1i32.overflowing_shl(36), (0x10, true));",
$EndFeature, "
```"),
- #[inline]
#[stable(feature = "wrapping", since = "1.7.0")]
- pub fn overflowing_shl(self, rhs: u32) -> (Self, bool) {
+ #[rustc_const_unstable(feature = "const_int_overflowing")]
+ #[inline]
+ #[cfg(not(stage0))]
+ pub const fn overflowing_shl(self, rhs: u32) -> (Self, bool) {
(self.wrapping_shl(rhs), (rhs > ($BITS - 1)))
}
}
+ /// no docs here
+ #[stable(feature = "wrapping", since = "1.7.0")]
+ #[inline]
+ #[cfg(stage0)]
+ pub fn overflowing_shr(self, rhs: u32) -> (Self, bool) {
+ (self.wrapping_shr(rhs), (rhs > ($BITS - 1)))
+ }
+
doc_comment! {
concat!("Shifts self right by `rhs` bits.
assert_eq!(0x10i32.overflowing_shr(36), (0x1, true));",
$EndFeature, "
```"),
- #[inline]
#[stable(feature = "wrapping", since = "1.7.0")]
- pub fn overflowing_shr(self, rhs: u32) -> (Self, bool) {
+ #[rustc_const_unstable(feature = "const_int_overflowing")]
+ #[inline]
+ #[cfg(not(stage0))]
+ pub const fn overflowing_shr(self, rhs: u32) -> (Self, bool) {
(self.wrapping_shr(rhs), (rhs > ($BITS - 1)))
}
}
}
}
+ /// no docs here
+ #[stable(feature = "rust1", since = "1.0.0")]
+ #[inline]
+ #[cfg(stage0)]
+ pub fn is_positive(self) -> bool { self > 0 }
+
doc_comment! {
concat!("Returns `true` if `self` is positive and `false` if the number is zero or
negative.
$EndFeature, "
```"),
#[stable(feature = "rust1", since = "1.0.0")]
+ #[rustc_const_unstable(feature = "const_int_sign")]
#[inline]
- pub fn is_positive(self) -> bool { self > 0 }
+ #[cfg(not(stage0))]
+ pub const fn is_positive(self) -> bool { self > 0 }
}
+ /// no docs here
+ #[stable(feature = "rust1", since = "1.0.0")]
+ #[inline]
+ #[cfg(stage0)]
+ pub fn is_negative(self) -> bool { self < 0 }
+
doc_comment! {
concat!("Returns `true` if `self` is negative and `false` if the number is zero or
positive.
$EndFeature, "
```"),
#[stable(feature = "rust1", since = "1.0.0")]
+ #[rustc_const_unstable(feature = "const_int_sign")]
#[inline]
- pub fn is_negative(self) -> bool { self < 0 }
+ #[cfg(not(stage0))]
+ pub const fn is_negative(self) -> bool { self < 0 }
+ }
+
+ /// no docs here
+ #[unstable(feature = "int_to_from_bytes", issue = "52963")]
+ #[inline]
+ #[cfg(stage0)]
+ pub fn to_be_bytes(self) -> [u8; mem::size_of::<Self>()] {
+ self.to_be().to_ne_bytes()
}
/// Return the memory representation of this integer as a byte array in
/// assert_eq!(bytes, [0x12, 0x34, 0x56, 0x78]);
/// ```
#[unstable(feature = "int_to_from_bytes", issue = "52963")]
+ #[rustc_const_unstable(feature = "const_int_conversion")]
#[inline]
- pub fn to_be_bytes(self) -> [u8; mem::size_of::<Self>()] {
+ #[cfg(not(stage0))]
+ pub const fn to_be_bytes(self) -> [u8; mem::size_of::<Self>()] {
self.to_be().to_ne_bytes()
}
+ /// no docs here
+ #[unstable(feature = "int_to_from_bytes", issue = "52963")]
+ #[inline]
+ #[cfg(stage0)]
+ pub fn to_le_bytes(self) -> [u8; mem::size_of::<Self>()] {
+ self.to_le().to_ne_bytes()
+ }
+
/// Return the memory representation of this integer as a byte array in
/// little-endian byte order.
///
/// assert_eq!(bytes, [0x78, 0x56, 0x34, 0x12]);
/// ```
#[unstable(feature = "int_to_from_bytes", issue = "52963")]
+ #[rustc_const_unstable(feature = "const_int_conversion")]
#[inline]
- pub fn to_le_bytes(self) -> [u8; mem::size_of::<Self>()] {
+ #[cfg(not(stage0))]
+ pub const fn to_le_bytes(self) -> [u8; mem::size_of::<Self>()] {
self.to_le().to_ne_bytes()
}
+ /// no docs here
+ #[unstable(feature = "int_to_from_bytes", issue = "52963")]
+ #[inline]
+ #[cfg(stage0)]
+ pub fn to_ne_bytes(self) -> [u8; mem::size_of::<Self>()] {
+ unsafe { mem::transmute(self) }
+ }
+
/// Return the memory representation of this integer as a byte array in
/// native byte order.
///
/// assert_eq!(bytes, [0x80, 0, 0, 0]);
/// ```
#[unstable(feature = "int_to_from_bytes", issue = "52963")]
+ #[rustc_const_unstable(feature = "const_int_conversion")]
#[inline]
- pub fn to_ne_bytes(self) -> [u8; mem::size_of::<Self>()] {
+ #[cfg(not(stage0))]
+ pub const fn to_ne_bytes(self) -> [u8; mem::size_of::<Self>()] {
unsafe { mem::transmute(self) }
}
+ /// no docs here
+ #[unstable(feature = "int_to_from_bytes", issue = "52963")]
+ #[inline]
+ #[cfg(stage0)]
+ pub fn from_be_bytes(bytes: [u8; mem::size_of::<Self>()]) -> Self {
+ Self::from_be(Self::from_ne_bytes(bytes))
+ }
+
/// Create an integer value from its representation as a byte array in
/// big endian.
///
/// assert_eq!(int, 0x12_34_56_78);
/// ```
#[unstable(feature = "int_to_from_bytes", issue = "52963")]
+ #[rustc_const_unstable(feature = "const_int_conversion")]
#[inline]
- pub fn from_be_bytes(bytes: [u8; mem::size_of::<Self>()]) -> Self {
+ #[cfg(not(stage0))]
+ pub const fn from_be_bytes(bytes: [u8; mem::size_of::<Self>()]) -> Self {
Self::from_be(Self::from_ne_bytes(bytes))
}
+ /// no docs here
+ #[unstable(feature = "int_to_from_bytes", issue = "52963")]
+ #[inline]
+ #[cfg(stage0)]
+ pub fn from_le_bytes(bytes: [u8; mem::size_of::<Self>()]) -> Self {
+ Self::from_le(Self::from_ne_bytes(bytes))
+ }
+
/// Create an integer value from its representation as a byte array in
/// little endian.
///
/// assert_eq!(int, 0x78_56_34_12);
/// ```
#[unstable(feature = "int_to_from_bytes", issue = "52963")]
+ #[rustc_const_unstable(feature = "const_int_conversion")]
#[inline]
- pub fn from_le_bytes(bytes: [u8; mem::size_of::<Self>()]) -> Self {
+ #[cfg(not(stage0))]
+ pub const fn from_le_bytes(bytes: [u8; mem::size_of::<Self>()]) -> Self {
Self::from_le(Self::from_ne_bytes(bytes))
}
+ /// no docs here
+ #[unstable(feature = "int_to_from_bytes", issue = "52963")]
+ #[inline]
+ #[cfg(stage0)]
+ pub fn from_ne_bytes(bytes: [u8; mem::size_of::<Self>()]) -> Self {
+ unsafe { mem::transmute(bytes) }
+ }
+
/// Create an integer value from its memory representation as a byte
/// array in native endianness.
///
/// assert_eq!(int, i32::min_value());
/// ```
#[unstable(feature = "int_to_from_bytes", issue = "52963")]
+ #[rustc_const_unstable(feature = "const_int_conversion")]
#[inline]
- pub fn from_ne_bytes(bytes: [u8; mem::size_of::<Self>()]) -> Self {
+ #[cfg(not(stage0))]
+ pub const fn from_ne_bytes(bytes: [u8; mem::size_of::<Self>()]) -> Self {
unsafe { mem::transmute(bytes) }
}
}
}
}
+ /// no docs here
+ #[stable(feature = "rust1", since = "1.0.0")]
+ #[inline]
+ #[cfg(stage0)]
+ pub fn rotate_left(self, n: u32) -> Self {
+ // Protect against undefined behaviour for over-long bit shifts
+ let n = n % $BITS;
+ (self << n) | (self >> (($BITS - n) % $BITS))
+ }
+
doc_comment! {
concat!("Shifts the bits to the left by a specified amount, `n`,
wrapping the truncated bits to the end of the resulting integer.
assert_eq!(n.rotate_left(", $rot, "), m);
```"),
#[stable(feature = "rust1", since = "1.0.0")]
+ #[rustc_const_unstable(feature = "const_int_rotate")]
#[inline]
- pub fn rotate_left(self, n: u32) -> Self {
- // Protect against undefined behaviour for over-long bit shifts
- let n = n % $BITS;
- (self << n) | (self >> (($BITS - n) % $BITS))
+ #[cfg(not(stage0))]
+ pub const fn rotate_left(self, n: u32) -> Self {
+ (self << (n % $BITS)) | (self >> (($BITS - (n % $BITS)) % $BITS))
}
}
+ /// no docs here
+ #[stable(feature = "rust1", since = "1.0.0")]
+ #[inline]
+ #[cfg(stage0)]
+ pub fn rotate_right(self, n: u32) -> Self {
+ // Protect against undefined behaviour for over-long bit shifts
+ let n = n % $BITS;
+ (self >> n) | (self << (($BITS - n) % $BITS))
+ }
+
doc_comment! {
concat!("Shifts the bits to the right by a specified amount, `n`,
wrapping the truncated bits to the beginning of the resulting
assert_eq!(n.rotate_right(", $rot, "), m);
```"),
#[stable(feature = "rust1", since = "1.0.0")]
+ #[rustc_const_unstable(feature = "const_int_rotate")]
#[inline]
- pub fn rotate_right(self, n: u32) -> Self {
- // Protect against undefined behaviour for over-long bit shifts
- let n = n % $BITS;
- (self >> n) | (self << (($BITS - n) % $BITS))
+ #[cfg(not(stage0))]
+ pub const fn rotate_right(self, n: u32) -> Self {
+ (self >> (n % $BITS)) | (self << (($BITS - (n % $BITS)) % $BITS))
}
}
}
}
+ /// no docs here
+ #[unstable(feature = "reverse_bits", issue = "48763")]
+ #[inline]
+ #[cfg(stage0)]
+ pub fn reverse_bits(self) -> Self {
+ unsafe { intrinsics::bitreverse(self as $ActualT) as Self }
+ }
+
doc_comment! {
concat!("Reverses the bit pattern of the integer.
assert_eq!(m, ", $reversed, ");
```"),
#[unstable(feature = "reverse_bits", issue = "48763")]
+ #[rustc_const_unstable(feature = "const_int_conversion")]
#[inline]
- pub fn reverse_bits(self) -> Self {
+ #[cfg(not(stage0))]
+ pub const fn reverse_bits(self) -> Self {
unsafe { intrinsics::bitreverse(self as $ActualT) as Self }
}
}
}
}
+ /// no docs here
+ #[stable(feature = "rust1", since = "1.0.0")]
+ #[inline]
+ #[cfg(stage0)]
+ pub fn wrapping_add(self, rhs: Self) -> Self {
+ unsafe {
+ intrinsics::overflowing_add(self, rhs)
+ }
+ }
+
doc_comment! {
concat!("Wrapping (modular) addition. Computes `self + rhs`,
wrapping around at the boundary of the type.
$EndFeature, "
```"),
#[stable(feature = "rust1", since = "1.0.0")]
+ #[rustc_const_unstable(feature = "const_int_wrapping")]
#[inline]
- pub fn wrapping_add(self, rhs: Self) -> Self {
+ #[cfg(not(stage0))]
+ pub const fn wrapping_add(self, rhs: Self) -> Self {
unsafe {
intrinsics::overflowing_add(self, rhs)
}
}
}
+ /// no docs here
+ #[stable(feature = "rust1", since = "1.0.0")]
+ #[inline]
+ #[cfg(stage0)]
+ pub fn wrapping_sub(self, rhs: Self) -> Self {
+ unsafe {
+ intrinsics::overflowing_sub(self, rhs)
+ }
+ }
+
doc_comment! {
concat!("Wrapping (modular) subtraction. Computes `self - rhs`,
wrapping around at the boundary of the type.
$EndFeature, "
```"),
#[stable(feature = "rust1", since = "1.0.0")]
+ #[rustc_const_unstable(feature = "const_int_wrapping")]
#[inline]
- pub fn wrapping_sub(self, rhs: Self) -> Self {
+ #[cfg(not(stage0))]
+ pub const fn wrapping_sub(self, rhs: Self) -> Self {
unsafe {
intrinsics::overflowing_sub(self, rhs)
}
}
}
+ /// no docs here
+ #[stable(feature = "rust1", since = "1.0.0")]
+ #[inline]
+ #[cfg(stage0)]
+ pub fn wrapping_mul(self, rhs: Self) -> Self {
+ unsafe {
+ intrinsics::overflowing_mul(self, rhs)
+ }
+ }
+
/// Wrapping (modular) multiplication. Computes `self *
/// rhs`, wrapping around at the boundary of the type.
///
/// assert_eq!(25u8.wrapping_mul(12), 44);
/// ```
#[stable(feature = "rust1", since = "1.0.0")]
+ #[rustc_const_unstable(feature = "const_int_wrapping")]
#[inline]
- pub fn wrapping_mul(self, rhs: Self) -> Self {
+ #[cfg(not(stage0))]
+ pub const fn wrapping_mul(self, rhs: Self) -> Self {
unsafe {
intrinsics::overflowing_mul(self, rhs)
}
self.overflowing_neg().0
}
+ /// no docs here
+ #[stable(feature = "num_wrapping", since = "1.2.0")]
+ #[inline]
+ #[cfg(stage0)]
+ pub fn wrapping_shl(self, rhs: u32) -> Self {
+ unsafe {
+ intrinsics::unchecked_shl(self, (rhs & ($BITS - 1)) as $SelfT)
+ }
+ }
+
doc_comment! {
concat!("Panic-free bitwise shift-left; yields `self << mask(rhs)`,
where `mask` removes any high-order bits of `rhs` that
assert_eq!(1", stringify!($SelfT), ".wrapping_shl(128), 1);", $EndFeature, "
```"),
#[stable(feature = "num_wrapping", since = "1.2.0")]
+ #[rustc_const_unstable(feature = "const_int_wrapping")]
#[inline]
- pub fn wrapping_shl(self, rhs: u32) -> Self {
+ #[cfg(not(stage0))]
+ pub const fn wrapping_shl(self, rhs: u32) -> Self {
unsafe {
intrinsics::unchecked_shl(self, (rhs & ($BITS - 1)) as $SelfT)
}
}
}
+ /// no docs here
+ #[stable(feature = "num_wrapping", since = "1.2.0")]
+ #[inline]
+ #[cfg(stage0)]
+ pub fn wrapping_shr(self, rhs: u32) -> Self {
+ unsafe {
+ intrinsics::unchecked_shr(self, (rhs & ($BITS - 1)) as $SelfT)
+ }
+ }
+
doc_comment! {
concat!("Panic-free bitwise shift-right; yields `self >> mask(rhs)`,
where `mask` removes any high-order bits of `rhs` that
assert_eq!(128", stringify!($SelfT), ".wrapping_shr(128), 128);", $EndFeature, "
```"),
#[stable(feature = "num_wrapping", since = "1.2.0")]
+ #[rustc_const_unstable(feature = "const_int_wrapping")]
#[inline]
- pub fn wrapping_shr(self, rhs: u32) -> Self {
+ #[cfg(not(stage0))]
+ pub const fn wrapping_shr(self, rhs: u32) -> Self {
unsafe {
intrinsics::unchecked_shr(self, (rhs & ($BITS - 1)) as $SelfT)
}
}
}
+ /// no docs here
+ #[stable(feature = "wrapping", since = "1.7.0")]
+ #[inline]
+ #[cfg(stage0)]
+ pub fn overflowing_add(self, rhs: Self) -> (Self, bool) {
+ let (a, b) = unsafe {
+ intrinsics::add_with_overflow(self as $ActualT,
+ rhs as $ActualT)
+ };
+ (a as Self, b)
+ }
+
doc_comment! {
concat!("Calculates `self` + `rhs`
assert_eq!(5", stringify!($SelfT), ".overflowing_add(2), (7, false));
assert_eq!(", stringify!($SelfT), "::MAX.overflowing_add(1), (0, true));", $EndFeature, "
```"),
- #[inline]
#[stable(feature = "wrapping", since = "1.7.0")]
- pub fn overflowing_add(self, rhs: Self) -> (Self, bool) {
+ #[rustc_const_unstable(feature = "const_int_overflowing")]
+ #[inline]
+ #[cfg(not(stage0))]
+ pub const fn overflowing_add(self, rhs: Self) -> (Self, bool) {
let (a, b) = unsafe {
intrinsics::add_with_overflow(self as $ActualT,
rhs as $ActualT)
}
}
+ /// no docs here
+ #[stable(feature = "wrapping", since = "1.7.0")]
+ #[inline]
+ #[cfg(stage0)]
+ pub fn overflowing_sub(self, rhs: Self) -> (Self, bool) {
+ let (a, b) = unsafe {
+ intrinsics::sub_with_overflow(self as $ActualT,
+ rhs as $ActualT)
+ };
+ (a as Self, b)
+ }
+
doc_comment! {
concat!("Calculates `self` - `rhs`
assert_eq!(0", stringify!($SelfT), ".overflowing_sub(1), (", stringify!($SelfT), "::MAX, true));",
$EndFeature, "
```"),
- #[inline]
#[stable(feature = "wrapping", since = "1.7.0")]
- pub fn overflowing_sub(self, rhs: Self) -> (Self, bool) {
+ #[rustc_const_unstable(feature = "const_int_overflowing")]
+ #[inline]
+ #[cfg(not(stage0))]
+ pub const fn overflowing_sub(self, rhs: Self) -> (Self, bool) {
let (a, b) = unsafe {
intrinsics::sub_with_overflow(self as $ActualT,
rhs as $ActualT)
}
}
+ /// no docs here
+ #[stable(feature = "wrapping", since = "1.7.0")]
+ #[inline]
+ #[cfg(stage0)]
+ pub fn overflowing_mul(self, rhs: Self) -> (Self, bool) {
+ let (a, b) = unsafe {
+ intrinsics::mul_with_overflow(self as $ActualT,
+ rhs as $ActualT)
+ };
+ (a as Self, b)
+ }
+
/// Calculates the multiplication of `self` and `rhs`.
///
/// Returns a tuple of the multiplication along with a boolean
/// assert_eq!(5u32.overflowing_mul(2), (10, false));
/// assert_eq!(1_000_000_000u32.overflowing_mul(10), (1410065408, true));
/// ```
- #[inline]
#[stable(feature = "wrapping", since = "1.7.0")]
- pub fn overflowing_mul(self, rhs: Self) -> (Self, bool) {
+ #[rustc_const_unstable(feature = "const_int_overflowing")]
+ #[inline]
+ #[cfg(not(stage0))]
+ pub const fn overflowing_mul(self, rhs: Self) -> (Self, bool) {
let (a, b) = unsafe {
intrinsics::mul_with_overflow(self as $ActualT,
rhs as $ActualT)
}
}
+ /// no docs here
+ #[stable(feature = "wrapping", since = "1.7.0")]
+ #[inline]
+ #[cfg(stage0)]
+ pub fn overflowing_shl(self, rhs: u32) -> (Self, bool) {
+ (self.wrapping_shl(rhs), (rhs > ($BITS - 1)))
+ }
+
doc_comment! {
concat!("Shifts self left by `rhs` bits.
", $Feature, "assert_eq!(0x1", stringify!($SelfT), ".overflowing_shl(4), (0x10, false));
assert_eq!(0x1", stringify!($SelfT), ".overflowing_shl(132), (0x10, true));", $EndFeature, "
```"),
- #[inline]
#[stable(feature = "wrapping", since = "1.7.0")]
- pub fn overflowing_shl(self, rhs: u32) -> (Self, bool) {
+ #[rustc_const_unstable(feature = "const_int_overflowing")]
+ #[inline]
+ #[cfg(not(stage0))]
+ pub const fn overflowing_shl(self, rhs: u32) -> (Self, bool) {
(self.wrapping_shl(rhs), (rhs > ($BITS - 1)))
}
}
+ /// no docs here
+ #[stable(feature = "wrapping", since = "1.7.0")]
+ #[inline]
+ #[cfg(stage0)]
+ pub fn overflowing_shr(self, rhs: u32) -> (Self, bool) {
+ (self.wrapping_shr(rhs), (rhs > ($BITS - 1)))
+ }
+
doc_comment! {
concat!("Shifts self right by `rhs` bits.
", $Feature, "assert_eq!(0x10", stringify!($SelfT), ".overflowing_shr(4), (0x1, false));
assert_eq!(0x10", stringify!($SelfT), ".overflowing_shr(132), (0x1, true));", $EndFeature, "
```"),
- #[inline]
#[stable(feature = "wrapping", since = "1.7.0")]
- pub fn overflowing_shr(self, rhs: u32) -> (Self, bool) {
+ #[rustc_const_unstable(feature = "const_int_overflowing")]
+ #[inline]
+ #[cfg(not(stage0))]
+ pub const fn overflowing_shr(self, rhs: u32) -> (Self, bool) {
(self.wrapping_shr(rhs), (rhs > ($BITS - 1)))
}
}
}
}
+ /// no docs here
+ #[unstable(feature = "int_to_from_bytes", issue = "52963")]
+ #[inline]
+ #[cfg(stage0)]
+ pub fn to_be_bytes(self) -> [u8; mem::size_of::<Self>()] {
+ self.to_be().to_ne_bytes()
+ }
+
/// Return the memory representation of this integer as a byte array in
/// big-endian (network) byte order.
///
/// assert_eq!(bytes, [0x12, 0x34, 0x56, 0x78]);
/// ```
#[unstable(feature = "int_to_from_bytes", issue = "52963")]
+ #[rustc_const_unstable(feature = "const_int_conversion")]
#[inline]
- pub fn to_be_bytes(self) -> [u8; mem::size_of::<Self>()] {
+ #[cfg(not(stage0))]
+ pub const fn to_be_bytes(self) -> [u8; mem::size_of::<Self>()] {
self.to_be().to_ne_bytes()
}
+ /// no docs here
+ #[unstable(feature = "int_to_from_bytes", issue = "52963")]
+ #[inline]
+ #[cfg(stage0)]
+ pub fn to_le_bytes(self) -> [u8; mem::size_of::<Self>()] {
+ self.to_le().to_ne_bytes()
+ }
+
/// Return the memory representation of this integer as a byte array in
/// little-endian byte order.
///
/// assert_eq!(bytes, [0x78, 0x56, 0x34, 0x12]);
/// ```
#[unstable(feature = "int_to_from_bytes", issue = "52963")]
+ #[rustc_const_unstable(feature = "const_int_conversion")]
#[inline]
- pub fn to_le_bytes(self) -> [u8; mem::size_of::<Self>()] {
+ #[cfg(not(stage0))]
+ pub const fn to_le_bytes(self) -> [u8; mem::size_of::<Self>()] {
self.to_le().to_ne_bytes()
}
+ /// no docs here
+ #[unstable(feature = "int_to_from_bytes", issue = "52963")]
+ #[inline]
+ #[cfg(stage0)]
+ pub fn to_ne_bytes(self) -> [u8; mem::size_of::<Self>()] {
+ unsafe { mem::transmute(self) }
+ }
+
/// Return the memory representation of this integer as a byte array in
/// native byte order.
///
/// assert_eq!(bytes, [0x80, 0, 0, 0]);
/// ```
#[unstable(feature = "int_to_from_bytes", issue = "52963")]
+ #[rustc_const_unstable(feature = "const_int_conversion")]
#[inline]
- pub fn to_ne_bytes(self) -> [u8; mem::size_of::<Self>()] {
+ #[cfg(not(stage0))]
+ pub const fn to_ne_bytes(self) -> [u8; mem::size_of::<Self>()] {
unsafe { mem::transmute(self) }
}
+ /// no docs here
+ #[unstable(feature = "int_to_from_bytes", issue = "52963")]
+ #[inline]
+ #[cfg(stage0)]
+ pub fn from_be_bytes(bytes: [u8; mem::size_of::<Self>()]) -> Self {
+ Self::from_be(Self::from_ne_bytes(bytes))
+ }
+
/// Create an integer value from its representation as a byte array in
/// big endian.
///
/// assert_eq!(int, 0x12_34_56_78);
/// ```
#[unstable(feature = "int_to_from_bytes", issue = "52963")]
+ #[rustc_const_unstable(feature = "const_int_conversion")]
#[inline]
- pub fn from_be_bytes(bytes: [u8; mem::size_of::<Self>()]) -> Self {
+ #[cfg(not(stage0))]
+ pub const fn from_be_bytes(bytes: [u8; mem::size_of::<Self>()]) -> Self {
Self::from_be(Self::from_ne_bytes(bytes))
}
+ /// no docs here
+ #[unstable(feature = "int_to_from_bytes", issue = "52963")]
+ #[inline]
+ #[cfg(stage0)]
+ pub fn from_le_bytes(bytes: [u8; mem::size_of::<Self>()]) -> Self {
+ Self::from_le(Self::from_ne_bytes(bytes))
+ }
+
/// Create an integer value from its representation as a byte array in
/// little endian.
///
/// assert_eq!(int, 0x78_56_34_12);
/// ```
#[unstable(feature = "int_to_from_bytes", issue = "52963")]
+ #[rustc_const_unstable(feature = "const_int_conversion")]
#[inline]
- pub fn from_le_bytes(bytes: [u8; mem::size_of::<Self>()]) -> Self {
+ #[cfg(not(stage0))]
+ pub const fn from_le_bytes(bytes: [u8; mem::size_of::<Self>()]) -> Self {
Self::from_le(Self::from_ne_bytes(bytes))
}
+ /// no docs here
+ #[unstable(feature = "int_to_from_bytes", issue = "52963")]
+ #[inline]
+ #[cfg(stage0)]
+ pub fn from_ne_bytes(bytes: [u8; mem::size_of::<Self>()]) -> Self {
+ unsafe { mem::transmute(bytes) }
+ }
+
/// Create an integer value from its memory representation as a byte
/// array in native endianness.
///
/// assert_eq!(int, i32::min_value());
/// ```
#[unstable(feature = "int_to_from_bytes", issue = "52963")]
+ #[rustc_const_unstable(feature = "const_int_conversion")]
#[inline]
- pub fn from_ne_bytes(bytes: [u8; mem::size_of::<Self>()]) -> Self {
+ #[cfg(not(stage0))]
+ pub const fn from_ne_bytes(bytes: [u8; mem::size_of::<Self>()]) -> Self {
unsafe { mem::transmute(bytes) }
}
}
/// The error type returned when a checked integral type conversion fails.
#[unstable(feature = "try_from", issue = "33417")]
-#[derive(Debug, Copy, Clone)]
+#[derive(Debug, Copy, Clone, PartialEq, Eq)]
pub struct TryFromIntError(());
impl TryFromIntError {
// The library infrastructure for slices is fairly messy. There's
// a lot of stuff defined here. Let's keep it clean.
//
-// Since slices don't support inherent methods; all operations
-// on them are defined on traits, which are then re-exported from
-// the prelude for convenience. So there are a lot of traits here.
-//
// The layout of this file is thus:
//
-// * Slice-specific 'extension' traits and their implementations. This
-// is where most of the slice API resides.
+// * Inherent methods. This is where most of the slice API resides.
// * Implementations of a few common traits with important slice ops.
// * Definitions of a bunch of iterators.
// * Free functions.
Repr { raw: FatPtr { data, len } }.rust
}
-/// Performs the same functionality as `from_raw_parts`, except that a mutable
-/// slice is returned.
+/// Performs the same functionality as [`from_raw_parts`], except that a
+/// mutable slice is returned.
///
-/// This function is unsafe for the same reasons as `from_raw_parts`, as well
+/// This function is unsafe for the same reasons as [`from_raw_parts`], as well
/// as not being able to provide a non-aliasing guarantee of the returned
/// mutable slice. `data` must be non-null and aligned even for zero-length
-/// slices as with `from_raw_parts`.
+/// slices as with [`from_raw_parts`]. See the documentation of
+/// [`from_raw_parts`] for more details.
+///
+/// [`from_raw_parts`]: ../../std/slice/fn.from_raw_parts.html
#[inline]
#[stable(feature = "rust1", since = "1.0.0")]
pub unsafe fn from_raw_parts_mut<'a, T>(data: *mut T, len: usize) -> &'a mut [T] {
///
/// fn from_str(s: &str) -> Result<Self, Self::Err> {
/// let coords: Vec<&str> = s.trim_matches(|p| p == '(' || p == ')' )
-/// .split(",")
+/// .split(',')
/// .collect();
///
/// let x_fromstr = coords[0].parse::<i32>()?;
self.trim_matches(|c: char| c.is_whitespace())
}
+ /// Returns a string slice with leading whitespace removed.
+ ///
+ /// 'Whitespace' is defined according to the terms of the Unicode Derived
+ /// Core Property `White_Space`.
+ ///
+ /// # Text directionality
+ ///
+ /// A string is a sequence of bytes. `start` in this context means the first
+ /// position of that byte string; for a left-to-right language like English or
+ /// Russian, this will be left side; and for right-to-left languages like
+ /// like Arabic or Hebrew, this will be the right side.
+ ///
+ /// # Examples
+ ///
+ /// Basic usage:
+ ///
+ /// ```
+ /// let s = " Hello\tworld\t";
+ /// assert_eq!("Hello\tworld\t", s.trim_start());
+ /// ```
+ ///
+ /// Directionality:
+ ///
+ /// ```
+ /// let s = " English ";
+ /// assert!(Some('E') == s.trim_start().chars().next());
+ ///
+ /// let s = " עברית ";
+ /// assert!(Some('×¢') == s.trim_start().chars().next());
+ /// ```
+ #[stable(feature = "trim_direction", since = "1.30.0")]
+ pub fn trim_start(&self) -> &str {
+ self.trim_start_matches(|c: char| c.is_whitespace())
+ }
+
+ /// Returns a string slice with trailing whitespace removed.
+ ///
+ /// 'Whitespace' is defined according to the terms of the Unicode Derived
+ /// Core Property `White_Space`.
+ ///
+ /// # Text directionality
+ ///
+ /// A string is a sequence of bytes. `end` in this context means the last
+ /// position of that byte string; for a left-to-right language like English or
+ /// Russian, this will be right side; and for right-to-left languages like
+ /// like Arabic or Hebrew, this will be the left side.
+ ///
+ /// # Examples
+ ///
+ /// Basic usage:
+ ///
+ /// ```
+ /// let s = " Hello\tworld\t";
+ /// assert_eq!(" Hello\tworld", s.trim_end());
+ /// ```
+ ///
+ /// Directionality:
+ ///
+ /// ```
+ /// let s = " English ";
+ /// assert!(Some('h') == s.trim_end().chars().rev().next());
+ ///
+ /// let s = " עברית ";
+ /// assert!(Some('ת') == s.trim_end().chars().rev().next());
+ /// ```
+ #[stable(feature = "trim_direction", since = "1.30.0")]
+ pub fn trim_end(&self) -> &str {
+ self.trim_end_matches(|c: char| c.is_whitespace())
+ }
+
/// Returns a string slice with leading whitespace removed.
///
/// 'Whitespace' is defined according to the terms of the Unicode Derived
/// assert!(Some('×¢') == s.trim_left().chars().next());
/// ```
#[stable(feature = "rust1", since = "1.0.0")]
+ #[rustc_deprecated(reason = "superseded by `trim_start`", since = "1.33.0")]
pub fn trim_left(&self) -> &str {
- self.trim_left_matches(|c: char| c.is_whitespace())
+ self.trim_start()
}
/// Returns a string slice with trailing whitespace removed.
/// assert!(Some('ת') == s.trim_right().chars().rev().next());
/// ```
#[stable(feature = "rust1", since = "1.0.0")]
+ #[rustc_deprecated(reason = "superseded by `trim_end`", since = "1.33.0")]
pub fn trim_right(&self) -> &str {
- self.trim_right_matches(|c: char| c.is_whitespace())
+ self.trim_end()
}
/// Returns a string slice with all prefixes and suffixes that match a
/// Basic usage:
///
/// ```
- /// assert_eq!("11foo1bar11".trim_left_matches('1'), "foo1bar11");
- /// assert_eq!("123foo1bar123".trim_left_matches(char::is_numeric), "foo1bar123");
+ /// assert_eq!("11foo1bar11".trim_start_matches('1'), "foo1bar11");
+ /// assert_eq!("123foo1bar123".trim_start_matches(char::is_numeric), "foo1bar123");
///
/// let x: &[_] = &['1', '2'];
- /// assert_eq!("12foo1bar12".trim_left_matches(x), "foo1bar12");
+ /// assert_eq!("12foo1bar12".trim_start_matches(x), "foo1bar12");
/// ```
- #[stable(feature = "rust1", since = "1.0.0")]
- pub fn trim_left_matches<'a, P: Pattern<'a>>(&'a self, pat: P) -> &'a str {
+ #[stable(feature = "trim_direction", since = "1.30.0")]
+ pub fn trim_start_matches<'a, P: Pattern<'a>>(&'a self, pat: P) -> &'a str {
let mut i = self.len();
let mut matcher = pat.into_searcher(self);
if let Some((a, _)) = matcher.next_reject() {
/// Simple patterns:
///
/// ```
- /// assert_eq!("11foo1bar11".trim_right_matches('1'), "11foo1bar");
- /// assert_eq!("123foo1bar123".trim_right_matches(char::is_numeric), "123foo1bar");
+ /// assert_eq!("11foo1bar11".trim_end_matches('1'), "11foo1bar");
+ /// assert_eq!("123foo1bar123".trim_end_matches(char::is_numeric), "123foo1bar");
///
/// let x: &[_] = &['1', '2'];
- /// assert_eq!("12foo1bar12".trim_right_matches(x), "12foo1bar");
+ /// assert_eq!("12foo1bar12".trim_end_matches(x), "12foo1bar");
/// ```
///
/// A more complex pattern, using a closure:
///
/// ```
- /// assert_eq!("1fooX".trim_right_matches(|c| c == '1' || c == 'X'), "1foo");
+ /// assert_eq!("1fooX".trim_end_matches(|c| c == '1' || c == 'X'), "1foo");
/// ```
- #[stable(feature = "rust1", since = "1.0.0")]
- pub fn trim_right_matches<'a, P: Pattern<'a>>(&'a self, pat: P) -> &'a str
+ #[stable(feature = "trim_direction", since = "1.30.0")]
+ pub fn trim_end_matches<'a, P: Pattern<'a>>(&'a self, pat: P) -> &'a str
where P::Searcher: ReverseSearcher<'a>
{
let mut j = 0;
}
}
+ /// Returns a string slice with all prefixes that match a pattern
+ /// repeatedly removed.
+ ///
+ /// The pattern can be a `&str`, [`char`], or a closure that determines if
+ /// a character matches.
+ ///
+ /// [`char`]: primitive.char.html
+ ///
+ /// # Text directionality
+ ///
+ /// A string is a sequence of bytes. 'Left' in this context means the first
+ /// position of that byte string; for a language like Arabic or Hebrew
+ /// which are 'right to left' rather than 'left to right', this will be
+ /// the _right_ side, not the left.
+ ///
+ /// # Examples
+ ///
+ /// Basic usage:
+ ///
+ /// ```
+ /// assert_eq!("11foo1bar11".trim_left_matches('1'), "foo1bar11");
+ /// assert_eq!("123foo1bar123".trim_left_matches(char::is_numeric), "foo1bar123");
+ ///
+ /// let x: &[_] = &['1', '2'];
+ /// assert_eq!("12foo1bar12".trim_left_matches(x), "foo1bar12");
+ /// ```
+ #[stable(feature = "rust1", since = "1.0.0")]
+ #[rustc_deprecated(reason = "superseded by `trim_start_matches`", since = "1.33.0")]
+ pub fn trim_left_matches<'a, P: Pattern<'a>>(&'a self, pat: P) -> &'a str {
+ self.trim_start_matches(pat)
+ }
+
+ /// Returns a string slice with all suffixes that match a pattern
+ /// repeatedly removed.
+ ///
+ /// The pattern can be a `&str`, [`char`], or a closure that
+ /// determines if a character matches.
+ ///
+ /// [`char`]: primitive.char.html
+ ///
+ /// # Text directionality
+ ///
+ /// A string is a sequence of bytes. 'Right' in this context means the last
+ /// position of that byte string; for a language like Arabic or Hebrew
+ /// which are 'right to left' rather than 'left to right', this will be
+ /// the _left_ side, not the right.
+ ///
+ /// # Examples
+ ///
+ /// Simple patterns:
+ ///
+ /// ```
+ /// assert_eq!("11foo1bar11".trim_right_matches('1'), "11foo1bar");
+ /// assert_eq!("123foo1bar123".trim_right_matches(char::is_numeric), "123foo1bar");
+ ///
+ /// let x: &[_] = &['1', '2'];
+ /// assert_eq!("12foo1bar12".trim_right_matches(x), "12foo1bar");
+ /// ```
+ ///
+ /// A more complex pattern, using a closure:
+ ///
+ /// ```
+ /// assert_eq!("1fooX".trim_right_matches(|c| c == '1' || c == 'X'), "1foo");
+ /// ```
+ #[stable(feature = "rust1", since = "1.0.0")]
+ #[rustc_deprecated(reason = "superseded by `trim_end_matches`", since = "1.33.0")]
+ pub fn trim_right_matches<'a, P: Pattern<'a>>(&'a self, pat: P) -> &'a str
+ where P::Searcher: ReverseSearcher<'a>
+ {
+ self.trim_end_matches(pat)
+ }
+
/// Parses this string slice into another type.
///
/// Because `parse` is so general, it can cause problems with type
use core::num::flt2dec::strategy::grisu::format_shortest_opt;
use core::num::flt2dec::{decode, DecodableFloat, FullDecoded, Decoded};
-use rand::{self, Rand, XorShiftRng};
-use rand::distributions::{IndependentSample, Range};
+use rand::{FromEntropy, XorShiftRng};
+use rand::distributions::{Distribution, Uniform};
pub fn decode_finite<T: DecodableFloat>(v: T) -> Decoded {
match decode(v).1 {
pub fn f32_random_equivalence_test<F, G>(f: F, g: G, k: usize, n: usize)
where F: FnMut(&Decoded, &mut [u8]) -> Option<(usize, i16)>,
G: FnMut(&Decoded, &mut [u8]) -> (usize, i16) {
- let mut rng: XorShiftRng = Rand::rand(&mut rand::thread_rng());
- let f32_range = Range::new(0x0000_0001u32, 0x7f80_0000);
+ let mut rng = XorShiftRng::from_entropy();
+ let f32_range = Uniform::new(0x0000_0001u32, 0x7f80_0000);
iterate("f32_random_equivalence_test", k, n, f, g, |_| {
- let x = f32::from_bits(f32_range.ind_sample(&mut rng));
+ let x = f32::from_bits(f32_range.sample(&mut rng));
decode_finite(x)
});
}
pub fn f64_random_equivalence_test<F, G>(f: F, g: G, k: usize, n: usize)
where F: FnMut(&Decoded, &mut [u8]) -> Option<(usize, i16)>,
G: FnMut(&Decoded, &mut [u8]) -> (usize, i16) {
- let mut rng: XorShiftRng = Rand::rand(&mut rand::thread_rng());
- let f64_range = Range::new(0x0000_0000_0000_0001u64, 0x7ff0_0000_0000_0000);
+ let mut rng = XorShiftRng::from_entropy();
+ let f64_range = Uniform::new(0x0000_0000_0000_0001u64, 0x7ff0_0000_0000_0000);
iterate("f64_random_equivalence_test", k, n, f, g, |_| {
- let x = f64::from_bits(f64_range.ind_sample(&mut rng));
+ let x = f64::from_bits(f64_range.sample(&mut rng));
decode_finite(x)
});
}
fn sort_unstable() {
use core::cmp::Ordering::{Equal, Greater, Less};
use core::slice::heapsort;
- use rand::{Rng, XorShiftRng};
+ use rand::{FromEntropy, Rng, XorShiftRng};
let mut v = [0; 600];
let mut tmp = [0; 600];
- let mut rng = XorShiftRng::new_unseeded();
+ let mut rng = XorShiftRng::from_entropy();
for len in (2..25).chain(500..510) {
let v = &mut v[0..len];
//! [win64]: http://msdn.microsoft.com/en-us/library/1eyas8tf.aspx
//! [llvm]: http://llvm.org/docs/ExceptionHandling.html#background-on-windows-exceptions
-#![allow(bad_style)]
+#![allow(nonstandard_style)]
#![allow(private_no_mangle_fns)]
use alloc::boxed::Box;
//! Unwinding implementation of top of native Win64 SEH,
//! however the unwind handler data (aka LSDA) uses GCC-compatible encoding.
-#![allow(bad_style)]
+#![allow(nonstandard_style)]
#![allow(private_no_mangle_fns)]
use alloc::boxed::Box;
// option. This file may not be copied, modified, or distributed
// except according to those terms.
-#![allow(bad_style)]
+#![allow(nonstandard_style)]
#![allow(dead_code)]
#![cfg(windows)]
syntax = { path = "../libsyntax" }
syntax_pos = { path = "../libsyntax_pos" }
backtrace = "0.3.3"
-parking_lot = "0.5.5"
+parking_lot = "0.6"
byteorder = { version = "1.1", features = ["i128"]}
chalk-engine = { version = "0.7.0", default-features=false }
rustc_fs_util = { path = "../librustc_fs_util" }
// expression to target
let guard_start = self.add_dummy_node(&[pat_exit]);
// Visit the guard expression
- let guard_exit = self.expr(&guard, guard_start);
-
+ let guard_exit = match guard {
+ hir::Guard::If(ref e) => self.expr(e, guard_start),
+ };
// #47295: We used to have very special case code
// here for when a pair of arms are both formed
// solely from constants, and if so, not add these
CanonicalPredicateGoal, CanonicalTypeOpProvePredicateGoal, CanonicalTypeOpNormalizeGoal,
};
use ty::{TyCtxt, FnSig, Instance, InstanceDef,
- ParamEnv, ParamEnvAnd, Predicate, PolyFnSig, PolyTraitRef, Ty, self};
+ ParamEnv, ParamEnvAnd, Predicate, PolyFnSig, PolyTraitRef, Ty};
use ty::subst::Substs;
// erase!() just makes tokens go away. It's used to specify which macro argument
// queries). Making them anonymous avoids hashing the result, which
// may save a bit of time.
[anon] EraseRegionsTy { ty: Ty<'tcx> },
- [anon] ConstToAllocation { val: &'tcx ty::Const<'tcx> },
[input] Freevars(DefId),
[input] MaybeUnusedTraitImport(DefId),
pub saved_files: Vec<(WorkProductFileKind, String)>,
}
-#[derive(Clone, Copy, Debug, RustcEncodable, RustcDecodable)]
+#[derive(Clone, Copy, Debug, RustcEncodable, RustcDecodable, PartialEq)]
pub enum WorkProductFileKind {
Object,
Bytecode,
pub fn walk_arm<'v, V: Visitor<'v>>(visitor: &mut V, arm: &'v Arm) {
walk_list!(visitor, visit_pat, &arm.pats);
- walk_list!(visitor, visit_expr, &arm.guard);
+ if let Some(ref g) = arm.guard {
+ match g {
+ Guard::If(ref e) => visitor.visit_expr(e),
+ }
+ }
visitor.visit_expr(&arm.body);
walk_list!(visitor, visit_attribute, &arm.attrs);
}
use lint::builtin::{self, PARENTHESIZED_PARAMS_IN_TYPES_AND_MODULES,
ELIDED_LIFETIMES_IN_PATHS};
use middle::cstore::CrateStore;
+use rustc_data_structures::fx::FxHashSet;
use rustc_data_structures::indexed_vec::IndexVec;
use rustc_data_structures::small_vec::OneVector;
use rustc_data_structures::thin_vec::ThinVec;
use util::common::FN_OUTPUT_NAME;
use util::nodemap::{DefIdMap, NodeMap};
-use std::collections::{BTreeMap, HashSet};
+use std::collections::BTreeMap;
use std::fmt::Debug;
use std::iter;
use std::mem;
hir::Arm {
attrs: self.lower_attrs(&arm.attrs),
pats: arm.pats.iter().map(|x| self.lower_pat(x)).collect(),
- guard: arm.guard.as_ref().map(|ref x| P(self.lower_expr(x))),
+ guard: match arm.guard {
+ Some(Guard::If(ref x)) => Some(hir::Guard::If(P(self.lower_expr(x)))),
+ _ => None,
+ },
body: P(self.lower_expr(&arm.body)),
}
}
exist_ty_id: NodeId,
collect_elided_lifetimes: bool,
currently_bound_lifetimes: Vec<hir::LifetimeName>,
- already_defined_lifetimes: HashSet<hir::LifetimeName>,
+ already_defined_lifetimes: FxHashSet<hir::LifetimeName>,
output_lifetimes: Vec<hir::GenericArg>,
output_lifetime_params: Vec<hir::GenericParam>,
}
exist_ty_id,
collect_elided_lifetimes: true,
currently_bound_lifetimes: Vec::new(),
- already_defined_lifetimes: HashSet::new(),
+ already_defined_lifetimes: FxHashSet::default(),
output_lifetimes: Vec::new(),
output_lifetime_params: Vec::new(),
};
pub struct Arm {
pub attrs: HirVec<Attribute>,
pub pats: HirVec<P<Pat>>,
- pub guard: Option<P<Expr>>,
+ pub guard: Option<Guard>,
pub body: P<Expr>,
}
+#[derive(Clone, RustcEncodable, RustcDecodable, Debug)]
+pub enum Guard {
+ If(P<Expr>),
+}
+
#[derive(Clone, RustcEncodable, RustcDecodable, Debug)]
pub struct Field {
pub id: NodeId,
self.print_pat(&p)?;
}
self.s.space()?;
- if let Some(ref e) = arm.guard {
- self.word_space("if")?;
- self.print_expr(&e)?;
- self.s.space()?;
+ if let Some(ref g) = arm.guard {
+ match g {
+ hir::Guard::If(e) => {
+ self.word_space("if")?;
+ self.print_expr(&e)?;
+ self.s.space()?;
+ }
+ }
}
self.word_space("=>")?;
use ich::{self, CachingSourceMapView, Fingerprint};
use middle::cstore::CrateStore;
use ty::{TyCtxt, fast_reject};
-use mir::interpret::AllocId;
use session::Session;
use std::cmp::Ord;
// CachingSourceMapView, so we initialize it lazily.
raw_source_map: &'a SourceMap,
caching_source_map: Option<CachingSourceMapView<'a>>,
-
- pub(super) alloc_id_recursion_tracker: FxHashSet<AllocId>,
}
#[derive(PartialEq, Eq, Clone, Copy)]
hash_spans: hash_spans_initial,
hash_bodies: true,
node_id_hashing_mode: NodeIdHashingMode::HashDefPath,
- alloc_id_recursion_tracker: Default::default(),
}
}
body
});
+impl_stable_hash_for!(enum hir::Guard {
+ If(expr),
+});
+
impl_stable_hash_for!(struct hir::Field {
id -> _,
ident,
match *self {
mir::UnsafetyViolationKind::General => {}
+ mir::UnsafetyViolationKind::MinConstFn => {}
mir::UnsafetyViolationKind::ExternStatic(lint_node_id) |
mir::UnsafetyViolationKind::BorrowPacked(lint_node_id) => {
lint_node_id.hash_stable(hcx, hasher);
level,
feature,
rustc_depr,
- rustc_const_unstable
+ const_stability
});
impl<'a> HashStable<StableHashingContext<'a>>
}
impl_stable_hash_for!(struct ::syntax::attr::RustcDeprecation { since, reason });
-impl_stable_hash_for!(struct ::syntax::attr::RustcConstUnstable { feature });
impl_stable_hash_for!(enum ::syntax::attr::IntType {
}
}
-impl_stable_hash_for!(struct ty::VariantDef {
- did,
- name,
- discr,
- fields,
- ctor_kind
-});
+impl<'a> HashStable<StableHashingContext<'a>> for ty::VariantFlags {
+ fn hash_stable<W: StableHasherResult>(&self,
+ _: &mut StableHashingContext<'a>,
+ hasher: &mut StableHasher<W>) {
+ std_hash::Hash::hash(self, hasher);
+ }
+}
impl_stable_hash_for!(enum ty::VariantDiscr {
Explicit(def_id),
ty::tls::with_opt(|tcx| {
trace!("hashing {:?}", *self);
let tcx = tcx.expect("can't hash AllocIds during hir lowering");
- let alloc_kind = tcx.alloc_map.lock().get(*self).expect("no value for AllocId");
+ let alloc_kind = tcx.alloc_map.lock().get(*self);
alloc_kind.hash_stable(hcx, hasher);
});
}
mem::discriminant(&self).hash_stable(hcx, hasher);
match *self {
+ FunctionArgCountMismatch |
DanglingPointerDeref |
DoubleFree |
InvalidMemoryAccess |
},
ReferencedConstant(ref err) => err.hash_stable(hcx, hasher),
MachineError(ref err) => err.hash_stable(hcx, hasher),
- FunctionPointerTyMismatch(a, b) => {
+ FunctionAbiMismatch(a, b) => {
+ a.hash_stable(hcx, hasher);
+ b.hash_stable(hcx, hasher)
+ },
+ FunctionArgMismatch(a, b) => {
a.hash_stable(hcx, hasher);
b.hash_stable(hcx, hasher)
},
use traits::{ObligationCause, ObligationCauseCode};
use ty::{self, subst::Subst, Region, Ty, TyCtxt, TypeFoldable, TyKind};
use ty::error::TypeError;
+use session::config::BorrowckMode;
use syntax::ast::DUMMY_NODE_ID;
use syntax_pos::{Pos, Span};
use errors::{Applicability, DiagnosticBuilder, DiagnosticStyledString};
) {
debug!("report_region_errors(): {} errors to start", errors.len());
- if will_later_be_reported_by_nll &&
- // FIXME: `use_mir_borrowck` seems wrong here...
- self.tcx.use_mir_borrowck() &&
- // ... this is a band-aid; may be better to explicitly
- // match on every borrowck_mode variant to guide decision
- // here.
- !self.tcx.migrate_borrowck() {
-
- // With `#![feature(nll)]`, we want to present a nice user
- // experience, so don't even mention the errors from the
- // AST checker.
- if self.tcx.features().nll {
- return;
+ // If the errors will later be reported by NLL, choose wether to display them or not based
+ // on the borrowck mode
+ if will_later_be_reported_by_nll {
+ match self.tcx.borrowck_mode() {
+ // If we're on AST or Migrate mode, report AST region errors
+ BorrowckMode::Ast | BorrowckMode::Migrate => {},
+ // If we're on MIR or Compare mode, don't report AST region errors as they should
+ // be reported by NLL
+ BorrowckMode::Compare | BorrowckMode::Mir => return,
}
-
- // But with nll, it's nice to have some note for later.
- for error in errors {
- match *error {
- RegionResolutionError::ConcreteFailure(ref origin, ..)
- | RegionResolutionError::GenericBoundFailure(ref origin, ..) => {
- self.tcx
- .sess
- .span_warn(origin.span(), "not reporting region error due to nll");
- }
-
- RegionResolutionError::SubSupConflict(ref rvo, ..) => {
- self.tcx
- .sess
- .span_warn(rvo.span(), "not reporting region error due to nll");
- }
- }
- }
-
- return;
}
// try to pre-process the errors, which will group some of them
self.resolve_type_vars_if_possible(t).to_string()
}
- pub fn shallow_resolve(&self, typ: Ty<'tcx>) -> Ty<'tcx> {
+ // We have this force-inlined variant of shallow_resolve() for the one
+ // callsite that is extremely hot. All other callsites use the normal
+ // variant.
+ #[inline(always)]
+ pub fn inlined_shallow_resolve(&self, typ: Ty<'tcx>) -> Ty<'tcx> {
match typ.sty {
ty::Infer(ty::TyVar(v)) => {
// Not entirely obvious: if `typ` is a type variable,
}
}
+ pub fn shallow_resolve(&self, typ: Ty<'tcx>) -> Ty<'tcx> {
+ self.inlined_shallow_resolve(typ)
+ }
+
pub fn resolve_type_vars_if_possible<T>(&self, value: &T) -> T
where T: TypeFoldable<'tcx>
{
#![feature(box_patterns)]
#![feature(box_syntax)]
-#![feature(const_fn)]
+#![cfg_attr(stage0, feature(const_fn))]
+#![cfg_attr(not(stage0), feature(min_const_fn))]
#![feature(core_intrinsics)]
#![feature(drain_filter)]
#![cfg_attr(windows, feature(libc))]
/// Lints indexed by name.
by_name: FxHashMap<String, TargetLint>,
- /// Map of registered lint groups to what lints they expand to. The bool
- /// is true if the lint group was added by a plugin.
- lint_groups: FxHashMap<&'static str, (Vec<LintId>, bool)>,
+ /// Map of registered lint groups to what lints they expand to. The first
+ /// bool is true if the lint group was added by a plugin. The optional string
+ /// is used to store the new names of deprecated lint group names.
+ lint_groups: FxHashMap<&'static str, (Vec<LintId>, bool, Option<&'static str>)>,
/// Extra info for future incompatibility lints, describing the
/// issue or RFC that caused the incompatibility.
/// compiled with the tool and therefore the lint was never
/// added to the `LintStore`. Otherwise the `LintId` will be
/// returned as if it where a rustc lint.
- Tool(Option<&'a [LintId]>),
+ Tool(Result<&'a [LintId], (Option<&'a [LintId]>, String)>),
}
impl LintStore {
let lints = lints.iter().filter(|f| f.edition == Some(*edition)).map(|f| f.id)
.collect::<Vec<_>>();
if !lints.is_empty() {
- self.register_group(sess, false, edition.lint_name(), lints)
+ self.register_group(sess, false, edition.lint_name(), None, lints)
}
}
self.future_incompatible.insert(lint.id, lint);
}
- self.register_group(sess, false, "future_incompatible", future_incompatible);
-
-
+ self.register_group(
+ sess,
+ false,
+ "future_incompatible",
+ None,
+ future_incompatible,
+ );
}
pub fn future_incompatible(&self, id: LintId) -> Option<&FutureIncompatibleInfo> {
self.future_incompatible.get(&id)
}
- pub fn register_group(&mut self, sess: Option<&Session>,
- from_plugin: bool, name: &'static str,
- to: Vec<LintId>) {
- let new = self.lint_groups.insert(name, (to, from_plugin)).is_none();
+ pub fn register_group(
+ &mut self,
+ sess: Option<&Session>,
+ from_plugin: bool,
+ name: &'static str,
+ deprecated_name: Option<&'static str>,
+ to: Vec<LintId>,
+ ) {
+ let new = self
+ .lint_groups
+ .insert(name, (to, from_plugin, None))
+ .is_none();
+ if let Some(deprecated) = deprecated_name {
+ self.lint_groups
+ .insert(deprecated, (vec![], from_plugin, Some(name)));
+ }
if !new {
let msg = format!("duplicate specification of lint group {}", name);
CheckLintNameResult::NoLint => {
Some(struct_err!(sess, E0602, "unknown lint: `{}`", lint_name))
}
- CheckLintNameResult::Tool(_) => unreachable!(),
+ CheckLintNameResult::Tool(result) => match result {
+ Err((Some(_), new_name)) => Some(sess.struct_warn(&format!(
+ "lint name `{}` is deprecated \
+ and does not have an effect anymore. \
+ Use: {}",
+ lint_name, new_name
+ ))),
+ _ => None,
+ },
};
if let Some(mut db) = db {
} else {
lint_name.to_string()
};
+ // If the lint was scoped with `tool::` check if the tool lint exists
if let Some(_) = tool_name {
match self.by_name.get(&complete_name) {
None => match self.lint_groups.get(&*complete_name) {
- None => return CheckLintNameResult::Tool(None),
- Some(ids) => return CheckLintNameResult::Tool(Some(&ids.0)),
+ None => return CheckLintNameResult::Tool(Err((None, String::new()))),
+ Some(ids) => return CheckLintNameResult::Tool(Ok(&ids.0)),
},
- Some(&Id(ref id)) => return CheckLintNameResult::Tool(Some(slice::from_ref(id))),
+ Some(&Id(ref id)) => return CheckLintNameResult::Tool(Ok(slice::from_ref(id))),
// If the lint was registered as removed or renamed by the lint tool, we don't need
// to treat tool_lints and rustc lints different and can use the code below.
_ => {}
}
match self.by_name.get(&complete_name) {
Some(&Renamed(ref new_name, _)) => CheckLintNameResult::Warning(
- format!("lint `{}` has been renamed to `{}`", lint_name, new_name),
+ format!(
+ "lint `{}` has been renamed to `{}`",
+ complete_name, new_name
+ ),
Some(new_name.to_owned()),
),
Some(&Removed(ref reason)) => CheckLintNameResult::Warning(
- format!("lint `{}` has been removed: `{}`", lint_name, reason),
+ format!("lint `{}` has been removed: `{}`", complete_name, reason),
None,
),
None => match self.lint_groups.get(&*complete_name) {
- None => CheckLintNameResult::NoLint,
- Some(ids) => CheckLintNameResult::Ok(&ids.0),
+ // If neither the lint, nor the lint group exists check if there is a `clippy::`
+ // variant of this lint
+ None => self.check_tool_name_for_backwards_compat(&complete_name, "clippy"),
+ Some(ids) => {
+ // Check if the lint group name is deprecated
+ if let Some(new_name) = ids.2 {
+ let lint_ids = self.lint_groups.get(new_name).unwrap();
+ return CheckLintNameResult::Tool(Err((
+ Some(&lint_ids.0),
+ new_name.to_string(),
+ )));
+ }
+ CheckLintNameResult::Ok(&ids.0)
+ }
},
Some(&Id(ref id)) => CheckLintNameResult::Ok(slice::from_ref(id)),
}
}
+
+ fn check_tool_name_for_backwards_compat(
+ &self,
+ lint_name: &str,
+ tool_name: &str,
+ ) -> CheckLintNameResult {
+ let complete_name = format!("{}::{}", tool_name, lint_name);
+ match self.by_name.get(&complete_name) {
+ None => match self.lint_groups.get(&*complete_name) {
+ // Now we are sure, that this lint exists nowhere
+ None => CheckLintNameResult::NoLint,
+ Some(ids) => {
+ // Reaching this would be weird, but lets cover this case anyway
+ if let Some(new_name) = ids.2 {
+ let lint_ids = self.lint_groups.get(new_name).unwrap();
+ return CheckLintNameResult::Tool(Err((
+ Some(&lint_ids.0),
+ new_name.to_string(),
+ )));
+ }
+ CheckLintNameResult::Tool(Err((Some(&ids.0), complete_name)))
+ }
+ },
+ Some(&Id(ref id)) => {
+ CheckLintNameResult::Tool(Err((Some(slice::from_ref(id)), complete_name)))
+ }
+ _ => CheckLintNameResult::NoLint,
+ }
+ }
}
/// Context for lint checking after type checking.
let gate_feature = !self.sess.features_untracked().tool_lints;
let known_tool = attr::is_known_lint_tool(lint_tool);
if gate_feature {
- feature_gate::emit_feature_err(&sess.parse_sess,
- "tool_lints",
- word.span,
- feature_gate::GateIssue::Language,
- &format!("scoped lint `{}` is experimental",
- word.ident));
+ feature_gate::emit_feature_err(
+ &sess.parse_sess,
+ "tool_lints",
+ word.span,
+ feature_gate::GateIssue::Language,
+ &format!("scoped lint `{}` is experimental", word.ident),
+ );
}
if !known_tool {
span_err!(
}
if gate_feature || !known_tool {
- continue
+ continue;
}
Some(lint_tool.as_str())
}
CheckLintNameResult::Tool(result) => {
- if let Some(ids) = result {
- let complete_name = &format!("{}::{}", tool_name.unwrap(), name);
- let src = LintSource::Node(Symbol::intern(complete_name), li.span);
- for id in ids {
- specs.insert(*id, (level, src));
+ match result {
+ Ok(ids) => {
+ let complete_name = &format!("{}::{}", tool_name.unwrap(), name);
+ let src = LintSource::Node(Symbol::intern(complete_name), li.span);
+ for id in ids {
+ specs.insert(*id, (level, src));
+ }
+ }
+ Err((Some(ids), new_lint_name)) => {
+ let lint = builtin::RENAMED_AND_REMOVED_LINTS;
+ let (lvl, src) =
+ self.sets
+ .get_lint_level(lint, self.cur, Some(&specs), &sess);
+ let msg = format!(
+ "lint name `{}` is deprecated \
+ and may not have an effect in the future. \
+ Also `cfg_attr(cargo-clippy)` won't be necessary anymore",
+ name
+ );
+ let mut err = lint::struct_lint_level(
+ self.sess,
+ lint,
+ lvl,
+ src,
+ Some(li.span.into()),
+ &msg,
+ );
+ err.span_suggestion_with_applicability(
+ li.span,
+ "change it to",
+ new_lint_name.to_string(),
+ Applicability::MachineApplicable,
+ ).emit();
+
+ let src = LintSource::Node(Symbol::intern(&new_lint_name), li.span);
+ for id in ids {
+ specs.insert(*id, (level, src));
+ }
+ }
+ Err((None, _)) => {
+ // If Tool(Err(None, _)) is returned, then either the lint does not
+ // exist in the tool or the code was not compiled with the tool and
+ // therefore the lint was never added to the `LintStore`. To detect
+ // this is the responsibility of the lint tool.
}
}
- // If Tool(None) is returned, then either the lint does not exist in the
- // tool or the code was not compiled with the tool and therefore the lint
- // was never added to the `LintStore`. To detect this is the responsibility
- // of the lint tool.
}
_ if !self.warn_about_weird_lints => {}
}
if let Some(ref guard) = arm.guard {
- self.consume_expr(&guard);
+ match guard {
+ hir::Guard::If(ref e) => self.consume_expr(e),
+ }
}
self.consume_expr(&arm.body);
let body_succ =
self.propagate_through_expr(&arm.body, succ);
let guard_succ =
- self.propagate_through_opt_expr(arm.guard.as_ref().map(|e| &**e), body_succ);
+ self.propagate_through_opt_expr(
+ arm.guard.as_ref().map(|g|
+ match g {
+ hir::Guard::If(e) => &**e,
+ }),
+ body_succ);
// only consider the first pattern; any later patterns must have
// the same bindings, and we also consider the first pattern to be
// the "authoritative" set of ids
fn resolve_arm<'a, 'tcx>(visitor: &mut RegionResolutionVisitor<'a, 'tcx>, arm: &'tcx hir::Arm) {
visitor.terminating_scopes.insert(arm.body.hir_id.local_id);
- if let Some(ref expr) = arm.guard {
- visitor.terminating_scopes.insert(expr.hir_id.local_id);
+ if let Some(ref g) = arm.guard {
+ match g {
+ hir::Guard::If(ref expr) => visitor.terminating_scopes.insert(expr.hir_id.local_id),
+ };
}
intravisit::walk_arm(visitor, arm);
},
feature: Symbol::intern("rustc_private"),
rustc_depr: None,
- rustc_const_unstable: None,
+ const_stability: None,
});
annotator.parent_stab = Some(stability);
}
use session::config;
use middle::lang_items;
+use rustc_data_structures::fx::FxHashSet;
use rustc_target::spec::PanicStrategy;
use syntax::ast;
use syntax::symbol::Symbol;
use hir;
use ty::TyCtxt;
-use std::collections::HashSet;
-
macro_rules! weak_lang_items {
($($name:ident, $item:ident, $sym:ident;)*) => (
return
}
- let mut missing = HashSet::new();
+ let mut missing = FxHashSet::default();
for &cnum in tcx.crates().iter() {
for &item in tcx.missing_lang_items(cnum).iter() {
missing.insert(item);
// except according to those terms.
use rustc_data_structures::indexed_vec::IndexVec;
-use rustc_data_structures::sync::{RwLock, ReadGuard};
+use rustc_data_structures::sync::{RwLock, MappedReadGuard, ReadGuard};
use rustc_data_structures::stable_hasher::{HashStable, StableHasher,
StableHasherResult};
use ich::StableHashingContext;
*self.predecessors.borrow_mut() = None;
}
- pub fn predecessors(&self, mir: &Mir) -> ReadGuard<IndexVec<BasicBlock, Vec<BasicBlock>>> {
+ pub fn predecessors(
+ &self,
+ mir: &Mir
+ ) -> MappedReadGuard<IndexVec<BasicBlock, Vec<BasicBlock>>> {
if self.predecessors.borrow().is_none() {
*self.predecessors.borrow_mut() = Some(calculate_predecessors(mir));
}
use std::{fmt, env};
use mir;
-use ty::{FnSig, Ty, layout};
+use ty::{Ty, layout};
use ty::layout::{Size, Align};
use rustc_data_structures::sync::Lrc;
+use rustc_target::spec::abi::Abi;
use super::{
Pointer, Lock, AccessKind
/// This variant is used by machines to signal their own errors that do not
/// match an existing variant
MachineError(String),
- FunctionPointerTyMismatch(FnSig<'tcx>, FnSig<'tcx>),
+
+ FunctionAbiMismatch(Abi, Abi),
+ FunctionArgMismatch(Ty<'tcx>, Ty<'tcx>),
+ FunctionArgCountMismatch,
NoMirFor(String),
UnterminatedCString(Pointer),
DanglingPointerDeref,
use self::EvalErrorKind::*;
match *self {
MachineError(ref inner) => inner,
- FunctionPointerTyMismatch(..) =>
- "tried to call a function through a function pointer of a different type",
+ FunctionAbiMismatch(..) | FunctionArgMismatch(..) | FunctionArgCountMismatch =>
+ "tried to call a function through a function pointer of incompatible type",
InvalidMemoryAccess =>
"tried to access memory through an invalid pointer",
DanglingPointerDeref =>
write!(f, "type validation failed: {}", err)
}
NoMirFor(ref func) => write!(f, "no mir for `{}`", func),
- FunctionPointerTyMismatch(sig, got) =>
- write!(f, "tried to call a function with sig {} through a \
- function pointer of type {}", sig, got),
+ FunctionAbiMismatch(caller_abi, callee_abi) =>
+ write!(f, "tried to call a function with ABI {:?} using caller ABI {:?}",
+ callee_abi, caller_abi),
+ FunctionArgMismatch(caller_ty, callee_ty) =>
+ write!(f, "tried to call a function with argument of type {:?} \
+ passing data of type {:?}",
+ callee_ty, caller_ty),
+ FunctionArgCountMismatch =>
+ write!(f, "tried to call a function with incorrect number of arguments"),
BoundsCheck { ref len, ref index } =>
write!(f, "index out of bounds: the len is {:?} but the index is {:?}", len, index),
ReallocatedWrongMemoryKind(ref old, ref new) =>
pub trait PointerArithmetic: layout::HasDataLayout {
// These are not supposed to be overridden.
+ #[inline(always)]
+ fn pointer_size(self) -> Size {
+ self.data_layout().pointer_size
+ }
+
//// Trunace the given value to the pointer size; also return whether there was an overflow
fn truncate_to_ptr(self, val: u128) -> (u64, bool) {
- let max_ptr_plus_1 = 1u128 << self.data_layout().pointer_size.bits();
+ let max_ptr_plus_1 = 1u128 << self.pointer_size().bits();
((val % max_ptr_plus_1) as u64, val >= max_ptr_plus_1)
}
impl<T: layout::HasDataLayout> PointerArithmetic for T {}
+/// Pointer is generic over the type that represents a reference to Allocations,
+/// thus making it possible for the most convenient representation to be used in
+/// each context.
+///
+/// Defaults to the index based and loosely coupled AllocId.
#[derive(Copy, Clone, Debug, Eq, PartialEq, Ord, PartialOrd, RustcEncodable, RustcDecodable, Hash)]
-pub struct Pointer {
- pub alloc_id: AllocId,
+pub struct Pointer<Id=AllocId> {
+ pub alloc_id: Id,
pub offset: Size,
}
/// Note that the bytes of a pointer represent the offset of the pointer
pub bytes: Vec<u8>,
/// Maps from byte addresses to allocations.
- /// Only the first byte of a pointer is inserted into the map.
+ /// Only the first byte of a pointer is inserted into the map; i.e.,
+ /// every entry in this map applies to `pointer_size` consecutive bytes starting
+ /// at the given offset.
pub relocations: Relocations,
/// Denotes undefined memory. Reading from undefined memory is forbidden in miri
pub undef_mask: UndefMask,
impl<'tcx> ::serialize::UseSpecializedDecodable for &'tcx Allocation {}
#[derive(Clone, PartialEq, Eq, PartialOrd, Ord, Hash, Debug, RustcEncodable, RustcDecodable)]
-pub struct Relocations(SortedMap<Size, AllocId>);
+pub struct Relocations<Id=AllocId>(SortedMap<Size, Id>);
-impl Relocations {
- pub fn new() -> Relocations {
+impl<Id> Relocations<Id> {
+ pub fn new() -> Self {
Relocations(SortedMap::new())
}
// The caller must guarantee that the given relocations are already sorted
// by address and contain no duplicates.
- pub fn from_presorted(r: Vec<(Size, AllocId)>) -> Relocations {
+ pub fn from_presorted(r: Vec<(Size, Id)>) -> Self {
Relocations(SortedMap::from_presorted_elements(r))
}
}
use ty::subst::Substs;
use hir::def_id::DefId;
-use super::{EvalResult, Pointer, PointerArithmetic, Allocation, AllocId, sign_extend};
+use super::{EvalResult, Pointer, PointerArithmetic, Allocation, AllocId, sign_extend, truncate};
/// Represents a constant value in Rust. Scalar and ScalarPair are optimizations which
/// matches the LocalValue optimizations for easy conversions between Value and ConstValue.
self.try_to_scalar()?.to_ptr().ok()
}
+ #[inline]
pub fn new_slice(
val: Scalar,
len: u64,
}.into())
}
+ #[inline]
pub fn new_dyn_trait(val: Scalar, vtable: Pointer) -> Self {
ConstValue::ScalarPair(val, Scalar::Ptr(vtable).into())
}
}
impl<'tcx> Scalar {
+ #[inline]
pub fn ptr_null(cx: impl HasDataLayout) -> Self {
Scalar::Bits {
bits: 0,
}
}
+ #[inline]
pub fn zst() -> Self {
Scalar::Bits { bits: 0, size: 0 }
}
+ #[inline]
pub fn ptr_signed_offset(self, i: i64, cx: impl HasDataLayout) -> EvalResult<'tcx, Self> {
let layout = cx.data_layout();
match self {
}
}
+ #[inline]
pub fn ptr_offset(self, i: Size, cx: impl HasDataLayout) -> EvalResult<'tcx, Self> {
let layout = cx.data_layout();
match self {
}
}
+ #[inline]
pub fn ptr_wrapping_signed_offset(self, i: i64, cx: impl HasDataLayout) -> Self {
let layout = cx.data_layout();
match self {
}
}
+ #[inline]
pub fn is_null_ptr(self, cx: impl HasDataLayout) -> bool {
match self {
Scalar::Bits { bits, size } => {
}
}
+ #[inline]
+ pub fn is_null(self) -> bool {
+ match self {
+ Scalar::Bits { bits, .. } => bits == 0,
+ Scalar::Ptr(_) => false
+ }
+ }
+
+ #[inline]
pub fn from_bool(b: bool) -> Self {
Scalar::Bits { bits: b as u128, size: 1 }
}
+ #[inline]
pub fn from_char(c: char) -> Self {
Scalar::Bits { bits: c as u128, size: 4 }
}
+ #[inline]
+ pub fn from_uint(i: impl Into<u128>, size: Size) -> Self {
+ let i = i.into();
+ debug_assert_eq!(truncate(i, size), i,
+ "Unsigned value {} does not fit in {} bits", i, size.bits());
+ Scalar::Bits { bits: i, size: size.bytes() as u8 }
+ }
+
+ #[inline]
+ pub fn from_int(i: impl Into<i128>, size: Size) -> Self {
+ let i = i.into();
+ // `into` performed sign extension, we have to truncate
+ let truncated = truncate(i as u128, size);
+ debug_assert_eq!(sign_extend(truncated, size) as i128, i,
+ "Signed value {} does not fit in {} bits", i, size.bits());
+ Scalar::Bits { bits: truncated, size: size.bytes() as u8 }
+ }
+
+ #[inline]
+ pub fn from_f32(f: f32) -> Self {
+ Scalar::Bits { bits: f.to_bits() as u128, size: 4 }
+ }
+
+ #[inline]
+ pub fn from_f64(f: f64) -> Self {
+ Scalar::Bits { bits: f.to_bits() as u128, size: 8 }
+ }
+
+ #[inline]
pub fn to_bits(self, target_size: Size) -> EvalResult<'tcx, u128> {
match self {
Scalar::Bits { bits, size } => {
}
}
+ #[inline]
pub fn to_ptr(self) -> EvalResult<'tcx, Pointer> {
match self {
Scalar::Bits { bits: 0, .. } => err!(InvalidNullPointerUsage),
}
}
+ #[inline]
pub fn is_bits(self) -> bool {
match self {
Scalar::Bits { .. } => true,
}
}
+ #[inline]
pub fn is_ptr(self) -> bool {
match self {
Scalar::Ptr(_) => true,
Ok(b as u32)
}
+ pub fn to_u64(self) -> EvalResult<'static, u64> {
+ let sz = Size::from_bits(64);
+ let b = self.to_bits(sz)?;
+ assert_eq!(b as u64 as u128, b);
+ Ok(b as u64)
+ }
+
pub fn to_usize(self, cx: impl HasDataLayout) -> EvalResult<'static, u64> {
let b = self.to_bits(cx.data_layout().pointer_size)?;
assert_eq!(b as u64 as u128, b);
Ok(b as i32)
}
+ pub fn to_i64(self) -> EvalResult<'static, i64> {
+ let sz = Size::from_bits(64);
+ let b = self.to_bits(sz)?;
+ let b = sign_extend(b, sz) as i128;
+ assert_eq!(b as i64 as i128, b);
+ Ok(b as i64)
+ }
+
pub fn to_isize(self, cx: impl HasDataLayout) -> EvalResult<'static, i64> {
let b = self.to_bits(cx.data_layout().pointer_size)?;
let b = sign_extend(b, cx.data_layout().pointer_size) as i128;
assert_eq!(b as i64 as i128, b);
Ok(b as i64)
}
+
+ #[inline]
+ pub fn to_f32(self) -> EvalResult<'static, f32> {
+ Ok(f32::from_bits(self.to_u32()?))
+ }
+
+ #[inline]
+ pub fn to_f64(self) -> EvalResult<'static, f64> {
+ Ok(f64::from_bits(self.to_u64()?))
+ }
}
impl From<Pointer> for Scalar {
/// 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, RustcEncodable, RustcDecodable, Hash)]
-pub enum Scalar {
+pub enum Scalar<Id=AllocId> {
/// The raw bytes of a simple value.
Bits {
/// The first `size` bytes are the value.
/// A pointer into an `Allocation`. An `Allocation` in the `memory` module has a list of
/// relocations, but a `Scalar` is only large enough to contain one, so we just represent the
/// relocation and its associated offset together as a `Pointer` here.
- Ptr(Pointer),
+ Ptr(Pointer<Id>),
}
#[derive(Clone, Copy, Debug, Eq, PartialEq, Ord, PartialOrd, RustcEncodable, RustcDecodable, Hash)]
-pub enum ScalarMaybeUndef {
- Scalar(Scalar),
+pub enum ScalarMaybeUndef<Id=AllocId> {
+ Scalar(Scalar<Id>),
Undef,
}
self.not_undef()?.to_char()
}
+ #[inline(always)]
+ pub fn to_f32(self) -> EvalResult<'tcx, f32> {
+ self.not_undef()?.to_f32()
+ }
+
+ #[inline(always)]
+ pub fn to_f64(self) -> EvalResult<'tcx, f64> {
+ self.not_undef()?.to_f64()
+ }
+
#[inline(always)]
pub fn to_u8(self) -> EvalResult<'tcx, u8> {
self.not_undef()?.to_u8()
self.not_undef()?.to_u32()
}
+ #[inline(always)]
+ pub fn to_u64(self) -> EvalResult<'tcx, u64> {
+ self.not_undef()?.to_u64()
+ }
+
#[inline(always)]
pub fn to_usize(self, cx: impl HasDataLayout) -> EvalResult<'tcx, u64> {
self.not_undef()?.to_usize(cx)
self.not_undef()?.to_i32()
}
+ #[inline(always)]
+ pub fn to_i64(self) -> EvalResult<'tcx, i64> {
+ self.not_undef()?.to_i64()
+ }
+
#[inline(always)]
pub fn to_isize(self, cx: impl HasDataLayout) -> EvalResult<'tcx, i64> {
self.not_undef()?.to_isize(cx)
use hir::def_id::DefId;
use hir::{self, HirId, InlineAsm};
use middle::region;
-use mir::interpret::{EvalErrorKind, Scalar, ScalarMaybeUndef, ConstValue};
+use mir::interpret::{ConstValue, EvalErrorKind, Scalar, ScalarMaybeUndef};
use mir::visit::MirVisitable;
use rustc_apfloat::ieee::{Double, Single};
use rustc_apfloat::Float;
use rustc_data_structures::graph::dominators::{dominators, Dominators};
use rustc_data_structures::graph::{self, GraphPredecessors, GraphSuccessors};
use rustc_data_structures::indexed_vec::{Idx, IndexVec};
-use smallvec::SmallVec;
use rustc_data_structures::sync::Lrc;
-use rustc_data_structures::sync::ReadGuard;
+use rustc_data_structures::sync::MappedReadGuard;
use rustc_serialize as serialize;
+use smallvec::SmallVec;
use std::borrow::Cow;
use std::fmt::{self, Debug, Formatter, Write};
use std::ops::{Index, IndexMut};
}
#[inline]
- pub fn predecessors(&self) -> ReadGuard<'_, IndexVec<BasicBlock, Vec<BasicBlock>>> {
+ pub fn predecessors(&self) -> MappedReadGuard<'_, IndexVec<BasicBlock, Vec<BasicBlock>>> {
self.cache.predecessors(self)
}
#[inline]
- pub fn predecessors_for(&self, bb: BasicBlock) -> ReadGuard<'_, Vec<BasicBlock>> {
- ReadGuard::map(self.predecessors(), |p| &p[bb])
+ pub fn predecessors_for(&self, bb: BasicBlock) -> MappedReadGuard<'_, Vec<BasicBlock>> {
+ MappedReadGuard::map(self.predecessors(), |p| &p[bb])
+ }
+
+ #[inline]
+ pub fn predecessor_locations(&self, loc: Location) -> impl Iterator<Item = Location> + '_ {
+ let if_zero_locations = if loc.statement_index == 0 {
+ let predecessor_blocks = self.predecessors_for(loc.block);
+ let num_predecessor_blocks = predecessor_blocks.len();
+ Some(
+ (0..num_predecessor_blocks)
+ .map(move |i| predecessor_blocks[i])
+ .map(move |bb| self.terminator_loc(bb)),
+ )
+ } else {
+ None
+ };
+
+ let if_not_zero_locations = if loc.statement_index == 0 {
+ None
+ } else {
+ Some(Location {
+ block: loc.block,
+ statement_index: loc.statement_index - 1,
+ })
+ };
+
+ if_zero_locations
+ .into_iter()
+ .flatten()
+ .chain(if_not_zero_locations)
}
#[inline]
});
mod binding_form_impl {
- use rustc_data_structures::stable_hasher::{HashStable, StableHasher, StableHasherResult};
use ich::StableHashingContext;
+ use rustc_data_structures::stable_hasher::{HashStable, StableHasher, StableHasherResult};
impl<'a, 'tcx> HashStable<StableHashingContext<'a>> for super::BindingForm<'tcx> {
- fn hash_stable<W: StableHasherResult>(&self,
- hcx: &mut StableHashingContext<'a>,
- hasher: &mut StableHasher<W>) {
+ fn hash_stable<W: StableHasherResult>(
+ &self,
+ hcx: &mut StableHashingContext<'a>,
+ hasher: &mut StableHasher<W>,
+ ) {
use super::BindingForm::*;
::std::mem::discriminant(self).hash_stable(hcx, hasher);
.map(|&u| {
let mut s = String::new();
let c = ty::Const {
- val: ConstValue::Scalar(Scalar::Bits {
+ val: ConstValue::Scalar(
+ Scalar::Bits {
bits: u,
size: size.bytes() as u8,
- }.into()),
+ }.into(),
+ ),
ty: switch_ty,
};
fmt_const_val(&mut s, &c).unwrap();
s.into()
- })
- .chain(iter::once(String::from("otherwise").into()))
+ }).chain(iter::once(String::from("otherwise").into()))
.collect()
}
Call {
/// active field number and is present only for union expressions
/// -- e.g. for a union expression `SomeUnion { c: .. }`, the
/// active field index would identity the field `c`
- Adt(&'tcx AdtDef, usize, &'tcx Substs<'tcx>, Option<CanonicalTy<'tcx>>, Option<usize>),
+ Adt(
+ &'tcx AdtDef,
+ usize,
+ &'tcx Substs<'tcx>,
+ Option<CanonicalTy<'tcx>>,
+ Option<usize>,
+ ),
Closure(DefId, ClosureSubsts<'tcx>),
Generator(DefId, GeneratorSubsts<'tcx>, hir::GeneratorMovability),
return write!(f, "{:?}{}", ((bits as i128) << shift) >> shift, i);
}
Char => return write!(f, "{:?}", ::std::char::from_u32(bits as u32).unwrap()),
- _ => {},
+ _ => {}
}
}
// print function definitons
let alloc = tcx.alloc_map.lock().get(ptr.alloc_id);
if let Some(interpret::AllocType::Memory(alloc)) = alloc {
assert_eq!(len as usize as u128, len);
- let slice = &alloc
- .bytes
- [(ptr.offset.bytes() as usize)..]
- [..(len as usize)];
+ 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)
+ write!(f, "pointer to erroneous constant {:?}, {:?}", ptr, len)
}
});
}
#[derive(Copy, Clone, Debug, PartialEq, Eq, Hash, RustcEncodable, RustcDecodable)]
pub enum UnsafetyViolationKind {
General,
+ /// unsafety is not allowed at all in min const fn
+ MinConstFn,
ExternStatic(ast::NodeId),
BorrowPacked(ast::NodeId),
}
let kind = box match **kind {
AggregateKind::Array(ty) => AggregateKind::Array(ty.fold_with(folder)),
AggregateKind::Tuple => AggregateKind::Tuple,
- AggregateKind::Adt(def, v, substs, user_ty, n) => {
- AggregateKind::Adt(
- def,
- v,
- substs.fold_with(folder),
- user_ty.fold_with(folder),
- n,
- )
- }
+ AggregateKind::Adt(def, v, substs, user_ty, n) => AggregateKind::Adt(
+ def,
+ v,
+ substs.fold_with(folder),
+ user_ty.fold_with(folder),
+ n,
+ ),
AggregateKind::Closure(id, substs) => {
AggregateKind::Closure(id, substs.fold_with(folder))
}
(match **kind {
AggregateKind::Array(ty) => ty.visit_with(visitor),
AggregateKind::Tuple => false,
- AggregateKind::Adt(_, _, substs, user_ty, _) =>
- substs.visit_with(visitor) || user_ty.visit_with(visitor),
+ AggregateKind::Adt(_, _, substs, user_ty, _) => {
+ substs.visit_with(visitor) || user_ty.visit_with(visitor)
+ }
AggregateKind::Closure(_, substs) => substs.visit_with(visitor),
AggregateKind::Generator(_, substs, _) => substs.visit_with(visitor),
}) || fields.visit_with(visitor)
use std::collections::btree_map::Keys as BTreeMapKeysIter;
use std::collections::btree_map::Values as BTreeMapValuesIter;
+use rustc_data_structures::fx::FxHashSet;
use std::{fmt, str};
use std::hash::Hasher;
use std::collections::hash_map::DefaultHasher;
-use std::collections::HashSet;
use std::iter::FromIterator;
use std::path::{Path, PathBuf};
SizeMin, // -Oz
}
-#[derive(Clone, Copy, PartialEq, Hash)]
+#[derive(Clone, Copy, PartialEq, Hash, Debug)]
pub enum Lto {
/// Don't do any LTO whatsoever
No,
let max_atomic_width = sess.target.target.max_atomic_width();
let atomic_cas = sess.target.target.options.atomic_cas;
- let mut ret = HashSet::new();
+ let mut ret = FxHashSet::default();
// Target bindings.
ret.insert((Symbol::intern("target_os"), Some(Symbol::intern(os))));
if let Some(ref fam) = sess.target.target.options.target_family {
pub use self::FileMatch::*;
+use rustc_data_structures::fx::FxHashSet;
use std::borrow::Cow;
-use std::collections::HashSet;
use std::env;
use std::fs;
use std::path::{Path, PathBuf};
pub fn for_each_lib_search_path<F>(&self, mut f: F) where
F: FnMut(&Path, PathKind)
{
- let mut visited_dirs = HashSet::new();
+ let mut visited_dirs = FxHashSet::default();
for (path, kind) in self.search_paths.iter(self.kind) {
f(path, kind);
use std;
use std::cell::{self, Cell, RefCell};
-use std::collections::HashMap;
use std::env;
use std::fmt;
use std::io::Write;
/// Map from imported macro spans (which consist of
/// the localized span for the macro body) to the
/// macro name and definition span in the source crate.
- pub imported_macro_spans: OneThread<RefCell<HashMap<Span, (String, Span)>>>,
+ pub imported_macro_spans: OneThread<RefCell<FxHashMap<Span, (String, Span)>>>,
incr_comp_session: OneThread<RefCell<IncrCompSession>>,
return config::Lto::No;
}
- // Right now ThinLTO isn't compatible with incremental compilation.
- if self.opts.incremental.is_some() {
- return config::Lto::No;
- }
-
// Now we're in "defaults" territory. By default we enable ThinLTO for
// optimized compiles (anything greater than O0).
match self.opts.optimize {
injected_allocator: Once::new(),
allocator_kind: Once::new(),
injected_panic_runtime: Once::new(),
- imported_macro_spans: OneThread::new(RefCell::new(HashMap::new())),
+ imported_macro_spans: OneThread::new(RefCell::new(FxHashMap::default())),
incr_comp_session: OneThread::new(RefCell::new(IncrCompSession::NotInitialized)),
self_profiling: Lock::new(SelfProfiler::new()),
profile_channel: Lock::new(None),
// commandline argument, you can do so here.
fn validate_commandline_args_with_session_available(sess: &Session) {
- if sess.lto() != Lto::No && sess.opts.incremental.is_some() {
- sess.err("can't perform LTO when compiling incrementally");
+ if sess.opts.incremental.is_some() {
+ match sess.lto() {
+ Lto::Yes |
+ Lto::Thin |
+ Lto::Fat => {
+ sess.err("can't perform LTO when compiling incrementally");
+ }
+ Lto::ThinLocal |
+ Lto::No => {
+ // This is fine
+ }
+ }
}
// Since we don't know if code in an rlib will be linked to statically or
// doing more work yet
if !pending_obligation.stalled_on.is_empty() {
if pending_obligation.stalled_on.iter().all(|&ty| {
- let resolved_ty = self.selcx.infcx().shallow_resolve(&ty);
+ // Use the force-inlined variant of shallow_resolve() because this code is hot.
+ let resolved_ty = self.selcx.infcx().inlined_shallow_resolve(&ty);
resolved_ty == ty // nothing changed here
}) {
debug!("process_predicate: pending obligation {:?} still stalled on {:?}",
local as usize == global as usize
}
+ /// Returns true if this function must conform to `min_const_fn`
+ pub fn is_min_const_fn(self, def_id: DefId) -> bool {
+ if self.features().staged_api {
+ // some intrinsics are waved through if called inside the
+ // standard library. Users never need to call them directly
+ if let abi::Abi::RustIntrinsic = self.fn_sig(def_id).abi() {
+ assert!(!self.is_const_fn(def_id));
+ match &self.item_name(def_id).as_str()[..] {
+ | "size_of"
+ | "min_align_of"
+ => return true,
+ _ => {},
+ }
+ }
+ // in order for a libstd function to be considered min_const_fn
+ // it needs to be stable and have no `rustc_const_unstable` attribute
+ match self.lookup_stability(def_id) {
+ // stable functions with unstable const fn aren't `min_const_fn`
+ Some(&attr::Stability { const_stability: Some(_), .. }) => false,
+ // unstable functions don't need to conform
+ Some(&attr::Stability { ref level, .. }) if level.is_unstable() => false,
+ // everything else needs to conform, because it would be callable from
+ // other `min_const_fn` functions
+ _ => true,
+ }
+ } else {
+ // users enabling the `const_fn` can do what they want
+ !self.sess.features_untracked().const_fn
+ }
+ }
+
/// Create a type context and call the closure with a `TyCtxt` reference
/// to the context. The closure enforces that the type context and any interned
/// value (types, substs, etc.) can only be used while `ty::tls` has a valid
const IS_FUNDAMENTAL = 1 << 2;
const IS_UNION = 1 << 3;
const IS_BOX = 1 << 4;
- /// Indicates whether this abstract data type will be expanded on in future (new
- /// fields/variants) and as such, whether downstream crates must match exhaustively on the
- /// fields/variants of this data type.
- ///
- /// See RFC 2008 (<https://github.com/rust-lang/rfcs/pull/2008>).
- const IS_NON_EXHAUSTIVE = 1 << 5;
+ /// Indicates whether the variant list of this ADT is `#[non_exhaustive]`.
+ /// (i.e., this flag is never set unless this ADT is an enum).
+ const IS_VARIANT_LIST_NON_EXHAUSTIVE = 1 << 5;
+ }
+}
+
+bitflags! {
+ pub struct VariantFlags: u32 {
+ const NO_VARIANT_FLAGS = 0;
+ /// Indicates whether the field list of this variant is `#[non_exhaustive]`.
+ const IS_FIELD_LIST_NON_EXHAUSTIVE = 1 << 0;
}
}
pub discr: VariantDiscr,
pub fields: Vec<FieldDef>,
pub ctor_kind: CtorKind,
+ flags: VariantFlags,
}
+impl<'a, 'gcx, 'tcx> VariantDef {
+ /// Create a new `VariantDef`.
+ ///
+ /// - `did` is the DefId used for the variant - for tuple-structs, it is the constructor DefId,
+ /// and for everything else, it is the variant DefId.
+ /// - `attribute_def_id` is the DefId that has the variant's attributes.
+ pub fn new(tcx: TyCtxt<'a, 'gcx, 'tcx>,
+ did: DefId,
+ name: Name,
+ discr: VariantDiscr,
+ fields: Vec<FieldDef>,
+ adt_kind: AdtKind,
+ ctor_kind: CtorKind)
+ -> Self
+ {
+ debug!("VariantDef::new({:?}, {:?}, {:?}, {:?}, {:?}, {:?})", did, name, discr, fields,
+ adt_kind, ctor_kind);
+ let mut flags = VariantFlags::NO_VARIANT_FLAGS;
+ if adt_kind == AdtKind::Struct && tcx.has_attr(did, "non_exhaustive") {
+ debug!("found non-exhaustive field list for {:?}", did);
+ flags = flags | VariantFlags::IS_FIELD_LIST_NON_EXHAUSTIVE;
+ }
+ VariantDef {
+ did,
+ name,
+ discr,
+ fields,
+ ctor_kind,
+ flags
+ }
+ }
+
+ #[inline]
+ pub fn is_field_list_non_exhaustive(&self) -> bool {
+ self.flags.intersects(VariantFlags::IS_FIELD_LIST_NON_EXHAUSTIVE)
+ }
+}
+
+impl_stable_hash_for!(struct VariantDef {
+ did,
+ name,
+ discr,
+ fields,
+ ctor_kind,
+ flags
+});
+
#[derive(Copy, Clone, Debug, PartialEq, Eq, RustcEncodable, RustcDecodable)]
pub enum VariantDiscr {
/// Explicit value for this variant, i.e. `X = 123`.
/// Represents the repr options provided by the user,
-#[derive(Copy, Clone, Eq, PartialEq, RustcEncodable, RustcDecodable, Default)]
+#[derive(Copy, Clone, Debug, Eq, PartialEq, RustcEncodable, RustcDecodable, Default)]
pub struct ReprOptions {
pub int: Option<attr::IntType>,
pub align: u32,
kind: AdtKind,
variants: Vec<VariantDef>,
repr: ReprOptions) -> Self {
+ debug!("AdtDef::new({:?}, {:?}, {:?}, {:?})", did, kind, variants, repr);
let mut flags = AdtFlags::NO_ADT_FLAGS;
let attrs = tcx.get_attrs(did);
if attr::contains_name(&attrs, "fundamental") {
if Some(did) == tcx.lang_items().owned_box() {
flags = flags | AdtFlags::IS_BOX;
}
- if tcx.has_attr(did, "non_exhaustive") {
- flags = flags | AdtFlags::IS_NON_EXHAUSTIVE;
+ if kind == AdtKind::Enum && tcx.has_attr(did, "non_exhaustive") {
+ debug!("found non-exhaustive variant list for {:?}", did);
+ flags = flags | AdtFlags::IS_VARIANT_LIST_NON_EXHAUSTIVE;
}
match kind {
AdtKind::Enum => flags = flags | AdtFlags::IS_ENUM,
}
#[inline]
- pub fn is_non_exhaustive(&self) -> bool {
- self.flags.intersects(AdtFlags::IS_NON_EXHAUSTIVE)
+ pub fn is_variant_list_non_exhaustive(&self) -> bool {
+ self.flags.intersects(AdtFlags::IS_VARIANT_LIST_NON_EXHAUSTIVE)
}
/// Returns the kind of the ADT - Struct or Enum.
}
}
-impl<'tcx> QueryDescription<'tcx> for queries::const_to_allocation<'tcx> {
- fn describe(_tcx: TyCtxt, val: &'tcx ty::Const<'tcx>) -> String {
- format!("converting constant `{:?}` to an allocation", val)
- }
-}
-
impl<'tcx> QueryDescription<'tcx> for queries::erase_regions_ty<'tcx> {
fn describe(_tcx: TyCtxt, ty: Ty<'tcx>) -> String {
format!("erasing regions from `{:?}`", ty)
}
}
-impl<'tcx> QueryDescription<'tcx> for queries::compile_codegen_unit<'tcx> {
- fn describe(_tcx: TyCtxt, _: InternedString) -> String {
- "compile_codegen_unit".to_string()
- }
-}
-
impl<'tcx> QueryDescription<'tcx> for queries::output_filenames<'tcx> {
fn describe(_tcx: TyCtxt, _: CrateNum) -> String {
"output_filenames".to_string()
#![allow(warnings)]
use std::mem;
+use rustc_data_structures::fx::FxHashSet;
use rustc_data_structures::sync::{Lock, LockGuard, Lrc, Weak};
use rustc_data_structures::OnDrop;
use syntax_pos::Span;
use errors::Diagnostic;
use std::process;
use std::{fmt, ptr};
-use std::collections::HashSet;
+
#[cfg(parallel_queries)]
use {
rayon_core,
fn cycle_check<'tcx>(query: Lrc<QueryJob<'tcx>>,
span: Span,
stack: &mut Vec<(Span, Lrc<QueryJob<'tcx>>)>,
- visited: &mut HashSet<*const QueryJob<'tcx>>
+ visited: &mut FxHashSet<*const QueryJob<'tcx>>
) -> Option<Option<Waiter<'tcx>>> {
if visited.contains(&query.as_ptr()) {
return if let Some(p) = stack.iter().position(|q| q.1.as_ptr() == query.as_ptr()) {
#[cfg(parallel_queries)]
fn connected_to_root<'tcx>(
query: Lrc<QueryJob<'tcx>>,
- visited: &mut HashSet<*const QueryJob<'tcx>>
+ visited: &mut FxHashSet<*const QueryJob<'tcx>>
) -> bool {
// We already visited this or we're deliberately ignoring it
if visited.contains(&query.as_ptr()) {
wakelist: &mut Vec<Lrc<QueryWaiter<'tcx>>>,
tcx: TyCtxt<'_, 'tcx, '_>
) -> bool {
- let mut visited = HashSet::new();
+ let mut visited = FxHashSet::default();
let mut stack = Vec::new();
// Look for a cycle starting with the last query in `jobs`
if let Some(waiter) = cycle_check(jobs.pop().unwrap(),
// connected to queries outside the cycle
let entry_points: Vec<Lrc<QueryJob<'tcx>>> = stack.iter().filter_map(|query| {
// Mark all the other queries in the cycle as already visited
- let mut visited = HashSet::from_iter(stack.iter().filter_map(|q| {
+ let mut visited = FxHashSet::from_iter(stack.iter().filter_map(|q| {
if q.1.as_ptr() != query.1.as_ptr() {
Some(q.1.as_ptr())
} else {
use middle::lang_items::{LanguageItems, LangItem};
use middle::exported_symbols::{SymbolExportLevel, ExportedSymbol};
use mir::interpret::ConstEvalResult;
-use mir::mono::{CodegenUnit, Stats};
+use mir::mono::CodegenUnit;
use mir;
-use mir::interpret::{GlobalId, Allocation};
+use mir::interpret::GlobalId;
use session::{CompileResult, CrateDisambiguator};
use session::config::OutputFilenames;
use traits::{self, Vtable};
/// other items (such as enum variant explicit discriminants).
[] fn const_eval: const_eval_dep_node(ty::ParamEnvAnd<'tcx, GlobalId<'tcx>>)
-> ConstEvalResult<'tcx>,
-
- /// Converts a constant value to a constant allocation
- [] fn const_to_allocation: const_to_allocation(
- &'tcx ty::Const<'tcx>
- ) -> &'tcx Allocation,
},
TypeChecking {
-> (Arc<DefIdSet>, Arc<Vec<Arc<CodegenUnit<'tcx>>>>),
[] fn is_codegened_item: IsCodegenedItem(DefId) -> bool,
[] fn codegen_unit: CodegenUnit(InternedString) -> Arc<CodegenUnit<'tcx>>,
- [] fn compile_codegen_unit: CompileCodegenUnit(InternedString) -> Stats,
},
Other {
DepConstructor::EraseRegionsTy { ty }
}
-fn const_to_allocation<'tcx>(
- val: &'tcx ty::Const<'tcx>,
-) -> DepConstructor<'tcx> {
- DepConstructor::ConstToAllocation { val }
-}
-
fn type_param_predicates<'tcx>((item_id, param_id): (DefId, DefId)) -> DepConstructor<'tcx> {
DepConstructor::TypeParamPredicates {
item_id,
}
}
- #[allow(bad_style)]
+ #[allow(nonstandard_style)]
#[derive(Copy, Clone, Debug, PartialEq, Eq, Hash)]
pub enum Query<$tcx> {
$($(#[$attr])* $name($K)),*
pub mod queries {
use std::marker::PhantomData;
- $(#[allow(bad_style)]
+ $(#[allow(nonstandard_style)]
pub struct $name<$tcx> {
data: PhantomData<&$tcx ()>
})*
DepKind::FulfillObligation |
DepKind::VtableMethods |
DepKind::EraseRegionsTy |
- DepKind::ConstToAllocation |
DepKind::NormalizeProjectionTy |
DepKind::NormalizeTyAfterErasingRegions |
DepKind::ImpliedOutlivesBounds |
// option. This file may not be copied, modified, or distributed
// except according to those terms.
-use rustc_data_structures::sync::{RwLock, ReadGuard};
+use rustc_data_structures::sync::{RwLock, ReadGuard, MappedReadGuard};
use std::mem;
/// The `Steal` struct is intended to used as the value for a query.
}
}
- pub fn borrow(&self) -> ReadGuard<T> {
+ pub fn borrow(&self) -> MappedReadGuard<T> {
ReadGuard::map(self.value.borrow(), |opt| match *opt {
None => bug!("attempted to read from stolen value"),
Some(ref v) => v
use ::mir::interpret::EvalErrorKind::*;
Some(match *self {
MachineError(ref err) => MachineError(err.clone()),
- FunctionPointerTyMismatch(a, b) => FunctionPointerTyMismatch(
+ FunctionAbiMismatch(a, b) => FunctionAbiMismatch(a, b),
+ FunctionArgMismatch(a, b) => FunctionArgMismatch(
tcx.lift(&a)?,
tcx.lift(&b)?,
),
+ FunctionArgCountMismatch => FunctionArgCountMismatch,
NoMirFor(ref s) => NoMirFor(s.clone()),
UnterminatedCString(ptr) => UnterminatedCString(ptr),
DanglingPointerDeref => DanglingPointerDeref,
pub dump_profq_msg_log:bool,
}
-#[allow(bad_style)]
+#[allow(nonstandard_style)]
#[derive(Clone, Debug, PartialEq, Eq)]
pub struct QueryMsg {
pub query: &'static str,
$($name),*
}
- #[allow(bad_style)]
+ #[allow(nonstandard_style)]
struct Categories<T> {
$($name: T),*
}
// option. This file may not be copied, modified, or distributed
// except according to those terms.
-use std::collections::HashMap;
+use rustc_data_structures::fx::FxHashMap;
use std::fs::File;
use std::io::prelude::*;
use std::marker::PhantomData;
#[derive(Clone)]
pub struct TimeGraph {
- data: Arc<Mutex<HashMap<TimelineId, PerThread>>>,
+ data: Arc<Mutex<FxHashMap<TimelineId, PerThread>>>,
}
#[derive(Clone, Copy)]
impl TimeGraph {
pub fn new() -> TimeGraph {
TimeGraph {
- data: Arc::new(Mutex::new(HashMap::new()))
+ data: Arc::new(Mutex::new(FxHashMap::default()))
}
}
num_cpus = "1.0"
rustc-demangle = "0.1.4"
rustc_llvm = { path = "../librustc_llvm" }
+memmap = "0.6"
[features]
# This is used to convince Cargo to separately cache builds of `rustc_codegen_llvm`
// option. This file may not be copied, modified, or distributed
// except according to those terms.
-use std::collections::HashMap;
+use rustc_data_structures::fx::FxHashMap;
use std::ffi::{OsStr, OsString};
use std::fs::{self, File};
use std::io::prelude::*;
/// For all the linkers we support, and information they might
/// need out of the shared crate context before we get rid of it.
pub struct LinkerInfo {
- exports: HashMap<CrateType, Vec<String>>,
+ exports: FxHashMap<CrateType, Vec<String>>,
}
impl LinkerInfo {
use back::bytecode::{DecodedBytecode, RLIB_BYTECODE_EXTENSION};
use back::symbol_export;
use back::write::{ModuleConfig, with_llvm_pmb, CodegenContext};
-use back::write::{self, DiagnosticHandlers};
+use back::write::{self, DiagnosticHandlers, pre_lto_bitcode_filename};
use errors::{FatalError, Handler};
use llvm::archive_ro::ArchiveRO;
use llvm::{True, False};
use llvm;
+use memmap;
+use rustc::dep_graph::WorkProduct;
use rustc::hir::def_id::LOCAL_CRATE;
use rustc::middle::exported_symbols::SymbolExportLevel;
use rustc::session::config::{self, Lto};
use rustc::util::common::time_ext;
+use rustc_data_structures::fx::FxHashMap;
use time_graph::Timeline;
-use {ModuleCodegen, ModuleLlvm, ModuleKind, ModuleSource};
+use {ModuleCodegen, ModuleLlvm, ModuleKind};
use libc;
-use std::ffi::CString;
+use std::ffi::{CStr, CString};
+use std::fs;
use std::ptr;
use std::slice;
use std::sync::Arc;
let module = module.take().unwrap();
{
let config = cgcx.config(module.kind);
- let llmod = module.llvm().unwrap().llmod();
- let tm = &*module.llvm().unwrap().tm;
+ let llmod = module.module_llvm.llmod();
+ let tm = &*module.module_llvm.tm;
run_pass_manager(cgcx, tm, llmod, config, false);
timeline.record("fat-done");
}
}
}
+/// Performs LTO, which in the case of full LTO means merging all modules into
+/// a single one and returning it for further optimizing. For ThinLTO, it will
+/// do the global analysis necessary and return two lists, one of the modules
+/// the need optimization and another for modules that can simply be copied over
+/// from the incr. comp. cache.
pub(crate) fn run(cgcx: &CodegenContext,
modules: Vec<ModuleCodegen>,
+ cached_modules: Vec<(SerializedModule, WorkProduct)>,
timeline: &mut Timeline)
- -> Result<Vec<LtoModuleCodegen>, FatalError>
+ -> Result<(Vec<LtoModuleCodegen>, Vec<WorkProduct>), FatalError>
{
let diag_handler = cgcx.create_diag_handler();
let export_threshold = match cgcx.lto {
}
}
- let arr = symbol_white_list.iter().map(|c| c.as_ptr()).collect::<Vec<_>>();
+ let symbol_white_list = symbol_white_list.iter()
+ .map(|c| c.as_ptr())
+ .collect::<Vec<_>>();
match cgcx.lto {
Lto::Yes | // `-C lto` == fat LTO by default
Lto::Fat => {
- fat_lto(cgcx, &diag_handler, modules, upstream_modules, &arr, timeline)
+ assert!(cached_modules.is_empty());
+ let opt_jobs = fat_lto(cgcx,
+ &diag_handler,
+ modules,
+ upstream_modules,
+ &symbol_white_list,
+ timeline);
+ opt_jobs.map(|opt_jobs| (opt_jobs, vec![]))
}
Lto::Thin |
Lto::ThinLocal => {
unreachable!("We should never reach this case if the LTO step \
is deferred to the linker");
}
- thin_lto(&diag_handler, modules, upstream_modules, &arr, timeline)
+ thin_lto(cgcx,
+ &diag_handler,
+ modules,
+ upstream_modules,
+ cached_modules,
+ &symbol_white_list,
+ timeline)
}
Lto::No => unreachable!(),
}
.filter(|&(_, module)| module.kind == ModuleKind::Regular)
.map(|(i, module)| {
let cost = unsafe {
- llvm::LLVMRustModuleCost(module.llvm().unwrap().llmod())
+ llvm::LLVMRustModuleCost(module.module_llvm.llmod())
};
(cost, i)
})
let mut serialized_bitcode = Vec::new();
{
let (llcx, llmod) = {
- let llvm = module.llvm().expect("can't lto pre-codegened modules");
+ let llvm = &module.module_llvm;
(&llvm.llcx, llvm.llmod())
};
info!("using {:?} as a base module", module.name);
// way we know of to do that is to serialize them to a string and them parse
// them later. Not great but hey, that's why it's "fat" LTO, right?
for module in modules {
- let llvm = module.llvm().expect("can't lto pre-codegened modules");
- let buffer = ModuleBuffer::new(llvm.llmod());
+ let buffer = ModuleBuffer::new(module.module_llvm.llmod());
let llmod_id = CString::new(&module.name[..]).unwrap();
serialized_modules.push((SerializedModule::Local(buffer), llmod_id));
}
/// calculating the *index* for ThinLTO. This index will then be shared amongst
/// all of the `LtoModuleCodegen` units returned below and destroyed once
/// they all go out of scope.
-fn thin_lto(diag_handler: &Handler,
+fn thin_lto(cgcx: &CodegenContext,
+ diag_handler: &Handler,
modules: Vec<ModuleCodegen>,
serialized_modules: Vec<(SerializedModule, CString)>,
+ cached_modules: Vec<(SerializedModule, WorkProduct)>,
symbol_white_list: &[*const libc::c_char],
timeline: &mut Timeline)
- -> Result<Vec<LtoModuleCodegen>, FatalError>
+ -> Result<(Vec<LtoModuleCodegen>, Vec<WorkProduct>), FatalError>
{
unsafe {
info!("going for that thin, thin LTO");
+ let green_modules: FxHashMap<_, _> = cached_modules
+ .iter()
+ .map(|&(_, ref wp)| (wp.cgu_name.clone(), wp.clone()))
+ .collect();
+
let mut thin_buffers = Vec::new();
let mut module_names = Vec::new();
let mut thin_modules = Vec::new();
// analysis!
for (i, module) in modules.iter().enumerate() {
info!("local module: {} - {}", i, module.name);
- let llvm = module.llvm().expect("can't lto precodegened module");
let name = CString::new(module.name.clone()).unwrap();
- let buffer = ThinBuffer::new(llvm.llmod());
+ let buffer = ThinBuffer::new(module.module_llvm.llmod());
+
+ // We emit the module after having serialized it into a ThinBuffer
+ // because only then it will contain the ThinLTO module summary.
+ if let Some(ref incr_comp_session_dir) = cgcx.incr_comp_session_dir {
+ if cgcx.config(module.kind).emit_pre_thin_lto_bc {
+ let path = incr_comp_session_dir
+ .join(pre_lto_bitcode_filename(&module.name));
+
+ fs::write(&path, buffer.data()).unwrap_or_else(|e| {
+ panic!("Error writing pre-lto-bitcode file `{}`: {}",
+ path.display(),
+ e);
+ });
+ }
+ }
+
thin_modules.push(llvm::ThinLTOModule {
identifier: name.as_ptr(),
data: buffer.data().as_ptr(),
// looking at upstream modules entirely sometimes (the contents,
// we must always unconditionally look at the index).
let mut serialized = Vec::new();
- for (module, name) in serialized_modules {
- info!("foreign module {:?}", name);
+
+ let cached_modules = cached_modules.into_iter().map(|(sm, wp)| {
+ (sm, CString::new(wp.cgu_name).unwrap())
+ });
+
+ for (module, name) in serialized_modules.into_iter().chain(cached_modules) {
+ info!("upstream or cached module {:?}", name);
thin_modules.push(llvm::ThinLTOModule {
identifier: name.as_ptr(),
data: module.data().as_ptr(),
module_names.push(name);
}
+ // Sanity check
+ assert_eq!(thin_modules.len(), module_names.len());
+
// Delegate to the C++ bindings to create some data here. Once this is a
// tried-and-true interface we may wish to try to upstream some of this
// to LLVM itself, right now we reimplement a lot of what they do
write::llvm_err(&diag_handler, "failed to prepare thin LTO context".to_string())
})?;
- let data = ThinData(data);
info!("thin LTO data created");
timeline.record("data");
+ let import_map = if cgcx.incr_comp_session_dir.is_some() {
+ ThinLTOImports::from_thin_lto_data(data)
+ } else {
+ // If we don't compile incrementally, we don't need to load the
+ // import data from LLVM.
+ assert!(green_modules.is_empty());
+ ThinLTOImports::new()
+ };
+ info!("thin LTO import map loaded");
+ timeline.record("import-map-loaded");
+
+ let data = ThinData(data);
+
// Throw our data in an `Arc` as we'll be sharing it across threads. We
// also put all memory referenced by the C++ data (buffers, ids, etc)
// into the arc as well. After this we'll create a thin module
serialized_modules: serialized,
module_names,
});
- Ok((0..shared.module_names.len()).map(|i| {
- LtoModuleCodegen::Thin(ThinModule {
+
+ let mut copy_jobs = vec![];
+ let mut opt_jobs = vec![];
+
+ info!("checking which modules can be-reused and which have to be re-optimized.");
+ for (module_index, module_name) in shared.module_names.iter().enumerate() {
+ let module_name = module_name_to_str(module_name);
+
+ // If the module hasn't changed and none of the modules it imports
+ // from has changed, we can re-use the post-ThinLTO version of the
+ // module.
+ if green_modules.contains_key(module_name) {
+ let imports_all_green = import_map.modules_imported_by(module_name)
+ .iter()
+ .all(|imported_module| green_modules.contains_key(imported_module));
+
+ if imports_all_green {
+ let work_product = green_modules[module_name].clone();
+ copy_jobs.push(work_product);
+ info!(" - {}: re-used", module_name);
+ continue
+ }
+ }
+
+ info!(" - {}: re-compiled", module_name);
+ opt_jobs.push(LtoModuleCodegen::Thin(ThinModule {
shared: shared.clone(),
- idx: i,
- })
- }).collect())
+ idx: module_index,
+ }));
+ }
+
+ Ok((opt_jobs, copy_jobs))
}
}
pub enum SerializedModule {
Local(ModuleBuffer),
FromRlib(Vec<u8>),
+ FromUncompressedFile(memmap::Mmap),
}
impl SerializedModule {
match *self {
SerializedModule::Local(ref m) => m.data(),
SerializedModule::FromRlib(ref m) => m,
+ SerializedModule::FromUncompressedFile(ref m) => m,
}
}
}
write::llvm_err(&diag_handler, msg)
})? as *const _;
let module = ModuleCodegen {
- source: ModuleSource::Codegened(ModuleLlvm {
+ module_llvm: ModuleLlvm {
llmod_raw,
llcx,
tm,
- }),
+ },
name: self.name().to_string(),
kind: ModuleKind::Regular,
};
{
- let llmod = module.llvm().unwrap().llmod();
+ let llmod = module.module_llvm.llmod();
cgcx.save_temp_bitcode(&module, "thin-lto-input");
// Before we do much else find the "main" `DICompileUnit` that we'll be
// little differently.
info!("running thin lto passes over {}", module.name);
let config = cgcx.config(module.kind);
- run_pass_manager(cgcx, module.llvm().unwrap().tm, llmod, config, true);
+ run_pass_manager(cgcx, module.module_llvm.tm, llmod, config, true);
cgcx.save_temp_bitcode(&module, "thin-lto-after-pm");
timeline.record("thin-done");
}
Ok(module)
}
}
+
+#[derive(Debug)]
+pub struct ThinLTOImports {
+ // key = llvm name of importing module, value = list of modules it imports from
+ imports: FxHashMap<String, Vec<String>>,
+}
+
+impl ThinLTOImports {
+ fn new() -> ThinLTOImports {
+ ThinLTOImports {
+ imports: FxHashMap(),
+ }
+ }
+
+ fn modules_imported_by(&self, llvm_module_name: &str) -> &[String] {
+ self.imports.get(llvm_module_name).map(|v| &v[..]).unwrap_or(&[])
+ }
+
+ /// Load the ThinLTO import map from ThinLTOData.
+ unsafe fn from_thin_lto_data(data: *const llvm::ThinLTOData) -> ThinLTOImports {
+ unsafe extern "C" fn imported_module_callback(payload: *mut libc::c_void,
+ importing_module_name: *const libc::c_char,
+ imported_module_name: *const libc::c_char) {
+ let map = &mut* (payload as *mut ThinLTOImports);
+ let importing_module_name = CStr::from_ptr(importing_module_name);
+ let importing_module_name = module_name_to_str(&importing_module_name);
+ let imported_module_name = CStr::from_ptr(imported_module_name);
+ let imported_module_name = module_name_to_str(&imported_module_name);
+
+ if !map.imports.contains_key(importing_module_name) {
+ map.imports.insert(importing_module_name.to_owned(), vec![]);
+ }
+
+ map.imports
+ .get_mut(importing_module_name)
+ .unwrap()
+ .push(imported_module_name.to_owned());
+ }
+ let mut map = ThinLTOImports {
+ imports: FxHashMap(),
+ };
+ llvm::LLVMRustGetThinLTOModuleImports(data,
+ imported_module_callback,
+ &mut map as *mut _ as *mut libc::c_void);
+ map
+ }
+}
+
+fn module_name_to_str(c_str: &CStr) -> &str {
+ match c_str.to_str() {
+ Ok(s) => s,
+ Err(e) => {
+ bug!("Encountered non-utf8 LLVM module name `{}`: {}",
+ c_str.to_string_lossy(),
+ e)
+ }
+ }
+}
// option. This file may not be copied, modified, or distributed
// except according to those terms.
-use std::collections::HashSet;
+use rustc_data_structures::fx::FxHashSet;
use std::env;
use std::path::{Path, PathBuf};
use std::fs;
}
fn minimize_rpaths(rpaths: &[String]) -> Vec<String> {
- let mut set = HashSet::new();
+ let mut set = FxHashSet::default();
let mut minimized = Vec::new();
for rpath in rpaths {
if set.insert(rpath) {
use attributes;
use back::bytecode::{self, RLIB_BYTECODE_EXTENSION};
-use back::lto::{self, ModuleBuffer, ThinBuffer};
+use back::lto::{self, ModuleBuffer, ThinBuffer, SerializedModule};
use back::link::{self, get_linker, remove};
use back::command::Command;
use back::linker::LinkerInfo;
use back::symbol_export::ExportedSymbols;
use base;
use consts;
-use rustc_incremental::{copy_cgu_workproducts_to_incr_comp_cache_dir, in_incr_comp_dir};
+use memmap;
+use rustc_incremental::{copy_cgu_workproducts_to_incr_comp_cache_dir,
+ in_incr_comp_dir, in_incr_comp_dir_sess};
use rustc::dep_graph::{WorkProduct, WorkProductId, WorkProductFileKind};
use rustc::middle::cstore::EncodedMetadata;
use rustc::session::config::{self, OutputFilenames, OutputType, Passes, Sanitizer, Lto};
use time_graph::{self, TimeGraph, Timeline};
use llvm::{self, DiagnosticInfo, PassManager, SMDiagnostic};
use llvm_util;
-use {CodegenResults, ModuleSource, ModuleCodegen, CompiledModule, ModuleKind};
+use {CodegenResults, ModuleCodegen, CompiledModule, ModuleKind, // ModuleLlvm,
+ CachedModuleCodegen};
use CrateInfo;
use rustc::hir::def_id::{CrateNum, LOCAL_CRATE};
use rustc::ty::TyCtxt;
("local-exec", llvm::ThreadLocalMode::LocalExec),
];
+const PRE_THIN_LTO_BC_EXT: &str = "pre-thin-lto.bc";
+
pub fn llvm_err(handler: &errors::Handler, msg: String) -> FatalError {
match llvm::last_error() {
Some(err) => handler.fatal(&format!("{}: {}", msg, err)),
None => llvm::CodeModel::None,
};
- let singlethread = sess.target.target.options.singlethread;
+ let features = attributes::llvm_target_features(sess).collect::<Vec<_>>();
+ let mut singlethread = sess.target.target.options.singlethread;
+
+ // On the wasm target once the `atomics` feature is enabled that means that
+ // we're no longer single-threaded, or otherwise we don't want LLVM to
+ // lower atomic operations to single-threaded operations.
+ if singlethread &&
+ sess.target.target.llvm_target.contains("wasm32") &&
+ features.iter().any(|s| *s == "+atomics")
+ {
+ singlethread = false;
+ }
let triple = SmallCStr::new(&sess.target.target.llvm_target);
let cpu = SmallCStr::new(llvm_util::target_cpu(sess));
- let features = attributes::llvm_target_features(sess)
- .collect::<Vec<_>>()
- .join(",");
+ let features = features.join(",");
let features = CString::new(features).unwrap();
let is_pie_binary = !find_features && is_pie_binary(sess);
let trap_unreachable = sess.target.target.options.trap_unreachable;
pgo_use: String,
// Flags indicating which outputs to produce.
+ pub emit_pre_thin_lto_bc: bool,
emit_no_opt_bc: bool,
emit_bc: bool,
emit_bc_compressed: bool,
pgo_use: String::new(),
emit_no_opt_bc: false,
+ emit_pre_thin_lto_bc: false,
emit_bc: false,
emit_bc_compressed: false,
emit_lto_bc: false,
let cgu = Some(&module.name[..]);
let path = self.output_filenames.temp_path_ext(&ext, cgu);
let cstr = path2cstr(&path);
- let llmod = module.llvm().unwrap().llmod();
+ let llmod = module.module_llvm.llmod();
llvm::LLVMWriteBitcodeToFile(llmod, cstr.as_ptr());
}
}
timeline: &mut Timeline)
-> Result<(), FatalError>
{
- let (llmod, llcx, tm) = match module.source {
- ModuleSource::Codegened(ref llvm) => (llvm.llmod(), &*llvm.llcx, &*llvm.tm),
- ModuleSource::Preexisting(_) => {
- bug!("optimize_and_codegen: called with ModuleSource::Preexisting")
- }
- };
-
+ let llmod = module.module_llvm.llmod();
+ let llcx = &*module.module_llvm.llcx;
+ let tm = &*module.module_llvm.tm;
let _handlers = DiagnosticHandlers::new(cgcx, diag_handler, llcx);
let module_name = module.name.clone();
}
fn generate_lto_work(cgcx: &CodegenContext,
- modules: Vec<ModuleCodegen>)
+ modules: Vec<ModuleCodegen>,
+ import_only_modules: Vec<(SerializedModule, WorkProduct)>)
-> Vec<(WorkItem, u64)>
{
let mut timeline = cgcx.time_graph.as_ref().map(|tg| {
CODEGEN_WORK_PACKAGE_KIND,
"generate lto")
}).unwrap_or(Timeline::noop());
- let lto_modules = lto::run(cgcx, modules, &mut timeline)
+ let (lto_modules, copy_jobs) = lto::run(cgcx, modules, import_only_modules, &mut timeline)
.unwrap_or_else(|e| e.raise());
- lto_modules.into_iter().map(|module| {
+ let lto_modules = lto_modules.into_iter().map(|module| {
let cost = module.cost();
(WorkItem::LTO(module), cost)
- }).collect()
+ });
+
+ let copy_jobs = copy_jobs.into_iter().map(|wp| {
+ (WorkItem::CopyPostLtoArtifacts(CachedModuleCodegen {
+ name: wp.cgu_name.clone(),
+ source: wp,
+ }), 0)
+ });
+
+ lto_modules.chain(copy_jobs).collect()
}
unsafe fn codegen(cgcx: &CodegenContext,
{
timeline.record("codegen");
{
- let (llmod, llcx, tm) = match module.source {
- ModuleSource::Codegened(ref llvm) => (llvm.llmod(), &*llvm.llcx, &*llvm.tm),
- ModuleSource::Preexisting(_) => {
- bug!("codegen: called with ModuleSource::Preexisting")
- }
- };
+ let llmod = module.module_llvm.llmod();
+ let llcx = &*module.module_llvm.llcx;
+ let tm = &*module.module_llvm.tm;
let module_name = module.name.clone();
let module_name = Some(&module_name[..]);
let handlers = DiagnosticHandlers::new(cgcx, diag_handler, llcx);
sess.opts.output_types.contains_key(&OutputType::Exe)
}
+fn need_pre_thin_lto_bitcode_for_incr_comp(sess: &Session) -> bool {
+ if sess.opts.incremental.is_none() {
+ return false
+ }
+
+ match sess.lto() {
+ Lto::Yes |
+ Lto::Fat |
+ Lto::No => false,
+ Lto::Thin |
+ Lto::ThinLocal => true,
+ }
+}
+
pub fn start_async_codegen(tcx: TyCtxt,
time_graph: Option<TimeGraph>,
metadata: EncodedMetadata,
// Save all versions of the bytecode if we're saving our temporaries.
if sess.opts.cg.save_temps {
modules_config.emit_no_opt_bc = true;
+ modules_config.emit_pre_thin_lto_bc = true;
modules_config.emit_bc = true;
modules_config.emit_lto_bc = true;
metadata_config.emit_bc = true;
allocator_config.emit_bc_compressed = true;
}
+ modules_config.emit_pre_thin_lto_bc =
+ need_pre_thin_lto_bitcode_for_incr_comp(sess);
+
modules_config.no_integrated_as = tcx.sess.opts.cg.no_integrated_as ||
tcx.sess.target.target.options.no_integrated_as;
fn copy_all_cgu_workproducts_to_incr_comp_cache_dir(
sess: &Session,
- compiled_modules: &CompiledModules
+ compiled_modules: &CompiledModules,
) -> FxHashMap<WorkProductId, WorkProduct> {
let mut work_products = FxHashMap::default();
return work_products;
}
- for module in compiled_modules.modules.iter() {
+ for module in compiled_modules.modules.iter().filter(|m| m.kind == ModuleKind::Regular) {
let mut files = vec![];
if let Some(ref path) = module.object {
// These are used in linking steps and will be cleaned up afterward.
}
-pub(crate) fn dump_incremental_data(codegen_results: &CodegenResults) {
- println!("[incremental] Re-using {} out of {} modules",
- codegen_results.modules.iter().filter(|m| m.pre_existing).count(),
- codegen_results.modules.len());
+pub(crate) fn dump_incremental_data(_codegen_results: &CodegenResults) {
+ // FIXME(mw): This does not work at the moment because the situation has
+ // become more complicated due to incremental LTO. Now a CGU
+ // can have more than two caching states.
+ // println!("[incremental] Re-using {} out of {} modules",
+ // codegen_results.modules.iter().filter(|m| m.pre_existing).count(),
+ // codegen_results.modules.len());
}
enum WorkItem {
+ /// Optimize a newly codegened, totally unoptimized module.
Optimize(ModuleCodegen),
+ /// Copy the post-LTO artifacts from the incremental cache to the output
+ /// directory.
+ CopyPostLtoArtifacts(CachedModuleCodegen),
+ /// Perform (Thin)LTO on the given module.
LTO(lto::LtoModuleCodegen),
}
impl WorkItem {
- fn kind(&self) -> ModuleKind {
+ fn module_kind(&self) -> ModuleKind {
match *self {
WorkItem::Optimize(ref m) => m.kind,
+ WorkItem::CopyPostLtoArtifacts(_) |
WorkItem::LTO(_) => ModuleKind::Regular,
}
}
fn name(&self) -> String {
match *self {
WorkItem::Optimize(ref m) => format!("optimize: {}", m.name),
+ WorkItem::CopyPostLtoArtifacts(ref m) => format!("copy post LTO artifacts: {}", m.name),
WorkItem::LTO(ref m) => format!("lto: {}", m.name()),
}
}
timeline: &mut Timeline)
-> Result<WorkItemResult, FatalError>
{
- let diag_handler = cgcx.create_diag_handler();
- let config = cgcx.config(work_item.kind());
- let module = match work_item {
- WorkItem::Optimize(module) => module,
- WorkItem::LTO(mut lto) => {
- unsafe {
- let module = lto.optimize(cgcx, timeline)?;
- let module = codegen(cgcx, &diag_handler, module, config, timeline)?;
- return Ok(WorkItemResult::Compiled(module))
- }
+ let module_config = cgcx.config(work_item.module_kind());
+
+ match work_item {
+ WorkItem::Optimize(module) => {
+ execute_optimize_work_item(cgcx, module, module_config, timeline)
}
- };
- let module_name = module.name.clone();
+ WorkItem::CopyPostLtoArtifacts(module) => {
+ execute_copy_from_cache_work_item(cgcx, module, module_config, timeline)
+ }
+ WorkItem::LTO(module) => {
+ execute_lto_work_item(cgcx, module, module_config, timeline)
+ }
+ }
+}
- let pre_existing = match module.source {
- ModuleSource::Codegened(_) => None,
- ModuleSource::Preexisting(ref wp) => Some(wp.clone()),
- };
+fn execute_optimize_work_item(cgcx: &CodegenContext,
+ module: ModuleCodegen,
+ module_config: &ModuleConfig,
+ timeline: &mut Timeline)
+ -> Result<WorkItemResult, FatalError>
+{
+ let diag_handler = cgcx.create_diag_handler();
- if let Some(wp) = pre_existing {
- let incr_comp_session_dir = cgcx.incr_comp_session_dir
- .as_ref()
- .unwrap();
- let name = &module.name;
- let mut object = None;
- let mut bytecode = None;
- let mut bytecode_compressed = None;
- for (kind, saved_file) in wp.saved_files {
- let obj_out = match kind {
- WorkProductFileKind::Object => {
- let path = cgcx.output_filenames.temp_path(OutputType::Object, Some(name));
- object = Some(path.clone());
- path
- }
- WorkProductFileKind::Bytecode => {
- let path = cgcx.output_filenames.temp_path(OutputType::Bitcode, Some(name));
- bytecode = Some(path.clone());
- path
- }
- WorkProductFileKind::BytecodeCompressed => {
- let path = cgcx.output_filenames.temp_path(OutputType::Bitcode, Some(name))
- .with_extension(RLIB_BYTECODE_EXTENSION);
- bytecode_compressed = Some(path.clone());
- path
- }
- };
- let source_file = in_incr_comp_dir(&incr_comp_session_dir,
- &saved_file);
- debug!("copying pre-existing module `{}` from {:?} to {}",
- module.name,
- source_file,
- obj_out.display());
- match link_or_copy(&source_file, &obj_out) {
- Ok(_) => { }
- Err(err) => {
- diag_handler.err(&format!("unable to copy {} to {}: {}",
- source_file.display(),
- obj_out.display(),
- err));
- }
- }
+ unsafe {
+ optimize(cgcx, &diag_handler, &module, module_config, timeline)?;
+ }
+
+ let linker_does_lto = cgcx.opts.debugging_opts.cross_lang_lto.enabled();
+
+ // After we've done the initial round of optimizations we need to
+ // decide whether to synchronously codegen this module or ship it
+ // back to the coordinator thread for further LTO processing (which
+ // has to wait for all the initial modules to be optimized).
+ //
+ // Here we dispatch based on the `cgcx.lto` and kind of module we're
+ // codegenning...
+ let needs_lto = match cgcx.lto {
+ Lto::No => false,
+
+ // If the linker does LTO, we don't have to do it. Note that we
+ // keep doing full LTO, if it is requested, as not to break the
+ // assumption that the output will be a single module.
+ Lto::Thin | Lto::ThinLocal if linker_does_lto => false,
+
+ // Here we've got a full crate graph LTO requested. We ignore
+ // this, however, if the crate type is only an rlib as there's
+ // no full crate graph to process, that'll happen later.
+ //
+ // This use case currently comes up primarily for targets that
+ // require LTO so the request for LTO is always unconditionally
+ // passed down to the backend, but we don't actually want to do
+ // anything about it yet until we've got a final product.
+ Lto::Yes | Lto::Fat | Lto::Thin => {
+ cgcx.crate_types.len() != 1 ||
+ cgcx.crate_types[0] != config::CrateType::Rlib
}
- assert_eq!(object.is_some(), config.emit_obj);
- assert_eq!(bytecode.is_some(), config.emit_bc);
- assert_eq!(bytecode_compressed.is_some(), config.emit_bc_compressed);
-
- Ok(WorkItemResult::Compiled(CompiledModule {
- name: module_name,
- kind: ModuleKind::Regular,
- pre_existing: true,
- object,
- bytecode,
- bytecode_compressed,
- }))
- } else {
- debug!("llvm-optimizing {:?}", module_name);
- unsafe {
- optimize(cgcx, &diag_handler, &module, config, timeline)?;
-
- let linker_does_lto = cgcx.opts.debugging_opts.cross_lang_lto.enabled();
-
- // After we've done the initial round of optimizations we need to
- // decide whether to synchronously codegen this module or ship it
- // back to the coordinator thread for further LTO processing (which
- // has to wait for all the initial modules to be optimized).
- //
- // Here we dispatch based on the `cgcx.lto` and kind of module we're
- // codegenning...
- let needs_lto = match cgcx.lto {
- Lto::No => false,
-
- // If the linker does LTO, we don't have to do it. Note that we
- // keep doing full LTO, if it is requested, as not to break the
- // assumption that the output will be a single module.
- Lto::Thin | Lto::ThinLocal if linker_does_lto => false,
-
- // Here we've got a full crate graph LTO requested. We ignore
- // this, however, if the crate type is only an rlib as there's
- // no full crate graph to process, that'll happen later.
- //
- // This use case currently comes up primarily for targets that
- // require LTO so the request for LTO is always unconditionally
- // passed down to the backend, but we don't actually want to do
- // anything about it yet until we've got a final product.
- Lto::Yes | Lto::Fat | Lto::Thin => {
- cgcx.crate_types.len() != 1 ||
- cgcx.crate_types[0] != config::CrateType::Rlib
- }
+ // When we're automatically doing ThinLTO for multi-codegen-unit
+ // builds we don't actually want to LTO the allocator modules if
+ // it shows up. This is due to various linker shenanigans that
+ // we'll encounter later.
+ //
+ // Additionally here's where we also factor in the current LLVM
+ // version. If it doesn't support ThinLTO we skip this.
+ Lto::ThinLocal => {
+ module.kind != ModuleKind::Allocator &&
+ unsafe { llvm::LLVMRustThinLTOAvailable() }
+ }
+ };
- // When we're automatically doing ThinLTO for multi-codegen-unit
- // builds we don't actually want to LTO the allocator modules if
- // it shows up. This is due to various linker shenanigans that
- // we'll encounter later.
- //
- // Additionally here's where we also factor in the current LLVM
- // version. If it doesn't support ThinLTO we skip this.
- Lto::ThinLocal => {
- module.kind != ModuleKind::Allocator &&
- llvm::LLVMRustThinLTOAvailable()
- }
- };
+ // Metadata modules never participate in LTO regardless of the lto
+ // settings.
+ let needs_lto = needs_lto && module.kind != ModuleKind::Metadata;
- // Metadata modules never participate in LTO regardless of the lto
- // settings.
- let needs_lto = needs_lto && module.kind != ModuleKind::Metadata;
+ if needs_lto {
+ Ok(WorkItemResult::NeedsLTO(module))
+ } else {
+ let module = unsafe {
+ codegen(cgcx, &diag_handler, module, module_config, timeline)?
+ };
+ Ok(WorkItemResult::Compiled(module))
+ }
+}
- if needs_lto {
- Ok(WorkItemResult::NeedsLTO(module))
- } else {
- let module = codegen(cgcx, &diag_handler, module, config, timeline)?;
- Ok(WorkItemResult::Compiled(module))
+fn execute_copy_from_cache_work_item(cgcx: &CodegenContext,
+ module: CachedModuleCodegen,
+ module_config: &ModuleConfig,
+ _: &mut Timeline)
+ -> Result<WorkItemResult, FatalError>
+{
+ let incr_comp_session_dir = cgcx.incr_comp_session_dir
+ .as_ref()
+ .unwrap();
+ let mut object = None;
+ let mut bytecode = None;
+ let mut bytecode_compressed = None;
+ for (kind, saved_file) in &module.source.saved_files {
+ let obj_out = match kind {
+ WorkProductFileKind::Object => {
+ let path = cgcx.output_filenames.temp_path(OutputType::Object,
+ Some(&module.name));
+ object = Some(path.clone());
+ path
+ }
+ WorkProductFileKind::Bytecode => {
+ let path = cgcx.output_filenames.temp_path(OutputType::Bitcode,
+ Some(&module.name));
+ bytecode = Some(path.clone());
+ path
+ }
+ WorkProductFileKind::BytecodeCompressed => {
+ let path = cgcx.output_filenames.temp_path(OutputType::Bitcode,
+ Some(&module.name))
+ .with_extension(RLIB_BYTECODE_EXTENSION);
+ bytecode_compressed = Some(path.clone());
+ path
+ }
+ };
+ let source_file = in_incr_comp_dir(&incr_comp_session_dir,
+ &saved_file);
+ debug!("copying pre-existing module `{}` from {:?} to {}",
+ module.name,
+ source_file,
+ obj_out.display());
+ match link_or_copy(&source_file, &obj_out) {
+ Ok(_) => { }
+ Err(err) => {
+ let diag_handler = cgcx.create_diag_handler();
+ diag_handler.err(&format!("unable to copy {} to {}: {}",
+ source_file.display(),
+ obj_out.display(),
+ err));
}
}
}
+
+ assert_eq!(object.is_some(), module_config.emit_obj);
+ assert_eq!(bytecode.is_some(), module_config.emit_bc);
+ assert_eq!(bytecode_compressed.is_some(), module_config.emit_bc_compressed);
+
+ Ok(WorkItemResult::Compiled(CompiledModule {
+ name: module.name,
+ kind: ModuleKind::Regular,
+ object,
+ bytecode,
+ bytecode_compressed,
+ }))
+}
+
+fn execute_lto_work_item(cgcx: &CodegenContext,
+ mut module: lto::LtoModuleCodegen,
+ module_config: &ModuleConfig,
+ timeline: &mut Timeline)
+ -> Result<WorkItemResult, FatalError>
+{
+ let diag_handler = cgcx.create_diag_handler();
+
+ unsafe {
+ let module = module.optimize(cgcx, timeline)?;
+ let module = codegen(cgcx, &diag_handler, module, module_config, timeline)?;
+ Ok(WorkItemResult::Compiled(module))
+ }
}
enum Message {
llvm_work_item: WorkItem,
cost: u64,
},
+ AddImportOnlyModule {
+ module_data: SerializedModule,
+ work_product: WorkProduct,
+ },
CodegenComplete,
CodegenItem,
}
let mut compiled_metadata_module = None;
let mut compiled_allocator_module = None;
let mut needs_lto = Vec::new();
+ let mut lto_import_only_modules = Vec::new();
let mut started_lto = false;
// This flag tracks whether all items have gone through codegens
work_items.len() > 0 ||
running > 0 ||
needs_lto.len() > 0 ||
+ lto_import_only_modules.len() > 0 ||
main_thread_worker_state != MainThreadWorkerState::Idle {
// While there are still CGUs to be codegened, the coordinator has
worker: get_worker_id(&mut free_worker_ids),
.. cgcx.clone()
};
- maybe_start_llvm_timer(cgcx.config(item.kind()),
+ maybe_start_llvm_timer(cgcx.config(item.module_kind()),
&mut llvm_start_time);
main_thread_worker_state = MainThreadWorkerState::LLVMing;
spawn_work(cgcx, item);
running == 0 &&
main_thread_worker_state == MainThreadWorkerState::Idle {
assert!(!started_lto);
- assert!(needs_lto.len() > 0);
+ assert!(needs_lto.len() + lto_import_only_modules.len() > 0);
started_lto = true;
let modules = mem::replace(&mut needs_lto, Vec::new());
- for (work, cost) in generate_lto_work(&cgcx, modules) {
+ let import_only_modules =
+ mem::replace(&mut lto_import_only_modules, Vec::new());
+ for (work, cost) in generate_lto_work(&cgcx, modules, import_only_modules) {
let insertion_index = work_items
.binary_search_by_key(&cost, |&(_, cost)| cost)
.unwrap_or_else(|e| e);
worker: get_worker_id(&mut free_worker_ids),
.. cgcx.clone()
};
- maybe_start_llvm_timer(cgcx.config(item.kind()),
+ maybe_start_llvm_timer(cgcx.config(item.module_kind()),
&mut llvm_start_time);
main_thread_worker_state = MainThreadWorkerState::LLVMing;
spawn_work(cgcx, item);
while work_items.len() > 0 && running < tokens.len() {
let (item, _) = work_items.pop().unwrap();
- maybe_start_llvm_timer(cgcx.config(item.kind()),
+ maybe_start_llvm_timer(cgcx.config(item.module_kind()),
&mut llvm_start_time);
let cgcx = CodegenContext {
} else {
running -= 1;
}
-
free_worker_ids.push(worker_id);
needs_lto.push(result);
}
+ Message::AddImportOnlyModule { module_data, work_product } => {
+ assert!(!started_lto);
+ assert!(!codegen_done);
+ assert_eq!(main_thread_worker_state,
+ MainThreadWorkerState::Codegenning);
+ lto_import_only_modules.push((module_data, work_product));
+ main_thread_worker_state = MainThreadWorkerState::Idle;
+ }
Message::Done { result: Err(()), worker_id: _ } => {
shared_emitter.fatal("aborting due to worker thread failure");
// Exit the coordinator thread
time_graph.dump(&format!("{}-timings", self.crate_name));
}
- let work_products = copy_all_cgu_workproducts_to_incr_comp_cache_dir(sess,
- &compiled_modules);
-
+ let work_products =
+ copy_all_cgu_workproducts_to_incr_comp_cache_dir(sess,
+ &compiled_modules);
produce_final_output_artifacts(sess,
&compiled_modules,
&self.output_filenames);
}
pub(crate) fn submit_codegened_module_to_llvm(tcx: TyCtxt,
- module: ModuleCodegen,
- cost: u64) {
+ module: ModuleCodegen,
+ cost: u64) {
let llvm_work_item = WorkItem::Optimize(module);
drop(tcx.tx_to_llvm_workers.lock().send(Box::new(Message::CodegenDone {
llvm_work_item,
})));
}
+pub(crate) fn submit_post_lto_module_to_llvm(tcx: TyCtxt,
+ module: CachedModuleCodegen) {
+ let llvm_work_item = WorkItem::CopyPostLtoArtifacts(module);
+ drop(tcx.tx_to_llvm_workers.lock().send(Box::new(Message::CodegenDone {
+ llvm_work_item,
+ cost: 0,
+ })));
+}
+
+pub(crate) fn submit_pre_lto_module_to_llvm(tcx: TyCtxt,
+ module: CachedModuleCodegen) {
+ let filename = pre_lto_bitcode_filename(&module.name);
+ let bc_path = in_incr_comp_dir_sess(tcx.sess, &filename);
+ let file = fs::File::open(&bc_path).unwrap_or_else(|e| {
+ panic!("failed to open bitcode file `{}`: {}", bc_path.display(), e)
+ });
+
+ let mmap = unsafe {
+ memmap::Mmap::map(&file).unwrap_or_else(|e| {
+ panic!("failed to mmap bitcode file `{}`: {}", bc_path.display(), e)
+ })
+ };
+
+ // Schedule the module to be loaded
+ drop(tcx.tx_to_llvm_workers.lock().send(Box::new(Message::AddImportOnlyModule {
+ module_data: SerializedModule::FromUncompressedFile(mmap),
+ work_product: module.source,
+ })));
+}
+
+pub(super) fn pre_lto_bitcode_filename(module_name: &str) -> String {
+ format!("{}.{}", module_name, PRE_THIN_LTO_BC_EXT)
+}
+
fn msvc_imps_needed(tcx: TyCtxt) -> bool {
// This should never be true (because it's not supported). If it is true,
// something is wrong with commandline arg validation.
//! int) and rec(x=int, y=int, z=int) will have the same llvm::Type.
use super::ModuleLlvm;
-use super::ModuleSource;
use super::ModuleCodegen;
use super::ModuleKind;
+use super::CachedModuleCodegen;
use abi;
use back::write::{self, OngoingCodegen};
use rustc::ty::{self, Ty, TyCtxt};
use rustc::ty::layout::{self, Align, TyLayout, LayoutOf};
use rustc::ty::query::Providers;
-use rustc::dep_graph::{DepNode, DepConstructor};
use rustc::middle::cstore::{self, LinkagePreference};
use rustc::middle::exported_symbols;
use rustc::util::common::{time, print_time_passes_entry};
use rustc::util::profiling::ProfileCategory;
-use rustc::session::config::{self, DebugInfo, EntryFnType};
+use rustc::session::config::{self, DebugInfo, EntryFnType, Lto};
use rustc::session::Session;
use rustc_incremental;
use allocator;
}
}
+#[derive(Debug)]
+enum CguReUsable {
+ PreLto,
+ PostLto,
+ No
+}
+
+fn determine_cgu_reuse<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
+ cgu: &CodegenUnit<'tcx>)
+ -> CguReUsable {
+ if !tcx.dep_graph.is_fully_enabled() {
+ return CguReUsable::No
+ }
+
+ let work_product_id = &cgu.work_product_id();
+ if tcx.dep_graph.previous_work_product(work_product_id).is_none() {
+ // We don't have anything cached for this CGU. This can happen
+ // if the CGU did not exist in the previous session.
+ return CguReUsable::No
+ }
+
+ // Try to mark the CGU as green. If it we can do so, it means that nothing
+ // affecting the LLVM module has changed and we can re-use a cached version.
+ // If we compile with any kind of LTO, this means we can re-use the bitcode
+ // of the Pre-LTO stage (possibly also the Post-LTO version but we'll only
+ // know that later). If we are not doing LTO, there is only one optimized
+ // version of each module, so we re-use that.
+ let dep_node = cgu.codegen_dep_node(tcx);
+ assert!(!tcx.dep_graph.dep_node_exists(&dep_node),
+ "CompileCodegenUnit dep-node for CGU `{}` already exists before marking.",
+ cgu.name());
+
+ if tcx.dep_graph.try_mark_green(tcx, &dep_node).is_some() {
+ // We can re-use either the pre- or the post-thinlto state
+ if tcx.sess.lto() != Lto::No {
+ CguReUsable::PreLto
+ } else {
+ CguReUsable::PostLto
+ }
+ } else {
+ CguReUsable::No
+ }
+}
+
pub fn codegen_crate<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
rx: mpsc::Receiver<Box<dyn Any + Send>>)
-> OngoingCodegen {
let metadata_module = ModuleCodegen {
name: metadata_cgu_name,
- source: ModuleSource::Codegened(metadata_llvm_module),
+ module_llvm: metadata_llvm_module,
kind: ModuleKind::Metadata,
};
Some(ModuleCodegen {
name: llmod_id,
- source: ModuleSource::Codegened(modules),
+ module_llvm: modules,
kind: ModuleKind::Allocator,
})
} else {
ongoing_codegen.wait_for_signal_to_codegen_item();
ongoing_codegen.check_for_errors(tcx.sess);
- // First, if incremental compilation is enabled, we try to re-use the
- // codegen unit from the cache.
- if tcx.dep_graph.is_fully_enabled() {
- let cgu_id = cgu.work_product_id();
-
- // Check whether there is a previous work-product we can
- // re-use. Not only must the file exist, and the inputs not
- // be dirty, but the hash of the symbols we will generate must
- // be the same.
- if let Some(buf) = tcx.dep_graph.previous_work_product(&cgu_id) {
- let dep_node = &DepNode::new(tcx,
- DepConstructor::CompileCodegenUnit(cgu.name().clone()));
-
- // We try to mark the DepNode::CompileCodegenUnit green. If we
- // succeed it means that none of the dependencies has changed
- // and we can safely re-use.
- if let Some(dep_node_index) = tcx.dep_graph.try_mark_green(tcx, dep_node) {
- let module = ModuleCodegen {
- name: cgu.name().to_string(),
- source: ModuleSource::Preexisting(buf),
- kind: ModuleKind::Regular,
- };
- tcx.dep_graph.mark_loaded_from_cache(dep_node_index, true);
- write::submit_codegened_module_to_llvm(tcx, module, 0);
- // Continue to next cgu, this one is done.
- continue
- }
- } else {
- // This can happen if files were deleted from the cache
- // directory for some reason. We just re-compile then.
+ let loaded_from_cache = match determine_cgu_reuse(tcx, &cgu) {
+ CguReUsable::No => {
+ let _timing_guard = time_graph.as_ref().map(|time_graph| {
+ time_graph.start(write::CODEGEN_WORKER_TIMELINE,
+ write::CODEGEN_WORK_PACKAGE_KIND,
+ &format!("codegen {}", cgu.name()))
+ });
+ let start_time = Instant::now();
+ let stats = compile_codegen_unit(tcx, *cgu.name());
+ all_stats.extend(stats);
+ total_codegen_time += start_time.elapsed();
+ false
}
- }
+ CguReUsable::PreLto => {
+ write::submit_pre_lto_module_to_llvm(tcx, CachedModuleCodegen {
+ name: cgu.name().to_string(),
+ source: cgu.work_product(tcx),
+ });
+ true
+ }
+ CguReUsable::PostLto => {
+ write::submit_post_lto_module_to_llvm(tcx, CachedModuleCodegen {
+ name: cgu.name().to_string(),
+ source: cgu.work_product(tcx),
+ });
+ true
+ }
+ };
- let _timing_guard = time_graph.as_ref().map(|time_graph| {
- time_graph.start(write::CODEGEN_WORKER_TIMELINE,
- write::CODEGEN_WORK_PACKAGE_KIND,
- &format!("codegen {}", cgu.name()))
- });
- let start_time = Instant::now();
- all_stats.extend(tcx.compile_codegen_unit(*cgu.name()));
- total_codegen_time += start_time.elapsed();
- ongoing_codegen.check_for_errors(tcx.sess);
+ if tcx.dep_graph.is_fully_enabled() {
+ let dep_node = cgu.codegen_dep_node(tcx);
+ let dep_node_index = tcx.dep_graph.dep_node_index_of(&dep_node);
+ tcx.dep_graph.mark_loaded_from_cache(dep_node_index, loaded_from_cache);
+ }
}
ongoing_codegen.codegen_finished(tcx);
}
fn compile_codegen_unit<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
- cgu: InternedString) -> Stats {
- let cgu = tcx.codegen_unit(cgu);
-
+ cgu_name: InternedString)
+ -> Stats {
let start_time = Instant::now();
- let (stats, module) = module_codegen(tcx, cgu);
+
+ let dep_node = tcx.codegen_unit(cgu_name).codegen_dep_node(tcx);
+ let ((stats, module), _) = tcx.dep_graph.with_task(dep_node,
+ tcx,
+ cgu_name,
+ module_codegen);
let time_to_codegen = start_time.elapsed();
// We assume that the cost to run LLVM on a CGU is proportional to
time_to_codegen.subsec_nanos() as u64;
write::submit_codegened_module_to_llvm(tcx,
- module,
- cost);
+ module,
+ cost);
return stats;
fn module_codegen<'a, 'tcx>(
tcx: TyCtxt<'a, 'tcx, 'tcx>,
- cgu: Arc<CodegenUnit<'tcx>>)
+ cgu_name: InternedString)
-> (Stats, ModuleCodegen)
{
- let cgu_name = cgu.name().to_string();
+ let cgu = tcx.codegen_unit(cgu_name);
// Instantiate monomorphizations without filling out definitions yet...
- let llvm_module = ModuleLlvm::new(tcx.sess, &cgu_name);
+ let llvm_module = ModuleLlvm::new(tcx.sess, &cgu_name.as_str());
let stats = {
let cx = CodegenCx::new(tcx, cgu, &llvm_module);
let mono_items = cx.codegen_unit
- .items_in_deterministic_order(cx.tcx);
+ .items_in_deterministic_order(cx.tcx);
for &(mono_item, (linkage, visibility)) in &mono_items {
mono_item.predefine(&cx, linkage, visibility);
}
};
(stats, ModuleCodegen {
- name: cgu_name,
- source: ModuleSource::Codegened(llvm_module),
+ name: cgu_name.to_string(),
+ module_llvm: llvm_module,
kind: ModuleKind::Regular,
})
}
.cloned()
.unwrap_or_else(|| panic!("failed to find cgu with name {:?}", name))
};
- providers.compile_codegen_unit = compile_codegen_unit;
provide_extern(providers);
}
extern crate serialize;
extern crate cc; // Used to locate MSVC
extern crate tempfile;
+extern crate memmap;
use back::bytecode::RLIB_BYTECODE_EXTENSION;
pub use llvm_util::target_features;
-
use std::any::Any;
-use std::path::PathBuf;
+use std::path::{PathBuf};
use std::sync::mpsc;
use rustc_data_structures::sync::Lrc;
mod command;
pub mod linker;
pub mod link;
- mod lto;
+ pub mod lto;
pub mod symbol_export;
pub mod write;
mod rpath;
/// as the crate name and disambiguator.
/// We currently generate these names via CodegenUnit::build_cgu_name().
name: String,
- source: ModuleSource,
+ module_llvm: ModuleLlvm,
kind: ModuleKind,
}
+struct CachedModuleCodegen {
+ name: String,
+ source: WorkProduct,
+}
+
#[derive(Copy, Clone, Debug, PartialEq)]
enum ModuleKind {
Regular,
}
impl ModuleCodegen {
- fn llvm(&self) -> Option<&ModuleLlvm> {
- match self.source {
- ModuleSource::Codegened(ref llvm) => Some(llvm),
- ModuleSource::Preexisting(_) => None,
- }
- }
-
fn into_compiled_module(self,
- emit_obj: bool,
- emit_bc: bool,
- emit_bc_compressed: bool,
- outputs: &OutputFilenames) -> CompiledModule {
- let pre_existing = match self.source {
- ModuleSource::Preexisting(_) => true,
- ModuleSource::Codegened(_) => false,
- };
+ emit_obj: bool,
+ emit_bc: bool,
+ emit_bc_compressed: bool,
+ outputs: &OutputFilenames) -> CompiledModule {
let object = if emit_obj {
Some(outputs.temp_path(OutputType::Object, Some(&self.name)))
} else {
CompiledModule {
name: self.name.clone(),
kind: self.kind,
- pre_existing,
object,
bytecode,
bytecode_compressed,
struct CompiledModule {
name: String,
kind: ModuleKind,
- pre_existing: bool,
object: Option<PathBuf>,
bytecode: Option<PathBuf>,
bytecode_compressed: Option<PathBuf>,
}
-enum ModuleSource {
- /// Copy the `.o` files or whatever from the incr. comp. directory.
- Preexisting(WorkProduct),
-
- /// Rebuild from this LLVM module.
- Codegened(ModuleLlvm),
-}
-
struct ModuleLlvm {
llcx: &'static mut llvm::Context,
llmod_raw: *const llvm::Module,
/// LLVMRustThinLTOBuffer
extern { pub type ThinLTOBuffer; }
+// LLVMRustModuleNameCallback
+pub type ThinLTOModuleNameCallback =
+ unsafe extern "C" fn(*mut c_void, *const c_char, *const c_char);
+
/// LLVMRustThinLTOModule
#[repr(C)]
pub struct ThinLTOModule {
Data: &ThinLTOData,
Module: &Module,
) -> bool;
+ pub fn LLVMRustGetThinLTOModuleImports(
+ Data: *const ThinLTOData,
+ ModuleNameCallback: ThinLTOModuleNameCallback,
+ CallbackPayload: *mut c_void,
+ );
pub fn LLVMRustFreeThinLTOData(Data: &'static mut ThinLTOData);
pub fn LLVMRustParseBitcodeForThinLTO(
Context: &Context,
// array, leading to crashes.
const ARM_WHITELIST: &[(&str, Option<&str>)] = &[
+ ("aclass", Some("arm_target_feature")),
("mclass", Some("arm_target_feature")),
("rclass", Some("arm_target_feature")),
("dsp", Some("arm_target_feature")),
("neon", Some("arm_target_feature")),
+ ("v5te", Some("arm_target_feature")),
+ ("v6k", Some("arm_target_feature")),
+ ("v6t2", Some("arm_target_feature")),
("v7", Some("arm_target_feature")),
("vfp2", Some("arm_target_feature")),
("vfp3", Some("arm_target_feature")),
const WASM_WHITELIST: &[(&str, Option<&str>)] = &[
("simd128", Some("wasm_target_feature")),
+ ("atomics", Some("wasm_target_feature")),
];
/// When rustdoc is running, provide a list of all known features so that all their respective
[dependencies]
bitflags = "1.0"
log = "0.4"
+unicode-width = "0.1.4"
extern crate bitflags;
extern crate log;
+extern crate unicode_width;
smallvec = { version = "0.6.5", features = ["union"] }
[dependencies.parking_lot]
-version = "0.5"
+version = "0.6"
features = ["nightly"]
}
#[cfg(windows)]
-#[allow(bad_style)]
+#[allow(nonstandard_style)]
mod imp {
use std::io;
use std::mem;
// option. This file may not be copied, modified, or distributed
// except according to those terms.
-use std::collections::HashMap;
+use fx::FxHashMap;
use std::cmp::max;
use std::slice;
use std::iter;
pub struct TestGraph {
num_nodes: usize,
start_node: usize,
- successors: HashMap<usize, Vec<usize>>,
- predecessors: HashMap<usize, Vec<usize>>,
+ successors: FxHashMap<usize, Vec<usize>>,
+ predecessors: FxHashMap<usize, Vec<usize>>,
}
impl TestGraph {
let mut graph = TestGraph {
num_nodes: start_node + 1,
start_node,
- successors: HashMap::new(),
- predecessors: HashMap::new(),
+ successors: FxHashMap::default(),
+ predecessors: FxHashMap::default(),
};
for &(source, target) in edges {
graph.num_nodes = max(graph.num_nodes, source + 1);
}
}
+impl<T1, T2, T3, T4, CTX> HashStable<CTX> for (T1, T2, T3, T4)
+ where T1: HashStable<CTX>,
+ T2: HashStable<CTX>,
+ T3: HashStable<CTX>,
+ T4: HashStable<CTX>,
+{
+ fn hash_stable<W: StableHasherResult>(&self,
+ ctx: &mut CTX,
+ hasher: &mut StableHasher<W>) {
+ let (ref _0, ref _1, ref _2, ref _3) = *self;
+ _0.hash_stable(ctx, hasher);
+ _1.hash_stable(ctx, hasher);
+ _2.hash_stable(ctx, hasher);
+ _3.hash_stable(ctx, hasher);
+ }
+}
+
impl<T: HashStable<CTX>, CTX> HashStable<CTX> for [T] {
default fn hash_stable<W: StableHasherResult>(&self,
ctx: &mut CTX,
pub use std::rc::Rc as Lrc;
pub use std::rc::Weak as Weak;
pub use std::cell::Ref as ReadGuard;
+ pub use std::cell::Ref as MappedReadGuard;
pub use std::cell::RefMut as WriteGuard;
+ pub use std::cell::RefMut as MappedWriteGuard;
pub use std::cell::RefMut as LockGuard;
+ pub use std::cell::RefMut as MappedLockGuard;
use std::cell::RefCell as InnerRwLock;
use std::cell::RefCell as InnerLock;
pub use std::marker::Sync as Sync;
pub use parking_lot::RwLockReadGuard as ReadGuard;
+ pub use parking_lot::MappedRwLockReadGuard as MappedReadGuard;
pub use parking_lot::RwLockWriteGuard as WriteGuard;
+ pub use parking_lot::MappedRwLockWriteGuard as MappedWriteGuard;
pub use parking_lot::MutexGuard as LockGuard;
+ pub use parking_lot::MappedMutexGuard as MappedLockGuard;
pub use std::sync::Arc as Lrc;
pub use std::sync::Weak as Weak;
let (mut krate, features) = syntax::config::features(
krate,
&sess.parse_sess,
- sess.opts.test,
sess.edition(),
);
// these need to be set "early" so that expansion sees `quote` if enabled.
ls.register_late_pass(Some(sess), true, pass);
}
- for (name, to) in lint_groups {
- ls.register_group(Some(sess), true, name, to);
+ for (name, (to, deprecated_name)) in lint_groups {
+ ls.register_group(Some(sess), true, name, deprecated_name, to);
}
*sess.plugin_llvm_passes.borrow_mut() = llvm_passes;
use super::*;
use syntax_pos::SpanData;
+use rustc_data_structures::fx::FxHashMap;
use rustc::util::common::QueryMsg;
use std::fs::File;
use std::time::{Duration, Instant};
-use std::collections::hash_map::HashMap;
use rustc::dep_graph::{DepNode};
#[derive(Debug, Clone, Eq, PartialEq)]
}
}
-fn compute_counts_rec(counts: &mut HashMap<String,QueryMetric>, traces: &[Rec]) {
+fn compute_counts_rec(counts: &mut FxHashMap<String,QueryMetric>, traces: &[Rec]) {
for t in traces.iter() {
match t.effect {
Effect::TimeBegin(ref msg) => {
}
}
-pub fn write_counts(count_file: &mut File, counts: &mut HashMap<String,QueryMetric>) {
+pub fn write_counts(count_file: &mut File, counts: &mut FxHashMap<String,QueryMetric>) {
use rustc::util::common::duration_to_secs_str;
use std::cmp::Reverse;
pub fn write_traces(html_file: &mut File, counts_file: &mut File, traces: &[Rec]) {
let capacity = traces.iter().fold(0, |acc, t| acc + 1 + t.extent.len());
- let mut counts : HashMap<String, QueryMetric> = HashMap::with_capacity(capacity);
+ let mut counts = FxHashMap::with_capacity_and_hasher(capacity, Default::default());
compute_counts_rec(&mut counts, traces);
write_counts(counts_file, &mut counts);
serialize = { path = "../libserialize" }
syntax_pos = { path = "../libsyntax_pos" }
rustc_data_structures = { path = "../librustc_data_structures" }
+rustc_cratesio_shim = { path = "../librustc_cratesio_shim" }
unicode-width = "0.1.4"
atty = "0.2"
-termcolor = "0.3"
+termcolor = "1.0"
use snippet::{Annotation, AnnotationType, Line, MultilineAnnotation, StyledString, Style};
use styled_buffer::StyledBuffer;
+use rustc_data_structures::fx::FxHashMap;
use rustc_data_structures::sync::Lrc;
use atty;
use std::borrow::Cow;
use std::io::prelude::*;
use std::io;
-use std::collections::HashMap;
use std::cmp::{min, Reverse};
use termcolor::{StandardStream, ColorChoice, ColorSpec, BufferWriter};
use termcolor::{WriteColor, Color, Buffer};
max_line_num_len + 1);
// Contains the vertical lines' positions for active multiline annotations
- let mut multilines = HashMap::new();
+ let mut multilines = FxHashMap::default();
// Next, output the annotate source for this file
for line_idx in 0..annotated_file.lines.len() {
width_offset,
code_offset);
- let mut to_add = HashMap::new();
+ let mut to_add = FxHashMap::default();
for (depth, style) in depths {
if multilines.get(&depth).is_some() {
use std::any::Any;
#[cfg(windows)]
-#[allow(bad_style)]
+#[allow(nonstandard_style)]
pub fn acquire_global_lock(name: &str) -> Box<dyn Any> {
use std::ffi::CString;
use std::io;
// option. This file may not be copied, modified, or distributed
// except according to those terms.
-use std::collections::HashMap;
+use rustc_data_structures::fx::FxHashMap;
#[derive(Clone)]
pub struct Registry {
- descriptions: HashMap<&'static str, &'static str>,
+ descriptions: FxHashMap<&'static str, &'static str>,
}
impl Registry {
[dependencies]
graphviz = { path = "../libgraphviz" }
log = "0.4"
-rand = "0.4"
+rand = "0.5"
rustc = { path = "../librustc" }
rustc_data_structures = { path = "../librustc_data_structures" }
serialize = { path = "../libserialize" }
(&user_path[..], None)
};
- let mut cgu_path_components = user_path.split("-").collect::<Vec<_>>();
+ let mut cgu_path_components = user_path.split('-').collect::<Vec<_>>();
// Remove the crate name
assert_eq!(cgu_path_components.remove(0), crate_name);
pub use persist::save_dep_graph;
pub use persist::save_work_product_index;
pub use persist::in_incr_comp_dir;
+pub use persist::in_incr_comp_dir_sess;
pub use persist::prepare_session_directory;
pub use persist::finalize_session_directory;
pub use persist::delete_workproduct_files;
//! the required condition is not met.
//!
-use std::collections::HashSet;
use std::iter::FromIterator;
use std::vec::Vec;
use rustc::dep_graph::{DepNode, label_strs};
//
// TypeOfItem for these.
-type Labels = HashSet<String>;
+type Labels = FxHashSet<String>;
/// Represents the requested configuration by rustc_clean/dirty
struct Assertion {
fn from_clean_labels(labels: Labels) -> Assertion {
Assertion {
clean: labels,
- dirty: Labels::new(),
+ dirty: Labels::default(),
}
}
fn from_dirty_labels(labels: Labels) -> Assertion {
Assertion {
- clean: Labels::new(),
+ clean: Labels::default(),
dirty: labels,
}
}
}
}
// if no `label` or `except` is given, only the node's group are asserted
- Labels::new()
+ Labels::default()
}
/// Return all DepNode labels that should be asserted for this item.
}
fn resolve_labels(&self, item: &NestedMetaItem, value: &str) -> Labels {
- let mut out: Labels = HashSet::new();
+ let mut out = Labels::default();
for label in value.split(',') {
let label = label.trim();
if DepNode::has_label_string(label) {
use std::path::{Path, PathBuf};
use std::time::{UNIX_EPOCH, SystemTime, Duration};
-use rand::{thread_rng, Rng};
+use rand::{RngCore, thread_rng};
const LOCK_FILE_EXT: &'static str = ".lock";
const DEP_GRAPH_FILENAME: &'static str = "dep-graph.bin";
pub use self::fs::finalize_session_directory;
pub use self::fs::garbage_collect_session_directories;
pub use self::fs::in_incr_comp_dir;
+pub use self::fs::in_incr_comp_dir_sess;
pub use self::fs::prepare_session_directory;
pub use self::load::dep_graph_tcx_init;
pub use self::load::load_dep_graph;
+++ /dev/null
-// Copyright 2015 The Rust Project Developers. See the COPYRIGHT
-// file at the top-level directory of this distribution and at
-// http://rust-lang.org/COPYRIGHT.
-//
-// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
-// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
-// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
-// option. This file may not be copied, modified, or distributed
-// except according to those terms.
-
-use rustc::hir::def::Def;
-use rustc::ty;
-use lint::{LateContext, LintContext, LintArray};
-use lint::{LintPass, LateLintPass};
-
-use rustc_target::spec::abi::Abi;
-use syntax::ast;
-use syntax::attr;
-use syntax_pos::Span;
-
-use rustc::hir::{self, GenericParamKind, PatKind};
-use rustc::hir::intravisit::FnKind;
-
-#[derive(PartialEq)]
-pub enum MethodLateContext {
- TraitAutoImpl,
- TraitImpl,
- PlainImpl,
-}
-
-pub fn method_context(cx: &LateContext, id: ast::NodeId) -> MethodLateContext {
- let def_id = cx.tcx.hir.local_def_id(id);
- let item = cx.tcx.associated_item(def_id);
- match item.container {
- ty::TraitContainer(..) => MethodLateContext::TraitAutoImpl,
- ty::ImplContainer(cid) => {
- match cx.tcx.impl_trait_ref(cid) {
- Some(_) => MethodLateContext::TraitImpl,
- None => MethodLateContext::PlainImpl,
- }
- }
- }
-}
-
-declare_lint! {
- pub NON_CAMEL_CASE_TYPES,
- Warn,
- "types, variants, traits and type parameters should have camel case names"
-}
-
-#[derive(Copy, Clone)]
-pub struct NonCamelCaseTypes;
-
-impl NonCamelCaseTypes {
- fn check_case(&self, cx: &LateContext, sort: &str, name: ast::Name, span: Span) {
- fn char_has_case(c: char) -> bool {
- c.is_lowercase() || c.is_uppercase()
- }
-
- fn is_camel_case(name: ast::Name) -> bool {
- let name = name.as_str();
- if name.is_empty() {
- return true;
- }
- let name = name.trim_matches('_');
-
- // start with a non-lowercase letter rather than non-uppercase
- // ones (some scripts don't have a concept of upper/lowercase)
- !name.is_empty() && !name.chars().next().unwrap().is_lowercase() &&
- !name.contains("__") && !name.chars().collect::<Vec<_>>().windows(2).any(|pair| {
- // contains a capitalisable character followed by, or preceded by, an underscore
- char_has_case(pair[0]) && pair[1] == '_' ||
- char_has_case(pair[1]) && pair[0] == '_'
- })
- }
-
- fn to_camel_case(s: &str) -> String {
- s.trim_matches('_')
- .split('_')
- .map(|word| {
- word.chars().enumerate().map(|(i, c)| if i == 0 {
- c.to_uppercase().collect::<String>()
- } else {
- c.to_lowercase().collect()
- })
- .collect::<String>()
- })
- .filter(|x| !x.is_empty())
- .fold((String::new(), None), |(acc, prev): (String, Option<String>), next| {
- // separate two components with an underscore if their boundary cannot
- // be distinguished using a uppercase/lowercase case distinction
- let join = if let Some(prev) = prev {
- let l = prev.chars().last().unwrap();
- let f = next.chars().next().unwrap();
- !char_has_case(l) && !char_has_case(f)
- } else { false };
- (acc + if join { "_" } else { "" } + &next, Some(next))
- }).0
- }
-
- if !is_camel_case(name) {
- let c = to_camel_case(&name.as_str());
- let m = if c.is_empty() {
- format!("{} `{}` should have a camel case name such as `CamelCase`", sort, name)
- } else {
- format!("{} `{}` should have a camel case name such as `{}`", sort, name, c)
- };
- cx.span_lint(NON_CAMEL_CASE_TYPES, span, &m);
- }
- }
-}
-
-impl LintPass for NonCamelCaseTypes {
- fn get_lints(&self) -> LintArray {
- lint_array!(NON_CAMEL_CASE_TYPES)
- }
-}
-
-impl<'a, 'tcx> LateLintPass<'a, 'tcx> for NonCamelCaseTypes {
- fn check_item(&mut self, cx: &LateContext, it: &hir::Item) {
- let has_repr_c = it.attrs
- .iter()
- .any(|attr| {
- attr::find_repr_attrs(cx.tcx.sess.diagnostic(), attr)
- .iter()
- .any(|r| r == &attr::ReprC)
- });
-
- if has_repr_c {
- return;
- }
-
- match it.node {
- hir::ItemKind::Ty(..) |
- hir::ItemKind::Enum(..) |
- hir::ItemKind::Struct(..) |
- hir::ItemKind::Union(..) => self.check_case(cx, "type", it.name, it.span),
- hir::ItemKind::Trait(..) => self.check_case(cx, "trait", it.name, it.span),
- _ => (),
- }
- }
-
- fn check_variant(&mut self, cx: &LateContext, v: &hir::Variant, _: &hir::Generics) {
- self.check_case(cx, "variant", v.node.name, v.span);
- }
-
- fn check_generic_param(&mut self, cx: &LateContext, param: &hir::GenericParam) {
- match param.kind {
- GenericParamKind::Lifetime { .. } => {}
- GenericParamKind::Type { synthetic, .. } => {
- if synthetic.is_none() {
- self.check_case(cx, "type parameter", param.name.ident().name, param.span);
- }
- }
- }
- }
-}
-
-declare_lint! {
- pub NON_SNAKE_CASE,
- Warn,
- "variables, methods, functions, lifetime parameters and modules should have snake case names"
-}
-
-#[derive(Copy, Clone)]
-pub struct NonSnakeCase;
-
-impl NonSnakeCase {
- fn to_snake_case(mut str: &str) -> String {
- let mut words = vec![];
- // Preserve leading underscores
- str = str.trim_left_matches(|c: char| {
- if c == '_' {
- words.push(String::new());
- true
- } else {
- false
- }
- });
- for s in str.split('_') {
- let mut last_upper = false;
- let mut buf = String::new();
- if s.is_empty() {
- continue;
- }
- for ch in s.chars() {
- if !buf.is_empty() && buf != "'" && ch.is_uppercase() && !last_upper {
- words.push(buf);
- buf = String::new();
- }
- last_upper = ch.is_uppercase();
- buf.extend(ch.to_lowercase());
- }
- words.push(buf);
- }
- words.join("_")
- }
-
- fn check_snake_case(&self, cx: &LateContext, sort: &str, name: &str, span: Option<Span>) {
- fn is_snake_case(ident: &str) -> bool {
- if ident.is_empty() {
- return true;
- }
- let ident = ident.trim_left_matches('\'');
- let ident = ident.trim_matches('_');
-
- let mut allow_underscore = true;
- ident.chars().all(|c| {
- allow_underscore = match c {
- '_' if !allow_underscore => return false,
- '_' => false,
- // It would be more obvious to use `c.is_lowercase()`,
- // but some characters do not have a lowercase form
- c if !c.is_uppercase() => true,
- _ => return false,
- };
- true
- })
- }
-
- if !is_snake_case(name) {
- let sc = NonSnakeCase::to_snake_case(name);
- let msg = if sc != name {
- format!("{} `{}` should have a snake case name such as `{}`",
- sort,
- name,
- sc)
- } else {
- format!("{} `{}` should have a snake case name", sort, name)
- };
- match span {
- Some(span) => cx.span_lint(NON_SNAKE_CASE, span, &msg),
- None => cx.lint(NON_SNAKE_CASE, &msg),
- }
- }
- }
-}
-
-impl LintPass for NonSnakeCase {
- fn get_lints(&self) -> LintArray {
- lint_array!(NON_SNAKE_CASE)
- }
-}
-
-impl<'a, 'tcx> LateLintPass<'a, 'tcx> for NonSnakeCase {
- fn check_crate(&mut self, cx: &LateContext, cr: &hir::Crate) {
- let attr_crate_name = attr::find_by_name(&cr.attrs, "crate_name")
- .and_then(|at| at.value_str().map(|s| (at, s)));
- if let Some(ref name) = cx.tcx.sess.opts.crate_name {
- self.check_snake_case(cx, "crate", name, None);
- } else if let Some((attr, name)) = attr_crate_name {
- self.check_snake_case(cx, "crate", &name.as_str(), Some(attr.span));
- }
- }
-
- fn check_generic_param(&mut self, cx: &LateContext, param: &hir::GenericParam) {
- match param.kind {
- GenericParamKind::Lifetime { .. } => {
- let name = param.name.ident().as_str();
- self.check_snake_case(cx, "lifetime", &name, Some(param.span));
- }
- GenericParamKind::Type { .. } => {}
- }
- }
-
- fn check_fn(&mut self,
- cx: &LateContext,
- fk: FnKind,
- _: &hir::FnDecl,
- _: &hir::Body,
- span: Span,
- id: ast::NodeId) {
- match fk {
- FnKind::Method(name, ..) => {
- match method_context(cx, id) {
- MethodLateContext::PlainImpl => {
- self.check_snake_case(cx, "method", &name.as_str(), Some(span))
- }
- MethodLateContext::TraitAutoImpl => {
- self.check_snake_case(cx, "trait method", &name.as_str(), Some(span))
- }
- _ => (),
- }
- }
- FnKind::ItemFn(name, _, header, _, attrs) => {
- // Skip foreign-ABI #[no_mangle] functions (Issue #31924)
- if header.abi != Abi::Rust && attr::find_by_name(attrs, "no_mangle").is_some() {
- return;
- }
- self.check_snake_case(cx, "function", &name.as_str(), Some(span))
- }
- FnKind::Closure(_) => (),
- }
- }
-
- fn check_item(&mut self, cx: &LateContext, it: &hir::Item) {
- if let hir::ItemKind::Mod(_) = it.node {
- self.check_snake_case(cx, "module", &it.name.as_str(), Some(it.span));
- }
- }
-
- fn check_trait_item(&mut self, cx: &LateContext, item: &hir::TraitItem) {
- if let hir::TraitItemKind::Method(_, hir::TraitMethod::Required(ref pnames)) = item.node {
- self.check_snake_case(cx,
- "trait method",
- &item.ident.as_str(),
- Some(item.span));
- for param_name in pnames {
- self.check_snake_case(cx, "variable", ¶m_name.as_str(), Some(param_name.span));
- }
- }
- }
-
- fn check_pat(&mut self, cx: &LateContext, p: &hir::Pat) {
- if let &PatKind::Binding(_, _, ref ident, _) = &p.node {
- self.check_snake_case(cx, "variable", &ident.as_str(), Some(p.span));
- }
- }
-
- fn check_struct_def(&mut self,
- cx: &LateContext,
- s: &hir::VariantData,
- _: ast::Name,
- _: &hir::Generics,
- _: ast::NodeId) {
- for sf in s.fields() {
- self.check_snake_case(cx, "structure field", &sf.ident.as_str(), Some(sf.span));
- }
- }
-}
-
-declare_lint! {
- pub NON_UPPER_CASE_GLOBALS,
- Warn,
- "static constants should have uppercase identifiers"
-}
-
-#[derive(Copy, Clone)]
-pub struct NonUpperCaseGlobals;
-
-impl NonUpperCaseGlobals {
- fn check_upper_case(cx: &LateContext, sort: &str, name: ast::Name, span: Span) {
- if name.as_str().chars().any(|c| c.is_lowercase()) {
- let uc = NonSnakeCase::to_snake_case(&name.as_str()).to_uppercase();
- if name != &*uc {
- cx.span_lint(NON_UPPER_CASE_GLOBALS,
- span,
- &format!("{} `{}` should have an upper case name such as `{}`",
- sort,
- name,
- uc));
- } else {
- cx.span_lint(NON_UPPER_CASE_GLOBALS,
- span,
- &format!("{} `{}` should have an upper case name", sort, name));
- }
- }
- }
-}
-
-impl LintPass for NonUpperCaseGlobals {
- fn get_lints(&self) -> LintArray {
- lint_array!(NON_UPPER_CASE_GLOBALS)
- }
-}
-
-impl<'a, 'tcx> LateLintPass<'a, 'tcx> for NonUpperCaseGlobals {
- fn check_item(&mut self, cx: &LateContext, it: &hir::Item) {
- match it.node {
- hir::ItemKind::Static(..) => {
- if attr::find_by_name(&it.attrs, "no_mangle").is_some() {
- return;
- }
- NonUpperCaseGlobals::check_upper_case(cx, "static variable", it.name, it.span);
- }
- hir::ItemKind::Const(..) => {
- NonUpperCaseGlobals::check_upper_case(cx, "constant", it.name, it.span);
- }
- _ => {}
- }
- }
-
- fn check_trait_item(&mut self, cx: &LateContext, ti: &hir::TraitItem) {
- match ti.node {
- hir::TraitItemKind::Const(..) => {
- NonUpperCaseGlobals::check_upper_case(cx, "associated constant",
- ti.ident.name, ti.span);
- }
- _ => {}
- }
- }
-
- fn check_impl_item(&mut self, cx: &LateContext, ii: &hir::ImplItem) {
- match ii.node {
- hir::ImplItemKind::Const(..) => {
- NonUpperCaseGlobals::check_upper_case(cx, "associated constant",
- ii.ident.name, ii.span);
- }
- _ => {}
- }
- }
-
- fn check_pat(&mut self, cx: &LateContext, p: &hir::Pat) {
- // Lint for constants that look like binding identifiers (#7526)
- if let PatKind::Path(hir::QPath::Resolved(None, ref path)) = p.node {
- if let Def::Const(..) = path.def {
- if path.segments.len() == 1 {
- NonUpperCaseGlobals::check_upper_case(cx,
- "constant in pattern",
- path.segments[0].ident.name,
- path.span);
- }
- }
- }
- }
-}
use lint::{LateContext, LintContext, LintArray};
use lint::{LintPass, LateLintPass, EarlyLintPass, EarlyContext};
-use std::collections::HashSet;
use rustc::util::nodemap::FxHashSet;
use syntax::tokenstream::{TokenTree, TokenStream};
use rustc::hir::{self, GenericParamKind, PatKind};
use rustc::hir::intravisit::FnKind;
-use bad_style::{MethodLateContext, method_context};
+use nonstandard_style::{MethodLateContext, method_context};
// hardwired lints from librustc
pub use lint::builtin::*;
doc_hidden_stack: Vec<bool>,
/// Private traits or trait items that leaked through. Don't check their methods.
- private_traits: HashSet<ast::NodeId>,
+ private_traits: FxHashSet<ast::NodeId>,
}
impl MissingDoc {
pub fn new() -> MissingDoc {
MissingDoc {
doc_hidden_stack: vec![false],
- private_traits: HashSet::new(),
+ private_traits: FxHashSet::default(),
}
}
let mut work_queue = vec![cfg.entry];
let mut reached_exit_without_self_call = false;
let mut self_call_spans = vec![];
- let mut visited = HashSet::new();
+ let mut visited = FxHashSet::default();
while let Some(idx) = work_queue.pop() {
if idx == cfg.exit {
}
declare_lint! {
- UNNAMEABLE_TEST_FUNCTIONS,
+ UNNAMEABLE_TEST_ITEMS,
Warn,
- "detects an function that cannot be named being marked as #[test]"
+ "detects an item that cannot be named being marked as #[test_case]",
+ report_in_external_macro: true
+}
+
+pub struct UnnameableTestItems {
+ boundary: ast::NodeId, // NodeId of the item under which things are not nameable
+ items_nameable: bool,
}
-pub struct UnnameableTestFunctions;
+impl UnnameableTestItems {
+ pub fn new() -> Self {
+ Self {
+ boundary: ast::DUMMY_NODE_ID,
+ items_nameable: true
+ }
+ }
+}
-impl LintPass for UnnameableTestFunctions {
+impl LintPass for UnnameableTestItems {
fn get_lints(&self) -> LintArray {
- lint_array!(UNNAMEABLE_TEST_FUNCTIONS)
+ lint_array!(UNNAMEABLE_TEST_ITEMS)
}
}
-impl<'a, 'tcx> LateLintPass<'a, 'tcx> for UnnameableTestFunctions {
+impl<'a, 'tcx> LateLintPass<'a, 'tcx> for UnnameableTestItems {
fn check_item(&mut self, cx: &LateContext, it: &hir::Item) {
- match it.node {
- hir::ItemKind::Fn(..) => {
- for attr in &it.attrs {
- if attr.name() == "test" {
- let parent = cx.tcx.hir.get_parent(it.id);
- match cx.tcx.hir.find(parent) {
- Some(Node::Item(hir::Item {node: hir::ItemKind::Mod(_), ..})) |
- None => {}
- _ => {
- cx.struct_span_lint(
- UNNAMEABLE_TEST_FUNCTIONS,
- attr.span,
- "cannot test inner function",
- ).emit();
- }
- }
- break;
- }
- }
+ if self.items_nameable {
+ if let hir::ItemKind::Mod(..) = it.node {}
+ else {
+ self.items_nameable = false;
+ self.boundary = it.id;
}
- _ => return,
- };
+ return;
+ }
+
+ if let Some(attr) = attr::find_by_name(&it.attrs, "rustc_test_marker") {
+ cx.struct_span_lint(
+ UNNAMEABLE_TEST_ITEMS,
+ attr.span,
+ "cannot test inner items",
+ ).emit();
+ }
+ }
+
+ fn check_item_post(&mut self, _cx: &LateContext, it: &hir::Item) {
+ if !self.items_nameable && self.boundary == it.id {
+ self.items_nameable = true;
+ }
}
}
use lint::LintId;
use lint::FutureIncompatibleInfo;
-mod bad_style;
+mod nonstandard_style;
pub mod builtin;
mod types;
mod unused;
-use bad_style::*;
+use nonstandard_style::*;
use builtin::*;
use types::*;
use unused::*;
macro_rules! add_lint_group {
($sess:ident, $name:expr, $($lint:ident),*) => (
- store.register_group($sess, false, $name, vec![$(LintId::of($lint)),*]);
+ store.register_group($sess, false, $name, None, vec![$(LintId::of($lint)),*]);
)
}
MutableTransmutes: MutableTransmutes,
UnionsWithDropFields: UnionsWithDropFields,
UnreachablePub: UnreachablePub,
- UnnameableTestFunctions: UnnameableTestFunctions,
+ UnnameableTestItems: UnnameableTestItems::new(),
TypeAliasBounds: TypeAliasBounds,
UnusedBrokenConst: UnusedBrokenConst,
TrivialConstraints: TrivialConstraints,
--- /dev/null
+// Copyright 2015 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+use rustc::hir::def::Def;
+use rustc::ty;
+use lint::{LateContext, LintContext, LintArray};
+use lint::{LintPass, LateLintPass};
+
+use rustc_target::spec::abi::Abi;
+use syntax::ast;
+use syntax::attr;
+use syntax_pos::Span;
+
+use rustc::hir::{self, GenericParamKind, PatKind};
+use rustc::hir::intravisit::FnKind;
+
+#[derive(PartialEq)]
+pub enum MethodLateContext {
+ TraitAutoImpl,
+ TraitImpl,
+ PlainImpl,
+}
+
+pub fn method_context(cx: &LateContext, id: ast::NodeId) -> MethodLateContext {
+ let def_id = cx.tcx.hir.local_def_id(id);
+ let item = cx.tcx.associated_item(def_id);
+ match item.container {
+ ty::TraitContainer(..) => MethodLateContext::TraitAutoImpl,
+ ty::ImplContainer(cid) => {
+ match cx.tcx.impl_trait_ref(cid) {
+ Some(_) => MethodLateContext::TraitImpl,
+ None => MethodLateContext::PlainImpl,
+ }
+ }
+ }
+}
+
+declare_lint! {
+ pub NON_CAMEL_CASE_TYPES,
+ Warn,
+ "types, variants, traits and type parameters should have camel case names"
+}
+
+#[derive(Copy, Clone)]
+pub struct NonCamelCaseTypes;
+
+impl NonCamelCaseTypes {
+ fn check_case(&self, cx: &LateContext, sort: &str, name: ast::Name, span: Span) {
+ fn char_has_case(c: char) -> bool {
+ c.is_lowercase() || c.is_uppercase()
+ }
+
+ fn is_camel_case(name: ast::Name) -> bool {
+ let name = name.as_str();
+ if name.is_empty() {
+ return true;
+ }
+ let name = name.trim_matches('_');
+
+ // start with a non-lowercase letter rather than non-uppercase
+ // ones (some scripts don't have a concept of upper/lowercase)
+ !name.is_empty() && !name.chars().next().unwrap().is_lowercase() &&
+ !name.contains("__") && !name.chars().collect::<Vec<_>>().windows(2).any(|pair| {
+ // contains a capitalisable character followed by, or preceded by, an underscore
+ char_has_case(pair[0]) && pair[1] == '_' ||
+ char_has_case(pair[1]) && pair[0] == '_'
+ })
+ }
+
+ fn to_camel_case(s: &str) -> String {
+ s.trim_matches('_')
+ .split('_')
+ .map(|word| {
+ word.chars().enumerate().map(|(i, c)| if i == 0 {
+ c.to_uppercase().collect::<String>()
+ } else {
+ c.to_lowercase().collect()
+ })
+ .collect::<String>()
+ })
+ .filter(|x| !x.is_empty())
+ .fold((String::new(), None), |(acc, prev): (String, Option<String>), next| {
+ // separate two components with an underscore if their boundary cannot
+ // be distinguished using a uppercase/lowercase case distinction
+ let join = if let Some(prev) = prev {
+ let l = prev.chars().last().unwrap();
+ let f = next.chars().next().unwrap();
+ !char_has_case(l) && !char_has_case(f)
+ } else { false };
+ (acc + if join { "_" } else { "" } + &next, Some(next))
+ }).0
+ }
+
+ if !is_camel_case(name) {
+ let c = to_camel_case(&name.as_str());
+ let m = if c.is_empty() {
+ format!("{} `{}` should have a camel case name such as `CamelCase`", sort, name)
+ } else {
+ format!("{} `{}` should have a camel case name such as `{}`", sort, name, c)
+ };
+ cx.span_lint(NON_CAMEL_CASE_TYPES, span, &m);
+ }
+ }
+}
+
+impl LintPass for NonCamelCaseTypes {
+ fn get_lints(&self) -> LintArray {
+ lint_array!(NON_CAMEL_CASE_TYPES)
+ }
+}
+
+impl<'a, 'tcx> LateLintPass<'a, 'tcx> for NonCamelCaseTypes {
+ fn check_item(&mut self, cx: &LateContext, it: &hir::Item) {
+ let has_repr_c = it.attrs
+ .iter()
+ .any(|attr| {
+ attr::find_repr_attrs(cx.tcx.sess.diagnostic(), attr)
+ .iter()
+ .any(|r| r == &attr::ReprC)
+ });
+
+ if has_repr_c {
+ return;
+ }
+
+ match it.node {
+ hir::ItemKind::Ty(..) |
+ hir::ItemKind::Enum(..) |
+ hir::ItemKind::Struct(..) |
+ hir::ItemKind::Union(..) => self.check_case(cx, "type", it.name, it.span),
+ hir::ItemKind::Trait(..) => self.check_case(cx, "trait", it.name, it.span),
+ _ => (),
+ }
+ }
+
+ fn check_variant(&mut self, cx: &LateContext, v: &hir::Variant, _: &hir::Generics) {
+ self.check_case(cx, "variant", v.node.name, v.span);
+ }
+
+ fn check_generic_param(&mut self, cx: &LateContext, param: &hir::GenericParam) {
+ match param.kind {
+ GenericParamKind::Lifetime { .. } => {}
+ GenericParamKind::Type { synthetic, .. } => {
+ if synthetic.is_none() {
+ self.check_case(cx, "type parameter", param.name.ident().name, param.span);
+ }
+ }
+ }
+ }
+}
+
+declare_lint! {
+ pub NON_SNAKE_CASE,
+ Warn,
+ "variables, methods, functions, lifetime parameters and modules should have snake case names"
+}
+
+#[derive(Copy, Clone)]
+pub struct NonSnakeCase;
+
+impl NonSnakeCase {
+ fn to_snake_case(mut str: &str) -> String {
+ let mut words = vec![];
+ // Preserve leading underscores
+ str = str.trim_left_matches(|c: char| {
+ if c == '_' {
+ words.push(String::new());
+ true
+ } else {
+ false
+ }
+ });
+ for s in str.split('_') {
+ let mut last_upper = false;
+ let mut buf = String::new();
+ if s.is_empty() {
+ continue;
+ }
+ for ch in s.chars() {
+ if !buf.is_empty() && buf != "'" && ch.is_uppercase() && !last_upper {
+ words.push(buf);
+ buf = String::new();
+ }
+ last_upper = ch.is_uppercase();
+ buf.extend(ch.to_lowercase());
+ }
+ words.push(buf);
+ }
+ words.join("_")
+ }
+
+ fn check_snake_case(&self, cx: &LateContext, sort: &str, name: &str, span: Option<Span>) {
+ fn is_snake_case(ident: &str) -> bool {
+ if ident.is_empty() {
+ return true;
+ }
+ let ident = ident.trim_left_matches('\'');
+ let ident = ident.trim_matches('_');
+
+ let mut allow_underscore = true;
+ ident.chars().all(|c| {
+ allow_underscore = match c {
+ '_' if !allow_underscore => return false,
+ '_' => false,
+ // It would be more obvious to use `c.is_lowercase()`,
+ // but some characters do not have a lowercase form
+ c if !c.is_uppercase() => true,
+ _ => return false,
+ };
+ true
+ })
+ }
+
+ if !is_snake_case(name) {
+ let sc = NonSnakeCase::to_snake_case(name);
+ let msg = if sc != name {
+ format!("{} `{}` should have a snake case name such as `{}`",
+ sort,
+ name,
+ sc)
+ } else {
+ format!("{} `{}` should have a snake case name", sort, name)
+ };
+ match span {
+ Some(span) => cx.span_lint(NON_SNAKE_CASE, span, &msg),
+ None => cx.lint(NON_SNAKE_CASE, &msg),
+ }
+ }
+ }
+}
+
+impl LintPass for NonSnakeCase {
+ fn get_lints(&self) -> LintArray {
+ lint_array!(NON_SNAKE_CASE)
+ }
+}
+
+impl<'a, 'tcx> LateLintPass<'a, 'tcx> for NonSnakeCase {
+ fn check_crate(&mut self, cx: &LateContext, cr: &hir::Crate) {
+ let attr_crate_name = attr::find_by_name(&cr.attrs, "crate_name")
+ .and_then(|at| at.value_str().map(|s| (at, s)));
+ if let Some(ref name) = cx.tcx.sess.opts.crate_name {
+ self.check_snake_case(cx, "crate", name, None);
+ } else if let Some((attr, name)) = attr_crate_name {
+ self.check_snake_case(cx, "crate", &name.as_str(), Some(attr.span));
+ }
+ }
+
+ fn check_generic_param(&mut self, cx: &LateContext, param: &hir::GenericParam) {
+ match param.kind {
+ GenericParamKind::Lifetime { .. } => {
+ let name = param.name.ident().as_str();
+ self.check_snake_case(cx, "lifetime", &name, Some(param.span));
+ }
+ GenericParamKind::Type { .. } => {}
+ }
+ }
+
+ fn check_fn(&mut self,
+ cx: &LateContext,
+ fk: FnKind,
+ _: &hir::FnDecl,
+ _: &hir::Body,
+ span: Span,
+ id: ast::NodeId) {
+ match fk {
+ FnKind::Method(name, ..) => {
+ match method_context(cx, id) {
+ MethodLateContext::PlainImpl => {
+ self.check_snake_case(cx, "method", &name.as_str(), Some(span))
+ }
+ MethodLateContext::TraitAutoImpl => {
+ self.check_snake_case(cx, "trait method", &name.as_str(), Some(span))
+ }
+ _ => (),
+ }
+ }
+ FnKind::ItemFn(name, _, header, _, attrs) => {
+ // Skip foreign-ABI #[no_mangle] functions (Issue #31924)
+ if header.abi != Abi::Rust && attr::find_by_name(attrs, "no_mangle").is_some() {
+ return;
+ }
+ self.check_snake_case(cx, "function", &name.as_str(), Some(span))
+ }
+ FnKind::Closure(_) => (),
+ }
+ }
+
+ fn check_item(&mut self, cx: &LateContext, it: &hir::Item) {
+ if let hir::ItemKind::Mod(_) = it.node {
+ self.check_snake_case(cx, "module", &it.name.as_str(), Some(it.span));
+ }
+ }
+
+ fn check_trait_item(&mut self, cx: &LateContext, item: &hir::TraitItem) {
+ if let hir::TraitItemKind::Method(_, hir::TraitMethod::Required(ref pnames)) = item.node {
+ self.check_snake_case(cx,
+ "trait method",
+ &item.ident.as_str(),
+ Some(item.span));
+ for param_name in pnames {
+ self.check_snake_case(cx, "variable", ¶m_name.as_str(), Some(param_name.span));
+ }
+ }
+ }
+
+ fn check_pat(&mut self, cx: &LateContext, p: &hir::Pat) {
+ if let &PatKind::Binding(_, _, ref ident, _) = &p.node {
+ self.check_snake_case(cx, "variable", &ident.as_str(), Some(p.span));
+ }
+ }
+
+ fn check_struct_def(&mut self,
+ cx: &LateContext,
+ s: &hir::VariantData,
+ _: ast::Name,
+ _: &hir::Generics,
+ _: ast::NodeId) {
+ for sf in s.fields() {
+ self.check_snake_case(cx, "structure field", &sf.ident.as_str(), Some(sf.span));
+ }
+ }
+}
+
+declare_lint! {
+ pub NON_UPPER_CASE_GLOBALS,
+ Warn,
+ "static constants should have uppercase identifiers"
+}
+
+#[derive(Copy, Clone)]
+pub struct NonUpperCaseGlobals;
+
+impl NonUpperCaseGlobals {
+ fn check_upper_case(cx: &LateContext, sort: &str, name: ast::Name, span: Span) {
+ if name.as_str().chars().any(|c| c.is_lowercase()) {
+ let uc = NonSnakeCase::to_snake_case(&name.as_str()).to_uppercase();
+ if name != &*uc {
+ cx.span_lint(NON_UPPER_CASE_GLOBALS,
+ span,
+ &format!("{} `{}` should have an upper case name such as `{}`",
+ sort,
+ name,
+ uc));
+ } else {
+ cx.span_lint(NON_UPPER_CASE_GLOBALS,
+ span,
+ &format!("{} `{}` should have an upper case name", sort, name));
+ }
+ }
+ }
+}
+
+impl LintPass for NonUpperCaseGlobals {
+ fn get_lints(&self) -> LintArray {
+ lint_array!(NON_UPPER_CASE_GLOBALS)
+ }
+}
+
+impl<'a, 'tcx> LateLintPass<'a, 'tcx> for NonUpperCaseGlobals {
+ fn check_item(&mut self, cx: &LateContext, it: &hir::Item) {
+ match it.node {
+ hir::ItemKind::Static(..) => {
+ if attr::find_by_name(&it.attrs, "no_mangle").is_some() {
+ return;
+ }
+ NonUpperCaseGlobals::check_upper_case(cx, "static variable", it.name, it.span);
+ }
+ hir::ItemKind::Const(..) => {
+ NonUpperCaseGlobals::check_upper_case(cx, "constant", it.name, it.span);
+ }
+ _ => {}
+ }
+ }
+
+ fn check_trait_item(&mut self, cx: &LateContext, ti: &hir::TraitItem) {
+ match ti.node {
+ hir::TraitItemKind::Const(..) => {
+ NonUpperCaseGlobals::check_upper_case(cx, "associated constant",
+ ti.ident.name, ti.span);
+ }
+ _ => {}
+ }
+ }
+
+ fn check_impl_item(&mut self, cx: &LateContext, ii: &hir::ImplItem) {
+ match ii.node {
+ hir::ImplItemKind::Const(..) => {
+ NonUpperCaseGlobals::check_upper_case(cx, "associated constant",
+ ii.ident.name, ii.span);
+ }
+ _ => {}
+ }
+ }
+
+ fn check_pat(&mut self, cx: &LateContext, p: &hir::Pat) {
+ // Lint for constants that look like binding identifiers (#7526)
+ if let PatKind::Path(hir::QPath::Resolved(None, ref path)) = p.node {
+ if let Def::Const(..) = path.def {
+ if path.segments.len() == 1 {
+ NonUpperCaseGlobals::check_upper_case(cx,
+ "constant in pattern",
+ path.segments[0].ident.name,
+ path.span);
+ }
+ }
+ }
+ }
+}
self.def_path_table.def_path_hash(item_id))
}
- fn get_variant(&self, item: &Entry, index: DefIndex) -> ty::VariantDef {
+ fn get_variant(&self,
+ tcx: TyCtxt<'a, 'tcx, 'tcx>,
+ item: &Entry,
+ index: DefIndex,
+ adt_kind: ty::AdtKind)
+ -> ty::VariantDef
+ {
let data = match item.kind {
EntryKind::Variant(data) |
EntryKind::Struct(data, _) |
_ => bug!(),
};
- ty::VariantDef {
- did: self.local_def_id(data.struct_ctor.unwrap_or(index)),
- name: self.item_name(index).as_symbol(),
- fields: item.children.decode(self).map(|index| {
+ ty::VariantDef::new(
+ tcx,
+ self.local_def_id(data.struct_ctor.unwrap_or(index)),
+ self.item_name(index).as_symbol(),
+ data.discr,
+ item.children.decode(self).map(|index| {
let f = self.entry(index);
ty::FieldDef {
did: self.local_def_id(index),
vis: f.visibility.decode(self)
}
}).collect(),
- discr: data.discr,
- ctor_kind: data.ctor_kind,
- }
+ adt_kind,
+ data.ctor_kind
+ )
}
pub fn get_adt_def(&self,
item.children
.decode(self)
.map(|index| {
- self.get_variant(&self.entry(index), index)
+ self.get_variant(tcx, &self.entry(index), index, kind)
})
.collect()
} else {
- vec![self.get_variant(&item, item_id)]
+ vec![self.get_variant(tcx, &item, item_id, kind)]
};
tcx.alloc_adt_def(did, kind, variants, repr)
// If the structure is marked as non_exhaustive then lower the visibility
// to within the crate.
- if adt_def.is_non_exhaustive() && ctor_vis == ty::Visibility::Public {
+ if adt_def.non_enum_variant().is_field_list_non_exhaustive() &&
+ ctor_vis == ty::Visibility::Public
+ {
ctor_vis = ty::Visibility::Restricted(DefId::local(CRATE_DEF_INDEX));
}
use creader::Library;
use schema::{METADATA_HEADER, rustc_version};
+use rustc_data_structures::fx::FxHashSet;
use rustc_data_structures::svh::Svh;
use rustc::middle::cstore::MetadataLoader;
use rustc::session::{config, Session};
use rustc_target::spec::{Target, TargetTriple};
use std::cmp;
-use std::collections::HashSet;
use std::fmt;
use std::fs;
use std::io::{self, Read};
impl<'a> Context<'a> {
pub fn maybe_load_library_crate(&mut self) -> Option<Library> {
- let mut seen_paths = HashSet::new();
+ let mut seen_paths = FxHashSet::default();
match self.extra_filename {
Some(s) => self.find_library_crate(s, &mut seen_paths)
.or_else(|| self.find_library_crate("", &mut seen_paths)),
fn find_library_crate(&mut self,
extra_prefix: &str,
- seen_paths: &mut HashSet<PathBuf>)
+ seen_paths: &mut FxHashSet<PathBuf>)
-> Option<Library> {
// If an SVH is specified, then this is a transitive dependency that
// must be loaded via -L plus some filtering.
use rustc::mir::{LocalDecl, LocalKind, Location, Operand, Place};
use rustc::mir::{ProjectionElem, Rvalue, Statement, StatementKind};
use rustc::ty;
+use rustc_data_structures::fx::FxHashSet;
use rustc_data_structures::indexed_vec::Idx;
use rustc_data_structures::sync::Lrc;
use rustc_errors::DiagnosticBuilder;
use super::{Context, MirBorrowckCtxt};
use super::{InitializationRequiringAction, PrefixSet};
+use dataflow::drop_flag_effects;
+use dataflow::move_paths::indexes::MoveOutIndex;
use dataflow::move_paths::MovePathIndex;
-use dataflow::{FlowAtLocation, MovingOutStatements};
use util::borrowck_errors::{BorrowckErrors, Origin};
impl<'cx, 'gcx, 'tcx> MirBorrowckCtxt<'cx, 'gcx, 'tcx> {
desired_action: InitializationRequiringAction,
(place, span): (&Place<'tcx>, Span),
mpi: MovePathIndex,
- curr_move_out: &FlowAtLocation<MovingOutStatements<'_, 'gcx, 'tcx>>,
) {
let use_spans = self
.move_spans(place, context.loc)
.or_else(|| self.borrow_spans(span, context.loc));
let span = use_spans.args_or_use();
- let mois = self.move_data.path_map[mpi]
- .iter()
- .filter(|moi| curr_move_out.contains(moi))
- .collect::<Vec<_>>();
+ let mois = self.get_moved_indexes(context, mpi);
+ debug!("report_use_of_moved_or_uninitialized: mois={:?}", mois);
if mois.is_empty() {
let root_place = self.prefixes(&place, PrefixSet::All).last().unwrap();
let mut is_loop_move = false;
for moi in &mois {
- let move_out = self.move_data.moves[**moi];
+ let move_out = self.move_data.moves[*moi];
let moved_place = &self.move_data.move_paths[move_out.path].place;
let move_spans = self.move_spans(moved_place, move_out.source);
};
if needs_note {
- let mpi = self.move_data.moves[*mois[0]].path;
+ let mpi = self.move_data.moves[mois[0]].path;
let place = &self.move_data.move_paths[mpi].place;
if let Some(ty) = self.retrieve_type_for_place(place) {
if issued_spans == borrow_spans {
borrow_spans.var_span_label(
&mut err,
- format!(
- "borrows occur due to use of `{}` in closure",
- desc_place
- ),
+ format!("borrows occur due to use of `{}` in closure", desc_place),
);
} else {
let borrow_place = &issued_borrow.borrowed_place;
borrow_spans.var_span_label(
&mut err,
- format!("second borrow occurs due to use of `{}` in closure", desc_place),
+ format!(
+ "second borrow occurs due to use of `{}` in closure",
+ desc_place
+ ),
);
}
let mut err = match &self.describe_place(&borrow.borrowed_place) {
Some(_) if self.is_place_thread_local(root_place) => {
- self.report_thread_local_value_does_not_live_long_enough(
- drop_span,
- borrow_span,
- )
+ self.report_thread_local_value_does_not_live_long_enough(drop_span, borrow_span)
}
Some(name) => self.report_local_value_does_not_live_long_enough(
context,
);
let mut err = self.tcx.path_does_not_live_long_enough(
- borrow_span, &format!("`{}`", name), Origin::Mir);
+ borrow_span,
+ &format!("`{}`", name),
+ Origin::Mir,
+ );
err.span_label(borrow_span, "borrowed value does not live long enough");
err.span_label(
drop_span, borrow_span
);
- let mut err = self.tcx.thread_local_value_does_not_live_long_enough(
- borrow_span, Origin::Mir);
+ let mut err = self
+ .tcx
+ .thread_local_value_does_not_live_long_enough(borrow_span, Origin::Mir);
- err.span_label(borrow_span,
- "thread-local variables cannot be borrowed beyond the end of the function");
+ err.span_label(
+ borrow_span,
+ "thread-local variables cannot be borrowed beyond the end of the function",
+ );
err.span_label(drop_span, "end of enclosing function is here");
err
}
err
}
+ fn get_moved_indexes(&mut self, context: Context, mpi: MovePathIndex) -> Vec<MoveOutIndex> {
+ let mir = self.mir;
+
+ let mut stack = Vec::new();
+ stack.extend(mir.predecessor_locations(context.loc));
+
+ let mut visited = FxHashSet();
+ let mut result = vec![];
+
+ 'dfs: while let Some(l) = stack.pop() {
+ debug!(
+ "report_use_of_moved_or_uninitialized: current_location={:?}",
+ l
+ );
+
+ if !visited.insert(l) {
+ continue;
+ }
+
+ // check for moves
+ let stmt_kind = mir[l.block]
+ .statements
+ .get(l.statement_index)
+ .map(|s| &s.kind);
+ if let Some(StatementKind::StorageDead(..)) = stmt_kind {
+ // this analysis only tries to find moves explicitly
+ // written by the user, so we ignore the move-outs
+ // created by `StorageDead` and at the beginning
+ // of a function.
+ } else {
+ for moi in &self.move_data.loc_map[l] {
+ debug!("report_use_of_moved_or_uninitialized: moi={:?}", moi);
+ if self.move_data.moves[*moi].path == mpi {
+ debug!("report_use_of_moved_or_uninitialized: found");
+ result.push(*moi);
+
+ // Strictly speaking, we could continue our DFS here. There may be
+ // other moves that can reach the point of error. But it is kind of
+ // confusing to highlight them.
+ //
+ // Example:
+ //
+ // ```
+ // let a = vec![];
+ // let b = a;
+ // let c = a;
+ // drop(a); // <-- current point of error
+ // ```
+ //
+ // Because we stop the DFS here, we only highlight `let c = a`,
+ // and not `let b = a`. We will of course also report an error at
+ // `let c = a` which highlights `let b = a` as the move.
+ continue 'dfs;
+ }
+ }
+ }
+
+ // check for inits
+ let mut any_match = false;
+ drop_flag_effects::for_location_inits(self.tcx, self.mir, self.move_data, l, |m| {
+ if m == mpi {
+ any_match = true;
+ }
+ });
+ if any_match {
+ continue 'dfs;
+ }
+
+ stack.extend(mir.predecessor_locations(l));
+ }
+
+ result
+ }
+
pub(super) fn report_illegal_mutation_of_borrowed(
&mut self,
context: Context,
let attrs = self.tcx.get_attrs(statik.def_id);
let is_thread_local = attrs.iter().any(|attr| attr.check_name("thread_local"));
- debug!("is_place_thread_local: attrs={:?} is_thread_local={:?}",
- attrs, is_thread_local);
+ debug!(
+ "is_place_thread_local: attrs={:?} is_thread_local={:?}",
+ attrs, is_thread_local
+ );
is_thread_local
} else {
debug!("is_place_thread_local: no");
// it's present.
args_span: Span,
// The span of the first use of the captured variable inside the closure.
- var_span: Span
+ var_span: Span,
},
// This access has a single span associated to it: common case.
OtherUse(Span),
use dataflow::move_paths::indexes::BorrowIndex;
use dataflow::move_paths::HasMoveData;
use dataflow::Borrows;
-use dataflow::{EverInitializedPlaces, MovingOutStatements};
+use dataflow::EverInitializedPlaces;
use dataflow::{FlowAtLocation, FlowsAtLocation};
use dataflow::MaybeUninitializedPlaces;
use either::Either;
crate struct Flows<'b, 'gcx: 'tcx, 'tcx: 'b> {
borrows: FlowAtLocation<Borrows<'b, 'gcx, 'tcx>>,
pub uninits: FlowAtLocation<MaybeUninitializedPlaces<'b, 'gcx, 'tcx>>,
- pub move_outs: FlowAtLocation<MovingOutStatements<'b, 'gcx, 'tcx>>,
pub ever_inits: FlowAtLocation<EverInitializedPlaces<'b, 'gcx, 'tcx>>,
/// Polonius Output
crate fn new(
borrows: FlowAtLocation<Borrows<'b, 'gcx, 'tcx>>,
uninits: FlowAtLocation<MaybeUninitializedPlaces<'b, 'gcx, 'tcx>>,
- move_outs: FlowAtLocation<MovingOutStatements<'b, 'gcx, 'tcx>>,
ever_inits: FlowAtLocation<EverInitializedPlaces<'b, 'gcx, 'tcx>>,
polonius_output: Option<Rc<Output<RegionVid, BorrowIndex, LocationIndex>>>,
) -> Self {
Flows {
borrows,
uninits,
- move_outs,
ever_inits,
polonius_output,
}
($this:ident, $meth:ident($arg:ident)) => {
FlowAtLocation::$meth(&mut $this.borrows, $arg);
FlowAtLocation::$meth(&mut $this.uninits, $arg);
- FlowAtLocation::$meth(&mut $this.move_outs, $arg);
FlowAtLocation::$meth(&mut $this.ever_inits, $arg);
};
}
});
s.push_str("] ");
- s.push_str("move_out: [");
- let mut saw_one = false;
- self.move_outs.each_state_bit(|mpi_move_out| {
- if saw_one {
- s.push_str(", ");
- };
- saw_one = true;
- let move_out = &self.move_outs.operator().move_data().moves[mpi_move_out];
- s.push_str(&format!("{:?}", move_out));
- });
- s.push_str("] ");
-
s.push_str("ever_init: [");
let mut saw_one = false;
self.ever_inits.each_state_bit(|mpi_ever_init| {
use dataflow::FlowAtLocation;
use dataflow::MoveDataParamEnv;
use dataflow::{do_dataflow, DebugFormatted};
-use dataflow::{EverInitializedPlaces, MovingOutStatements};
+use dataflow::EverInitializedPlaces;
use dataflow::{MaybeInitializedPlaces, MaybeUninitializedPlaces};
use util::borrowck_errors::{BorrowckErrors, Origin};
MaybeUninitializedPlaces::new(tcx, mir, &mdpe),
|bd, i| DebugFormatted::new(&bd.move_data().move_paths[i]),
));
- let flow_move_outs = FlowAtLocation::new(do_dataflow(
- tcx,
- mir,
- id,
- &attributes,
- &dead_unwinds,
- MovingOutStatements::new(tcx, mir, &mdpe),
- |bd, i| DebugFormatted::new(&bd.move_data().moves[i]),
- ));
let flow_ever_inits = FlowAtLocation::new(do_dataflow(
tcx,
mir,
let mut state = Flows::new(
flow_borrows,
flow_uninits,
- flow_move_outs,
flow_ever_inits,
polonius_output,
);
let place = self.base_path(place_span.0);
let maybe_uninits = &flow_state.uninits;
- let curr_move_outs = &flow_state.move_outs;
// Bad scenarios:
//
desired_action,
place_span,
mpi,
- curr_move_outs,
);
return; // don't bother finding other problems.
}
let place = self.base_path(place_span.0);
let maybe_uninits = &flow_state.uninits;
- let curr_move_outs = &flow_state.move_outs;
// Bad scenarios:
//
desired_action,
place_span,
child_mpi,
- curr_move_outs,
);
return; // don't bother finding other problems.
}
flow_inits,
move_data,
elements,
- errors_buffer,
);
if let Some(all_facts) = &mut all_facts {
use rustc::traits::query::{Fallible, NoSolution};
use rustc::ty::fold::TypeFoldable;
use rustc::ty::{self, CanonicalTy, RegionVid, ToPolyTraitRef, Ty, TyCtxt, TyKind};
-use rustc_errors::Diagnostic;
use std::fmt;
use std::rc::Rc;
use syntax_pos::{Span, DUMMY_SP};
/// - `liveness` -- results of a liveness computation on the MIR; used to create liveness
/// constraints for the regions in the types of variables
/// - `flow_inits` -- results of a maybe-init dataflow analysis
-/// - `move_data` -- move-data constructed when performing the maybe-init dataflow analysis
-/// - `errors_buffer` -- errors are sent here for future reporting
+/// - `move_data` -- move-data constructed when performing the maybe-init dataflow analysiss
pub(crate) fn type_check<'gcx, 'tcx>(
infcx: &InferCtxt<'_, 'gcx, 'tcx>,
param_env: ty::ParamEnv<'gcx>,
flow_inits: &mut FlowAtLocation<MaybeInitializedPlaces<'_, 'gcx, 'tcx>>,
move_data: &MoveData<'tcx>,
elements: &Rc<RegionValueElements>,
- errors_buffer: &mut Vec<Diagnostic>,
) -> MirTypeckResults<'tcx> {
let implicit_region_bound = infcx.tcx.mk_region(ty::ReVar(universal_regions.fr_fn_body));
let mut constraints = MirTypeckRegionConstraints {
®ion_bound_pairs,
Some(implicit_region_bound),
Some(&mut borrowck_context),
- Some(errors_buffer),
|cx| {
cx.equate_inputs_and_outputs(
mir,
region_bound_pairs: &'a [(ty::Region<'tcx>, GenericKind<'tcx>)],
implicit_region_bound: Option<ty::Region<'tcx>>,
borrowck_context: Option<&'a mut BorrowCheckContext<'a, 'tcx>>,
- errors_buffer: Option<&mut Vec<Diagnostic>>,
mut extra: impl FnMut(&mut TypeChecker<'a, 'gcx, 'tcx>) -> R,
) -> R where {
let mut checker = TypeChecker::new(
if !errors_reported {
// if verifier failed, don't do further checks to avoid ICEs
- checker.typeck_mir(mir, errors_buffer);
+ checker.typeck_mir(mir);
}
extra(&mut checker)
mir: &Mir<'tcx>,
term: &Terminator<'tcx>,
term_location: Location,
- errors_buffer: &mut Option<&mut Vec<Diagnostic>>,
) {
debug!("check_terminator: {:?}", term);
let tcx = self.tcx();
&sig,
);
let sig = self.normalize(sig, term_location);
- self.check_call_dest(mir, term, &sig, destination, term_location, errors_buffer);
+ self.check_call_dest(mir, term, &sig, destination, term_location);
self.prove_predicates(
sig.inputs().iter().map(|ty| ty::Predicate::WellFormed(ty)),
sig: &ty::FnSig<'tcx>,
destination: &Option<(Place<'tcx>, BasicBlock)>,
term_location: Location,
- errors_buffer: &mut Option<&mut Vec<Diagnostic>>,
) {
let tcx = self.tcx();
match *destination {
// this check is done at `check_local`.
if self.tcx().features().unsized_locals {
let span = term.source_info.span;
- self.ensure_place_sized(dest_ty, span, errors_buffer);
+ self.ensure_place_sized(dest_ty, span);
}
}
None => {
mir: &Mir<'tcx>,
local: Local,
local_decl: &LocalDecl<'tcx>,
- errors_buffer: &mut Option<&mut Vec<Diagnostic>>,
) {
match mir.local_kind(local) {
LocalKind::ReturnPointer | LocalKind::Arg => {
}
// When `#![feature(unsized_locals)]` is enabled, only function calls
- // are checked in `check_call_dest`.
+ // and nullary ops are checked in `check_call_dest`.
if !self.tcx().features().unsized_locals {
let span = local_decl.source_info.span;
let ty = local_decl.ty;
- self.ensure_place_sized(ty, span, errors_buffer);
+ self.ensure_place_sized(ty, span);
}
}
- fn ensure_place_sized(&mut self,
- ty: Ty<'tcx>,
- span: Span,
- errors_buffer: &mut Option<&mut Vec<Diagnostic>>) {
+ fn ensure_place_sized(&mut self, ty: Ty<'tcx>, span: Span) {
let tcx = self.tcx();
// Erase the regions from `ty` to get a global type. The
cannot be statically determined",
ty
);
- if let Some(ref mut errors_buffer) = *errors_buffer {
- diag.buffer(errors_buffer);
- } else {
- // we're allowed to use emit() here because the
- // NLL migration will be turned on (and thus
- // errors will need to be buffered) *only if*
- // errors_buffer is Some.
- diag.emit();
- }
+
+ // While this is located in `nll::typeck` this error is not
+ // an NLL error, it's a required check to prevent creation
+ // of unsized rvalues in certain cases:
+ // * operand of a box expression
+ // * callee in a call expression
+ diag.emit();
}
}
}
},
Rvalue::NullaryOp(_, ty) => {
+ // Even with unsized locals cannot box an unsized value.
+ if self.tcx().features().unsized_locals {
+ let span = mir.source_info(location).span;
+ self.ensure_place_sized(ty, span);
+ }
+
let trait_ref = ty::TraitRef {
def_id: tcx.lang_items().sized_trait().unwrap(),
substs: tcx.mk_substs_trait(ty, &[]),
})
}
- fn typeck_mir(&mut self, mir: &Mir<'tcx>, mut errors_buffer: Option<&mut Vec<Diagnostic>>) {
+ fn typeck_mir(&mut self, mir: &Mir<'tcx>) {
self.last_span = mir.span;
debug!("run_on_mir: {:?}", mir.span);
for (local, local_decl) in mir.local_decls.iter_enumerated() {
- self.check_local(mir, local, local_decl, &mut errors_buffer);
+ self.check_local(mir, local, local_decl);
}
for (block, block_data) in mir.basic_blocks().iter_enumerated() {
location.statement_index += 1;
}
- self.check_terminator(mir, block_data.terminator(), location, &mut errors_buffer);
+ self.check_terminator(mir, block_data.terminator(), location);
self.check_iscleanup(mir, block_data);
}
}
&[],
None,
None,
- None,
|_| (),
);
bindings: Vec<Binding<'tcx>>,
// ...and the guard must be evaluated...
- guard: Option<ExprRef<'tcx>>,
+ guard: Option<Guard<'tcx>>,
// ...and then we branch to arm with this index.
arm_index: usize,
// the block to branch to if the guard fails; if there is no
// guard, this block is simply unreachable
- let guard = self.hir.mirror(guard);
+ let guard = match guard {
+ Guard::If(e) => self.hir.mirror(e),
+ };
let source_info = self.source_info(guard.span);
let cond = unpack!(block = self.as_local_operand(block, guard));
if autoref {
}
}
+impl_stable_hash_for!(struct CompileTimeEvaluator {});
+
#[derive(Clone, Debug)]
enum ConstEvalError {
NeedsRfc(String),
)
}
- fn try_ptr_op<'a>(
+ fn ptr_op<'a>(
_ecx: &EvalContext<'a, 'mir, 'tcx, Self>,
_bin_op: mir::BinOp,
- left: Scalar,
+ _left: Scalar,
_left_layout: TyLayout<'tcx>,
- right: Scalar,
+ _right: Scalar,
_right_layout: TyLayout<'tcx>,
- ) -> EvalResult<'tcx, Option<(Scalar, bool)>> {
- if left.is_bits() && right.is_bits() {
- Ok(None)
- } else {
- Err(
- ConstEvalError::NeedsRfc("pointer arithmetic or comparison".to_string()).into(),
- )
- }
+ ) -> EvalResult<'tcx, (Scalar, bool)> {
+ Err(
+ ConstEvalError::NeedsRfc("pointer arithmetic or comparison".to_string()).into(),
+ )
}
fn find_foreign_static<'a>(
use util::elaborate_drops::DropFlagState;
-use super::move_paths::{HasMoveData, MoveData, MoveOutIndex, MovePathIndex, InitIndex};
+use super::move_paths::{HasMoveData, MoveData, MovePathIndex, InitIndex};
use super::move_paths::{LookupResult, InitKind};
use super::{BitDenotation, BlockSets, InitialFlow};
use super::drop_flag_effects_for_function_entry;
use super::drop_flag_effects_for_location;
-use super::{on_lookup_result_bits, for_location_inits};
+use super::on_lookup_result_bits;
mod storage_liveness;
fn move_data(&self) -> &MoveData<'tcx> { &self.mdpe.move_data }
}
-/// `MovingOutStatements` tracks the statements that perform moves out
-/// of particular places. More precisely, it tracks whether the
-/// *effect* of such moves (namely, the uninitialization of the
-/// place in question) can reach some point in the control-flow of
-/// the function, or if that effect is "killed" by some intervening
-/// operation reinitializing that place.
-///
-/// The resulting dataflow is a more enriched version of
-/// `MaybeUninitializedPlaces`. Both structures on their own only tell
-/// you if a place *might* be uninitialized at a given point in the
-/// control flow. But `MovingOutStatements` also includes the added
-/// data of *which* particular statement causing the deinitialization
-/// that the borrow checker's error message may need to report.
-#[allow(dead_code)]
-pub struct MovingOutStatements<'a, 'gcx: 'tcx, 'tcx: 'a> {
- tcx: TyCtxt<'a, 'gcx, 'tcx>,
- mir: &'a Mir<'tcx>,
- mdpe: &'a MoveDataParamEnv<'gcx, 'tcx>,
-}
-
-impl<'a, 'gcx: 'tcx, 'tcx: 'a> MovingOutStatements<'a, 'gcx, 'tcx> {
- pub fn new(tcx: TyCtxt<'a, 'gcx, 'tcx>,
- mir: &'a Mir<'tcx>,
- mdpe: &'a MoveDataParamEnv<'gcx, 'tcx>)
- -> Self
- {
- MovingOutStatements { tcx: tcx, mir: mir, mdpe: mdpe }
- }
-}
-
-impl<'a, 'gcx, 'tcx> HasMoveData<'tcx> for MovingOutStatements<'a, 'gcx, 'tcx> {
- fn move_data(&self) -> &MoveData<'tcx> { &self.mdpe.move_data }
-}
-
/// `EverInitializedPlaces` tracks all places that might have ever been
/// initialized upon reaching a particular point in the control flow
/// for a function, without an intervening `Storage Dead`.
}
}
-impl<'a, 'gcx, 'tcx> BitDenotation for MovingOutStatements<'a, 'gcx, 'tcx> {
- type Idx = MoveOutIndex;
- fn name() -> &'static str { "moving_out" }
- fn bits_per_block(&self) -> usize {
- self.move_data().moves.len()
- }
-
- fn start_block_effect(&self, _sets: &mut IdxSet<MoveOutIndex>) {
- // no move-statements have been executed prior to function
- // execution, so this method has no effect on `_sets`.
- }
-
- fn statement_effect(&self,
- sets: &mut BlockSets<MoveOutIndex>,
- location: Location) {
- let (tcx, mir, move_data) = (self.tcx, self.mir, self.move_data());
- let stmt = &mir[location.block].statements[location.statement_index];
- let loc_map = &move_data.loc_map;
- let path_map = &move_data.path_map;
-
- match stmt.kind {
- // this analysis only tries to find moves explicitly
- // written by the user, so we ignore the move-outs
- // created by `StorageDead` and at the beginning
- // of a function.
- mir::StatementKind::StorageDead(_) => {}
- _ => {
- debug!("stmt {:?} at loc {:?} moves out of move_indexes {:?}",
- stmt, location, &loc_map[location]);
- // Every path deinitialized by a *particular move*
- // has corresponding bit, "gen'ed" (i.e. set)
- // here, in dataflow vector
- sets.gen_all_and_assert_dead(&loc_map[location]);
- }
- }
-
- for_location_inits(tcx, mir, move_data, location,
- |mpi| sets.kill_all(&path_map[mpi]));
- }
-
- fn terminator_effect(&self,
- sets: &mut BlockSets<MoveOutIndex>,
- location: Location)
- {
- let (tcx, mir, move_data) = (self.tcx, self.mir, self.move_data());
- let term = mir[location.block].terminator();
- let loc_map = &move_data.loc_map;
- let path_map = &move_data.path_map;
-
- debug!("terminator {:?} at loc {:?} moves out of move_indexes {:?}",
- term, location, &loc_map[location]);
- sets.gen_all_and_assert_dead(&loc_map[location]);
-
- for_location_inits(tcx, mir, move_data, location,
- |mpi| sets.kill_all(&path_map[mpi]));
- }
-
- fn propagate_call_return(&self,
- in_out: &mut IdxSet<MoveOutIndex>,
- _call_bb: mir::BasicBlock,
- _dest_bb: mir::BasicBlock,
- dest_place: &mir::Place) {
- let move_data = self.move_data();
- let bits_per_block = self.bits_per_block();
-
- let path_map = &move_data.path_map;
- on_lookup_result_bits(self.tcx,
- self.mir,
- move_data,
- move_data.rev_lookup.find(dest_place),
- |mpi| for moi in &path_map[mpi] {
- assert!(moi.index() < bits_per_block);
- in_out.remove(&moi);
- });
- }
-}
-
impl<'a, 'gcx, 'tcx> BitDenotation for EverInitializedPlaces<'a, 'gcx, 'tcx> {
type Idx = InitIndex;
fn name() -> &'static str { "ever_init" }
}
}
-impl<'a, 'gcx, 'tcx> BitwiseOperator for MovingOutStatements<'a, 'gcx, 'tcx> {
- #[inline]
- fn join(&self, pred1: Word, pred2: Word) -> Word {
- pred1 | pred2 // moves from both preds are in scope
- }
-}
-
impl<'a, 'gcx, 'tcx> BitwiseOperator for EverInitializedPlaces<'a, 'gcx, 'tcx> {
#[inline]
fn join(&self, pred1: Word, pred2: Word) -> Word {
}
}
-impl<'a, 'gcx, 'tcx> InitialFlow for MovingOutStatements<'a, 'gcx, 'tcx> {
- #[inline]
- fn bottom_value() -> bool {
- false // bottom = no loans in scope by default
- }
-}
-
impl<'a, 'gcx, 'tcx> InitialFlow for EverInitializedPlaces<'a, 'gcx, 'tcx> {
#[inline]
fn bottom_value() -> bool {
pub use self::impls::{MaybeStorageLive};
pub use self::impls::{MaybeInitializedPlaces, MaybeUninitializedPlaces};
-pub use self::impls::{DefinitelyInitializedPlaces, MovingOutStatements};
+pub use self::impls::DefinitelyInitializedPlaces;
pub use self::impls::EverInitializedPlaces;
pub use self::impls::borrows::Borrows;
pub use self::impls::HaveBeenBorrowedLocals;
use self::move_paths::MoveData;
mod at_location;
-mod drop_flag_effects;
+pub mod drop_flag_effects;
mod graphviz;
mod impls;
pub mod move_paths;
}
}
- fn gen_all_and_assert_dead<I>(&mut self, i: I)
- where I: IntoIterator,
- I::Item: Borrow<E>
- {
- for j in i {
- let j = j.borrow();
- let retval = self.gen_set.add(j);
- self.kill_set.remove(j);
- assert!(retval);
- }
- }
-
fn kill(&mut self, e: &E) {
self.gen_set.remove(e);
self.kill_set.add(e);
fn convert_arm<'a, 'gcx, 'tcx>(cx: &mut Cx<'a, 'gcx, 'tcx>, arm: &'tcx hir::Arm) -> Arm<'tcx> {
Arm {
patterns: arm.pats.iter().map(|p| cx.pattern_from_hir(p)).collect(),
- guard: arm.guard.to_ref(),
+ guard: match arm.guard {
+ Some(hir::Guard::If(ref e)) => Some(Guard::If(e.to_ref())),
+ _ => None,
+ },
body: arm.body.to_ref(),
// BUG: fix this
lint_level: LintLevel::Inherited,
use rustc_data_structures::indexed_vec::Idx;
use rustc::hir::def_id::{DefId, LOCAL_CRATE};
-use rustc::hir::map::blocks::FnLikeNode;
use rustc::hir::Node;
use rustc::middle::region;
use rustc::infer::InferCtxt;
let constness = match body_owner_kind {
hir::BodyOwnerKind::Const |
hir::BodyOwnerKind::Static(_) => hir::Constness::Const,
- hir::BodyOwnerKind::Fn => {
- let fn_like = FnLikeNode::from_node(infcx.tcx.hir.get(src_id));
- fn_like.map_or(hir::Constness::NotConst, |f| f.constness())
- }
+ hir::BodyOwnerKind::Fn => hir::Constness::NotConst,
};
let attrs = tcx.hir.attrs(src_id);
// Respect -C overflow-checks.
check_overflow |= tcx.sess.overflow_checks();
- // Constants and const fn's always need overflow checks.
+ // Constants always need overflow checks.
check_overflow |= constness == hir::Constness::Const;
let lint_level = lint_level_for_hir_id(tcx, src_id);
#[derive(Clone, Debug)]
pub struct Arm<'tcx> {
pub patterns: Vec<Pattern<'tcx>>,
- pub guard: Option<ExprRef<'tcx>>,
+ pub guard: Option<Guard<'tcx>>,
pub body: ExprRef<'tcx>,
pub lint_level: LintLevel,
}
+#[derive(Clone, Debug)]
+pub enum Guard<'tcx> {
+ If(ExprRef<'tcx>),
+}
+
#[derive(Copy, Clone, Debug)]
pub enum LogicalOp {
And,
fn is_non_exhaustive_enum(&self, ty: Ty<'tcx>) -> bool {
match ty.sty {
- ty::Adt(adt_def, ..) => adt_def.is_enum() && adt_def.is_non_exhaustive(),
+ ty::Adt(adt_def, ..) => adt_def.is_variant_list_non_exhaustive(),
_ => false,
}
}
}
(pattern, &**pat)
}).collect(),
- arm.guard.as_ref().map(|e| &**e)
+ arm.guard.as_ref().map(|g| match g {
+ hir::Guard::If(ref e) => &**e,
+ })
)).collect();
// Bail out early if inlining failed.
"cannot bind by-move into a pattern guard")
.span_label(p.span, "moves value into pattern guard")
.emit();
- } else if by_ref_span.is_some() {
- struct_span_err!(cx.tcx.sess, p.span, E0009,
- "cannot bind by-move and by-ref in the same pattern")
- .span_label(p.span, "by-move pattern here")
- .span_label(by_ref_span.unwrap(), "both by-ref and by-move used")
- .emit();
+ } else if let Some(by_ref_span) = by_ref_span {
+ struct_span_err!(
+ cx.tcx.sess,
+ p.span,
+ E0009,
+ "cannot bind by-move and by-ref in the same pattern",
+ )
+ .span_label(p.span, "by-move pattern here")
+ .span_label(by_ref_span, "both by-ref and by-move used")
+ .emit();
}
};
/// assign.
///
/// FIXME: this should be done by borrowck.
-fn check_for_mutation_in_guard(cx: &MatchVisitor, guard: &hir::Expr) {
+fn check_for_mutation_in_guard(cx: &MatchVisitor, guard: &hir::Guard) {
let mut checker = MutationChecker {
cx,
};
- ExprUseVisitor::new(&mut checker, cx.tcx, cx.param_env, cx.region_scope_tree, cx.tables, None)
- .walk_expr(guard);
+ match guard {
+ hir::Guard::If(expr) =>
+ ExprUseVisitor::new(&mut checker,
+ cx.tcx,
+ cx.param_env,
+ cx.region_scope_tree,
+ cx.tables,
+ None).walk_expr(expr),
+ };
}
struct MutationChecker<'a, 'tcx: 'a> {
use rustc_apfloat::ieee::{Single, Double};
use rustc::mir::interpret::{
- Scalar, EvalResult, Pointer, PointerArithmetic, EvalErrorKind,
- truncate, sign_extend
+ Scalar, EvalResult, Pointer, PointerArithmetic, EvalErrorKind, truncate
};
use rustc::mir::CastKind;
use rustc_apfloat::Float;
Misc => {
let src = self.read_value(src)?;
if self.type_is_fat_ptr(src_layout.ty) {
- match (src.value, self.type_is_fat_ptr(dest.layout.ty)) {
+ match (*src, self.type_is_fat_ptr(dest.layout.ty)) {
// pointers to extern types
(Value::Scalar(_),_) |
// slices and trait objects to other slices/trait objects
(Value::ScalarPair(..), true) => {
// No change to value
- self.write_value(src.value, dest)?;
+ self.write_value(*src, dest)?;
}
// slices and trait objects to thin pointers (dropping the metadata)
(Value::ScalarPair(data, _), false) => {
.discriminant_for_variant(*self.tcx, index)
.val;
return self.write_scalar(
- Scalar::Bits {
- bits: discr_val,
- size: dst_layout.size.bytes() as u8,
- },
+ Scalar::from_uint(discr_val, dst_layout.size),
dest);
}
}
match dest_layout.ty.sty {
Int(_) | Uint(_) => {
let v = self.truncate(v, dest_layout);
- Ok(Scalar::Bits {
- bits: v,
- size: dest_layout.size.bytes() as u8,
- })
+ Ok(Scalar::from_uint(v, dest_layout.size))
}
- Float(FloatTy::F32) if signed => Ok(Scalar::Bits {
- bits: Single::from_i128(v as i128).value.to_bits(),
- size: 4,
- }),
- Float(FloatTy::F64) if signed => Ok(Scalar::Bits {
- bits: Double::from_i128(v as i128).value.to_bits(),
- size: 8,
- }),
- Float(FloatTy::F32) => Ok(Scalar::Bits {
- bits: Single::from_u128(v).value.to_bits(),
- size: 4,
- }),
- Float(FloatTy::F64) => Ok(Scalar::Bits {
- bits: Double::from_u128(v).value.to_bits(),
- size: 8,
- }),
+ Float(FloatTy::F32) if signed => Ok(Scalar::from_uint(
+ Single::from_i128(v as i128).value.to_bits(),
+ Size::from_bits(32)
+ )),
+ Float(FloatTy::F64) if signed => Ok(Scalar::from_uint(
+ Double::from_i128(v as i128).value.to_bits(),
+ Size::from_bits(64)
+ )),
+ Float(FloatTy::F32) => Ok(Scalar::from_uint(
+ Single::from_u128(v).value.to_bits(),
+ Size::from_bits(32)
+ )),
+ Float(FloatTy::F64) => Ok(Scalar::from_uint(
+ Double::from_u128(v).value.to_bits(),
+ Size::from_bits(64)
+ )),
Char => {
- assert_eq!(v as u8 as u128, v);
- Ok(Scalar::Bits { bits: v, size: 4 })
+ // `u8` to `char` cast
+ debug_assert_eq!(v as u8 as u128, v);
+ Ok(Scalar::from_uint(v, Size::from_bytes(4)))
},
// No alignment check needed for raw pointers.
// But we have to truncate to target ptr size.
RawPtr(_) => {
- Ok(Scalar::Bits {
- bits: self.memory.truncate_to_ptr(v).0 as u128,
- size: self.memory.pointer_size().bytes() as u8,
- })
+ Ok(Scalar::from_uint(
+ self.truncate_to_ptr(v).0,
+ self.pointer_size(),
+ ))
},
// Casts to bool are not permitted by rustc, no need to handle them here.
match dest_ty.sty {
// float -> uint
Uint(t) => {
- let width = t.bit_width().unwrap_or(self.memory.pointer_size().bits() as usize);
+ let width = t.bit_width().unwrap_or(self.pointer_size().bits() as usize);
let v = match fty {
FloatTy::F32 => Single::from_bits(bits).to_u128(width).value,
FloatTy::F64 => Double::from_bits(bits).to_u128(width).value,
};
// This should already fit the bit width
- Ok(Scalar::Bits {
- bits: v,
- size: (width / 8) as u8,
- })
+ Ok(Scalar::from_uint(v, Size::from_bits(width as u64)))
},
// float -> int
Int(t) => {
- let width = t.bit_width().unwrap_or(self.memory.pointer_size().bits() as usize);
+ let width = t.bit_width().unwrap_or(self.pointer_size().bits() as usize);
let v = match fty {
FloatTy::F32 => Single::from_bits(bits).to_i128(width).value,
FloatTy::F64 => Double::from_bits(bits).to_i128(width).value,
};
- // We got an i128, but we may need something smaller. We have to truncate ourselves.
- let truncated = truncate(v as u128, Size::from_bits(width as u64));
- assert_eq!(sign_extend(truncated, Size::from_bits(width as u64)) as i128, v,
- "truncating and extending changed the value?!?");
- Ok(Scalar::Bits {
- bits: truncated,
- size: (width / 8) as u8,
- })
+ Ok(Scalar::from_int(v, Size::from_bits(width as u64)))
},
// f64 -> f32
Float(FloatTy::F32) if fty == FloatTy::F64 => {
- Ok(Scalar::Bits {
- bits: Single::to_bits(Double::from_bits(bits).convert(&mut false).value),
- size: 4,
- })
+ Ok(Scalar::from_uint(
+ Single::to_bits(Double::from_bits(bits).convert(&mut false).value),
+ Size::from_bits(32),
+ ))
},
// f32 -> f64
Float(FloatTy::F64) if fty == FloatTy::F32 => {
- Ok(Scalar::Bits {
- bits: Double::to_bits(Single::from_bits(bits).convert(&mut false).value),
- size: 8,
- })
+ Ok(Scalar::from_uint(
+ Double::to_bits(Single::from_bits(bits).convert(&mut false).value),
+ Size::from_bits(64),
+ ))
},
// identity cast
- Float(FloatTy:: F64) => Ok(Scalar::Bits {
- bits,
- size: 8,
- }),
- Float(FloatTy:: F32) => Ok(Scalar::Bits {
- bits,
- size: 4,
- }),
+ Float(FloatTy:: F64) => Ok(Scalar::from_uint(bits, Size::from_bits(64))),
+ Float(FloatTy:: F32) => Ok(Scalar::from_uint(bits, Size::from_bits(32))),
_ => err!(Unimplemented(format!("float to {:?} cast", dest_ty))),
}
}
// except according to those terms.
use std::fmt::Write;
-use std::hash::{Hash, Hasher};
use std::mem;
use rustc::hir::def_id::DefId;
use rustc::hir::def::Def;
use rustc::hir::map::definitions::DefPathData;
+use rustc::ich::StableHashingContext;
use rustc::mir;
use rustc::ty::layout::{
self, Size, Align, HasDataLayout, LayoutOf, TyLayout
use rustc::ty::subst::{Subst, Substs};
use rustc::ty::{self, Ty, TyCtxt, TypeFoldable};
use rustc::ty::query::TyCtxtAt;
-use rustc_data_structures::fx::{FxHashSet, FxHasher};
use rustc_data_structures::indexed_vec::IndexVec;
+use rustc_data_structures::stable_hasher::{HashStable, StableHasher, StableHasherResult};
use rustc::mir::interpret::{
- GlobalId, Scalar, FrameInfo,
+ GlobalId, Scalar, FrameInfo, AllocId,
EvalResult, EvalErrorKind,
ScalarMaybeUndef,
truncate, sign_extend,
Memory, Machine
};
+use super::snapshot::InfiniteLoopDetector;
+
pub struct EvalContext<'a, 'mir, 'tcx: 'a + 'mir, M: Machine<'mir, 'tcx>> {
/// Stores the `Machine` instance.
pub machine: M,
/// The locals are stored as `Option<Value>`s.
/// `None` represents a local that is currently dead, while a live local
/// can either directly contain `Scalar` or refer to some part of an `Allocation`.
- pub locals: IndexVec<mir::Local, LocalValue>,
+ pub locals: IndexVec<mir::Local, LocalValue<AllocId>>,
////////////////////////////////////////////////////////////////////////////////
// Current position within the function
pub stmt: usize,
}
-impl<'mir, 'tcx: 'mir> Eq for Frame<'mir, 'tcx> {}
-
-impl<'mir, 'tcx: 'mir> PartialEq for Frame<'mir, 'tcx> {
- fn eq(&self, other: &Self) -> bool {
- let Frame {
- mir: _,
- instance,
- span: _,
- return_to_block,
- return_place,
- locals,
- block,
- stmt,
- } = self;
-
- // Some of these are constant during evaluation, but are included
- // anyways for correctness.
- *instance == other.instance
- && *return_to_block == other.return_to_block
- && *return_place == other.return_place
- && *locals == other.locals
- && *block == other.block
- && *stmt == other.stmt
- }
-}
+impl<'a, 'mir, 'tcx: 'mir> HashStable<StableHashingContext<'a>> for Frame<'mir, 'tcx> {
+ fn hash_stable<W: StableHasherResult>(
+ &self,
+ hcx: &mut StableHashingContext<'a>,
+ hasher: &mut StableHasher<W>) {
-impl<'mir, 'tcx: 'mir> Hash for Frame<'mir, 'tcx> {
- fn hash<H: Hasher>(&self, state: &mut H) {
let Frame {
- mir: _,
+ mir,
instance,
- span: _,
+ span,
return_to_block,
return_place,
locals,
stmt,
} = self;
- instance.hash(state);
- return_to_block.hash(state);
- return_place.hash(state);
- locals.hash(state);
- block.hash(state);
- stmt.hash(state);
+ (mir, instance, span, return_to_block).hash_stable(hcx, hasher);
+ (return_place, locals, block, stmt).hash_stable(hcx, hasher);
}
}
None { cleanup: bool },
}
+impl<'a> HashStable<StableHashingContext<'a>> for StackPopCleanup {
+ fn hash_stable<W: StableHasherResult>(
+ &self,
+ hcx: &mut StableHashingContext<'a>,
+ hasher: &mut StableHasher<W>) {
+ match self {
+ StackPopCleanup::Goto(ref block) => block.hash_stable(hcx, hasher),
+ StackPopCleanup::None { cleanup } => cleanup.hash_stable(hcx, hasher),
+ }
+ }
+}
+
// State of a local variable
#[derive(Copy, Clone, PartialEq, Eq, Hash)]
-pub enum LocalValue {
+pub enum LocalValue<Id=AllocId> {
Dead,
// Mostly for convenience, we re-use the `Operand` type here.
// This is an optimization over just always having a pointer here;
// we can thus avoid doing an allocation when the local just stores
// immediate values *and* never has its address taken.
- Live(Operand),
+ Live(Operand<Id>),
}
impl<'tcx> LocalValue {
}
}
-/// The virtual machine state during const-evaluation at a given point in time.
-type EvalSnapshot<'a, 'mir, 'tcx, M>
- = (M, Vec<Frame<'mir, 'tcx>>, Memory<'a, 'mir, 'tcx, M>);
-
-pub(super) struct InfiniteLoopDetector<'a, 'mir, 'tcx: 'a + 'mir, M: Machine<'mir, 'tcx>> {
- /// The set of all `EvalSnapshot` *hashes* observed by this detector.
- ///
- /// When a collision occurs in this table, we store the full snapshot in
- /// `snapshots`.
- hashes: FxHashSet<u64>,
-
- /// The set of all `EvalSnapshot`s observed by this detector.
- ///
- /// An `EvalSnapshot` will only be fully cloned once it has caused a
- /// collision in `hashes`. As a result, the detector must observe at least
- /// *two* full cycles of an infinite loop before it triggers.
- snapshots: FxHashSet<EvalSnapshot<'a, 'mir, 'tcx, M>>,
-}
-
-impl<'a, 'mir, 'tcx, M> Default for InfiniteLoopDetector<'a, 'mir, 'tcx, M>
- where M: Machine<'mir, 'tcx>,
- 'tcx: 'a + 'mir,
-{
- fn default() -> Self {
- InfiniteLoopDetector {
- hashes: FxHashSet::default(),
- snapshots: FxHashSet::default(),
- }
- }
-}
-
-impl<'a, 'mir, 'tcx, M> InfiniteLoopDetector<'a, 'mir, 'tcx, M>
- where M: Machine<'mir, 'tcx>,
- 'tcx: 'a + 'mir,
-{
- /// Returns `true` if the loop detector has not yet observed a snapshot.
- pub fn is_empty(&self) -> bool {
- self.hashes.is_empty()
- }
-
- pub fn observe_and_analyze(
- &mut self,
- machine: &M,
- stack: &Vec<Frame<'mir, 'tcx>>,
- memory: &Memory<'a, 'mir, 'tcx, M>,
- ) -> EvalResult<'tcx, ()> {
- let snapshot = (machine, stack, memory);
-
- let mut fx = FxHasher::default();
- snapshot.hash(&mut fx);
- let hash = fx.finish();
-
- if self.hashes.insert(hash) {
- // No collision
- return Ok(())
- }
-
- if self.snapshots.insert((machine.clone(), stack.clone(), memory.clone())) {
- // Spurious collision or first cycle
- return Ok(())
- }
-
- // Second cycle
- Err(EvalErrorKind::InfiniteLoop.into())
- }
-}
+impl_stable_hash_for!(enum self::LocalValue {
+ Dead,
+ Live(x),
+});
impl<'a, 'mir, 'tcx, M: Machine<'mir, 'tcx>> HasDataLayout for &'a EvalContext<'a, 'mir, 'tcx, M> {
#[inline]
}
impl<'c, 'b, 'a, 'mir, 'tcx, M: Machine<'mir, 'tcx>> HasDataLayout
- for &'c &'b mut EvalContext<'a, 'mir, 'tcx, M> {
+ for &'c &'b mut EvalContext<'a, 'mir, 'tcx, M>
+{
#[inline]
fn data_layout(&self) -> &layout::TargetDataLayout {
&self.tcx.data_layout
use syntax::symbol::Symbol;
use rustc::ty;
use rustc::ty::layout::{LayoutOf, Primitive};
+use rustc::mir::BinOp;
use rustc::mir::interpret::{
EvalResult, EvalErrorKind, Scalar,
};
"ctlz" => bits.leading_zeros() as u128 - extra,
"cttz" => (bits << extra).trailing_zeros() as u128 - extra,
"bswap" => (bits << extra).swap_bytes(),
+ "bitreverse" => (bits << extra).reverse_bits(),
_ => bug!("not a numeric intrinsic: {}", name),
};
- Ok(Scalar::Bits { bits: bits_out, size: size.bytes() as u8 })
+ Ok(Scalar::from_uint(bits_out, size))
}
impl<'a, 'mir, 'tcx, M: Machine<'mir, 'tcx>> EvalContext<'a, 'mir, 'tcx, M> {
"min_align_of" => {
let elem_ty = substs.type_at(0);
let elem_align = self.layout_of(elem_ty)?.align.abi();
- let align_val = Scalar::Bits {
- bits: elem_align as u128,
- size: dest.layout.size.bytes() as u8,
- };
+ let align_val = Scalar::from_uint(elem_align, dest.layout.size);
self.write_scalar(align_val, dest)?;
}
"size_of" => {
let ty = substs.type_at(0);
let size = self.layout_of(ty)?.size.bytes() as u128;
- let size_val = Scalar::Bits {
- bits: size,
- size: dest.layout.size.bytes() as u8,
- };
+ let size_val = Scalar::from_uint(size, dest.layout.size);
self.write_scalar(size_val, dest)?;
}
"type_id" => {
let ty = substs.type_at(0);
let type_id = self.tcx.type_id_hash(ty) as u128;
- let id_val = Scalar::Bits {
- bits: type_id,
- size: dest.layout.size.bytes() as u8,
- };
+ let id_val = Scalar::from_uint(type_id, dest.layout.size);
self.write_scalar(id_val, dest)?;
}
- "ctpop" | "cttz" | "cttz_nonzero" | "ctlz" | "ctlz_nonzero" | "bswap" => {
+ | "ctpop"
+ | "cttz"
+ | "cttz_nonzero"
+ | "ctlz"
+ | "ctlz_nonzero"
+ | "bswap"
+ | "bitreverse" => {
let ty = substs.type_at(0);
let layout_of = self.layout_of(ty)?;
let bits = self.read_scalar(args[0])?.to_bits(layout_of.size)?;
};
self.write_scalar(out_val, dest)?;
}
+ | "overflowing_add"
+ | "overflowing_sub"
+ | "overflowing_mul"
+ | "unchecked_shl"
+ | "unchecked_shr"
+ | "add_with_overflow"
+ | "sub_with_overflow"
+ | "mul_with_overflow" => {
+ let lhs = self.read_value(args[0])?;
+ let rhs = self.read_value(args[1])?;
+ let (bin_op, ignore_overflow) = match intrinsic_name {
+ "overflowing_add" => (BinOp::Add, true),
+ "overflowing_sub" => (BinOp::Sub, true),
+ "overflowing_mul" => (BinOp::Mul, true),
+ "unchecked_shl" => (BinOp::Shl, true),
+ "unchecked_shr" => (BinOp::Shr, true),
+ "add_with_overflow" => (BinOp::Add, false),
+ "sub_with_overflow" => (BinOp::Sub, false),
+ "mul_with_overflow" => (BinOp::Mul, false),
+ _ => bug!("Already checked for int ops")
+ };
+ if ignore_overflow {
+ self.binop_ignore_overflow(bin_op, lhs, rhs, dest)?;
+ } else {
+ self.binop_with_overflow(bin_op, lhs, rhs, dest)?;
+ }
+ }
"transmute" => {
// Go through an allocation, to make sure the completely different layouts
// do not pose a problem. (When the user transmutes through a union,
use std::hash::Hash;
use rustc::hir::def_id::DefId;
+use rustc::ich::StableHashingContext;
use rustc::mir::interpret::{Allocation, EvalResult, Scalar};
use rustc::mir;
use rustc::ty::{self, layout::TyLayout, query::TyCtxtAt};
+use rustc_data_structures::stable_hasher::HashStable;
use super::{EvalContext, PlaceTy, OpTy};
/// Methods of this trait signifies a point where CTFE evaluation would fail
/// and some use case dependent behaviour can instead be applied
-pub trait Machine<'mir, 'tcx>: Clone + Eq + Hash {
+pub trait Machine<'mir, 'tcx>: Clone + Eq + Hash + for<'a> HashStable<StableHashingContext<'a>> {
/// Additional data that can be accessed via the Memory
- type MemoryData: Clone + Eq + Hash;
+ type MemoryData: Clone + Eq + Hash + for<'a> HashStable<StableHashingContext<'a>>;
/// Additional memory kinds a machine wishes to distinguish from the builtin ones
type MemoryKinds: ::std::fmt::Debug + Copy + Clone + Eq + Hash;
def_id: DefId,
) -> EvalResult<'tcx, &'tcx Allocation>;
- /// Called for all binary operations except on float types.
- ///
- /// Returns `None` if the operation should be handled by the integer
- /// op code in order to share more code between machines
+ /// Called for all binary operations on integer(-like) types when one operand is a pointer
+ /// value, and for the `Offset` operation that is inherently about pointers.
///
/// Returns a (value, overflowed) pair if the operation succeeded
- fn try_ptr_op<'a>(
+ fn ptr_op<'a>(
ecx: &EvalContext<'a, 'mir, 'tcx, Self>,
bin_op: mir::BinOp,
left: Scalar,
left_layout: TyLayout<'tcx>,
right: Scalar,
right_layout: TyLayout<'tcx>,
- ) -> EvalResult<'tcx, Option<(Scalar, bool)>>;
+ ) -> EvalResult<'tcx, (Scalar, bool)>;
/// Heap allocations via the `box` keyword
///
//! short-circuiting the empty case!
use std::collections::VecDeque;
-use std::hash::{Hash, Hasher};
use std::ptr;
use rustc::ty::{self, Instance, query::TyCtxtAt};
use rustc::ty::layout::{self, Align, TargetDataLayout, Size, HasDataLayout};
-use rustc::mir::interpret::{Pointer, AllocId, Allocation, ScalarMaybeUndef, GlobalId,
- EvalResult, Scalar, EvalErrorKind, AllocType, truncate};
+use rustc::mir::interpret::{Pointer, AllocId, Allocation, ConstValue, ScalarMaybeUndef, GlobalId,
+ EvalResult, Scalar, EvalErrorKind, AllocType, PointerArithmetic,
+ truncate};
pub use rustc::mir::interpret::{write_target_uint, read_target_uint};
-use rustc_data_structures::fx::{FxHashSet, FxHashMap, FxHasher};
+use rustc_data_structures::fx::{FxHashSet, FxHashMap};
use syntax::ast::Mutability;
&self.tcx.data_layout
}
}
-
-impl<'a, 'mir, 'tcx, M> Eq for Memory<'a, 'mir, 'tcx, M>
- where M: Machine<'mir, 'tcx>,
- 'tcx: 'a + 'mir,
-{}
-
-impl<'a, 'mir, 'tcx, M> PartialEq for Memory<'a, 'mir, 'tcx, M>
- where M: Machine<'mir, 'tcx>,
- 'tcx: 'a + 'mir,
+impl<'a, 'b, 'c, 'mir, 'tcx, M: Machine<'mir, 'tcx>> HasDataLayout
+ for &'b &'c mut Memory<'a, 'mir, 'tcx, M>
{
- fn eq(&self, other: &Self) -> bool {
- let Memory {
- data,
- alloc_map,
- tcx: _,
- } = self;
-
- *data == other.data
- && *alloc_map == other.alloc_map
- }
-}
-
-impl<'a, 'mir, 'tcx, M> Hash for Memory<'a, 'mir, 'tcx, M>
- where M: Machine<'mir, 'tcx>,
- 'tcx: 'a + 'mir,
-{
- fn hash<H: Hasher>(&self, state: &mut H) {
- let Memory {
- data,
- alloc_map: _,
- tcx: _,
- } = self;
-
- data.hash(state);
-
- // We ignore some fields which don't change between evaluation steps.
-
- // Since HashMaps which contain the same items may have different
- // iteration orders, we use a commutative operation (in this case
- // addition, but XOR would also work), to combine the hash of each
- // `Allocation`.
- self.alloc_map.iter()
- .map(|(&id, alloc)| {
- let mut h = FxHasher::default();
- id.hash(&mut h);
- alloc.hash(&mut h);
- h.finish()
- })
- .fold(0u64, |hash, x| hash.wrapping_add(x))
- .hash(state);
+ #[inline]
+ fn data_layout(&self) -> &TargetDataLayout {
+ &self.tcx.data_layout
}
}
-/// Helper function to obtain the global (tcx) allocation for a static
-fn const_eval_static<'a, 'mir, 'tcx, M: Machine<'mir, 'tcx>>(
- tcx: TyCtxtAt<'a, 'tcx, 'tcx>,
- id: AllocId
-) -> EvalResult<'tcx, &'tcx Allocation> {
- let alloc = tcx.alloc_map.lock().get(id);
- let def_id = match alloc {
- Some(AllocType::Memory(mem)) => {
- return Ok(mem)
- }
- Some(AllocType::Function(..)) => {
- return err!(DerefFunctionPointer)
- }
- Some(AllocType::Static(did)) => {
- did
- }
- None =>
- return err!(DanglingPointerDeref),
- };
- // We got a "lazy" static that has not been computed yet, do some work
- trace!("static_alloc: Need to compute {:?}", def_id);
- if tcx.is_foreign_item(def_id) {
- return M::find_foreign_static(tcx, def_id);
- }
- let instance = Instance::mono(tcx.tcx, def_id);
- let gid = GlobalId {
- instance,
- promoted: None,
- };
- tcx.const_eval(ty::ParamEnv::reveal_all().and(gid)).map_err(|err| {
- // no need to report anything, the const_eval call takes care of that for statics
- assert!(tcx.is_static(def_id).is_some());
- EvalErrorKind::ReferencedConstant(err).into()
- }).map(|val| {
- // FIXME We got our static (will be a ByRef), now we make a *copy*?!?
- tcx.const_to_allocation(val)
- })
-}
-
impl<'a, 'mir, 'tcx, M: Machine<'mir, 'tcx>> Memory<'a, 'mir, 'tcx, M> {
pub fn new(tcx: TyCtxtAt<'a, 'tcx, 'tcx>, data: M::MemoryData) -> Self {
Memory {
Ok(())
}
- pub fn pointer_size(&self) -> Size {
- self.tcx.data_layout.pointer_size
- }
-
- pub fn endianness(&self) -> layout::Endian {
- self.tcx.data_layout.endian
- }
-
/// Check that the pointer is aligned AND non-NULL. This supports scalars
/// for the benefit of other parts of miri that need to check alignment even for ZST.
pub fn check_align(&self, ptr: Scalar, required_align: Align) -> EvalResult<'tcx> {
}
Scalar::Bits { bits, size } => {
assert_eq!(size as u64, self.pointer_size().bytes());
- // FIXME: what on earth does this line do? docs or fix needed!
- let v = ((bits as u128) % (1 << self.pointer_size().bytes())) as u64;
- if v == 0 {
+ assert!(bits < (1u128 << self.pointer_size().bits()));
+ if bits == 0 {
return err!(InvalidNullPointerUsage);
}
- // the base address if the "integer allocation" is 0 and hence always aligned
- (v, required_align)
+ // the "base address" is 0 and hence always aligned
+ (bits as u64, required_align)
}
};
// Check alignment
/// Check if the pointer is "in-bounds". Notice that a pointer pointing at the end
/// of an allocation (i.e., at the first *inaccessible* location) *is* considered
- /// in-bounds! This follows C's/LLVM's rules.
+ /// in-bounds! This follows C's/LLVM's rules. The `access` boolean is just used
+ /// for the error message.
+ /// If you want to check bounds before doing a memory access, be sure to
+ /// check the pointer one past the end of your access, then everything will
+ /// work out exactly.
pub fn check_bounds(&self, ptr: Pointer, access: bool) -> EvalResult<'tcx> {
let alloc = self.get(ptr.alloc_id)?;
let allocation_size = alloc.bytes.len() as u64;
/// Allocation accessors
impl<'a, 'mir, 'tcx, M: Machine<'mir, 'tcx>> Memory<'a, 'mir, 'tcx, M> {
+ /// Helper function to obtain the global (tcx) allocation for a static
+ fn get_static_alloc(
+ tcx: TyCtxtAt<'a, 'tcx, 'tcx>,
+ id: AllocId,
+ ) -> EvalResult<'tcx, &'tcx Allocation> {
+ let alloc = tcx.alloc_map.lock().get(id);
+ let def_id = match alloc {
+ Some(AllocType::Memory(mem)) => {
+ return Ok(mem)
+ }
+ Some(AllocType::Function(..)) => {
+ return err!(DerefFunctionPointer)
+ }
+ Some(AllocType::Static(did)) => {
+ did
+ }
+ None =>
+ return err!(DanglingPointerDeref),
+ };
+ // We got a "lazy" static that has not been computed yet, do some work
+ trace!("static_alloc: Need to compute {:?}", def_id);
+ if tcx.is_foreign_item(def_id) {
+ return M::find_foreign_static(tcx, def_id);
+ }
+ let instance = Instance::mono(tcx.tcx, def_id);
+ let gid = GlobalId {
+ instance,
+ promoted: None,
+ };
+ tcx.const_eval(ty::ParamEnv::reveal_all().and(gid)).map_err(|err| {
+ // no need to report anything, the const_eval call takes care of that for statics
+ assert!(tcx.is_static(def_id).is_some());
+ EvalErrorKind::ReferencedConstant(err).into()
+ }).map(|const_val| {
+ if let ConstValue::ByRef(_, allocation, _) = const_val.val {
+ allocation
+ } else {
+ bug!("Matching on non-ByRef static")
+ }
+ })
+ }
+
pub fn get(&self, id: AllocId) -> EvalResult<'tcx, &Allocation> {
match self.alloc_map.get(&id) {
// Normal alloc?
Some(alloc) => Ok(&alloc.1),
// Static. No need to make any copies, just provide read access to the global static
// memory in tcx.
- None => const_eval_static::<M>(self.tcx, id),
+ None => Self::get_static_alloc(self.tcx, id),
}
}
if ptr.offset.bytes() != 0 {
return err!(InvalidFunctionPointer);
}
- debug!("reading fn ptr: {}", ptr.alloc_id);
+ trace!("reading fn ptr: {}", ptr.alloc_id);
match self.tcx.alloc_map.lock().get(ptr.alloc_id) {
Some(AllocType::Function(instance)) => Ok(instance),
_ => Err(EvalErrorKind::ExecuteMemory.into()),
/// Byte accessors
impl<'a, 'mir, 'tcx, M: Machine<'mir, 'tcx>> Memory<'a, 'mir, 'tcx, M> {
- /// This checks alignment!
- fn get_bytes_unchecked(
+ /// The last argument controls whether we error out when there are undefined
+ /// or pointer bytes. You should never call this, call `get_bytes` or
+ /// `get_bytes_with_undef_and_ptr` instead,
+ fn get_bytes_internal(
&self,
ptr: Pointer,
size: Size,
align: Align,
+ check_defined_and_ptr: bool,
) -> EvalResult<'tcx, &[u8]> {
- // Zero-sized accesses can use dangling pointers,
- // but they still have to be aligned and non-NULL
+ assert_ne!(size.bytes(), 0, "0-sized accesses should never even get a `Pointer`");
self.check_align(ptr.into(), align)?;
- if size.bytes() == 0 {
- return Ok(&[]);
- }
// if ptr.offset is in bounds, then so is ptr (because offset checks for overflow)
- self.check_bounds(ptr.offset(size, self)?, true)?;
+ self.check_bounds(ptr.offset(size, &*self)?, true)?;
+
+ if check_defined_and_ptr {
+ self.check_defined(ptr, size)?;
+ self.check_relocations(ptr, size)?;
+ } else {
+ // We still don't want relocations on the *edges*
+ self.check_relocation_edges(ptr, size)?;
+ }
+
let alloc = self.get(ptr.alloc_id)?;
assert_eq!(ptr.offset.bytes() as usize as u64, ptr.offset.bytes());
assert_eq!(size.bytes() as usize as u64, size.bytes());
Ok(&alloc.bytes[offset..offset + size.bytes() as usize])
}
- /// This checks alignment!
- fn get_bytes_unchecked_mut(
+ #[inline]
+ fn get_bytes(&self, ptr: Pointer, size: Size, align: Align) -> EvalResult<'tcx, &[u8]> {
+ self.get_bytes_internal(ptr, size, align, true)
+ }
+
+ /// It is the caller's responsibility to handle undefined and pointer bytes.
+ /// However, this still checks that there are no relocations on the egdes.
+ #[inline]
+ fn get_bytes_with_undef_and_ptr(
+ &self,
+ ptr: Pointer,
+ size: Size,
+ align: Align
+ ) -> EvalResult<'tcx, &[u8]> {
+ self.get_bytes_internal(ptr, size, align, false)
+ }
+
+ /// Just calling this already marks everything as defined and removes relocations,
+ /// so be sure to actually put data there!
+ fn get_bytes_mut(
&mut self,
ptr: Pointer,
size: Size,
align: Align,
) -> EvalResult<'tcx, &mut [u8]> {
- // Zero-sized accesses can use dangling pointers,
- // but they still have to be aligned and non-NULL
+ assert_ne!(size.bytes(), 0, "0-sized accesses should never even get a `Pointer`");
self.check_align(ptr.into(), align)?;
- if size.bytes() == 0 {
- return Ok(&mut []);
- }
// if ptr.offset is in bounds, then so is ptr (because offset checks for overflow)
- self.check_bounds(ptr.offset(size, &*self)?, true)?;
+ self.check_bounds(ptr.offset(size, &self)?, true)?;
+
+ self.mark_definedness(ptr, size, true)?;
+ self.clear_relocations(ptr, size)?;
+
let alloc = self.get_mut(ptr.alloc_id)?;
assert_eq!(ptr.offset.bytes() as usize as u64, ptr.offset.bytes());
assert_eq!(size.bytes() as usize as u64, size.bytes());
let offset = ptr.offset.bytes() as usize;
Ok(&mut alloc.bytes[offset..offset + size.bytes() as usize])
}
-
- fn get_bytes(&self, ptr: Pointer, size: Size, align: Align) -> EvalResult<'tcx, &[u8]> {
- assert_ne!(size.bytes(), 0);
- if self.relocations(ptr, size)?.len() != 0 {
- return err!(ReadPointerAsBytes);
- }
- self.check_defined(ptr, size)?;
- self.get_bytes_unchecked(ptr, size, align)
- }
-
- fn get_bytes_mut(
- &mut self,
- ptr: Pointer,
- size: Size,
- align: Align,
- ) -> EvalResult<'tcx, &mut [u8]> {
- assert_ne!(size.bytes(), 0);
- self.clear_relocations(ptr, size)?;
- self.mark_definedness(ptr, size, true)?;
- self.get_bytes_unchecked_mut(ptr, size, align)
- }
}
/// Reading and writing
id: AllocId,
kind: MemoryKind<M::MemoryKinds>,
) -> EvalResult<'tcx> {
- let alloc = const_eval_static::<M>(self.tcx, id)?;
+ let alloc = Self::get_static_alloc(self.tcx, id)?;
if alloc.mutability == Mutability::Immutable {
return err!(ModifiedConstantMemory);
}
}
let src = src.to_ptr()?;
let dest = dest.to_ptr()?;
- self.check_relocation_edges(src, size)?;
// first copy the relocations to a temporary buffer, because
// `get_bytes_mut` will clear the relocations, which is correct,
// since we don't want to keep any relocations at the target.
+ // (`get_bytes_with_undef_and_ptr` below checks that there are no
+ // relocations overlapping the edges; those would not be handled correctly).
let relocations = {
let relocations = self.relocations(src, size)?;
let mut new_relocations = Vec::with_capacity(relocations.len() * (length as usize));
new_relocations
};
- // This also checks alignment.
- let src_bytes = self.get_bytes_unchecked(src, size, src_align)?.as_ptr();
+ // This also checks alignment, and relocation edges on the src.
+ let src_bytes = self.get_bytes_with_undef_and_ptr(src, size, src_align)?.as_ptr();
let dest_bytes = self.get_bytes_mut(dest, size * length, dest_align)?.as_mut_ptr();
// SAFE: The above indexing would have panicked if there weren't at least `size` bytes
}
}
+ // copy definedness to the destination
self.copy_undef_mask(src, dest, size, length)?;
- // copy back the relocations
+ // copy the relocations to the destination
self.get_mut(dest.alloc_id)?.relocations.insert_presorted(relocations);
Ok(())
match alloc.bytes[offset..].iter().position(|&c| c == 0) {
Some(size) => {
let p1 = Size::from_bytes((size + 1) as u64);
- if self.relocations(ptr, p1)?.len() != 0 {
- return err!(ReadPointerAsBytes);
- }
+ self.check_relocations(ptr, p1)?;
self.check_defined(ptr, p1)?;
Ok(&alloc.bytes[offset..offset + size])
}
ptr_align: Align,
size: Size
) -> EvalResult<'tcx, ScalarMaybeUndef> {
- // Make sure we don't read part of a pointer as a pointer
- self.check_relocation_edges(ptr, size)?;
- let endianness = self.endianness();
- // get_bytes_unchecked tests alignment
- let bytes = self.get_bytes_unchecked(ptr, size, ptr_align.min(self.int_align(size)))?;
+ // get_bytes_unchecked tests alignment and relocation edges
+ let bytes = self.get_bytes_with_undef_and_ptr(
+ ptr, size, ptr_align.min(self.int_align(size))
+ )?;
// Undef check happens *after* we established that the alignment is correct.
// We must not return Ok() for unaligned pointers!
if !self.is_defined(ptr, size)? {
return Ok(ScalarMaybeUndef::Undef);
}
// Now we do the actual reading
- let bits = read_target_uint(endianness, bytes).unwrap();
+ let bits = read_target_uint(self.tcx.data_layout.endian, bytes).unwrap();
// See if we got a pointer
if size != self.pointer_size() {
- if self.relocations(ptr, size)?.len() != 0 {
- return err!(ReadPointerAsBytes);
- }
+ // *Now* better make sure that the inside also is free of relocations.
+ self.check_relocations(ptr, size)?;
} else {
let alloc = self.get(ptr.alloc_id)?;
match alloc.relocations.get(&ptr.offset) {
}
}
// We don't. Just return the bits.
- Ok(ScalarMaybeUndef::Scalar(Scalar::Bits {
- bits,
- size: size.bytes() as u8,
- }))
+ Ok(ScalarMaybeUndef::Scalar(Scalar::from_uint(bits, size)))
}
pub fn read_ptr_sized(&self, ptr: Pointer, ptr_align: Align)
val: ScalarMaybeUndef,
type_size: Size,
) -> EvalResult<'tcx> {
- let endianness = self.endianness();
-
let val = match val {
ScalarMaybeUndef::Scalar(scalar) => scalar,
ScalarMaybeUndef::Undef => return self.mark_definedness(ptr, type_size, false),
Scalar::Bits { bits, size } => {
assert_eq!(size as u64, type_size.bytes());
- assert_eq!(truncate(bits, Size::from_bytes(size.into())), bits,
+ debug_assert_eq!(truncate(bits, Size::from_bytes(size.into())), bits,
"Unexpected value of size {} when writing to memory", size);
bits
},
{
// get_bytes_mut checks alignment
+ let endian = self.tcx.data_layout.endian;
let dst = self.get_bytes_mut(ptr, type_size, ptr_align)?;
- write_target_uint(endianness, dst, bytes).unwrap();
+ write_target_uint(endian, dst, bytes).unwrap();
}
// See if we have to also write a relocation
/// Relocations
impl<'a, 'mir, 'tcx, M: Machine<'mir, 'tcx>> Memory<'a, 'mir, 'tcx, M> {
+ /// Return all relocations overlapping with the given ptr-offset pair.
fn relocations(
&self,
ptr: Pointer,
size: Size,
) -> EvalResult<'tcx, &[(Size, AllocId)]> {
+ // We have to go back `pointer_size - 1` bytes, as that one would still overlap with
+ // the beginning of this range.
let start = ptr.offset.bytes().saturating_sub(self.pointer_size().bytes() - 1);
- let end = ptr.offset + size;
+ let end = ptr.offset + size; // this does overflow checking
Ok(self.get(ptr.alloc_id)?.relocations.range(Size::from_bytes(start)..end))
}
+ /// Check that there ar eno relocations overlapping with the given range.
+ #[inline(always)]
+ fn check_relocations(&self, ptr: Pointer, size: Size) -> EvalResult<'tcx> {
+ if self.relocations(ptr, size)?.len() != 0 {
+ err!(ReadPointerAsBytes)
+ } else {
+ Ok(())
+ }
+ }
+
+ /// Remove all relocations inside the given range.
+ /// If there are relocations overlapping with the edges, they
+ /// are removed as well *and* the bytes they cover are marked as
+ /// uninitialized. This is a somewhat odd "spooky action at a distance",
+ /// but it allows strictly more code to run than if we would just error
+ /// immediately in that case.
fn clear_relocations(&mut self, ptr: Pointer, size: Size) -> EvalResult<'tcx> {
// Find the start and end of the given range and its outermost relocations.
let (first, last) = {
Ok(())
}
+ /// Error if there are relocations overlapping with the egdes of the
+ /// given memory range.
+ #[inline]
fn check_relocation_edges(&self, ptr: Pointer, size: Size) -> EvalResult<'tcx> {
- let overlapping_start = self.relocations(ptr, Size::ZERO)?.len();
- let overlapping_end = self.relocations(ptr.offset(size, self)?, Size::ZERO)?.len();
- if overlapping_start + overlapping_end != 0 {
- return err!(ReadPointerAsBytes);
- }
+ self.check_relocations(ptr, Size::ZERO)?;
+ self.check_relocations(ptr.offset(size, self)?, Size::ZERO)?;
Ok(())
}
}
mod machine;
mod memory;
mod operator;
+mod snapshot;
mod step;
mod terminator;
mod traits;
use std::convert::TryInto;
use rustc::{mir, ty};
-use rustc::ty::layout::{self, Size, Align, LayoutOf, TyLayout, HasDataLayout, IntegerExt};
+use rustc::ty::layout::{self, Size, LayoutOf, TyLayout, HasDataLayout, IntegerExt};
use rustc_data_structures::indexed_vec::Idx;
-
use rustc::mir::interpret::{
- GlobalId, ConstValue, Scalar, EvalResult, Pointer, ScalarMaybeUndef, EvalErrorKind
+ GlobalId, AllocId,
+ ConstValue, Pointer, Scalar, ScalarMaybeUndef,
+ EvalResult, EvalErrorKind
};
use super::{EvalContext, Machine, MemPlace, MPlaceTy, MemoryKind};
/// In particular, thanks to `ScalarPair`, arithmetic operations and casts can be entirely
/// defined on `Value`, and do not have to work with a `Place`.
#[derive(Copy, Clone, Debug, Hash, PartialEq, Eq)]
-pub enum Value {
- Scalar(ScalarMaybeUndef),
- ScalarPair(ScalarMaybeUndef, ScalarMaybeUndef),
+pub enum Value<Id=AllocId> {
+ Scalar(ScalarMaybeUndef<Id>),
+ ScalarPair(ScalarMaybeUndef<Id>, ScalarMaybeUndef<Id>),
}
impl<'tcx> Value {
len: u64,
cx: impl HasDataLayout
) -> Self {
- Value::ScalarPair(val.into(), Scalar::Bits {
- bits: len as u128,
- size: cx.data_layout().pointer_size.bytes() as u8,
- }.into())
+ Value::ScalarPair(val.into(), Scalar::from_uint(len, cx.data_layout().pointer_size).into())
}
pub fn new_dyn_trait(val: Scalar, vtable: Pointer) -> Self {
}
}
+impl_stable_hash_for!(enum ::interpret::Value {
+ Scalar(x),
+ ScalarPair(x, y),
+});
+
// ScalarPair needs a type to interpret, so we often have a value and a type together
// as input for binary and cast operations.
#[derive(Copy, Clone, Debug)]
pub struct ValTy<'tcx> {
- pub value: Value,
+ value: Value,
pub layout: TyLayout<'tcx>,
}
/// or still in memory. The latter is an optimization, to delay reading that chunk of
/// memory and to avoid having to store arbitrary-sized data here.
#[derive(Copy, Clone, Debug, Hash, PartialEq, Eq)]
-pub enum Operand {
- Immediate(Value),
- Indirect(MemPlace),
+pub enum Operand<Id=AllocId> {
+ Immediate(Value<Id>),
+ Indirect(MemPlace<Id>),
}
impl Operand {
- #[inline]
- pub fn from_ptr(ptr: Pointer, align: Align) -> Self {
- Operand::Indirect(MemPlace::from_ptr(ptr, align))
- }
-
- #[inline]
- pub fn from_scalar_value(val: Scalar) -> Self {
- Operand::Immediate(Value::Scalar(val.into()))
- }
-
#[inline]
pub fn to_mem_place(self) -> MemPlace {
match self {
}
}
+impl_stable_hash_for!(enum ::interpret::Operand {
+ Immediate(x),
+ Indirect(x),
+});
+
#[derive(Copy, Clone, Debug)]
pub struct OpTy<'tcx> {
- crate op: Operand, // ideally we'd make this private, but we are not there yet
+ crate op: Operand, // ideally we'd make this private, but const_prop needs this
pub layout: TyLayout<'tcx>,
}
}
impl<'tcx> Eq for OpTy<'tcx> {}
-impl<'tcx> OpTy<'tcx> {
- #[inline]
- pub fn from_ptr(ptr: Pointer, align: Align, layout: TyLayout<'tcx>) -> Self {
- OpTy { op: Operand::from_ptr(ptr, align), layout }
- }
-
- #[inline]
- pub fn from_aligned_ptr(ptr: Pointer, layout: TyLayout<'tcx>) -> Self {
- OpTy { op: Operand::from_ptr(ptr, layout.align), layout }
- }
-
- #[inline]
- pub fn from_scalar_value(val: Scalar, layout: TyLayout<'tcx>) -> Self {
- OpTy { op: Operand::Immediate(Value::Scalar(val.into())), layout }
- }
-}
-
// Use the existing layout if given (but sanity check in debug mode),
// or compute the layout.
#[inline(always)]
ConstValue::ByRef(id, alloc, offset) => {
// We rely on mutability being set correctly in that allocation to prevent writes
// where none should happen -- and for `static mut`, we copy on demand anyway.
- Ok(Operand::from_ptr(Pointer::new(id, offset), alloc.align))
+ Ok(Operand::Indirect(MemPlace::from_ptr(Pointer::new(id, offset), alloc.align)))
},
ConstValue::ScalarPair(a, b) =>
Ok(Operand::Immediate(Value::ScalarPair(a.into(), b))),
// except according to those terms.
use rustc::mir;
-use rustc::ty::{self, layout::TyLayout};
+use rustc::ty::{self, layout::{Size, TyLayout}};
use syntax::ast::FloatTy;
use rustc_apfloat::ieee::{Double, Single};
use rustc_apfloat::Float;
right: ValTy<'tcx>,
dest: PlaceTy<'tcx>,
) -> EvalResult<'tcx> {
- let (val, overflowed) = self.binary_op(op, left, right)?;
+ let (val, overflowed) = self.binary_op_val(op, left, right)?;
let val = Value::ScalarPair(val.into(), Scalar::from_bool(overflowed).into());
self.write_value(val, dest)
}
right: ValTy<'tcx>,
dest: PlaceTy<'tcx>,
) -> EvalResult<'tcx> {
- let (val, _overflowed) = self.binary_op(op, left, right)?;
+ let (val, _overflowed) = self.binary_op_val(op, left, right)?;
self.write_scalar(val, dest)
}
}
($ty:path, $size:expr) => {{
let l = <$ty>::from_bits(l);
let r = <$ty>::from_bits(r);
- let bitify = |res: ::rustc_apfloat::StatusAnd<$ty>| Scalar::Bits {
- bits: res.value.to_bits(),
- size: $size,
- };
+ let bitify = |res: ::rustc_apfloat::StatusAnd<$ty>|
+ Scalar::from_uint(res.value.to_bits(), Size::from_bytes($size));
let val = match bin_op {
Eq => Scalar::from_bool(l == r),
Ne => Scalar::from_bool(l != r),
}
};
let truncated = self.truncate(result, left_layout);
- return Ok((Scalar::Bits {
- bits: truncated,
- size: size.bytes() as u8,
- }, oflo));
+ return Ok((Scalar::from_uint(truncated, size), oflo));
}
// For the remaining ops, the types must be the same on both sides
Rem | Div => {
// int_min / -1
if r == -1 && l == (1 << (size.bits() - 1)) {
- return Ok((Scalar::Bits { bits: l, size: size.bytes() as u8 }, true));
+ return Ok((Scalar::from_uint(l, size), true));
}
},
_ => {},
let max = 1 << (size.bits() - 1);
oflo = result >= max || result < -max;
}
+ // this may be out-of-bounds for the result type, so we have to truncate ourselves
let result = result as u128;
let truncated = self.truncate(result, left_layout);
- return Ok((Scalar::Bits {
- bits: truncated,
- size: size.bytes() as u8,
- }, oflo));
+ return Ok((Scalar::from_uint(truncated, size), oflo));
}
}
- let size = left_layout.size.bytes() as u8;
+ let size = left_layout.size;
// only ints left
let val = match bin_op {
Gt => Scalar::from_bool(l > r),
Ge => Scalar::from_bool(l >= r),
- BitOr => Scalar::Bits { bits: l | r, size },
- BitAnd => Scalar::Bits { bits: l & r, size },
- BitXor => Scalar::Bits { bits: l ^ r, size },
+ BitOr => Scalar::from_uint(l | r, size),
+ BitAnd => Scalar::from_uint(l & r, size),
+ BitXor => Scalar::from_uint(l ^ r, size),
Add | Sub | Mul | Rem | Div => {
+ debug_assert!(!left_layout.abi.is_signed());
let op: fn(u128, u128) -> (u128, bool) = match bin_op {
Add => u128::overflowing_add,
Sub => u128::overflowing_sub,
};
let (result, oflo) = op(l, r);
let truncated = self.truncate(result, left_layout);
- return Ok((Scalar::Bits {
- bits: truncated,
- size,
- }, oflo || truncated != result));
+ return Ok((Scalar::from_uint(truncated, size), oflo || truncated != result));
}
_ => {
Ok((val, false))
}
+ /// Convenience wrapper that's useful when keeping the layout together with the
+ /// value.
+ #[inline]
+ pub fn binary_op_val(
+ &self,
+ bin_op: mir::BinOp,
+ left: ValTy<'tcx>,
+ right: ValTy<'tcx>,
+ ) -> EvalResult<'tcx, (Scalar, bool)> {
+ self.binary_op(
+ bin_op,
+ left.to_scalar()?, left.layout,
+ right.to_scalar()?, right.layout,
+ )
+ }
+
/// Returns the result of the specified operation and whether it overflowed.
pub fn binary_op(
&self,
bin_op: mir::BinOp,
- ValTy { value: left, layout: left_layout }: ValTy<'tcx>,
- ValTy { value: right, layout: right_layout }: ValTy<'tcx>,
+ left: Scalar,
+ left_layout: TyLayout<'tcx>,
+ right: Scalar,
+ right_layout: TyLayout<'tcx>,
) -> EvalResult<'tcx, (Scalar, bool)> {
- let left = left.to_scalar()?;
- let right = right.to_scalar()?;
-
trace!("Running binary op {:?}: {:?} ({:?}), {:?} ({:?})",
bin_op, left, left_layout.ty, right, right_layout.ty);
right_layout.ty.is_fn());
// Handle operations that support pointer values
- if let Some(handled) =
- M::try_ptr_op(self, bin_op, left, left_layout, right, right_layout)?
- {
- return Ok(handled);
+ if left.is_ptr() || right.is_ptr() || bin_op == mir::BinOp::Offset {
+ return M::ptr_op(self, bin_op, left, left_layout, right, right_layout);
}
// Everything else only works with "proper" bits
- let left = left.to_bits(left_layout.size)?;
- let right = right.to_bits(right_layout.size)?;
+ let left = left.to_bits(left_layout.size).expect("we checked is_ptr");
+ let right = right.to_bits(right_layout.size).expect("we checked is_ptr");
self.binary_int_op(bin_op, left, left_layout, right, right_layout)
}
}
(Neg, FloatTy::F64) => Double::to_bits(-Double::from_bits(val)),
_ => bug!("Invalid float op {:?}", un_op)
};
- Ok(Scalar::Bits { bits: res, size: layout.size.bytes() as u8 })
+ Ok(Scalar::from_uint(res, layout.size))
}
_ => {
assert!(layout.ty.is_integral());
}
};
// res needs tuncating
- Ok(Scalar::Bits {
- bits: self.truncate(res, layout),
- size: layout.size.bytes() as u8,
- })
+ Ok(Scalar::from_uint(self.truncate(res, layout), layout.size))
}
}
}
use std::convert::TryFrom;
+use rustc::ich::StableHashingContext;
use rustc::mir;
use rustc::ty::{self, Ty};
use rustc::ty::layout::{self, Size, Align, LayoutOf, TyLayout, HasDataLayout};
use rustc_data_structures::indexed_vec::Idx;
+use rustc_data_structures::stable_hasher::{HashStable, StableHasher, StableHasherResult};
use rustc::mir::interpret::{
- GlobalId, Scalar, EvalResult, Pointer, ScalarMaybeUndef
+ GlobalId, AllocId, Scalar, EvalResult, Pointer, ScalarMaybeUndef, PointerArithmetic
};
use super::{EvalContext, Machine, Value, ValTy, Operand, OpTy, MemoryKind};
#[derive(Copy, Clone, Debug, Hash, PartialEq, Eq)]
-pub struct MemPlace {
+pub struct MemPlace<Id=AllocId> {
/// A place may have an integral pointer for ZSTs, and since it might
/// be turned back into a reference before ever being dereferenced.
/// However, it may never be undef.
- pub ptr: Scalar,
+ pub ptr: Scalar<Id>,
pub align: Align,
/// Metadata for unsized places. Interpretation is up to the type.
/// Must not be present for sized types, but can be missing for unsized types
/// (e.g. `extern type`).
- pub extra: Option<Scalar>,
+ pub extra: Option<Scalar<Id>>,
}
+impl_stable_hash_for!(struct ::interpret::MemPlace {
+ ptr,
+ align,
+ extra,
+});
+
#[derive(Copy, Clone, Debug, Hash, PartialEq, Eq)]
-pub enum Place {
+pub enum Place<Id=AllocId> {
/// A place referring to a value allocated in the `Memory` system.
- Ptr(MemPlace),
+ Ptr(MemPlace<Id>),
/// To support alloc-free locals, we are able to write directly to a local.
/// (Without that optimization, we'd just always be a `MemPlace`.)
},
}
+impl<'a> HashStable<StableHashingContext<'a>> for Place {
+ fn hash_stable<W: StableHasherResult>(
+ &self, hcx: &mut StableHashingContext<'a>,
+ hasher: &mut StableHasher<W>) {
+
+ match self {
+ Place::Ptr(mem_place) => mem_place.hash_stable(hcx, hasher),
+
+ Place::Local { frame, local } => {
+ frame.hash_stable(hcx, hasher);
+ local.hash_stable(hcx, hasher);
+ },
+ }
+ }
+}
#[derive(Copy, Clone, Debug)]
pub struct PlaceTy<'tcx> {
place: Place,
ty::Array(inner, _) =>
(None, self.tcx.mk_array(inner, inner_len)),
ty::Slice(..) => {
- let len = Scalar::Bits {
- bits: inner_len.into(),
- size: self.memory.pointer_size().bytes() as u8
- };
+ let len = Scalar::from_uint(inner_len, self.pointer_size());
(Some(len), base.layout.ty)
}
_ =>
src: OpTy<'tcx>,
dest: PlaceTy<'tcx>,
) -> EvalResult<'tcx> {
+ assert!(!src.layout.is_unsized() && !dest.layout.is_unsized(),
+ "Cannot copy unsized data");
assert_eq!(src.layout.size, dest.layout.size,
"Size mismatch when copying!\nsrc: {:#?}\ndest: {:#?}", src, dest);
let discr_val = (discr_val << shift) >> shift;
let discr_dest = self.place_field(dest, 0)?;
- self.write_scalar(Scalar::Bits {
- bits: discr_val,
- size: size.bytes() as u8,
- }, discr_dest)?;
+ self.write_scalar(Scalar::from_uint(discr_val, size), discr_dest)?;
}
layout::Variants::NicheFilling {
dataful_variant,
self.place_field(dest, 0)?;
let niche_value = ((variant_index - niche_variants.start()) as u128)
.wrapping_add(niche_start);
- self.write_scalar(Scalar::Bits {
- bits: niche_value,
- size: niche_dest.layout.size.bytes() as u8,
- }, niche_dest)?;
+ self.write_scalar(
+ Scalar::from_uint(niche_value, niche_dest.layout.size),
+ niche_dest
+ )?;
}
}
}
let layout = self.layout_of(ty)?;
// More sanity checks
- let (size, align) = self.read_size_and_align_from_vtable(vtable)?;
- assert_eq!(size, layout.size);
- assert_eq!(align.abi(), layout.align.abi()); // only ABI alignment is preserved
- // FIXME: More checks for the vtable? We could make sure it is exactly
- // the one one would expect for this type.
+ if cfg!(debug_assertions) {
+ let (size, align) = self.read_size_and_align_from_vtable(vtable)?;
+ assert_eq!(size, layout.size);
+ assert_eq!(align.abi(), layout.align.abi()); // only ABI alignment is preserved
+ }
let mplace = MPlaceTy {
mplace: MemPlace { extra: None, ..*mplace },
--- /dev/null
+//! This module contains the machinery necessary to detect infinite loops
+//! during const-evaluation by taking snapshots of the state of the interpreter
+//! at regular intervals.
+
+use std::hash::{Hash, Hasher};
+
+use rustc::ich::{StableHashingContext, StableHashingContextProvider};
+use rustc::mir;
+use rustc::mir::interpret::{
+ AllocId, Pointer, Scalar, ScalarMaybeUndef,
+ Relocations, Allocation, UndefMask,
+ EvalResult, EvalErrorKind,
+};
+
+use rustc::ty::{self, TyCtxt};
+use rustc::ty::layout::Align;
+use rustc_data_structures::fx::FxHashSet;
+use rustc_data_structures::indexed_vec::IndexVec;
+use rustc_data_structures::stable_hasher::{HashStable, StableHasher, StableHasherResult};
+use syntax::ast::Mutability;
+use syntax::source_map::Span;
+
+use super::eval_context::{LocalValue, StackPopCleanup};
+use super::{Frame, Memory, Machine, Operand, MemPlace, Place, Value};
+
+pub(super) struct InfiniteLoopDetector<'a, 'mir, 'tcx: 'a + 'mir, M: Machine<'mir, 'tcx>> {
+ /// The set of all `EvalSnapshot` *hashes* observed by this detector.
+ ///
+ /// When a collision occurs in this table, we store the full snapshot in
+ /// `snapshots`.
+ hashes: FxHashSet<u64>,
+
+ /// The set of all `EvalSnapshot`s observed by this detector.
+ ///
+ /// An `EvalSnapshot` will only be fully cloned once it has caused a
+ /// collision in `hashes`. As a result, the detector must observe at least
+ /// *two* full cycles of an infinite loop before it triggers.
+ snapshots: FxHashSet<EvalSnapshot<'a, 'mir, 'tcx, M>>,
+}
+
+impl<'a, 'mir, 'tcx, M> Default for InfiniteLoopDetector<'a, 'mir, 'tcx, M>
+ where M: Machine<'mir, 'tcx>,
+ 'tcx: 'a + 'mir,
+{
+ fn default() -> Self {
+ InfiniteLoopDetector {
+ hashes: FxHashSet::default(),
+ snapshots: FxHashSet::default(),
+ }
+ }
+}
+
+impl<'a, 'mir, 'tcx, M> InfiniteLoopDetector<'a, 'mir, 'tcx, M>
+ where M: Machine<'mir, 'tcx>,
+ 'tcx: 'a + 'mir,
+{
+ /// Returns `true` if the loop detector has not yet observed a snapshot.
+ pub fn is_empty(&self) -> bool {
+ self.hashes.is_empty()
+ }
+
+ pub fn observe_and_analyze(
+ &mut self,
+ tcx: &TyCtxt<'b, 'tcx, 'tcx>,
+ machine: &M,
+ memory: &Memory<'a, 'mir, 'tcx, M>,
+ stack: &[Frame<'mir, 'tcx>],
+ ) -> EvalResult<'tcx, ()> {
+
+ let mut hcx = tcx.get_stable_hashing_context();
+ let mut hasher = StableHasher::<u64>::new();
+ (machine, stack).hash_stable(&mut hcx, &mut hasher);
+ let hash = hasher.finish();
+
+ if self.hashes.insert(hash) {
+ // No collision
+ return Ok(())
+ }
+
+ info!("snapshotting the state of the interpreter");
+
+ if self.snapshots.insert(EvalSnapshot::new(machine, memory, stack)) {
+ // Spurious collision or first cycle
+ return Ok(())
+ }
+
+ // Second cycle
+ Err(EvalErrorKind::InfiniteLoop.into())
+ }
+}
+
+trait SnapshotContext<'a> {
+ fn resolve(&'a self, id: &AllocId) -> Option<&'a Allocation>;
+}
+
+/// Taking a snapshot of the evaluation context produces a view of
+/// the state of the interpreter that is invariant to `AllocId`s.
+trait Snapshot<'a, Ctx: SnapshotContext<'a>> {
+ type Item;
+ fn snapshot(&self, ctx: &'a Ctx) -> Self::Item;
+}
+
+macro_rules! __impl_snapshot_field {
+ ($field:ident, $ctx:expr) => ($field.snapshot($ctx));
+ ($field:ident, $ctx:expr, $delegate:expr) => ($delegate);
+}
+
+macro_rules! impl_snapshot_for {
+ // FIXME(mark-i-m): Some of these should be `?` rather than `*`.
+ (enum $enum_name:ident {
+ $( $variant:ident $( ( $($field:ident $(-> $delegate:expr)*),* ) )* ),* $(,)*
+ }) => {
+
+ impl<'a, Ctx> self::Snapshot<'a, Ctx> for $enum_name
+ where Ctx: self::SnapshotContext<'a>,
+ {
+ type Item = $enum_name<AllocIdSnapshot<'a>>;
+
+ #[inline]
+ fn snapshot(&self, __ctx: &'a Ctx) -> Self::Item {
+ match *self {
+ $(
+ $enum_name::$variant $( ( $(ref $field),* ) )* =>
+ $enum_name::$variant $(
+ ( $( __impl_snapshot_field!($field, __ctx $(, $delegate)*) ),* ),
+ )*
+ )*
+ }
+ }
+ }
+ };
+
+ // FIXME(mark-i-m): same here.
+ (struct $struct_name:ident { $($field:ident $(-> $delegate:expr)*),* $(,)* }) => {
+ impl<'a, Ctx> self::Snapshot<'a, Ctx> for $struct_name
+ where Ctx: self::SnapshotContext<'a>,
+ {
+ type Item = $struct_name<AllocIdSnapshot<'a>>;
+
+ #[inline]
+ fn snapshot(&self, __ctx: &'a Ctx) -> Self::Item {
+ let $struct_name {
+ $(ref $field),*
+ } = *self;
+
+ $struct_name {
+ $( $field: __impl_snapshot_field!($field, __ctx $(, $delegate)*) ),*
+ }
+ }
+ }
+ };
+}
+
+impl<'a, Ctx, T> Snapshot<'a, Ctx> for Option<T>
+ where Ctx: SnapshotContext<'a>,
+ T: Snapshot<'a, Ctx>
+{
+ type Item = Option<<T as Snapshot<'a, Ctx>>::Item>;
+
+ fn snapshot(&self, ctx: &'a Ctx) -> Self::Item {
+ match self {
+ Some(x) => Some(x.snapshot(ctx)),
+ None => None,
+ }
+ }
+}
+
+#[derive(Eq, PartialEq)]
+struct AllocIdSnapshot<'a>(Option<AllocationSnapshot<'a>>);
+
+impl<'a, Ctx> Snapshot<'a, Ctx> for AllocId
+ where Ctx: SnapshotContext<'a>,
+{
+ type Item = AllocIdSnapshot<'a>;
+
+ fn snapshot(&self, ctx: &'a Ctx) -> Self::Item {
+ AllocIdSnapshot(ctx.resolve(self).map(|alloc| alloc.snapshot(ctx)))
+ }
+}
+
+impl_snapshot_for!(struct Pointer {
+ alloc_id,
+ offset -> *offset,
+});
+
+impl<'a, Ctx> Snapshot<'a, Ctx> for Scalar
+ where Ctx: SnapshotContext<'a>,
+{
+ type Item = Scalar<AllocIdSnapshot<'a>>;
+
+ fn snapshot(&self, ctx: &'a Ctx) -> Self::Item {
+ match self {
+ Scalar::Ptr(p) => Scalar::Ptr(p.snapshot(ctx)),
+ Scalar::Bits{ size, bits } => Scalar::Bits {
+ size: *size,
+ bits: *bits,
+ },
+ }
+ }
+}
+
+impl_snapshot_for!(enum ScalarMaybeUndef {
+ Scalar(s),
+ Undef,
+});
+
+impl_snapshot_for!(struct MemPlace {
+ ptr,
+ extra,
+ align -> *align,
+});
+
+impl<'a, Ctx> Snapshot<'a, Ctx> for Place
+ where Ctx: SnapshotContext<'a>,
+{
+ type Item = Place<AllocIdSnapshot<'a>>;
+
+ fn snapshot(&self, ctx: &'a Ctx) -> Self::Item {
+ match self {
+ Place::Ptr(p) => Place::Ptr(p.snapshot(ctx)),
+
+ Place::Local{ frame, local } => Place::Local{
+ frame: *frame,
+ local: *local,
+ },
+ }
+ }
+}
+
+impl_snapshot_for!(enum Value {
+ Scalar(s),
+ ScalarPair(s, t),
+});
+
+impl_snapshot_for!(enum Operand {
+ Immediate(v),
+ Indirect(m),
+});
+
+impl_snapshot_for!(enum LocalValue {
+ Live(v),
+ Dead,
+});
+
+impl<'a, Ctx> Snapshot<'a, Ctx> for Relocations
+ where Ctx: SnapshotContext<'a>,
+{
+ type Item = Relocations<AllocIdSnapshot<'a>>;
+
+ fn snapshot(&self, ctx: &'a Ctx) -> Self::Item {
+ Relocations::from_presorted(self.iter()
+ .map(|(size, id)| (*size, id.snapshot(ctx)))
+ .collect())
+ }
+}
+
+#[derive(Eq, PartialEq)]
+struct AllocationSnapshot<'a> {
+ bytes: &'a [u8],
+ relocations: Relocations<AllocIdSnapshot<'a>>,
+ undef_mask: &'a UndefMask,
+ align: &'a Align,
+ mutability: &'a Mutability,
+}
+
+impl<'a, Ctx> Snapshot<'a, Ctx> for &'a Allocation
+ where Ctx: SnapshotContext<'a>,
+{
+ type Item = AllocationSnapshot<'a>;
+
+ fn snapshot(&self, ctx: &'a Ctx) -> Self::Item {
+ let Allocation { bytes, relocations, undef_mask, align, mutability } = self;
+
+ AllocationSnapshot {
+ bytes,
+ undef_mask,
+ align,
+ mutability,
+ relocations: relocations.snapshot(ctx),
+ }
+ }
+}
+
+#[derive(Eq, PartialEq)]
+struct FrameSnapshot<'a, 'tcx: 'a> {
+ instance: &'a ty::Instance<'tcx>,
+ span: &'a Span,
+ return_to_block: &'a StackPopCleanup,
+ return_place: Place<AllocIdSnapshot<'a>>,
+ locals: IndexVec<mir::Local, LocalValue<AllocIdSnapshot<'a>>>,
+ block: &'a mir::BasicBlock,
+ stmt: usize,
+}
+
+impl<'a, 'mir, 'tcx, Ctx> Snapshot<'a, Ctx> for &'a Frame<'mir, 'tcx>
+ where Ctx: SnapshotContext<'a>,
+{
+ type Item = FrameSnapshot<'a, 'tcx>;
+
+ fn snapshot(&self, ctx: &'a Ctx) -> Self::Item {
+ let Frame {
+ mir: _,
+ instance,
+ span,
+ return_to_block,
+ return_place,
+ locals,
+ block,
+ stmt,
+ } = self;
+
+ FrameSnapshot {
+ instance,
+ span,
+ return_to_block,
+ block,
+ stmt: *stmt,
+ return_place: return_place.snapshot(ctx),
+ locals: locals.iter().map(|local| local.snapshot(ctx)).collect(),
+ }
+ }
+}
+
+#[derive(Eq, PartialEq)]
+struct MemorySnapshot<'a, 'mir: 'a, 'tcx: 'a + 'mir, M: Machine<'mir, 'tcx> + 'a> {
+ data: &'a M::MemoryData,
+}
+
+impl<'a, 'mir, 'tcx, M> Memory<'a, 'mir, 'tcx, M>
+ where M: Machine<'mir, 'tcx>,
+{
+ fn snapshot<'b: 'a>(&'b self) -> MemorySnapshot<'b, 'mir, 'tcx, M> {
+ let Memory { data, .. } = self;
+ MemorySnapshot { data }
+ }
+}
+
+impl<'a, 'b, 'mir, 'tcx, M> SnapshotContext<'b> for Memory<'a, 'mir, 'tcx, M>
+ where M: Machine<'mir, 'tcx>,
+{
+ fn resolve(&'b self, id: &AllocId) -> Option<&'b Allocation> {
+ self.get(*id).ok()
+ }
+}
+
+/// The virtual machine state during const-evaluation at a given point in time.
+struct EvalSnapshot<'a, 'mir, 'tcx: 'a + 'mir, M: Machine<'mir, 'tcx>> {
+ machine: M,
+ memory: Memory<'a, 'mir, 'tcx, M>,
+ stack: Vec<Frame<'mir, 'tcx>>,
+}
+
+impl<'a, 'mir, 'tcx, M> EvalSnapshot<'a, 'mir, 'tcx, M>
+ where M: Machine<'mir, 'tcx>,
+{
+ fn new(
+ machine: &M,
+ memory: &Memory<'a, 'mir, 'tcx, M>,
+ stack: &[Frame<'mir, 'tcx>]) -> Self {
+
+ EvalSnapshot {
+ machine: machine.clone(),
+ memory: memory.clone(),
+ stack: stack.into(),
+ }
+ }
+
+ fn snapshot<'b: 'a>(&'b self)
+ -> (&'b M, MemorySnapshot<'b, 'mir, 'tcx, M>, Vec<FrameSnapshot<'a, 'tcx>>) {
+ let EvalSnapshot{ machine, memory, stack } = self;
+ (&machine, memory.snapshot(), stack.iter().map(|frame| frame.snapshot(memory)).collect())
+ }
+}
+
+impl<'a, 'mir, 'tcx, M> Hash for EvalSnapshot<'a, 'mir, 'tcx, M>
+ where M: Machine<'mir, 'tcx>,
+{
+ fn hash<H: Hasher>(&self, state: &mut H) {
+ // Implement in terms of hash stable, so that k1 == k2 -> hash(k1) == hash(k2)
+ let mut hcx = self.memory.tcx.get_stable_hashing_context();
+ let mut hasher = StableHasher::<u64>::new();
+ self.hash_stable(&mut hcx, &mut hasher);
+ hasher.finish().hash(state)
+ }
+}
+
+impl<'a, 'b, 'mir, 'tcx, M> HashStable<StableHashingContext<'b>>
+ for EvalSnapshot<'a, 'mir, 'tcx, M>
+ where M: Machine<'mir, 'tcx>,
+{
+ fn hash_stable<W: StableHasherResult>(
+ &self,
+ hcx: &mut StableHashingContext<'b>,
+ hasher: &mut StableHasher<W>) {
+
+ let EvalSnapshot{ machine, memory, stack } = self;
+ (machine, &memory.data, stack).hash_stable(hcx, hasher);
+ }
+}
+
+impl<'a, 'mir, 'tcx, M> Eq for EvalSnapshot<'a, 'mir, 'tcx, M>
+ where M: Machine<'mir, 'tcx>,
+{}
+
+impl<'a, 'mir, 'tcx, M> PartialEq for EvalSnapshot<'a, 'mir, 'tcx, M>
+ where M: Machine<'mir, 'tcx>,
+{
+ fn eq(&self, other: &Self) -> bool {
+ self.snapshot() == other.snapshot()
+ }
+}
use rustc::mir;
use rustc::ty::layout::LayoutOf;
-use rustc::mir::interpret::{EvalResult, Scalar};
+use rustc::mir::interpret::{EvalResult, Scalar, PointerArithmetic};
use super::{EvalContext, Machine};
"Constant evaluating a complex constant, this might take some time");
}
- self.loop_detector.observe_and_analyze(&self.machine, &self.stack, &self.memory)
+ self.loop_detector.observe_and_analyze(
+ &self.tcx,
+ &self.machine,
+ &self.memory,
+ &self.stack[..],
+ )
}
pub fn run(&mut self) -> EvalResult<'tcx> {
let src = self.eval_place(place)?;
let mplace = self.force_allocation(src)?;
let len = mplace.len(&self)?;
- let size = self.memory.pointer_size().bytes() as u8;
+ let size = self.pointer_size();
self.write_scalar(
- Scalar::Bits {
- bits: len as u128,
- size,
- },
+ Scalar::from_uint(len, size),
dest,
)?;
}
let layout = self.layout_of(ty)?;
assert!(!layout.is_unsized(),
"SizeOf nullary MIR operator called for unsized type");
- let size = self.memory.pointer_size().bytes() as u8;
+ let size = self.pointer_size();
self.write_scalar(
- Scalar::Bits {
- bits: layout.size.bytes() as u128,
- size,
- },
+ Scalar::from_uint(layout.size.bytes(), size),
dest,
)?;
}
Discriminant(ref place) => {
let place = self.eval_place(place)?;
let discr_val = self.read_discriminant(self.place_to_op(place)?)?.0;
- let size = dest.layout.size.bytes() as u8;
- self.write_scalar(Scalar::Bits {
- bits: discr_val,
- size,
- }, dest)?;
+ let size = dest.layout.size;
+ self.write_scalar(Scalar::from_uint(discr_val, size), dest)?;
}
}
use std::borrow::Cow;
-use rustc::mir;
-use rustc::ty::{self, Ty};
-use rustc::ty::layout::LayoutOf;
+use rustc::{mir, ty};
+use rustc::ty::layout::{self, TyLayout, LayoutOf};
use syntax::source_map::Span;
use rustc_target::spec::abi::Abi;
-use rustc::mir::interpret::{EvalResult, Scalar};
+use rustc::mir::interpret::{EvalResult, PointerArithmetic, EvalErrorKind, Scalar};
use super::{
- EvalContext, Machine, Value, OpTy, Place, PlaceTy, ValTy, Operand, StackPopCleanup
+ EvalContext, Machine, Value, OpTy, Place, PlaceTy, Operand, StackPopCleanup
};
impl<'a, 'mir, 'tcx, M: Machine<'mir, 'tcx>> EvalContext<'a, 'mir, 'tcx, M> {
let mut target_block = targets[targets.len() - 1];
for (index, &const_int) in values.iter().enumerate() {
- // Compare using binary_op
- let const_int = Scalar::Bits {
- bits: const_int,
- size: discr.layout.size.bytes() as u8
- };
+ // Compare using binary_op, to also support pointer values
+ let const_int = Scalar::from_uint(const_int, discr.layout.size);
let (res, _) = self.binary_op(mir::BinOp::Eq,
- discr,
- ValTy { value: Value::Scalar(const_int.into()), layout: discr.layout }
+ discr.to_scalar()?, discr.layout,
+ const_int, discr.layout,
)?;
if res.to_bool()? {
target_block = targets[index];
};
let func = self.eval_operand(func, None)?;
- let (fn_def, sig) = match func.layout.ty.sty {
+ let (fn_def, abi) = match func.layout.ty.sty {
ty::FnPtr(sig) => {
+ let caller_abi = sig.abi();
let fn_ptr = self.read_scalar(func)?.to_ptr()?;
let instance = self.memory.get_fn(fn_ptr)?;
- let instance_ty = instance.ty(*self.tcx);
- match instance_ty.sty {
- ty::FnDef(..) => {
- let sig = self.tcx.normalize_erasing_late_bound_regions(
- self.param_env,
- &sig,
- );
- let real_sig = instance_ty.fn_sig(*self.tcx);
- let real_sig = self.tcx.normalize_erasing_late_bound_regions(
- self.param_env,
- &real_sig,
- );
- if !self.check_sig_compat(sig, real_sig)? {
- return err!(FunctionPointerTyMismatch(real_sig, sig));
- }
- (instance, sig)
- }
- _ => bug!("unexpected fn ptr to ty: {:?}", instance_ty),
- }
+ (instance, caller_abi)
}
ty::FnDef(def_id, substs) => {
let sig = func.layout.ty.fn_sig(*self.tcx);
- let sig = self.tcx.normalize_erasing_late_bound_regions(
- self.param_env,
- &sig,
- );
- (self.resolve(def_id, substs)?, sig)
+ (self.resolve(def_id, substs)?, sig.abi())
},
_ => {
let msg = format!("can't handle callee of type {:?}", func.layout.ty);
let args = self.eval_operands(args)?;
self.eval_fn_call(
fn_def,
+ terminator.source_info.span,
+ abi,
&args[..],
dest,
ret,
- terminator.source_info.span,
- Some(sig),
)?;
}
if expected == cond_val {
self.goto_block(Some(target))?;
} else {
+ // Compute error message
use rustc::mir::interpret::EvalErrorKind::*;
return match *msg {
BoundsCheck { ref len, ref index } => {
}
}
- Yield { .. } => unimplemented!("{:#?}", terminator.kind),
- GeneratorDrop => unimplemented!(),
- DropAndReplace { .. } => unimplemented!(),
- Resume => unimplemented!(),
- Abort => unimplemented!(),
+ Yield { .. } |
+ GeneratorDrop |
+ DropAndReplace { .. } |
+ Resume |
+ Abort => unimplemented!("{:#?}", terminator.kind),
FalseEdges { .. } => bug!("should have been eliminated by\
`simplify_branches` mir pass"),
FalseUnwind { .. } => bug!("should have been eliminated by\
Ok(())
}
- /// Decides whether it is okay to call the method with signature `real_sig`
- /// using signature `sig`.
- /// FIXME: This should take into account the platform-dependent ABI description.
- fn check_sig_compat(
- &mut self,
- sig: ty::FnSig<'tcx>,
- real_sig: ty::FnSig<'tcx>,
- ) -> EvalResult<'tcx, bool> {
- fn check_ty_compat<'tcx>(ty: Ty<'tcx>, real_ty: Ty<'tcx>) -> bool {
- if ty == real_ty {
- return true;
- } // This is actually a fast pointer comparison
- return match (&ty.sty, &real_ty.sty) {
- // Permit changing the pointer type of raw pointers and references as well as
- // mutability of raw pointers.
- // FIXME: Should not be allowed when fat pointers are involved.
- (&ty::RawPtr(_), &ty::RawPtr(_)) => true,
- (&ty::Ref(_, _, _), &ty::Ref(_, _, _)) => {
- ty.is_mutable_pointer() == real_ty.is_mutable_pointer()
- }
- // rule out everything else
- _ => false,
- };
+ fn check_argument_compat(
+ caller: TyLayout<'tcx>,
+ callee: TyLayout<'tcx>,
+ ) -> bool {
+ if caller.ty == callee.ty {
+ // No question
+ return true;
}
-
- if sig.abi == real_sig.abi && sig.variadic == real_sig.variadic &&
- sig.inputs_and_output.len() == real_sig.inputs_and_output.len() &&
- sig.inputs_and_output
- .iter()
- .zip(real_sig.inputs_and_output)
- .all(|(ty, real_ty)| check_ty_compat(ty, real_ty))
- {
- // Definitely good.
- return Ok(true);
+ // Compare layout
+ match (&caller.abi, &callee.abi) {
+ (layout::Abi::Scalar(ref caller), layout::Abi::Scalar(ref callee)) =>
+ // Different valid ranges are okay (once we enforce validity,
+ // that will take care to make it UB to leave the range, just
+ // like for transmute).
+ caller.value == callee.value,
+ // Be conservative
+ _ => false
}
+ }
- if sig.variadic || real_sig.variadic {
- // We're not touching this
- return Ok(false);
+ /// Pass a single argument, checking the types for compatibility.
+ fn pass_argument(
+ &mut self,
+ skip_zst: bool,
+ caller_arg: &mut impl Iterator<Item=OpTy<'tcx>>,
+ callee_arg: PlaceTy<'tcx>,
+ ) -> EvalResult<'tcx> {
+ if skip_zst && callee_arg.layout.is_zst() {
+ // Nothing to do.
+ trace!("Skipping callee ZST");
+ return Ok(());
}
-
- // We need to allow what comes up when a non-capturing closure is cast to a fn().
- match (sig.abi, real_sig.abi) {
- (Abi::Rust, Abi::RustCall) // check the ABIs. This makes the test here non-symmetric.
- if check_ty_compat(sig.output(), real_sig.output())
- && real_sig.inputs_and_output.len() == 3 => {
- // First argument of real_sig must be a ZST
- let fst_ty = real_sig.inputs_and_output[0];
- if self.layout_of(fst_ty)?.is_zst() {
- // Second argument must be a tuple matching the argument list of sig
- let snd_ty = real_sig.inputs_and_output[1];
- match snd_ty.sty {
- ty::Tuple(tys) if sig.inputs().len() == tys.len() =>
- if sig.inputs()
- .iter()
- .zip(tys)
- .all(|(ty, real_ty)| check_ty_compat(ty, real_ty)) {
- return Ok(true)
- },
- _ => {}
- }
- }
- }
- _ => {}
- };
-
- // Nope, this doesn't work.
- return Ok(false);
+ let caller_arg = caller_arg.next()
+ .ok_or_else(|| EvalErrorKind::FunctionArgCountMismatch)?;
+ if skip_zst {
+ debug_assert!(!caller_arg.layout.is_zst(), "ZSTs must have been already filtered out");
+ }
+ // Now, check
+ if !Self::check_argument_compat(caller_arg.layout, callee_arg.layout) {
+ return err!(FunctionArgMismatch(caller_arg.layout.ty, callee_arg.layout.ty));
+ }
+ self.copy_op(caller_arg, callee_arg)
}
/// Call this function -- pushing the stack frame and initializing the arguments.
- /// `sig` is optional in case of FnPtr/FnDef -- but mandatory for closures!
fn eval_fn_call(
&mut self,
instance: ty::Instance<'tcx>,
+ span: Span,
+ caller_abi: Abi,
args: &[OpTy<'tcx>],
dest: Option<PlaceTy<'tcx>>,
ret: Option<mir::BasicBlock>,
- span: Span,
- sig: Option<ty::FnSig<'tcx>>,
) -> EvalResult<'tcx> {
trace!("eval_fn_call: {:#?}", instance);
match instance.def {
ty::InstanceDef::Intrinsic(..) => {
+ if caller_abi != Abi::RustIntrinsic {
+ return err!(FunctionAbiMismatch(caller_abi, Abi::RustIntrinsic));
+ }
// The intrinsic itself cannot diverge, so if we got here without a return
// place... (can happen e.g. for transmute returning `!`)
let dest = match dest {
ty::InstanceDef::DropGlue(..) |
ty::InstanceDef::CloneShim(..) |
ty::InstanceDef::Item(_) => {
+ // ABI check
+ {
+ let callee_abi = {
+ let instance_ty = instance.ty(*self.tcx);
+ match instance_ty.sty {
+ ty::FnDef(..) =>
+ instance_ty.fn_sig(*self.tcx).abi(),
+ ty::Closure(..) => Abi::RustCall,
+ ty::Generator(..) => Abi::Rust,
+ _ => bug!("unexpected callee ty: {:?}", instance_ty),
+ }
+ };
+ // Rust and RustCall are compatible
+ let normalize_abi = |abi| if abi == Abi::RustCall { Abi::Rust } else { abi };
+ if normalize_abi(caller_abi) != normalize_abi(callee_abi) {
+ return err!(FunctionAbiMismatch(caller_abi, callee_abi));
+ }
+ }
+
+ // We need MIR for this fn
let mir = match M::find_fn(self, instance, args, dest, ret)? {
Some(mir) => mir,
None => return Ok(()),
StackPopCleanup::Goto(ret),
)?;
- // If we didn't get a signture, ask `fn_sig`
- let sig = sig.unwrap_or_else(|| {
- let fn_sig = instance.ty(*self.tcx).fn_sig(*self.tcx);
- self.tcx.normalize_erasing_late_bound_regions(self.param_env, &fn_sig)
- });
- assert_eq!(sig.inputs().len(), args.len());
- // We can't test the types, as it is fine if the types are ABI-compatible but
- // not equal.
-
- // Figure out how to pass which arguments.
- // FIXME: Somehow this is horribly full of special cases here, and codegen has
- // none of that. What is going on?
- trace!(
- "ABI: {:?}, args: {:#?}",
- sig.abi,
- args.iter()
- .map(|arg| (arg.layout.ty, format!("{:?}", **arg)))
- .collect::<Vec<_>>()
- );
- trace!(
- "spread_arg: {:?}, locals: {:#?}",
- mir.spread_arg,
- mir.args_iter()
- .map(|local|
- (local, self.layout_of_local(self.cur_frame(), local).unwrap().ty)
- )
- .collect::<Vec<_>>()
- );
-
- // We have two iterators: Where the arguments come from,
- // and where they go to.
-
- // For where they come from: If the ABI is RustCall, we untuple the
- // last incoming argument. These do not have the same type,
- // so to keep the code paths uniform we accept an allocation
- // (for RustCall ABI only).
- let args_effective : Cow<[OpTy<'tcx>]> =
- if sig.abi == Abi::RustCall && !args.is_empty() {
- // Untuple
- let (&untuple_arg, args) = args.split_last().unwrap();
- trace!("eval_fn_call: Will pass last argument by untupling");
- Cow::from(args.iter().map(|&a| Ok(a))
- .chain((0..untuple_arg.layout.fields.count()).into_iter()
- .map(|i| self.operand_field(untuple_arg, i as u64))
+ // We want to pop this frame again in case there was an error, to put
+ // the blame in the right location. Until the 2018 edition is used in
+ // the compiler, we have to do this with an immediately invoked function.
+ let res = (||{
+ trace!(
+ "caller ABI: {:?}, args: {:#?}",
+ caller_abi,
+ args.iter()
+ .map(|arg| (arg.layout.ty, format!("{:?}", **arg)))
+ .collect::<Vec<_>>()
+ );
+ trace!(
+ "spread_arg: {:?}, locals: {:#?}",
+ mir.spread_arg,
+ mir.args_iter()
+ .map(|local|
+ (local, self.layout_of_local(self.cur_frame(), local).unwrap().ty)
)
- .collect::<EvalResult<Vec<OpTy<'tcx>>>>()?)
- } else {
- // Plain arg passing
- Cow::from(args)
+ .collect::<Vec<_>>()
+ );
+
+ // Figure out how to pass which arguments.
+ // We have two iterators: Where the arguments come from,
+ // and where they go to.
+ let skip_zst = match caller_abi {
+ Abi::Rust | Abi::RustCall => true,
+ _ => false
};
- // Now we have to spread them out across the callee's locals,
- // taking into account the `spread_arg`.
- let mut args_iter = args_effective.iter();
- let mut local_iter = mir.args_iter();
- // HACK: ClosureOnceShim calls something that expects a ZST as
- // first argument, but the callers do not actually pass that ZST.
- // Codegen doesn't care because ZST arguments do not even exist there.
- match instance.def {
- ty::InstanceDef::ClosureOnceShim { .. } if sig.abi == Abi::Rust => {
- let local = local_iter.next().unwrap();
+ // For where they come from: If the ABI is RustCall, we untuple the
+ // last incoming argument. These two iterators do not have the same type,
+ // so to keep the code paths uniform we accept an allocation
+ // (for RustCall ABI only).
+ let caller_args : Cow<[OpTy<'tcx>]> =
+ if caller_abi == Abi::RustCall && !args.is_empty() {
+ // Untuple
+ let (&untuple_arg, args) = args.split_last().unwrap();
+ trace!("eval_fn_call: Will pass last argument by untupling");
+ Cow::from(args.iter().map(|&a| Ok(a))
+ .chain((0..untuple_arg.layout.fields.count()).into_iter()
+ .map(|i| self.operand_field(untuple_arg, i as u64))
+ )
+ .collect::<EvalResult<Vec<OpTy<'tcx>>>>()?)
+ } else {
+ // Plain arg passing
+ Cow::from(args)
+ };
+ // Skip ZSTs
+ let mut caller_iter = caller_args.iter()
+ .filter(|op| !skip_zst || !op.layout.is_zst())
+ .map(|op| *op);
+
+ // Now we have to spread them out across the callee's locals,
+ // taking into account the `spread_arg`. If we could write
+ // this is a single iterator (that handles `spread_arg`), then
+ // `pass_argument` would be the loop body. It takes care to
+ // not advance `caller_iter` for ZSTs.
+ let mut locals_iter = mir.args_iter();
+ while let Some(local) = locals_iter.next() {
let dest = self.eval_place(&mir::Place::Local(local))?;
- assert!(dest.layout.is_zst());
- }
- _ => {}
- }
- // Now back to norml argument passing.
- while let Some(local) = local_iter.next() {
- let dest = self.eval_place(&mir::Place::Local(local))?;
- if Some(local) == mir.spread_arg {
- // Must be a tuple
- for i in 0..dest.layout.fields.count() {
- let dest = self.place_field(dest, i as u64)?;
- self.copy_op(*args_iter.next().unwrap(), dest)?;
+ if Some(local) == mir.spread_arg {
+ // Must be a tuple
+ for i in 0..dest.layout.fields.count() {
+ let dest = self.place_field(dest, i as u64)?;
+ self.pass_argument(skip_zst, &mut caller_iter, dest)?;
+ }
+ } else {
+ // Normal argument
+ self.pass_argument(skip_zst, &mut caller_iter, dest)?;
}
- } else {
- // Normal argument
- self.copy_op(*args_iter.next().unwrap(), dest)?;
}
+ // Now we should have no more caller args
+ if caller_iter.next().is_some() {
+ trace!("Caller has too many args over");
+ return err!(FunctionArgCountMismatch);
+ }
+ Ok(())
+ })();
+ match res {
+ Err(err) => {
+ self.stack.pop();
+ Err(err)
+ }
+ Ok(v) => Ok(v)
}
- // Now we should be done
- assert!(args_iter.next().is_none());
- Ok(())
}
// cannot use the shim here, because that will only result in infinite recursion
ty::InstanceDef::Virtual(_, idx) => {
- let ptr_size = self.memory.pointer_size();
+ let ptr_size = self.pointer_size();
let ptr_align = self.tcx.data_layout.pointer_align;
let ptr = self.ref_to_mplace(self.read_value(args[0])?)?;
let vtable = ptr.vtable()?;
args[0].op = Operand::Immediate(Value::Scalar(ptr.ptr.into())); // strip vtable
trace!("Patched self operand to {:#?}", args[0]);
// recurse with concrete function
- self.eval_fn_call(instance, &args, dest, ret, span, sig)
+ self.eval_fn_call(instance, span, caller_abi, &args, dest, ret)
}
}
}
self.eval_fn_call(
instance,
+ span,
+ Abi::Rust,
&[arg],
Some(dest),
Some(target),
- span,
- None,
)
}
}
use rustc::ty::{self, Ty};
use rustc::ty::layout::{Size, Align, LayoutOf};
-use rustc::mir::interpret::{Scalar, Pointer, EvalResult};
+use rustc::mir::interpret::{Scalar, Pointer, EvalResult, PointerArithmetic};
use syntax::ast::Mutability;
let size = layout.size.bytes();
let align = layout.align.abi();
- let ptr_size = self.memory.pointer_size();
+ let ptr_size = self.pointer_size();
let ptr_align = self.tcx.data_layout.pointer_align;
let methods = self.tcx.vtable_methods(trait_ref);
let vtable = self.memory.allocate(
self.memory.write_ptr_sized(vtable, ptr_align, Scalar::Ptr(drop).into())?;
let size_ptr = vtable.offset(ptr_size, &self)?;
- self.memory.write_ptr_sized(size_ptr, ptr_align, Scalar::Bits {
- bits: size as u128,
- size: ptr_size.bytes() as u8,
- }.into())?;
+ self.memory.write_ptr_sized(size_ptr, ptr_align, Scalar::from_uint(size, ptr_size).into())?;
let align_ptr = vtable.offset(ptr_size * 2, &self)?;
- self.memory.write_ptr_sized(align_ptr, ptr_align, Scalar::Bits {
- bits: align as u128,
- size: ptr_size.bytes() as u8,
- }.into())?;
+ self.memory.write_ptr_sized(align_ptr, ptr_align,
+ Scalar::from_uint(align, ptr_size).into())?;
for (i, method) in methods.iter().enumerate() {
if let Some((def_id, substs)) = *method {
&self,
vtable: Pointer,
) -> EvalResult<'tcx, (Size, Align)> {
- let pointer_size = self.memory.pointer_size();
+ let pointer_size = self.pointer_size();
let pointer_align = self.tcx.data_layout.pointer_align;
let size = self.memory.read_ptr_sized(vtable.offset(pointer_size, self)?,pointer_align)?
.to_bits(pointer_size)? as u64;
use rustc::ty::{self, Ty};
use rustc_data_structures::fx::FxHashSet;
use rustc::mir::interpret::{
- Scalar, AllocType, EvalResult, ScalarMaybeUndef, EvalErrorKind
+ Scalar, AllocType, EvalResult, ScalarMaybeUndef, EvalErrorKind, PointerArithmetic
};
use super::{
bits
},
Scalar::Ptr(_) => {
- let ptr_size = self.memory.pointer_size();
+ match ty.sty {
+ ty::Bool |
+ ty::Char |
+ ty::Float(_) |
+ ty::Int(_) |
+ ty::Uint(_) => {
+ return validation_failure!(
+ "a pointer",
+ path,
+ format!("the type {}", ty.sty)
+ );
+ }
+ ty::RawPtr(_) |
+ ty::Ref(_, _, _) |
+ ty::FnPtr(_) => {}
+ _ => { unreachable!(); }
+ }
+
+ let ptr_size = self.pointer_size();
let ptr_max = u128::max_value() >> (128 - ptr_size.bits());
return if lo > hi {
if lo - hi == 1 {
"non-pointer vtable in fat pointer", path
),
}
+ // FIXME: More checks for the vtable.
}
ty::Slice(..) | ty::Str => {
match ptr.extra.unwrap().to_usize(self) {
#![feature(box_patterns)]
#![feature(box_syntax)]
#![feature(crate_visibility_modifier)]
-#![feature(const_fn)]
#![feature(core_intrinsics)]
#![feature(decl_macro)]
#![cfg_attr(stage0, feature(macro_vis_matcher))]
#![feature(slice_concat_ext)]
#![feature(if_while_or_patterns)]
#![feature(try_from)]
+#![feature(reverse_bits)]
#![recursion_limit="256"]
shim::provide(providers);
transform::provide(providers);
providers.const_eval = interpret::const_eval_provider;
- providers.const_to_allocation = interpret::const_to_allocation_provider;
providers.check_match = hair::pattern::check_match;
}
//! inlining, even when they are not marked #[inline].
use monomorphize::collector::InliningMap;
-use rustc::dep_graph::WorkProductId;
+use rustc::dep_graph::{WorkProductId, WorkProduct, DepNode, DepConstructor};
use rustc::hir::CodegenFnAttrFlags;
use rustc::hir::def_id::{DefId, LOCAL_CRATE, CRATE_DEF_INDEX};
use rustc::hir::map::DefPathData;
WorkProductId::from_cgu_name(&self.name().as_str())
}
+ fn work_product(&self, tcx: TyCtxt) -> WorkProduct {
+ let work_product_id = self.work_product_id();
+ tcx.dep_graph
+ .previous_work_product(&work_product_id)
+ .unwrap_or_else(|| {
+ panic!("Could not find work-product for CGU `{}`", self.name())
+ })
+ }
+
fn items_in_deterministic_order<'a>(&self,
tcx: TyCtxt<'a, 'tcx, 'tcx>)
-> Vec<(MonoItem<'tcx>,
items.sort_by_cached_key(|&(i, _)| item_sort_key(tcx, i));
items
}
+
+ fn codegen_dep_node(&self, tcx: TyCtxt<'_, 'tcx, 'tcx>) -> DepNode {
+ DepNode::new(tcx, DepConstructor::CompileCodegenUnit(self.name().clone()))
+ }
}
impl<'tcx> CodegenUnitExt<'tcx> for CodegenUnit<'tcx> {
pub struct UnsafetyChecker<'a, 'tcx: 'a> {
mir: &'a Mir<'tcx>,
+ min_const_fn: bool,
source_scope_local_data: &'a IndexVec<SourceScope, SourceScopeLocalData>,
violations: Vec<UnsafetyViolation>,
source_info: SourceInfo,
}
impl<'a, 'gcx, 'tcx> UnsafetyChecker<'a, 'tcx> {
- fn new(mir: &'a Mir<'tcx>,
- source_scope_local_data: &'a IndexVec<SourceScope, SourceScopeLocalData>,
- tcx: TyCtxt<'a, 'tcx, 'tcx>,
- param_env: ty::ParamEnv<'tcx>) -> Self {
+ fn new(
+ min_const_fn: bool,
+ mir: &'a Mir<'tcx>,
+ source_scope_local_data: &'a IndexVec<SourceScope, SourceScopeLocalData>,
+ tcx: TyCtxt<'a, 'tcx, 'tcx>,
+ param_env: ty::ParamEnv<'tcx>,
+ ) -> Self {
Self {
mir,
+ min_const_fn,
source_scope_local_data,
violations: vec![],
source_info: SourceInfo {
fn register_violations(&mut self,
violations: &[UnsafetyViolation],
unsafe_blocks: &[(ast::NodeId, bool)]) {
+ if self.min_const_fn {
+ for violation in violations {
+ let mut violation = violation.clone();
+ violation.kind = UnsafetyViolationKind::MinConstFn;
+ if !self.violations.contains(&violation) {
+ self.violations.push(violation)
+ }
+ }
+ }
let within_unsafe = match self.source_scope_local_data[self.source_info.scope].safety {
Safety::Safe => {
for violation in violations {
self.violations.push(violation.clone())
}
}
-
false
}
Safety::BuiltinUnsafe | Safety::FnUnsafe => true,
let param_env = tcx.param_env(def_id);
let mut checker = UnsafetyChecker::new(
+ tcx.is_const_fn(def_id) && tcx.is_min_const_fn(def_id),
mir, source_scope_local_data, tcx, param_env);
checker.visit_mir(mir);
.note(&details.as_str()[..])
.emit();
}
+ UnsafetyViolationKind::MinConstFn => {
+ tcx.sess.struct_span_err(
+ source_info.span,
+ &format!("{} is unsafe and unsafe operations \
+ are not allowed in const fn", description))
+ .span_label(source_info.span, &description.as_str()[..])
+ .note(&details.as_str()[..])
+ .emit();
+ }
UnsafetyViolationKind::ExternStatic(lint_node_id) => {
tcx.lint_node_note(SAFE_EXTERN_STATICS,
lint_node_id,
};
use rustc::ty::{TyCtxt, self, Instance};
use interpret::{EvalContext, CompileTimeEvaluator, eval_promoted, mk_borrowck_eval_cx};
-use interpret::{Value, OpTy, MemoryKind};
+use interpret::{self, Value, OpTy, MemoryKind};
use transform::{MirPass, MirSource};
use syntax::source_map::{Span, DUMMY_SP};
use rustc::ty::subst::Substs;
| MachineError(_)
// at runtime these transformations might make sense
// FIXME: figure out the rules and start linting
- | FunctionPointerTyMismatch(..)
+ | FunctionAbiMismatch(..)
+ | FunctionArgMismatch(..)
+ | FunctionArgCountMismatch
// fine at runtime, might be a register address or sth
| ReadBytesAsPointer
// fine at runtime
Rvalue::Len(_) => None,
Rvalue::NullaryOp(NullOp::SizeOf, ty) => {
type_size_of(self.tcx, self.param_env, ty).and_then(|n| Some((
- OpTy::from_scalar_value(
- Scalar::Bits {
- bits: n as u128,
- size: self.tcx.data_layout.pointer_size.bytes() as u8,
- },
- self.tcx.layout_of(self.param_env.and(self.tcx.types.usize)).ok()?,
- ),
+ OpTy {
+ op: interpret::Operand::Immediate(Value::Scalar(
+ Scalar::Bits {
+ bits: n as u128,
+ size: self.tcx.data_layout.pointer_size.bytes() as u8,
+ }.into()
+ )),
+ layout: self.tcx.layout_of(self.param_env.and(self.tcx.types.usize)).ok()?,
+ },
span,
)))
}
// Now run the actual operation.
this.ecx.unary_op(op, prim, arg.layout)
})?;
- Some((OpTy::from_scalar_value(val, place_layout), span))
+ let res = OpTy {
+ op: interpret::Operand::Immediate(Value::Scalar(val.into())),
+ layout: place_layout,
+ };
+ Some((res, span))
}
Rvalue::CheckedBinaryOp(op, ref left, ref right) |
Rvalue::BinaryOp(op, ref left, ref right) => {
})?;
trace!("const evaluating {:?} for {:?} and {:?}", op, left, right);
let (val, overflow) = self.use_ecx(source_info, |this| {
- this.ecx.binary_op(op, l, r)
+ this.ecx.binary_op_val(op, l, r)
})?;
let val = if let Rvalue::CheckedBinaryOp(..) = *rvalue {
Value::ScalarPair(
Value::Scalar(val.into())
};
let res = OpTy {
- op: ::interpret::Operand::Immediate(val),
+ op: interpret::Operand::Immediate(val),
layout: place_layout,
};
Some((res, span))
use rustc::ty::subst::Substs;
use util::dump_mir;
use util::liveness::{self, IdentityMap};
+use rustc_data_structures::fx::FxHashMap;
use rustc_data_structures::indexed_vec::Idx;
use rustc_data_structures::indexed_set::IdxSet;
-use std::collections::HashMap;
use std::borrow::Cow;
use std::iter::once;
use std::mem;
state_field: usize,
// Mapping from Local to (type of local, generator struct index)
- remap: HashMap<Local, (Ty<'tcx>, usize)>,
+ // FIXME(eddyb) This should use `IndexVec<Local, Option<_>>`.
+ remap: FxHashMap<Local, (Ty<'tcx>, usize)>,
// A map from a suspension point in a block to the locals which have live storage at that point
- storage_liveness: HashMap<BasicBlock, liveness::LiveVarSet<Local>>,
+ // FIXME(eddyb) This should use `IndexVec<BasicBlock, Option<_>>`.
+ storage_liveness: FxHashMap<BasicBlock, liveness::LiveVarSet<Local>>,
// A list of suspension points, generated during the transform
suspension_points: Vec<SuspensionPoint>,
}
}
-fn locals_live_across_suspend_points<'a, 'tcx,>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
- mir: &Mir<'tcx>,
- source: MirSource,
- movable: bool) ->
- (liveness::LiveVarSet<Local>,
- HashMap<BasicBlock, liveness::LiveVarSet<Local>>) {
+fn locals_live_across_suspend_points(
+ tcx: TyCtxt<'a, 'tcx, 'tcx>,
+ mir: &Mir<'tcx>,
+ source: MirSource,
+ movable: bool,
+) -> (
+ liveness::LiveVarSet<Local>,
+ FxHashMap<BasicBlock, liveness::LiveVarSet<Local>>,
+) {
let dead_unwinds = IdxSet::new_empty(mir.basic_blocks().len());
let node_id = tcx.hir.as_local_node_id(source.def_id).unwrap();
&liveness,
);
- let mut storage_liveness_map = HashMap::new();
+ let mut storage_liveness_map = FxHashMap::default();
for (block, data) in mir.basic_blocks().iter_enumerated() {
if let TerminatorKind::Yield { .. } = data.terminator().kind {
interior: Ty<'tcx>,
movable: bool,
mir: &mut Mir<'tcx>)
- -> (HashMap<Local, (Ty<'tcx>, usize)>,
+ -> (FxHashMap<Local, (Ty<'tcx>, usize)>,
GeneratorLayout<'tcx>,
- HashMap<BasicBlock, liveness::LiveVarSet<Local>>)
+ FxHashMap<BasicBlock, liveness::LiveVarSet<Local>>)
{
// Use a liveness analysis to compute locals which are live across a suspension point
let (live_locals, storage_liveness) = locals_live_across_suspend_points(tcx,
pub mod add_call_guards;
pub mod promote_consts;
pub mod qualify_consts;
+mod qualify_min_const_fn;
pub mod remove_noop_landing_pads;
pub mod dump_mir;
pub mod deaggregator;
mir: &'a Mir<'tcx>,
mode: Mode)
-> Qualifier<'a, 'tcx, 'tcx> {
+ assert!(def_id.is_local());
let mut rpo = traversal::reverse_postorder(mir);
let temps = promote_consts::collect_temps(mir, &mut rpo);
rpo.reset();
| "min_align_of"
| "type_id"
| "bswap"
+ | "bitreverse"
| "ctpop"
| "cttz"
| "cttz_nonzero"
| "ctlz"
- | "ctlz_nonzero" => is_const_fn = Some(def_id),
+ | "ctlz_nonzero"
+ | "overflowing_add"
+ | "overflowing_sub"
+ | "overflowing_mul"
+ | "unchecked_shl"
+ | "unchecked_shr"
+ | "add_with_overflow"
+ | "sub_with_overflow"
+ | "mul_with_overflow" => is_const_fn = Some(def_id),
"transmute" => {
if self.mode != Mode::Fn {
is_const_fn = Some(def_id);
);
}
} else if let Some(&attr::Stability {
- rustc_const_unstable: Some(attr::RustcConstUnstable {
- feature: ref feature_name
- }),
+ const_stability: Some(ref feature_name),
.. }) = self.tcx.lookup_stability(def_id) {
if
// feature-gate is not enabled,
.iter()
.any(|&(ref sym, _)| sym == feature_name) &&
- // this doesn't come from a crate with the feature-gate enabled,
- self.def_id.is_local() &&
-
// this doesn't come from a macro that has #[allow_internal_unstable]
!self.span.allows_unstable()
{
let (temps, candidates) = {
let mut qualifier = Qualifier::new(tcx, def_id, mir, mode);
if mode == Mode::ConstFn {
- // Enforce a constant-like CFG for `const fn`.
- qualifier.qualify_const();
+ if tcx.is_min_const_fn(def_id) {
+ // enforce `min_const_fn` for stable const fns
+ use super::qualify_min_const_fn::is_min_const_fn;
+ if let Err((span, err)) = is_min_const_fn(tcx, def_id, mir) {
+ tcx.sess.span_err(span, &err);
+ } else {
+ // this should not produce any errors, but better safe than sorry
+ // FIXME(#53819)
+ qualifier.qualify_const();
+ }
+ } else {
+ // Enforce a constant-like CFG for `const fn`.
+ qualifier.qualify_const();
+ }
} else {
while let Some((bb, data)) = qualifier.rpo.next() {
qualifier.visit_basic_block_data(bb, data);
--- /dev/null
+use rustc::hir::def_id::DefId;
+use rustc::hir;
+use rustc::mir::*;
+use rustc::ty::{self, Predicate, TyCtxt};
+use std::borrow::Cow;
+use syntax_pos::Span;
+
+type McfResult = Result<(), (Span, Cow<'static, str>)>;
+
+pub fn is_min_const_fn(
+ tcx: TyCtxt<'a, 'tcx, 'tcx>,
+ def_id: DefId,
+ mir: &'a Mir<'tcx>,
+) -> McfResult {
+ let mut current = def_id;
+ loop {
+ let predicates = tcx.predicates_of(current);
+ for predicate in &predicates.predicates {
+ match predicate {
+ | Predicate::RegionOutlives(_)
+ | Predicate::TypeOutlives(_)
+ | Predicate::WellFormed(_)
+ | Predicate::ConstEvaluatable(..) => continue,
+ | Predicate::ObjectSafe(_) => {
+ bug!("object safe predicate on function: {:#?}", predicate)
+ }
+ Predicate::ClosureKind(..) => {
+ bug!("closure kind predicate on function: {:#?}", predicate)
+ }
+ Predicate::Subtype(_) => bug!("subtype predicate on function: {:#?}", predicate),
+ Predicate::Projection(_) => {
+ let span = tcx.def_span(current);
+ // we'll hit a `Predicate::Trait` later which will report an error
+ tcx.sess
+ .delay_span_bug(span, "projection without trait bound");
+ continue;
+ }
+ Predicate::Trait(pred) => {
+ if Some(pred.def_id()) == tcx.lang_items().sized_trait() {
+ continue;
+ }
+ match pred.skip_binder().self_ty().sty {
+ ty::Param(ref p) => {
+ let generics = tcx.generics_of(current);
+ let def = generics.type_param(p, tcx);
+ let span = tcx.def_span(def.def_id);
+ return Err((
+ span,
+ "trait bounds other than `Sized` \
+ on const fn parameters are unstable"
+ .into(),
+ ));
+ }
+ // other kinds of bounds are either tautologies
+ // or cause errors in other passes
+ _ => continue,
+ }
+ }
+ }
+ }
+ match predicates.parent {
+ Some(parent) => current = parent,
+ None => break,
+ }
+ }
+
+ for local in mir.vars_iter() {
+ return Err((
+ mir.local_decls[local].source_info.span,
+ "local variables in const fn are unstable".into(),
+ ));
+ }
+ for local in &mir.local_decls {
+ check_ty(tcx, local.ty, local.source_info.span)?;
+ }
+ // impl trait is gone in MIR, so check the return type manually
+ check_ty(
+ tcx,
+ tcx.fn_sig(def_id).output().skip_binder(),
+ mir.local_decls.iter().next().unwrap().source_info.span,
+ )?;
+
+ for bb in mir.basic_blocks() {
+ check_terminator(tcx, mir, bb.terminator())?;
+ for stmt in &bb.statements {
+ check_statement(tcx, mir, stmt)?;
+ }
+ }
+ Ok(())
+}
+
+fn check_ty(
+ tcx: TyCtxt<'a, 'tcx, 'tcx>,
+ ty: ty::Ty<'tcx>,
+ span: Span,
+) -> McfResult {
+ for ty in ty.walk() {
+ match ty.sty {
+ ty::Ref(_, _, hir::Mutability::MutMutable) => return Err((
+ span,
+ "mutable references in const fn are unstable".into(),
+ )),
+ ty::Anon(..) => return Err((span, "`impl Trait` in const fn is unstable".into())),
+ ty::FnPtr(..) => {
+ return Err((span, "function pointers in const fn are unstable".into()))
+ }
+ ty::Dynamic(preds, _) => {
+ for pred in preds.iter() {
+ match pred.skip_binder() {
+ | ty::ExistentialPredicate::AutoTrait(_)
+ | ty::ExistentialPredicate::Projection(_) => {
+ return Err((
+ span,
+ "trait bounds other than `Sized` \
+ on const fn parameters are unstable"
+ .into(),
+ ))
+ }
+ ty::ExistentialPredicate::Trait(trait_ref) => {
+ if Some(trait_ref.def_id) != tcx.lang_items().sized_trait() {
+ return Err((
+ span,
+ "trait bounds other than `Sized` \
+ on const fn parameters are unstable"
+ .into(),
+ ));
+ }
+ }
+ }
+ }
+ }
+ _ => {}
+ }
+ }
+ Ok(())
+}
+
+fn check_rvalue(
+ tcx: TyCtxt<'a, 'tcx, 'tcx>,
+ mir: &'a Mir<'tcx>,
+ rvalue: &Rvalue<'tcx>,
+ span: Span,
+) -> McfResult {
+ match rvalue {
+ Rvalue::Repeat(operand, _) | Rvalue::Use(operand) => {
+ check_operand(tcx, mir, operand, span)
+ }
+ Rvalue::Len(place) | Rvalue::Discriminant(place) | Rvalue::Ref(_, _, place) => {
+ check_place(tcx, mir, place, span, PlaceMode::Read)
+ }
+ Rvalue::Cast(_, operand, cast_ty) => {
+ use rustc::ty::cast::CastTy;
+ let cast_in = CastTy::from_ty(operand.ty(mir, tcx)).expect("bad input type for cast");
+ let cast_out = CastTy::from_ty(cast_ty).expect("bad output type for cast");
+ match (cast_in, cast_out) {
+ (CastTy::Ptr(_), CastTy::Int(_)) | (CastTy::FnPtr, CastTy::Int(_)) => Err((
+ span,
+ "casting pointers to ints is unstable in const fn".into(),
+ )),
+ (CastTy::RPtr(_), CastTy::Float) => bug!(),
+ (CastTy::RPtr(_), CastTy::Int(_)) => bug!(),
+ (CastTy::Ptr(_), CastTy::RPtr(_)) => bug!(),
+ _ => check_operand(tcx, mir, operand, span),
+ }
+ }
+ // 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)?;
+ let ty = lhs.ty(mir, tcx);
+ if ty.is_integral() || ty.is_bool() || ty.is_char() {
+ Ok(())
+ } else {
+ Err((
+ span,
+ "only int, `bool` and `char` operations are stable in const fn".into(),
+ ))
+ }
+ }
+ // checked by regular const fn checks
+ Rvalue::NullaryOp(..) => Ok(()),
+ Rvalue::UnaryOp(_, operand) => {
+ let ty = operand.ty(mir, tcx);
+ if ty.is_integral() || ty.is_bool() {
+ check_operand(tcx, mir, operand, span)
+ } else {
+ Err((
+ span,
+ "only int and `bool` operations are stable in const fn".into(),
+ ))
+ }
+ }
+ Rvalue::Aggregate(_, operands) => {
+ for operand in operands {
+ check_operand(tcx, mir, operand, span)?;
+ }
+ Ok(())
+ }
+ }
+}
+
+enum PlaceMode {
+ Assign,
+ Read,
+}
+
+fn check_statement(
+ tcx: TyCtxt<'a, 'tcx, 'tcx>,
+ mir: &'a Mir<'tcx>,
+ statement: &Statement<'tcx>,
+) -> McfResult {
+ let span = statement.source_info.span;
+ match &statement.kind {
+ StatementKind::Assign(place, rval) => {
+ check_place(tcx, mir, place, span, PlaceMode::Assign)?;
+ check_rvalue(tcx, mir, rval, span)
+ }
+
+ StatementKind::ReadForMatch(_) => Err((span, "match in const fn is unstable".into())),
+
+ // just an assignment
+ StatementKind::SetDiscriminant { .. } => Ok(()),
+
+ | StatementKind::InlineAsm { .. } => {
+ Err((span, "cannot use inline assembly in const fn".into()))
+ }
+
+ // These are all NOPs
+ | StatementKind::StorageLive(_)
+ | StatementKind::StorageDead(_)
+ | StatementKind::Validate(..)
+ | StatementKind::EndRegion(_)
+ | StatementKind::UserAssertTy(..)
+ | StatementKind::Nop => 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, PlaceMode::Read)
+ }
+ Operand::Constant(_) => Ok(()),
+ }
+}
+
+fn check_place(
+ tcx: TyCtxt<'a, 'tcx, 'tcx>,
+ mir: &'a Mir<'tcx>,
+ place: &Place<'tcx>,
+ span: Span,
+ mode: PlaceMode,
+) -> McfResult {
+ match place {
+ Place::Local(l) => match mode {
+ PlaceMode::Assign => match mir.local_kind(*l) {
+ LocalKind::Temp | LocalKind::ReturnPointer => Ok(()),
+ LocalKind::Arg | LocalKind::Var => {
+ Err((span, "assignments in const fn are unstable".into()))
+ }
+ },
+ PlaceMode::Read => Ok(()),
+ },
+ // promoteds are always fine, they are essentially constants
+ Place::Promoted(_) => Ok(()),
+ Place::Static(_) => Err((span, "cannot access `static` items in const fn".into())),
+ Place::Projection(proj) => {
+ match proj.elem {
+ | ProjectionElem::Deref | ProjectionElem::Field(..) | ProjectionElem::Index(_) => {
+ check_place(tcx, mir, &proj.base, span, mode)
+ }
+ // slice patterns are unstable
+ | ProjectionElem::ConstantIndex { .. } | ProjectionElem::Subslice { .. } => {
+ return Err((span, "slice patterns in const fn are unstable".into()))
+ }
+ | ProjectionElem::Downcast(..) => {
+ Err((span, "`match` or `if let` in `const fn` is unstable".into()))
+ }
+ }
+ }
+ }
+}
+
+fn check_terminator(
+ tcx: TyCtxt<'a, 'tcx, 'tcx>,
+ mir: &'a Mir<'tcx>,
+ terminator: &Terminator<'tcx>,
+) -> McfResult {
+ let span = terminator.source_info.span;
+ match &terminator.kind {
+ | TerminatorKind::Goto { .. }
+ | TerminatorKind::Return
+ | TerminatorKind::Resume => Ok(()),
+
+ TerminatorKind::Drop { location, .. } => {
+ check_place(tcx, mir, location, span, PlaceMode::Read)
+ }
+ TerminatorKind::DropAndReplace { location, value, .. } => {
+ check_place(tcx, mir, location, span, PlaceMode::Read)?;
+ check_operand(tcx, mir, value, span)
+ },
+ TerminatorKind::SwitchInt { .. } => Err((
+ span,
+ "`if`, `match`, `&&` and `||` are not stable in const fn".into(),
+ )),
+ | TerminatorKind::Abort | TerminatorKind::Unreachable => {
+ Err((span, "const fn with unreachable code is not stable".into()))
+ }
+ | TerminatorKind::GeneratorDrop | TerminatorKind::Yield { .. } => {
+ Err((span, "const fn generators are unstable".into()))
+ }
+
+ TerminatorKind::Call {
+ func,
+ args,
+ destination: _,
+ cleanup: _,
+ } => {
+ let fn_ty = func.ty(mir, tcx);
+ if let ty::FnDef(def_id, _) = fn_ty.sty {
+ if tcx.is_min_const_fn(def_id) {
+ check_operand(tcx, mir, func, span)?;
+
+ for arg in args {
+ check_operand(tcx, mir, arg, span)?;
+ }
+ Ok(())
+ } else {
+ Err((
+ span,
+ "can only call other `min_const_fn` within a `min_const_fn`".into(),
+ ))
+ }
+ } else {
+ Err((span, "can only call other const fns within const fn".into()))
+ }
+ }
+
+ TerminatorKind::Assert {
+ cond,
+ expected: _,
+ msg: _,
+ target: _,
+ cleanup: _,
+ } => check_operand(tcx, mir, cond, span),
+
+ | TerminatorKind::FalseEdges { .. } | TerminatorKind::FalseUnwind { .. } => span_bug!(
+ terminator.source_info.span,
+ "min_const_fn encountered `{:#?}`",
+ terminator
+ ),
+ }
+}
}
if let Some(&attr::Stability {
- rustc_const_unstable: Some(attr::RustcConstUnstable {
- feature: ref feature_name
- }),
+ const_stability: Some(ref feature_name),
.. }) = self.tcx.lookup_stability(def_id) {
let stable_check =
// feature-gate is enabled,
.iter()
.any(|&(ref sym, _)| sym == feature_name) ||
- // this comes from a crate with the feature-gate enabled,
- !def_id.is_local() ||
-
// this comes from a macro that has #[allow_internal_unstable]
span.allows_unstable();
if !stable_check {
for index in hirvec_arm.iter() {
let _ = v.check_expr(&*index.body);
match index.guard {
- Some(ref expr) => {
+ Some(hir::Guard::If(ref expr)) => {
let _ = v.check_expr(&expr);
},
None => {},
// option. This file may not be copied, modified, or distributed
// except according to those terms.
-#![allow(bad_style)]
+#![allow(nonstandard_style)]
#![cfg_attr(not(stage0), feature(nll))]
#![cfg_attr(not(stage0), feature(infer_outlives_requirements))]
use rustc::lint::{EarlyLintPassObject, LateLintPassObject, LintId, Lint};
use rustc::session::Session;
+use rustc::util::nodemap::FxHashMap;
use syntax::ext::base::{SyntaxExtension, NamedSyntaxExtension, NormalTT, IdentTT};
use syntax::ext::base::MacroExpanderFn;
use syntax::feature_gate::AttributeType;
use syntax_pos::Span;
-use std::collections::HashMap;
use std::borrow::ToOwned;
/// Structure used to register plugins.
pub late_lint_passes: Vec<LateLintPassObject>,
#[doc(hidden)]
- pub lint_groups: HashMap<&'static str, Vec<LintId>>,
+ pub lint_groups: FxHashMap<&'static str, (Vec<LintId>, Option<&'static str>)>,
#[doc(hidden)]
pub llvm_passes: Vec<String>,
syntax_exts: vec![],
early_lint_passes: vec![],
late_lint_passes: vec![],
- lint_groups: HashMap::new(),
+ lint_groups: FxHashMap::default(),
llvm_passes: vec![],
attributes: vec![],
whitelisted_custom_derives: Vec::new(),
self.late_lint_passes.push(lint_pass);
}
/// Register a lint group.
- pub fn register_lint_group(&mut self, name: &'static str, to: Vec<&'static Lint>) {
- self.lint_groups.insert(name, to.into_iter().map(|x| LintId::of(x)).collect());
+ pub fn register_lint_group(
+ &mut self,
+ name: &'static str,
+ deprecated_name: Option<&'static str>,
+ to: Vec<&'static Lint>
+ ) {
+ self.lint_groups.insert(name,
+ (to.into_iter().map(|x| LintId::of(x)).collect(),
+ deprecated_name));
}
/// Register an LLVM pass.
// visibility to within the crate.
let struct_def_id = self.tcx.hir.get_parent_did(node_id);
let adt_def = self.tcx.adt_def(struct_def_id);
- if adt_def.is_non_exhaustive() && ctor_vis == ty::Visibility::Public {
+ if adt_def.non_enum_variant().is_field_list_non_exhaustive()
+ && ctor_vis == ty::Visibility::Public
+ {
ctor_vis = ty::Visibility::Restricted(
DefId::local(CRATE_DEF_INDEX));
}
self.session.features_untracked().uniform_paths);
let source = module_path[0];
+
+ // HACK(eddyb) For `use x::{self, ...};`, use the ID of the
+ // `self` nested import for the canary. This allows the
+ // ambiguity reporting scope to ignore false positives
+ // in the same way it does for `use x;` (by comparing IDs).
+ let mut canary_id = id;
+ if let ast::UseTreeKind::Nested(ref items) = use_tree.kind {
+ for &(ref use_tree, id) in items {
+ if let ast::UseTreeKind::Simple(..) = use_tree.kind {
+ if use_tree.ident().name == keywords::SelfValue.name() {
+ canary_id = id;
+ break;
+ }
+ }
+ }
+ }
+
// Helper closure to emit a canary with the given base path.
let emit = |this: &mut Self, base: Option<Ident>| {
let subclass = SingleImport {
base.into_iter().collect(),
subclass.clone(),
source.span,
- id,
+ canary_id,
root_use_tree.span,
root_id,
ty::Visibility::Invisible,
use syntax::ptr::P;
use syntax_pos::{Span, DUMMY_SP, MultiSpan};
-use errors::{DiagnosticBuilder, DiagnosticId};
+use errors::{Applicability, DiagnosticBuilder, DiagnosticId};
use std::cell::{Cell, RefCell};
use std::cmp;
let sugg_msg = "try using a local type parameter instead";
if let Some((sugg_span, new_snippet)) = cm.generate_local_type_param_snippet(span) {
// Suggest the modification to the user
- err.span_suggestion(sugg_span,
- sugg_msg,
- new_snippet);
+ err.span_suggestion_with_applicability(
+ sugg_span,
+ sugg_msg,
+ new_snippet,
+ Applicability::MachineApplicable,
+ );
} else if let Some(sp) = cm.generate_fn_name_span(span) {
err.span_label(sp, "try adding a local type parameter in this method instead");
} else {
crate_loader: &'a mut CrateLoader<'b>,
macro_names: FxHashSet<Ident>,
macro_prelude: FxHashMap<Name, &'a NameBinding<'a>>,
+ unshadowable_attrs: FxHashMap<Name, &'a NameBinding<'a>>,
pub all_macros: FxHashMap<Name, Def>,
macro_map: FxHashMap<DefId, Lrc<SyntaxExtension>>,
macro_defs: FxHashMap<Mark, DefId>,
crate_loader,
macro_names: FxHashSet(),
macro_prelude: FxHashMap(),
+ unshadowable_attrs: FxHashMap(),
all_macros: FxHashMap(),
macro_map: FxHashMap(),
invocations,
// This has to happen *after* we determine which pat_idents are variants
self.check_consistent_bindings(&arm.pats);
- walk_list!(self, visit_expr, &arm.guard);
+ match arm.guard {
+ Some(ast::Guard::If(ref expr)) => self.visit_expr(expr),
+ _ => {}
+ }
self.visit_expr(&arm.body);
self.ribs[ValueNS].pop();
enum_path);
err.help(&msg);
} else {
- err.span_suggestion(span, "you can try using the variant's enum",
- enum_path);
+ err.span_suggestion_with_applicability(
+ span,
+ "you can try using the variant's enum",
+ enum_path,
+ Applicability::MachineApplicable,
+ );
}
}
}
let self_is_available = this.self_value_is_available(path[0].span, span);
match candidate {
AssocSuggestion::Field => {
- err.span_suggestion(span, "try",
- format!("self.{}", path_str));
+ err.span_suggestion_with_applicability(
+ span,
+ "try",
+ format!("self.{}", path_str),
+ Applicability::MachineApplicable,
+ );
if !self_is_available {
err.span_label(span, format!("`self` value is only available in \
methods with `self` parameter"));
}
}
AssocSuggestion::MethodWithSelf if self_is_available => {
- err.span_suggestion(span, "try",
- format!("self.{}", path_str));
+ err.span_suggestion_with_applicability(
+ span,
+ "try",
+ format!("self.{}", path_str),
+ Applicability::MachineApplicable,
+ );
}
AssocSuggestion::MethodWithSelf | AssocSuggestion::AssocItem => {
- err.span_suggestion(span, "try",
- format!("Self::{}", path_str));
+ err.span_suggestion_with_applicability(
+ span,
+ "try",
+ format!("Self::{}", path_str),
+ Applicability::MachineApplicable,
+ );
}
}
return (err, candidates);
format!("other_{}", name)
};
- err.span_suggestion(binding.span,
- rename_msg,
- if snippet.ends_with(';') {
- format!("{} as {};",
- &snippet[..snippet.len()-1],
- suggested_name)
- } else {
- format!("{} as {}", snippet, suggested_name)
- });
+ err.span_suggestion_with_applicability(
+ binding.span,
+ rename_msg,
+ if snippet.ends_with(';') {
+ format!("{} as {};", &snippet[..snippet.len() - 1], suggested_name)
+ } else {
+ format!("{} as {}", snippet, suggested_name)
+ },
+ Applicability::MachineApplicable,
+ );
} else {
err.span_label(binding.span, rename_msg);
}
self.macro_prelude.insert(ident.name, binding);
}
+ fn add_unshadowable_attr(&mut self, ident: ast::Ident, ext: Lrc<SyntaxExtension>) {
+ let def_id = DefId {
+ krate: BUILTIN_MACROS_CRATE,
+ index: DefIndex::from_array_index(self.macro_map.len(),
+ DefIndexAddressSpace::Low),
+ };
+ let kind = ext.kind();
+ self.macro_map.insert(def_id, ext);
+ let binding = self.arenas.alloc_name_binding(NameBinding {
+ kind: NameBindingKind::Def(Def::Macro(def_id, kind), false),
+ span: DUMMY_SP,
+ vis: ty::Visibility::Invisible,
+ expansion: Mark::root(),
+ });
+ self.unshadowable_attrs.insert(ident.name, binding);
+ }
+
fn resolve_imports(&mut self) {
ImportResolver { resolver: self }.resolve_imports()
}
return def;
}
+ if kind == MacroKind::Attr {
+ if let Some(ext) = self.unshadowable_attrs.get(&path[0].name) {
+ return Ok(ext.def());
+ }
+ }
+
let legacy_resolution = self.resolve_legacy_scope(&invocation.legacy_scope, path[0], false);
let result = if let Some((legacy_binding, _)) = legacy_resolution {
Ok(legacy_binding.def())
self.per_ns(|_, ns| {
if let Some(result) = result[ns].get().ok() {
+ if let NameBindingKind::Import { directive, .. } = result.kind {
+ // Skip canaries that resolve to the import itself.
+ // These come from `use crate_name;`, which isn't really
+ // ambiguous, as the import can't actually shadow itself.
+ if directive.id == import.id {
+ return;
+ }
+ }
if has_explicit_self {
// There should only be one `self::x` (module-scoped) canary.
assert_eq!(canary_results[ns].module_scope, None);
errors = true;
- // Special-case the error when `self::x` finds its own `use x;`.
- if has_external_crate &&
- results.module_scope == Some(span) &&
- results.block_scopes.is_empty() {
- let msg = format!("`{}` import is redundant", name);
- this.session.struct_span_err(span, &msg)
- .span_label(span,
- format!("refers to external crate `::{}`", name))
- .span_label(span,
- format!("defines `self::{}`, shadowing itself", name))
- .help(&format!("remove or write `::{}` explicitly instead", name))
- .note("relative `use` paths enabled by `#![feature(uniform_paths)]`")
- .emit();
- return;
- }
-
let msg = format!("`{}` import is ambiguous", name);
let mut err = this.session.struct_span_err(span, &msg);
let mut suggestion_choices = String::new();
// of macro use (callsite) spans. We store these to ensure
// we only write one macro def per unique macro definition, and
// one macro use per unique callsite span.
- // mac_defs: HashSet<Span>,
+ // mac_defs: FxHashSet<Span>,
macro_calls: FxHashSet<Span>,
}
dumper,
span: span_utils.clone(),
cur_scope: CRATE_NODE_ID,
- // mac_defs: HashSet::new(),
+ // mac_defs: FxHashSet::default(),
macro_calls: FxHashSet(),
}
}
let crate_root = source_file.map(|source_file| {
let source_file = Path::new(source_file);
match source_file.file_name() {
- Some(_) => source_file.parent().unwrap().display().to_string(),
- None => source_file.display().to_string(),
- }
+ Some(_) => source_file.parent().unwrap().display(),
+ None => source_file.display(),
+ }.to_string()
});
let data = CratePreludeData {
let segments = &path.segments[if path.is_global() { 1 } else { 0 }..];
let mut result = Vec::with_capacity(segments.len());
+ let mut segs = Vec::with_capacity(segments.len());
- let mut segs = vec![];
for (i, seg) in segments.iter().enumerate() {
segs.push(seg.clone());
let sub_path = ast::Path {
for variant in &enum_definition.variants {
let name = variant.node.ident.name.to_string();
- let mut qualname = enum_data.qualname.clone();
- qualname.push_str("::");
- qualname.push_str(&name);
+ let qualname = format!("{}::{}", enum_data.qualname, name);
match variant.node.data {
ast::VariantData::Struct(ref fields, _) => {
match self.save_ctxt.get_path_def(id) {
HirDef::Local(id) => {
let mut value = if immut == ast::Mutability::Immutable {
- self.span.snippet(ident.span).to_string()
+ self.span.snippet(ident.span)
} else {
- "<mutable>".to_string()
+ "<mutable>".to_owned()
};
let hir_id = self.tcx.hir.node_to_hir_id(id);
let typ = self.save_ctxt
/// mac_uses and mac_defs sets to prevent multiples.
fn process_macro_use(&mut self, span: Span) {
let source_span = span.source_callsite();
- if self.macro_calls.contains(&source_span) {
+ if !self.macro_calls.insert(source_span) {
return;
}
- self.macro_calls.insert(source_span);
let data = match self.save_ctxt.get_macro_use_data(span) {
None => return,
}
}
}
+
+ fn process_bounds(&mut self, bounds: &'l ast::GenericBounds) {
+ for bound in bounds {
+ if let ast::GenericBound::Trait(ref trait_ref, _) = *bound {
+ self.process_path(trait_ref.trait_ref.ref_id, &trait_ref.trait_ref.path)
+ }
+ }
+ }
}
impl<'l, 'tcx: 'l, 'll, O: DumpOutput + 'll> Visitor<'l> for DumpVisitor<'l, 'tcx, 'll, O> {
fn visit_generics(&mut self, generics: &'l ast::Generics) {
for param in &generics.params {
- match param.kind {
- ast::GenericParamKind::Lifetime { .. } => {}
- ast::GenericParamKind::Type { ref default, .. } => {
- for bound in ¶m.bounds {
- if let ast::GenericBound::Trait(ref trait_ref, _) = *bound {
- self.process_path(trait_ref.trait_ref.ref_id, &trait_ref.trait_ref.path)
- }
- }
- if let Some(ref ty) = default {
- self.visit_ty(&ty);
- }
+ if let ast::GenericParamKind::Type { ref default, .. } = param.kind {
+ self.process_bounds(¶m.bounds);
+ if let Some(ref ty) = default {
+ self.visit_ty(&ty);
}
}
}
+ for pred in &generics.where_clause.predicates {
+ if let ast::WherePredicate::BoundPredicate(ref wbp) = *pred {
+ self.process_bounds(&wbp.bounds);
+ self.visit_ty(&wbp.bounded_ty);
+ }
+ }
}
fn visit_ty(&mut self, t: &'l ast::Ty) {
}
}
ast::ExprKind::Closure(_, _, _, ref decl, ref body, _fn_decl_span) => {
- let mut id = String::from("$");
- id.push_str(&ex.id.to_string());
+ let id = format!("${}", ex.id);
// walk arg and return types
for arg in &decl.inputs {
fn visit_arm(&mut self, arm: &'l ast::Arm) {
self.process_var_decl_multi(&arm.pats);
- walk_list!(self, visit_expr, &arm.guard);
+ match arm.guard {
+ Some(ast::Guard::If(ref expr)) => self.visit_expr(expr),
+ _ => {}
+ }
self.visit_expr(&arm.body);
}
let end = cm.lookup_char_pos(span.hi());
SpanData {
- file_name: start.file.name.clone().to_string().into(),
+ file_name: start.file.name.to_string().into(),
byte_start: span.lo().0,
byte_end: span.hi().0,
line_start: Row::new_one_indexed(start.line as u32),
// List external crates used by the current crate.
pub fn get_external_crates(&self) -> Vec<ExternalCrateData> {
- let mut result = Vec::new();
+ let mut result = Vec::with_capacity(self.tcx.crates().len());
for &n in self.tcx.crates().iter() {
let span = match *self.tcx.extern_crate(n.as_def_id()) {
filter!(self.span_utils, sub_span, item.span, None);
Some(Data::DefData(Def {
- kind: DefKind::Function,
+ kind: DefKind::ForeignFunction,
id: id_from_node_id(item.id, self),
span: self.span_from_span(sub_span.unwrap()),
name: item.ident.to_string(),
let span = self.span_from_span(sub_span.unwrap());
Some(Data::DefData(Def {
- kind: DefKind::Static,
+ kind: DefKind::ForeignStatic,
id,
span,
name: item.ident.to_string(),
decl_id: None,
docs: self.docs_for_attrs(&item.attrs),
sig: sig::item_signature(item, self),
- attributes: lower_attributes(item.attrs.to_owned(), self),
+ attributes: lower_attributes(item.attrs.clone(), self),
}))
}
ast::ItemKind::Impl(.., ref trait_ref, ref typ, ref impls) => {
},
];
text.push_str(&name);
- // Could be either `mod foo;` or `mod foo { ... }`, but we'll just puck one.
+ // Could be either `mod foo;` or `mod foo { ... }`, but we'll just pick one.
text.push(';');
Ok(Signature {
let mut text = "<".to_owned();
- let mut defs = vec![];
+ let mut defs = Vec::with_capacity(self.params.len());
for param in &self.params {
let mut param_text = param.ident.to_string();
defs.push(SigElement {
let loc = self.sess.source_map().lookup_char_pos(span.lo());
span_bug!(
span,
- "Mis-counted brackets when breaking path? Parsing '{}' \
- in {}, line {}",
+ "Mis-counted brackets when breaking path? Parsing '{}' in {}, line {}",
self.snippet(span),
loc.file.name,
loc.line
/// such as references to macro internal variables.
pub fn filter_generated(&self, sub_span: Option<Span>, parent: Span) -> bool {
if !generated_code(parent) {
- if sub_span.is_none() {
- // Edge case - this occurs on generated code with incorrect expansion info.
- return true;
- }
- return false;
+ // Edge case - this occurs on generated code with incorrect expansion info.
+ return sub_span.is_none()
}
// If sub_span is none, filter out generated code.
let sub_span = match sub_span {
html_root_url = "https://doc.rust-lang.org/nightly/")]
#![feature(box_syntax)]
-#![feature(const_fn)]
+#![cfg_attr(stage0, feature(const_fn))]
+#![cfg_attr(not(stage0), feature(min_const_fn))]
#![cfg_attr(not(stage0), feature(nll))]
#![cfg_attr(not(stage0), feature(infer_outlives_requirements))]
#![feature(slice_patterns)]
mod l4re_base;
mod fuchsia_base;
mod redox_base;
+mod riscv_base;
#[derive(Clone, Copy, Debug, Eq, Ord, PartialEq, PartialOrd, Hash,
RustcEncodable, RustcDecodable)]
("aarch64-unknown-hermit", aarch64_unknown_hermit),
("x86_64-unknown-hermit", x86_64_unknown_hermit),
+ ("riscv32imc-unknown-none-elf", riscv32imc_unknown_none_elf),
("riscv32imac-unknown-none-elf", riscv32imac_unknown_none_elf),
("aarch64-unknown-none", aarch64_unknown_none),
// option. This file may not be copied, modified, or distributed
// except according to those terms.
-use spec::{LinkerFlavor, PanicStrategy, Target, TargetOptions, TargetResult};
-use spec::abi::{Abi};
+use spec::{LinkerFlavor, LldFlavor, PanicStrategy,
+ Target, TargetOptions, TargetResult};
pub fn target() -> TargetResult {
Ok(Target {
target_env: String::new(),
target_vendor: "unknown".to_string(),
arch: "riscv32".to_string(),
- linker_flavor: LinkerFlavor::Ld,
+ linker_flavor: LinkerFlavor::Lld(LldFlavor::Ld),
options: TargetOptions {
- linker: Some("riscv32-unknown-elf-ld".to_string()),
+ linker: Some("rust-lld".to_string()),
cpu: "generic-rv32".to_string(),
max_atomic_width: Some(32),
atomic_cas: false, // incomplete +a extension
- features: "+m,+a".to_string(), // disable +c extension
+ features: "+m,+a,+c".to_string(),
executables: true,
panic_strategy: PanicStrategy::Abort,
relocation_model: "static".to_string(),
emit_debug_gdb_scripts: false,
- abi_blacklist: vec![
- Abi::Cdecl,
- Abi::Stdcall,
- Abi::Fastcall,
- Abi::Vectorcall,
- Abi::Thiscall,
- Abi::Aapcs,
- Abi::Win64,
- Abi::SysV64,
- Abi::PtxKernel,
- Abi::Msp430Interrupt,
- Abi::X86Interrupt,
- ],
+ abi_blacklist: super::riscv_base::abi_blacklist(),
.. Default::default()
},
})
--- /dev/null
+// Copyright 2018 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+use spec::{LinkerFlavor, LldFlavor, PanicStrategy,
+ Target, TargetOptions, TargetResult};
+
+pub fn target() -> TargetResult {
+ Ok(Target {
+ data_layout: "e-m:e-p:32:32-i64:64-n32-S128".to_string(),
+ llvm_target: "riscv32".to_string(),
+ target_endian: "little".to_string(),
+ target_pointer_width: "32".to_string(),
+ target_c_int_width: "32".to_string(),
+ target_os: "none".to_string(),
+ target_env: String::new(),
+ target_vendor: "unknown".to_string(),
+ arch: "riscv32".to_string(),
+ linker_flavor: LinkerFlavor::Lld(LldFlavor::Ld),
+
+ options: TargetOptions {
+ linker: Some("rust-lld".to_string()),
+ cpu: "generic-rv32".to_string(),
+ // https://gcc.gnu.org/bugzilla/show_bug.cgi?id=86005
+ max_atomic_width: None, //Some(32),
+ atomic_cas: false,
+ features: "+m,+c".to_string(),
+ executables: true,
+ panic_strategy: PanicStrategy::Abort,
+ relocation_model: "static".to_string(),
+ emit_debug_gdb_scripts: false,
+ abi_blacklist: super::riscv_base::abi_blacklist(),
+ .. Default::default()
+ },
+ })
+}
--- /dev/null
+// Copyright 2018 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+use spec::abi::Abi;
+
+// All the calling conventions trigger an assertion(Unsupported calling
+// convention) in llvm on RISCV
+pub fn abi_blacklist() -> Vec<Abi> {
+ vec![
+ Abi::Cdecl,
+ Abi::Stdcall,
+ Abi::Fastcall,
+ Abi::Vectorcall,
+ Abi::Thiscall,
+ Abi::Aapcs,
+ Abi::Win64,
+ Abi::SysV64,
+ Abi::PtxKernel,
+ Abi::Msp430Interrupt,
+ Abi::X86Interrupt,
+ Abi::AmdGpuKernel,
+ ]
+}
dll_suffix: ".wasm".to_string(),
linker_is_gnu: false,
- // A bit of a lie, but "eh"
- max_atomic_width: Some(32),
+ max_atomic_width: Some(64),
// Unwinding doesn't work right now, so the whole target unconditionally
// defaults to panic=abort. Note that this is guaranteed to change in
};
for (i, (arm, pats_diverge)) in arms.iter().zip(all_arm_pats_diverge).enumerate() {
- if let Some(ref e) = arm.guard {
+ if let Some(ref g) = arm.guard {
self.diverges.set(pats_diverge);
- self.check_expr_has_type_or_error(e, tcx.types.bool);
+ match g {
+ hir::Guard::If(e) => self.check_expr_has_type_or_error(e, tcx.types.bool),
+ };
}
self.diverges.set(pats_diverge);
}
// Require `..` if struct has non_exhaustive attribute.
- if adt.is_struct() && adt.is_non_exhaustive() && !adt.did.is_local() && !etc {
+ if variant.is_field_list_non_exhaustive() && !adt.did.is_local() && !etc {
span_err!(tcx.sess, span, E0638,
"`..` required with {} marked as non-exhaustive",
kind_name);
if !self.infcx.type_moves_by_default(self.param_env,
checked,
sp) {
- let sp = cm.call_span_if_macro(sp);
- if let Ok(code) = cm.span_to_snippet(sp) {
- return Some((sp,
- "consider dereferencing the borrow",
- format!("*{}", code)));
+ // do not suggest if the span comes from a macro (#52783)
+ if let (Ok(code),
+ true) = (cm.span_to_snippet(sp), sp == expr.span) {
+ return Some((
+ sp,
+ "consider dereferencing the borrow",
+ format!("*{}", code),
+ ));
}
}
}
use std::iter;
-fn equate_intrinsic_type<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
- it: &hir::ForeignItem,
- n_tps: usize,
- abi: Abi,
- inputs: Vec<Ty<'tcx>>,
- output: Ty<'tcx>) {
+fn equate_intrinsic_type<'a, 'tcx>(
+ tcx: TyCtxt<'a, 'tcx, 'tcx>,
+ it: &hir::ForeignItem,
+ n_tps: usize,
+ abi: Abi,
+ safety: hir::Unsafety,
+ inputs: Vec<Ty<'tcx>>,
+ output: Ty<'tcx>,
+) {
let def_id = tcx.hir.local_def_id(it.id);
match it.node {
inputs.into_iter(),
output,
false,
- hir::Unsafety::Unsafe,
+ safety,
abi
)));
let cause = ObligationCause::new(it.span, it.id, ObligationCauseCode::IntrinsicType);
it: &hir::ForeignItem) {
let param = |n| tcx.mk_ty_param(n, Symbol::intern(&format!("P{}", n)).as_interned_str());
let name = it.name.as_str();
- let (n_tps, inputs, output) = if name.starts_with("atomic_") {
+ let (n_tps, inputs, output, unsafety) = if name.starts_with("atomic_") {
let split : Vec<&str> = name.split('_').collect();
assert!(split.len() >= 2, "Atomic intrinsic not correct format");
return;
}
};
- (n_tps, inputs, output)
+ (n_tps, inputs, output, hir::Unsafety::Unsafe)
} else if &name[..] == "abort" || &name[..] == "unreachable" {
- (0, Vec::new(), tcx.types.never)
+ (0, Vec::new(), tcx.types.never, hir::Unsafety::Unsafe)
} else {
+ let unsafety = match &name[..] {
+ "size_of" | "min_align_of" => hir::Unsafety::Normal,
+ _ => hir::Unsafety::Unsafe,
+ };
let (n_tps, inputs, output) = match &name[..] {
"breakpoint" => (0, Vec::new(), tcx.mk_nil()),
"size_of" |
return;
}
};
- (n_tps, inputs, output)
+ (n_tps, inputs, output, unsafety)
};
- equate_intrinsic_type(tcx, it, n_tps, Abi::RustIntrinsic, inputs, output)
+ equate_intrinsic_type(tcx, it, n_tps, Abi::RustIntrinsic, unsafety, inputs, output)
}
/// Type-check `extern "platform-intrinsic" { ... }` functions.
}
};
- equate_intrinsic_type(tcx, it, n_tps, Abi::PlatformIntrinsic,
+ equate_intrinsic_type(tcx, it, n_tps, Abi::PlatformIntrinsic, hir::Unsafety::Unsafe,
inputs, output)
}
use rustc::infer::anon_types::AnonTypeDecl;
use rustc::infer::type_variable::{TypeVariableOrigin};
use rustc::middle::region;
-use rustc::mir::interpret::{GlobalId};
+use rustc::mir::interpret::{ConstValue, GlobalId};
use rustc::ty::subst::{CanonicalSubsts, UnpackedKind, Subst, Substs};
use rustc::traits::{self, ObligationCause, ObligationCauseCode, TraitEngine};
use rustc::ty::{self, Ty, TyCtxt, GenericParamDefKind, Visibility, ToPredicate, RegionKind};
}
}
} else {
+ let span = fcx.tcx.sess.source_map().def_span(span);
fcx.tcx.sess.span_err(span, "function should have one argument");
}
} else {
}
}
} else {
+ let span = fcx.tcx.sess.source_map().def_span(span);
fcx.tcx.sess.span_err(span, "function should have one argument");
}
} else {
};
let param_env = ty::ParamEnv::reveal_all();
if let Ok(static_) = tcx.const_eval(param_env.and(cid)) {
- let alloc = tcx.const_to_allocation(static_);
+ let alloc = if let ConstValue::ByRef(_, allocation, _) = static_.val {
+ allocation
+ } else {
+ bug!("Matching on non-ByRef static")
+ };
if alloc.relocations.len() != 0 {
let msg = "statics with a custom `#[link_section]` must be a \
simple list of bytes on the wasm target with no \
// re-link the regions that EIfEO can erase.
self.demand_eqtype(span, adt_ty_hint, adt_ty);
- let (substs, adt_kind, kind_name) = match &adt_ty.sty{
+ let (substs, adt_kind, kind_name) = match &adt_ty.sty {
&ty::Adt(adt, substs) => {
(substs, adt.adt_kind(), adt.variant_descr())
}
base_expr: &'gcx Option<P<hir::Expr>>) -> Ty<'tcx>
{
// Find the relevant variant
- let (variant, struct_ty) =
- if let Some(variant_ty) = self.check_struct_path(qpath, expr.id) {
- variant_ty
- } else {
- self.check_struct_fields_on_error(fields, base_expr);
- return self.tcx.types.err;
- };
+ let (variant, adt_ty) =
+ if let Some(variant_ty) = self.check_struct_path(qpath, expr.id) {
+ variant_ty
+ } else {
+ self.check_struct_fields_on_error(fields, base_expr);
+ return self.tcx.types.err;
+ };
let path_span = match *qpath {
hir::QPath::Resolved(_, ref path) => path.span,
};
// Prohibit struct expressions when non exhaustive flag is set.
- if let ty::Adt(adt, _) = struct_ty.sty {
- if !adt.did.is_local() && adt.is_non_exhaustive() {
- span_err!(self.tcx.sess, expr.span, E0639,
- "cannot create non-exhaustive {} using struct expression",
- adt.variant_descr());
- }
+ let adt = adt_ty.ty_adt_def().expect("`check_struct_path` returned non-ADT type");
+ if !adt.did.is_local() && variant.is_field_list_non_exhaustive() {
+ span_err!(self.tcx.sess, expr.span, E0639,
+ "cannot create non-exhaustive {} using struct expression",
+ adt.variant_descr());
}
- let error_happened = self.check_expr_struct_fields(struct_ty, expected, expr.id, path_span,
+ let error_happened = self.check_expr_struct_fields(adt_ty, expected, expr.id, path_span,
variant, fields, base_expr.is_none());
if let &Some(ref base_expr) = base_expr {
// If check_expr_struct_fields hit an error, do not attempt to populate
// the fields with the base_expr. This could cause us to hit errors later
// when certain fields are assumed to exist that in fact do not.
if !error_happened {
- self.check_expr_has_type_or_error(base_expr, struct_ty);
- match struct_ty.sty {
+ self.check_expr_has_type_or_error(base_expr, adt_ty);
+ match adt_ty.sty {
ty::Adt(adt, substs) if adt.is_struct() => {
let fru_field_types = adt.non_enum_variant().fields.iter().map(|f| {
self.normalize_associated_types_in(expr.span, &f.ty(self.tcx, substs))
}
}
}
- self.require_type_is_sized(struct_ty, expr.span, traits::StructInitializerSized);
- struct_ty
+ self.require_type_is_sized(adt_ty, expr.span, traits::StructInitializerSized);
+ adt_ty
}
let source_map = self.tcx.sess.source_map();
match is_assign {
IsAssign::Yes => {
- let mut err = struct_span_err!(self.tcx.sess, expr.span, E0368,
- "binary assignment operation `{}=` \
- cannot be applied to type `{}`",
- op.node.as_str(),
- lhs_ty);
- err.span_label(lhs_expr.span,
- format!("cannot use `{}=` on type `{}`",
- op.node.as_str(), lhs_ty));
+ let mut err = struct_span_err!(
+ self.tcx.sess,
+ expr.span,
+ E0368,
+ "binary assignment operation `{}=` cannot be applied to type `{}`",
+ op.node.as_str(),
+ lhs_ty,
+ );
+ err.span_label(
+ lhs_expr.span,
+ format!("cannot use `{}=` on type `{}`",
+ op.node.as_str(), lhs_ty),
+ );
let mut suggested_deref = false;
if let Ref(_, mut rty, _) = lhs_ty.sty {
if {
rty = rty_inner;
}
let msg = &format!(
- "`{}=` can be used on '{}', you can \
- dereference `{2}`: `*{2}`",
- op.node.as_str(),
- rty,
- lstring
+ "`{}=` can be used on '{}', you can dereference `{}`",
+ op.node.as_str(),
+ rty,
+ lstring,
+ );
+ err.span_suggestion_with_applicability(
+ lhs_expr.span,
+ msg,
+ format!("*{}", lstring),
+ errors::Applicability::MachineApplicable,
);
- err.help(msg);
suggested_deref = true;
}
}
}
}
-fn convert_struct_variant<'a, 'tcx>(
+fn convert_variant<'a, 'tcx>(
tcx: TyCtxt<'a, 'tcx, 'tcx>,
did: DefId,
name: ast::Name,
discr: ty::VariantDiscr,
def: &hir::VariantData,
+ adt_kind: ty::AdtKind
) -> ty::VariantDef {
let mut seen_fields: FxHashMap<ast::Ident, Span> = FxHashMap();
let node_id = tcx.hir.as_local_node_id(did).unwrap();
}
})
.collect();
- ty::VariantDef {
+ ty::VariantDef::new(tcx,
did,
name,
discr,
fields,
- ctor_kind: CtorKind::from_hir(def),
- }
+ adt_kind,
+ CtorKind::from_hir(def))
}
fn adt_def<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, def_id: DefId) -> &'tcx ty::AdtDef {
};
distance_from_explicit += 1;
- convert_struct_variant(tcx, did, v.node.name, discr, &v.node.data)
+ convert_variant(tcx, did, v.node.name, discr, &v.node.data, AdtKind::Enum)
})
.collect(),
)
};
(
AdtKind::Struct,
- vec![convert_struct_variant(
+ vec![convert_variant(
tcx,
ctor_id.unwrap_or(def_id),
item.name,
ty::VariantDiscr::Relative(0),
def,
+ AdtKind::Struct
)],
)
}
ItemKind::Union(ref def, _) => (
AdtKind::Union,
- vec![convert_struct_variant(
+ vec![convert_variant(
tcx,
def_id,
item.name,
ty::VariantDiscr::Relative(0),
def,
+ AdtKind::Union
)],
),
_ => bug!(),
&hir::WherePredicate::BoundPredicate(ref bound_pred) => {
let ty = icx.to_ty(&bound_pred.bounded_ty);
+ // Keep the type around in a WF predicate, in case of no bounds.
+ // That way, `where Ty:` is not a complete noop (see #53696).
+ if bound_pred.bounds.is_empty() {
+ if let ty::Param(_) = ty.sty {
+ // This is a `where T:`, which can be in the HIR from the
+ // transformation that moves `?Sized` to `T`'s declaration.
+ // We can skip the predicate because type parameters are
+ // trivially WF, but also we *should*, to avoid exposing
+ // users who never wrote `where Type:,` themselves, to
+ // compiler/tooling bugs from not handling WF predicates.
+ } else {
+ predicates.push(ty::Predicate::WellFormed(ty));
+ }
+ }
+
for bound in bound_pred.bounds.iter() {
match bound {
&hir::GenericBound::Trait(ref poly_trait_ref, _) => {
decl: &hir::FnDecl,
abi: abi::Abi,
) -> ty::PolyFnSig<'tcx> {
- let fty = AstConv::ty_of_fn(
- &ItemCtxt::new(tcx, def_id),
- hir::Unsafety::Unsafe,
- abi,
- decl,
- );
+ let unsafety = if abi == abi::Abi::RustIntrinsic {
+ match &*tcx.item_name(def_id).as_str() {
+ "size_of" | "min_align_of" => hir::Unsafety::Normal,
+ _ => hir::Unsafety::Unsafe,
+ }
+ } else {
+ hir::Unsafety::Unsafe
+ };
+ let fty = AstConv::ty_of_fn(&ItemCtxt::new(tcx, def_id), unsafety, abi, decl);
// feature gate SIMD types in FFI, since I (huonw) am not sure the
// ABIs are handled at all correctly.
use rustc::session::Session;
use syntax_pos::Span;
-use errors::{DiagnosticId, DiagnosticBuilder};
+use errors::{Applicability, DiagnosticId, DiagnosticBuilder};
use rustc::ty::{Ty, TypeFoldable};
pub trait StructuredDiagnostic<'tcx> {
)
};
if let Ok(snippet) = self.sess.source_map().span_to_snippet(self.span) {
- err.span_suggestion(self.span,
- &format!("cast the value to `{}`", self.cast_ty),
- format!("{} as {}", snippet, self.cast_ty));
+ err.span_suggestion_with_applicability(
+ self.span,
+ &format!("cast the value to `{}`", self.cast_ty),
+ format!("{} as {}", snippet, self.cast_ty),
+ Applicability::MachineApplicable,
+ );
} else {
err.help(&format!("cast the value to `{}`", self.cast_ty));
}
Predicate::RegionOutlives(ref pred) => pred.clean(cx),
Predicate::TypeOutlives(ref pred) => pred.clean(cx),
Predicate::Projection(ref pred) => pred.clean(cx),
- Predicate::WellFormed(_) => panic!("not user writable"),
+ Predicate::WellFormed(ty) => {
+ // This comes from `where Ty:` (i.e. no bounds) (see #53696).
+ WherePredicate::BoundPredicate {
+ ty: ty.clean(cx),
+ bounds: vec![],
+ }
+ }
Predicate::ObjectSafe(_) => panic!("not user writable"),
Predicate::ClosureKind(..) => panic!("not user writable"),
Predicate::ConstEvaluatable(..) => panic!("not user writable"),
#![allow(non_camel_case_types)]
+use rustc_data_structures::fx::FxHashMap;
use std::cell::RefCell;
-use std::collections::{HashMap, VecDeque};
+use std::collections::VecDeque;
use std::default::Default;
use std::fmt::{self, Write};
use std::borrow::Cow;
/// references.
struct Footnotes<'a, I: Iterator<Item = Event<'a>>> {
inner: I,
- footnotes: HashMap<String, (Vec<Event<'a>>, u16)>,
+ footnotes: FxHashMap<String, (Vec<Event<'a>>, u16)>,
}
impl<'a, I: Iterator<Item = Event<'a>>> Footnotes<'a, I> {
fn new(iter: I) -> Self {
Footnotes {
inner: iter,
- footnotes: HashMap::new(),
+ footnotes: FxHashMap::default(),
}
}
fn get_entry(&mut self, key: &str) -> &mut (Vec<Event<'a>>, u16) {
#[derive(Default)]
pub struct IdMap {
- map: HashMap<String, usize>,
+ map: FxHashMap<String, usize>,
}
impl IdMap {
}
pub fn reset(&mut self) {
- self.map = HashMap::new();
+ self.map = FxHashMap::default();
}
pub fn derive(&mut self, candidate: String) -> String {
use std::borrow::Cow;
use std::cell::RefCell;
use std::cmp::Ordering;
-use std::collections::{BTreeMap, HashSet, VecDeque};
+use std::collections::{BTreeMap, VecDeque};
use std::default::Default;
use std::error;
use std::fmt::{self, Display, Formatter, Write as FmtWrite};
/// Generates the documentation for `crate` into the directory `dst`
pub fn run(mut krate: clean::Crate,
+ extern_urls: BTreeMap<String, String>,
external_html: &ExternalHtml,
playground_url: Option<String>,
dst: PathBuf,
},
_ => PathBuf::new(),
};
+ let extern_url = extern_urls.get(&e.name).map(|u| &**u);
cache.extern_locations.insert(n, (e.name.clone(), src_root,
- extern_location(e, &cx.dst)));
+ extern_location(e, extern_url, &cx.dst)));
let did = DefId { krate: n, index: CRATE_DEF_INDEX };
cache.external_paths.insert(did, (vec![e.name.to_string()], ItemType::Module));
// To avoid "light.css" to be overwritten, we'll first run over the received themes and only
// then we'll run over the "official" styles.
- let mut themes: HashSet<String> = HashSet::new();
+ let mut themes: FxHashSet<String> = FxHashSet::default();
for entry in &cx.shared.themes {
let mut content = Vec::with_capacity(100000);
/// Attempts to find where an external crate is located, given that we're
/// rendering in to the specified source destination.
-fn extern_location(e: &clean::ExternalCrate, dst: &Path) -> ExternalLocation {
+fn extern_location(e: &clean::ExternalCrate, extern_url: Option<&str>, dst: &Path)
+ -> ExternalLocation
+{
// See if there's documentation generated into the local directory
let local_location = dst.join(&e.name);
if local_location.is_dir() {
return Local;
}
+ if let Some(url) = extern_url {
+ let mut url = url.to_string();
+ if !url.ends_with("/") {
+ url.push('/');
+ }
+ return Remote(url);
+ }
+
// Failing that, see if there's an attribute specifying where to find this
// external crate
e.attrs.lists("doc")
#[derive(Debug)]
struct AllTypes {
- structs: HashSet<ItemEntry>,
- enums: HashSet<ItemEntry>,
- unions: HashSet<ItemEntry>,
- primitives: HashSet<ItemEntry>,
- traits: HashSet<ItemEntry>,
- macros: HashSet<ItemEntry>,
- functions: HashSet<ItemEntry>,
- typedefs: HashSet<ItemEntry>,
- existentials: HashSet<ItemEntry>,
- statics: HashSet<ItemEntry>,
- constants: HashSet<ItemEntry>,
- keywords: HashSet<ItemEntry>,
+ structs: FxHashSet<ItemEntry>,
+ enums: FxHashSet<ItemEntry>,
+ unions: FxHashSet<ItemEntry>,
+ primitives: FxHashSet<ItemEntry>,
+ traits: FxHashSet<ItemEntry>,
+ macros: FxHashSet<ItemEntry>,
+ functions: FxHashSet<ItemEntry>,
+ typedefs: FxHashSet<ItemEntry>,
+ existentials: FxHashSet<ItemEntry>,
+ statics: FxHashSet<ItemEntry>,
+ constants: FxHashSet<ItemEntry>,
+ keywords: FxHashSet<ItemEntry>,
}
impl AllTypes {
fn new() -> AllTypes {
+ let new_set = |cap| FxHashSet::with_capacity_and_hasher(cap, Default::default());
AllTypes {
- structs: HashSet::with_capacity(100),
- enums: HashSet::with_capacity(100),
- unions: HashSet::with_capacity(100),
- primitives: HashSet::with_capacity(26),
- traits: HashSet::with_capacity(100),
- macros: HashSet::with_capacity(100),
- functions: HashSet::with_capacity(100),
- typedefs: HashSet::with_capacity(100),
- existentials: HashSet::with_capacity(100),
- statics: HashSet::with_capacity(100),
- constants: HashSet::with_capacity(100),
- keywords: HashSet::with_capacity(100),
+ structs: new_set(100),
+ enums: new_set(100),
+ unions: new_set(100),
+ primitives: new_set(26),
+ traits: new_set(100),
+ macros: new_set(100),
+ functions: new_set(100),
+ typedefs: new_set(100),
+ existentials: new_set(100),
+ statics: new_set(100),
+ constants: new_set(100),
+ keywords: new_set(100),
}
}
}
}
-fn print_entries(f: &mut fmt::Formatter, e: &HashSet<ItemEntry>, title: &str,
+fn print_entries(f: &mut fmt::Formatter, e: &FxHashSet<ItemEntry>, title: &str,
class: &str) -> fmt::Result {
if !e.is_empty() {
let mut e: Vec<&ItemEntry> = e.iter().collect();
</h2>
")?;
+ let mut foreign_cache = FxHashSet();
for implementor in foreign {
- let assoc_link = AssocItemLink::GotoSource(
- implementor.impl_item.def_id, &implementor.inner_impl().provided_trait_methods
- );
- render_impl(w, cx, &implementor, assoc_link,
- RenderMode::Normal, implementor.impl_item.stable_since(), false)?;
+ if foreign_cache.insert(implementor.inner_impl().to_string()) {
+ let assoc_link = AssocItemLink::GotoSource(
+ implementor.impl_item.def_id,
+ &implementor.inner_impl().provided_trait_methods
+ );
+ render_impl(w, cx, &implementor, assoc_link,
+ RenderMode::Normal, implementor.impl_item.stable_since(), false)?;
+ }
}
}
}
}
let format_impls = |impls: Vec<&Impl>| {
- let mut links = HashSet::new();
+ let mut links = FxHashSet::default();
impls.iter()
.filter_map(|i| {
let is_negative_impl = is_negative_impl(i.inner_impl());
}
}
+ highlightSourceLines(null);
window.onhashchange = highlightSourceLines;
// Gets the human-readable string for the virtual-key code of the
margin-left: 33px;
margin-top: -13px;
}
+
.content .stability::before {
content: '˪';
font-size: 30px;
top: -9px;
left: -13px;
}
+.methods > .stability {
+ margin-top: -8px;
+}
+
+#main > .stability {
+ margin-top: 0;
+}
nav {
border-bottom: 1px solid;
.search-results td span.grey {
color: #ccc;
}
+
+.impl-items code {
+ background-color: rgba(0, 0, 0, 0);
+}
.search-results td span.grey {
color: #999;
}
+
+.impl-items code {
+ background-color: rgba(0, 0, 0, 0);
+}
stable("extern", |o| {
o.optmulti("", "extern", "pass an --extern to rustc", "NAME=PATH")
}),
+ unstable("extern-html-root-url", |o| {
+ o.optmulti("", "extern-html-root-url",
+ "base URL to use for dependencies", "NAME=URL")
+ }),
stable("plugin-path", |o| {
o.optmulti("", "plugin-path", "removed", "DIR")
}),
return 1;
}
};
+ let extern_urls = match parse_extern_html_roots(&matches) {
+ Ok(ex) => ex,
+ Err(err) => {
+ diag.struct_err(err).emit();
+ return 1;
+ }
+ };
let test_args = matches.opt_strs("test-args");
let test_args: Vec<String> = test_args.iter()
let output = matches.opt_str("o").map(|s| PathBuf::from(&s));
let css_file_extension = matches.opt_str("e").map(|s| PathBuf::from(&s));
- let cfgs = matches.opt_strs("cfg");
+ let mut cfgs = matches.opt_strs("cfg");
+ cfgs.push("rustdoc".to_string());
if let Some(ref p) = css_file_extension {
if !p.is_file() {
info!("going to format");
match output_format.as_ref().map(|s| &**s) {
Some("html") | None => {
- html::render::run(krate, &external_html, playground_url,
+ html::render::run(krate, extern_urls, &external_html, playground_url,
output.unwrap_or(PathBuf::from("doc")),
resource_suffix.unwrap_or(String::new()),
passes.into_iter().collect(),
Ok(Externs::new(externs))
}
+/// Extracts `--extern-html-root-url` arguments from `matches` and returns a map of crate names to
+/// the given URLs. If an `--extern-html-root-url` argument was ill-formed, returns an error
+/// describing the issue.
+fn parse_extern_html_roots(matches: &getopts::Matches)
+ -> Result<BTreeMap<String, String>, &'static str>
+{
+ let mut externs = BTreeMap::new();
+ for arg in &matches.opt_strs("extern-html-root-url") {
+ let mut parts = arg.splitn(2, '=');
+ let name = parts.next().ok_or("--extern-html-root-url must not be empty")?;
+ let url = parts.next().ok_or("--extern-html-root-url must be of the form name=url")?;
+ externs.insert(name.to_string(), url.to_string());
+ }
+
+ Ok(externs)
+}
+
/// Interprets the input file as a rust source file, passing it through the
/// compiler all the way through the analysis passes. The rustdoc output is then
/// generated from the cleaned AST of the crate.
for s in &matches.opt_strs("L") {
paths.add_path(s, ErrorOutputType::default());
}
- let cfgs = matches.opt_strs("cfg");
+ let mut cfgs = matches.opt_strs("cfg");
+ cfgs.push("rustdoc".to_string());
let triple = matches.opt_str("target").map(|target| {
if target.ends_with(".json") {
TargetTriple::TargetPath(PathBuf::from(target))
// option. This file may not be copied, modified, or distributed
// except according to those terms.
-use std::collections::HashSet;
+use rustc_data_structures::fx::FxHashSet;
use std::fs::File;
use std::hash::{Hash, Hasher};
use std::io::Read;
#[derive(Debug, Clone, Eq)]
pub struct CssPath {
pub name: String,
- pub children: HashSet<CssPath>,
+ pub children: FxHashSet<CssPath>,
}
// This PartialEq implementation IS NOT COMMUTATIVE!!!
fn new(name: String) -> CssPath {
CssPath {
name,
- children: HashSet::new(),
+ children: FxHashSet::default(),
}
}
}
.replace("\t", " ")
.replace("{", "")
.replace("}", "")
- .split(" ")
+ .split(' ')
.filter(|s| s.len() > 0)
.collect::<Vec<&str>>()
.join(" ")
}
-fn inner(v: &[u8], events: &[Events], pos: &mut usize) -> HashSet<CssPath> {
+fn inner(v: &[u8], events: &[Events], pos: &mut usize) -> FxHashSet<CssPath> {
let mut paths = Vec::with_capacity(50);
while *pos < events.len() {
unwind = { path = "../libunwind" }
[dev-dependencies]
-rand = "0.4"
+rand = "0.5"
[target.x86_64-apple-darwin.dependencies]
rustc_asan = { path = "../librustc_asan" }
/// }
/// ```
#[stable(feature = "rust1", since = "1.0.0")]
- fn cause(&self) -> Option<&dyn Error> { None }
+ #[rustc_deprecated(since = "1.33.0", reason = "replaced by Error::source, which can support \
+ downcasting")]
+ fn cause(&self) -> Option<&dyn Error> {
+ self.source()
+ }
+
+ /// The lower-level source of this error, if any.
+ ///
+ /// # Examples
+ ///
+ /// ```
+ /// use std::error::Error;
+ /// use std::fmt;
+ ///
+ /// #[derive(Debug)]
+ /// struct SuperError {
+ /// side: SuperErrorSideKick,
+ /// }
+ ///
+ /// impl fmt::Display for SuperError {
+ /// fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
+ /// write!(f, "SuperError is here!")
+ /// }
+ /// }
+ ///
+ /// impl Error for SuperError {
+ /// fn description(&self) -> &str {
+ /// "I'm the superhero of errors"
+ /// }
+ ///
+ /// fn source(&self) -> Option<&(dyn Error + 'static)> {
+ /// Some(&self.side)
+ /// }
+ /// }
+ ///
+ /// #[derive(Debug)]
+ /// struct SuperErrorSideKick;
+ ///
+ /// impl fmt::Display for SuperErrorSideKick {
+ /// fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
+ /// write!(f, "SuperErrorSideKick is here!")
+ /// }
+ /// }
+ ///
+ /// impl Error for SuperErrorSideKick {
+ /// fn description(&self) -> &str {
+ /// "I'm SuperError side kick"
+ /// }
+ /// }
+ ///
+ /// fn get_super_error() -> Result<(), SuperError> {
+ /// Err(SuperError { side: SuperErrorSideKick })
+ /// }
+ ///
+ /// fn main() {
+ /// match get_super_error() {
+ /// Err(e) => {
+ /// println!("Error: {}", e.description());
+ /// println!("Caused by: {}", e.source().unwrap());
+ /// }
+ /// _ => println!("No error"),
+ /// }
+ /// }
+ /// ```
+ #[stable(feature = "error_source", since = "1.30.0")]
+ fn source(&self) -> Option<&(dyn Error + 'static)> { None }
/// Get the `TypeId` of `self`
#[doc(hidden)]
use fs::{self, File, OpenOptions};
use io::{ErrorKind, SeekFrom};
use path::Path;
- use rand::{StdRng, Rng};
+ use rand::{StdRng, FromEntropy, RngCore};
use str;
use sys_common::io::test::{TempDir, tmpdir};
use thread;
#[test]
fn binary_file() {
let mut bytes = [0; 1024];
- StdRng::new().unwrap().fill_bytes(&mut bytes);
+ StdRng::from_entropy().fill_bytes(&mut bytes);
let tmpdir = tmpdir();
#[test]
fn write_then_read() {
let mut bytes = [0; 1024];
- StdRng::new().unwrap().fill_bytes(&mut bytes);
+ StdRng::from_entropy().fill_bytes(&mut bytes);
let tmpdir = tmpdir();
// We never call `lock.init()`, so it is UB to attempt to acquire this mutex reentrantly!
lock: Mutex,
ptr: Cell<*mut Arc<T>>,
- init: fn() -> Arc<T>,
}
#[inline]
unsafe impl<T> Sync for Lazy<T> {}
-impl<T: Send + Sync + 'static> Lazy<T> {
- /// Safety: `init` must not call `get` on the variable that is being
- /// initialized.
- pub const unsafe fn new(init: fn() -> Arc<T>) -> Lazy<T> {
+impl<T> Lazy<T> {
+ pub const fn new() -> Lazy<T> {
Lazy {
lock: Mutex::new(),
ptr: Cell::new(ptr::null_mut()),
- init,
}
}
+}
- pub fn get(&'static self) -> Option<Arc<T>> {
- unsafe {
- let _guard = self.lock.lock();
- let ptr = self.ptr.get();
- if ptr.is_null() {
- Some(self.init())
- } else if ptr == done() {
- None
- } else {
- Some((*ptr).clone())
- }
+impl<T: Send + Sync + 'static> Lazy<T> {
+ /// Safety: `init` must not call `get` on the variable that is being
+ /// initialized.
+ pub unsafe fn get(&'static self, init: fn() -> Arc<T>) -> Option<Arc<T>> {
+ let _guard = self.lock.lock();
+ let ptr = self.ptr.get();
+ if ptr.is_null() {
+ Some(self.init(init))
+ } else if ptr == done() {
+ None
+ } else {
+ Some((*ptr).clone())
}
}
// Must only be called with `lock` held
- unsafe fn init(&'static self) -> Arc<T> {
+ unsafe fn init(&'static self, init: fn() -> Arc<T>) -> Arc<T> {
// If we successfully register an at exit handler, then we cache the
// `Arc` allocation in our own internal box (it will get deallocated by
// the at exit handler). Otherwise we just return the freshly allocated
});
// This could reentrantly call `init` again, which is a problem
// because our `lock` allows reentrancy!
- // That's why `new` is unsafe and requires the caller to ensure no reentrancy happens.
- let ret = (self.init)();
+ // That's why `get` is unsafe and requires the caller to ensure no reentrancy happens.
+ let ret = init();
if registered.is_ok() {
self.ptr.set(Box::into_raw(Box::new(ret.clone())));
}
/// ```
#[stable(feature = "rust1", since = "1.0.0")]
pub fn stdin() -> Stdin {
- static INSTANCE: Lazy<Mutex<BufReader<Maybe<StdinRaw>>>> = unsafe { Lazy::new(stdin_init) };
+ static INSTANCE: Lazy<Mutex<BufReader<Maybe<StdinRaw>>>> = Lazy::new();
return Stdin {
- inner: INSTANCE.get().expect("cannot access stdin during shutdown"),
+ inner: unsafe {
+ INSTANCE.get(stdin_init).expect("cannot access stdin during shutdown")
+ },
};
fn stdin_init() -> Arc<Mutex<BufReader<Maybe<StdinRaw>>>> {
/// ```
#[stable(feature = "rust1", since = "1.0.0")]
pub fn stdout() -> Stdout {
- static INSTANCE: Lazy<ReentrantMutex<RefCell<LineWriter<Maybe<StdoutRaw>>>>>
- = unsafe { Lazy::new(stdout_init) };
+ static INSTANCE: Lazy<ReentrantMutex<RefCell<LineWriter<Maybe<StdoutRaw>>>>> = Lazy::new();
return Stdout {
- inner: INSTANCE.get().expect("cannot access stdout during shutdown"),
+ inner: unsafe {
+ INSTANCE.get(stdout_init).expect("cannot access stdout during shutdown")
+ },
};
fn stdout_init() -> Arc<ReentrantMutex<RefCell<LineWriter<Maybe<StdoutRaw>>>>> {
/// ```
#[stable(feature = "rust1", since = "1.0.0")]
pub fn stderr() -> Stderr {
- static INSTANCE: Lazy<ReentrantMutex<RefCell<Maybe<StderrRaw>>>> =
- unsafe { Lazy::new(stderr_init) };
+ static INSTANCE: Lazy<ReentrantMutex<RefCell<Maybe<StderrRaw>>>> = Lazy::new();
return Stderr {
- inner: INSTANCE.get().expect("cannot access stderr during shutdown"),
+ inner: unsafe {
+ INSTANCE.get(stderr_init).expect("cannot access stderr during shutdown")
+ },
};
fn stderr_init() -> Arc<ReentrantMutex<RefCell<Maybe<StderrRaw>>>> {
#![feature(cfg_target_vendor)]
#![feature(char_error_internals)]
#![feature(compiler_builtins_lib)]
-#![feature(const_fn)]
+#![cfg_attr(stage0, feature(const_fn))]
+#![cfg_attr(not(stage0), feature(min_const_fn))]
#![feature(const_int_ops)]
#![feature(const_ip)]
#![feature(core_intrinsics)]
/// These macros do not have any corresponding definition with a `macro_rules!`
/// macro, but are documented here. Their implementations can be found hardcoded
/// into libsyntax itself.
-#[cfg(dox)]
+#[cfg(rustdoc)]
mod builtin {
/// Unconditionally causes compilation to fail with the given error message when encountered.
//! OS-specific functionality.
#![stable(feature = "os", since = "1.0.0")]
-#![allow(missing_docs, bad_style, missing_debug_implementations)]
+#![allow(missing_docs, nonstandard_style, missing_debug_implementations)]
cfg_if! {
- if #[cfg(dox)] {
+ if #[cfg(rustdoc)] {
// When documenting libstd we want to show unix/windows/linux modules as
// these are the "main modules" that are used across platforms. This
/// [poison]: struct.Mutex.html#poisoning
#[stable(feature = "rust1", since = "1.0.0")]
pub fn call_once<F>(&self, f: F) where F: FnOnce() {
- // Fast path, just see if we've completed initialization.
- // An `Acquire` load is enough because that makes all the initialization
- // operations visible to us. The cold path uses SeqCst consistently
- // because the performance difference really does not matter there,
- // and SeqCst minimizes the chances of something going wrong.
- if self.state.load(Ordering::Acquire) == COMPLETE {
- return
+ // Fast path check
+ if self.is_completed() {
+ return;
}
let mut f = Some(f);
/// ```
#[unstable(feature = "once_poison", issue = "33577")]
pub fn call_once_force<F>(&self, f: F) where F: FnOnce(&OnceState) {
- // same as above, just with a different parameter to `call_inner`.
- // An `Acquire` load is enough because that makes all the initialization
- // operations visible to us. The cold path uses SeqCst consistently
- // because the performance difference really does not matter there,
- // and SeqCst minimizes the chances of something going wrong.
- if self.state.load(Ordering::Acquire) == COMPLETE {
- return
+ // Fast path check
+ if self.is_completed() {
+ return;
}
let mut f = Some(f);
});
}
+ /// Returns true if some `call_once` call has completed
+ /// successfuly. Specifically, `is_completed` will return false in
+ /// the following situtations:
+ /// * `call_once` was not called at all,
+ /// * `call_once` was called, but has not yet completed,
+ /// * the `Once` instance is poisoned
+ ///
+ /// It is also possible that immediately after `is_completed`
+ /// returns false, some other thread finishes executing
+ /// `call_once`.
+ ///
+ /// # Examples
+ ///
+ /// ```
+ /// #![feature(once_is_completed)]
+ /// use std::sync::Once;
+ ///
+ /// static INIT: Once = Once::new();
+ ///
+ /// assert_eq!(INIT.is_completed(), false);
+ /// INIT.call_once(|| {
+ /// assert_eq!(INIT.is_completed(), false);
+ /// });
+ /// assert_eq!(INIT.is_completed(), true);
+ /// ```
+ ///
+ /// ```
+ /// #![feature(once_is_completed)]
+ /// use std::sync::Once;
+ /// use std::thread;
+ ///
+ /// static INIT: Once = Once::new();
+ ///
+ /// assert_eq!(INIT.is_completed(), false);
+ /// let handle = thread::spawn(|| {
+ /// INIT.call_once(|| panic!());
+ /// });
+ /// assert!(handle.join().is_err());
+ /// assert_eq!(INIT.is_completed(), false);
+ /// ```
+ #[unstable(feature = "once_is_completed", issue = "42")]
+ pub fn is_completed(&self) -> bool {
+ // An `Acquire` load is enough because that makes all the initialization
+ // operations visible to us, and, this being a fast path, weaker
+ // ordering helps with performance. This `Acquire` synchronizes with
+ // `SeqCst` operations on the slow path.
+ self.state.load(Ordering::Acquire) == COMPLETE
+ }
+
// This is a non-generic function to reduce the monomorphization cost of
// using `call_once` (this isn't exactly a trivial or small implementation).
//
fn call_inner(&self,
ignore_poisoning: bool,
init: &mut dyn FnMut(bool)) {
+
+ // This cold path uses SeqCst consistently because the
+ // performance difference really does not matter there, and
+ // SeqCst minimizes the chances of something going wrong.
let mut state = self.state.load(Ordering::SeqCst);
'outer: loop {
thread::spawn(move || {
let mut rng = rand::thread_rng();
for _ in 0..M {
- if rng.gen_weighted_bool(N) {
+ if rng.gen_bool(1.0 / (N as f64)) {
drop(r.write().unwrap());
} else {
drop(r.read().unwrap());
unsafe impl Send for Condvar {}
unsafe impl Sync for Condvar {}
+const NEW: Condvar = Condvar {
+ condvar: UnsafeCell::new(AtomicU32::new(abi::CONDVAR_HAS_NO_WAITERS.0)),
+};
+
impl Condvar {
pub const fn new() -> Condvar {
- Condvar {
- condvar: UnsafeCell::new(AtomicU32::new(abi::CONDVAR_HAS_NO_WAITERS.0)),
- }
+ NEW
}
pub unsafe fn init(&mut self) {}
unsafe impl Send for RWLock {}
unsafe impl Sync for RWLock {}
+const NEW: RWLock = RWLock {
+ lock: UnsafeCell::new(AtomicU32::new(abi::LOCK_UNLOCKED.0)),
+};
+
impl RWLock {
pub const fn new() -> RWLock {
- RWLock {
- lock: UnsafeCell::new(AtomicU32::new(abi::LOCK_UNLOCKED.0)),
- }
+ NEW
}
pub unsafe fn try_read(&self) -> bool {
// then later used in the `std::os` module when documenting, for example,
// Windows when we're compiling for Linux.
-#[cfg(dox)]
+#[cfg(rustdoc)]
cfg_if! {
if #[cfg(any(unix, target_os = "redox"))] {
// On unix we'll document what's already available
}
}
-#[cfg(dox)]
+#[cfg(rustdoc)]
cfg_if! {
if #[cfg(windows)] {
// On windows we'll just be documenting what's already available
// option. This file may not be copied, modified, or distributed
// except according to those terms.
-#![allow(dead_code, missing_docs, bad_style)]
+#![allow(dead_code, missing_docs, nonstandard_style)]
use io::{self, ErrorKind};
// reason for this is that if an error occurs we don't actually know if
// the file descriptor was closed or not, and if we retried (for
// something like EINTR), we might close another valid file descriptor
- // (opened after we closed ours.
+ // opened after we closed ours.
let _ = unsafe { libc::close(self.fd) };
}
}
// option. This file may not be copied, modified, or distributed
// except according to those terms.
-#![allow(missing_docs, bad_style)]
+#![allow(missing_docs, nonstandard_style)]
use io::{self, ErrorKind};
use libc;
-#[cfg(any(dox, target_os = "linux"))] pub use os::linux as platform;
-
-#[cfg(all(not(dox), target_os = "android"))] pub use os::android as platform;
-#[cfg(all(not(dox), target_os = "bitrig"))] pub use os::bitrig as platform;
-#[cfg(all(not(dox), target_os = "dragonfly"))] pub use os::dragonfly as platform;
-#[cfg(all(not(dox), target_os = "freebsd"))] pub use os::freebsd as platform;
-#[cfg(all(not(dox), target_os = "haiku"))] pub use os::haiku as platform;
-#[cfg(all(not(dox), target_os = "ios"))] pub use os::ios as platform;
-#[cfg(all(not(dox), target_os = "macos"))] pub use os::macos as platform;
-#[cfg(all(not(dox), target_os = "netbsd"))] pub use os::netbsd as platform;
-#[cfg(all(not(dox), target_os = "openbsd"))] pub use os::openbsd as platform;
-#[cfg(all(not(dox), target_os = "solaris"))] pub use os::solaris as platform;
-#[cfg(all(not(dox), target_os = "emscripten"))] pub use os::emscripten as platform;
-#[cfg(all(not(dox), target_os = "fuchsia"))] pub use os::fuchsia as platform;
-#[cfg(all(not(dox), target_os = "l4re"))] pub use os::linux as platform;
-#[cfg(all(not(dox), target_os = "hermit"))] pub use os::hermit as platform;
+#[cfg(any(rustdoc, target_os = "linux"))] pub use os::linux as platform;
+
+#[cfg(all(not(rustdoc), target_os = "android"))] pub use os::android as platform;
+#[cfg(all(not(rustdoc), target_os = "bitrig"))] pub use os::bitrig as platform;
+#[cfg(all(not(rustdoc), target_os = "dragonfly"))] pub use os::dragonfly as platform;
+#[cfg(all(not(rustdoc), target_os = "freebsd"))] pub use os::freebsd as platform;
+#[cfg(all(not(rustdoc), target_os = "haiku"))] pub use os::haiku as platform;
+#[cfg(all(not(rustdoc), target_os = "ios"))] pub use os::ios as platform;
+#[cfg(all(not(rustdoc), target_os = "macos"))] pub use os::macos as platform;
+#[cfg(all(not(rustdoc), target_os = "netbsd"))] pub use os::netbsd as platform;
+#[cfg(all(not(rustdoc), target_os = "openbsd"))] pub use os::openbsd as platform;
+#[cfg(all(not(rustdoc), target_os = "solaris"))] pub use os::solaris as platform;
+#[cfg(all(not(rustdoc), target_os = "emscripten"))] pub use os::emscripten as platform;
+#[cfg(all(not(rustdoc), target_os = "fuchsia"))] pub use os::fuchsia as platform;
+#[cfg(all(not(rustdoc), target_os = "l4re"))] pub use os::linux as platform;
+#[cfg(all(not(rustdoc), target_os = "hermit"))] pub use os::hermit as platform;
pub use self::rand::hashmap_random_keys;
pub use libc::strlen;
#[cfg(not(target_env = "gnu"))]
fn on_resolver_failure() {}
-
-#[cfg(all(test, taget_env = "gnu"))]
-mod test {
- use super::*;
-
- #[test]
- fn test_res_init() {
- // This mostly just tests that the weak linkage doesn't panic wildly...
- res_init_if_glibc_before_2_26().unwrap();
- }
-
- #[test]
- fn test_parse_glibc_version() {
- let cases = [
- ("0.0", Some((0, 0))),
- ("01.+2", Some((1, 2))),
- ("3.4.5.six", Some((3, 4))),
- ("1", None),
- ("1.-2", None),
- ("1.foo", None),
- ("foo.1", None),
- ];
- for &(version_str, parsed) in cases.iter() {
- assert_eq!(parsed, parse_glibc_version(version_str));
- }
- }
-}
_ => None
}
}
+
+#[cfg(all(test, target_env = "gnu"))]
+mod test {
+ use super::*;
+
+ #[test]
+ fn test_glibc_version() {
+ // This mostly just tests that the weak linkage doesn't panic wildly...
+ glibc_version();
+ }
+
+ #[test]
+ fn test_parse_glibc_version() {
+ let cases = [
+ ("0.0", Some((0, 0))),
+ ("01.+2", Some((1, 2))),
+ ("3.4.5.six", Some((3, 4))),
+ ("1", None),
+ ("1.-2", None),
+ ("1.foo", None),
+ ("foo.1", None),
+ ];
+ for &(version_str, parsed) in cases.iter() {
+ assert_eq!(parsed, parse_glibc_version(version_str));
+ }
+ }
+}
mod imp {
use fs::File;
use io::Read;
+ #[cfg(any(target_os = "linux", target_os = "android"))]
use libc;
- use sys::os::errno;
#[cfg(any(target_os = "linux", target_os = "android"))]
fn getrandom(buf: &mut [u8]) -> libc::c_long {
}
#[cfg(not(any(target_os = "linux", target_os = "android")))]
- fn getrandom(_buf: &mut [u8]) -> libc::c_long { -1 }
+ fn getrandom_fill_bytes(_buf: &mut [u8]) -> bool { false }
+ #[cfg(any(target_os = "linux", target_os = "android"))]
fn getrandom_fill_bytes(v: &mut [u8]) -> bool {
+ use sync::atomic::{AtomicBool, Ordering};
+ use sys::os::errno;
+
+ static GETRANDOM_UNAVAILABLE: AtomicBool = AtomicBool::new(false);
+ if GETRANDOM_UNAVAILABLE.load(Ordering::Relaxed) {
+ return false;
+ }
+
let mut read = 0;
while read < v.len() {
let result = getrandom(&mut v[read..]);
let err = errno() as libc::c_int;
if err == libc::EINTR {
continue;
+ } else if err == libc::ENOSYS {
+ GETRANDOM_UNAVAILABLE.store(true, Ordering::Relaxed);
+ return false;
} else if err == libc::EAGAIN {
- return false
+ return false;
} else {
panic!("unexpected getrandom error: {}", err);
}
read += result as usize;
}
}
-
- return true
+ true
}
- #[cfg(any(target_os = "linux", target_os = "android"))]
- fn is_getrandom_available() -> bool {
- use io;
- use sync::atomic::{AtomicBool, Ordering};
- use sync::Once;
-
- static CHECKER: Once = Once::new();
- static AVAILABLE: AtomicBool = AtomicBool::new(false);
-
- CHECKER.call_once(|| {
- let mut buf: [u8; 0] = [];
- let result = getrandom(&mut buf);
- let available = if result == -1 {
- let err = io::Error::last_os_error().raw_os_error();
- err != Some(libc::ENOSYS)
- } else {
- true
- };
- AVAILABLE.store(available, Ordering::Relaxed);
- });
-
- AVAILABLE.load(Ordering::Relaxed)
- }
-
- #[cfg(not(any(target_os = "linux", target_os = "android")))]
- fn is_getrandom_available() -> bool { false }
-
pub fn fill_bytes(v: &mut [u8]) {
// getrandom_fill_bytes here can fail if getrandom() returns EAGAIN,
// meaning it would have blocked because the non-blocking pool (urandom)
- // has not initialized in the kernel yet due to a lack of entropy the
+ // has not initialized in the kernel yet due to a lack of entropy. The
// fallback we do here is to avoid blocking applications which could
// depend on this call without ever knowing they do and don't have a
- // work around. The PRNG of /dev/urandom will still be used but not
- // over a completely full entropy pool
- if is_getrandom_available() && getrandom_fill_bytes(v) {
- return
+ // work around. The PRNG of /dev/urandom will still be used but over a
+ // possibly predictable entropy pool.
+ if getrandom_fill_bytes(v) {
+ return;
}
- let mut file = File::open("/dev/urandom")
- .expect("failed to open /dev/urandom");
- file.read_exact(v).expect("failed to read /dev/urandom");
+ // getrandom failed because it is permanently or temporarily (because
+ // of missing entropy) unavailable. Open /dev/urandom, read from it,
+ // and close it again.
+ let mut file = File::open("/dev/urandom").expect("failed to open /dev/urandom");
+ file.read_exact(v).expect("failed to read /dev/urandom")
}
}
unsupported()
}
-#[allow(bad_style)]
+#[allow(nonstandard_style)]
pub mod netc {
pub const AF_INET: u8 = 0;
pub const AF_INET6: u8 = 1;
//! C definitions used by libnative that don't belong in liblibc
-#![allow(bad_style)]
+#![allow(nonstandard_style)]
#![cfg_attr(test, allow(dead_code))]
#![unstable(issue = "0", feature = "windows_c")]
// will not appear in the final documentation. This should be also defined for
// other architectures supported by Windows such as ARM, and for historical
// interest, maybe MIPS and PowerPC as well.
-#[cfg(all(dox, not(any(target_arch = "x86_64", target_arch = "x86", target_arch = "aarch64"))))]
+#[cfg(all(rustdoc, not(any(target_arch = "x86_64", target_arch = "x86", target_arch = "aarch64"))))]
pub enum CONTEXT {}
#[cfg(target_arch = "aarch64")]
// option. This file may not be copied, modified, or distributed
// except according to those terms.
-#![allow(missing_docs, bad_style)]
+#![allow(missing_docs, nonstandard_style)]
use ptr;
use ffi::{OsStr, OsString};
//! Implementation of `std::os` functionality for Windows
-#![allow(bad_style)]
+#![allow(nonstandard_style)]
use os::windows::prelude::*;
pub mod test {
use path::{Path, PathBuf};
use env;
- use rand::{self, Rng};
+ use rand::{self, RngCore};
use fs;
pub struct TempDir(PathBuf);
use std::env::*;
use std::ffi::{OsString, OsStr};
-use rand::Rng;
+use rand::{thread_rng, Rng};
+use rand::distributions::Alphanumeric;
fn make_rand_name() -> OsString {
- let mut rng = rand::thread_rng();
- let n = format!("TEST{}", rng.gen_ascii_chars().take(10)
+ let mut rng = thread_rng();
+ let n = format!("TEST{}", rng.sample_iter(&Alphanumeric).take(10)
.collect::<String>());
let n = OsString::from(n);
assert!(var_os(&n).is_none());
/// Waits for the associated thread to finish.
///
+ /// In terms of [atomic memory orderings], the completion of the associated
+ /// thread synchronizes with this function returning. In other words, all
+ /// operations performed by that thread are ordered before all
+ /// operations that happen after `join` returns.
+ ///
/// If the child thread panics, [`Err`] is returned with the parameter given
/// to [`panic`].
///
/// [`Err`]: ../../std/result/enum.Result.html#variant.Err
/// [`panic`]: ../../std/macro.panic.html
+ /// [atomic memory orderings]: ../../std/sync/atomic/index.html
///
/// # Panics
///
use tokenstream::{ThinTokenStream, TokenStream};
use serialize::{self, Encoder, Decoder};
-use std::collections::HashSet;
use std::fmt;
+use rustc_data_structures::fx::FxHashSet;
use rustc_data_structures::sync::Lrc;
use std::u32;
/// The set of MetaItems that define the compilation environment of the crate,
/// used to drive conditional compilation
-pub type CrateConfig = HashSet<(Name, Option<Symbol>)>;
+pub type CrateConfig = FxHashSet<(Name, Option<Symbol>)>;
#[derive(Clone, RustcEncodable, RustcDecodable, Debug)]
pub struct Crate {
pub struct Arm {
pub attrs: Vec<Attribute>,
pub pats: Vec<P<Pat>>,
- pub guard: Option<P<Expr>>,
+ pub guard: Option<Guard>,
pub body: P<Expr>,
}
+#[derive(Clone, RustcEncodable, RustcDecodable, Debug)]
+pub enum Guard {
+ If(P<Expr>),
+}
+
#[derive(Clone, RustcEncodable, RustcDecodable, Debug)]
pub struct Field {
pub ident: Ident,
if let TyKind::ImplicitSelf = *self { true } else { false }
}
- crate fn is_unit(&self) -> bool {
+ pub fn is_unit(&self) -> bool {
if let TyKind::Tup(ref tys) = *self { tys.is_empty() } else { false }
}
}
pub level: StabilityLevel,
pub feature: Symbol,
pub rustc_depr: Option<RustcDeprecation>,
- pub rustc_const_unstable: Option<RustcConstUnstable>,
+ /// `None` means the function is stable but needs to be allowed by the
+ /// `min_const_fn` feature
+ /// `Some` contains the feature gate required to be able to use the function
+ /// as const fn
+ pub const_stability: Option<Symbol>,
}
/// The available stability levels.
pub reason: Symbol,
}
-#[derive(RustcEncodable, RustcDecodable, PartialEq, PartialOrd, Clone, Debug, Eq, Hash)]
-pub struct RustcConstUnstable {
- pub feature: Symbol,
-}
-
/// Check if `attrs` contains an attribute like `#![feature(feature_name)]`.
/// This will not perform any "sanity checks" on the form of the attributes.
pub fn contains_feature_attr(attrs: &[Attribute], feature_name: &str) -> bool {
let mut stab: Option<Stability> = None;
let mut rustc_depr: Option<RustcDeprecation> = None;
- let mut rustc_const_unstable: Option<RustcConstUnstable> = None;
+ let mut rustc_const_unstable: Option<Symbol> = None;
'outer: for attr in attrs_iter {
if ![
mark_used(attr);
let meta = attr.meta();
+ // attributes with data
if let Some(MetaItem { node: MetaItemKind::List(ref metas), .. }) = meta {
let meta = meta.as_ref().unwrap();
let get = |meta: &MetaItem, item: &mut Option<Symbol>| {
get_meta!(feature);
if let Some(feature) = feature {
- rustc_const_unstable = Some(RustcConstUnstable {
- feature
- });
+ rustc_const_unstable = Some(feature);
} else {
span_err!(diagnostic, attr.span(), E0629, "missing 'feature'");
continue
},
feature,
rustc_depr: None,
- rustc_const_unstable: None,
+ const_stability: None,
})
}
(None, _, _) => {
},
feature,
rustc_depr: None,
- rustc_const_unstable: None,
+ const_stability: None,
})
}
(None, _) => {
}
// Merge the const-unstable info into the stability info
- if let Some(rustc_const_unstable) = rustc_const_unstable {
+ if let Some(feature) = rustc_const_unstable {
if let Some(ref mut stab) = stab {
- stab.rustc_const_unstable = Some(rustc_const_unstable);
+ stab.const_stability = Some(feature);
} else {
span_err!(diagnostic, item_sp, E0630,
"rustc_const_unstable attribute must be paired with \
pub use self::builtin::{
cfg_matches, contains_feature_attr, eval_condition, find_crate_name, find_deprecation,
find_repr_attrs, find_stability, find_unwind_attr, Deprecation, InlineAttr, IntType, ReprAttr,
- RustcConstUnstable, RustcDeprecation, Stability, StabilityLevel, UnwindAttr,
+ RustcDeprecation, Stability, StabilityLevel, UnwindAttr,
};
pub use self::IntType::*;
pub use self::ReprAttr::*;
/// A folder that strips out items that do not belong in the current configuration.
pub struct StripUnconfigured<'a> {
- pub should_test: bool,
pub sess: &'a ParseSess,
pub features: Option<&'a Features>,
}
// `cfg_attr`-process the crate's attributes and compute the crate's features.
-pub fn features(mut krate: ast::Crate, sess: &ParseSess, should_test: bool, edition: Edition)
+pub fn features(mut krate: ast::Crate, sess: &ParseSess, edition: Edition)
-> (ast::Crate, Features) {
let features;
{
let mut strip_unconfigured = StripUnconfigured {
- should_test,
sess,
features: None,
};
// Determine if a node with the given attributes should be included in this configuration.
pub fn in_cfg(&mut self, attrs: &[ast::Attribute]) -> bool {
attrs.iter().all(|attr| {
- // When not compiling with --test we should not compile the #[test] functions
- if !self.should_test && is_test_or_bench(attr) {
- return false;
- }
-
let mis = if !is_cfg(attr) {
return true;
} else if let Some(mis) = attr.meta_item_list() {
//
// NB: This is intentionally not part of the fold_expr() function
// in order for fold_opt_expr() to be able to avoid this check
- if let Some(attr) = expr.attrs().iter().find(|a| is_cfg(a) || is_test_or_bench(a)) {
+ if let Some(attr) = expr.attrs().iter().find(|a| is_cfg(a)) {
let msg = "removing an expression is not supported in this position";
self.sess.span_diagnostic.span_err(attr.span, msg);
}
fn is_cfg(attr: &ast::Attribute) -> bool {
attr.check_name("cfg")
}
-
-pub fn is_test_or_bench(attr: &ast::Attribute) -> bool {
- attr.check_name("test") || attr.check_name("bench")
-}
use symbol::{keywords, Ident, Symbol};
use ThinVec;
-use std::collections::HashMap;
+use rustc_data_structures::fx::FxHashMap;
use std::iter;
use std::path::PathBuf;
use std::rc::Rc;
fn visit_ast_fragment_with_placeholders(&mut self, mark: Mark, fragment: &AstFragment,
derives: &[Mark]);
fn add_builtin(&mut self, ident: ast::Ident, ext: Lrc<SyntaxExtension>);
+ fn add_unshadowable_attr(&mut self, ident: ast::Ident, ext: Lrc<SyntaxExtension>);
fn resolve_imports(&mut self);
// Resolves attribute and derive legacy macros from `#![plugin(..)]`.
fn resolve_macro_invocation(&mut self, invoc: &Invocation, scope: Mark, force: bool)
-> Result<Option<Lrc<SyntaxExtension>>, Determinacy>;
+
fn resolve_macro_path(&mut self, path: &ast::Path, kind: MacroKind, scope: Mark,
derives_in_scope: &[ast::Path], force: bool)
-> Result<Lrc<SyntaxExtension>, Determinacy>;
fn visit_ast_fragment_with_placeholders(&mut self, _invoc: Mark, _fragment: &AstFragment,
_derives: &[Mark]) {}
fn add_builtin(&mut self, _ident: ast::Ident, _ext: Lrc<SyntaxExtension>) {}
+ fn add_unshadowable_attr(&mut self, _ident: ast::Ident, _ext: Lrc<SyntaxExtension>) {}
fn resolve_imports(&mut self) {}
fn find_legacy_attr_invoc(&mut self, _attrs: &mut Vec<Attribute>, _allow_derive: bool)
pub resolver: &'a mut dyn Resolver,
pub resolve_err_count: usize,
pub current_expansion: ExpansionData,
- pub expansions: HashMap<Span, Vec<String>>,
+ pub expansions: FxHashMap<Span, Vec<String>>,
}
impl<'a> ExtCtxt<'a> {
directory_ownership: DirectoryOwnership::Owned { relative: None },
crate_span: None,
},
- expansions: HashMap::new(),
+ expansions: FxHashMap::default(),
}
}
use symbol::Symbol;
use syntax_pos::Span;
-use std::collections::HashSet;
+use rustc_data_structures::fx::FxHashSet;
pub fn collect_derives(cx: &mut ExtCtxt, attrs: &mut Vec<ast::Attribute>) -> Vec<ast::Path> {
let mut result = Vec::new();
pub fn add_derived_markers<T>(cx: &mut ExtCtxt, span: Span, traits: &[ast::Path], item: T) -> T
where T: HasAttrs,
{
- let (mut names, mut pretty_name) = (HashSet::new(), "derive(".to_owned());
+ let (mut names, mut pretty_name) = (FxHashSet::default(), "derive(".to_owned());
for (i, path) in traits.iter().enumerate() {
if i > 0 {
pretty_name.push_str(", ");
use ast::{MacStmtStyle, StmtKind, ItemKind};
use attr::{self, HasAttrs};
use source_map::{ExpnInfo, MacroBang, MacroAttribute, dummy_spanned, respan};
-use config::{is_test_or_bench, StripUnconfigured};
+use config::StripUnconfigured;
use errors::{Applicability, FatalError};
use ext::base::*;
-use ext::build::AstBuilder;
use ext::derive::{add_derived_markers, collect_derives};
use ext::hygiene::{self, Mark, SyntaxContext};
use ext::placeholders::{placeholder, PlaceholderExpander};
use tokenstream::{TokenStream, TokenTree};
use visit::{self, Visitor};
-use std::collections::HashMap;
+use rustc_data_structures::fx::FxHashMap;
use std::fs::File;
use std::io::Read;
-use std::iter::FromIterator;
use std::{iter, mem};
use std::rc::Rc;
use std::path::PathBuf;
// Unresolved macros produce dummy outputs as a recovery measure.
invocations.reverse();
let mut expanded_fragments = Vec::new();
- let mut derives: HashMap<Mark, Vec<_>> = HashMap::new();
+ let mut derives: FxHashMap<Mark, Vec<_>> = FxHashMap::default();
let mut undetermined_invocations = Vec::new();
let (mut progress, mut force) = (false, !self.monotonic);
loop {
let (fragment_with_placeholders, invocations) = {
let mut collector = InvocationCollector {
cfg: StripUnconfigured {
- should_test: self.cx.ecfg.should_test,
sess: self.cx.parse_sess,
features: self.cx.ecfg.features,
},
cx: self.cx,
invocations: Vec::new(),
monotonic: self.monotonic,
- tests_nameable: true,
};
(fragment.fold_with(&mut collector), collector.invocations)
};
fn fully_configure(&mut self, item: Annotatable) -> Annotatable {
let mut cfg = StripUnconfigured {
- should_test: self.cx.ecfg.should_test,
sess: self.cx.parse_sess,
features: self.cx.ecfg.features,
};
cfg: StripUnconfigured<'a>,
invocations: Vec<Invocation>,
monotonic: bool,
-
- /// Test functions need to be nameable. Tests inside functions or in other
- /// unnameable locations need to be ignored. `tests_nameable` tracks whether
- /// any test functions found in the current context would be nameable.
- tests_nameable: bool,
}
impl<'a, 'b> InvocationCollector<'a, 'b> {
placeholder(fragment_kind, NodeId::placeholder_from_mark(mark))
}
- /// Folds the item allowing tests to be expanded because they are still nameable.
- /// This should probably only be called with module items
- fn fold_nameable(&mut self, item: P<ast::Item>) -> OneVector<P<ast::Item>> {
- fold::noop_fold_item(item, self)
- }
-
- /// Folds the item but doesn't allow tests to occur within it
- fn fold_unnameable(&mut self, item: P<ast::Item>) -> OneVector<P<ast::Item>> {
- let was_nameable = mem::replace(&mut self.tests_nameable, false);
- let items = fold::noop_fold_item(item, self);
- self.tests_nameable = was_nameable;
- items
- }
-
fn collect_bang(&mut self, mac: ast::Mac, span: Span, kind: AstFragmentKind) -> AstFragment {
self.collect(kind, InvocationKind::Bang { mac: mac, ident: None, span: span })
}
fn fold_item(&mut self, item: P<ast::Item>) -> OneVector<P<ast::Item>> {
let item = configure!(self, item);
- let (attr, traits, mut item) = self.classify_item(item);
+ let (attr, traits, item) = self.classify_item(item);
if attr.is_some() || !traits.is_empty() {
let item = Annotatable::Item(item);
return self.collect_attr(attr, traits, item, AstFragmentKind::Items).make_items();
}
ast::ItemKind::Mod(ast::Mod { inner, .. }) => {
if item.ident == keywords::Invalid.ident() {
- return self.fold_nameable(item);
+ return noop_fold_item(item, self);
}
let orig_directory_ownership = self.cx.current_expansion.directory_ownership;
let orig_module =
mem::replace(&mut self.cx.current_expansion.module, Rc::new(module));
- let result = self.fold_nameable(item);
+ let result = noop_fold_item(item, self);
self.cx.current_expansion.module = orig_module;
self.cx.current_expansion.directory_ownership = orig_directory_ownership;
result
}
- // Ensure that test functions are accessible from the test harness.
- // #[test] fn foo() {}
- // becomes:
- // #[test] pub fn foo_gensym(){}
- // #[allow(unused)]
- // use foo_gensym as foo;
- ast::ItemKind::Fn(..) if self.cx.ecfg.should_test => {
- if self.tests_nameable && item.attrs.iter().any(|attr| is_test_or_bench(attr)) {
- let orig_ident = item.ident;
- let orig_vis = item.vis.clone();
-
- // Publicize the item under gensymed name to avoid pollution
- item = item.map(|mut item| {
- item.vis = respan(item.vis.span, ast::VisibilityKind::Public);
- item.ident = item.ident.gensym();
- item
- });
-
- // Use the gensymed name under the item's original visibility
- let mut use_item = self.cx.item_use_simple_(
- item.ident.span,
- orig_vis,
- Some(orig_ident),
- self.cx.path(item.ident.span,
- vec![keywords::SelfValue.ident(), item.ident]));
-
- // #[allow(unused)] because the test function probably isn't being referenced
- use_item = use_item.map(|mut ui| {
- ui.attrs.push(
- self.cx.attribute(DUMMY_SP, attr::mk_list_item(DUMMY_SP,
- Ident::from_str("allow"), vec![
- attr::mk_nested_word_item(Ident::from_str("unused"))
- ]
- ))
- );
-
- ui
- });
- OneVector::from_iter(
- self.fold_unnameable(item).into_iter()
- .chain(self.fold_unnameable(use_item)))
- } else {
- self.fold_unnameable(item)
- }
- }
- _ => self.fold_unnameable(item),
+ _ => noop_fold_item(item, self),
}
}
feature_tests! {
fn enable_quotes = quote,
fn enable_asm = asm,
+ fn enable_custom_test_frameworks = custom_test_frameworks,
fn enable_global_asm = global_asm,
fn enable_log_syntax = log_syntax,
fn enable_concat_idents = concat_idents,
use ThinVec;
use util::move_map::MoveMap;
-use std::collections::HashMap;
+use rustc_data_structures::fx::FxHashMap;
pub fn placeholder(kind: AstFragmentKind, id: ast::NodeId) -> AstFragment {
fn mac_placeholder() -> ast::Mac {
}
pub struct PlaceholderExpander<'a, 'b: 'a> {
- expanded_fragments: HashMap<ast::NodeId, AstFragment>,
+ expanded_fragments: FxHashMap<ast::NodeId, AstFragment>,
cx: &'a mut ExtCtxt<'b>,
monotonic: bool,
}
pub fn new(cx: &'a mut ExtCtxt<'b>, monotonic: bool) -> Self {
PlaceholderExpander {
cx,
- expanded_fragments: HashMap::new(),
+ expanded_fragments: FxHashMap::default(),
monotonic,
}
}
use symbol::keywords;
use tokenstream::TokenStream;
+use rustc_data_structures::fx::FxHashMap;
+use std::collections::hash_map::Entry::{Occupied, Vacant};
use std::mem;
use std::ops::{Deref, DerefMut};
use std::rc::Rc;
-use std::collections::HashMap;
-use std::collections::hash_map::Entry::{Occupied, Vacant};
// To avoid costly uniqueness checks, we require that `MatchSeq` always has a nonempty body.
/// A `ParseResult` where the `Success` variant contains a mapping of `Ident`s to `NamedMatch`es.
/// This represents the mapping of metavars to the token trees they bind to.
-pub type NamedParseResult = ParseResult<HashMap<Ident, Rc<NamedMatch>>>;
+pub type NamedParseResult = ParseResult<FxHashMap<Ident, Rc<NamedMatch>>>;
/// Count how many metavars are named in the given matcher `ms`.
pub fn count_names(ms: &[TokenTree]) -> usize {
sess: &ParseSess,
m: &TokenTree,
res: &mut I,
- ret_val: &mut HashMap<Ident, Rc<NamedMatch>>,
+ ret_val: &mut FxHashMap<Ident, Rc<NamedMatch>>,
) -> Result<(), (syntax_pos::Span, String)> {
match *m {
TokenTree::Sequence(_, ref seq) => for next_m in &seq.tts {
Ok(())
}
- let mut ret_val = HashMap::new();
+ let mut ret_val = FxHashMap::default();
for m in ms {
match n_rec(sess, m, res.by_ref(), &mut ret_val) {
Ok(_) => {}
use symbol::Symbol;
use tokenstream::{TokenStream, TokenTree};
+use rustc_data_structures::fx::FxHashMap;
use std::borrow::Cow;
-use std::collections::HashMap;
use std::collections::hash_map::Entry;
use rustc_data_structures::sync::Lrc;
// If two sequences have the same span in a matcher, then map that
// span to None (invalidating the mapping here and forcing the code to
// use a slow path).
- first: HashMap<Span, Option<TokenSet>>,
+ first: FxHashMap<Span, Option<TokenSet>>,
}
impl FirstSets {
fn new(tts: &[quoted::TokenTree]) -> FirstSets {
use self::quoted::TokenTree;
- let mut sets = FirstSets { first: HashMap::new() };
+ let mut sets = FirstSets { first: FxHashMap::default() };
build_recur(&mut sets, tts);
return sets;
use syntax_pos::{Span, DUMMY_SP};
use tokenstream::{TokenStream, TokenTree, Delimited};
-use std::rc::Rc;
+use rustc_data_structures::fx::FxHashMap;
use rustc_data_structures::sync::Lrc;
use std::mem;
use std::ops::Add;
-use std::collections::HashMap;
+use std::rc::Rc;
// An iterator over the token trees in a delimited token tree (`{ ... }`) or a sequence (`$(...)`).
enum Frame {
/// `src` contains no `TokenTree::{Sequence, MetaVar, MetaVarDecl}`s, `interp` can
/// (and should) be None.
pub fn transcribe(cx: &ExtCtxt,
- interp: Option<HashMap<Ident, Rc<NamedMatch>>>,
+ interp: Option<FxHashMap<Ident, Rc<NamedMatch>>>,
src: Vec<quoted::TokenTree>)
-> TokenStream {
let mut stack: OneVector<Frame> = smallvec![Frame::new(src)];
- let interpolations = interp.unwrap_or_else(HashMap::new); /* just a convenience */
+ let interpolations = interp.unwrap_or_else(FxHashMap::default); /* just a convenience */
let mut repeats = Vec::new();
let mut result: Vec<TokenStream> = Vec::new();
let mut result_stack = Vec::new();
}
fn lookup_cur_matched(ident: Ident,
- interpolations: &HashMap<Ident, Rc<NamedMatch>>,
+ interpolations: &FxHashMap<Ident, Rc<NamedMatch>>,
repeats: &[(usize, usize)])
-> Option<Rc<NamedMatch>> {
interpolations.get(&ident).map(|matched| {
}
fn lockstep_iter_size(tree: "ed::TokenTree,
- interpolations: &HashMap<Ident, Rc<NamedMatch>>,
+ interpolations: &FxHashMap<Ident, Rc<NamedMatch>>,
repeats: &[(usize, usize)])
-> LockstepIterSize {
use self::quoted::TokenTree;
use std::{env, path};
macro_rules! set {
+ // The const_fn feature also enables the min_const_fn feature, because `min_const_fn` allows
+ // the declaration `const fn`, but the `const_fn` feature gate enables things inside those
+ // functions that we do not want to expose to the user for now.
+ (const_fn) => {{
+ fn f(features: &mut Features, _: Span) {
+ features.const_fn = true;
+ features.min_const_fn = true;
+ }
+ f as fn(&mut Features, Span)
+ }};
($field: ident) => {{
fn f(features: &mut Features, _: Span) {
features.$field = true;
// #23121. Array patterns have some hazards yet.
(active, slice_patterns, "1.0.0", Some(23121), None),
- // Allows the definition of `const fn` functions.
+ // Allows the definition of `const fn` functions with some advanced features.
(active, const_fn, "1.2.0", Some(24111), None),
+ // Allows the definition of `const fn` functions.
+ (active, min_const_fn, "1.30.0", Some(53555), None),
+
// Allows let bindings and destructuring in `const fn` functions and constants.
(active, const_let, "1.22.1", Some(48821), None),
- // Allows accessing fields of unions inside const fn
+ // Allows accessing fields of unions inside const fn.
(active, const_fn_union, "1.27.0", Some(51909), None),
- // Allows casting raw pointers to `usize` during const eval
+ // Allows casting raw pointers to `usize` during const eval.
(active, const_raw_ptr_to_usize_cast, "1.27.0", Some(51910), None),
- // Allows dereferencing raw pointers during const eval
+ // Allows dereferencing raw pointers during const eval.
(active, const_raw_ptr_deref, "1.27.0", Some(51911), None),
- // Allows reinterpretation of the bits of a value of one type as another type during const eval
+ // Allows reinterpretation of the bits of a value of one type as another type during const eval.
(active, const_transmute, "1.29.0", Some(53605), None),
- // Allows comparing raw pointers during const eval
+ // Allows comparing raw pointers during const eval.
(active, const_compare_raw_pointers, "1.27.0", Some(53020), None),
// Allows panicking during const eval (produces compile-time errors)
// unsized rvalues at arguments and parameters
(active, unsized_locals, "1.30.0", Some(48055), None),
+
+ // #![test_runner]
+ // #[test_case]
+ (active, custom_test_frameworks, "1.30.0", Some(50297), None),
);
declare_features! (
// Defining procedural macros in `proc-macro` crates
(accepted, proc_macro, "1.29.0", Some(38356), None),
// Allows use of the :vis macro fragment specifier
- (accepted, macro_vis_matcher, "1.29.0", Some(41022), None),
+ (accepted, macro_vis_matcher, "1.30.0", Some(41022), None),
// Allows importing and reexporting macros with `use`,
// enables macro modularization in general.
(accepted, use_extern_macros, "1.30.0", Some(35896), None),
("cfg_attr", Normal, Ungated),
("main", Normal, Ungated),
("start", Normal, Ungated),
- ("test", Normal, Ungated),
- ("bench", Normal, Ungated),
("repr", Normal, Ungated),
("path", Normal, Ungated),
("abi", Normal, Ungated),
attribute is just used for rustc unit \
tests and will never be stable",
cfg_fn!(rustc_attrs))),
+ ("rustc_test_marker", Normal, Gated(Stability::Unstable,
+ "rustc_attrs",
+ "the `#[rustc_test_marker]` attribute \
+ is used internally to track tests",
+ cfg_fn!(rustc_attrs))),
// RFC #2094
("nll", Whitelisted, Gated(Stability::Unstable,
("no_builtins", CrateLevel, Ungated),
("recursion_limit", CrateLevel, Ungated),
("type_length_limit", CrateLevel, Ungated),
+ ("test_runner", CrateLevel, Gated(Stability::Unstable,
+ "custom_test_frameworks",
+ EXPLAIN_CUSTOM_TEST_FRAMEWORKS,
+ cfg_fn!(custom_test_frameworks))),
];
// cfg(...)'s that are feature gated
("target_vendor", "cfg_target_vendor", cfg_fn!(cfg_target_vendor)),
("target_thread_local", "cfg_target_thread_local", cfg_fn!(cfg_target_thread_local)),
("target_has_atomic", "cfg_target_has_atomic", cfg_fn!(cfg_target_has_atomic)),
+ ("rustdoc", "doc_cfg", cfg_fn!(doc_cfg)),
];
#[derive(Debug)]
pub const EXPLAIN_GLOBAL_ASM: &'static str =
"`global_asm!` is not stable enough for use and is subject to change";
+pub const EXPLAIN_CUSTOM_TEST_FRAMEWORKS: &'static str =
+ "custom test frameworks are an unstable feature";
+
pub const EXPLAIN_LOG_SYNTAX: &'static str =
"`log_syntax!` is not stable enough for use and is subject to change";
gate_feature_post!(&self, async_await, span, "async fn is unstable");
}
if header.constness.node == ast::Constness::Const {
- gate_feature_post!(&self, const_fn, span, "const fn is unstable");
+ gate_feature_post!(&self, min_const_fn, span, "const fn is unstable");
}
// stability of const fn methods are covered in
// visit_trait_item and visit_impl_item below; this is
match ii.node {
ast::ImplItemKind::Method(ref sig, _) => {
if sig.header.constness.node == ast::Constness::Const {
- gate_feature_post!(&self, const_fn, ii.span, "const fn is unstable");
+ gate_feature_post!(&self, min_const_fn, ii.span, "const fn is unstable");
}
}
ast::ImplItemKind::Existential(..) => {
noop_fold_arm(a, self)
}
+ fn fold_guard(&mut self, g: Guard) -> Guard {
+ noop_fold_guard(g, self)
+ }
+
fn fold_pat(&mut self, p: P<Pat>) -> P<Pat> {
noop_fold_pat(p, self)
}
Arm {
attrs: fold_attrs(attrs, fld),
pats: pats.move_map(|x| fld.fold_pat(x)),
- guard: guard.map(|x| fld.fold_expr(x)),
+ guard: guard.map(|x| fld.fold_guard(x)),
body: fld.fold_expr(body),
}
}
+pub fn noop_fold_guard<T: Folder>(g: Guard, fld: &mut T) -> Guard {
+ match g {
+ Guard::If(e) => Guard::If(fld.fold_expr(e)),
+ }
+}
+
pub fn noop_fold_ty_binding<T: Folder>(b: TypeBinding, fld: &mut T) -> TypeBinding {
TypeBinding {
id: fld.new_id(b.id),
use errors;
use feature_gate::UnstableFeatures;
use parse::token;
- use std::collections::HashSet;
use std::io;
use std::path::PathBuf;
use diagnostics::plugin::ErrorMap;
+ use rustc_data_structures::fx::FxHashSet;
use rustc_data_structures::sync::Lock;
use with_globals;
fn mk_sess(cm: Lrc<SourceMap>) -> ParseSess {
ParseSess {
span_diagnostic: errors::Handler::with_emitter(true, false, Box::new(emitter)),
unstable_features: UnstableFeatures::from_environment(),
- config: CrateConfig::new(),
+ config: CrateConfig::default(),
included_mod_stack: Lock::new(Vec::new()),
code_map: cm,
- missing_fragment_specifiers: Lock::new(HashSet::new()),
+ missing_fragment_specifiers: Lock::new(FxHashSet::default()),
raw_identifier_spans: Lock::new(Vec::new()),
registered_diagnostics: Lock::new(ErrorMap::new()),
non_modrs_mods: Lock::new(vec![]),
use tokenstream::{TokenStream, TokenTree};
use diagnostics::plugin::ErrorMap;
+use rustc_data_structures::fx::FxHashSet;
use std::borrow::Cow;
-use std::collections::HashSet;
use std::iter;
use std::path::{Path, PathBuf};
use std::str;
pub span_diagnostic: Handler,
pub unstable_features: UnstableFeatures,
pub config: CrateConfig,
- pub missing_fragment_specifiers: Lock<HashSet<Span>>,
+ pub missing_fragment_specifiers: Lock<FxHashSet<Span>>,
/// Places where raw identifiers were used. This is used for feature gating
/// raw identifiers
pub raw_identifier_spans: Lock<Vec<Span>>,
ParseSess {
span_diagnostic: handler,
unstable_features: UnstableFeatures::from_environment(),
- config: HashSet::new(),
- missing_fragment_specifiers: Lock::new(HashSet::new()),
+ config: FxHashSet::default(),
+ missing_fragment_specifiers: Lock::new(FxHashSet::default()),
raw_identifier_spans: Lock::new(Vec::new()),
registered_diagnostics: Lock::new(ErrorMap::new()),
included_mod_stack: Lock::new(vec![]),
use ast::{AngleBracketedArgs, ParenthesisedArgs, AttrStyle, BareFnTy};
use ast::{GenericBound, TraitBoundModifier};
use ast::Unsafety;
-use ast::{Mod, AnonConst, Arg, Arm, Attribute, BindingMode, TraitItemKind};
+use ast::{Mod, AnonConst, Arg, Arm, Guard, Attribute, BindingMode, TraitItemKind};
use ast::Block;
use ast::{BlockCheckMode, CaptureBy, Movability};
use ast::{Constness, Crate};
} 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());
+ err.span_suggestion_with_applicability(
+ self.span,
+ "remove this comma",
+ String::new(),
+ Applicability::MachineApplicable,
+ );
}
}
err
{
self.expect(bra)?;
let result = self.parse_seq_to_before_end(ket, sep, f)?;
- if self.token == *ket {
- self.bump();
- }
+ self.eat(ket);
Ok(result)
}
let ident = self.parse_ident()?;
self.expect(&token::Colon)?;
let ty = self.parse_ty()?;
- let default = if self.check(&token::Eq) {
- self.bump();
+ let default = if self.eat(&token::Eq) {
let expr = self.parse_expr()?;
self.expect(&token::Semi)?;
Some(expr)
while self.token != token::CloseDelim(token::Paren) {
es.push(self.parse_expr()?);
self.expect_one_of(&[], &[token::Comma, token::CloseDelim(token::Paren)])?;
- if self.check(&token::Comma) {
+ if self.eat(&token::Comma) {
trailing_comma = true;
-
- self.bump();
} else {
trailing_comma = false;
break;
attrs.extend(self.parse_inner_attributes()?);
- if self.check(&token::CloseDelim(token::Bracket)) {
+ if self.eat(&token::CloseDelim(token::Bracket)) {
// Empty vector.
- self.bump();
ex = ExprKind::Array(Vec::new());
} else {
// Nonempty vector.
let first_expr = self.parse_expr()?;
- if self.check(&token::Semi) {
+ if self.eat(&token::Semi) {
// Repeating array syntax: [ 0; 512 ]
- self.bump();
let count = AnonConst {
id: ast::DUMMY_NODE_ID,
value: self.parse_expr()?,
};
self.expect(&token::CloseDelim(token::Bracket))?;
ex = ExprKind::Repeat(first_expr, count);
- } else if self.check(&token::Comma) {
+ } else if self.eat(&token::Comma) {
// Vector with two or more elements.
- self.bump();
let remaining_exprs = self.parse_seq_to_end(
&token::CloseDelim(token::Bracket),
SeqSep::trailing_allowed(token::Comma),
self.eat(&token::BinOp(token::Or));
let pats = self.parse_pats()?;
let guard = if self.eat_keyword(keywords::If) {
- Some(self.parse_expr()?)
+ Some(Guard::If(self.parse_expr()?))
} else {
None
};
/// Parse the RHS of a local variable declaration (e.g. '= 14;')
fn parse_initializer(&mut self, skip_eq: bool) -> PResult<'a, Option<P<Expr>>> {
- if self.check(&token::Eq) {
- self.bump();
+ if self.eat(&token::Eq) {
Ok(Some(self.parse_expr()?))
} else if skip_eq {
Ok(Some(self.parse_expr()?))
);
err.emit();
self.bump();
- } else if self.check(&token::BinOp(token::Or)) {
- self.bump();
+ } else if self.eat(&token::BinOp(token::Or)) {
+ // No op.
} else {
return Ok(pats);
}
self.this_token_to_string()));
if self.token.is_ident() {
// This is likely another field; emit the diagnostic and keep going
- err.span_suggestion(sp, "try adding a comma", ",".into());
+ err.span_suggestion_with_applicability(
+ sp,
+ "try adding a comma",
+ ",".into(),
+ Applicability::MachineApplicable,
+ );
err.emit();
} else {
return Err(err)
let (in_cfg, outer_attrs) = {
let mut strip_unconfigured = ::config::StripUnconfigured {
sess: self.sess,
- should_test: false, // irrelevant
features: None, // don't perform gated feature checking
};
let outer_attrs = strip_unconfigured.process_cfg_attrs(outer_attrs.to_owned());
let id_span = self.span;
let id = self.parse_ident()?;
- if self.check(&token::Semi) {
- self.bump();
+ if self.eat(&token::Semi) {
if in_cfg && self.recurse_into_file_modules {
// This mod is in an external file. Let's go get it!
let ModulePathSuccess { path, directory_ownership, warn } =
self.print_outer_attributes(&arm.attrs)?;
self.print_pats(&arm.pats)?;
self.s.space()?;
- if let Some(ref e) = arm.guard {
- self.word_space("if")?;
- self.print_expr(e)?;
- self.s.space()?;
+ if let Some(ref g) = arm.guard {
+ match g {
+ ast::Guard::If(ref e) => {
+ self.word_space("if")?;
+ self.print_expr(e)?;
+ self.s.space()?;
+ }
+ }
}
self.word_space("=>")?;
use rustc_data_structures::fx::FxHashMap;
use rustc_data_structures::stable_hasher::StableHasher;
-use rustc_data_structures::sync::{Lrc, Lock, LockGuard};
+use rustc_data_structures::sync::{Lrc, Lock, LockGuard, MappedLockGuard};
use std::cmp;
use std::hash::Hash;
use std::path::{Path, PathBuf};
Ok(self.new_source_file(filename, src))
}
- pub fn files(&self) -> LockGuard<Vec<Lrc<SourceFile>>> {
+ pub fn files(&self) -> MappedLockGuard<Vec<Lrc<SourceFile>>> {
LockGuard::map(self.files.borrow(), |files| &mut files.file_maps)
}
use attr::{self, HasAttrs};
use syntax_pos::{self, DUMMY_SP, NO_EXPANSION, Span, SourceFile, BytePos};
-use source_map::{self, SourceMap, ExpnInfo, MacroAttribute, dummy_spanned};
+use source_map::{self, SourceMap, ExpnInfo, MacroAttribute, dummy_spanned, respan};
use errors;
use config;
use entry::{self, EntryPointType};
use ThinVec;
use rustc_data_structures::small_vec::ExpectOne;
-enum ShouldPanic {
- No,
- Yes(Option<Symbol>),
-}
-
struct Test {
span: Span,
- path: Vec<Ident> ,
- bench: bool,
- ignore: bool,
- should_panic: ShouldPanic,
- allow_fail: bool,
+ path: Vec<Ident>,
}
struct TestCtxt<'a> {
span_diagnostic: &'a errors::Handler,
path: Vec<Ident>,
ext_cx: ExtCtxt<'a>,
- testfns: Vec<Test>,
+ test_cases: Vec<Test>,
reexport_test_harness_main: Option<Symbol>,
is_libtest: bool,
ctxt: SyntaxContext,
features: &'a Features,
+ test_runner: Option<ast::Path>,
// top-level re-export submodule, filled out after folding is finished
toplevel_reexport: Option<Ident>,
attr::first_attr_value_str_by_name(&krate.attrs,
"reexport_test_harness_main");
+ // Do this here so that the test_runner crate attribute gets marked as used
+ // even in non-test builds
+ let test_runner = get_test_runner(span_diagnostic, &krate);
+
if should_test {
generate_test_harness(sess, resolver, reexport_test_harness_main,
- krate, span_diagnostic, features)
+ krate, span_diagnostic, features, test_runner)
} else {
krate
}
fn fold_crate(&mut self, c: ast::Crate) -> ast::Crate {
let mut folded = fold::noop_fold_crate(c, self);
- // Add a special __test module to the crate that will contain code
- // generated for the test harness
- let (mod_, reexport) = mk_test_module(&mut self.cx);
- if let Some(re) = reexport {
- folded.module.items.push(re)
- }
- folded.module.items.push(mod_);
+ // Create a main function to run our tests
+ let test_main = {
+ let unresolved = mk_main(&mut self.cx);
+ self.cx.ext_cx.monotonic_expander().fold_item(unresolved).pop().unwrap()
+ };
+
+ folded.module.items.push(test_main);
folded
}
}
debug!("current path: {}", path_name_i(&self.cx.path));
- if is_test_fn(&self.cx, &i) || is_bench_fn(&self.cx, &i) {
- match i.node {
- ast::ItemKind::Fn(_, header, _, _) => {
- if header.unsafety == ast::Unsafety::Unsafe {
- let diag = self.cx.span_diagnostic;
- diag.span_fatal(
- i.span,
- "unsafe functions cannot be used for tests"
- ).raise();
- }
- if header.asyncness.is_async() {
- let diag = self.cx.span_diagnostic;
- diag.span_fatal(
- i.span,
- "async functions cannot be used for tests"
- ).raise();
- }
- }
- _ => {},
- }
+ let mut item = i.into_inner();
+ if is_test_case(&item) {
+ debug!("this is a test item");
- debug!("this is a test function");
let test = Test {
- span: i.span,
+ span: item.span,
path: self.cx.path.clone(),
- bench: is_bench_fn(&self.cx, &i),
- ignore: is_ignored(&i),
- should_panic: should_panic(&i, &self.cx),
- allow_fail: is_allowed_fail(&i),
};
- self.cx.testfns.push(test);
- self.tests.push(i.ident);
+ self.cx.test_cases.push(test);
+ self.tests.push(item.ident);
}
- let mut item = i.into_inner();
// We don't want to recurse into anything other than mods, since
// mods or tests inside of functions will break things
if let ast::ItemKind::Mod(module) = item.node {
fn fold_mac(&mut self, mac: ast::Mac) -> ast::Mac { mac }
}
+/// A folder used to remove any entry points (like fn main) because the harness
+/// generator will provide its own
struct EntryPointCleaner {
// Current depth in the ast
depth: usize,
fn fold_mac(&mut self, mac: ast::Mac) -> ast::Mac { mac }
}
+/// Creates an item (specifically a module) that "pub use"s the tests passed in.
+/// Each tested submodule will contain a similar reexport module that we will export
+/// under the name of the original module. That is, `submod::__test_reexports` is
+/// reexported like so `pub use submod::__test_reexports as submod`.
fn mk_reexport_mod(cx: &mut TestCtxt,
parent: ast::NodeId,
tests: Vec<Ident>,
(it, sym)
}
+/// Crawl over the crate, inserting test reexports and the test main function
fn generate_test_harness(sess: &ParseSess,
resolver: &mut dyn Resolver,
reexport_test_harness_main: Option<Symbol>,
krate: ast::Crate,
sd: &errors::Handler,
- features: &Features) -> ast::Crate {
+ features: &Features,
+ test_runner: Option<ast::Path>) -> ast::Crate {
// Remove the entry points
let mut cleaner = EntryPointCleaner { depth: 0 };
let krate = cleaner.fold_crate(krate);
span_diagnostic: sd,
ext_cx: ExtCtxt::new(sess, econfig, resolver),
path: Vec::new(),
- testfns: Vec::new(),
+ test_cases: Vec::new(),
reexport_test_harness_main,
// NB: doesn't consider the value of `--crate-name` passed on the command line.
is_libtest: attr::find_crate_name(&krate.attrs).map(|s| s == "test").unwrap_or(false),
toplevel_reexport: None,
ctxt: SyntaxContext::empty().apply_mark(mark),
features,
+ test_runner
};
mark.set_expn_info(ExpnInfo {
call_site: DUMMY_SP,
def_site: None,
- format: MacroAttribute(Symbol::intern("test")),
+ format: MacroAttribute(Symbol::intern("test_case")),
allow_internal_unstable: true,
allow_internal_unsafe: false,
local_inner_macros: false,
ShouldPanicOnlyWithNoArgs,
}
-fn is_test_fn(cx: &TestCtxt, i: &ast::Item) -> bool {
- let has_test_attr = attr::contains_name(&i.attrs, "test");
-
- fn has_test_signature(_cx: &TestCtxt, i: &ast::Item) -> HasTestSignature {
- let has_should_panic_attr = attr::contains_name(&i.attrs, "should_panic");
- match i.node {
- ast::ItemKind::Fn(ref decl, _, ref generics, _) => {
- // If the termination trait is active, the compiler will check that the output
- // type implements the `Termination` trait as `libtest` enforces that.
- let has_output = match decl.output {
- ast::FunctionRetTy::Default(..) => false,
- ast::FunctionRetTy::Ty(ref t) if t.node.is_unit() => false,
- _ => true
- };
-
- if !decl.inputs.is_empty() {
- return No(BadTestSignature::NoArgumentsAllowed);
- }
-
- match (has_output, has_should_panic_attr) {
- (true, true) => No(BadTestSignature::ShouldPanicOnlyWithNoArgs),
- (true, false) => if !generics.params.is_empty() {
- No(BadTestSignature::WrongTypeSignature)
- } else {
- Yes
- },
- (false, _) => Yes
- }
- }
- _ => No(BadTestSignature::NotEvenAFunction),
- }
- }
-
- let has_test_signature = if has_test_attr {
- let diag = cx.span_diagnostic;
- match has_test_signature(cx, i) {
- Yes => true,
- No(cause) => {
- match cause {
- BadTestSignature::NotEvenAFunction =>
- diag.span_err(i.span, "only functions may be used as tests"),
- BadTestSignature::WrongTypeSignature =>
- diag.span_err(i.span,
- "functions used as tests must have signature fn() -> ()"),
- BadTestSignature::NoArgumentsAllowed =>
- diag.span_err(i.span, "functions used as tests can not have any arguments"),
- BadTestSignature::ShouldPanicOnlyWithNoArgs =>
- diag.span_err(i.span, "functions using `#[should_panic]` must return `()`"),
- }
- false
- }
- }
- } else {
- false
- };
-
- has_test_attr && has_test_signature
-}
-
-fn is_bench_fn(cx: &TestCtxt, i: &ast::Item) -> bool {
- let has_bench_attr = attr::contains_name(&i.attrs, "bench");
-
- fn has_bench_signature(_cx: &TestCtxt, i: &ast::Item) -> bool {
- match i.node {
- ast::ItemKind::Fn(ref decl, _, _, _) => {
- // NB: inadequate check, but we're running
- // well before resolve, can't get too deep.
- decl.inputs.len() == 1
- }
- _ => false
- }
- }
-
- let has_bench_signature = has_bench_signature(cx, i);
-
- if has_bench_attr && !has_bench_signature {
- let diag = cx.span_diagnostic;
-
- diag.span_err(i.span, "functions used as benches must have signature \
- `fn(&mut Bencher) -> impl Termination`");
- }
-
- has_bench_attr && has_bench_signature
-}
-
-fn is_ignored(i: &ast::Item) -> bool {
- attr::contains_name(&i.attrs, "ignore")
-}
-
-fn is_allowed_fail(i: &ast::Item) -> bool {
- attr::contains_name(&i.attrs, "allow_fail")
-}
-
-fn should_panic(i: &ast::Item, cx: &TestCtxt) -> ShouldPanic {
- match attr::find_by_name(&i.attrs, "should_panic") {
- Some(attr) => {
- let sd = cx.span_diagnostic;
- if attr.is_value_str() {
- sd.struct_span_warn(
- attr.span(),
- "attribute must be of the form: \
- `#[should_panic]` or \
- `#[should_panic(expected = \"error message\")]`"
- ).note("Errors in this attribute were erroneously allowed \
- and will become a hard error in a future release.")
- .emit();
- return ShouldPanic::Yes(None);
- }
- match attr.meta_item_list() {
- // Handle #[should_panic]
- None => ShouldPanic::Yes(None),
- // Handle #[should_panic(expected = "foo")]
- Some(list) => {
- let msg = list.iter()
- .find(|mi| mi.check_name("expected"))
- .and_then(|mi| mi.meta_item())
- .and_then(|mi| mi.value_str());
- if list.len() != 1 || msg.is_none() {
- sd.struct_span_warn(
- attr.span(),
- "argument must be of the form: \
- `expected = \"error message\"`"
- ).note("Errors in this attribute were erroneously \
- allowed and will become a hard error in a \
- future release.").emit();
- ShouldPanic::Yes(None)
- } else {
- ShouldPanic::Yes(msg)
- }
- },
- }
- }
- None => ShouldPanic::No,
- }
-}
-
-/*
-
-We're going to be building a module that looks more or less like:
-
-mod __test {
- extern crate test (name = "test", vers = "...");
- fn main() {
- test::test_main_static(&::os::args()[], tests, test::Options::new())
- }
-
- static tests : &'static [test::TestDescAndFn] = &[
- ... the list of tests in the crate ...
- ];
-}
-
-*/
-
-fn mk_std(cx: &TestCtxt) -> P<ast::Item> {
- let id_test = Ident::from_str("test");
- let sp = ignored_span(cx, DUMMY_SP);
- let (vi, vis, ident) = if cx.is_libtest {
- (ast::ItemKind::Use(P(ast::UseTree {
- span: DUMMY_SP,
- prefix: path_node(vec![id_test]),
- kind: ast::UseTreeKind::Simple(None, ast::DUMMY_NODE_ID, ast::DUMMY_NODE_ID),
- })),
- ast::VisibilityKind::Public, keywords::Invalid.ident())
- } else {
- (ast::ItemKind::ExternCrate(None), ast::VisibilityKind::Inherited, id_test)
- };
- P(ast::Item {
- id: ast::DUMMY_NODE_ID,
- ident,
- node: vi,
- attrs: vec![],
- vis: dummy_spanned(vis),
- span: sp,
- tokens: None,
- })
-}
-
+/// Creates a function item for use as the main function of a test build.
+/// This function will call the `test_runner` as specified by the crate attribute
fn mk_main(cx: &mut TestCtxt) -> P<ast::Item> {
// Writing this out by hand with 'ignored_span':
// pub fn main() {
// #![main]
- // use std::slice::AsSlice;
- // test::test_main_static(::std::os::args().as_slice(), TESTS, test::Options::new());
+ // test::test_main_static(::std::os::args().as_slice(), &[..tests]);
// }
-
let sp = ignored_span(cx, DUMMY_SP);
let ecx = &cx.ext_cx;
-
- // test::test_main_static
- let test_main_path =
- ecx.path(sp, vec![Ident::from_str("test"), Ident::from_str("test_main_static")]);
+ let test_id = ecx.ident_of("test").gensym();
// test::test_main_static(...)
- let test_main_path_expr = ecx.expr_path(test_main_path);
- let tests_ident_expr = ecx.expr_ident(sp, Ident::from_str("TESTS"));
+ let mut test_runner = cx.test_runner.clone().unwrap_or(
+ ecx.path(sp, vec![
+ test_id, ecx.ident_of("test_main_static")
+ ]));
+
+ test_runner.span = sp;
+
+ let test_main_path_expr = ecx.expr_path(test_runner.clone());
let call_test_main = ecx.expr_call(sp, test_main_path_expr,
- vec![tests_ident_expr]);
+ vec![mk_tests_slice(cx)]);
let call_test_main = ecx.stmt_expr(call_test_main);
+
// #![main]
let main_meta = ecx.meta_word(sp, Symbol::intern("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")))
+ ));
+
// pub fn main() { ... }
let main_ret_ty = ecx.ty(sp, ast::TyKind::Tup(vec![]));
- let main_body = ecx.block(sp, vec![call_test_main]);
+
+ // If no test runner is provided we need to import the test crate
+ let main_body = if cx.test_runner.is_none() {
+ ecx.block(sp, vec![test_extern_stmt, call_test_main])
+ } else {
+ ecx.block(sp, vec![call_test_main])
+ };
+
let main = ast::ItemKind::Fn(ecx.fn_decl(vec![], ast::FunctionRetTy::Ty(main_ret_ty)),
ast::FnHeader::default(),
ast::Generics::default(),
main_body);
+
+ // Honor the reexport_test_harness_main attribute
+ let main_id = Ident::new(
+ cx.reexport_test_harness_main.unwrap_or(Symbol::gensym("main")),
+ sp);
+
P(ast::Item {
- ident: Ident::from_str("main"),
+ ident: main_id,
attrs: vec![main_attr],
id: ast::DUMMY_NODE_ID,
node: main,
span: sp,
tokens: None,
})
-}
-
-fn mk_test_module(cx: &mut TestCtxt) -> (P<ast::Item>, Option<P<ast::Item>>) {
- // Link to test crate
- let import = mk_std(cx);
-
- // A constant vector of test descriptors.
- let tests = mk_tests(cx);
-
- // The synthesized main function which will call the console test runner
- // with our list of tests
- let mainfn = mk_main(cx);
- let testmod = ast::Mod {
- inner: DUMMY_SP,
- items: vec![import, mainfn, tests],
- };
- let item_ = ast::ItemKind::Mod(testmod);
- let mod_ident = Ident::with_empty_ctxt(Symbol::gensym("__test"));
-
- let mut expander = cx.ext_cx.monotonic_expander();
- let item = expander.fold_item(P(ast::Item {
- id: ast::DUMMY_NODE_ID,
- ident: mod_ident,
- attrs: vec![],
- node: item_,
- vis: dummy_spanned(ast::VisibilityKind::Public),
- span: DUMMY_SP,
- tokens: None,
- })).pop().unwrap();
- let reexport = cx.reexport_test_harness_main.map(|s| {
- // building `use __test::main as <ident>;`
- let rename = Ident::with_empty_ctxt(s);
-
- let use_path = ast::UseTree {
- span: DUMMY_SP,
- prefix: path_node(vec![mod_ident, Ident::from_str("main")]),
- kind: ast::UseTreeKind::Simple(Some(rename), ast::DUMMY_NODE_ID, ast::DUMMY_NODE_ID),
- };
-
- expander.fold_item(P(ast::Item {
- id: ast::DUMMY_NODE_ID,
- ident: keywords::Invalid.ident(),
- attrs: vec![],
- node: ast::ItemKind::Use(P(use_path)),
- vis: dummy_spanned(ast::VisibilityKind::Inherited),
- span: DUMMY_SP,
- tokens: None,
- })).pop().unwrap()
- });
-
- debug!("Synthetic test module:\n{}\n", pprust::item_to_string(&item));
-
- (item, reexport)
-}
-
-fn nospan<T>(t: T) -> source_map::Spanned<T> {
- source_map::Spanned { node: t, span: DUMMY_SP }
-}
-
-fn path_node(ids: Vec<Ident>) -> ast::Path {
- ast::Path {
- span: DUMMY_SP,
- segments: ids.into_iter().map(|id| ast::PathSegment::from_ident(id)).collect(),
- }
}
fn path_name_i(idents: &[Ident]) -> String {
path_name
}
-fn mk_tests(cx: &TestCtxt) -> P<ast::Item> {
- // The vector of test_descs for this crate
- let test_descs = mk_test_descs(cx);
-
- // FIXME #15962: should be using quote_item, but that stringifies
- // __test_reexports, causing it to be reinterned, losing the
- // gensym information.
- let sp = ignored_span(cx, DUMMY_SP);
- let ecx = &cx.ext_cx;
- let struct_type = ecx.ty_path(ecx.path(sp, vec![ecx.ident_of("self"),
- ecx.ident_of("test"),
- ecx.ident_of("TestDescAndFn")]));
- let static_lt = ecx.lifetime(sp, keywords::StaticLifetime.ident());
- // &'static [self::test::TestDescAndFn]
- let static_type = ecx.ty_rptr(sp,
- ecx.ty(sp, ast::TyKind::Slice(struct_type)),
- Some(static_lt),
- ast::Mutability::Immutable);
- // static TESTS: $static_type = &[...];
- ecx.item_const(sp,
- ecx.ident_of("TESTS"),
- static_type,
- test_descs)
+/// Creates a slice containing every test like so:
+/// &[path::to::test1, path::to::test2]
+fn mk_tests_slice(cx: &TestCtxt) -> P<ast::Expr> {
+ debug!("building test vector from {} tests", cx.test_cases.len());
+ let ref ecx = cx.ext_cx;
+
+ ecx.expr_vec_slice(DUMMY_SP,
+ cx.test_cases.iter().map(|test| {
+ ecx.expr_addr_of(test.span,
+ ecx.expr_path(ecx.path(test.span, visible_path(cx, &test.path))))
+ }).collect())
}
-fn mk_test_descs(cx: &TestCtxt) -> P<ast::Expr> {
- debug!("building test vector from {} tests", cx.testfns.len());
-
- P(ast::Expr {
- id: ast::DUMMY_NODE_ID,
- node: ast::ExprKind::AddrOf(ast::Mutability::Immutable,
- P(ast::Expr {
- id: ast::DUMMY_NODE_ID,
- node: ast::ExprKind::Array(cx.testfns.iter().map(|test| {
- mk_test_desc_and_fn_rec(cx, test)
- }).collect()),
- span: DUMMY_SP,
- attrs: ThinVec::new(),
- })),
- span: DUMMY_SP,
- attrs: ThinVec::new(),
- })
-}
-
-fn mk_test_desc_and_fn_rec(cx: &TestCtxt, test: &Test) -> P<ast::Expr> {
- // FIXME #15962: should be using quote_expr, but that stringifies
- // __test_reexports, causing it to be reinterned, losing the
- // gensym information.
-
- let span = ignored_span(cx, test.span);
- let ecx = &cx.ext_cx;
- let self_id = ecx.ident_of("self");
- let test_id = ecx.ident_of("test");
-
- // creates self::test::$name
- let test_path = |name| {
- ecx.path(span, vec![self_id, test_id, ecx.ident_of(name)])
- };
- // creates $name: $expr
- let field = |name, expr| ecx.field_imm(span, ecx.ident_of(name), expr);
-
- // path to the #[test] function: "foo::bar::baz"
- let path_string = path_name_i(&test.path[..]);
-
- debug!("encoding {}", path_string);
-
- let name_expr = ecx.expr_str(span, Symbol::intern(&path_string));
-
- // self::test::StaticTestName($name_expr)
- let name_expr = ecx.expr_call(span,
- ecx.expr_path(test_path("StaticTestName")),
- vec![name_expr]);
-
- let ignore_expr = ecx.expr_bool(span, test.ignore);
- let should_panic_path = |name| {
- ecx.path(span, vec![self_id, test_id, ecx.ident_of("ShouldPanic"), ecx.ident_of(name)])
- };
- let fail_expr = match test.should_panic {
- ShouldPanic::No => ecx.expr_path(should_panic_path("No")),
- ShouldPanic::Yes(msg) => {
- match msg {
- Some(msg) => {
- let msg = ecx.expr_str(span, msg);
- let path = should_panic_path("YesWithMessage");
- ecx.expr_call(span, ecx.expr_path(path), vec![msg])
- }
- None => ecx.expr_path(should_panic_path("Yes")),
- }
- }
- };
- let allow_fail_expr = ecx.expr_bool(span, test.allow_fail);
-
- // self::test::TestDesc { ... }
- let desc_expr = ecx.expr_struct(
- span,
- test_path("TestDesc"),
- vec![field("name", name_expr),
- field("ignore", ignore_expr),
- field("should_panic", fail_expr),
- field("allow_fail", allow_fail_expr)]);
-
+/// Creates a path from the top-level __test module to the test via __test_reexports
+fn visible_path(cx: &TestCtxt, path: &[Ident]) -> Vec<Ident>{
let mut visible_path = vec![];
- if cx.features.extern_absolute_paths {
- visible_path.push(keywords::Crate.ident());
- }
match cx.toplevel_reexport {
Some(id) => visible_path.push(id),
None => {
- let diag = cx.span_diagnostic;
- diag.bug("expected to find top-level re-export name, but found None");
- }
- };
- visible_path.extend_from_slice(&test.path[..]);
-
- // Rather than directly give the test function to the test
- // harness, we create a wrapper like one of the following:
- //
- // || test::assert_test_result(real_function()) // for test
- // |b| test::assert_test_result(real_function(b)) // for bench
- //
- // this will coerce into a fn pointer that is specialized to the
- // actual return type of `real_function` (Typically `()`, but not always).
- let fn_expr = {
- // construct `real_function()` (this will be inserted into the overall expr)
- let real_function_expr = ecx.expr_path(ecx.path_global(span, visible_path));
- // construct path `test::assert_test_result`
- let assert_test_result = test_path("assert_test_result");
- if test.bench {
- // construct `|b| {..}`
- let b_ident = Ident::with_empty_ctxt(Symbol::gensym("b"));
- let b_expr = ecx.expr_ident(span, b_ident);
- ecx.lambda(
- span,
- vec![b_ident],
- // construct `assert_test_result(..)`
- ecx.expr_call(
- span,
- ecx.expr_path(assert_test_result),
- vec![
- // construct `real_function(b)`
- ecx.expr_call(
- span,
- real_function_expr,
- vec![b_expr],
- )
- ],
- ),
- )
- } else {
- // construct `|| {..}`
- ecx.lambda(
- span,
- vec![],
- // construct `assert_test_result(..)`
- ecx.expr_call(
- span,
- ecx.expr_path(assert_test_result),
- vec![
- // construct `real_function()`
- ecx.expr_call(
- span,
- real_function_expr,
- vec![],
- )
- ],
- ),
- )
+ cx.span_diagnostic.bug("expected to find top-level re-export name, but found None");
}
- };
-
- let variant_name = if test.bench { "StaticBenchFn" } else { "StaticTestFn" };
+ }
+ visible_path.extend_from_slice(path);
+ visible_path
+}
- // self::test::$variant_name($fn_expr)
- let testfn_expr = ecx.expr_call(span, ecx.expr_path(test_path(variant_name)), vec![fn_expr]);
+fn is_test_case(i: &ast::Item) -> bool {
+ attr::contains_name(&i.attrs, "rustc_test_marker")
+}
- // self::test::TestDescAndFn { ... }
- ecx.expr_struct(span,
- test_path("TestDescAndFn"),
- vec![field("desc", desc_expr),
- field("testfn", testfn_expr)])
+fn get_test_runner(sd: &errors::Handler, krate: &ast::Crate) -> Option<ast::Path> {
+ let test_attr = attr::find_by_name(&krate.attrs, "test_runner")?;
+ if let Some(meta_list) = test_attr.meta_item_list() {
+ if meta_list.len() != 1 {
+ sd.span_fatal(test_attr.span(),
+ "#![test_runner(..)] accepts exactly 1 argument").raise()
+ }
+ Some(meta_list[0].word().as_ref().unwrap().ident.clone())
+ } else {
+ sd.span_fatal(test_attr.span(),
+ "test_runner must be of the form #[test_runner(..)]").raise()
+ }
}
pub fn walk_arm<'a, V: Visitor<'a>>(visitor: &mut V, arm: &'a Arm) {
walk_list!(visitor, visit_pat, &arm.pats);
- walk_list!(visitor, visit_expr, &arm.guard);
+ if let Some(ref g) = &arm.guard {
+ match g {
+ Guard::If(ref e) => visitor.visit_expr(e),
+ }
+ }
visitor.visit_expr(&arm.body);
walk_list!(visitor, visit_attribute, &arm.attrs);
}
rustc_data_structures = { path = "../librustc_data_structures" }
rustc_target = { path = "../librustc_target" }
smallvec = { version = "0.6.5", features = ["union"] }
+log = "0.4"
use syntax_pos::{MultiSpan, Span, DUMMY_SP};
use errors::Applicability;
+use rustc_data_structures::fx::{FxHashMap, FxHashSet};
use std::borrow::Cow;
use std::collections::hash_map::Entry;
-use std::collections::{HashMap, HashSet};
#[derive(PartialEq)]
enum ArgumentType {
/// Unique format specs seen for each argument.
arg_unique_types: Vec<Vec<ArgumentType>>,
/// Map from named arguments to their resolved indices.
- names: HashMap<String, usize>,
+ names: FxHashMap<String, usize>,
/// The latest consecutive literal strings, or empty if there weren't any.
literal: String,
/// * `count_args`: `vec![Exact(0), Exact(5), Exact(3)]`
count_args: Vec<Position>,
/// Relative slot numbers for count arguments.
- count_positions: HashMap<usize, usize>,
+ count_positions: FxHashMap<usize, usize>,
/// Number of count slots assigned.
count_positions_count: usize,
fn parse_args(ecx: &mut ExtCtxt,
sp: Span,
tts: &[tokenstream::TokenTree])
- -> Option<(P<ast::Expr>, Vec<P<ast::Expr>>, HashMap<String, usize>)> {
+ -> Option<(P<ast::Expr>, Vec<P<ast::Expr>>, FxHashMap<String, usize>)> {
let mut args = Vec::<P<ast::Expr>>::new();
- let mut names = HashMap::<String, usize>::new();
+ let mut names = FxHashMap::<String, usize>::default();
let mut p = ecx.new_parser_from_tts(tts);
sp: Span,
efmt: P<ast::Expr>,
args: Vec<P<ast::Expr>>,
- names: HashMap<String, usize>,
+ names: FxHashMap<String, usize>,
append_newline: bool)
-> P<ast::Expr> {
// NOTE: this verbose way of initializing `Vec<Vec<ArgumentType>>` is because
curpiece: 0,
arg_index_map: Vec::new(),
count_args: Vec::new(),
- count_positions: HashMap::new(),
+ count_positions: FxHashMap::default(),
count_positions_count: 0,
count_args_index_offset: 0,
literal: String::new(),
// The set of foreign substitutions we've explained. This prevents spamming the user
// with `%d should be written as {}` over and over again.
- let mut explained = HashSet::new();
+ let mut explained = FxHashSet::default();
macro_rules! check_foreign {
($kind:ident) => {{
#![cfg_attr(not(stage0), feature(nll))]
#![cfg_attr(not(stage0), feature(infer_outlives_requirements))]
#![feature(str_escape)]
-
+#![feature(quote)]
#![feature(rustc_diagnostic_macros)]
extern crate fmt_macros;
extern crate rustc_target;
#[macro_use]
extern crate smallvec;
+#[macro_use]
+extern crate log;
mod diagnostics;
mod global_asm;
mod log_syntax;
mod trace_macros;
+mod test;
+mod test_case;
pub mod proc_macro_registrar;
use rustc_data_structures::sync::Lrc;
use syntax::ast;
-use syntax::ext::base::{MacroExpanderFn, NormalTT, NamedSyntaxExtension};
+use syntax::ext::base::{MacroExpanderFn, NormalTT, NamedSyntaxExtension, MultiModifier};
use syntax::ext::hygiene;
use syntax::symbol::Symbol;
enable_quotes: bool) {
deriving::register_builtin_derives(resolver);
+ {
+ let mut register_unshadowable = |name, ext| {
+ resolver.add_unshadowable_attr(ast::Ident::with_empty_ctxt(name), Lrc::new(ext));
+ };
+
+ register_unshadowable(Symbol::intern("test"),
+ MultiModifier(Box::new(test::expand_test)));
+
+ register_unshadowable(Symbol::intern("bench"),
+ MultiModifier(Box::new(test::expand_bench)));
+ }
+
let mut register = |name, ext| {
resolver.add_builtin(ast::Ident::with_empty_ctxt(name), Lrc::new(ext));
};
assert: assert::expand_assert,
}
+ register(Symbol::intern("test_case"), MultiModifier(Box::new(test_case::expand)));
+
// format_args uses `unstable` things internally.
register(Symbol::intern("format_args"),
NormalTT {
--- /dev/null
+// Copyright 2013 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+/// The expansion from a test function to the appropriate test struct for libtest
+/// Ideally, this code would be in libtest but for efficiency and error messages it lives here.
+
+use syntax::ext::base::*;
+use syntax::ext::build::AstBuilder;
+use syntax::ext::hygiene::{self, Mark, SyntaxContext};
+use syntax::attr;
+use syntax::ast;
+use syntax::print::pprust;
+use syntax::symbol::Symbol;
+use syntax_pos::{DUMMY_SP, Span};
+use syntax::source_map::{ExpnInfo, MacroAttribute};
+use std::iter;
+
+pub fn expand_test(
+ cx: &mut ExtCtxt,
+ attr_sp: Span,
+ _meta_item: &ast::MetaItem,
+ item: Annotatable,
+) -> Vec<Annotatable> {
+ expand_test_or_bench(cx, attr_sp, item, false)
+}
+
+pub fn expand_bench(
+ cx: &mut ExtCtxt,
+ attr_sp: Span,
+ _meta_item: &ast::MetaItem,
+ item: Annotatable,
+) -> Vec<Annotatable> {
+ expand_test_or_bench(cx, attr_sp, item, true)
+}
+
+pub fn expand_test_or_bench(
+ cx: &mut ExtCtxt,
+ attr_sp: Span,
+ item: Annotatable,
+ is_bench: bool
+) -> Vec<Annotatable> {
+ // If we're not in test configuration, remove the annotated item
+ if !cx.ecfg.should_test { return vec![]; }
+
+ let item =
+ if let Annotatable::Item(i) = item { i }
+ else {
+ cx.parse_sess.span_diagnostic.span_fatal(item.span(),
+ "#[test] attribute is only allowed on fn items").raise();
+ };
+
+ if let ast::ItemKind::Mac(_) = item.node {
+ cx.parse_sess.span_diagnostic.span_warn(item.span,
+ "#[test] attribute should not be used on macros. Use #[cfg(test)] instead.");
+ return vec![Annotatable::Item(item)];
+ }
+
+ // has_*_signature will report any errors in the type so compilation
+ // will fail. We shouldn't try to expand in this case because the errors
+ // would be spurious.
+ if (!is_bench && !has_test_signature(cx, &item)) ||
+ (is_bench && !has_bench_signature(cx, &item)) {
+ return vec![Annotatable::Item(item)];
+ }
+
+ let (sp, attr_sp) = {
+ let mark = Mark::fresh(Mark::root());
+ mark.set_expn_info(ExpnInfo {
+ call_site: DUMMY_SP,
+ def_site: None,
+ format: MacroAttribute(Symbol::intern("test")),
+ allow_internal_unstable: true,
+ allow_internal_unsafe: false,
+ local_inner_macros: false,
+ edition: hygiene::default_edition(),
+ });
+ (item.span.with_ctxt(SyntaxContext::empty().apply_mark(mark)),
+ attr_sp.with_ctxt(SyntaxContext::empty().apply_mark(mark)))
+ };
+
+ // Gensym "test" so we can extern crate without conflicting with any local names
+ let test_id = cx.ident_of("test").gensym();
+
+ // creates test::$name
+ let test_path = |name| {
+ cx.path(sp, vec![test_id, cx.ident_of(name)])
+ };
+
+ // creates test::$name
+ let should_panic_path = |name| {
+ cx.path(sp, vec![test_id, cx.ident_of("ShouldPanic"), cx.ident_of(name)])
+ };
+
+ // creates $name: $expr
+ let field = |name, expr| cx.field_imm(sp, cx.ident_of(name), expr);
+
+ let test_fn = if is_bench {
+ // A simple ident for a lambda
+ let b = cx.ident_of("b");
+
+ cx.expr_call(sp, cx.expr_path(test_path("StaticBenchFn")), vec![
+ // |b| self::test::assert_test_result(
+ cx.lambda1(sp,
+ cx.expr_call(sp, cx.expr_path(test_path("assert_test_result")), vec![
+ // super::$test_fn(b)
+ cx.expr_call(sp,
+ cx.expr_path(cx.path(sp, vec![item.ident])),
+ vec![cx.expr_ident(sp, b)])
+ ]),
+ b
+ )
+ // )
+ ])
+ } else {
+ cx.expr_call(sp, cx.expr_path(test_path("StaticTestFn")), vec![
+ // || {
+ cx.lambda0(sp,
+ // test::assert_test_result(
+ cx.expr_call(sp, cx.expr_path(test_path("assert_test_result")), vec![
+ // $test_fn()
+ cx.expr_call(sp, cx.expr_path(cx.path(sp, vec![item.ident])), vec![])
+ // )
+ ])
+ // }
+ )
+ // )
+ ])
+ };
+
+ let mut test_const = cx.item(sp, item.ident.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"))
+ ])),
+ // #[rustc_test_marker]
+ cx.attribute(attr_sp, cx.meta_word(attr_sp, Symbol::intern("rustc_test_marker")))
+ ],
+ // const $ident: test::TestDescAndFn =
+ ast::ItemKind::Const(cx.ty(sp, ast::TyKind::Path(None, test_path("TestDescAndFn"))),
+ // test::TestDescAndFn {
+ cx.expr_struct(sp, test_path("TestDescAndFn"), vec![
+ // desc: test::TestDesc {
+ field("desc", cx.expr_struct(sp, test_path("TestDesc"), vec![
+ // name: "path::to::test"
+ field("name", cx.expr_call(sp, cx.expr_path(test_path("StaticTestName")),
+ vec![
+ cx.expr_str(sp, Symbol::intern(&item_path(
+ // skip the name of the root module
+ &cx.current_expansion.module.mod_path[1..],
+ &item.ident
+ )))
+ ])),
+ // ignore: true | false
+ field("ignore", cx.expr_bool(sp, should_ignore(&item))),
+ // allow_fail: true | false
+ field("allow_fail", cx.expr_bool(sp, should_fail(&item))),
+ // should_panic: ...
+ field("should_panic", match should_panic(cx, &item) {
+ // test::ShouldPanic::No
+ ShouldPanic::No => cx.expr_path(should_panic_path("No")),
+ // test::ShouldPanic::Yes
+ ShouldPanic::Yes(None) => cx.expr_path(should_panic_path("Yes")),
+ // test::ShouldPanic::YesWithMessage("...")
+ ShouldPanic::Yes(Some(sym)) => cx.expr_call(sp,
+ cx.expr_path(should_panic_path("YesWithMessage")),
+ vec![cx.expr_str(sp, sym)]),
+ }),
+ // },
+ ])),
+ // testfn: test::StaticTestFn(...) | test::StaticBenchFn(...)
+ field("testfn", test_fn)
+ // }
+ ])
+ // }
+ ));
+ test_const = test_const.map(|mut tc| { tc.vis.node = ast::VisibilityKind::Public; tc});
+
+ // extern crate test as test_gensym
+ let test_extern = cx.item(sp,
+ test_id,
+ vec![],
+ ast::ItemKind::ExternCrate(Some(Symbol::intern("test")))
+ );
+
+ debug!("Synthetic test item:\n{}\n", pprust::item_to_string(&test_const));
+
+ vec![
+ // Access to libtest under a gensymed name
+ Annotatable::Item(test_extern),
+ // The generated test case
+ Annotatable::Item(test_const),
+ // The original item
+ Annotatable::Item(item)
+ ]
+}
+
+fn item_path(mod_path: &[ast::Ident], item_ident: &ast::Ident) -> String {
+ mod_path.iter().chain(iter::once(item_ident))
+ .map(|x| x.to_string()).collect::<Vec<String>>().join("::")
+}
+
+enum ShouldPanic {
+ No,
+ Yes(Option<Symbol>),
+}
+
+fn should_ignore(i: &ast::Item) -> bool {
+ attr::contains_name(&i.attrs, "ignore")
+}
+
+fn should_fail(i: &ast::Item) -> bool {
+ attr::contains_name(&i.attrs, "allow_fail")
+}
+
+fn should_panic(cx: &ExtCtxt, i: &ast::Item) -> ShouldPanic {
+ match attr::find_by_name(&i.attrs, "should_panic") {
+ Some(attr) => {
+ let ref sd = cx.parse_sess.span_diagnostic;
+ if attr.is_value_str() {
+ sd.struct_span_warn(
+ attr.span(),
+ "attribute must be of the form: \
+ `#[should_panic]` or \
+ `#[should_panic(expected = \"error message\")]`"
+ ).note("Errors in this attribute were erroneously allowed \
+ and will become a hard error in a future release.")
+ .emit();
+ return ShouldPanic::Yes(None);
+ }
+ match attr.meta_item_list() {
+ // Handle #[should_panic]
+ None => ShouldPanic::Yes(None),
+ // Handle #[should_panic(expected = "foo")]
+ Some(list) => {
+ let msg = list.iter()
+ .find(|mi| mi.check_name("expected"))
+ .and_then(|mi| mi.meta_item())
+ .and_then(|mi| mi.value_str());
+ if list.len() != 1 || msg.is_none() {
+ sd.struct_span_warn(
+ attr.span(),
+ "argument must be of the form: \
+ `expected = \"error message\"`"
+ ).note("Errors in this attribute were erroneously \
+ allowed and will become a hard error in a \
+ future release.").emit();
+ ShouldPanic::Yes(None)
+ } else {
+ ShouldPanic::Yes(msg)
+ }
+ },
+ }
+ }
+ None => ShouldPanic::No,
+ }
+}
+
+fn has_test_signature(cx: &ExtCtxt, i: &ast::Item) -> bool {
+ let has_should_panic_attr = attr::contains_name(&i.attrs, "should_panic");
+ let ref sd = cx.parse_sess.span_diagnostic;
+ if let ast::ItemKind::Fn(ref decl, ref header, ref generics, _) = i.node {
+ if header.unsafety == ast::Unsafety::Unsafe {
+ sd.span_err(
+ i.span,
+ "unsafe functions cannot be used for tests"
+ );
+ return false
+ }
+ if header.asyncness.is_async() {
+ sd.span_err(
+ i.span,
+ "async functions cannot be used for tests"
+ );
+ return false
+ }
+
+
+ // If the termination trait is active, the compiler will check that the output
+ // type implements the `Termination` trait as `libtest` enforces that.
+ let has_output = match decl.output {
+ ast::FunctionRetTy::Default(..) => false,
+ ast::FunctionRetTy::Ty(ref t) if t.node.is_unit() => false,
+ _ => true
+ };
+
+ if !decl.inputs.is_empty() {
+ sd.span_err(i.span, "functions used as tests can not have any arguments");
+ return false;
+ }
+
+ match (has_output, has_should_panic_attr) {
+ (true, true) => {
+ sd.span_err(i.span, "functions using `#[should_panic]` must return `()`");
+ false
+ },
+ (true, false) => if !generics.params.is_empty() {
+ sd.span_err(i.span,
+ "functions used as tests must have signature fn() -> ()");
+ false
+ } else {
+ true
+ },
+ (false, _) => true
+ }
+ } else {
+ sd.span_err(i.span, "only functions may be used as tests");
+ false
+ }
+}
+
+fn has_bench_signature(cx: &ExtCtxt, i: &ast::Item) -> bool {
+ let has_sig = if let ast::ItemKind::Fn(ref decl, _, _, _) = i.node {
+ // NB: inadequate check, but we're running
+ // well before resolve, can't get too deep.
+ decl.inputs.len() == 1
+ } else {
+ false
+ };
+
+ if !has_sig {
+ cx.parse_sess.span_diagnostic.span_err(i.span, "functions used as benches must have \
+ signature `fn(&mut Bencher) -> impl Termination`");
+ }
+
+ has_sig
+}
--- /dev/null
+
+// Copyright 2018 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+// #[test_case] is used by custom test authors to mark tests
+// When building for test, it needs to make the item public and gensym the name
+// Otherwise, we'll omit the item. This behavior means that any item annotated
+// with #[test_case] is never addressable.
+//
+// We mark item with an inert attribute "rustc_test_marker" which the test generation
+// logic will pick up on.
+
+use syntax::ext::base::*;
+use syntax::ext::build::AstBuilder;
+use syntax::ext::hygiene::{self, Mark, SyntaxContext};
+use syntax::ast;
+use syntax::source_map::respan;
+use syntax::symbol::Symbol;
+use syntax_pos::{DUMMY_SP, Span};
+use syntax::source_map::{ExpnInfo, MacroAttribute};
+use syntax::feature_gate;
+
+pub fn expand(
+ ecx: &mut ExtCtxt,
+ attr_sp: Span,
+ _meta_item: &ast::MetaItem,
+ anno_item: Annotatable
+) -> Vec<Annotatable> {
+ if !ecx.ecfg.enable_custom_test_frameworks() {
+ feature_gate::emit_feature_err(&ecx.parse_sess,
+ "custom_test_frameworks",
+ attr_sp,
+ feature_gate::GateIssue::Language,
+ feature_gate::EXPLAIN_CUSTOM_TEST_FRAMEWORKS);
+
+ return vec![anno_item];
+ }
+
+ if !ecx.ecfg.should_test { return vec![]; }
+
+ let sp = {
+ let mark = Mark::fresh(Mark::root());
+ mark.set_expn_info(ExpnInfo {
+ call_site: DUMMY_SP,
+ def_site: None,
+ format: MacroAttribute(Symbol::intern("test_case")),
+ allow_internal_unstable: true,
+ allow_internal_unsafe: false,
+ local_inner_macros: false,
+ edition: hygiene::default_edition(),
+ });
+ attr_sp.with_ctxt(SyntaxContext::empty().apply_mark(mark))
+ };
+
+ let mut item = anno_item.expect_item();
+
+ item = item.map(|mut item| {
+ item.vis = respan(item.vis.span, ast::VisibilityKind::Public);
+ item.ident = item.ident.gensym();
+ item.attrs.push(
+ ecx.attribute(sp,
+ ecx.meta_word(sp, Symbol::intern("rustc_test_marker")))
+ );
+ item
+ });
+
+ return vec![Annotatable::Item(item)]
+}
use symbol::Symbol;
use serialize::{Encodable, Decodable, Encoder, Decoder};
-use std::collections::HashMap;
-use rustc_data_structures::fx::FxHashSet;
+use rustc_data_structures::fx::{FxHashMap, FxHashSet};
use std::fmt;
/// A SyntaxContext represents a chain of macro expansions (represented by marks).
crate struct HygieneData {
marks: Vec<MarkData>,
syntax_contexts: Vec<SyntaxContextData>,
- markings: HashMap<(SyntaxContext, Mark, Transparency), SyntaxContext>,
+ markings: FxHashMap<(SyntaxContext, Mark, Transparency), SyntaxContext>,
default_edition: Edition,
}
opaque: SyntaxContext(0),
opaque_and_semitransparent: SyntaxContext(0),
}],
- markings: HashMap::new(),
+ markings: FxHashMap::default(),
default_edition: Edition::Edition2015,
}
}
}
pub fn clear_markings() {
- HygieneData::with(|data| data.markings = HashMap::new());
+ HygieneData::with(|data| data.markings = FxHashMap::default());
}
impl SyntaxContext {
impl<T: Write> OutputFormatter for JsonFormatter<T> {
fn write_run_start(&mut self, test_count: usize) -> io::Result<()> {
self.write_message(&*format!(
- r#"{{ "type": "suite", "event": "started", "test_count": "{}" }}"#,
+ r#"{{ "type": "suite", "event": "started", "test_count": {} }}"#,
test_count
))
}
\"allowed_fail\": {}, \
\"ignored\": {}, \
\"measured\": {}, \
- \"filtered_out\": \"{}\" }}",
+ \"filtered_out\": {} }}",
if state.failed == 0 { "ok" } else { "failed" },
state.passed,
state.failed + state.allowed_fail,
#![feature(panic_unwind)]
#![feature(staged_api)]
#![feature(termination_trait_lib)]
+#![feature(test)]
extern crate getopts;
#[cfg(any(unix, target_os = "cloudabi"))]
// a Vec<TestDescAndFn> is used in order to effect ownership-transfer
// semantics into parallel test runners, which in turn requires a Vec<>
// rather than a &[].
-pub fn test_main_static(tests: &[TestDescAndFn]) {
+pub fn test_main_static(tests: &[&TestDescAndFn]) {
let args = env::args().collect::<Vec<_>>();
let owned_tests = tests
.iter()
};
#[cfg(windows)]
- #[allow(bad_style)]
+ #[allow(nonstandard_style)]
fn num_cpus() -> usize {
#[repr(C)]
struct SYSTEM_INFO {
#[cfg(test)]
mod bench {
- use Bencher;
+ extern crate test;
+ use self::test::Bencher;
use stats::Stats;
#[bench]
// option. This file may not be copied, modified, or distributed
// except according to those terms.
-#![allow(bad_style)]
+#![allow(nonstandard_style)]
macro_rules! cfg_if {
( $( if #[cfg( $meta:meta )] { $($it1:item)* } else { $($it2:item)* } )* ) =>
-Subproject commit e19f07f5a6e5546ab4f6ea951e3c6b8627edeaa7
+Subproject commit 2a1cdeadd3ea8e1eba9cc681037b83f07332763b
return true;
}
+extern "C" typedef void (*LLVMRustModuleNameCallback)(void*, // payload
+ const char*, // importing module name
+ const char*); // imported module name
+
+// Calls `module_name_callback` for each module import done by ThinLTO.
+// The callback is provided with regular null-terminated C strings.
+extern "C" void
+LLVMRustGetThinLTOModuleImports(const LLVMRustThinLTOData *data,
+ LLVMRustModuleNameCallback module_name_callback,
+ void* callback_payload) {
+ for (const auto& importing_module : data->ImportLists) {
+ const std::string importing_module_id = importing_module.getKey().str();
+ const auto& imports = importing_module.getValue();
+ for (const auto& imported_module : imports) {
+ const std::string imported_module_id = imported_module.getKey().str();
+ module_name_callback(callback_payload,
+ importing_module_id.c_str(),
+ imported_module_id.c_str());
+ }
+ }
+}
+
// This struct and various functions are sort of a hack right now, but the
// problem is that we've got in-memory LLVM modules after we generate and
// optimize all codegen-units for one compilation in rustc. To be compatible
report_fatal_error("ThinLTO not available");
}
+extern "C" LLVMRustThinLTOModuleImports
+LLVMRustGetLLVMRustThinLTOModuleImports(const LLVMRustThinLTOData *Data) {
+ report_fatal_error("ThinLTO not available");
+}
+
extern "C" void
LLVMRustFreeThinLTOData(LLVMRustThinLTOData *Data) {
report_fatal_error("ThinLTO not available");
# If this file is modified, then llvm will be (optionally) cleaned and then rebuilt.
# The actual contents of this file do not matter, but to trigger a change on the
# build bots then the contents should be changed so git updates the mtime.
-2018-08-02
+2018-08-22
// NB: We do not expect *any* monomorphization to be generated here.
-#![feature(const_fn)]
+#![feature(min_const_fn)]
#![deny(dead_code)]
#![crate_type = "rlib"]
// compile-flags:-Clink-dead-code
-#![feature(const_fn)]
+#![feature(min_const_fn)]
#![crate_type = "rlib"]
// This test makes sure that, when -Clink-dead-code is specified, we generate
#[plugin_registrar]
pub fn plugin_registrar(reg: &mut Registry) {
reg.register_late_lint_pass(box Pass);
- reg.register_lint_group("lint_me", vec![TEST_LINT, PLEASE_LINT]);
+ reg.register_lint_group("lint_me", None, vec![TEST_LINT, PLEASE_LINT]);
}
// option. This file may not be copied, modified, or distributed
// except according to those terms.
-#![feature(const_fn)]
+#![feature(min_const_fn)]
#![feature(cfg_target_thread_local, thread_local_internals)]
// On platforms *without* `#[thread_local]`, use
#![feature(rustc_attrs)]
#![crate_type = "rlib"]
-#![rustc_partition_codegened(module="issue_49595-__test", cfg="cfail2")]
+#![rustc_partition_codegened(module="issue_49595-tests", cfg="cfail2")]
#![rustc_partition_codegened(module="issue_49595-lit_test", cfg="cfail3")]
mod tests {
- #[cfg_attr(not(cfail1), ignore)]
- #[test]
+ #[cfg_attr(not(cfail1), test)]
fn test() {
}
}
// compile-flags: -Z lower_128bit_ops=yes -C debug_assertions=yes
-#![feature(const_fn)]
+#![feature(min_const_fn)]
static TEST_SIGNED: i128 = const_signed(-222);
static TEST_UNSIGNED: u128 = const_unsigned(200);
// ignore-emscripten
-// compile-flags: -Z lower_128bit_ops=yes -C debug_assertions=no
+// compile-flags: -Z lower_128bit_ops=yes -C debug_assertions=no -O
-#![feature(const_fn)]
+#![feature(min_const_fn)]
static TEST_SIGNED: i128 = const_signed(-222);
static TEST_UNSIGNED: u128 = const_unsigned(200);
// END RUST SOURCE
// START rustc.const_signed.Lower128Bit.after.mir
-// _8 = _1;
-// _9 = const compiler_builtins::int::addsub::rust_i128_addo(move _8, const 1i128) -> bb10;
-// ...
-// _7 = move (_9.0: i128);
-// ...
-// _10 = const compiler_builtins::int::addsub::rust_i128_subo(move _7, const 2i128) -> bb11;
-// ...
-// _6 = move (_10.0: i128);
-// ...
-// _11 = const compiler_builtins::int::mul::rust_i128_mulo(move _6, const 3i128) -> bb12;
-// ...
-// _5 = move (_11.0: i128);
-// ...
-// _12 = Eq(const 4i128, const 0i128);
-// assert(!move _12, "attempt to divide by zero") -> bb4;
-// ...
-// _13 = Eq(const 4i128, const -1i128);
-// _14 = Eq(_5, const -170141183460469231731687303715884105728i128);
-// _15 = BitAnd(move _13, move _14);
-// assert(!move _15, "attempt to divide with overflow") -> bb5;
-// ...
-// _4 = const compiler_builtins::int::sdiv::rust_i128_div(move _5, const 4i128) -> bb13;
-// ...
-// _17 = Eq(const 5i128, const -1i128);
-// _18 = Eq(_4, const -170141183460469231731687303715884105728i128);
-// _19 = BitAnd(move _17, move _18);
-// assert(!move _19, "attempt to calculate the remainder with overflow") -> bb7;
-// ...
-// _3 = const compiler_builtins::int::sdiv::rust_i128_rem(move _4, const 5i128) -> bb15;
-// ...
-// _2 = move (_20.0: i128);
-// ...
-// _23 = const 7i32 as u128 (Misc);
-// _21 = const compiler_builtins::int::shift::rust_i128_shro(move _2, move _23) -> bb16;
-// ...
-// _0 = move (_21.0: i128);
-// ...
-// assert(!move (_9.1: bool), "attempt to add with overflow") -> bb1;
-// ...
-// assert(!move (_10.1: bool), "attempt to subtract with overflow") -> bb2;
-// ...
-// assert(!move (_11.1: bool), "attempt to multiply with overflow") -> bb3;
-// ...
-// _16 = Eq(const 5i128, const 0i128);
-// assert(!move _16, "attempt to calculate the remainder with a divisor of zero") -> bb6;
-// ...
-// assert(!move (_20.1: bool), "attempt to shift left with overflow") -> bb8;
-// ...
-// _22 = const 6i32 as u128 (Misc);
-// _20 = const compiler_builtins::int::shift::rust_i128_shlo(move _3, move _22) -> bb14;
-// ...
-// assert(!move (_21.1: bool), "attempt to shift right with overflow") -> bb9;
+// _7 = const compiler_builtins::int::addsub::rust_i128_add(move _8, const 1i128) -> bb7;
+// ...
+// _10 = Eq(const 4i128, const -1i128);
+// _11 = Eq(_5, const -170141183460469231731687303715884105728i128);
+// _12 = BitAnd(move _10, move _11);
+// assert(!move _12, "attempt to divide with overflow") -> bb2;
+// ...
+// _4 = const compiler_builtins::int::sdiv::rust_i128_div(move _5, const 4i128) -> bb8;
+// ...
+// _14 = Eq(const 5i128, const -1i128);
+// _15 = Eq(_4, const -170141183460469231731687303715884105728i128);
+// _16 = BitAnd(move _14, move _15);
+// assert(!move _16, "attempt to calculate the remainder with overflow") -> bb4;
+// ...
+// _3 = const compiler_builtins::int::sdiv::rust_i128_rem(move _4, const 5i128) -> bb11;
+// ...
+// _9 = Eq(const 4i128, const 0i128);
+// assert(!move _9, "attempt to divide by zero") -> bb1;
+// ...
+// _5 = const compiler_builtins::int::mul::rust_i128_mul(move _6, const 3i128) -> bb5;
+// ...
+// _6 = const compiler_builtins::int::addsub::rust_i128_sub(move _7, const 2i128) -> bb6;
+// ...
+// _13 = Eq(const 5i128, const 0i128);
+// assert(!move _13, "attempt to calculate the remainder with a divisor of zero") -> bb3;
+// ...
+// _17 = const 7i32 as u32 (Misc);
+// _0 = const compiler_builtins::int::shift::rust_i128_shr(move _2, move _17) -> bb9;
+// ...
+// _18 = const 6i32 as u32 (Misc);
+// _2 = const compiler_builtins::int::shift::rust_i128_shl(move _3, move _18) -> bb10;
// END rustc.const_signed.Lower128Bit.after.mir
// START rustc.const_unsigned.Lower128Bit.after.mir
-// _8 = _1;
-// _9 = const compiler_builtins::int::addsub::rust_u128_addo(move _8, const 1u128) -> bb8;
-// ...
-// _7 = move (_9.0: u128);
-// ...
-// _10 = const compiler_builtins::int::addsub::rust_u128_subo(move _7, const 2u128) -> bb9;
-// ...
-// _6 = move (_10.0: u128);
-// ...
-// _11 = const compiler_builtins::int::mul::rust_u128_mulo(move _6, const 3u128) -> bb10;
-// ...
-// _5 = move (_11.0: u128);
-// ...
-// _12 = Eq(const 4u128, const 0u128);
-// assert(!move _12, "attempt to divide by zero") -> bb4;
-// ...
-// _4 = const compiler_builtins::int::udiv::rust_u128_div(move _5, const 4u128) -> bb11;
-// ...
-// _3 = const compiler_builtins::int::udiv::rust_u128_rem(move _4, const 5u128) -> bb13;
-// ...
-// _2 = move (_14.0: u128);
-// ...
-// _17 = const 7i32 as u128 (Misc);
-// _15 = const compiler_builtins::int::shift::rust_u128_shro(move _2, move _17) -> bb14;
-// ...
-// _0 = move (_15.0: u128);
-// ...
-// assert(!move (_9.1: bool), "attempt to add with overflow") -> bb1;
-// ...
-// assert(!move (_10.1: bool), "attempt to subtract with overflow") -> bb2;
-// ...
-// assert(!move (_11.1: bool), "attempt to multiply with overflow") -> bb3;
-// ...
-// _13 = Eq(const 5u128, const 0u128);
-// assert(!move _13, "attempt to calculate the remainder with a divisor of zero") -> bb5;
-// ...
-// assert(!move (_14.1: bool), "attempt to shift left with overflow") -> bb6;
-// ...
-// _16 = const 6i32 as u128 (Misc);
-// _14 = const compiler_builtins::int::shift::rust_u128_shlo(move _3, move _16) -> bb12;
-// ...
-// assert(!move (_15.1: bool), "attempt to shift right with overflow") -> bb7;
+// _8 = _1;
+// _7 = const compiler_builtins::int::addsub::rust_u128_add(move _8, const 1u128) -> bb5;
+// ...
+// _4 = const compiler_builtins::int::udiv::rust_u128_div(move _5, const 4u128) -> bb6;
+// ...
+// _3 = const compiler_builtins::int::udiv::rust_u128_rem(move _4, const 5u128) -> bb9;
+// ...
+// _9 = Eq(const 4u128, const 0u128);
+// assert(!move _9, "attempt to divide by zero") -> bb1;
+// ...
+// _5 = const compiler_builtins::int::mul::rust_u128_mul(move _6, const 3u128) -> bb3;
+// ...
+// _6 = const compiler_builtins::int::addsub::rust_u128_sub(move _7, const 2u128) -> bb4;
+// ...
+// _10 = Eq(const 5u128, const 0u128);
+// assert(!move _10, "attempt to calculate the remainder with a divisor of zero") -> bb2;
+// ...
+// return;
+// ...
+// _11 = const 7i32 as u32 (Misc);
+// _0 = const compiler_builtins::int::shift::rust_u128_shr(move _2, move _11) -> bb7;
+// ...
+// _12 = const 6i32 as u32 (Misc);
+// _2 = const compiler_builtins::int::shift::rust_u128_shl(move _3, move _12) -> bb8;
+
// END rustc.const_unsigned.Lower128Bit.after.mir
// START rustc.test_signed.Lower128Bit.after.mir
// error-pattern:index out of bounds: the len is 5 but the index is 5
-#![feature(const_fn)]
+#![feature(min_const_fn)]
const fn test(x: usize) -> i32 {
[42;5][x]
}
-{ "type": "suite", "event": "started", "test_count": "4" }
+{ "type": "suite", "event": "started", "test_count": 4 }
{ "type": "test", "event": "started", "name": "a" }
{ "type": "test", "name": "a", "event": "ok" }
{ "type": "test", "event": "started", "name": "b" }
{ "type": "test", "name": "c", "event": "ok" }
{ "type": "test", "event": "started", "name": "d" }
{ "type": "test", "name": "d", "event": "ignored" }
-{ "type": "suite", "event": "failed", "passed": 2, "failed": 1, "allowed_fail": 0, "ignored": 1, "measured": 0, "filtered_out": "0" }
+{ "type": "suite", "event": "failed", "passed": 2, "failed": 1, "allowed_fail": 0, "ignored": 1, "measured": 0, "filtered_out": 0 }
// Crate that exports a const fn. Used for testing cross-crate.
#![crate_type="rlib"]
-#![feature(const_fn)]
+#![feature(min_const_fn)]
pub const fn foo() -> usize { 22 }
// option. This file may not be copied, modified, or distributed
// except according to those terms.
-#![feature(const_fn)]
+#![feature(min_const_fn)]
#![crate_type = "lib"]
const fn foo(i: i32) -> i32 {
// option. This file may not be copied, modified, or distributed
// except according to those terms.
-#![feature(const_fn)]
+#![feature(min_const_fn)]
const fn add(x: usize, y: usize) -> usize {
x + y
// option. This file may not be copied, modified, or distributed
// except according to those terms.
-#![feature(const_fn)]
+#![feature(min_const_fn)]
struct Foo { value: u32 }
// Test a call whose argument is the result of another call.
-#![feature(const_fn)]
+#![feature(min_const_fn)]
const fn sub(x: u32, y: u32) -> u32 {
x - y
--- /dev/null
+// Copyright 2018 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+#![feature(const_int_conversion, const_int_ops, reverse_bits, int_to_from_bytes)]
+
+const REVERSE: u32 = 0x12345678_u32.reverse_bits();
+const FROM_BE_BYTES: i32 = i32::from_be_bytes([0x12, 0x34, 0x56, 0x78]);
+const FROM_LE_BYTES: i32 = i32::from_le_bytes([0x12, 0x34, 0x56, 0x78]);
+const FROM_NE_BYTES: i32 = i32::from_be(i32::from_ne_bytes([0x80, 0, 0, 0]));
+const TO_BE_BYTES: [u8; 4] = 0x12_34_56_78_i32.to_be_bytes();
+const TO_LE_BYTES: [u8; 4] = 0x12_34_56_78_i32.to_le_bytes();
+const TO_NE_BYTES: [u8; 4] = i32::min_value().to_be().to_ne_bytes();
+
+fn ident<T>(ident: T) -> T {
+ ident
+}
+
+fn main() {
+ assert_eq!(REVERSE, ident(0x1e6a2c48));
+ assert_eq!(FROM_BE_BYTES, ident(0x12_34_56_78));
+ assert_eq!(FROM_LE_BYTES, ident(0x78_56_34_12));
+ assert_eq!(FROM_NE_BYTES, ident(i32::min_value()));
+ assert_eq!(TO_BE_BYTES, ident([0x12, 0x34, 0x56, 0x78]));
+ assert_eq!(TO_LE_BYTES, ident([0x78, 0x56, 0x34, 0x12]));
+ assert_eq!(TO_NE_BYTES, ident([0x80, 0, 0, 0]));
+}
+
--- /dev/null
+// Copyright 2018 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+#![feature(const_int_overflowing)]
+
+const ADD_A: (u32, bool) = 5u32.overflowing_add(2);
+const ADD_B: (u32, bool) = u32::max_value().overflowing_add(1);
+
+const SUB_A: (u32, bool) = 5u32.overflowing_sub(2);
+const SUB_B: (u32, bool) = 0u32.overflowing_sub(1);
+
+const MUL_A: (u32, bool) = 5u32.overflowing_mul(2);
+const MUL_B: (u32, bool) = 1_000_000_000u32.overflowing_mul(10);
+
+const SHL_A: (u32, bool) = 0x1u32.overflowing_shl(4);
+const SHL_B: (u32, bool) = 0x1u32.overflowing_shl(132);
+
+const SHR_A: (u32, bool) = 0x10u32.overflowing_shr(4);
+const SHR_B: (u32, bool) = 0x10u32.overflowing_shr(132);
+
+fn ident<T>(ident: T) -> T {
+ ident
+}
+
+fn main() {
+ assert_eq!(ADD_A, ident((7, false)));
+ assert_eq!(ADD_B, ident((0, true)));
+
+ assert_eq!(SUB_A, ident((3, false)));
+ assert_eq!(SUB_B, ident((u32::max_value(), true)));
+
+ assert_eq!(MUL_A, ident((10, false)));
+ assert_eq!(MUL_B, ident((1410065408, true)));
+
+ assert_eq!(SHL_A, ident((0x10, false)));
+ assert_eq!(SHL_B, ident((0x10, true)));
+
+ assert_eq!(SHR_A, ident((0x1, false)));
+ assert_eq!(SHR_B, ident((0x1, true)));
+}
--- /dev/null
+// Copyright 2018 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+#![feature(const_int_rotate)]
+
+const LEFT: u32 = 0x10000b3u32.rotate_left(8);
+const RIGHT: u32 = 0xb301u32.rotate_right(8);
+
+fn ident<T>(ident: T) -> T {
+ ident
+}
+
+fn main() {
+ assert_eq!(LEFT, ident(0xb301));
+ assert_eq!(RIGHT, ident(0x10000b3));
+}
--- /dev/null
+// Copyright 2018 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+#![feature(const_int_sign)]
+
+const NEGATIVE_A: bool = (-10i32).is_negative();
+const NEGATIVE_B: bool = 10i32.is_negative();
+const POSITIVE_A: bool= (-10i32).is_positive();
+const POSITIVE_B: bool= 10i32.is_positive();
+
+fn main() {
+ assert!(NEGATIVE_A);
+ assert!(!NEGATIVE_B);
+ assert!(!POSITIVE_A);
+ assert!(POSITIVE_B);
+}
--- /dev/null
+// Copyright 2018 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+#![feature(const_int_wrapping)]
+
+const ADD_A: u32 = 200u32.wrapping_add(55);
+const ADD_B: u32 = 200u32.wrapping_add(u32::max_value());
+
+const SUB_A: u32 = 100u32.wrapping_sub(100);
+const SUB_B: u32 = 100u32.wrapping_sub(u32::max_value());
+
+const MUL_A: u8 = 10u8.wrapping_mul(12);
+const MUL_B: u8 = 25u8.wrapping_mul(12);
+
+const SHL_A: u32 = 1u32.wrapping_shl(7);
+const SHL_B: u32 = 1u32.wrapping_shl(128);
+
+const SHR_A: u32 = 128u32.wrapping_shr(7);
+const SHR_B: u32 = 128u32.wrapping_shr(128);
+
+fn ident<T>(ident: T) -> T {
+ ident
+}
+
+fn main() {
+ assert_eq!(ADD_A, ident(255));
+ assert_eq!(ADD_B, ident(199));
+
+ assert_eq!(SUB_A, ident(0));
+ assert_eq!(SUB_B, ident(101));
+
+ assert_eq!(MUL_A, ident(120));
+ assert_eq!(MUL_B, ident(44));
+
+ assert_eq!(SHL_A, ident(128));
+ assert_eq!(SHL_B, ident(1));
+
+ assert_eq!(SHR_A, ident(1));
+ assert_eq!(SHR_B, ident(128));
+}
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.
-#![feature(const_fn)]
+#![feature(min_const_fn)]
struct A;
// option. This file may not be copied, modified, or distributed
// except according to those terms.
-#![feature(const_fn)]
+#![feature(min_const_fn)]
#[derive(PartialEq, Eq)]
enum Cake {
// option. This file may not be copied, modified, or distributed
// except according to those terms.
-#![feature(const_fn)]
+#![feature(min_const_fn)]
use std::mem;
// A quick test of 'unsafe const fn' functionality
-#![feature(const_fn)]
+#![feature(min_const_fn)]
const unsafe fn dummy(v: u32) -> u32 {
!v
// option. This file may not be copied, modified, or distributed
// except according to those terms.
-#![feature(const_fn)]
+#![feature(min_const_fn)]
const FOO: isize = 10;
const BAR: isize = 3;
// https://github.com/rust-lang/rust/issues/48279
-#![feature(const_fn)]
+#![feature(min_const_fn)]
#[derive(PartialEq, Eq)]
pub struct NonZeroU32 {
// https://github.com/rust-lang/rust/issues/46114
-#![feature(const_fn)]
+#![feature(min_const_fn)]
#[derive(Eq, PartialEq)]
struct A { value: u32 }
// https://github.com/rust-lang/rust/issues/43754
-#![feature(const_fn)]
+#![feature(min_const_fn)]
const fn foo(x: usize) -> usize {
return x;
}
// ignore-wasm32
// ignore-emscripten
+// compile-flags: -C debug_assertions=yes
+
#![feature(const_fn, libc)]
#![allow(const_err)]
use std::env;
use std::process::{Command, Stdio};
-// this will panic in debug mode
+// this will panic in debug mode and overflow in release mode
const fn bar() -> usize { 0 - 1 }
fn foo() {
// option. This file may not be copied, modified, or distributed
// except according to those terms.
-#![feature(const_fn)]
+#![feature(min_const_fn)]
fn main() {}
// option. This file may not be copied, modified, or distributed
// except according to those terms.
-#![feature(const_fn)]
+#![feature(min_const_fn)]
struct A {
field: usize,
}
// option. This file may not be copied, modified, or distributed
// except according to those terms.
-#![feature(const_fn)]
+#![feature(min_const_fn)]
const fn foo() -> *const i8 {
b"foo" as *const _ as *const i8
// option. This file may not be copied, modified, or distributed
// except according to those terms.
-#![feature(const_fn)]
+#![feature(min_const_fn)]
const fn foo() -> i64 {
3
--- /dev/null
+// Copyright 2018 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+#![feature(step_trait)]
+
+use std::iter::Step;
+
+#[cfg(target_pointer_width = "16")]
+fn main() {
+ assert!(Step::steps_between(&0u32, &::std::u32::MAX).is_none());
+}
+
+#[cfg(any(target_pointer_width = "32", target_pointer_width = "64"))]
+fn main() {
+ assert!(Step::steps_between(&0u32, &::std::u32::MAX).is_some());
+}
// option. This file may not be copied, modified, or distributed
// except according to those terms.
-#![feature(const_fn)]
+#![feature(min_const_fn)]
const fn f() -> usize {
5
}
--- /dev/null
+// Copyright 2018 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+// edition:2018
+
+#![feature(uniform_paths)]
+
+use std;
+
+mod foo {
+ pub use std as my_std;
+}
+
+mod bar {
+ pub use std::{self};
+}
+
+fn main() {
+ self::std::io::stdout();
+ foo::my_std::io::stdout();
+ bar::std::io::stdout();
+}
match enum_unit {
_ => "no error with only wildcard"
};
+
+
+ // issue #53549 - check that variant constructors can still be called normally.
+
+ match NonExhaustiveEnum::Unit {
+ NonExhaustiveEnum::Unit => {},
+ _ => {}
+ };
+
+ match NonExhaustiveEnum::Tuple(2) {
+ NonExhaustiveEnum::Tuple(2) => {},
+ _ => {}
+ };
+
+ match (NonExhaustiveEnum::Unit {}) {
+ NonExhaustiveEnum::Unit {} => {},
+ _ => {}
+ };
+
+ match (NonExhaustiveEnum::Tuple { 0: 2 }) {
+ NonExhaustiveEnum::Tuple { 0: 2 } => {},
+ _ => {}
+ };
+
+ match (NonExhaustiveEnum::Struct { field: 2 }) {
+ NonExhaustiveEnum::Struct { field: 2 } => {},
+ _ => {}
+ };
+
}
}
#[cfg(any(target_arch = "x86", target_arch = "x86_64"))]
-#[allow(bad_style)]
+#[allow(nonstandard_style)]
mod test {
// An SSE type
#[repr(simd)]
--- /dev/null
+// Copyright 2018 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+#![feature(try_from)]
+#![allow(unused_must_use)]
+
+use std::convert::TryFrom;
+use std::num::TryFromIntError;
+
+fn main() {
+ let x: u32 = 125;
+ let y: Result<u8, TryFromIntError> = u8::try_from(x);
+ y == Ok(125);
+}
// compile-flags: -Cmetadata=aux
-#![feature(const_fn)]
+#![feature(min_const_fn)]
pub const fn foo() {}
pub const unsafe fn bar() {}
// option. This file may not be copied, modified, or distributed
// except according to those terms.
-#![feature(const_fn)]
+#![feature(min_const_fn)]
#![crate_name = "foo"]
// @has foo/fn.bar.html
#![crate_type="lib"]
-#![feature(const_fn)]
+#![feature(min_const_fn)]
pub struct Foo;
--- /dev/null
+// Copyright 2012-2014 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+// ignore-tidy-linelength
+
+// compile-flags:-Z unstable-options --extern-html-root-url core=https://example.com/core/0.1.0
+
+// @has extern_html_root_url/index.html
+// @has - '//a/@href' 'https://example.com/core/0.1.0/core/iter/index.html'
+#[doc(no_inline)]
+pub use std::iter;
pub trait SoAmbiguous {}
-#[allow(bad_style)]
+#[allow(nonstandard_style)]
pub fn SoAmbiguous() {}
#[plugin_registrar]
pub fn plugin_registrar(reg: &mut Registry) {
reg.register_late_lint_pass(box Pass);
- reg.register_lint_group("lint_me", vec![TEST_LINT, PLEASE_LINT]);
+ reg.register_lint_group("lint_me", None, vec![TEST_LINT, PLEASE_LINT]);
}
use rustc_plugin::Registry;
use syntax::ast;
declare_tool_lint!(pub clippy::TEST_LINT, Warn, "Warn about stuff");
+declare_tool_lint!(pub clippy::TEST_GROUP, Warn, "Warn about other stuff");
struct Pass;
impl LintPass for Pass {
fn get_lints(&self) -> LintArray {
- lint_array!(TEST_LINT)
+ lint_array!(TEST_LINT, TEST_GROUP)
}
}
if it.ident.name == "lintme" {
cx.span_lint(TEST_LINT, it.span, "item is named 'lintme'");
}
+ if it.ident.name == "lintmetoo" {
+ cx.span_lint(TEST_GROUP, it.span, "item is named 'lintmetoo'");
+ }
}
}
#[plugin_registrar]
pub fn plugin_registrar(reg: &mut Registry) {
reg.register_early_lint_pass(box Pass);
+ reg.register_lint_group("clippy::group", Some("clippy_group"), vec![TEST_LINT, TEST_GROUP]);
}
--- /dev/null
+// Copyright 2018 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+// run-pass
+// aux-build:lint_tool_test.rs
+// ignore-stage1
+// compile-flags: -A test-lint
+
+#![feature(plugin)]
+#![warn(unused)]
+#![plugin(lint_tool_test)]
+
+fn lintme() { }
+
+pub fn main() {
+}
--- /dev/null
+warning: lint name `test_lint` is deprecated and does not have an effect anymore. Use: clippy::test_lint
+ |
+ = note: requested on the command line with `-A test_lint`
+
+warning: item is named 'lintme'
+ --> $DIR/lint_tool_cmdline_allow.rs:20:1
+ |
+LL | fn lintme() { }
+ | ^^^^^^^^^^^^^^^
+ |
+ = note: #[warn(clippy::test_lint)] on by default
+
+warning: function is never used: `lintme`
+ --> $DIR/lint_tool_cmdline_allow.rs:20:1
+ |
+LL | fn lintme() { }
+ | ^^^^^^^^^^^
+ |
+note: lint level defined here
+ --> $DIR/lint_tool_cmdline_allow.rs:17:9
+ |
+LL | #![warn(unused)]
+ | ^^^^^^
+ = note: #[warn(dead_code)] implied by #[warn(unused)]
+
// option. This file may not be copied, modified, or distributed
// except according to those terms.
-// run-pass
// aux-build:lint_tool_test.rs
// ignore-stage1
+// compile-flags: --cfg foo
#![feature(plugin)]
#![feature(tool_lints)]
#![plugin(lint_tool_test)]
#![allow(dead_code)]
+#![cfg_attr(foo, warn(test_lint))]
+//~^ WARNING lint name `test_lint` is deprecated and may not have an effect in the future
+//~^^ WARNING lint name `test_lint` is deprecated and may not have an effect in the future
+#![deny(clippy_group)]
+//~^ WARNING lint name `clippy_group` is deprecated and may not have an effect in the future
-fn lintme() { } //~ WARNING item is named 'lintme'
+fn lintme() { } //~ ERROR item is named 'lintme'
+
+#[allow(clippy::group)]
+fn lintmetoo() {}
#[allow(clippy::test_lint)]
pub fn main() {
fn lintme() { }
+ fn lintmetoo() { } //~ ERROR item is named 'lintmetoo'
+}
+
+#[allow(test_group)]
+//~^ WARNING lint name `test_group` is deprecated and may not have an effect in the future
+#[deny(this_lint_does_not_exist)] //~ WARNING unknown lint: `this_lint_does_not_exist`
+fn hello() {
+ fn lintmetoo() { }
}
-warning: item is named 'lintme'
- --> $DIR/lint_tool_test.rs:19:1
+warning: lint name `test_lint` is deprecated and may not have an effect in the future. Also `cfg_attr(cargo-clippy)` won't be necessary anymore
+ --> $DIR/lint_tool_test.rs:18:23
|
-LL | fn lintme() { } //~ WARNING item is named 'lintme'
+LL | #![cfg_attr(foo, warn(test_lint))]
+ | ^^^^^^^^^ help: change it to: `clippy::test_lint`
+ |
+ = note: #[warn(renamed_and_removed_lints)] on by default
+
+warning: lint name `clippy_group` is deprecated and may not have an effect in the future. Also `cfg_attr(cargo-clippy)` won't be necessary anymore
+ --> $DIR/lint_tool_test.rs:21:9
+ |
+LL | #![deny(clippy_group)]
+ | ^^^^^^^^^^^^ help: change it to: `clippy::group`
+
+warning: lint name `test_group` is deprecated and may not have an effect in the future. Also `cfg_attr(cargo-clippy)` won't be necessary anymore
+ --> $DIR/lint_tool_test.rs:35:9
+ |
+LL | #[allow(test_group)]
+ | ^^^^^^^^^^ help: change it to: `clippy::test_group`
+
+warning: unknown lint: `this_lint_does_not_exist`
+ --> $DIR/lint_tool_test.rs:37:8
+ |
+LL | #[deny(this_lint_does_not_exist)] //~ WARNING unknown lint: `this_lint_does_not_exist`
+ | ^^^^^^^^^^^^^^^^^^^^^^^^
+ |
+ = note: #[warn(unknown_lints)] on by default
+
+warning: lint name `test_lint` is deprecated and may not have an effect in the future. Also `cfg_attr(cargo-clippy)` won't be necessary anymore
+ --> $DIR/lint_tool_test.rs:18:23
+ |
+LL | #![cfg_attr(foo, warn(test_lint))]
+ | ^^^^^^^^^ help: change it to: `clippy::test_lint`
+
+error: item is named 'lintme'
+ --> $DIR/lint_tool_test.rs:24:1
+ |
+LL | fn lintme() { } //~ ERROR item is named 'lintme'
| ^^^^^^^^^^^^^^^
|
- = note: #[warn(clippy::test_lint)] on by default
+note: lint level defined here
+ --> $DIR/lint_tool_test.rs:21:9
+ |
+LL | #![deny(clippy_group)]
+ | ^^^^^^^^^^^^
+ = note: #[deny(clippy::test_lint)] implied by #[deny(clippy::group)]
+
+error: item is named 'lintmetoo'
+ --> $DIR/lint_tool_test.rs:32:5
+ |
+LL | fn lintmetoo() { } //~ ERROR item is named 'lintmetoo'
+ | ^^^^^^^^^^^^^^^^^^
+ |
+note: lint level defined here
+ --> $DIR/lint_tool_test.rs:21:9
+ |
+LL | #![deny(clippy_group)]
+ | ^^^^^^^^^^^^
+ = note: #[deny(clippy::test_group)] implied by #[deny(clippy::group)]
+
+error: aborting due to 2 previous errors
error: function should have one argument
--> $DIR/alloc-error-handler-bad-signature-3.rs:20:1
|
-LL | / fn oom() -> ! { //~ ERROR function should have one argument
-LL | | loop {}
-LL | | }
- | |_^
+LL | fn oom() -> ! { //~ ERROR function should have one argument
+ | ^^^^^^^^^^^^^
error: aborting due to previous error
-warning: not reporting region error due to nll
- --> $DIR/associated-types-project-from-hrtb-in-fn-body.rs:32:12
- |
-LL | let z: I::A = if cond { x } else { y };
- | ^^^^
-
error: unsatisfied lifetime constraints
--> $DIR/associated-types-project-from-hrtb-in-fn-body.rs:32:29
|
-warning: not reporting region error due to nll
- --> $DIR/project-fn-ret-contravariant.rs:53:16
- |
-LL | let a = bar(foo, y);
- | ^^^
-
-warning: not reporting region error due to nll
- --> $DIR/project-fn-ret-contravariant.rs:54:16
- |
-LL | let b = bar(foo, x);
- | ^^^
-
error: unsatisfied lifetime constraints
--> $DIR/project-fn-ret-contravariant.rs:53:12
|
-warning: not reporting region error due to nll
- --> $DIR/project-fn-ret-contravariant.rs:48:8
- |
-LL | bar(foo, x) //[transmute]~ ERROR E0495
- | ^^^
-
error: unsatisfied lifetime constraints
--> $DIR/project-fn-ret-contravariant.rs:48:4
|
-warning: not reporting region error due to nll
- --> $DIR/project-fn-ret-invariant.rs:63:16
- |
-LL | let a = bar(foo, y); //[krisskross]~ ERROR E0623
- | ^^^
-
-warning: not reporting region error due to nll
- --> $DIR/project-fn-ret-invariant.rs:64:16
- |
-LL | let b = bar(foo, x);
- | ^^^
-
error: unsatisfied lifetime constraints
--> $DIR/project-fn-ret-invariant.rs:63:12
|
-warning: not reporting region error due to nll
- --> $DIR/project-fn-ret-invariant.rs:47:12
- |
-LL | let f = foo; // <-- No consistent type can be inferred for `f` here.
- | ^^^
-
error: unsatisfied lifetime constraints
--> $DIR/project-fn-ret-invariant.rs:48:12
|
-warning: not reporting region error due to nll
- --> $DIR/project-fn-ret-invariant.rs:58:8
- |
-LL | bar(foo, x) //[transmute]~ ERROR E0495
- | ^^^
-
error: unsatisfied lifetime constraints
--> $DIR/project-fn-ret-invariant.rs:58:4
|
-warning: not reporting region error due to nll
- --> $DIR/borrowck-reborrow-from-shorter-lived-andmut.rs:19:18
- |
-LL | S { pointer: &mut *p.pointer }
- | ^^^^^^^^^^^^^^^
-
error: unsatisfied lifetime constraints
--> $DIR/borrowck-reborrow-from-shorter-lived-andmut.rs:19:5
|
-warning: not reporting region error due to nll
- --> $DIR/issue-45983.rs:36:27
- |
-LL | give_any(|y| x = Some(y));
- | ^
-
error: borrowed data escapes outside of closure
--> $DIR/issue-45983.rs:36:18
|
give_any(|y| x = Some(y));
//[ast]~^ ERROR borrowed data cannot be stored outside of its closure
//[migrate]~^^ ERROR borrowed data cannot be stored outside of its closure
- //[nll]~^^^ WARN not reporting region error due to nll
- //[nll]~| ERROR borrowed data escapes outside of closure
+ //[nll]~^^^ ERROR borrowed data escapes outside of closure
//[nll]~| ERROR cannot assign to `x`, as it is not declared as mutable
}
-warning: not reporting region error due to nll
- --> $DIR/issue-7573.rs:27:31
- |
-LL | let mut lines_to_use: Vec<&CrateId> = Vec::new();
- | ^
-
error: borrowed data escapes outside of closure
--> $DIR/issue-7573.rs:32:9
|
// permitted as `Foo` is not copy (even in a static/const
// initializer).
-#![feature(const_fn)]
+#![feature(min_const_fn)]
struct Foo(usize);
-warning: not reporting region error due to nll
- --> $DIR/regions-escape-bound-fn-2.rs:18:27
- |
-LL | with_int(|y| x = Some(y));
- | ^
-
error: borrowed data escapes outside of closure
--> $DIR/regions-escape-bound-fn-2.rs:18:18
|
-warning: not reporting region error due to nll
- --> $DIR/regions-escape-bound-fn.rs:18:22
- |
-LL | with_int(|y| x = Some(y));
- | ^^^^^^^
-
error: borrowed data escapes outside of closure
--> $DIR/regions-escape-bound-fn.rs:18:18
|
-warning: not reporting region error due to nll
- --> $DIR/regions-escape-unboxed-closure.rs:16:27
- |
-LL | with_int(&mut |y| x = Some(y));
- | ^^^^^^^
-
error: borrowed data escapes outside of closure
--> $DIR/regions-escape-unboxed-closure.rs:16:23
|
// except according to those terms.
#![feature(stmt_expr_attributes)]
+#![feature(custom_test_frameworks)]
fn main() {
let _ = #[cfg(unset)] ();
//~^ ERROR removing an expression is not supported in this position
let _ = [1, 2, 3][#[cfg(unset)] 1];
//~^ ERROR removing an expression is not supported in this position
- let _ = #[test] ();
- //~^ ERROR removing an expression is not supported in this position
}
error: removing an expression is not supported in this position
- --> $DIR/cfg-non-opt-expr.rs:14:13
+ --> $DIR/cfg-non-opt-expr.rs:15:13
|
LL | let _ = #[cfg(unset)] ();
| ^^^^^^^^^^^^^
error: removing an expression is not supported in this position
- --> $DIR/cfg-non-opt-expr.rs:16:21
+ --> $DIR/cfg-non-opt-expr.rs:17:21
|
LL | let _ = 1 + 2 + #[cfg(unset)] 3;
| ^^^^^^^^^^^^^
error: removing an expression is not supported in this position
- --> $DIR/cfg-non-opt-expr.rs:18:23
+ --> $DIR/cfg-non-opt-expr.rs:19:23
|
LL | let _ = [1, 2, 3][#[cfg(unset)] 1];
| ^^^^^^^^^^^^^
-error: removing an expression is not supported in this position
- --> $DIR/cfg-non-opt-expr.rs:20:13
- |
-LL | let _ = #[test] ();
- | ^^^^^^^
-
-error: aborting due to 4 previous errors
+error: aborting due to 3 previous errors
use std::borrow::Borrow;
#[rustc_dump_program_clauses] //~ ERROR program clause dump
-trait Foo<'a, 'b, S, T, U> where S: Debug, T: Borrow<U>, U: ?Sized, 'a: 'b, U: 'b {
+trait Foo<'a, 'b, S, T, U>
+where
+ S: Debug,
+ T: Borrow<U>,
+ U: ?Sized,
+ 'a: 'b,
+ U: 'b,
+ Vec<T>:, // NOTE(#53696) this checks an empty list of bounds.
+{
fn s(_: S) -> S;
fn t(_: T) -> T;
fn u(_: U) -> U;
= note: Implemented(Self: Foo<'a, 'b, S, T, U>) :- FromEnv(Self: Foo<'a, 'b, S, T, U>).
= note: RegionOutlives('a : 'b) :- FromEnv(Self: Foo<'a, 'b, S, T, U>).
= note: TypeOutlives(U : 'b) :- FromEnv(Self: Foo<'a, 'b, S, T, U>).
- = note: WellFormed(Self: Foo<'a, 'b, S, T, U>) :- Implemented(Self: Foo<'a, 'b, S, T, U>), WellFormed(S: std::marker::Sized), WellFormed(T: std::marker::Sized), WellFormed(S: std::fmt::Debug), WellFormed(T: std::borrow::Borrow<U>), RegionOutlives('a : 'b), TypeOutlives(U : 'b).
+ = note: WellFormed(Self: Foo<'a, 'b, S, T, U>) :- Implemented(Self: Foo<'a, 'b, S, T, U>), WellFormed(S: std::marker::Sized), WellFormed(T: std::marker::Sized), WellFormed(S: std::fmt::Debug), WellFormed(T: std::borrow::Borrow<U>), RegionOutlives('a : 'b), TypeOutlives(U : 'b), WellFormed(std::vec::Vec<T>).
+ = note: WellFormed(std::vec::Vec<T>) :- FromEnv(Self: Foo<'a, 'b, S, T, U>).
error: aborting due to previous error
-warning: not reporting region error due to nll
- --> $DIR/expect-fn-supply-fn.rs:24:52
- |
-LL | with_closure_expecting_fn_with_free_region(|x: fn(&'x u32), y| {});
- | ^^^^^^^^^^^
-
error[E0631]: type mismatch in closure arguments
--> $DIR/expect-fn-supply-fn.rs:40:5
|
-warning: not reporting region error due to nll
- --> $DIR/closure-bounds-static-cant-capture-borrowed.rs:15:9
- |
-LL | bar(|| {
- | _________^
-LL | | //~^ ERROR explicit lifetime required in the type of `x` [E0621]
-LL | | let _ = x;
-LL | | })
- | |_____^
-
error[E0621]: explicit lifetime required in the type of `x`
--> $DIR/closure-bounds-static-cant-capture-borrowed.rs:15:5
|
-warning: not reporting region error due to nll
- --> $DIR/expect-region-supply-region.rs:28:13
- |
-LL | f = Some(x); //~ ERROR borrowed data cannot be stored outside of its closure
- | ^^^^^^^
-
-warning: not reporting region error due to nll
- --> $DIR/expect-region-supply-region.rs:38:13
- |
-LL | f = Some(x); //~ ERROR borrowed data cannot be stored outside of its closure
- | ^^^^^^^
-
-warning: not reporting region error due to nll
- --> $DIR/expect-region-supply-region.rs:47:33
- |
-LL | closure_expecting_bound(|x: &'x u32| {
- | ^^^^^^^
-
-warning: not reporting region error due to nll
- --> $DIR/expect-region-supply-region.rs:52:13
- |
-LL | f = Some(x);
- | ^^^^^^^
-
error: borrowed data escapes outside of closure
--> $DIR/expect-region-supply-region.rs:28:9
|
// Crate that exports a const fn. Used for testing cross-crate.
#![crate_type="rlib"]
-#![feature(const_fn)]
+#![feature(min_const_fn)]
pub const fn foo() -> usize { 22 } //~ ERROR const fn is unstable
--- /dev/null
+// Copyright 2015 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+// Crate that exports a const fn. Used for testing cross-crate.
+
+#![crate_type="rlib"]
+#![stable(feature = "rust1", since = "1.0.0")]
+
+#![feature(rustc_const_unstable, const_fn)]
+#![feature(staged_api)]
+
+#[stable(feature = "rust1", since = "1.0.0")]
+#[rustc_const_unstable(feature="foo")]
+pub const fn foo() -> u32 { 42 }
--- /dev/null
+// only-x86_64
+
+union Nonsense {
+ u: usize,
+ int_32_ref: &'static i32,
+ uint_8: u8,
+ uint_16: u16,
+ uint_32: u32,
+ uint_64: u64,
+ uint_128: u128,
+ int_8: i8,
+ int_16: i16,
+ int_32: i32,
+ int_64: i64,
+ int_128: i128,
+ float_32: f32,
+ float_64: f64,
+ truthy_falsey: bool,
+ character: char,
+ stringy: &'static str,
+}
+
+fn main() {
+ const I32_REF_USIZE_UNION: usize = unsafe { Nonsense { int_32_ref: &3 }.u };
+ //~^ ERROR this constant likely exhibits undefined behavior
+
+ const I32_REF_U8_UNION: u8 = unsafe { Nonsense { int_32_ref: &3 }.uint_8 };
+ //~^ ERROR this constant cannot be used
+
+ const I32_REF_U16_UNION: u16 = unsafe { Nonsense { int_32_ref: &3 }.uint_16 };
+ //~^ ERROR this constant cannot be used
+
+ const I32_REF_U32_UNION: u32 = unsafe { Nonsense { int_32_ref: &3 }.uint_32 };
+ //~^ ERROR this constant cannot be used
+
+ const I32_REF_U64_UNION: u64 = unsafe { Nonsense { int_32_ref: &3 }.uint_64 };
+ //~^ ERROR this constant likely exhibits undefined behavior
+
+ const I32_REF_U128_UNION: u128 = unsafe { Nonsense { int_32_ref: &3 }.uint_128 };
+ //~^ ERROR this constant cannot be used
+
+ const I32_REF_I8_UNION: i8 = unsafe { Nonsense { int_32_ref: &3 }.int_8 };
+ //~^ ERROR this constant cannot be used
+
+ const I32_REF_I16_UNION: i16 = unsafe { Nonsense { int_32_ref: &3 }.int_16 };
+ //~^ ERROR this constant cannot be used
+
+ const I32_REF_I32_UNION: i32 = unsafe { Nonsense { int_32_ref: &3 }.int_32 };
+ //~^ ERROR this constant cannot be used
+
+ const I32_REF_I64_UNION: i64 = unsafe { Nonsense { int_32_ref: &3 }.int_64 };
+ //~^ ERROR this constant likely exhibits undefined behavior
+
+ const I32_REF_I128_UNION: i128 = unsafe { Nonsense { int_32_ref: &3 }.int_128 };
+ //~^ ERROR this constant cannot be used
+
+ const I32_REF_F32_UNION: f32 = unsafe { Nonsense { int_32_ref: &3 }.float_32 };
+ //~^ ERROR this constant cannot be used
+
+ const I32_REF_F64_UNION: f64 = unsafe { Nonsense { int_32_ref: &3 }.float_64 };
+ //~^ ERROR this constant likely exhibits undefined behavior
+
+ const I32_REF_BOOL_UNION: bool = unsafe { Nonsense { int_32_ref: &3 }.truthy_falsey };
+ //~^ ERROR this constant cannot be used
+
+ const I32_REF_CHAR_UNION: char = unsafe { Nonsense { int_32_ref: &3 }.character };
+ //~^ ERROR this constant cannot be used
+
+ const STR_U8_UNION: u8 = unsafe { Nonsense { stringy: "3" }.uint_8 };
+ //~^ ERROR this constant cannot be used
+
+ const STR_U16_UNION: u16 = unsafe { Nonsense { stringy: "3" }.uint_16 };
+ //~^ ERROR this constant cannot be used
+
+ const STR_U32_UNION: u32 = unsafe { Nonsense { stringy: "3" }.uint_32 };
+ //~^ ERROR this constant cannot be used
+
+ const STR_U64_UNION: u64 = unsafe { Nonsense { stringy: "3" }.uint_64 };
+ //~^ ERROR this constant likely exhibits undefined behavior
+
+ const STR_U128_UNION: u128 = unsafe { Nonsense { stringy: "3" }.uint_128 };
+ //~^ ERROR this constant cannot be used
+
+ const STR_I8_UNION: i8 = unsafe { Nonsense { stringy: "3" }.int_8 };
+ //~^ ERROR this constant cannot be used
+
+ const STR_I16_UNION: i16 = unsafe { Nonsense { stringy: "3" }.int_16 };
+ //~^ ERROR this constant cannot be used
+
+ const STR_I32_UNION: i32 = unsafe { Nonsense { stringy: "3" }.int_32 };
+ //~^ ERROR this constant cannot be used
+
+ const STR_I64_UNION: i64 = unsafe { Nonsense { stringy: "3" }.int_64 };
+ //~^ ERROR this constant likely exhibits undefined behavior
+
+ const STR_I128_UNION: i128 = unsafe { Nonsense { stringy: "3" }.int_128 };
+ //~^ ERROR this constant cannot be used
+
+ const STR_F32_UNION: f32 = unsafe { Nonsense { stringy: "3" }.float_32 };
+ //~^ ERROR this constant cannot be used
+
+ const STR_F64_UNION: f64 = unsafe { Nonsense { stringy: "3" }.float_64 };
+ //~^ ERROR this constant likely exhibits undefined behavior
+
+ const STR_BOOL_UNION: bool = unsafe { Nonsense { stringy: "3" }.truthy_falsey };
+ //~^ ERROR this constant cannot be used
+
+ const STR_CHAR_UNION: char = unsafe { Nonsense { stringy: "3" }.character };
+ //~^ ERROR this constant cannot be used
+}
--- /dev/null
+error[E0080]: this constant likely exhibits undefined behavior
+ --> $DIR/const-pointer-values-in-various-types.rs:24:5
+ |
+LL | const I32_REF_USIZE_UNION: usize = unsafe { Nonsense { int_32_ref: &3 }.u };
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type validation failed: encountered a pointer, but expected the type usize
+ |
+ = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rust compiler repository if you believe it should not be considered undefined behavior
+
+error: this constant cannot be used
+ --> $DIR/const-pointer-values-in-various-types.rs:27:5
+ |
+LL | const I32_REF_U8_UNION: u8 = unsafe { Nonsense { int_32_ref: &3 }.uint_8 };
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^----------------------------------^^^
+ | |
+ | a raw memory access tried to access part of a pointer value as raw bytes
+ |
+ = note: #[deny(const_err)] on by default
+
+error: this constant cannot be used
+ --> $DIR/const-pointer-values-in-various-types.rs:30:5
+ |
+LL | const I32_REF_U16_UNION: u16 = unsafe { Nonsense { int_32_ref: &3 }.uint_16 };
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^-----------------------------------^^^
+ | |
+ | a raw memory access tried to access part of a pointer value as raw bytes
+
+error: this constant cannot be used
+ --> $DIR/const-pointer-values-in-various-types.rs:33:5
+ |
+LL | const I32_REF_U32_UNION: u32 = unsafe { Nonsense { int_32_ref: &3 }.uint_32 };
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^-----------------------------------^^^
+ | |
+ | a raw memory access tried to access part of a pointer value as raw bytes
+
+error[E0080]: this constant likely exhibits undefined behavior
+ --> $DIR/const-pointer-values-in-various-types.rs:36:5
+ |
+LL | const I32_REF_U64_UNION: u64 = unsafe { Nonsense { int_32_ref: &3 }.uint_64 };
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type validation failed: encountered a pointer, but expected the type u64
+ |
+ = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rust compiler repository if you believe it should not be considered undefined behavior
+
+error: this constant cannot be used
+ --> $DIR/const-pointer-values-in-various-types.rs:39:5
+ |
+LL | const I32_REF_U128_UNION: u128 = unsafe { Nonsense { int_32_ref: &3 }.uint_128 };
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ attempted to read undefined bytes
+
+error: this constant cannot be used
+ --> $DIR/const-pointer-values-in-various-types.rs:42:5
+ |
+LL | const I32_REF_I8_UNION: i8 = unsafe { Nonsense { int_32_ref: &3 }.int_8 };
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^---------------------------------^^^
+ | |
+ | a raw memory access tried to access part of a pointer value as raw bytes
+
+error: this constant cannot be used
+ --> $DIR/const-pointer-values-in-various-types.rs:45:5
+ |
+LL | const I32_REF_I16_UNION: i16 = unsafe { Nonsense { int_32_ref: &3 }.int_16 };
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^----------------------------------^^^
+ | |
+ | a raw memory access tried to access part of a pointer value as raw bytes
+
+error: this constant cannot be used
+ --> $DIR/const-pointer-values-in-various-types.rs:48:5
+ |
+LL | const I32_REF_I32_UNION: i32 = unsafe { Nonsense { int_32_ref: &3 }.int_32 };
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^----------------------------------^^^
+ | |
+ | a raw memory access tried to access part of a pointer value as raw bytes
+
+error[E0080]: this constant likely exhibits undefined behavior
+ --> $DIR/const-pointer-values-in-various-types.rs:51:5
+ |
+LL | const I32_REF_I64_UNION: i64 = unsafe { Nonsense { int_32_ref: &3 }.int_64 };
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type validation failed: encountered a pointer, but expected the type i64
+ |
+ = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rust compiler repository if you believe it should not be considered undefined behavior
+
+error: this constant cannot be used
+ --> $DIR/const-pointer-values-in-various-types.rs:54:5
+ |
+LL | const I32_REF_I128_UNION: i128 = unsafe { Nonsense { int_32_ref: &3 }.int_128 };
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ attempted to read undefined bytes
+
+error: this constant cannot be used
+ --> $DIR/const-pointer-values-in-various-types.rs:57:5
+ |
+LL | const I32_REF_F32_UNION: f32 = unsafe { Nonsense { int_32_ref: &3 }.float_32 };
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^------------------------------------^^^
+ | |
+ | a raw memory access tried to access part of a pointer value as raw bytes
+
+error[E0080]: this constant likely exhibits undefined behavior
+ --> $DIR/const-pointer-values-in-various-types.rs:60:5
+ |
+LL | const I32_REF_F64_UNION: f64 = unsafe { Nonsense { int_32_ref: &3 }.float_64 };
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type validation failed: encountered a pointer, but expected the type f64
+ |
+ = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rust compiler repository if you believe it should not be considered undefined behavior
+
+error: this constant cannot be used
+ --> $DIR/const-pointer-values-in-various-types.rs:63:5
+ |
+LL | const I32_REF_BOOL_UNION: bool = unsafe { Nonsense { int_32_ref: &3 }.truthy_falsey };
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^-----------------------------------------^^^
+ | |
+ | a raw memory access tried to access part of a pointer value as raw bytes
+
+error: this constant cannot be used
+ --> $DIR/const-pointer-values-in-various-types.rs:66:5
+ |
+LL | const I32_REF_CHAR_UNION: char = unsafe { Nonsense { int_32_ref: &3 }.character };
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^-------------------------------------^^^
+ | |
+ | a raw memory access tried to access part of a pointer value as raw bytes
+
+error: this constant cannot be used
+ --> $DIR/const-pointer-values-in-various-types.rs:69:5
+ |
+LL | const STR_U8_UNION: u8 = unsafe { Nonsense { stringy: "3" }.uint_8 };
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^--------------------------------^^^
+ | |
+ | a raw memory access tried to access part of a pointer value as raw bytes
+
+error: this constant cannot be used
+ --> $DIR/const-pointer-values-in-various-types.rs:72:5
+ |
+LL | const STR_U16_UNION: u16 = unsafe { Nonsense { stringy: "3" }.uint_16 };
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^---------------------------------^^^
+ | |
+ | a raw memory access tried to access part of a pointer value as raw bytes
+
+error: this constant cannot be used
+ --> $DIR/const-pointer-values-in-various-types.rs:75:5
+ |
+LL | const STR_U32_UNION: u32 = unsafe { Nonsense { stringy: "3" }.uint_32 };
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^---------------------------------^^^
+ | |
+ | a raw memory access tried to access part of a pointer value as raw bytes
+
+error[E0080]: this constant likely exhibits undefined behavior
+ --> $DIR/const-pointer-values-in-various-types.rs:78:5
+ |
+LL | const STR_U64_UNION: u64 = unsafe { Nonsense { stringy: "3" }.uint_64 };
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type validation failed: encountered a pointer, but expected the type u64
+ |
+ = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rust compiler repository if you believe it should not be considered undefined behavior
+
+error: this constant cannot be used
+ --> $DIR/const-pointer-values-in-various-types.rs:81:5
+ |
+LL | const STR_U128_UNION: u128 = unsafe { Nonsense { stringy: "3" }.uint_128 };
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^----------------------------------^^^
+ | |
+ | a raw memory access tried to access part of a pointer value as raw bytes
+
+error: this constant cannot be used
+ --> $DIR/const-pointer-values-in-various-types.rs:84:5
+ |
+LL | const STR_I8_UNION: i8 = unsafe { Nonsense { stringy: "3" }.int_8 };
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^-------------------------------^^^
+ | |
+ | a raw memory access tried to access part of a pointer value as raw bytes
+
+error: this constant cannot be used
+ --> $DIR/const-pointer-values-in-various-types.rs:87:5
+ |
+LL | const STR_I16_UNION: i16 = unsafe { Nonsense { stringy: "3" }.int_16 };
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^--------------------------------^^^
+ | |
+ | a raw memory access tried to access part of a pointer value as raw bytes
+
+error: this constant cannot be used
+ --> $DIR/const-pointer-values-in-various-types.rs:90:5
+ |
+LL | const STR_I32_UNION: i32 = unsafe { Nonsense { stringy: "3" }.int_32 };
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^--------------------------------^^^
+ | |
+ | a raw memory access tried to access part of a pointer value as raw bytes
+
+error[E0080]: this constant likely exhibits undefined behavior
+ --> $DIR/const-pointer-values-in-various-types.rs:93:5
+ |
+LL | const STR_I64_UNION: i64 = unsafe { Nonsense { stringy: "3" }.int_64 };
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type validation failed: encountered a pointer, but expected the type i64
+ |
+ = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rust compiler repository if you believe it should not be considered undefined behavior
+
+error: this constant cannot be used
+ --> $DIR/const-pointer-values-in-various-types.rs:96:5
+ |
+LL | const STR_I128_UNION: i128 = unsafe { Nonsense { stringy: "3" }.int_128 };
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^---------------------------------^^^
+ | |
+ | a raw memory access tried to access part of a pointer value as raw bytes
+
+error: this constant cannot be used
+ --> $DIR/const-pointer-values-in-various-types.rs:99:5
+ |
+LL | const STR_F32_UNION: f32 = unsafe { Nonsense { stringy: "3" }.float_32 };
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^----------------------------------^^^
+ | |
+ | a raw memory access tried to access part of a pointer value as raw bytes
+
+error[E0080]: this constant likely exhibits undefined behavior
+ --> $DIR/const-pointer-values-in-various-types.rs:102:5
+ |
+LL | const STR_F64_UNION: f64 = unsafe { Nonsense { stringy: "3" }.float_64 };
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type validation failed: encountered a pointer, but expected the type f64
+ |
+ = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rust compiler repository if you believe it should not be considered undefined behavior
+
+error: this constant cannot be used
+ --> $DIR/const-pointer-values-in-various-types.rs:105:5
+ |
+LL | const STR_BOOL_UNION: bool = unsafe { Nonsense { stringy: "3" }.truthy_falsey };
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^---------------------------------------^^^
+ | |
+ | a raw memory access tried to access part of a pointer value as raw bytes
+
+error: this constant cannot be used
+ --> $DIR/const-pointer-values-in-various-types.rs:108:5
+ |
+LL | const STR_CHAR_UNION: char = unsafe { Nonsense { stringy: "3" }.character };
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^-----------------------------------^^^
+ | |
+ | a raw memory access tried to access part of a pointer value as raw bytes
+
+error: aborting due to 29 previous errors
+
+For more information about this error, try `rustc --explain E0080`.
|
LL | let x: &'static _ = &std::time::Duration::from_millis(42).subsec_millis();
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ temporary value does not live long enough
+LL | //~^ does not live long enough
LL | }
| - temporary value only lives until here
|
fn main() {
let _: &'static u32 = &meh(); //~ ERROR does not live long enough
let x: &'static _ = &std::time::Duration::from_millis(42).subsec_millis();
+ //~^ does not live long enough
}
|
LL | let _: &'static u32 = &meh(); //~ ERROR does not live long enough
| ^^^^^ temporary value does not live long enough
+...
+LL | }
+ | - temporary value only lives until here
+ |
+ = note: borrowed value must be valid for the static lifetime...
+
+error[E0597]: borrowed value does not live long enough
+ --> $DIR/dont_promote_unstable_const_fn.rs:33:26
+ |
LL | let x: &'static _ = &std::time::Duration::from_millis(42).subsec_millis();
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ temporary value does not live long enough
+LL | //~^ does not live long enough
LL | }
| - temporary value only lives until here
|
= note: borrowed value must be valid for the static lifetime...
-error: aborting due to 3 previous errors
+error: aborting due to 4 previous errors
For more information about this error, try `rustc --explain E0597`.
--- /dev/null
+error[E0597]: borrowed value does not live long enough
+ --> $DIR/dont_promote_unstable_const_fn_cross_crate.rs:19:29
+ |
+LL | let _x: &'static u32 = &foo(); //~ ERROR does not live long enough
+ | ^^^^^ temporary value does not live long enough
+LL | }
+ | - temporary value only lives until here
+ |
+ = note: borrowed value must be valid for the static lifetime...
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0597`.
--- /dev/null
+// Copyright 2018 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+// aux-build:stability.rs
+
+extern crate stability;
+
+use stability::foo;
+
+fn main() {
+ let _: &'static u32 = &foo(); //~ ERROR does not live long enough
+ let _x: &'static u32 = &foo(); //~ ERROR does not live long enough
+}
--- /dev/null
+error[E0597]: borrowed value does not live long enough
+ --> $DIR/dont_promote_unstable_const_fn_cross_crate.rs:18:28
+ |
+LL | let _: &'static u32 = &foo(); //~ ERROR does not live long enough
+ | ^^^^^ temporary value does not live long enough
+LL | let _x: &'static u32 = &foo(); //~ ERROR does not live long enough
+LL | }
+ | - temporary value only lives until here
+ |
+ = note: borrowed value must be valid for the static lifetime...
+
+error[E0597]: borrowed value does not live long enough
+ --> $DIR/dont_promote_unstable_const_fn_cross_crate.rs:19:29
+ |
+LL | let _x: &'static u32 = &foo(); //~ ERROR does not live long enough
+ | ^^^^^ temporary value does not live long enough
+LL | }
+ | - temporary value only lives until here
+ |
+ = note: borrowed value must be valid for the static lifetime...
+
+error: aborting due to 2 previous errors
+
+For more information about this error, try `rustc --explain E0597`.
#![warn(const_err)]
-#![feature(const_fn)]
+#![feature(min_const_fn)]
const fn foo(x: u32) -> u32 {
x
// compile-pass
-#![feature(const_fn)]
+#![feature(min_const_fn)]
struct S(pub &'static u32, pub u32);
--- /dev/null
+// Copyright 2018 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+#![feature(const_let)]
+
+fn main() {
+ let _ = [(); {
+ //~^ WARNING Constant evaluating a complex constant, this might take some time
+ //~| ERROR could not evaluate repeat length
+ let mut x = &0;
+ let mut n = 0;
+ while n < 5 { //~ ERROR constant contains unimplemented expression type
+ n = (n + 1) % 5;
+ x = &0; // Materialize a new AllocId
+ }
+ 0
+ }];
+}
--- /dev/null
+error[E0019]: constant contains unimplemented expression type
+ --> $DIR/issue-52475.rs:19:9
+ |
+LL | / while n < 5 { //~ ERROR constant contains unimplemented expression type
+LL | | n = (n + 1) % 5;
+LL | | x = &0; // Materialize a new AllocId
+LL | | }
+ | |_________^
+
+warning: Constant evaluating a complex constant, this might take some time
+ --> $DIR/issue-52475.rs:14:18
+ |
+LL | let _ = [(); {
+ | __________________^
+LL | | //~^ WARNING Constant evaluating a complex constant, this might take some time
+LL | | //~| ERROR could not evaluate repeat length
+LL | | let mut x = &0;
+... |
+LL | | 0
+LL | | }];
+ | |_____^
+
+error[E0080]: could not evaluate repeat length
+ --> $DIR/issue-52475.rs:14:18
+ |
+LL | let _ = [(); {
+ | __________________^
+LL | | //~^ WARNING Constant evaluating a complex constant, this might take some time
+LL | | //~| ERROR could not evaluate repeat length
+LL | | let mut x = &0;
+... |
+LL | | n = (n + 1) % 5;
+ | | ----------- duplicate interpreter state observed here, const evaluation will never terminate
+... |
+LL | | 0
+LL | | }];
+ | |_____^
+
+error: aborting due to 2 previous errors
+
+Some errors occurred: E0019, E0080.
+For more information about an error, try `rustc --explain E0019`.
+++ /dev/null
-// Copyright 2017 The Rust Project Developers. See the COPYRIGHT
-// file at the top-level directory of this distribution and at
-// http://rust-lang.org/COPYRIGHT.
-//
-// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
-// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
-// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
-// option. This file may not be copied, modified, or distributed
-// except according to those terms.
-
-//compile-pass
-
-#![feature(const_fn_union)]
-
-fn main() {}
-
-static FOO: u32 = 42;
-
-union Foo {
- f: Float,
- r: &'static u32,
-}
-
-#[cfg(target_pointer_width="64")]
-type Float = f64;
-
-#[cfg(target_pointer_width="32")]
-type Float = f32;
-
-static BAR: Float = unsafe { Foo { r: &FOO }.f };
+++ /dev/null
-// Copyright 2018 The Rust Project Developers. See the COPYRIGHT
-// file at the top-level directory of this distribution and at
-// http://rust-lang.org/COPYRIGHT.
-//
-// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
-// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
-// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
-// option. This file may not be copied, modified, or distributed
-// except according to those terms.
-
-// compile-pass
-
-union Foo {
- a: &'static u8,
- b: usize,
-}
-
-// a usize's value may be a pointer, that's fine
-const PTR_AS_USIZE: usize = unsafe { Foo { a: &1 }.b};
-
-fn main() {
-}
--- /dev/null
+// Copyright 2018 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+#![feature(reverse_bits, int_to_from_bytes)]
+
+fn main() {
+ let x: &'static i32 = &(5_i32.reverse_bits());
+ //~^ ERROR does not live long enough
+ let y: &'static i32 = &(i32::from_be_bytes([0x12, 0x34, 0x56, 0x78]));
+ //~^ ERROR does not live long enough
+ let z: &'static i32 = &(i32::from_le_bytes([0x12, 0x34, 0x56, 0x78]));
+ //~^ ERROR does not live long enough
+ let a: &'static i32 = &(i32::from_be(i32::from_ne_bytes([0x80, 0, 0, 0])));
+ //~^ ERROR does not live long enough
+ let b: &'static [u8] = &(0x12_34_56_78_i32.to_be_bytes());
+ //~^ ERROR does not live long enough
+ let c: &'static [u8] = &(0x12_34_56_78_i32.to_le_bytes());
+ //~^ ERROR does not live long enough
+ let d: &'static [u8] = &(i32::min_value().to_be().to_ne_bytes());
+ //~^ ERROR does not live long enough
+}
--- /dev/null
+error[E0597]: borrowed value does not live long enough
+ --> $DIR/const-int-conversion.rs:14:28
+ |
+LL | let x: &'static i32 = &(5_i32.reverse_bits());
+ | ^^^^^^^^^^^^^^^^^^^^^^ temporary value does not live long enough
+...
+LL | }
+ | - temporary value only lives until here
+ |
+ = note: borrowed value must be valid for the static lifetime...
+
+error[E0597]: borrowed value does not live long enough
+ --> $DIR/const-int-conversion.rs:16:28
+ |
+LL | let y: &'static i32 = &(i32::from_be_bytes([0x12, 0x34, 0x56, 0x78]));
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ temporary value does not live long enough
+...
+LL | }
+ | - temporary value only lives until here
+ |
+ = note: borrowed value must be valid for the static lifetime...
+
+error[E0597]: borrowed value does not live long enough
+ --> $DIR/const-int-conversion.rs:18:28
+ |
+LL | let z: &'static i32 = &(i32::from_le_bytes([0x12, 0x34, 0x56, 0x78]));
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ temporary value does not live long enough
+...
+LL | }
+ | - temporary value only lives until here
+ |
+ = note: borrowed value must be valid for the static lifetime...
+
+error[E0597]: borrowed value does not live long enough
+ --> $DIR/const-int-conversion.rs:20:28
+ |
+LL | let a: &'static i32 = &(i32::from_be(i32::from_ne_bytes([0x80, 0, 0, 0])));
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ temporary value does not live long enough
+...
+LL | }
+ | - temporary value only lives until here
+ |
+ = note: borrowed value must be valid for the static lifetime...
+
+error[E0597]: borrowed value does not live long enough
+ --> $DIR/const-int-conversion.rs:22:29
+ |
+LL | let b: &'static [u8] = &(0x12_34_56_78_i32.to_be_bytes());
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ temporary value does not live long enough
+...
+LL | }
+ | - temporary value only lives until here
+ |
+ = note: borrowed value must be valid for the static lifetime...
+
+error[E0597]: borrowed value does not live long enough
+ --> $DIR/const-int-conversion.rs:24:29
+ |
+LL | let c: &'static [u8] = &(0x12_34_56_78_i32.to_le_bytes());
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ temporary value does not live long enough
+...
+LL | }
+ | - temporary value only lives until here
+ |
+ = note: borrowed value must be valid for the static lifetime...
+
+error[E0597]: borrowed value does not live long enough
+ --> $DIR/const-int-conversion.rs:26:29
+ |
+LL | let d: &'static [u8] = &(i32::min_value().to_be().to_ne_bytes());
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ temporary value does not live long enough
+LL | //~^ ERROR does not live long enough
+LL | }
+ | - temporary value only lives until here
+ |
+ = note: borrowed value must be valid for the static lifetime...
+
+error: aborting due to 7 previous errors
+
+For more information about this error, try `rustc --explain E0597`.
--- /dev/null
+// Copyright 2018 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+fn main() {
+ let x: &'static (i32, bool) = &(5_i32.overflowing_add(3)); //~ ERROR does not live long enough
+ let y: &'static (i32, bool) = &(5_i32.overflowing_sub(3)); //~ ERROR does not live long enough
+ let z: &'static (i32, bool) = &(5_i32.overflowing_mul(3)); //~ ERROR does not live long enough
+}
--- /dev/null
+error[E0597]: borrowed value does not live long enough
+ --> $DIR/const-int-overflowing.rs:12:36
+ |
+LL | let x: &'static (i32, bool) = &(5_i32.overflowing_add(3)); //~ ERROR does not live long enough
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^ temporary value does not live long enough
+...
+LL | }
+ | - temporary value only lives until here
+ |
+ = note: borrowed value must be valid for the static lifetime...
+
+error[E0597]: borrowed value does not live long enough
+ --> $DIR/const-int-overflowing.rs:13:36
+ |
+LL | let y: &'static (i32, bool) = &(5_i32.overflowing_sub(3)); //~ ERROR does not live long enough
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^ temporary value does not live long enough
+LL | let z: &'static (i32, bool) = &(5_i32.overflowing_mul(3)); //~ ERROR does not live long enough
+LL | }
+ | - temporary value only lives until here
+ |
+ = note: borrowed value must be valid for the static lifetime...
+
+error[E0597]: borrowed value does not live long enough
+ --> $DIR/const-int-overflowing.rs:14:36
+ |
+LL | let z: &'static (i32, bool) = &(5_i32.overflowing_mul(3)); //~ ERROR does not live long enough
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^ temporary value does not live long enough
+LL | }
+ | - temporary value only lives until here
+ |
+ = note: borrowed value must be valid for the static lifetime...
+
+error: aborting due to 3 previous errors
+
+For more information about this error, try `rustc --explain E0597`.
--- /dev/null
+// Copyright 2018 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+fn main() {
+ let x: &'static i32 = &(5_i32.rotate_left(3)); //~ ERROR does not live long enough
+ let y: &'static i32 = &(5_i32.rotate_right(3)); //~ ERROR does not live long enough
+}
--- /dev/null
+error[E0597]: borrowed value does not live long enough
+ --> $DIR/const-int-rotate.rs:12:28
+ |
+LL | let x: &'static i32 = &(5_i32.rotate_left(3)); //~ ERROR does not live long enough
+ | ^^^^^^^^^^^^^^^^^^^^^^ temporary value does not live long enough
+LL | let y: &'static i32 = &(5_i32.rotate_right(3)); //~ ERROR does not live long enough
+LL | }
+ | - temporary value only lives until here
+ |
+ = note: borrowed value must be valid for the static lifetime...
+
+error[E0597]: borrowed value does not live long enough
+ --> $DIR/const-int-rotate.rs:13:28
+ |
+LL | let y: &'static i32 = &(5_i32.rotate_right(3)); //~ ERROR does not live long enough
+ | ^^^^^^^^^^^^^^^^^^^^^^^ temporary value does not live long enough
+LL | }
+ | - temporary value only lives until here
+ |
+ = note: borrowed value must be valid for the static lifetime...
+
+error: aborting due to 2 previous errors
+
+For more information about this error, try `rustc --explain E0597`.
--- /dev/null
+// Copyright 2018 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+fn main() {
+ let x: &'static bool = &(5_i32.is_negative()); //~ ERROR does not live long enough
+ let y: &'static bool = &(5_i32.is_positive()); //~ ERROR does not live long enough
+}
--- /dev/null
+error[E0597]: borrowed value does not live long enough
+ --> $DIR/const-int-sign.rs:12:29
+ |
+LL | let x: &'static bool = &(5_i32.is_negative()); //~ ERROR does not live long enough
+ | ^^^^^^^^^^^^^^^^^^^^^ temporary value does not live long enough
+LL | let y: &'static bool = &(5_i32.is_positive()); //~ ERROR does not live long enough
+LL | }
+ | - temporary value only lives until here
+ |
+ = note: borrowed value must be valid for the static lifetime...
+
+error[E0597]: borrowed value does not live long enough
+ --> $DIR/const-int-sign.rs:13:29
+ |
+LL | let y: &'static bool = &(5_i32.is_positive()); //~ ERROR does not live long enough
+ | ^^^^^^^^^^^^^^^^^^^^^ temporary value does not live long enough
+LL | }
+ | - temporary value only lives until here
+ |
+ = note: borrowed value must be valid for the static lifetime...
+
+error: aborting due to 2 previous errors
+
+For more information about this error, try `rustc --explain E0597`.
--- /dev/null
+// Copyright 2018 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+fn main() {
+ let x: &'static i32 = &(5_i32.wrapping_add(3)); //~ ERROR does not live long enough
+ let y: &'static i32 = &(5_i32.wrapping_sub(3)); //~ ERROR does not live long enough
+ let z: &'static i32 = &(5_i32.wrapping_mul(3)); //~ ERROR does not live long enough
+ let a: &'static i32 = &(5_i32.wrapping_shl(3)); //~ ERROR does not live long enough
+ let b: &'static i32 = &(5_i32.wrapping_shr(3)); //~ ERROR does not live long enough
+}
--- /dev/null
+error[E0597]: borrowed value does not live long enough
+ --> $DIR/const-int-wrapping.rs:12:28
+ |
+LL | let x: &'static i32 = &(5_i32.wrapping_add(3)); //~ ERROR does not live long enough
+ | ^^^^^^^^^^^^^^^^^^^^^^^ temporary value does not live long enough
+...
+LL | }
+ | - temporary value only lives until here
+ |
+ = note: borrowed value must be valid for the static lifetime...
+
+error[E0597]: borrowed value does not live long enough
+ --> $DIR/const-int-wrapping.rs:13:28
+ |
+LL | let y: &'static i32 = &(5_i32.wrapping_sub(3)); //~ ERROR does not live long enough
+ | ^^^^^^^^^^^^^^^^^^^^^^^ temporary value does not live long enough
+...
+LL | }
+ | - temporary value only lives until here
+ |
+ = note: borrowed value must be valid for the static lifetime...
+
+error[E0597]: borrowed value does not live long enough
+ --> $DIR/const-int-wrapping.rs:14:28
+ |
+LL | let z: &'static i32 = &(5_i32.wrapping_mul(3)); //~ ERROR does not live long enough
+ | ^^^^^^^^^^^^^^^^^^^^^^^ temporary value does not live long enough
+...
+LL | }
+ | - temporary value only lives until here
+ |
+ = note: borrowed value must be valid for the static lifetime...
+
+error[E0597]: borrowed value does not live long enough
+ --> $DIR/const-int-wrapping.rs:15:28
+ |
+LL | let a: &'static i32 = &(5_i32.wrapping_shl(3)); //~ ERROR does not live long enough
+ | ^^^^^^^^^^^^^^^^^^^^^^^ temporary value does not live long enough
+LL | let b: &'static i32 = &(5_i32.wrapping_shr(3)); //~ ERROR does not live long enough
+LL | }
+ | - temporary value only lives until here
+ |
+ = note: borrowed value must be valid for the static lifetime...
+
+error[E0597]: borrowed value does not live long enough
+ --> $DIR/const-int-wrapping.rs:16:28
+ |
+LL | let b: &'static i32 = &(5_i32.wrapping_shr(3)); //~ ERROR does not live long enough
+ | ^^^^^^^^^^^^^^^^^^^^^^^ temporary value does not live long enough
+LL | }
+ | - temporary value only lives until here
+ |
+ = note: borrowed value must be valid for the static lifetime...
+
+error: aborting due to 5 previous errors
+
+For more information about this error, try `rustc --explain E0597`.
// compile-pass
-#![feature(const_fn)]
+#![feature(min_const_fn)]
#[derive(PartialEq, Eq)]
enum Cake {
// error-pattern: cycle detected
-#![feature(const_fn)]
-
struct Foo {
bytes: [u8; std::mem::size_of::<Foo>()]
}
note: ...which requires const-evaluating `Foo::bytes::{{constant}}`...
--> $SRC_DIR/libcore/mem.rs:LL:COL
|
-LL | unsafe { intrinsics::size_of::<T>() }
- | ^^^^^^^^^^^^^^^^^^^^^^^^^^
+LL | intrinsics::size_of::<T>()
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^
= note: ...which again requires computing layout of `Foo`, completing the cycle
note: cycle used when const-evaluating `Foo::bytes::{{constant}}`
--> $SRC_DIR/libcore/mem.rs:LL:COL
|
-LL | unsafe { intrinsics::size_of::<T>() }
- | ^^^^^^^^^^^^^^^^^^^^^^^^^^
+LL | intrinsics::size_of::<T>()
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^
error: aborting due to previous error
--- /dev/null
+error[E0493]: destructors cannot be evaluated at compile-time
+ --> $DIR/min_const_fn.rs:49:25
+ |
+LL | const fn into_inner(self) -> T { self.0 } //~ destructors cannot be evaluated
+ | ^^^^ constant functions cannot evaluate destructors
+
+error: mutable references in const fn are unstable
+ --> $DIR/min_const_fn.rs:51:5
+ |
+LL | const fn get_mut(&mut self) -> &mut T { &mut self.0 }
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+error[E0493]: destructors cannot be evaluated at compile-time
+ --> $DIR/min_const_fn.rs:56:28
+ |
+LL | const fn into_inner_lt(self) -> T { self.0 } //~ destructors cannot be evaluated
+ | ^^^^ constant functions cannot evaluate destructors
+
+error: mutable references in const fn are unstable
+ --> $DIR/min_const_fn.rs:58:5
+ |
+LL | const fn get_mut_lt(&'a mut self) -> &mut T { &mut self.0 }
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+error[E0493]: destructors cannot be evaluated at compile-time
+ --> $DIR/min_const_fn.rs:63:27
+ |
+LL | const fn into_inner_s(self) -> T { self.0 } //~ ERROR destructors
+ | ^^^^ constant functions cannot evaluate destructors
+
+error: mutable references in const fn are unstable
+ --> $DIR/min_const_fn.rs:65:5
+ |
+LL | const fn get_mut_s(&mut self) -> &mut T { &mut self.0 }
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+error: mutable references in const fn are unstable
+ --> $DIR/min_const_fn.rs:70:5
+ |
+LL | const fn get_mut_sq(&mut self) -> &mut T { &mut self.0 }
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+error: trait bounds other than `Sized` on const fn parameters are unstable
+ --> $DIR/min_const_fn.rs:88:16
+ |
+LL | const fn foo11<T: std::fmt::Display>(t: T) -> T { t }
+ | ^
+
+error: trait bounds other than `Sized` on const fn parameters are unstable
+ --> $DIR/min_const_fn.rs:90:18
+ |
+LL | const fn foo11_2<T: Send>(t: T) -> T { t }
+ | ^
+
+error: only int, `bool` and `char` operations are stable in const fn
+ --> $DIR/min_const_fn.rs:92:33
+ |
+LL | const fn foo19(f: f32) -> f32 { f * 2.0 }
+ | ^^^^^^^
+
+error: only int, `bool` and `char` operations are stable in const fn
+ --> $DIR/min_const_fn.rs:94:35
+ |
+LL | const fn foo19_2(f: f32) -> f32 { 2.0 - f }
+ | ^^^^^^^
+
+error: only int and `bool` operations are stable in const fn
+ --> $DIR/min_const_fn.rs:96:35
+ |
+LL | const fn foo19_3(f: f32) -> f32 { -f }
+ | ^^
+
+error: only int, `bool` and `char` operations are stable in const fn
+ --> $DIR/min_const_fn.rs:98:43
+ |
+LL | const fn foo19_4(f: f32, g: f32) -> f32 { f / g }
+ | ^^^^^
+
+error: cannot access `static` items in const fn
+ --> $DIR/min_const_fn.rs:102:27
+ |
+LL | const fn foo25() -> u32 { BAR } //~ ERROR cannot access `static` items in const fn
+ | ^^^
+
+error: cannot access `static` items in const fn
+ --> $DIR/min_const_fn.rs:103:36
+ |
+LL | const fn foo26() -> &'static u32 { &BAR } //~ ERROR cannot access `static` items
+ | ^^^^
+
+error: casting pointers to ints is unstable in const fn
+ --> $DIR/min_const_fn.rs:104:42
+ |
+LL | const fn foo30(x: *const u32) -> usize { x as usize }
+ | ^^^^^^^^^^
+
+error: casting pointers to ints is unstable in const fn
+ --> $DIR/min_const_fn.rs:106:42
+ |
+LL | const fn foo30_2(x: *mut u32) -> usize { x as usize }
+ | ^^^^^^^^^^
+
+error: `if`, `match`, `&&` and `||` are not stable in const fn
+ --> $DIR/min_const_fn.rs:108:38
+ |
+LL | const fn foo30_4(b: bool) -> usize { if b { 1 } else { 42 } }
+ | ^^^^^^^^^^^^^^^^^^^^^^
+
+error: `if`, `match`, `&&` and `||` are not stable in const fn
+ --> $DIR/min_const_fn.rs:110:29
+ |
+LL | const fn foo30_5(b: bool) { while b { } } //~ ERROR not stable in const fn
+ | ^^^^^^^^^^^
+
+error: local variables in const fn are unstable
+ --> $DIR/min_const_fn.rs:111:34
+ |
+LL | const fn foo30_6() -> bool { let x = true; x } //~ ERROR local variables in const fn are unstable
+ | ^
+
+error: `if`, `match`, `&&` and `||` are not stable in const fn
+ --> $DIR/min_const_fn.rs:112:44
+ |
+LL | const fn foo36(a: bool, b: bool) -> bool { a && b }
+ | ^^^^^^
+
+error: `if`, `match`, `&&` and `||` are not stable in const fn
+ --> $DIR/min_const_fn.rs:114:44
+ |
+LL | const fn foo37(a: bool, b: bool) -> bool { a || b }
+ | ^^^^^^
+
+error: mutable references in const fn are unstable
+ --> $DIR/min_const_fn.rs:116:14
+ |
+LL | const fn inc(x: &mut i32) { *x += 1 }
+ | ^
+
+error: trait bounds other than `Sized` on const fn parameters are unstable
+ --> $DIR/min_const_fn.rs:121:6
+ |
+LL | impl<T: std::fmt::Debug> Foo<T> {
+ | ^
+
+error: trait bounds other than `Sized` on const fn parameters are unstable
+ --> $DIR/min_const_fn.rs:126:6
+ |
+LL | impl<T: std::fmt::Debug + Sized> Foo<T> {
+ | ^
+
+error: trait bounds other than `Sized` on const fn parameters are unstable
+ --> $DIR/min_const_fn.rs:131:6
+ |
+LL | impl<T: Sync + Sized> Foo<T> {
+ | ^
+
+error: `impl Trait` in const fn is unstable
+ --> $DIR/min_const_fn.rs:137:1
+ |
+LL | const fn no_rpit2() -> AlanTuring<impl std::fmt::Debug> { AlanTuring(0) }
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+error: trait bounds other than `Sized` on const fn parameters are unstable
+ --> $DIR/min_const_fn.rs:139:34
+ |
+LL | const fn no_apit2(_x: AlanTuring<impl std::fmt::Debug>) {}
+ | ^^^^^^^^^^^^^^^^^^^^
+
+error: trait bounds other than `Sized` on const fn parameters are unstable
+ --> $DIR/min_const_fn.rs:141:22
+ |
+LL | const fn no_apit(_x: impl std::fmt::Debug) {} //~ ERROR trait bounds other than `Sized`
+ | ^^^^^^^^^^^^^^^^^^^^
+
+error: `impl Trait` in const fn is unstable
+ --> $DIR/min_const_fn.rs:142:1
+ |
+LL | const fn no_rpit() -> impl std::fmt::Debug {} //~ ERROR `impl Trait` in const fn is unstable
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+error: trait bounds other than `Sized` on const fn parameters are unstable
+ --> $DIR/min_const_fn.rs:143:23
+ |
+LL | const fn no_dyn_trait(_x: &dyn std::fmt::Debug) {} //~ ERROR trait bounds other than `Sized`
+ | ^^
+
+error: trait bounds other than `Sized` on const fn parameters are unstable
+ --> $DIR/min_const_fn.rs:144:1
+ |
+LL | const fn no_dyn_trait_ret() -> &'static dyn std::fmt::Debug { &() }
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+error[E0597]: borrowed value does not live long enough
+ --> $DIR/min_const_fn.rs:144:64
+ |
+LL | const fn no_dyn_trait_ret() -> &'static dyn std::fmt::Debug { &() }
+ | ^^ - temporary value only lives until here
+ | |
+ | temporary value does not live long enough
+ |
+ = note: borrowed value must be valid for the static lifetime...
+
+error: trait bounds other than `Sized` on const fn parameters are unstable
+ --> $DIR/min_const_fn.rs:149:41
+ |
+LL | const fn really_no_traits_i_mean_it() { (&() as &std::fmt::Debug, ()).1 }
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+error: function pointers in const fn are unstable
+ --> $DIR/min_const_fn.rs:152:21
+ |
+LL | const fn no_fn_ptrs(_x: fn()) {}
+ | ^^
+
+error: function pointers in const fn are unstable
+ --> $DIR/min_const_fn.rs:154:1
+ |
+LL | const fn no_fn_ptrs2() -> fn() { fn foo() {} foo }
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+error: aborting due to 36 previous errors
+
+Some errors occurred: E0493, E0597.
+For more information about an error, try `rustc --explain E0493`.
--- /dev/null
+// Copyright 2018 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+#![feature(min_const_fn)]
+
+// ok
+const fn foo1() {}
+const fn foo2(x: i32) -> i32 { x }
+const fn foo3<T>(x: T) -> T { x }
+const fn foo7() {
+ (
+ foo1(),
+ foo2(420),
+ foo3(69),
+ ).0
+}
+const fn foo12<T: Sized>(t: T) -> T { t }
+const fn foo13<T: ?Sized>(t: &T) -> &T { t }
+const fn foo14<'a, T: 'a>(t: &'a T) -> &'a T { t }
+const fn foo15<T>(t: T) -> T where T: Sized { t }
+const fn foo15_2<T>(t: &T) -> &T where T: ?Sized { t }
+const fn foo16(f: f32) -> f32 { f }
+const fn foo17(f: f32) -> u32 { f as u32 }
+const fn foo18(i: i32) -> i32 { i * 3 }
+const fn foo20(b: bool) -> bool { !b }
+const fn foo21<T, U>(t: T, u: U) -> (T, U) { (t, u) }
+const fn foo22(s: &[u8], i: usize) -> u8 { s[i] }
+const FOO: u32 = 42;
+const fn foo23() -> u32 { FOO }
+const fn foo24() -> &'static u32 { &FOO }
+const fn foo27(x: &u32) -> u32 { *x }
+const fn foo28(x: u32) -> u32 { *&x }
+const fn foo29(x: u32) -> i32 { x as i32 }
+const fn foo31(a: bool, b: bool) -> bool { a & b }
+const fn foo32(a: bool, b: bool) -> bool { a | b }
+const fn foo33(a: bool, b: bool) -> bool { a & b }
+const fn foo34(a: bool, b: bool) -> bool { a | b }
+const fn foo35(a: bool, b: bool) -> bool { a ^ b }
+struct Foo<T: ?Sized>(T);
+impl<T> Foo<T> {
+ const fn new(t: T) -> Self { Foo(t) }
+ const fn into_inner(self) -> T { self.0 } //~ destructors cannot be evaluated
+ const fn get(&self) -> &T { &self.0 }
+ const fn get_mut(&mut self) -> &mut T { &mut self.0 }
+ //~^ mutable references in const fn are unstable
+}
+impl<'a, T> Foo<T> {
+ const fn new_lt(t: T) -> Self { Foo(t) }
+ const fn into_inner_lt(self) -> T { self.0 } //~ destructors cannot be evaluated
+ const fn get_lt(&'a self) -> &T { &self.0 }
+ const fn get_mut_lt(&'a mut self) -> &mut T { &mut self.0 }
+ //~^ mutable references in const fn are unstable
+}
+impl<T: Sized> Foo<T> {
+ const fn new_s(t: T) -> Self { Foo(t) }
+ const fn into_inner_s(self) -> T { self.0 } //~ ERROR destructors
+ const fn get_s(&self) -> &T { &self.0 }
+ const fn get_mut_s(&mut self) -> &mut T { &mut self.0 }
+ //~^ mutable references in const fn are unstable
+}
+impl<T: ?Sized> Foo<T> {
+ const fn get_sq(&self) -> &T { &self.0 }
+ const fn get_mut_sq(&mut self) -> &mut T { &mut self.0 }
+ //~^ mutable references in const fn are unstable
+}
+
+
+const fn char_ops(c: char, d: char) -> bool { c == d }
+const fn char_ops2(c: char, d: char) -> bool { c < d }
+const fn char_ops3(c: char, d: char) -> bool { c != d }
+const fn i32_ops(c: i32, d: i32) -> bool { c == d }
+const fn i32_ops2(c: i32, d: i32) -> bool { c < d }
+const fn i32_ops3(c: i32, d: i32) -> bool { c != d }
+const fn i32_ops4(c: i32, d: i32) -> i32 { c + d }
+const fn char_cast(u: u8) -> char { u as char }
+const unsafe fn foo4() -> i32 { 42 }
+const unsafe fn foo5<T>() -> *const T { 0 as *const T }
+const unsafe fn foo6<T>() -> *mut T { 0 as *mut T }
+
+// not ok
+const fn foo11<T: std::fmt::Display>(t: T) -> T { t }
+//~^ ERROR trait bounds other than `Sized` on const fn parameters are unstable
+const fn foo11_2<T: Send>(t: T) -> T { t }
+//~^ ERROR trait bounds other than `Sized` on const fn parameters are unstable
+const fn foo19(f: f32) -> f32 { f * 2.0 }
+//~^ ERROR only int, `bool` and `char` operations are stable in const fn
+const fn foo19_2(f: f32) -> f32 { 2.0 - f }
+//~^ ERROR only int, `bool` and `char` operations are stable in const fn
+const fn foo19_3(f: f32) -> f32 { -f }
+//~^ ERROR only int and `bool` operations are stable in const fn
+const fn foo19_4(f: f32, g: f32) -> f32 { f / g }
+//~^ ERROR only int, `bool` and `char` operations are stable in const fn
+
+static BAR: u32 = 42;
+const fn foo25() -> u32 { BAR } //~ ERROR cannot access `static` items in const fn
+const fn foo26() -> &'static u32 { &BAR } //~ ERROR cannot access `static` items
+const fn foo30(x: *const u32) -> usize { x as usize }
+//~^ ERROR casting pointers to int
+const fn foo30_2(x: *mut u32) -> usize { x as usize }
+//~^ ERROR casting pointers to int
+const fn foo30_4(b: bool) -> usize { if b { 1 } else { 42 } }
+//~^ ERROR `if`, `match`, `&&` and `||` are not stable in const fn
+const fn foo30_5(b: bool) { while b { } } //~ ERROR not stable in const fn
+const fn foo30_6() -> bool { let x = true; x } //~ ERROR local variables in const fn are unstable
+const fn foo36(a: bool, b: bool) -> bool { a && b }
+//~^ ERROR `if`, `match`, `&&` and `||` are not stable in const fn
+const fn foo37(a: bool, b: bool) -> bool { a || b }
+//~^ ERROR `if`, `match`, `&&` and `||` are not stable in const fn
+const fn inc(x: &mut i32) { *x += 1 }
+//~^ ERROR mutable references in const fn are unstable
+
+fn main() {}
+
+impl<T: std::fmt::Debug> Foo<T> {
+//~^ ERROR trait bounds other than `Sized` on const fn parameters are unstable
+ const fn foo(&self) {}
+}
+
+impl<T: std::fmt::Debug + Sized> Foo<T> {
+//~^ ERROR trait bounds other than `Sized` on const fn parameters are unstable
+ const fn foo2(&self) {}
+}
+
+impl<T: Sync + Sized> Foo<T> {
+//~^ ERROR trait bounds other than `Sized` on const fn parameters are unstable
+ const fn foo3(&self) {}
+}
+
+struct AlanTuring<T>(T);
+const fn no_rpit2() -> AlanTuring<impl std::fmt::Debug> { AlanTuring(0) }
+//~^ ERROR `impl Trait` in const fn is unstable
+const fn no_apit2(_x: AlanTuring<impl std::fmt::Debug>) {}
+//~^ ERROR trait bounds other than `Sized`
+const fn no_apit(_x: impl std::fmt::Debug) {} //~ ERROR trait bounds other than `Sized`
+const fn no_rpit() -> impl std::fmt::Debug {} //~ ERROR `impl Trait` in const fn is unstable
+const fn no_dyn_trait(_x: &dyn std::fmt::Debug) {} //~ ERROR trait bounds other than `Sized`
+const fn no_dyn_trait_ret() -> &'static dyn std::fmt::Debug { &() }
+//~^ ERROR trait bounds other than `Sized`
+
+const fn no_unsafe() { unsafe {} }
+
+const fn really_no_traits_i_mean_it() { (&() as &std::fmt::Debug, ()).1 }
+//~^ ERROR trait bounds other than `Sized`
+
+const fn no_fn_ptrs(_x: fn()) {}
+//~^ ERROR function pointers in const fn are unstable
+const fn no_fn_ptrs2() -> fn() { fn foo() {} foo }
+//~^ ERROR function pointers in const fn are unstable
+
--- /dev/null
+error[E0493]: destructors cannot be evaluated at compile-time
+ --> $DIR/min_const_fn.rs:49:25
+ |
+LL | const fn into_inner(self) -> T { self.0 } //~ destructors cannot be evaluated
+ | ^^^^ constant functions cannot evaluate destructors
+
+error: mutable references in const fn are unstable
+ --> $DIR/min_const_fn.rs:51:5
+ |
+LL | const fn get_mut(&mut self) -> &mut T { &mut self.0 }
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+error[E0493]: destructors cannot be evaluated at compile-time
+ --> $DIR/min_const_fn.rs:56:28
+ |
+LL | const fn into_inner_lt(self) -> T { self.0 } //~ destructors cannot be evaluated
+ | ^^^^ constant functions cannot evaluate destructors
+
+error: mutable references in const fn are unstable
+ --> $DIR/min_const_fn.rs:58:5
+ |
+LL | const fn get_mut_lt(&'a mut self) -> &mut T { &mut self.0 }
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+error[E0493]: destructors cannot be evaluated at compile-time
+ --> $DIR/min_const_fn.rs:63:27
+ |
+LL | const fn into_inner_s(self) -> T { self.0 } //~ ERROR destructors
+ | ^^^^ constant functions cannot evaluate destructors
+
+error: mutable references in const fn are unstable
+ --> $DIR/min_const_fn.rs:65:5
+ |
+LL | const fn get_mut_s(&mut self) -> &mut T { &mut self.0 }
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+error: mutable references in const fn are unstable
+ --> $DIR/min_const_fn.rs:70:5
+ |
+LL | const fn get_mut_sq(&mut self) -> &mut T { &mut self.0 }
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+error: trait bounds other than `Sized` on const fn parameters are unstable
+ --> $DIR/min_const_fn.rs:88:16
+ |
+LL | const fn foo11<T: std::fmt::Display>(t: T) -> T { t }
+ | ^
+
+error: trait bounds other than `Sized` on const fn parameters are unstable
+ --> $DIR/min_const_fn.rs:90:18
+ |
+LL | const fn foo11_2<T: Send>(t: T) -> T { t }
+ | ^
+
+error: only int, `bool` and `char` operations are stable in const fn
+ --> $DIR/min_const_fn.rs:92:33
+ |
+LL | const fn foo19(f: f32) -> f32 { f * 2.0 }
+ | ^^^^^^^
+
+error: only int, `bool` and `char` operations are stable in const fn
+ --> $DIR/min_const_fn.rs:94:35
+ |
+LL | const fn foo19_2(f: f32) -> f32 { 2.0 - f }
+ | ^^^^^^^
+
+error: only int and `bool` operations are stable in const fn
+ --> $DIR/min_const_fn.rs:96:35
+ |
+LL | const fn foo19_3(f: f32) -> f32 { -f }
+ | ^^
+
+error: only int, `bool` and `char` operations are stable in const fn
+ --> $DIR/min_const_fn.rs:98:43
+ |
+LL | const fn foo19_4(f: f32, g: f32) -> f32 { f / g }
+ | ^^^^^
+
+error: cannot access `static` items in const fn
+ --> $DIR/min_const_fn.rs:102:27
+ |
+LL | const fn foo25() -> u32 { BAR } //~ ERROR cannot access `static` items in const fn
+ | ^^^
+
+error: cannot access `static` items in const fn
+ --> $DIR/min_const_fn.rs:103:36
+ |
+LL | const fn foo26() -> &'static u32 { &BAR } //~ ERROR cannot access `static` items
+ | ^^^^
+
+error: casting pointers to ints is unstable in const fn
+ --> $DIR/min_const_fn.rs:104:42
+ |
+LL | const fn foo30(x: *const u32) -> usize { x as usize }
+ | ^^^^^^^^^^
+
+error: casting pointers to ints is unstable in const fn
+ --> $DIR/min_const_fn.rs:106:42
+ |
+LL | const fn foo30_2(x: *mut u32) -> usize { x as usize }
+ | ^^^^^^^^^^
+
+error: `if`, `match`, `&&` and `||` are not stable in const fn
+ --> $DIR/min_const_fn.rs:108:38
+ |
+LL | const fn foo30_4(b: bool) -> usize { if b { 1 } else { 42 } }
+ | ^^^^^^^^^^^^^^^^^^^^^^
+
+error: `if`, `match`, `&&` and `||` are not stable in const fn
+ --> $DIR/min_const_fn.rs:110:29
+ |
+LL | const fn foo30_5(b: bool) { while b { } } //~ ERROR not stable in const fn
+ | ^^^^^^^^^^^
+
+error: local variables in const fn are unstable
+ --> $DIR/min_const_fn.rs:111:34
+ |
+LL | const fn foo30_6() -> bool { let x = true; x } //~ ERROR local variables in const fn are unstable
+ | ^
+
+error: `if`, `match`, `&&` and `||` are not stable in const fn
+ --> $DIR/min_const_fn.rs:112:44
+ |
+LL | const fn foo36(a: bool, b: bool) -> bool { a && b }
+ | ^^^^^^
+
+error: `if`, `match`, `&&` and `||` are not stable in const fn
+ --> $DIR/min_const_fn.rs:114:44
+ |
+LL | const fn foo37(a: bool, b: bool) -> bool { a || b }
+ | ^^^^^^
+
+error: mutable references in const fn are unstable
+ --> $DIR/min_const_fn.rs:116:14
+ |
+LL | const fn inc(x: &mut i32) { *x += 1 }
+ | ^
+
+error: trait bounds other than `Sized` on const fn parameters are unstable
+ --> $DIR/min_const_fn.rs:121:6
+ |
+LL | impl<T: std::fmt::Debug> Foo<T> {
+ | ^
+
+error: trait bounds other than `Sized` on const fn parameters are unstable
+ --> $DIR/min_const_fn.rs:126:6
+ |
+LL | impl<T: std::fmt::Debug + Sized> Foo<T> {
+ | ^
+
+error: trait bounds other than `Sized` on const fn parameters are unstable
+ --> $DIR/min_const_fn.rs:131:6
+ |
+LL | impl<T: Sync + Sized> Foo<T> {
+ | ^
+
+error: `impl Trait` in const fn is unstable
+ --> $DIR/min_const_fn.rs:137:1
+ |
+LL | const fn no_rpit2() -> AlanTuring<impl std::fmt::Debug> { AlanTuring(0) }
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+error: trait bounds other than `Sized` on const fn parameters are unstable
+ --> $DIR/min_const_fn.rs:139:34
+ |
+LL | const fn no_apit2(_x: AlanTuring<impl std::fmt::Debug>) {}
+ | ^^^^^^^^^^^^^^^^^^^^
+
+error: trait bounds other than `Sized` on const fn parameters are unstable
+ --> $DIR/min_const_fn.rs:141:22
+ |
+LL | const fn no_apit(_x: impl std::fmt::Debug) {} //~ ERROR trait bounds other than `Sized`
+ | ^^^^^^^^^^^^^^^^^^^^
+
+error: `impl Trait` in const fn is unstable
+ --> $DIR/min_const_fn.rs:142:1
+ |
+LL | const fn no_rpit() -> impl std::fmt::Debug {} //~ ERROR `impl Trait` in const fn is unstable
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+error: trait bounds other than `Sized` on const fn parameters are unstable
+ --> $DIR/min_const_fn.rs:143:23
+ |
+LL | const fn no_dyn_trait(_x: &dyn std::fmt::Debug) {} //~ ERROR trait bounds other than `Sized`
+ | ^^
+
+error: trait bounds other than `Sized` on const fn parameters are unstable
+ --> $DIR/min_const_fn.rs:144:1
+ |
+LL | const fn no_dyn_trait_ret() -> &'static dyn std::fmt::Debug { &() }
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+error: trait bounds other than `Sized` on const fn parameters are unstable
+ --> $DIR/min_const_fn.rs:149:41
+ |
+LL | const fn really_no_traits_i_mean_it() { (&() as &std::fmt::Debug, ()).1 }
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+error: function pointers in const fn are unstable
+ --> $DIR/min_const_fn.rs:152:21
+ |
+LL | const fn no_fn_ptrs(_x: fn()) {}
+ | ^^
+
+error: function pointers in const fn are unstable
+ --> $DIR/min_const_fn.rs:154:1
+ |
+LL | const fn no_fn_ptrs2() -> fn() { fn foo() {} foo }
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+error: aborting due to 35 previous errors
+
+For more information about this error, try `rustc --explain E0493`.
--- /dev/null
+error: trait bounds other than `Sized` on const fn parameters are unstable
+ --> $DIR/min_const_fn_dyn.rs:21:5
+ |
+LL | x.0.field;
+ | ^^^^^^^^^
+
+error: trait bounds other than `Sized` on const fn parameters are unstable
+ --> $DIR/min_const_fn_dyn.rs:24:66
+ |
+LL | const fn no_inner_dyn_trait_ret() -> Hide { Hide(HasDyn { field: &0 }) }
+ | ^^
+
+error[E0597]: borrowed value does not live long enough
+ --> $DIR/min_const_fn_dyn.rs:24:67
+ |
+LL | const fn no_inner_dyn_trait_ret() -> Hide { Hide(HasDyn { field: &0 }) }
+ | ^ - temporary value only lives until here
+ | |
+ | temporary value does not live long enough
+ |
+ = note: borrowed value must be valid for the static lifetime...
+
+error: aborting due to 3 previous errors
+
+For more information about this error, try `rustc --explain E0597`.
--- /dev/null
+// Copyright 2018 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+#![feature(min_const_fn)]
+
+struct HasDyn {
+ field: &'static dyn std::fmt::Debug,
+}
+
+struct Hide(HasDyn);
+
+const fn no_inner_dyn_trait(_x: Hide) {}
+const fn no_inner_dyn_trait2(x: Hide) {
+ x.0.field;
+//~^ ERROR trait bounds other than `Sized`
+}
+const fn no_inner_dyn_trait_ret() -> Hide { Hide(HasDyn { field: &0 }) }
+//~^ ERROR trait bounds other than `Sized`
+
+fn main() {}
--- /dev/null
+error: trait bounds other than `Sized` on const fn parameters are unstable
+ --> $DIR/min_const_fn_dyn.rs:21:5
+ |
+LL | x.0.field;
+ | ^^^^^^^^^
+
+error: trait bounds other than `Sized` on const fn parameters are unstable
+ --> $DIR/min_const_fn_dyn.rs:24:66
+ |
+LL | const fn no_inner_dyn_trait_ret() -> Hide { Hide(HasDyn { field: &0 }) }
+ | ^^
+
+error: aborting due to 2 previous errors
+
--- /dev/null
+// Copyright 2018 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+#![feature(min_const_fn)]
+
+struct HasPtr {
+ field: fn(),
+}
+
+struct Hide(HasPtr);
+
+fn field() {}
+
+const fn no_inner_dyn_trait(_x: Hide) {}
+const fn no_inner_dyn_trait2(x: Hide) {
+ x.0.field;
+//~^ ERROR function pointers in const fn
+}
+const fn no_inner_dyn_trait_ret() -> Hide { Hide(HasPtr { field }) }
+//~^ ERROR function pointers in const fn
+
+fn main() {}
--- /dev/null
+error: function pointers in const fn are unstable
+ --> $DIR/min_const_fn_fn_ptr.rs:23:5
+ |
+LL | x.0.field;
+ | ^^^^^^^^^
+
+error: function pointers in const fn are unstable
+ --> $DIR/min_const_fn_fn_ptr.rs:26:59
+ |
+LL | const fn no_inner_dyn_trait_ret() -> Hide { Hide(HasPtr { field }) }
+ | ^^^^^
+
+error: aborting due to 2 previous errors
+
--- /dev/null
+// Copyright 2018 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+#![feature(integer_atomics, min_const_fn)]
+
+// compile-pass
+
+use std::cell::UnsafeCell;
+use std::sync::atomic::AtomicU32;
+pub struct Condvar {
+ condvar: UnsafeCell<AtomicU32>,
+}
+
+unsafe impl Send for Condvar {}
+unsafe impl Sync for Condvar {}
+
+#[repr(C)]
+#[derive(Copy, Clone, Eq, PartialEq, Hash, Debug)]
+struct NoWait(u32);
+
+const CONDVAR_HAS_NO_WAITERS: NoWait = NoWait(42);
+
+impl Condvar {
+ pub const fn new() -> Condvar {
+ Condvar {
+ condvar: UnsafeCell::new(AtomicU32::new(CONDVAR_HAS_NO_WAITERS.0)),
+ }
+ }
+}
+
+fn main() {}
--- /dev/null
+// Copyright 2018 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+#![unstable(feature = "humans",
+ reason = "who ever let humans program computers,
+ we're apparently really bad at it",
+ issue = "0")]
+
+#![feature(rustc_const_unstable, const_fn, foo, foo2)]
+#![feature(staged_api)]
+
+#[stable(feature = "rust1", since = "1.0.0")]
+#[rustc_const_unstable(feature="foo")]
+const fn foo() -> u32 { 42 }
+
+#[stable(feature = "rust1", since = "1.0.0")]
+// can't call non-min_const_fn
+const fn bar() -> u32 { foo() } //~ ERROR can only call other `min_const_fn`
+
+#[unstable(feature = "rust1", issue="0")]
+const fn foo2() -> u32 { 42 }
+
+#[stable(feature = "rust1", since = "1.0.0")]
+// can't call non-min_const_fn
+const fn bar2() -> u32 { foo2() } //~ ERROR can only call other `min_const_fn`
+
+#[stable(feature = "rust1", since = "1.0.0")]
+// conformity is required, even with `const_fn` feature gate
+const fn bar3() -> u32 { (5f32 + 6f32) as u32 } //~ ERROR only int, `bool` and `char` operations
+
+// check whether this function cannot be called even with the feature gate active
+#[unstable(feature = "foo2", issue="0")]
+const fn foo2_gated() -> u32 { 42 }
+
+#[stable(feature = "rust1", since = "1.0.0")]
+// can't call non-min_const_fn
+const fn bar2_gated() -> u32 { foo2_gated() } //~ ERROR can only call other `min_const_fn`
+
+fn main() {}
--- /dev/null
+error: can only call other `min_const_fn` within a `min_const_fn`
+ --> $DIR/min_const_fn_libstd_stability.rs:25:25
+ |
+LL | const fn bar() -> u32 { foo() } //~ ERROR can only call other `min_const_fn`
+ | ^^^^^
+
+error: can only call other `min_const_fn` within a `min_const_fn`
+ --> $DIR/min_const_fn_libstd_stability.rs:32:26
+ |
+LL | const fn bar2() -> u32 { foo2() } //~ ERROR can only call other `min_const_fn`
+ | ^^^^^^
+
+error: only int, `bool` and `char` operations are stable in const fn
+ --> $DIR/min_const_fn_libstd_stability.rs:36:26
+ |
+LL | const fn bar3() -> u32 { (5f32 + 6f32) as u32 } //~ ERROR only int, `bool` and `char` operations
+ | ^^^^^^^^^^^^^
+
+error: can only call other `min_const_fn` within a `min_const_fn`
+ --> $DIR/min_const_fn_libstd_stability.rs:44:32
+ |
+LL | const fn bar2_gated() -> u32 { foo2_gated() } //~ ERROR can only call other `min_const_fn`
+ | ^^^^^^^^^^^^
+
+error: aborting due to 4 previous errors
+
--- /dev/null
+// Copyright 2018 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+#![feature(min_const_fn)]
+
+// ok
+const unsafe fn foo4() -> i32 { 42 }
+const unsafe fn foo5<T>() -> *const T { 0 as *const T }
+const unsafe fn foo6<T>() -> *mut T { 0 as *mut T }
+const fn no_unsafe() { unsafe {} }
+
+// not ok
+const fn foo8() -> i32 {
+ unsafe { foo4() } //~ ERROR unsafe operations are not allowed in const fn
+}
+const fn foo9() -> *const String {
+ unsafe { foo5::<String>() } //~ ERROR unsafe operations are not allowed in const fn
+}
+const fn foo10() -> *const Vec<std::cell::Cell<u32>> {
+ unsafe { foo6::<Vec<std::cell::Cell<u32>>>() } //~ ERROR not allowed in const fn
+}
+const unsafe fn foo30_3(x: *mut usize) -> usize { *x } //~ ERROR not allowed in const fn
+//~^ dereferencing raw pointers in constant functions
+
+fn main() {}
+
+const unsafe fn no_union() {
+ union Foo { x: (), y: () }
+ Foo { x: () }.y //~ ERROR not allowed in const fn
+ //~^ unions in const fn
+}
--- /dev/null
+error[E0658]: dereferencing raw pointers in constant functions is unstable (see issue #51911)
+ --> $DIR/min_const_fn_unsafe.rs:29:51
+ |
+LL | const unsafe fn foo30_3(x: *mut usize) -> usize { *x } //~ ERROR not allowed in const fn
+ | ^^
+ |
+ = help: add #![feature(const_raw_ptr_deref)] to the crate attributes to enable
+
+error[E0658]: unions in const fn are unstable (see issue #51909)
+ --> $DIR/min_const_fn_unsafe.rs:36:5
+ |
+LL | Foo { x: () }.y //~ ERROR not allowed in const fn
+ | ^^^^^^^^^^^^^^^
+ |
+ = help: add #![feature(const_fn_union)] to the crate attributes to enable
+
+error: call to unsafe function is unsafe and unsafe operations are not allowed in const fn
+ --> $DIR/min_const_fn_unsafe.rs:21:14
+ |
+LL | unsafe { foo4() } //~ ERROR unsafe operations are not allowed in const fn
+ | ^^^^^^ call to unsafe function
+ |
+ = note: consult the function's documentation for information on how to avoid undefined behavior
+
+error: call to unsafe function is unsafe and unsafe operations are not allowed in const fn
+ --> $DIR/min_const_fn_unsafe.rs:24:14
+ |
+LL | unsafe { foo5::<String>() } //~ ERROR unsafe operations are not allowed in const fn
+ | ^^^^^^^^^^^^^^^^ call to unsafe function
+ |
+ = note: consult the function's documentation for information on how to avoid undefined behavior
+
+error: call to unsafe function is unsafe and unsafe operations are not allowed in const fn
+ --> $DIR/min_const_fn_unsafe.rs:27:14
+ |
+LL | unsafe { foo6::<Vec<std::cell::Cell<u32>>>() } //~ ERROR not allowed in const fn
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ call to unsafe function
+ |
+ = note: consult the function's documentation for information on how to avoid undefined behavior
+
+error: dereference of raw pointer is unsafe and unsafe operations are not allowed in const fn
+ --> $DIR/min_const_fn_unsafe.rs:29:51
+ |
+LL | const unsafe fn foo30_3(x: *mut usize) -> usize { *x } //~ ERROR not allowed in const fn
+ | ^^ dereference of raw pointer
+ |
+ = note: raw pointers may be NULL, dangling or unaligned; they can violate aliasing rules and cause data races: all of these are undefined behavior
+
+error: access to union field is unsafe and unsafe operations are not allowed in const fn
+ --> $DIR/min_const_fn_unsafe.rs:36:5
+ |
+LL | Foo { x: () }.y //~ ERROR not allowed in const fn
+ | ^^^^^^^^^^^^^^^ access to union field
+ |
+ = note: the field may not be properly initialized: using uninitialized data will cause undefined behavior
+
+error: aborting due to 7 previous errors
+
+For more information about this error, try `rustc --explain E0658`.
--- /dev/null
+// Copyright 2017 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+// compile-flags: --test
+// run-pass
+
+#![feature(custom_test_frameworks)]
+#![test_runner(crate::foo_runner)]
+
+#[cfg(test)]
+fn foo_runner(ts: &[&Fn(usize)->()]) {
+ for (i, t) in ts.iter().enumerate() {
+ t(i);
+ }
+}
+
+#[test_case]
+fn test1(i: usize) {
+ println!("Hi #{}", i);
+}
+
+#[test_case]
+fn test2(i: usize) {
+ println!("Hey #{}", i);
+}
--- /dev/null
+// Copyright 2018 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+use std::process::exit;
+
+pub trait Testable {
+ // Name of the test
+ fn name(&self) -> String;
+
+ // Tests pass by default
+ fn run(&self) -> bool {
+ true
+ }
+
+ // A test can generate subtests
+ fn subtests(&self) -> Vec<Box<dyn Testable>> {
+ vec![]
+ }
+}
+
+fn run_test(t: &dyn Testable) -> bool {
+ let success = t.subtests().into_iter().all(|sub_t| run_test(&*sub_t)) && t.run();
+ println!("{}...{}", t.name(), if success { "SUCCESS" } else { "FAIL" });
+ success
+}
+
+pub fn runner(tests: &[&dyn Testable]) {
+ let mut failed = false;
+ for t in tests {
+ if !run_test(*t) {
+ failed = true;
+ }
+ }
+
+ if failed {
+ exit(1);
+ }
+}
--- /dev/null
+// Copyright 2018 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+pub trait Testable {
+ fn name(&self) -> String;
+ fn run(&self) -> Option<String>; // None will be success, Some is the error message
+}
+
+pub fn runner(tests: &[&dyn Testable]) {
+ for t in tests {
+ print!("{}........{}", t.name(), t.run().unwrap_or_else(|| "SUCCESS".to_string()));
+ }
+}
--- /dev/null
+// Copyright 2018 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+// run-pass
+// aux-build:dynamic_runner.rs
+// compile-flags:--test
+#![feature(custom_test_frameworks)]
+#![test_runner(dynamic_runner::runner)]
+
+extern crate dynamic_runner;
+
+pub struct AllFoo(&'static str);
+struct IsFoo(String);
+
+impl dynamic_runner::Testable for AllFoo {
+ fn name(&self) -> String {
+ String::from(self.0)
+ }
+
+ fn subtests(&self) -> Vec<Box<dyn dynamic_runner::Testable>> {
+ self.0.split(" ").map(|word|
+ Box::new(IsFoo(word.into())) as Box<dyn dynamic_runner::Testable>
+ ).collect()
+ }
+}
+
+impl dynamic_runner::Testable for IsFoo {
+ fn name(&self) -> String {
+ self.0.clone()
+ }
+
+ fn run(&self) -> bool {
+ self.0 == "foo"
+ }
+}
+
+#[test_case]
+const TEST_2: AllFoo = AllFoo("foo foo");
--- /dev/null
+// Copyright 2018 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+// run-pass
+// aux-build:example_runner.rs
+// compile-flags:--test
+
+#![feature(custom_test_frameworks)]
+#![test_runner(example_runner::runner)]
+extern crate example_runner;
+
+pub struct IsFoo(&'static str);
+
+impl example_runner::Testable for IsFoo {
+ fn name(&self) -> String {
+ self.0.to_string()
+ }
+
+ fn run(&self) -> Option<String> {
+ if self.0 != "foo" {
+ return Some(format!("{} != foo", self.0));
+ }
+ None
+ }
+}
+
+#[test_case]
+const TEST_1: IsFoo = IsFoo("hello");
+
+#[test_case]
+const TEST_2: IsFoo = IsFoo("foo");
--- /dev/null
+// Copyright 2018 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+// aux-build:example_runner.rs
+// compile-flags:--test
+#![feature(custom_test_frameworks)]
+#![test_runner(example_runner::runner)]
+
+extern crate example_runner;
+
+#[test]
+fn wrong_kind(){}
--- /dev/null
+error[E0277]: the trait bound `test::TestDescAndFn: example_runner::Testable` is not satisfied
+ --> $DIR/mismatch.rs:19:1
+ |
+LL | fn wrong_kind(){}
+ | ^^^^^^^^^^^^^^^^^ the trait `example_runner::Testable` is not implemented for `test::TestDescAndFn`
+ |
+ = note: required for the cast to the object type `dyn example_runner::Testable`
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0277`.
fn foo(_: String) {}
fn foo2(s: &String) {
- foo(s); //~ ERROR mismatched types
+ foo(s);
+ //~^ ERROR mismatched types
}
fn foo3(_: u32) {}
fn foo4(u: &u32) {
- foo3(u); //~ ERROR mismatched types
+ foo3(u);
+ //~^ ERROR mismatched types
}
fn main() {
let s = String::new();
let r_s = &s;
foo2(r_s);
- foo(&"aaa".to_owned()); //~ ERROR mismatched types
- foo(&mut "aaa".to_owned()); //~ ERROR mismatched types
+ foo(&"aaa".to_owned());
+ //~^ ERROR mismatched types
+ foo(&mut "aaa".to_owned());
+ //~^ ERROR mismatched types
foo3(borrow!(0));
foo4(&0);
+ assert_eq!(3i32, &3i32);
+ //~^ ERROR mismatched types
}
error[E0308]: mismatched types
--> $DIR/deref-suggestion.rs:18:9
|
-LL | foo(s); //~ ERROR mismatched types
+LL | foo(s);
| ^
| |
| expected struct `std::string::String`, found reference
found type `&std::string::String`
error[E0308]: mismatched types
- --> $DIR/deref-suggestion.rs:23:10
+ --> $DIR/deref-suggestion.rs:24:10
|
-LL | foo3(u); //~ ERROR mismatched types
+LL | foo3(u);
| ^
| |
| expected u32, found &u32
found type `&u32`
error[E0308]: mismatched types
- --> $DIR/deref-suggestion.rs:30:9
+ --> $DIR/deref-suggestion.rs:32:9
|
-LL | foo(&"aaa".to_owned()); //~ ERROR mismatched types
+LL | foo(&"aaa".to_owned());
| ^^^^^^^^^^^^^^^^^
| |
| expected struct `std::string::String`, found reference
found type `&std::string::String`
error[E0308]: mismatched types
- --> $DIR/deref-suggestion.rs:31:9
+ --> $DIR/deref-suggestion.rs:34:9
|
-LL | foo(&mut "aaa".to_owned()); //~ ERROR mismatched types
+LL | foo(&mut "aaa".to_owned());
| ^^^^^^^^^^^^^^^^^^^^^
| |
| expected struct `std::string::String`, found mutable reference
= note: expected type `u32`
found type `&{integer}`
-error: aborting due to 5 previous errors
+error[E0308]: mismatched types
+ --> $DIR/deref-suggestion.rs:38:5
+ |
+LL | assert_eq!(3i32, &3i32);
+ | ^^^^^^^^^^^^^^^^^^^^^^^^ expected i32, found &i32
+ |
+ = note: expected type `i32`
+ found type `&i32`
+ = note: this error originates in a macro outside of the current crate (in Nightly builds, run with -Z external-macro-backtrace for more info)
+
+error: aborting due to 6 previous errors
For more information about this error, try `rustc --explain E0308`.
LL | S[0];
| ^^^^
-error[E0507]: cannot move out of borrowed content
- --> $DIR/dst-index.rs:41:5
- |
-LL | S[0];
- | ^^^^ cannot move out of borrowed content
-
error[E0161]: cannot move a value of type dyn std::fmt::Debug: the size of dyn std::fmt::Debug cannot be statically determined
--> $DIR/dst-index.rs:44:5
|
LL | T[0];
| ^^^^
+error[E0507]: cannot move out of borrowed content
+ --> $DIR/dst-index.rs:41:5
+ |
+LL | S[0];
+ | ^^^^ cannot move out of borrowed content
+
error[E0507]: cannot move out of borrowed content
--> $DIR/dst-index.rs:44:5
|
LL | let _x: Box<str> = box *"hello world";
| ^^^^^^^^^^^^^^
-error[E0507]: cannot move out of borrowed content
- --> $DIR/dst-rvalue.rs:16:28
- |
-LL | let _x: Box<str> = box *"hello world";
- | ^^^^^^^^^^^^^^ cannot move out of borrowed content
-
error[E0161]: cannot move a value of type [isize]: the size of [isize] cannot be statically determined
--> $DIR/dst-rvalue.rs:21:32
|
LL | let _x: Box<[isize]> = box *array;
| ^^^^^^
+error[E0507]: cannot move out of borrowed content
+ --> $DIR/dst-rvalue.rs:16:28
+ |
+LL | let _x: Box<str> = box *"hello world";
+ | ^^^^^^^^^^^^^^ cannot move out of borrowed content
+
error[E0508]: cannot move out of type `[isize]`, a non-copy slice
--> $DIR/dst-rvalue.rs:21:32
|
Bu64 = 0x8000_0000_0000_0000 //~ERROR already exists
}
+fn main() {}
-error[E0601]: `main` function not found in crate `enum_discrim_autosizing`
- |
- = note: consider adding a `main` function to `$DIR/enum-discrim-autosizing.rs`
-
error[E0081]: discriminant value `0` already exists
--> $DIR/enum-discrim-autosizing.rs:18:12
|
LL | Bu64 = 0x8000_0000_0000_0000 //~ERROR already exists
| ^^^^^^^^^^^^^^^^^^^^^ enum already has `0`
-error: aborting due to 2 previous errors
+error: aborting due to previous error
-Some errors occurred: E0081, E0601.
-For more information about an error, try `rustc --explain E0081`.
+For more information about this error, try `rustc --explain E0081`.
--- /dev/null
+error[E0161]: cannot move a value of type [i32]: the size of [i32] cannot be statically determined
+ --> $DIR/E0161.rs:32:9
+ |
+LL | box *x; //~ ERROR E0161
+ | ^^
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0161`.
--- /dev/null
+error[E0161]: cannot move a value of type [i32]: the size of [i32] cannot be statically determined
+ --> $DIR/E0161.rs:32:5
+ |
+LL | box *x; //~ ERROR E0161
+ | ^^^^^^
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0161`.
--- /dev/null
+error[E0161]: cannot move a value of type [i32]: the size of [i32] cannot be statically determined
+ --> $DIR/E0161.rs:32:9
+ |
+LL | box *x; //~ ERROR E0161
+ | ^^
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0161`.
--- /dev/null
+error[E0161]: cannot move a value of type [i32]: the size of [i32] cannot be statically determined
+ --> $DIR/E0161.rs:32:5
+ |
+LL | box *x; //~ ERROR E0161
+ | ^^^^^^
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0161`.
--- /dev/null
+error[E0161]: cannot move a value of type [i32]: the size of [i32] cannot be statically determined
+ --> $DIR/E0161.rs:32:9
+ |
+LL | box *x; //~ ERROR E0161
+ | ^^
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0161`.
--- /dev/null
+error[E0161]: cannot move a value of type [i32]: the size of [i32] cannot be statically determined
+ --> $DIR/E0161.rs:32:5
+ |
+LL | box *x; //~ ERROR E0161
+ | ^^^^^^
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0161`.
// option. This file may not be copied, modified, or distributed
// except according to those terms.
+// ignore-compare-mode-nll
+
+// Check that E0161 is a hard error in all possible configurations that might
+// affect it.
+
+// revisions: ast nll zflags edition astul nllul zflagsul editionul
+//[zflags]compile-flags: -Z borrowck=migrate -Z two-phase-borrows
+//[edition]edition:2018
+//[zflagsul]compile-flags: -Z borrowck=migrate -Z two-phase-borrows
+//[editionul]edition:2018
+
+#![cfg_attr(nll, feature(nll))]
+#![cfg_attr(nllul, feature(nll))]
+#![cfg_attr(astul, feature(unsized_locals))]
+#![cfg_attr(zflagsul, feature(unsized_locals))]
+#![cfg_attr(nllul, feature(unsized_locals))]
+#![cfg_attr(editionul, feature(unsized_locals))]
+
#![feature(box_syntax)]
-fn main() {
- let _x: Box<str> = box *"hello"; //~ ERROR E0161
- //~^ ERROR E0507
+fn foo(x: Box<[i32]>) {
+ box *x; //~ ERROR E0161
}
+
+fn main() {}
--- /dev/null
+error[E0161]: cannot move a value of type [i32]: the size of [i32] cannot be statically determined
+ --> $DIR/E0161.rs:32:9
+ |
+LL | box *x; //~ ERROR E0161
+ | ^^
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0161`.
--- /dev/null
+error[E0161]: cannot move a value of type [i32]: the size of [i32] cannot be statically determined
+ --> $DIR/E0161.rs:32:5
+ |
+LL | box *x; //~ ERROR E0161
+ | ^^^^^^
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0161`.
LL | fn size_of<T>(); //~ ERROR E0308
| ^^^^^^^^^^^^^^^^ expected (), found usize
|
- = note: expected type `unsafe extern "rust-intrinsic" fn()`
- found type `unsafe extern "rust-intrinsic" fn() -> usize`
+ = note: expected type `extern "rust-intrinsic" fn()`
+ found type `extern "rust-intrinsic" fn() -> usize`
error: aborting due to previous error
-warning: not reporting region error due to nll
- --> $DIR/E0621-does-not-trigger-for-closures.rs:25:5
- |
-LL | invoke(&x, |a, b| if a > b { a } else { b }); //~ ERROR E0495
- | ^^^^^^
-
error: unsatisfied lifetime constraints
--> $DIR/E0621-does-not-trigger-for-closures.rs:25:45
|
= note: expected type `i32`
found type `WrongGeneric::<&{integer}>`
-warning: not reporting region error due to nll
- --> $DIR/generic_type_does_not_live_long_enough.rs:19:1
- |
-LL | existential type WrongGeneric<T>: 'static;
- | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
-
error: aborting due to previous error
For more information about this error, try `rustc --explain E0308`.
--- /dev/null
+// Copyright 2017 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+#![test_runner(main)] //~ ERROR custom test frameworks are an unstable feature
+
+fn main() {}
--- /dev/null
+error[E0658]: custom test frameworks are an unstable feature (see issue #50297)
+ --> $DIR/feature-gate-custom_test_frameworks.rs:11:1
+ |
+LL | #![test_runner(main)] //~ ERROR custom test frameworks are an unstable feature
+ | ^^^^^^^^^^^^^^^^^^^^^
+ |
+ = help: add #![feature(custom_test_frameworks)] to the crate attributes to enable
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0658`.
--- /dev/null
+// Copyright 2018 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+#[cfg(rustdoc)] //~ ERROR: `cfg(rustdoc)` is experimental and subject to change
+pub struct SomeStruct;
+
+fn main() {}
--- /dev/null
+error[E0658]: `cfg(rustdoc)` is experimental and subject to change (see issue #43781)
+ --> $DIR/feature-gate-doc_cfg-cfg-rustdoc.rs:11:7
+ |
+LL | #[cfg(rustdoc)] //~ ERROR: `cfg(rustdoc)` is experimental and subject to change
+ | ^^^^^^^
+ |
+ = help: add #![feature(doc_cfg)] to the crate attributes to enable
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0658`.
// option. This file may not be copied, modified, or distributed
// except according to those terms.
-// Test use of const fn without feature gate.
+// Test use of const fn without the `const_fn` feature gate.
+// `min_const_fn` is checked in its own file
+#![feature(min_const_fn)]
-const fn foo() -> usize { 0 } //~ ERROR const fn is unstable
+const fn foo() -> usize { 0 } // ok
trait Foo {
const fn foo() -> u32; //~ ERROR const fn is unstable
}
impl Foo {
- const fn baz() -> u32 { 0 } //~ ERROR const fn is unstable
+ const fn baz() -> u32 { 0 } // ok
}
impl Foo for u32 {
- const fn foo() -> u32 { 0 } //~ ERROR const fn is unstable
- //~| ERROR trait fns cannot be declared const
+ const fn foo() -> u32 { 0 } //~ ERROR trait fns cannot be declared const
}
static FOO: usize = foo();
error[E0379]: trait fns cannot be declared const
- --> $DIR/feature-gate-const_fn.rs:16:5
+ --> $DIR/feature-gate-const_fn.rs:18:5
|
LL | const fn foo() -> u32; //~ ERROR const fn is unstable
| ^^^^^ trait fns cannot be const
error[E0379]: trait fns cannot be declared const
- --> $DIR/feature-gate-const_fn.rs:18:5
+ --> $DIR/feature-gate-const_fn.rs:20:5
|
LL | const fn bar() -> u32 { 0 } //~ ERROR const fn is unstable
| ^^^^^ trait fns cannot be const
error[E0379]: trait fns cannot be declared const
- --> $DIR/feature-gate-const_fn.rs:27:5
+ --> $DIR/feature-gate-const_fn.rs:29:5
|
-LL | const fn foo() -> u32 { 0 } //~ ERROR const fn is unstable
+LL | const fn foo() -> u32 { 0 } //~ ERROR trait fns cannot be declared const
| ^^^^^ trait fns cannot be const
error[E0658]: const fn is unstable (see issue #24111)
- --> $DIR/feature-gate-const_fn.rs:13:1
- |
-LL | const fn foo() -> usize { 0 } //~ ERROR const fn is unstable
- | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
- |
- = help: add #![feature(const_fn)] to the crate attributes to enable
-
-error[E0658]: const fn is unstable (see issue #24111)
- --> $DIR/feature-gate-const_fn.rs:16:5
+ --> $DIR/feature-gate-const_fn.rs:18:5
|
LL | const fn foo() -> u32; //~ ERROR const fn is unstable
| ^^^^^^^^^^^^^^^^^^^^^^
= help: add #![feature(const_fn)] to the crate attributes to enable
error[E0658]: const fn is unstable (see issue #24111)
- --> $DIR/feature-gate-const_fn.rs:18:5
+ --> $DIR/feature-gate-const_fn.rs:20:5
|
LL | const fn bar() -> u32 { 0 } //~ ERROR const fn is unstable
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
= help: add #![feature(const_fn)] to the crate attributes to enable
-error[E0658]: const fn is unstable (see issue #24111)
- --> $DIR/feature-gate-const_fn.rs:23:5
- |
-LL | const fn baz() -> u32 { 0 } //~ ERROR const fn is unstable
- | ^^^^^^^^^^^^^^^^^^^^^^^^^^^
- |
- = help: add #![feature(const_fn)] to the crate attributes to enable
-
-error[E0658]: const fn is unstable (see issue #24111)
- --> $DIR/feature-gate-const_fn.rs:27:5
- |
-LL | const fn foo() -> u32 { 0 } //~ ERROR const fn is unstable
- | ^^^^^^^^^^^^^^^^^^^^^^^^^^^
- |
- = help: add #![feature(const_fn)] to the crate attributes to enable
-
-error: aborting due to 8 previous errors
+error: aborting due to 5 previous errors
Some errors occurred: E0379, E0658.
For more information about an error, try `rustc --explain E0379`.
--- /dev/null
+// Copyright 2015 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+// Test use of min_const_fn without feature gate.
+
+const fn foo() -> usize { 0 } //~ ERROR const fn is unstable
+
+trait Foo {
+ const fn foo() -> u32; //~ ERROR const fn is unstable
+ //~| ERROR trait fns cannot be declared const
+ const fn bar() -> u32 { 0 } //~ ERROR const fn is unstable
+ //~| ERROR trait fns cannot be declared const
+}
+
+impl Foo {
+ const fn baz() -> u32 { 0 } //~ ERROR const fn is unstable
+}
+
+impl Foo for u32 {
+ const fn foo() -> u32 { 0 } //~ ERROR const fn is unstable
+ //~| ERROR trait fns cannot be declared const
+}
+
+static FOO: usize = foo();
+const BAR: usize = foo();
+
+macro_rules! constant {
+ ($n:ident: $t:ty = $v:expr) => {
+ const $n: $t = $v;
+ }
+}
+
+constant! {
+ BAZ: usize = foo()
+}
+
+fn main() {
+ let x: [usize; foo()] = [];
+}
--- /dev/null
+error[E0379]: trait fns cannot be declared const
+ --> $DIR/feature-gate-min_const_fn.rs:16:5
+ |
+LL | const fn foo() -> u32; //~ ERROR const fn is unstable
+ | ^^^^^ trait fns cannot be const
+
+error[E0379]: trait fns cannot be declared const
+ --> $DIR/feature-gate-min_const_fn.rs:18:5
+ |
+LL | const fn bar() -> u32 { 0 } //~ ERROR const fn is unstable
+ | ^^^^^ trait fns cannot be const
+
+error[E0379]: trait fns cannot be declared const
+ --> $DIR/feature-gate-min_const_fn.rs:27:5
+ |
+LL | const fn foo() -> u32 { 0 } //~ ERROR const fn is unstable
+ | ^^^^^ trait fns cannot be const
+
+error[E0658]: const fn is unstable (see issue #53555)
+ --> $DIR/feature-gate-min_const_fn.rs:13:1
+ |
+LL | const fn foo() -> usize { 0 } //~ ERROR const fn is unstable
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+ |
+ = help: add #![feature(min_const_fn)] to the crate attributes to enable
+
+error[E0658]: const fn is unstable (see issue #24111)
+ --> $DIR/feature-gate-min_const_fn.rs:16:5
+ |
+LL | const fn foo() -> u32; //~ ERROR const fn is unstable
+ | ^^^^^^^^^^^^^^^^^^^^^^
+ |
+ = help: add #![feature(const_fn)] to the crate attributes to enable
+
+error[E0658]: const fn is unstable (see issue #24111)
+ --> $DIR/feature-gate-min_const_fn.rs:18:5
+ |
+LL | const fn bar() -> u32 { 0 } //~ ERROR const fn is unstable
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^
+ |
+ = help: add #![feature(const_fn)] to the crate attributes to enable
+
+error[E0658]: const fn is unstable (see issue #53555)
+ --> $DIR/feature-gate-min_const_fn.rs:23:5
+ |
+LL | const fn baz() -> u32 { 0 } //~ ERROR const fn is unstable
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^
+ |
+ = help: add #![feature(min_const_fn)] to the crate attributes to enable
+
+error[E0658]: const fn is unstable (see issue #53555)
+ --> $DIR/feature-gate-min_const_fn.rs:27:5
+ |
+LL | const fn foo() -> u32 { 0 } //~ ERROR const fn is unstable
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^
+ |
+ = help: add #![feature(min_const_fn)] to the crate attributes to enable
+
+error: aborting due to 8 previous errors
+
+Some errors occurred: E0379, E0658.
+For more information about an error, try `rustc --explain E0379`.
#![feature = "foo"] //~ ERROR: malformed feature
#![feature(test_removed_feature)] //~ ERROR: feature has been removed
+
+fn main() {}
LL | #![feature(test_removed_feature)] //~ ERROR: feature has been removed
| ^^^^^^^^^^^^^^^^^^^^
-error[E0601]: `main` function not found in crate `gated_bad_feature`
- |
- = note: consider adding a `main` function to `$DIR/gated-bad-feature.rs`
-
-error: aborting due to 6 previous errors
+error: aborting due to 5 previous errors
-Some errors occurred: E0555, E0556, E0557, E0601.
+Some errors occurred: E0555, E0556, E0557.
For more information about an error, try `rustc --explain E0555`.
-warning: not reporting region error due to nll
- --> $DIR/hr-subtype.rs:43:26
- |
-LL | gimme::<$t2>(None::<$t1>);
- | ^^^^^^^^^^^
-...
-LL | / check! { free_inv_x_vs_free_inv_y: (fn(Inv<'x>),
-LL | | fn(Inv<'y>)) }
- | |__________________________________________________- in this macro invocation
-
-warning: not reporting region error due to nll
- --> $DIR/hr-subtype.rs:49:26
- |
-LL | gimme::<$t1>(None::<$t2>);
- | ^^^^^^^^^^^
-...
-LL | / check! { free_inv_x_vs_free_inv_y: (fn(Inv<'x>),
-LL | | fn(Inv<'y>)) }
- | |__________________________________________________- in this macro invocation
-
error: unsatisfied lifetime constraints
--> $DIR/hr-subtype.rs:43:13
|
-warning: not reporting region error due to nll
- --> $DIR/hr-subtype.rs:49:26
- |
-LL | gimme::<$t1>(None::<$t2>);
- | ^^^^^^^^^^^
-...
-LL | / check! { free_x_vs_free_y: (fn(&'x u32),
-LL | | fn(&'y u32)) }
- | |__________________________________________- in this macro invocation
-
error: unsatisfied lifetime constraints
--> $DIR/hr-subtype.rs:49:13
|
error[E0382]: use of moved value: `foo.x`
--> $DIR/fields-move.rs:28:9
|
-LL | $foo.x
- | ------ value moved here
-...
LL | $foo.x //~ ERROR use of moved value: `foo.x`
| ^^^^^^ value used here after move
...
error[E0382]: use of moved value: `foo.x`
--> $DIR/fields-move.rs:39:42
|
-LL | $foo.x
- | ------ value moved here
-...
LL | $foo.x //~ ERROR use of moved value: `foo.x`
| ------ value moved here
...
-LL | assert_two_copies(copy_modern!(foo), foo.x); //~ ERROR use of moved value: `foo.x`
- | ----- value moved here
LL | assert_two_copies(copy_legacy!(foo), foo.x); //~ ERROR use of moved value: `foo.x`
| ^^^^^ value used here after move
|
struct FromOutside;
genmod_legacy!();
}
+
+fn main() {}
LL | genmod_legacy!();
| ----------------- in this macro invocation
-error[E0601]: `main` function not found in crate `generate_mod`
- |
- = note: consider adding a `main` function to `$DIR/generate-mod.rs`
-
-error: aborting due to 7 previous errors
+error: aborting due to 6 previous errors
-Some errors occurred: E0412, E0601.
-For more information about an error, try `rustc --explain E0412`.
+For more information about this error, try `rustc --explain E0412`.
}
fn f() { ::foo::m!(); }
}
+
+fn main() {}
LL | Vec::new(); //~ ERROR failed to resolve
| ^^^ Use of undeclared type or module `Vec`
-error[E0601]: `main` function not found in crate `no_implicit_prelude`
- |
- = note: consider adding a `main` function to `$DIR/no_implicit_prelude.rs`
-
error[E0599]: no method named `clone` found for type `()` in the current scope
--> $DIR/no_implicit_prelude.rs:22:12
|
= note: the following trait is implemented but not in scope, perhaps add a `use` for it:
`use std::clone::Clone;`
-error: aborting due to 3 previous errors
+error: aborting due to 2 previous errors
-Some errors occurred: E0433, E0599, E0601.
+Some errors occurred: E0433, E0599.
For more information about an error, try `rustc --explain E0433`.
-warning: not reporting region error due to nll
- --> $DIR/dyn-trait.rs:32:16
- |
-LL | static_val(x); //~ ERROR cannot infer
- | ^
-
error: borrowed data escapes outside of function
--> $DIR/dyn-trait.rs:32:5
|
-warning: not reporting region error due to nll
- --> $DIR/must_outlive_least_region_or_bound.rs:13:35
- |
-LL | fn elided(x: &i32) -> impl Copy { x }
- | ^
-
-warning: not reporting region error due to nll
- --> $DIR/must_outlive_least_region_or_bound.rs:16:44
- |
-LL | fn explicit<'a>(x: &'a i32) -> impl Copy { x }
- | ^
-
-warning: not reporting region error due to nll
- --> $DIR/must_outlive_least_region_or_bound.rs:22:69
- |
-LL | fn with_bound<'a>(x: &'a i32) -> impl LifetimeTrait<'a> + 'static { x }
- | ^
-
-warning: not reporting region error due to nll
- --> $DIR/must_outlive_least_region_or_bound.rs:29:5
- |
-LL | move |_| println!("{}", y)
- | ^^^^^^^^^^^^^^^^^^^^^^^^^^
-
-warning: not reporting region error due to nll
- --> $DIR/must_outlive_least_region_or_bound.rs:32:51
- |
-LL | fn ty_param_wont_outlive_static<T:Debug>(x: T) -> impl Debug + 'static {
- | ^^^^^^^^^^^^^^^^^^^^
-
error[E0621]: explicit lifetime required in the type of `x`
--> $DIR/must_outlive_least_region_or_bound.rs:13:35
|
-warning: not reporting region error due to nll
- --> $DIR/static-return-lifetime-infered.rs:17:16
- |
-LL | self.x.iter().map(|a| a.0)
- | ^^^^
-
-warning: not reporting region error due to nll
- --> $DIR/static-return-lifetime-infered.rs:21:16
- |
-LL | self.x.iter().map(|a| a.0)
- | ^^^^
-
error: unsatisfied lifetime constraints
--> $DIR/static-return-lifetime-infered.rs:17:9
|
-warning: not reporting region error due to nll
- --> $DIR/type_parameters_captured.rs:17:20
- |
-LL | fn foo<T>(x: T) -> impl Any + 'static {
- | ^^^^^^^^^^^^^^^^^^
-
error[E0310]: the parameter type `T` may not live long enough
--> $DIR/type_parameters_captured.rs:19:5
|
fn test() { f1066(); } //~ ERROR cannot find function `f1066` in this scope
}
+
+fn main() {}
LL | fn test() { f1066(); } //~ ERROR cannot find function `f1066` in this scope
| ^^^^^ not found in this scope
-error[E0601]: `main` function not found in crate `import_glob_circular`
- |
- = note: consider adding a `main` function to `$DIR/import-glob-circular.rs`
-
-error: aborting due to 2 previous errors
+error: aborting due to previous error
-Some errors occurred: E0425, E0601.
-For more information about an error, try `rustc --explain E0425`.
+For more information about this error, try `rustc --explain E0425`.
fn main() { let y = x; }
}
+
+fn main() {}
LL | pub use a::x;
| ^^^^ no `x` in `a`
-error[E0601]: `main` function not found in crate `import_loop_2`
- |
- = note: the main function must be defined at the crate level but you have one or more functions named 'main' that are not defined at the crate level. Either move the definition or attach the `#[main]` attribute to override this behavior.
-note: here is a function named 'main'
- --> $DIR/import-loop-2.rs:20:5
- |
-LL | fn main() { let y = x; }
- | ^^^^^^^^^^^^^^^^^^^^^^^^
-
-error: aborting due to 2 previous errors
+error: aborting due to previous error
-Some errors occurred: E0432, E0601.
-For more information about an error, try `rustc --explain E0432`.
+For more information about this error, try `rustc --explain E0432`.
-warning: not reporting region error due to nll
- --> $DIR/mismatched.rs:14:42
- |
-LL | fn foo(x: &'a u32, y: &u32) -> &'a u32 { y } //~ ERROR explicit lifetime required
- | ^
-
-warning: not reporting region error due to nll
- --> $DIR/mismatched.rs:16:46
- |
-LL | fn foo2(x: &'a u32, y: &'b u32) -> &'a u32 { y } //~ ERROR lifetime mismatch
- | ^
-
error[E0621]: explicit lifetime required in the type of `y`
--> $DIR/mismatched.rs:14:42
|
+++ /dev/null
-warning: not reporting region error due to nll
- --> $DIR/mismatched_trait.rs:16:9
- |
-LL | y //~ ERROR explicit lifetime required
- | ^
-
-error[E0621]: explicit lifetime required in the type of `y`
- --> $DIR/mismatched_trait.rs:16:9
- |
-LL | fn baz(&self, x: &'a u32, y: &u32) -> &'a u32 {
- | ---- help: add explicit lifetime `'a` to the type of `y`: `&'a u32`
-LL | y //~ ERROR explicit lifetime required
- | ^ lifetime `'a` required
-
-error: aborting due to previous error
-
-For more information about this error, try `rustc --explain E0621`.
--> $DIR/inaccessible-test-modules.rs:15:5
|
LL | use __test as x; //~ ERROR unresolved import `__test`
- | ^^^^^^^^^^^ no `__test` in the root. Did you mean to use `__test`?
+ | ^^^^^^^^^^^ no `__test` in the root. Did you mean to use `test`?
error[E0432]: unresolved import `__test_reexports`
--> $DIR/inaccessible-test-modules.rs:16:5
//https://github.com/rust-lang/rust/issues/31364
-#![feature(const_fn)]
+#![feature(min_const_fn)]
const fn a() -> usize { b() }
const fn b() -> usize { a() }
const ARR: [i32; a()] = [5; 6]; //~ ERROR could not evaluate constant expression
#![crate_type(lib)] //~ ERROR `crate_type` requires a value
fn my_lib_fn() {}
+
+fn main() {}
|
= note: for example: `#![crate_type="lib"]`
-error[E0601]: `main` function not found in crate `invalid_crate_type_syntax`
- |
- = note: consider adding a `main` function to `$DIR/invalid_crate_type_syntax.rs`
-
-error: aborting due to 2 previous errors
+error: aborting due to previous error
-For more information about this error, try `rustc --explain E0601`.
-warning: not reporting region error due to nll
- --> $DIR/issue-10291.rs:13:9
- |
-LL | x //~ ERROR E0312
- | ^
-
error: unsatisfied lifetime constraints
--> $DIR/issue-10291.rs:12:5
|
fn main() {
concat!(test!());
- //~^ ERROR cannot find macro `test!` in this scope
+ //~^ error: cannot find macro `test!` in this scope
}
| ^^^^^^^^^^^^^^^^^^^^ expected isize, found mutable reference
|
= note: expected type `isize`
- found type `&mut __test::test::Bencher`
+ found type `&mut test::Bencher`
error: aborting due to previous error
-warning: not reporting region error due to nll
- --> $DIR/issue-13058.rs:24:21
- |
-LL | let cont_iter = cont.iter();
- | ^^^^
-
-warning: not reporting region error due to nll
- --> $DIR/issue-13058.rs:24:26
- |
-LL | let cont_iter = cont.iter();
- | ^^^^
-
error[E0308]: mismatched types
--> $DIR/issue-13058.rs:36:11
|
+++ /dev/null
-warning: not reporting region error due to nll
- --> $DIR/issue-14285.rs:22:7
- |
-LL | B(a) //~ ERROR 22:5: 22:9: explicit lifetime required in the type of `a` [E0621]
- | ^
-
-error[E0621]: explicit lifetime required in the type of `a`
- --> $DIR/issue-14285.rs:22:5
- |
-LL | fn foo<'a>(a: &Foo) -> B<'a> {
- | ---- help: add explicit lifetime `'a` to the type of `a`: `&'a (dyn Foo + 'a)`
-LL | B(a) //~ ERROR 22:5: 22:9: explicit lifetime required in the type of `a` [E0621]
- | ^^^^ lifetime `'a` required
-
-error: aborting due to previous error
-
-For more information about this error, try `rustc --explain E0621`.
-warning: not reporting region error due to nll
- --> $DIR/issue-15034.rs:27:9
- |
-LL | Parser { lexer: lexer }
- | ^^^^^^
-
error[E0621]: explicit lifetime required in the type of `lexer`
--> $DIR/issue-15034.rs:27:9
|
-warning: not reporting region error due to nll
- --> $DIR/issue-16683.rs:14:9
- |
-LL | self.a(); //~ ERROR cannot infer
- | ^^^^
-
-warning: not reporting region error due to nll
- --> $DIR/issue-16683.rs:14:14
- |
-LL | self.a(); //~ ERROR cannot infer
- | ^
-
error: borrowed data escapes outside of function
--> $DIR/issue-16683.rs:14:9
|
-warning: not reporting region error due to nll
- --> $DIR/issue-16922.rs:14:14
- |
-LL | Box::new(value) as Box<Any>
- | ^^^^^
-
error[E0621]: explicit lifetime required in the type of `value`
--> $DIR/issue-16922.rs:14:5
|
-warning: not reporting region error due to nll
- --> $DIR/issue-17728.rs:23:49
- |
-LL | let maybe_room = room.direction_to_room.get(&direction);
- | ^^^
-
error[E0308]: match arms have incompatible types
--> $DIR/issue-17728.rs:110:5
|
-warning: not reporting region error due to nll
- --> $DIR/issue-17758.rs:17:9
- |
-LL | self.foo();
- | ^^^^
-
-warning: not reporting region error due to nll
- --> $DIR/issue-17758.rs:17:14
- |
-LL | self.foo();
- | ^^^
-
error: borrowed data escapes outside of function
--> $DIR/issue-17758.rs:17:9
|
-warning: not reporting region error due to nll
- --> $DIR/issue-26217.rs:14:5
- |
-LL | foo::<&'a i32>();
- | ^^^^^^^^^^^^^^
-
error[E0131]: `main` function is not allowed to have generic parameters
--> $DIR/issue-26217.rs:13:8
|
+++ /dev/null
-warning: not reporting region error due to nll
- --> $DIR/issue-3154.rs:16:15
- |
-LL | thing{ x: x } //~ ERROR 16:5: 16:18: explicit lifetime required in the type of `x` [E0621]
- | ^
-
-warning: not reporting region error due to nll
- --> $DIR/issue-3154.rs:16:5
- |
-LL | thing{ x: x } //~ ERROR 16:5: 16:18: explicit lifetime required in the type of `x` [E0621]
- | ^^^^^
-
-error[E0621]: explicit lifetime required in the type of `x`
- --> $DIR/issue-3154.rs:16:5
- |
-LL | fn thing<'a,Q>(x: &Q) -> thing<'a,Q> {
- | -- help: add explicit lifetime `'a` to the type of `x`: `&'a Q`
-LL | thing{ x: x } //~ ERROR 16:5: 16:18: explicit lifetime required in the type of `x` [E0621]
- | ^^^^^^^^^^^^^ lifetime `'a` required
-
-error: aborting due to previous error
-
-For more information about this error, try `rustc --explain E0621`.
#[macro_export]
macro_rules! foo { () => {} } //~ ERROR a macro named `foo` has already been exported
//~| WARN this was previously accepted
+
+fn main() {}
LL | macro_rules! foo { ($i:ident) => {} }
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
-error[E0601]: `main` function not found in crate `issue_38715`
- |
- = note: consider adding a `main` function to `$DIR/issue-38715.rs`
-
-error: aborting due to 2 previous errors
+error: aborting due to previous error
-For more information about this error, try `rustc --explain E0601`.
-warning: not reporting region error due to nll
- --> $DIR/issue-40288-2.rs:17:20
- |
-LL | slice[0] = y;
- | ^
-
-warning: not reporting region error due to nll
- --> $DIR/issue-40288-2.rs:16:20
- |
-LL | let slice: &mut [_] = &mut out;
- | ^^^^^^^^
-
-warning: not reporting region error due to nll
- --> $DIR/issue-40288-2.rs:14:19
- |
-LL | let mut out = [x];
- | ^^^
-
-warning: not reporting region error due to nll
- --> $DIR/issue-40288-2.rs:32:20
- |
-LL | dst.head = y;
- | ^
-
-warning: not reporting region error due to nll
- --> $DIR/issue-40288-2.rs:31:18
- |
-LL | let dst: &mut Struct<_, [()]> = &mut out;
- | ^^^^^^^^^^^^^^^^^^^^
-
-warning: not reporting region error due to nll
- --> $DIR/issue-40288-2.rs:29:19
- |
-LL | let mut out = Struct { head: x, _tail: [()] };
- | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
-
error[E0621]: explicit lifetime required in the type of `y`
--> $DIR/issue-40288-2.rs:17:9
|
}
foo!(a);
+
+fn main() {}
LL | ($($p:vis)*) => {} //~ ERROR repetition matches empty token tree
| ^^^^^^^^
-error[E0601]: `main` function not found in crate `issue_42755`
- |
- = note: consider adding a `main` function to `$DIR/issue-42755.rs`
-
-error: aborting due to 2 previous errors
+error: aborting due to previous error
-For more information about this error, try `rustc --explain E0601`.
impl<T> Complete for T { //~ ERROR the trait bound `T: std::marker::Copy` is not satisfied
type Assoc = T;
}
+
+fn main() {}
-error[E0601]: `main` function not found in crate `issue_43784_associated_type`
- |
- = note: consider adding a `main` function to `$DIR/issue-43784-associated-type.rs`
-
error[E0277]: the trait bound `T: std::marker::Copy` is not satisfied
--> $DIR/issue-43784-associated-type.rs:23:9
|
|
= help: consider adding a `where T: std::marker::Copy` bound
-error: aborting due to 2 previous errors
+error: aborting due to previous error
-Some errors occurred: E0277, E0601.
-For more information about an error, try `rustc --explain E0277`.
+For more information about this error, try `rustc --explain E0277`.
impl<T> Partial for T where T: Complete {}
impl<T> Complete for T {} //~ ERROR the trait bound `T: std::marker::Copy` is not satisfied
+
+fn main() {}
-error[E0601]: `main` function not found in crate `issue_43784_supertrait`
- |
- = note: consider adding a `main` function to `$DIR/issue-43784-supertrait.rs`
-
error[E0277]: the trait bound `T: std::marker::Copy` is not satisfied
--> $DIR/issue-43784-supertrait.rs:18:9
|
|
= help: consider adding a `where T: std::marker::Copy` bound
-error: aborting due to 2 previous errors
+error: aborting due to previous error
-Some errors occurred: E0277, E0601.
-For more information about an error, try `rustc --explain E0277`.
+For more information about this error, try `rustc --explain E0277`.
//~^^^^^^^^^^ ERROR cycle detected when computing layout of
-#![feature(const_fn)]
+
#![feature(core_intrinsics)]
use std::intrinsics;
--- /dev/null
+// Regression test for https://github.com/rust-lang/rust/issues/52060
+// The compiler shouldn't ICE in this case
+static A: &'static [u32] = &[1];
+static B: [u32; 1] = [0; A.len()];
+//~^ ERROR [E0013]
+//~| ERROR `core::slice::<impl [T]>::len` is not yet stable as a const fn
+
+fn main() {}
--- /dev/null
+error[E0013]: constants cannot refer to statics, use a constant instead
+ --> $DIR/issue-52060.rs:4:26
+ |
+LL | static B: [u32; 1] = [0; A.len()];
+ | ^
+
+error: `core::slice::<impl [T]>::len` is not yet stable as a const fn
+ --> $DIR/issue-52060.rs:4:26
+ |
+LL | static B: [u32; 1] = [0; A.len()];
+ | ^^^^^^^
+ |
+ = help: in Nightly builds, add `#![feature(const_slice_len)]` to the crate attributes to enable
+
+error: aborting due to 2 previous errors
+
+For more information about this error, try `rustc --explain E0013`.
-warning: not reporting region error due to nll
- --> $DIR/issue-52213.rs:12:11
- |
-LL | match (&t,) { //~ ERROR cannot infer an appropriate lifetime
- | ^^^^^
-
error: unsatisfied lifetime constraints
--> $DIR/issue-52213.rs:13:20
|
| -^^^^^
| |
| cannot use `+=` on type `&isize`
+help: `+=` can be used on 'isize', you can dereference `x`
|
- = help: `+=` can be used on 'isize', you can dereference `x`: `*x`
+LL | let x = |ref x: isize| { *x += 1; };
+ | ^^
error: aborting due to previous error
-warning: not reporting region error due to nll
- --> $DIR/issue-52533-1.rs:19:18
- |
-LL | gimme(|x, y| y)
- | ^
-
error: unsatisfied lifetime constraints
--> $DIR/issue-52533-1.rs:19:18
|
-warning: not reporting region error due to nll
- --> $DIR/issue-52533.rs:15:16
- |
-LL | foo(|a, b| b)
- | ^
-
error: unsatisfied lifetime constraints
--> $DIR/issue-52533.rs:15:16
|
= note: required because of the requirements on the impl of `Gettable<T>` for `S<T>`
= note: required for the cast to the object type `dyn Gettable<T>`
-warning: not reporting region error due to nll
- --> $DIR/kindck-impl-type-params.rs:42:13
- |
-LL | let a = &t as &Gettable<&'a isize>;
- | ^^
-
error[E0277]: the trait bound `std::string::String: std::marker::Copy` is not satisfied
--> $DIR/kindck-impl-type-params.rs:48:13
|
LL | fn assert_send<T:Send+'static>() { }
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
-warning: not reporting region error due to nll
- --> $DIR/kindck-send-object1.rs:24:5
- |
-LL | assert_send::<&'a (Dummy+Sync)>();
- | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
-
error[E0277]: `(dyn Dummy + 'a)` cannot be sent between threads safely
--> $DIR/kindck-send-object1.rs:39:5
|
-warning: not reporting region error due to nll
- --> $DIR/lifetime-bound-will-change-warning.rs:44:13
- |
-LL | ref_obj(x) //~ ERROR mismatched types
- | ^
-
-warning: not reporting region error due to nll
- --> $DIR/lifetime-bound-will-change-warning.rs:49:18
- |
-LL | lib::ref_obj(x) //~ ERROR mismatched types
- | ^
-
error: borrowed data escapes outside of function
--> $DIR/lifetime-bound-will-change-warning.rs:44:5
|
+++ /dev/null
-warning: not reporting region error due to nll
- --> $DIR/42701_one_named_and_one_anonymous.rs:20:9
- |
-LL | &*x //~ ERROR explicit lifetime
- | ^^^
-
-error[E0621]: explicit lifetime required in the type of `x`
- --> $DIR/42701_one_named_and_one_anonymous.rs:20:9
- |
-LL | fn foo2<'a>(a: &'a Foo, x: &i32) -> &'a i32 {
- | ---- help: add explicit lifetime `'a` to the type of `x`: `&'a i32`
-...
-LL | &*x //~ ERROR explicit lifetime
- | ^^^ lifetime `'a` required
-
-error: aborting due to previous error
-
-For more information about this error, try `rustc --explain E0621`.
+++ /dev/null
-warning: not reporting region error due to nll
- --> $DIR/ex1-return-one-existing-name-early-bound-in-struct.rs:21:21
- |
-LL | other //~ ERROR explicit lifetime
- | ^^^^^
-
-error[E0621]: explicit lifetime required in the type of `other`
- --> $DIR/ex1-return-one-existing-name-early-bound-in-struct.rs:21:21
- |
-LL | fn bar(&self, other: Foo) -> Foo<'a> {
- | --- help: add explicit lifetime `'a` to the type of `other`: `Foo<'a>`
-...
-LL | other //~ ERROR explicit lifetime
- | ^^^^^ lifetime `'a` required
-
-error: aborting due to previous error
-
-For more information about this error, try `rustc --explain E0621`.
+++ /dev/null
-warning: not reporting region error due to nll
- --> $DIR/ex1-return-one-existing-name-if-else-2.rs:12:16
- |
-LL | if x > y { x } else { y } //~ ERROR explicit lifetime
- | ^
-
-error[E0621]: explicit lifetime required in the type of `x`
- --> $DIR/ex1-return-one-existing-name-if-else-2.rs:12:16
- |
-LL | fn foo<'a>(x: &i32, y: &'a i32) -> &'a i32 {
- | ---- help: add explicit lifetime `'a` to the type of `x`: `&'a i32`
-LL | if x > y { x } else { y } //~ ERROR explicit lifetime
- | ^ lifetime `'a` required
-
-error: aborting due to previous error
-
-For more information about this error, try `rustc --explain E0621`.
+++ /dev/null
-warning: not reporting region error due to nll
- --> $DIR/ex1-return-one-existing-name-if-else-3.rs:12:27
- |
-LL | if x > y { x } else { y } //~ ERROR explicit lifetime
- | ^
-
-error[E0621]: explicit lifetime required in parameter type
- --> $DIR/ex1-return-one-existing-name-if-else-3.rs:12:27
- |
-LL | fn foo<'a>((x, y): (&'a i32, &i32)) -> &'a i32 {
- | --------------- help: add explicit lifetime `'a` to type: `(&'a i32, &'a i32)`
-LL | if x > y { x } else { y } //~ ERROR explicit lifetime
- | ^ lifetime `'a` required
-
-error: aborting due to previous error
-
-For more information about this error, try `rustc --explain E0621`.
+++ /dev/null
-warning: not reporting region error due to nll
- --> $DIR/ex1-return-one-existing-name-if-else-using-impl-2.rs:14:15
- |
-LL | if x > y { x } else { y } //~ ERROR explicit lifetime
- | ^
-
-error[E0621]: explicit lifetime required in the type of `x`
- --> $DIR/ex1-return-one-existing-name-if-else-using-impl-2.rs:14:15
- |
-LL | fn foo<'a>(x: &i32, y: &'a i32) -> &'a i32 {
- | ---- help: add explicit lifetime `'a` to the type of `x`: `&'a i32`
-LL | if x > y { x } else { y } //~ ERROR explicit lifetime
- | ^ lifetime `'a` required
-
-error: aborting due to previous error
-
-For more information about this error, try `rustc --explain E0621`.
+++ /dev/null
-warning: not reporting region error due to nll
- --> $DIR/ex1-return-one-existing-name-if-else-using-impl-3.rs:18:36
- |
-LL | if true { &self.field } else { x } //~ ERROR explicit lifetime
- | ^
-
-error[E0621]: explicit lifetime required in the type of `x`
- --> $DIR/ex1-return-one-existing-name-if-else-using-impl-3.rs:18:36
- |
-LL | fn foo<'a>(&'a self, x: &i32) -> &i32 {
- | ---- help: add explicit lifetime `'a` to the type of `x`: `&'a i32`
-LL |
-LL | if true { &self.field } else { x } //~ ERROR explicit lifetime
- | ^ lifetime `'a` required
-
-error: aborting due to previous error
-
-For more information about this error, try `rustc --explain E0621`.
-warning: not reporting region error due to nll
- --> $DIR/ex1-return-one-existing-name-if-else-using-impl.rs:21:20
- |
-LL | if x > y { x } else { y } //~ ERROR lifetime mismatch
- | ^
-
error: unsatisfied lifetime constraints
--> $DIR/ex1-return-one-existing-name-if-else-using-impl.rs:21:20
|
+++ /dev/null
-warning: not reporting region error due to nll
- --> $DIR/ex1-return-one-existing-name-if-else.rs:12:27
- |
-LL | if x > y { x } else { y } //~ ERROR explicit lifetime
- | ^
-
-error[E0621]: explicit lifetime required in the type of `y`
- --> $DIR/ex1-return-one-existing-name-if-else.rs:12:27
- |
-LL | fn foo<'a>(x: &'a i32, y: &i32) -> &'a i32 {
- | ---- help: add explicit lifetime `'a` to the type of `y`: `&'a i32`
-LL | if x > y { x } else { y } //~ ERROR explicit lifetime
- | ^ lifetime `'a` required
-
-error: aborting due to previous error
-
-For more information about this error, try `rustc --explain E0621`.
-warning: not reporting region error due to nll
- --> $DIR/ex1-return-one-existing-name-return-type-is-anon.rs:18:5
- |
-LL | x //~ ERROR lifetime mismatch
- | ^
-
error: unsatisfied lifetime constraints
--> $DIR/ex1-return-one-existing-name-return-type-is-anon.rs:18:5
|
-warning: not reporting region error due to nll
- --> $DIR/ex1-return-one-existing-name-self-is-anon.rs:18:30
- |
-LL | if true { x } else { self } //~ ERROR lifetime mismatch
- | ^^^^
-
error: unsatisfied lifetime constraints
--> $DIR/ex1-return-one-existing-name-self-is-anon.rs:18:30
|
-warning: not reporting region error due to nll
- --> $DIR/ex2a-push-one-existing-name-2.rs:16:12
- |
-LL | y.push(x); //~ ERROR explicit lifetime
- | ^
-
error[E0621]: explicit lifetime required in the type of `x`
--> $DIR/ex2a-push-one-existing-name-2.rs:16:5
|
-warning: not reporting region error due to nll
- --> $DIR/ex2a-push-one-existing-name-early-bound.rs:17:12
+error[E0621]: explicit lifetime required in the type of `y`
+ --> $DIR/ex2a-push-one-existing-name-early-bound.rs:17:5
|
+LL | fn baz<'a, 'b, T>(x: &mut Vec<&'a T>, y: &T)
+ | -- help: add explicit lifetime `'a` to the type of `y`: `&'a T`
+...
LL | x.push(y); //~ ERROR explicit lifetime required
- | ^
-
-error[E0282]: type annotations needed
- --> $DIR/ex2a-push-one-existing-name-early-bound.rs:20:9
- |
-LL | let x = baz;
- | - ^^^ cannot infer type for `T`
- | |
- | consider giving `x` a type
+ | ^^^^^^^^^ lifetime `'a` required
error: aborting due to previous error
-For more information about this error, try `rustc --explain E0282`.
+For more information about this error, try `rustc --explain E0621`.
x.push(y); //~ ERROR explicit lifetime required
}
fn main() {
-let x = baz;
}
-warning: not reporting region error due to nll
- --> $DIR/ex2a-push-one-existing-name.rs:16:12
- |
-LL | x.push(y); //~ ERROR explicit lifetime
- | ^
-
error[E0621]: explicit lifetime required in the type of `y`
--> $DIR/ex2a-push-one-existing-name.rs:16:5
|
-warning: not reporting region error due to nll
- --> $DIR/ex2b-push-no-existing-names.rs:16:12
- |
-LL | x.push(y); //~ ERROR lifetime mismatch
- | ^
-
error: unsatisfied lifetime constraints
--> $DIR/ex2b-push-no-existing-names.rs:16:5
|
-warning: not reporting region error due to nll
- --> $DIR/ex2c-push-inference-variable.rs:16:13
- |
-LL | let z = Ref { data: y.data };
- | ^^^
-
error: unsatisfied lifetime constraints
--> $DIR/ex2c-push-inference-variable.rs:17:5
|
-warning: not reporting region error due to nll
- --> $DIR/ex2d-push-inference-variable-2.rs:17:13
- |
-LL | let b = Ref { data: y.data };
- | ^^^
-
error: unsatisfied lifetime constraints
--> $DIR/ex2d-push-inference-variable-2.rs:18:5
|
-warning: not reporting region error due to nll
- --> $DIR/ex2e-push-inference-variable-3.rs:17:13
- |
-LL | let b = Ref { data: y.data };
- | ^^^
-
error: unsatisfied lifetime constraints
--> $DIR/ex2e-push-inference-variable-3.rs:18:5
|
-warning: not reporting region error due to nll
- --> $DIR/ex3-both-anon-regions-2.rs:12:10
- |
-LL | *v = x; //~ ERROR lifetime mismatch
- | ^
-
error: unsatisfied lifetime constraints
--> $DIR/ex3-both-anon-regions-2.rs:12:5
|
-warning: not reporting region error due to nll
- --> $DIR/ex3-both-anon-regions-3.rs:12:13
- |
-LL | z.push((x,y)); //~ ERROR lifetime mismatch
- | ^
-
-warning: not reporting region error due to nll
- --> $DIR/ex3-both-anon-regions-3.rs:12:15
- |
-LL | z.push((x,y)); //~ ERROR lifetime mismatch
- | ^
-
error: unsatisfied lifetime constraints
--> $DIR/ex3-both-anon-regions-3.rs:12:5
|
-warning: not reporting region error due to nll
- --> $DIR/ex3-both-anon-regions-both-are-structs-2.rs:16:11
- |
-LL | x.b = y.b; //~ ERROR lifetime mismatch
- | ^^^
-
error: unsatisfied lifetime constraints
--> $DIR/ex3-both-anon-regions-both-are-structs-2.rs:16:5
|
-warning: not reporting region error due to nll
- --> $DIR/ex3-both-anon-regions-both-are-structs-3.rs:16:11
- |
-LL | x.a = x.b; //~ ERROR lifetime mismatch
- | ^^^
-
error: unsatisfied lifetime constraints
--> $DIR/ex3-both-anon-regions-both-are-structs-3.rs:16:5
|
-warning: not reporting region error due to nll
- --> $DIR/ex3-both-anon-regions-both-are-structs-4.rs:16:11
- |
-LL | x.a = x.b; //~ ERROR lifetime mismatch
- | ^^^
-
error: unsatisfied lifetime constraints
--> $DIR/ex3-both-anon-regions-both-are-structs-4.rs:16:5
|
-warning: not reporting region error due to nll
- --> $DIR/ex3-both-anon-regions-both-are-structs-earlybound-regions.rs:18:12
- |
-LL | x.push(y); //~ ERROR lifetime mismatch
- | ^
-
error: unsatisfied lifetime constraints
--> $DIR/ex3-both-anon-regions-both-are-structs-earlybound-regions.rs:18:5
|
-warning: not reporting region error due to nll
- --> $DIR/ex3-both-anon-regions-both-are-structs-latebound-regions.rs:15:12
- |
-LL | x.push(y); //~ ERROR lifetime mismatch
- | ^
-
error: unsatisfied lifetime constraints
--> $DIR/ex3-both-anon-regions-both-are-structs-latebound-regions.rs:15:5
|
-warning: not reporting region error due to nll
- --> $DIR/ex3-both-anon-regions-both-are-structs.rs:15:12
- |
-LL | x.push(y); //~ ERROR lifetime mismatch
- | ^
-
error: unsatisfied lifetime constraints
--> $DIR/ex3-both-anon-regions-both-are-structs.rs:15:5
|
-warning: not reporting region error due to nll
- --> $DIR/ex3-both-anon-regions-latebound-regions.rs:12:12
- |
-LL | x.push(y); //~ ERROR lifetime mismatch
- | ^
-
error: unsatisfied lifetime constraints
--> $DIR/ex3-both-anon-regions-latebound-regions.rs:12:5
|
-warning: not reporting region error due to nll
- --> $DIR/ex3-both-anon-regions-one-is-struct-2.rs:14:9
- |
-LL | y = x.b; //~ ERROR lifetime mismatch
- | ^^^
-
error: unsatisfied lifetime constraints
--> $DIR/ex3-both-anon-regions-one-is-struct-2.rs:14:5
|
-warning: not reporting region error due to nll
- --> $DIR/ex3-both-anon-regions-one-is-struct-3.rs:14:11
- |
-LL | y.b = x; //~ ERROR lifetime mismatch
- | ^
-
error: unsatisfied lifetime constraints
--> $DIR/ex3-both-anon-regions-one-is-struct-3.rs:14:5
|
-warning: not reporting region error due to nll
- --> $DIR/ex3-both-anon-regions-one-is-struct-4.rs:14:11
- |
-LL | y.b = x; //~ ERROR lifetime mismatch
- | ^
-
error: unsatisfied lifetime constraints
--> $DIR/ex3-both-anon-regions-one-is-struct-4.rs:14:5
|
-warning: not reporting region error due to nll
- --> $DIR/ex3-both-anon-regions-one-is-struct.rs:17:11
- |
-LL | x.b = y; //~ ERROR lifetime mismatch
- | ^
-
error: unsatisfied lifetime constraints
--> $DIR/ex3-both-anon-regions-one-is-struct.rs:17:5
|
-warning: not reporting region error due to nll
- --> $DIR/ex3-both-anon-regions-return-type-is-anon.rs:17:5
- |
-LL | x //~ ERROR lifetime mismatch
- | ^
-
error: unsatisfied lifetime constraints
--> $DIR/ex3-both-anon-regions-return-type-is-anon.rs:17:5
|
-warning: not reporting region error due to nll
- --> $DIR/ex3-both-anon-regions-self-is-anon.rs:17:19
- |
-LL | if true { x } else { self } //~ ERROR lifetime mismatch
- | ^
-
error: unsatisfied lifetime constraints
--> $DIR/ex3-both-anon-regions-self-is-anon.rs:17:19
|
-warning: not reporting region error due to nll
- --> $DIR/ex3-both-anon-regions-using-fn-items.rs:11:10
- |
-LL | y.push(z); //~ ERROR lifetime mismatch
- | ^
-
error[E0596]: cannot borrow `y` as mutable, as it is not declared as mutable
--> $DIR/ex3-both-anon-regions-using-fn-items.rs:11:3
|
-warning: not reporting region error due to nll
- --> $DIR/ex3-both-anon-regions-using-impl-items.rs:15:16
- |
-LL | x.push(y); //~ ERROR lifetime mismatch
- | ^
-
error: unsatisfied lifetime constraints
--> $DIR/ex3-both-anon-regions-using-impl-items.rs:15:9
|
-warning: not reporting region error due to nll
- --> $DIR/ex3-both-anon-regions-using-trait-objects.rs:11:10
- |
-LL | y.push(z); //~ ERROR lifetime mismatch
- | ^
-
error[E0596]: cannot borrow `y` as mutable, as it is not declared as mutable
--> $DIR/ex3-both-anon-regions-using-trait-objects.rs:11:3
|
-warning: not reporting region error due to nll
- --> $DIR/ex3-both-anon-regions.rs:12:12
- |
-LL | x.push(y); //~ ERROR lifetime mismatch
- | ^
-
error: unsatisfied lifetime constraints
--> $DIR/ex3-both-anon-regions.rs:12:5
|
// option. This file may not be copied, modified, or distributed
// except according to those terms.
-#![deny(bad_style)]
+#![deny(nonstandard_style)]
#![allow(dead_code)]
fn CamelCase() {} //~ ERROR should have a snake
-#[allow(bad_style)]
+#[allow(nonstandard_style)]
mod test {
fn CamelCase() {}
- #[forbid(bad_style)]
+ #[forbid(nonstandard_style)]
mod bad {
fn CamelCase() {} //~ ERROR should have a snake
}
mod warn {
- #![warn(bad_style)]
+ #![warn(nonstandard_style)]
fn CamelCase() {} //~ WARN should have a snake
note: lint level defined here
--> $DIR/lint-group-style.rs:11:9
|
-LL | #![deny(bad_style)]
- | ^^^^^^^^^
- = note: #[deny(non_snake_case)] implied by #[deny(bad_style)]
+LL | #![deny(nonstandard_style)]
+ | ^^^^^^^^^^^^^^^^^
+ = note: #[deny(non_snake_case)] implied by #[deny(nonstandard_style)]
error: function `CamelCase` should have a snake case name such as `camel_case`
--> $DIR/lint-group-style.rs:22:9
note: lint level defined here
--> $DIR/lint-group-style.rs:20:14
|
-LL | #[forbid(bad_style)]
- | ^^^^^^^^^
- = note: #[forbid(non_snake_case)] implied by #[forbid(bad_style)]
+LL | #[forbid(nonstandard_style)]
+ | ^^^^^^^^^^^^^^^^^
+ = note: #[forbid(non_snake_case)] implied by #[forbid(nonstandard_style)]
error: static variable `bad` should have an upper case name such as `BAD`
--> $DIR/lint-group-style.rs:24:9
note: lint level defined here
--> $DIR/lint-group-style.rs:20:14
|
-LL | #[forbid(bad_style)]
- | ^^^^^^^^^
- = note: #[forbid(non_upper_case_globals)] implied by #[forbid(bad_style)]
+LL | #[forbid(nonstandard_style)]
+ | ^^^^^^^^^^^^^^^^^
+ = note: #[forbid(non_upper_case_globals)] implied by #[forbid(nonstandard_style)]
warning: function `CamelCase` should have a snake case name such as `camel_case`
--> $DIR/lint-group-style.rs:30:9
note: lint level defined here
--> $DIR/lint-group-style.rs:28:17
|
-LL | #![warn(bad_style)]
- | ^^^^^^^^^
- = note: #[warn(non_snake_case)] implied by #[warn(bad_style)]
+LL | #![warn(nonstandard_style)]
+ | ^^^^^^^^^^^^^^^^^
+ = note: #[warn(non_snake_case)] implied by #[warn(nonstandard_style)]
warning: type `snake_case` should have a camel case name such as `SnakeCase`
--> $DIR/lint-group-style.rs:32:9
note: lint level defined here
--> $DIR/lint-group-style.rs:28:17
|
-LL | #![warn(bad_style)]
- | ^^^^^^^^^
- = note: #[warn(non_camel_case_types)] implied by #[warn(bad_style)]
+LL | #![warn(nonstandard_style)]
+ | ^^^^^^^^^^^^^^^^^
+ = note: #[warn(non_camel_case_types)] implied by #[warn(nonstandard_style)]
error: aborting due to 3 previous errors
// option. This file may not be copied, modified, or distributed
// except according to those terms.
-#![allow(bad_style, unused_variables)]
+#![allow(nonstandard_style, unused_variables)]
#![deny(non_shorthand_field_patterns)]
struct Foo {
// Forbidding a group (here, `unused`) overrules subsequent allowance of both
// the group, and an individual lint in the group (here, `unused_variables`);
// and, forbidding an individual lint (here, `non_snake_case`) overrules
-// subsequent allowance of a lint group containing it (here, `bad_style`). See
+// subsequent allowance of a lint group containing it (here, `nonstandard_style`). See
// Issue #42873.
#![forbid(unused, non_snake_case)]
#[allow(unused)] //~ ERROR overruled
fn bar() {}
-#[allow(bad_style)] //~ ERROR overruled
+#[allow(nonstandard_style)] //~ ERROR overruled
fn main() {
println!("hello forbidden world")
}
LL | #[allow(unused)] //~ ERROR overruled
| ^^^^^^ overruled by previous forbid
-error[E0453]: allow(bad_style) overruled by outer forbid(non_snake_case)
+error[E0453]: allow(nonstandard_style) overruled by outer forbid(non_snake_case)
--> $DIR/outer-forbid.rs:25:9
|
LL | #![forbid(unused, non_snake_case)]
| -------------- `forbid` level set here
...
-LL | #[allow(bad_style)] //~ ERROR overruled
- | ^^^^^^^^^ overruled by previous forbid
+LL | #[allow(nonstandard_style)] //~ ERROR overruled
+ | ^^^^^^^^^^^^^^^^^ overruled by previous forbid
error: aborting due to 3 previous errors
// option. This file may not be copied, modified, or distributed
// except according to those terms.
-// compile-flags: --test -D unnameable_test_functions
+// compile-flags: --test -D unnameable_test_items
#[test]
fn foo() {
- #[test] //~ ERROR cannot test inner function [unnameable_test_functions]
+ #[test] //~ ERROR cannot test inner items [unnameable_test_items]
fn bar() {}
bar();
}
mod x {
#[test]
fn foo() {
- #[test] //~ ERROR cannot test inner function [unnameable_test_functions]
+ #[test] //~ ERROR cannot test inner items [unnameable_test_items]
fn bar() {}
bar();
}
-error: cannot test inner function
+error: cannot test inner items
--> $DIR/test-inner-fn.rs:15:5
|
-LL | #[test] //~ ERROR cannot test inner function [unnameable_test_functions]
+LL | #[test] //~ ERROR cannot test inner items [unnameable_test_items]
| ^^^^^^^
|
- = note: requested on the command line with `-D unnameable-test-functions`
+ = note: requested on the command line with `-D unnameable-test-items`
-error: cannot test inner function
+error: cannot test inner items
--> $DIR/test-inner-fn.rs:23:9
|
-LL | #[test] //~ ERROR cannot test inner function [unnameable_test_functions]
+LL | #[test] //~ ERROR cannot test inner items [unnameable_test_items]
| ^^^^^^^
error: aborting due to 2 previous errors
-warning: not reporting region error due to nll
- --> $DIR/lub-if.rs:38:9
- |
-LL | s //~ ERROR E0312
- | ^
-
-warning: not reporting region error due to nll
- --> $DIR/lub-if.rs:45:9
- |
-LL | s //~ ERROR E0312
- | ^
-
error: unsatisfied lifetime constraints
--> $DIR/lub-if.rs:38:9
|
-warning: not reporting region error due to nll
- --> $DIR/lub-match.rs:40:13
- |
-LL | s //~ ERROR E0312
- | ^
-
-warning: not reporting region error due to nll
- --> $DIR/lub-match.rs:49:13
- |
-LL | s //~ ERROR E0312
- | ^
-
error: unsatisfied lifetime constraints
--> $DIR/lub-match.rs:40:13
|
#[allow(unused_extern_crates)]
#[macro_use(foo(bar))] //~ ERROR bad macro import
extern crate std;
+
+fn main() {}
LL | #[macro_use(foo(bar))] //~ ERROR bad macro import
| ^^^^^^^^
-error[E0601]: `main` function not found in crate `macro_use_bad_args_1`
- |
- = note: consider adding a `main` function to `$DIR/macro-use-bad-args-1.rs`
-
-error: aborting due to 2 previous errors
+error: aborting due to previous error
-Some errors occurred: E0466, E0601.
-For more information about an error, try `rustc --explain E0466`.
+For more information about this error, try `rustc --explain E0466`.
#[allow(unused_extern_crates)]
#[macro_use(foo="bar")] //~ ERROR bad macro import
extern crate std;
+
+fn main() {}
LL | #[macro_use(foo="bar")] //~ ERROR bad macro import
| ^^^^^^^^^
-error[E0601]: `main` function not found in crate `macro_use_bad_args_2`
- |
- = note: consider adding a `main` function to `$DIR/macro-use-bad-args-2.rs`
-
-error: aborting due to 2 previous errors
+error: aborting due to previous error
-Some errors occurred: E0466, E0601.
-For more information about an error, try `rustc --explain E0466`.
+For more information about this error, try `rustc --explain E0466`.
-warning: not reporting region error due to nll
- --> $DIR/match-ref-mut-invariance.rs:20:37
- |
-LL | match self.0 { ref mut x => x } //~ ERROR mismatched types
- | ^
-
error: unsatisfied lifetime constraints
--> $DIR/match-ref-mut-invariance.rs:20:9
|
-warning: not reporting region error due to nll
- --> $DIR/match-ref-mut-let-invariance.rs:21:9
- |
-LL | x //~ ERROR mismatched types
- | ^
-
error: unsatisfied lifetime constraints
--> $DIR/match-ref-mut-let-invariance.rs:21:9
|
return hd1(v);
}
+
+fn main() {}
| |
| help: try using a local type parameter instead: `hd1<U>`
-error[E0601]: `main` function not found in crate `nested_ty_params`
- |
- = note: consider adding a `main` function to `$DIR/nested-ty-params.rs`
-
-error: aborting due to 3 previous errors
+error: aborting due to 2 previous errors
-Some errors occurred: E0401, E0601.
-For more information about an error, try `rustc --explain E0401`.
+For more information about this error, try `rustc --explain E0401`.
let y = 22;
let mut closure = expect_sig(|p, y| *p = y);
//~^ ERROR
- //~| WARNING not reporting region error due to nll
closure(&mut p, &y);
}
-warning: not reporting region error due to nll
- --> $DIR/escape-argument-callee.rs:36:50
- |
-LL | let mut closure = expect_sig(|p, y| *p = y);
- | ^
-
note: No external requirements
--> $DIR/escape-argument-callee.rs:36:38
|
|_outlives1, _outlives2, _outlives3, x, y| {
// Only works if 'x: 'y:
let p = x.get();
- //~^ WARN not reporting region error due to nll
demand_y(x, y, p) //~ ERROR
},
);
-warning: not reporting region error due to nll
- --> $DIR/propagate-approximated-fail-no-postdom.rs:55:21
- |
-LL | let p = x.get();
- | ^^^^^^^
-
note: No external requirements
--> $DIR/propagate-approximated-fail-no-postdom.rs:53:9
|
LL | / |_outlives1, _outlives2, _outlives3, x, y| {
LL | | // Only works if 'x: 'y:
LL | | let p = x.get();
-LL | | //~^ WARN not reporting region error due to nll
LL | | demand_y(x, y, p) //~ ERROR
LL | | },
| |_________^
]
error: unsatisfied lifetime constraints
- --> $DIR/propagate-approximated-fail-no-postdom.rs:57:13
+ --> $DIR/propagate-approximated-fail-no-postdom.rs:56:13
|
LL | |_outlives1, _outlives2, _outlives3, x, y| {
| ---------- ---------- has type `std::cell::Cell<&'2 &u32>`
//~^ ERROR unsatisfied lifetime constraints
// Only works if 'x: 'y:
- demand_y(x, y, x.get()) //~ WARNING not reporting region error due to nll
+ demand_y(x, y, x.get())
});
}
-warning: not reporting region error due to nll
- --> $DIR/propagate-approximated-ref.rs:57:9
- |
-LL | demand_y(x, y, x.get()) //~ WARNING not reporting region error due to nll
- | ^^^^^^^^^^^^^^^^^^^^^^^
-
note: External requirements
--> $DIR/propagate-approximated-ref.rs:53:47
|
LL | | //~^ ERROR unsatisfied lifetime constraints
LL | |
LL | | // Only works if 'x: 'y:
-LL | | demand_y(x, y, x.get()) //~ WARNING not reporting region error due to nll
+LL | | demand_y(x, y, x.get())
LL | | });
| |_____^
|
LL | | //~^ ERROR unsatisfied lifetime constraints
LL | |
LL | | // Only works if 'x: 'y:
-LL | | demand_y(x, y, x.get()) //~ WARNING not reporting region error due to nll
+LL | | demand_y(x, y, x.get())
LL | | });
| |______^ argument requires that `'a` must outlive `'b`
let a = 0;
let cell = Cell::new(&a);
foo(cell, |cell_a, cell_x| {
- //~^ WARNING not reporting region error due to nll
cell_a.set(cell_x.get()); // forces 'x: 'a, error in closure
//~^ ERROR
})
-warning: not reporting region error due to nll
- --> $DIR/propagate-approximated-shorter-to-static-comparing-against-free.rs:31:5
- |
-LL | foo(cell, |cell_a, cell_x| {
- | ^^^
-
note: No external requirements
--> $DIR/propagate-approximated-shorter-to-static-comparing-against-free.rs:31:15
|
LL | foo(cell, |cell_a, cell_x| {
| _______________^
-LL | | //~^ WARNING not reporting region error due to nll
LL | | cell_a.set(cell_x.get()); // forces 'x: 'a, error in closure
LL | | //~^ ERROR
LL | | })
]
error: borrowed data escapes outside of closure
- --> $DIR/propagate-approximated-shorter-to-static-comparing-against-free.rs:33:9
+ --> $DIR/propagate-approximated-shorter-to-static-comparing-against-free.rs:32:9
|
LL | foo(cell, |cell_a, cell_x| {
| ------ ------ `cell_x` is a reference that is only valid in the closure body
| |
| `cell_a` is declared here, outside of the closure body
-LL | //~^ WARNING not reporting region error due to nll
LL | cell_a.set(cell_x.get()); // forces 'x: 'a, error in closure
| ^^^^^^^^^^^^^^^^^^^^^^^^ `cell_x` escapes the closure body here
= note: defining type: DefId(0/0:5 ~ propagate_approximated_shorter_to_static_comparing_against_free[317d]::case1[0]) with substs []
note: External requirements
- --> $DIR/propagate-approximated-shorter-to-static-comparing-against-free.rs:46:15
+ --> $DIR/propagate-approximated-shorter-to-static-comparing-against-free.rs:45:15
|
LL | foo(cell, |cell_a, cell_x| {
| _______________^
= note: where '_#1r: '_#0r
note: No external requirements
- --> $DIR/propagate-approximated-shorter-to-static-comparing-against-free.rs:39:1
+ --> $DIR/propagate-approximated-shorter-to-static-comparing-against-free.rs:38:1
|
LL | / fn case2() {
LL | | let a = 0;
= note: defining type: DefId(0/0:6 ~ propagate_approximated_shorter_to_static_comparing_against_free[317d]::case2[0]) with substs []
error[E0597]: `a` does not live long enough
- --> $DIR/propagate-approximated-shorter-to-static-comparing-against-free.rs:41:26
+ --> $DIR/propagate-approximated-shorter-to-static-comparing-against-free.rs:40:26
|
LL | let cell = Cell::new(&a);
| ^^ borrowed value does not live long enough
//~^ ERROR
// Only works if 'x: 'y:
- demand_y(x, y, x.get()) //~ WARNING not reporting region error due to nll
+ demand_y(x, y, x.get())
});
}
-warning: not reporting region error due to nll
- --> $DIR/propagate-approximated-shorter-to-static-no-bound.rs:49:9
- |
-LL | demand_y(x, y, x.get()) //~ WARNING not reporting region error due to nll
- | ^^^^^^^^^^^^^^^^^^^^^^^
-
note: External requirements
--> $DIR/propagate-approximated-shorter-to-static-no-bound.rs:45:47
|
LL | | //~^ ERROR
LL | |
LL | | // Only works if 'x: 'y:
-LL | | demand_y(x, y, x.get()) //~ WARNING not reporting region error due to nll
+LL | | demand_y(x, y, x.get())
LL | | });
| |_____^
|
LL | | //~^ ERROR
LL | |
LL | | // Only works if 'x: 'y:
-LL | | demand_y(x, y, x.get()) //~ WARNING not reporting region error due to nll
+LL | | demand_y(x, y, x.get())
LL | | });
| |______^ `cell_a` escapes the function body here
//~^ ERROR
// Only works if 'x: 'y:
demand_y(x, y, x.get())
- //~^ WARNING not reporting region error due to nll
});
}
-warning: not reporting region error due to nll
- --> $DIR/propagate-approximated-shorter-to-static-wrong-bound.rs:51:9
- |
-LL | demand_y(x, y, x.get())
- | ^^^^^^^^^^^^^^^^^^^^^^^
-
note: External requirements
--> $DIR/propagate-approximated-shorter-to-static-wrong-bound.rs:48:47
|
LL | | //~^ ERROR
LL | | // Only works if 'x: 'y:
LL | | demand_y(x, y, x.get())
-LL | | //~^ WARNING not reporting region error due to nll
LL | | });
| |_____^
|
LL | | establish_relationships(&cell_a, &cell_b, |_outlives1, _outlives2, x, y| {
LL | | //~^ ERROR
LL | | // Only works if 'x: 'y:
-... |
+LL | | demand_y(x, y, x.get())
LL | | });
LL | | }
| |_^
LL | | //~^ ERROR
LL | | // Only works if 'x: 'y:
LL | | demand_y(x, y, x.get())
-LL | | //~^ WARNING not reporting region error due to nll
LL | | });
| |______^ `cell_a` escapes the function body here
//~^ ERROR unsatisfied lifetime constraints
// Only works if 'x: 'y:
- demand_y(outlives1, outlives2, x.get()) //~ WARNING not reporting region error due to nll
+ demand_y(outlives1, outlives2, x.get())
});
}
-warning: not reporting region error due to nll
- --> $DIR/propagate-approximated-val.rs:50:9
- |
-LL | demand_y(outlives1, outlives2, x.get()) //~ WARNING not reporting region error due to nll
- | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
-
note: External requirements
--> $DIR/propagate-approximated-val.rs:46:45
|
LL | | //~^ ERROR unsatisfied lifetime constraints
LL | |
LL | | // Only works if 'x: 'y:
-LL | | demand_y(outlives1, outlives2, x.get()) //~ WARNING not reporting region error due to nll
+LL | | demand_y(outlives1, outlives2, x.get())
LL | | });
| |_____^
|
LL | | //~^ ERROR unsatisfied lifetime constraints
LL | |
LL | | // Only works if 'x: 'y:
-LL | | demand_y(outlives1, outlives2, x.get()) //~ WARNING not reporting region error due to nll
+LL | | demand_y(outlives1, outlives2, x.get())
LL | | });
| |______^ argument requires that `'a` must outlive `'b`
-warning: not reporting region error due to nll
- --> $DIR/propagate-despite-same-free-region.rs:54:21
- |
-LL | let p = x.get();
- | ^^^^^^^
-
note: External requirements
--> $DIR/propagate-despite-same-free-region.rs:52:9
|
establish_relationships(&cell_a, &cell_b, |_outlives, x, y| {
// Only works if 'x: 'y:
demand_y(x, y, x.get())
- //~^ WARN not reporting region error due to nll
- //~| ERROR
+ //~^ ERROR
});
}
-warning: not reporting region error due to nll
- --> $DIR/propagate-fail-to-approximate-longer-no-bounds.rs:47:9
- |
-LL | demand_y(x, y, x.get())
- | ^^^^^^^^^^^^^^^^^^^^^^^
-
note: No external requirements
--> $DIR/propagate-fail-to-approximate-longer-no-bounds.rs:45:47
|
| _______________________________________________^
LL | | // Only works if 'x: 'y:
LL | | demand_y(x, y, x.get())
-LL | | //~^ WARN not reporting region error due to nll
-LL | | //~| ERROR
+LL | | //~^ ERROR
LL | | });
| |_____^
|
LL | | establish_relationships(&cell_a, &cell_b, |_outlives, x, y| {
LL | | // Only works if 'x: 'y:
LL | | demand_y(x, y, x.get())
-... |
+LL | | //~^ ERROR
LL | | });
LL | | }
| |_^
establish_relationships(&cell_a, &cell_b, |_outlives1, _outlives2, x, y| {
// Only works if 'x: 'y:
demand_y(x, y, x.get())
- //~^ WARN not reporting region error due to nll
- //~| ERROR
+ //~^ ERROR
});
}
-warning: not reporting region error due to nll
- --> $DIR/propagate-fail-to-approximate-longer-wrong-bounds.rs:51:9
- |
-LL | demand_y(x, y, x.get())
- | ^^^^^^^^^^^^^^^^^^^^^^^
-
note: No external requirements
--> $DIR/propagate-fail-to-approximate-longer-wrong-bounds.rs:49:47
|
| _______________________________________________^
LL | | // Only works if 'x: 'y:
LL | | demand_y(x, y, x.get())
-LL | | //~^ WARN not reporting region error due to nll
-LL | | //~| ERROR
+LL | | //~^ ERROR
LL | | });
| |_____^
|
LL | | establish_relationships(&cell_a, &cell_b, |_outlives1, _outlives2, x, y| {
LL | | // Only works if 'x: 'y:
LL | | demand_y(x, y, x.get())
-... |
+LL | | //~^ ERROR
LL | | });
LL | | }
| |_^
// The latter does not hold.
require(value);
- //~^ WARNING not reporting region error due to nll
});
}
-warning: not reporting region error due to nll
- --> $DIR/propagate-from-trait-match.rs:55:9
- |
-LL | require(value);
- | ^^^^^^^
-
note: External requirements
--> $DIR/propagate-from-trait-match.rs:42:36
|
LL | |
LL | | // This function call requires that
... |
-LL | | //~^ WARNING not reporting region error due to nll
+LL | | require(value);
LL | | });
| |_____^
|
LL | |
LL | | // This function call requires that
... |
-LL | | //~^ WARNING not reporting region error due to nll
+LL | | require(value);
LL | | });
| |_____^
|
fn foo(x: &u32) -> &'static u32 {
&*x
- //~^ WARN not reporting region error due to nll
- //~| ERROR explicit lifetime required in the type of `x`
+ //~^ ERROR explicit lifetime required in the type of `x`
}
fn main() { }
-warning: not reporting region error due to nll
- --> $DIR/region-lbr-anon-does-not-outlive-static.rs:19:5
- |
-LL | &*x
- | ^^^
-
error[E0621]: explicit lifetime required in the type of `x`
--> $DIR/region-lbr-anon-does-not-outlive-static.rs:19:5
|
fn foo<'a>(x: &'a u32) -> &'static u32 {
&*x
- //~^ WARN not reporting region error due to nll
- //~| ERROR
+ //~^ ERROR
}
fn main() { }
-warning: not reporting region error due to nll
- --> $DIR/region-lbr-named-does-not-outlive-static.rs:19:5
- |
-LL | &*x
- | ^^^
-
error: unsatisfied lifetime constraints
--> $DIR/region-lbr-named-does-not-outlive-static.rs:19:5
|
fn foo<'a, 'b>(x: &'a u32, y: &'b u32) -> &'b u32 {
&*x
- //~^ WARN not reporting region error due to nll
- //~| ERROR unsatisfied lifetime constraints
+ //~^ ERROR unsatisfied lifetime constraints
}
fn main() { }
-warning: not reporting region error due to nll
- --> $DIR/region-lbr1-does-not-outlive-ebr2.rs:19:5
- |
-LL | &*x
- | ^^^
-
error: unsatisfied lifetime constraints
--> $DIR/region-lbr1-does-not-outlive-ebr2.rs:19:5
|
#[rustc_regions]
fn test() {
expect_sig(|a, b| b); // ought to return `a`
- //~^ WARN not reporting region error due to nll
- //~| ERROR
+ //~^ ERROR
}
fn expect_sig<F>(f: F) -> F
-warning: not reporting region error due to nll
- --> $DIR/return-wrong-bound-region.rs:21:23
- |
-LL | expect_sig(|a, b| b); // ought to return `a`
- | ^
-
note: No external requirements
--> $DIR/return-wrong-bound-region.rs:21:16
|
|
LL | / fn test() {
LL | | expect_sig(|a, b| b); // ought to return `a`
-LL | | //~^ WARN not reporting region error due to nll
-LL | | //~| ERROR
+LL | | //~^ ERROR
LL | | }
| |_^
|
fn bar<'a, 'b>() -> fn(&'a u32, &'b u32) -> &'a u32 {
let g: fn(_, _) -> _ = |_x, y| y;
g
- //~^ WARNING not reporting region error due to nll
- //~^^ ERROR unsatisfied lifetime constraints
+ //~^ ERROR unsatisfied lifetime constraints
}
fn main() {}
-warning: not reporting region error due to nll
- --> $DIR/mir_check_cast_closure.rs:17:5
- |
-LL | g
- | ^
-
error: unsatisfied lifetime constraints
--> $DIR/mir_check_cast_closure.rs:17:5
|
// The MIR type checker must therefore relate `'?0` to `'?1` and `'?2`
// as part of checking the `ReifyFnPointer`.
let f: fn(_) -> _ = foo;
- //~^ WARNING not reporting region error due to nll
f(x)
//~^ ERROR
}
-warning: not reporting region error due to nll
- --> $DIR/mir_check_cast_reify.rs:46:25
- |
-LL | let f: fn(_) -> _ = foo;
- | ^^^
-
error: unsatisfied lifetime constraints
- --> $DIR/mir_check_cast_reify.rs:48:5
+ --> $DIR/mir_check_cast_reify.rs:47:5
|
LL | fn bar<'a>(x: &'a u32) -> &'static u32 {
| -- lifetime `'a` defined here
// Here the NLL checker must relate the types in `f` to the types
// in `g`. These are related via the `UnsafeFnPointer` cast.
let g: unsafe fn(_) -> _ = f;
- //~^ WARNING not reporting region error due to nll
unsafe { g(input) }
//~^ ERROR
}
-warning: not reporting region error due to nll
- --> $DIR/mir_check_cast_unsafe_fn.rs:18:32
- |
-LL | let g: unsafe fn(_) -> _ = f;
- | ^
-
error: unsatisfied lifetime constraints
- --> $DIR/mir_check_cast_unsafe_fn.rs:20:14
+ --> $DIR/mir_check_cast_unsafe_fn.rs:19:14
|
LL | fn bar<'a>(input: &'a u32, f: fn(&'a u32) -> &'a u32) -> &'static u32 {
| -- lifetime `'a` defined here
fn bar<'a>(x: &'a u32) -> &'static dyn Debug {
x
//~^ ERROR unsatisfied lifetime constraints
- //~| WARNING not reporting region error due to nll
}
fn main() {}
-warning: not reporting region error due to nll
- --> $DIR/mir_check_cast_unsize.rs:18:5
- |
-LL | x
- | ^
-
error: unsatisfied lifetime constraints
--> $DIR/mir_check_cast_unsize.rs:18:5
|
fn foo<'a, T>(x: &T) -> impl Foo<'a> {
x
- //~^ WARNING not reporting region error due to nll
- //~| ERROR explicit lifetime required in the type of `x` [E0621]
+ //~^ ERROR explicit lifetime required in the type of `x` [E0621]
}
fn main() {}
-warning: not reporting region error due to nll
- --> $DIR/impl-trait-captures.rs:21:5
- |
-LL | x
- | ^
-
error[E0621]: explicit lifetime required in the type of `x`
--> $DIR/impl-trait-captures.rs:21:5
|
use std::fmt::Debug;
fn no_region<'a, T>(x: Box<T>) -> impl Debug + 'a
- //~^ WARNING not reporting region error due to nll
where
T: Debug,
{
}
fn wrong_region<'a, 'b, T>(x: Box<T>) -> impl Debug + 'a
- //~^ WARNING not reporting region error due to nll
where
T: 'b + Debug,
{
-warning: not reporting region error due to nll
- --> $DIR/impl-trait-outlives.rs:17:35
- |
-LL | fn no_region<'a, T>(x: Box<T>) -> impl Debug + 'a
- | ^^^^^^^^^^^^^^^
-
-warning: not reporting region error due to nll
- --> $DIR/impl-trait-outlives.rs:33:42
- |
-LL | fn wrong_region<'a, 'b, T>(x: Box<T>) -> impl Debug + 'a
- | ^^^^^^^^^^^^^^^
-
error[E0309]: the parameter type `T` may not live long enough
- --> $DIR/impl-trait-outlives.rs:22:5
+ --> $DIR/impl-trait-outlives.rs:21:5
|
LL | x
| ^
= help: consider adding an explicit lifetime bound `T: ReEarlyBound(0, 'a)`...
error[E0309]: the parameter type `T` may not live long enough
- --> $DIR/impl-trait-outlives.rs:38:5
+ --> $DIR/impl-trait-outlives.rs:36:5
|
LL | x
| ^
#[rustc_errors]
fn generic2<T: Iterator>(value: T) {
twice(value, |value_ref, item| invoke2(value_ref, item));
- //~^ WARNING not reporting region error due to nll
- //~| ERROR the parameter type `T` may not live long enough
+ //~^ ERROR the parameter type `T` may not live long enough
}
fn invoke2<'a, T, U>(a: &T, b: Cell<&'a Option<U>>)
-warning: not reporting region error due to nll
- --> $DIR/projection-implied-bounds.rs:45:36
- |
-LL | twice(value, |value_ref, item| invoke2(value_ref, item));
- | ^^^^^^^
-
error[E0310]: the parameter type `T` may not live long enough
--> $DIR/projection-implied-bounds.rs:45:18
|
T: Iterator,
{
with_signature(x, |mut y| Box::new(y.next()))
- //~^ WARNING not reporting region error due to nll
- //~| ERROR the associated type `<T as std::iter::Iterator>::Item` may not live long enough
+ //~^ ERROR the associated type `<T as std::iter::Iterator>::Item` may not live long enough
}
#[rustc_regions]
T: 'b + Iterator,
{
with_signature(x, |mut y| Box::new(y.next()))
- //~^ WARNING not reporting region error due to nll
- //~| ERROR the associated type `<T as std::iter::Iterator>::Item` may not live long enough
+ //~^ ERROR the associated type `<T as std::iter::Iterator>::Item` may not live long enough
}
#[rustc_regions]
-warning: not reporting region error due to nll
- --> $DIR/projection-no-regions-closure.rs:35:31
- |
-LL | with_signature(x, |mut y| Box::new(y.next()))
- | ^^^^^^^^^^^^^^^^^^
-
-warning: not reporting region error due to nll
- --> $DIR/projection-no-regions-closure.rs:53:31
- |
-LL | with_signature(x, |mut y| Box::new(y.next()))
- | ^^^^^^^^^^^^^^^^^^
-
note: External requirements
--> $DIR/projection-no-regions-closure.rs:35:23
|
LL | | where
LL | | T: Iterator,
LL | | {
-... |
-LL | | //~| ERROR the associated type `<T as std::iter::Iterator>::Item` may not live long enough
+LL | | with_signature(x, |mut y| Box::new(y.next()))
+LL | | //~^ ERROR the associated type `<T as std::iter::Iterator>::Item` may not live long enough
LL | | }
| |_^
|
= help: consider adding an explicit lifetime bound `<T as std::iter::Iterator>::Item: ReEarlyBound(0, 'a)`...
note: External requirements
- --> $DIR/projection-no-regions-closure.rs:45:23
+ --> $DIR/projection-no-regions-closure.rs:44:23
|
LL | with_signature(x, |mut y| Box::new(y.next()))
| ^^^^^^^^^^^^^^^^^^^^^^^^^^
= note: where <T as std::iter::Iterator>::Item: '_#2r
note: No external requirements
- --> $DIR/projection-no-regions-closure.rs:41:1
+ --> $DIR/projection-no-regions-closure.rs:40:1
|
LL | / fn correct_region<'a, T>(x: Box<T>) -> Box<dyn Anything + 'a>
LL | | where
]
note: External requirements
- --> $DIR/projection-no-regions-closure.rs:53:23
+ --> $DIR/projection-no-regions-closure.rs:52:23
|
LL | with_signature(x, |mut y| Box::new(y.next()))
| ^^^^^^^^^^^^^^^^^^^^^^^^^^
= note: where <T as std::iter::Iterator>::Item: '_#3r
note: No external requirements
- --> $DIR/projection-no-regions-closure.rs:49:1
+ --> $DIR/projection-no-regions-closure.rs:48:1
|
LL | / fn wrong_region<'a, 'b, T>(x: Box<T>) -> Box<dyn Anything + 'a>
LL | | where
LL | | T: 'b + Iterator,
LL | | {
-... |
-LL | | //~| ERROR the associated type `<T as std::iter::Iterator>::Item` may not live long enough
+LL | | with_signature(x, |mut y| Box::new(y.next()))
+LL | | //~^ ERROR the associated type `<T as std::iter::Iterator>::Item` may not live long enough
LL | | }
| |_^
|
]
error[E0309]: the associated type `<T as std::iter::Iterator>::Item` may not live long enough
- --> $DIR/projection-no-regions-closure.rs:53:23
+ --> $DIR/projection-no-regions-closure.rs:52:23
|
LL | with_signature(x, |mut y| Box::new(y.next()))
| ^^^^^^^^^^^^^^^^^^^^^^^^^^
= help: consider adding an explicit lifetime bound `<T as std::iter::Iterator>::Item: ReEarlyBound(0, 'a)`...
note: External requirements
- --> $DIR/projection-no-regions-closure.rs:64:23
+ --> $DIR/projection-no-regions-closure.rs:62:23
|
LL | with_signature(x, |mut y| Box::new(y.next()))
| ^^^^^^^^^^^^^^^^^^^^^^^^^^
= note: where <T as std::iter::Iterator>::Item: '_#3r
note: No external requirements
- --> $DIR/projection-no-regions-closure.rs:59:1
+ --> $DIR/projection-no-regions-closure.rs:57:1
|
LL | / fn outlives_region<'a, 'b, T>(x: Box<T>) -> Box<dyn Anything + 'a>
LL | | where
T: Iterator,
{
Box::new(x.next())
- //~^ WARNING not reporting region error due to nll
- //~| the associated type `<T as std::iter::Iterator>::Item` may not live long enough
+ //~^ ERROR the associated type `<T as std::iter::Iterator>::Item` may not live long enough
}
fn correct_region<'a, T>(mut x: T) -> Box<dyn Anything + 'a>
T: 'b + Iterator,
{
Box::new(x.next())
- //~^ WARNING not reporting region error due to nll
- //~| the associated type `<T as std::iter::Iterator>::Item` may not live long enough
+ //~^ ERROR the associated type `<T as std::iter::Iterator>::Item` may not live long enough
}
fn outlives_region<'a, 'b, T>(mut x: T) -> Box<dyn Anything + 'a>
-warning: not reporting region error due to nll
- --> $DIR/projection-no-regions-fn.rs:23:5
- |
-LL | Box::new(x.next())
- | ^^^^^^^^^^^^^^^^^^
-
-warning: not reporting region error due to nll
- --> $DIR/projection-no-regions-fn.rs:39:5
- |
-LL | Box::new(x.next())
- | ^^^^^^^^^^^^^^^^^^
-
error[E0309]: the associated type `<T as std::iter::Iterator>::Item` may not live long enough
--> $DIR/projection-no-regions-fn.rs:23:5
|
= help: consider adding an explicit lifetime bound `<T as std::iter::Iterator>::Item: ReEarlyBound(0, 'a)`...
error[E0309]: the associated type `<T as std::iter::Iterator>::Item` may not live long enough
- --> $DIR/projection-no-regions-fn.rs:39:5
+ --> $DIR/projection-no-regions-fn.rs:38:5
|
LL | Box::new(x.next())
| ^^^^^^^^^^^^^^^^^^
T: Anything<'b>,
{
with_signature(cell, t, |cell, t| require(cell, t));
- //~^ WARNING not reporting region error due to nll
- //~| ERROR the parameter type `T` may not live long enough
+ //~^ ERROR the parameter type `T` may not live long enough
//~| ERROR
}
'a: 'a,
{
with_signature(cell, t, |cell, t| require(cell, t));
- //~^ WARNING not reporting region error due to nll
- //~| ERROR the parameter type `T` may not live long enough
+ //~^ ERROR the parameter type `T` may not live long enough
//~| ERROR
}
// can do better here with a more involved verification step.
with_signature(cell, t, |cell, t| require(cell, t));
- //~^ WARNING not reporting region error due to nll
- //~| ERROR the parameter type `T` may not live long enough
+ //~^ ERROR the parameter type `T` may not live long enough
//~| ERROR
}
-warning: not reporting region error due to nll
- --> $DIR/projection-one-region-closure.rs:55:39
- |
-LL | with_signature(cell, t, |cell, t| require(cell, t));
- | ^^^^^^^
-
-warning: not reporting region error due to nll
- --> $DIR/projection-one-region-closure.rs:67:39
- |
-LL | with_signature(cell, t, |cell, t| require(cell, t));
- | ^^^^^^^
-
-warning: not reporting region error due to nll
- --> $DIR/projection-one-region-closure.rs:89:39
- |
-LL | with_signature(cell, t, |cell, t| require(cell, t));
- | ^^^^^^^
-
note: External requirements
--> $DIR/projection-one-region-closure.rs:55:29
|
= help: consider adding an explicit lifetime bound `T: ReFree(DefId(0/0:8 ~ projection_one_region_closure[317d]::no_relationships_late[0]), BrNamed(crate0:DefIndex(1:16), 'a))`...
note: External requirements
- --> $DIR/projection-one-region-closure.rs:67:29
+ --> $DIR/projection-one-region-closure.rs:66:29
|
LL | with_signature(cell, t, |cell, t| require(cell, t));
| ^^^^^^^^^^^^^^^^^^^^^^^^^^
= note: where '_#2r: '_#3r
note: No external requirements
- --> $DIR/projection-one-region-closure.rs:62:1
+ --> $DIR/projection-one-region-closure.rs:61:1
|
LL | / fn no_relationships_early<'a, 'b, T>(cell: Cell<&'a ()>, t: T)
LL | | where
]
error: unsatisfied lifetime constraints
- --> $DIR/projection-one-region-closure.rs:67:5
+ --> $DIR/projection-one-region-closure.rs:66:5
|
LL | fn no_relationships_early<'a, 'b, T>(cell: Cell<&'a ()>, t: T)
| -- -- lifetime `'b` defined here
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ argument requires that `'b` must outlive `'a`
error[E0309]: the parameter type `T` may not live long enough
- --> $DIR/projection-one-region-closure.rs:67:29
+ --> $DIR/projection-one-region-closure.rs:66:29
|
LL | with_signature(cell, t, |cell, t| require(cell, t));
| ^^^^^^^^^^^^^^^^^^^^^^^^^^
= help: consider adding an explicit lifetime bound `T: ReEarlyBound(0, 'a)`...
note: External requirements
- --> $DIR/projection-one-region-closure.rs:89:29
+ --> $DIR/projection-one-region-closure.rs:87:29
|
LL | with_signature(cell, t, |cell, t| require(cell, t));
| ^^^^^^^^^^^^^^^^^^^^^^^^^^
= note: where '_#2r: '_#3r
note: No external requirements
- --> $DIR/projection-one-region-closure.rs:74:1
+ --> $DIR/projection-one-region-closure.rs:72:1
|
LL | / fn projection_outlives<'a, 'b, T>(cell: Cell<&'a ()>, t: T)
LL | | where
]
error: unsatisfied lifetime constraints
- --> $DIR/projection-one-region-closure.rs:89:5
+ --> $DIR/projection-one-region-closure.rs:87:5
|
LL | fn projection_outlives<'a, 'b, T>(cell: Cell<&'a ()>, t: T)
| -- -- lifetime `'b` defined here
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ argument requires that `'b` must outlive `'a`
error[E0309]: the parameter type `T` may not live long enough
- --> $DIR/projection-one-region-closure.rs:89:29
+ --> $DIR/projection-one-region-closure.rs:87:29
|
LL | with_signature(cell, t, |cell, t| require(cell, t));
| ^^^^^^^^^^^^^^^^^^^^^^^^^^
= help: consider adding an explicit lifetime bound `T: ReEarlyBound(0, 'a)`...
note: External requirements
- --> $DIR/projection-one-region-closure.rs:102:29
+ --> $DIR/projection-one-region-closure.rs:99:29
|
LL | with_signature(cell, t, |cell, t| require(cell, t));
| ^^^^^^^^^^^^^^^^^^^^^^^^^^
= note: where '_#2r: '_#3r
note: No external requirements
- --> $DIR/projection-one-region-closure.rs:96:1
+ --> $DIR/projection-one-region-closure.rs:93:1
|
LL | / fn elements_outlive<'a, 'b, T>(cell: Cell<&'a ()>, t: T)
LL | | where
T: Anything<'b>,
{
with_signature(cell, t, |cell, t| require(cell, t));
- //~^ WARNING not reporting region error due to nll
- //~| ERROR
+ //~^ ERROR
}
#[rustc_regions]
'a: 'a,
{
with_signature(cell, t, |cell, t| require(cell, t));
- //~^ WARNING not reporting region error due to nll
- //~| ERROR
+ //~^ ERROR
}
#[rustc_regions]
// can do better here with a more involved verification step.
with_signature(cell, t, |cell, t| require(cell, t));
- //~^ WARNING not reporting region error due to nll
- //~| ERROR
+ //~^ ERROR
}
#[rustc_regions]
-warning: not reporting region error due to nll
- --> $DIR/projection-one-region-trait-bound-closure.rs:47:39
- |
-LL | with_signature(cell, t, |cell, t| require(cell, t));
- | ^^^^^^^
-
-warning: not reporting region error due to nll
- --> $DIR/projection-one-region-trait-bound-closure.rs:58:39
- |
-LL | with_signature(cell, t, |cell, t| require(cell, t));
- | ^^^^^^^
-
-warning: not reporting region error due to nll
- --> $DIR/projection-one-region-trait-bound-closure.rs:79:39
- |
-LL | with_signature(cell, t, |cell, t| require(cell, t));
- | ^^^^^^^
-
note: External requirements
--> $DIR/projection-one-region-trait-bound-closure.rs:47:29
|
LL | | where
LL | | T: Anything<'b>,
LL | | {
-... |
-LL | | //~| ERROR
+LL | | with_signature(cell, t, |cell, t| require(cell, t));
+LL | | //~^ ERROR
LL | | }
| |_^
|
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ argument requires that `'b` must outlive `'a`
note: External requirements
- --> $DIR/projection-one-region-trait-bound-closure.rs:58:29
+ --> $DIR/projection-one-region-trait-bound-closure.rs:57:29
|
LL | with_signature(cell, t, |cell, t| require(cell, t));
| ^^^^^^^^^^^^^^^^^^^^^^^^^^
= note: where '_#2r: '_#3r
note: No external requirements
- --> $DIR/projection-one-region-trait-bound-closure.rs:53:1
+ --> $DIR/projection-one-region-trait-bound-closure.rs:52:1
|
LL | / fn no_relationships_early<'a, 'b, T>(cell: Cell<&'a ()>, t: T)
LL | | where
LL | | T: Anything<'b>,
LL | | 'a: 'a,
... |
-LL | | //~| ERROR
+LL | | //~^ ERROR
LL | | }
| |_^
|
]
error: unsatisfied lifetime constraints
- --> $DIR/projection-one-region-trait-bound-closure.rs:58:5
+ --> $DIR/projection-one-region-trait-bound-closure.rs:57:5
|
LL | fn no_relationships_early<'a, 'b, T>(cell: Cell<&'a ()>, t: T)
| -- -- lifetime `'b` defined here
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ argument requires that `'b` must outlive `'a`
note: External requirements
- --> $DIR/projection-one-region-trait-bound-closure.rs:79:29
+ --> $DIR/projection-one-region-trait-bound-closure.rs:77:29
|
LL | with_signature(cell, t, |cell, t| require(cell, t));
| ^^^^^^^^^^^^^^^^^^^^^^^^^^
= note: where '_#2r: '_#3r
note: No external requirements
- --> $DIR/projection-one-region-trait-bound-closure.rs:64:1
+ --> $DIR/projection-one-region-trait-bound-closure.rs:62:1
|
LL | / fn projection_outlives<'a, 'b, T>(cell: Cell<&'a ()>, t: T)
LL | | where
LL | | T: Anything<'b>,
LL | | T::AssocType: 'a,
... |
-LL | | //~| ERROR
+LL | | //~^ ERROR
LL | | }
| |_^
|
]
error: unsatisfied lifetime constraints
- --> $DIR/projection-one-region-trait-bound-closure.rs:79:5
+ --> $DIR/projection-one-region-trait-bound-closure.rs:77:5
|
LL | fn projection_outlives<'a, 'b, T>(cell: Cell<&'a ()>, t: T)
| -- -- lifetime `'b` defined here
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ argument requires that `'b` must outlive `'a`
note: External requirements
- --> $DIR/projection-one-region-trait-bound-closure.rs:90:29
+ --> $DIR/projection-one-region-trait-bound-closure.rs:87:29
|
LL | with_signature(cell, t, |cell, t| require(cell, t));
| ^^^^^^^^^^^^^^^^^^^^^^^^^^
= note: where '_#2r: '_#3r
note: No external requirements
- --> $DIR/projection-one-region-trait-bound-closure.rs:85:1
+ --> $DIR/projection-one-region-trait-bound-closure.rs:82:1
|
LL | / fn elements_outlive<'a, 'b, T>(cell: Cell<&'a ()>, t: T)
LL | | where
]
note: External requirements
- --> $DIR/projection-one-region-trait-bound-closure.rs:102:29
+ --> $DIR/projection-one-region-trait-bound-closure.rs:99:29
|
LL | with_signature(cell, t, |cell, t| require(cell, t));
| ^^^^^^^^^^^^^^^^^^^^^^^^^^
= note: where '_#1r: '_#2r
note: No external requirements
- --> $DIR/projection-one-region-trait-bound-closure.rs:94:1
+ --> $DIR/projection-one-region-trait-bound-closure.rs:91:1
|
LL | / fn one_region<'a, T>(cell: Cell<&'a ()>, t: T)
LL | | where
T: Anything<'b, 'c>,
{
with_signature(cell, t, |cell, t| require(cell, t));
- //~^ WARNING not reporting region error due to nll
- //~| ERROR associated type `<T as Anything<'_#6r, '_#7r>>::AssocType` may not live long enough
+ //~^ ERROR associated type `<T as Anything<'_#6r, '_#7r>>::AssocType` may not live long enough
}
#[rustc_regions]
'a: 'a,
{
with_signature(cell, t, |cell, t| require(cell, t));
- //~^ WARNING not reporting region error due to nll
- //~| ERROR associated type `<T as Anything<'_#7r, '_#8r>>::AssocType` may not live long enough
+ //~^ ERROR associated type `<T as Anything<'_#7r, '_#8r>>::AssocType` may not live long enough
}
#[rustc_regions]
// can do better here with a more involved verification step.
with_signature(cell, t, |cell, t| require(cell, t));
- //~^ WARNING not reporting region error due to nll
- //~| ERROR associated type `<T as Anything<'_#7r, '_#8r>>::AssocType` may not live long enough
+ //~^ ERROR associated type `<T as Anything<'_#7r, '_#8r>>::AssocType` may not live long enough
}
#[rustc_regions]
T: Anything<'b, 'b>,
{
with_signature(cell, t, |cell, t| require(cell, t));
- //~^ WARNING not reporting region error due to nll
- //~| ERROR
+ //~^ ERROR
}
#[rustc_regions]
-warning: not reporting region error due to nll
- --> $DIR/projection-two-region-trait-bound-closure.rs:48:39
- |
-LL | with_signature(cell, t, |cell, t| require(cell, t));
- | ^^^^^^^
-
-warning: not reporting region error due to nll
- --> $DIR/projection-two-region-trait-bound-closure.rs:59:39
- |
-LL | with_signature(cell, t, |cell, t| require(cell, t));
- | ^^^^^^^
-
-warning: not reporting region error due to nll
- --> $DIR/projection-two-region-trait-bound-closure.rs:80:39
- |
-LL | with_signature(cell, t, |cell, t| require(cell, t));
- | ^^^^^^^
-
-warning: not reporting region error due to nll
- --> $DIR/projection-two-region-trait-bound-closure.rs:108:39
- |
-LL | with_signature(cell, t, |cell, t| require(cell, t));
- | ^^^^^^^
-
note: External requirements
--> $DIR/projection-two-region-trait-bound-closure.rs:48:29
|
LL | | where
LL | | T: Anything<'b, 'c>,
LL | | {
-... |
-LL | | //~| ERROR associated type `<T as Anything<'_#6r, '_#7r>>::AssocType` may not live long enough
+LL | | with_signature(cell, t, |cell, t| require(cell, t));
+LL | | //~^ ERROR associated type `<T as Anything<'_#6r, '_#7r>>::AssocType` may not live long enough
LL | | }
| |_^
|
= help: consider adding an explicit lifetime bound `<T as Anything<'_#6r, '_#7r>>::AssocType: ReFree(DefId(0/0:8 ~ projection_two_region_trait_bound_closure[317d]::no_relationships_late[0]), BrNamed(crate0:DefIndex(1:18), 'a))`...
note: External requirements
- --> $DIR/projection-two-region-trait-bound-closure.rs:59:29
+ --> $DIR/projection-two-region-trait-bound-closure.rs:58:29
|
LL | with_signature(cell, t, |cell, t| require(cell, t));
| ^^^^^^^^^^^^^^^^^^^^^^^^^^
= note: where <T as Anything<ReClosureBound('_#2r), ReClosureBound('_#3r)>>::AssocType: '_#4r
note: No external requirements
- --> $DIR/projection-two-region-trait-bound-closure.rs:54:1
+ --> $DIR/projection-two-region-trait-bound-closure.rs:53:1
|
LL | / fn no_relationships_early<'a, 'b, 'c, T>(cell: Cell<&'a ()>, t: T)
LL | | where
LL | | T: Anything<'b, 'c>,
LL | | 'a: 'a,
... |
-LL | | //~| ERROR associated type `<T as Anything<'_#7r, '_#8r>>::AssocType` may not live long enough
+LL | | //~^ ERROR associated type `<T as Anything<'_#7r, '_#8r>>::AssocType` may not live long enough
LL | | }
| |_^
|
]
error[E0309]: the associated type `<T as Anything<'_#7r, '_#8r>>::AssocType` may not live long enough
- --> $DIR/projection-two-region-trait-bound-closure.rs:59:29
+ --> $DIR/projection-two-region-trait-bound-closure.rs:58:29
|
LL | with_signature(cell, t, |cell, t| require(cell, t));
| ^^^^^^^^^^^^^^^^^^^^^^^^^^
= help: consider adding an explicit lifetime bound `<T as Anything<'_#7r, '_#8r>>::AssocType: ReEarlyBound(0, 'a)`...
note: External requirements
- --> $DIR/projection-two-region-trait-bound-closure.rs:80:29
+ --> $DIR/projection-two-region-trait-bound-closure.rs:78:29
|
LL | with_signature(cell, t, |cell, t| require(cell, t));
| ^^^^^^^^^^^^^^^^^^^^^^^^^^
= note: where <T as Anything<ReClosureBound('_#2r), ReClosureBound('_#3r)>>::AssocType: '_#4r
note: No external requirements
- --> $DIR/projection-two-region-trait-bound-closure.rs:65:1
+ --> $DIR/projection-two-region-trait-bound-closure.rs:63:1
|
LL | / fn projection_outlives<'a, 'b, 'c, T>(cell: Cell<&'a ()>, t: T)
LL | | where
LL | | T: Anything<'b, 'c>,
LL | | T::AssocType: 'a,
... |
-LL | | //~| ERROR associated type `<T as Anything<'_#7r, '_#8r>>::AssocType` may not live long enough
+LL | | //~^ ERROR associated type `<T as Anything<'_#7r, '_#8r>>::AssocType` may not live long enough
LL | | }
| |_^
|
]
error[E0309]: the associated type `<T as Anything<'_#7r, '_#8r>>::AssocType` may not live long enough
- --> $DIR/projection-two-region-trait-bound-closure.rs:80:29
+ --> $DIR/projection-two-region-trait-bound-closure.rs:78:29
|
LL | with_signature(cell, t, |cell, t| require(cell, t));
| ^^^^^^^^^^^^^^^^^^^^^^^^^^
= help: consider adding an explicit lifetime bound `<T as Anything<'_#7r, '_#8r>>::AssocType: ReEarlyBound(0, 'a)`...
note: External requirements
- --> $DIR/projection-two-region-trait-bound-closure.rs:91:29
+ --> $DIR/projection-two-region-trait-bound-closure.rs:88:29
|
LL | with_signature(cell, t, |cell, t| require(cell, t));
| ^^^^^^^^^^^^^^^^^^^^^^^^^^
= note: where <T as Anything<ReClosureBound('_#2r), ReClosureBound('_#3r)>>::AssocType: '_#4r
note: No external requirements
- --> $DIR/projection-two-region-trait-bound-closure.rs:86:1
+ --> $DIR/projection-two-region-trait-bound-closure.rs:83:1
|
LL | / fn elements_outlive1<'a, 'b, 'c, T>(cell: Cell<&'a ()>, t: T)
LL | | where
]
note: External requirements
- --> $DIR/projection-two-region-trait-bound-closure.rs:100:29
+ --> $DIR/projection-two-region-trait-bound-closure.rs:97:29
|
LL | with_signature(cell, t, |cell, t| require(cell, t));
| ^^^^^^^^^^^^^^^^^^^^^^^^^^
= note: where <T as Anything<ReClosureBound('_#2r), ReClosureBound('_#3r)>>::AssocType: '_#4r
note: No external requirements
- --> $DIR/projection-two-region-trait-bound-closure.rs:95:1
+ --> $DIR/projection-two-region-trait-bound-closure.rs:92:1
|
LL | / fn elements_outlive2<'a, 'b, 'c, T>(cell: Cell<&'a ()>, t: T)
LL | | where
]
note: External requirements
- --> $DIR/projection-two-region-trait-bound-closure.rs:108:29
+ --> $DIR/projection-two-region-trait-bound-closure.rs:105:29
|
LL | with_signature(cell, t, |cell, t| require(cell, t));
| ^^^^^^^^^^^^^^^^^^^^^^^^^^
= note: where <T as Anything<ReClosureBound('_#1r), ReClosureBound('_#1r)>>::AssocType: '_#2r
note: No external requirements
- --> $DIR/projection-two-region-trait-bound-closure.rs:104:1
+ --> $DIR/projection-two-region-trait-bound-closure.rs:101:1
|
LL | / fn two_regions<'a, 'b, T>(cell: Cell<&'a ()>, t: T)
LL | | where
LL | | T: Anything<'b, 'b>,
LL | | {
-... |
-LL | | //~| ERROR
+LL | | with_signature(cell, t, |cell, t| require(cell, t));
+LL | | //~^ ERROR
LL | | }
| |_^
|
]
error: unsatisfied lifetime constraints
- --> $DIR/projection-two-region-trait-bound-closure.rs:108:5
+ --> $DIR/projection-two-region-trait-bound-closure.rs:105:5
|
LL | fn two_regions<'a, 'b, T>(cell: Cell<&'a ()>, t: T)
| -- -- lifetime `'b` defined here
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ argument requires that `'b` must outlive `'a`
note: External requirements
- --> $DIR/projection-two-region-trait-bound-closure.rs:119:29
+ --> $DIR/projection-two-region-trait-bound-closure.rs:115:29
|
LL | with_signature(cell, t, |cell, t| require(cell, t));
| ^^^^^^^^^^^^^^^^^^^^^^^^^^
= note: where <T as Anything<ReClosureBound('_#2r), ReClosureBound('_#2r)>>::AssocType: '_#3r
note: No external requirements
- --> $DIR/projection-two-region-trait-bound-closure.rs:114:1
+ --> $DIR/projection-two-region-trait-bound-closure.rs:110:1
|
LL | / fn two_regions_outlive<'a, 'b, T>(cell: Cell<&'a ()>, t: T)
LL | | where
]
note: External requirements
- --> $DIR/projection-two-region-trait-bound-closure.rs:131:29
+ --> $DIR/projection-two-region-trait-bound-closure.rs:127:29
|
LL | with_signature(cell, t, |cell, t| require(cell, t));
| ^^^^^^^^^^^^^^^^^^^^^^^^^^
= note: where <T as Anything<ReClosureBound('_#1r), ReClosureBound('_#1r)>>::AssocType: '_#2r
note: No external requirements
- --> $DIR/projection-two-region-trait-bound-closure.rs:123:1
+ --> $DIR/projection-two-region-trait-bound-closure.rs:119:1
|
LL | / fn one_region<'a, T>(cell: Cell<&'a ()>, t: T)
LL | | where
fn generic<T>(value: T) {
let cell = Cell::new(&());
twice(cell, value, |a, b| invoke(a, b));
- //~^ WARNING not reporting region error
- //
- // This error from the old region solver looks bogus.
}
#[rustc_regions]
fn generic_fail<'a, T>(cell: Cell<&'a ()>, value: T) {
twice(cell, value, |a, b| invoke(a, b));
- //~^ WARNING not reporting region error
- //~| WARNING not reporting region error
- //~| ERROR the parameter type `T` may not live long enough
+ //~^ ERROR the parameter type `T` may not live long enough
}
fn invoke<'a, 'x, T>(x: Option<Cell<&'x &'a ()>>, y: &T)
-warning: not reporting region error due to nll
- --> $DIR/ty-param-closure-approximate-lower-bound.rs:34:31
- |
-LL | twice(cell, value, |a, b| invoke(a, b));
- | ^^^^^^^^^^^^
-
-warning: not reporting region error due to nll
- --> $DIR/ty-param-closure-approximate-lower-bound.rs:42:31
- |
-LL | twice(cell, value, |a, b| invoke(a, b));
- | ^^^^^^
-
-warning: not reporting region error due to nll
- --> $DIR/ty-param-closure-approximate-lower-bound.rs:42:31
- |
-LL | twice(cell, value, |a, b| invoke(a, b));
- | ^^^^^^^^^^^^
-
note: External requirements
--> $DIR/ty-param-closure-approximate-lower-bound.rs:34:24
|
LL | / fn generic<T>(value: T) {
LL | | let cell = Cell::new(&());
LL | | twice(cell, value, |a, b| invoke(a, b));
-LL | | //~^ WARNING not reporting region error
-LL | | //
-LL | | // This error from the old region solver looks bogus.
LL | | }
| |_^
|
]
note: External requirements
- --> $DIR/ty-param-closure-approximate-lower-bound.rs:42:24
+ --> $DIR/ty-param-closure-approximate-lower-bound.rs:39:24
|
LL | twice(cell, value, |a, b| invoke(a, b));
| ^^^^^^^^^^^^^^^^^^^
= note: where T: '_#1r
note: No external requirements
- --> $DIR/ty-param-closure-approximate-lower-bound.rs:41:1
+ --> $DIR/ty-param-closure-approximate-lower-bound.rs:38:1
|
LL | / fn generic_fail<'a, T>(cell: Cell<&'a ()>, value: T) {
LL | | twice(cell, value, |a, b| invoke(a, b));
-LL | | //~^ WARNING not reporting region error
-LL | | //~| WARNING not reporting region error
-LL | | //~| ERROR the parameter type `T` may not live long enough
+LL | | //~^ ERROR the parameter type `T` may not live long enough
LL | | }
| |_^
|
]
error[E0309]: the parameter type `T` may not live long enough
- --> $DIR/ty-param-closure-approximate-lower-bound.rs:42:24
+ --> $DIR/ty-param-closure-approximate-lower-bound.rs:39:24
|
LL | twice(cell, value, |a, b| invoke(a, b));
| ^^^^^^^^^^^^^^^^^^^
// `'a` (and subsequently reports an error).
with_signature(x, |y| y)
- //~^ WARNING not reporting region error due to nll
- //~| ERROR the parameter type `T` may not live long enough
+ //~^ ERROR the parameter type `T` may not live long enough
}
fn correct_region<'a, T>(x: Box<T>) -> Box<Debug + 'a>
T: 'b + Debug,
{
x
- //~^ WARNING not reporting region error due to nll
- //~| ERROR the parameter type `T` may not live long enough
+ //~^ ERROR the parameter type `T` may not live long enough
}
fn outlives_region<'a, 'b, T>(x: Box<T>) -> Box<Debug + 'a>
-warning: not reporting region error due to nll
- --> $DIR/ty-param-closure-outlives-from-return-type.rs:36:27
- |
-LL | with_signature(x, |y| y)
- | ^
-
-warning: not reporting region error due to nll
- --> $DIR/ty-param-closure-outlives-from-return-type.rs:52:5
- |
-LL | x
- | ^
-
note: External requirements
--> $DIR/ty-param-closure-outlives-from-return-type.rs:36:23
|
LL | | T: Debug,
LL | | {
... |
-LL | | //~| ERROR the parameter type `T` may not live long enough
+LL | | //~^ ERROR the parameter type `T` may not live long enough
LL | | }
| |_^
|
= help: consider adding an explicit lifetime bound `T: ReEarlyBound(0, 'a)`...
error[E0309]: the parameter type `T` may not live long enough
- --> $DIR/ty-param-closure-outlives-from-return-type.rs:52:5
+ --> $DIR/ty-param-closure-outlives-from-return-type.rs:51:5
|
LL | x
| ^
// function, there is no where clause *anywhere*, and hence we
// get an error (but reported by the closure creator).
require(&x, &y)
- //~^ WARNING not reporting region error due to nll
})
}
//~^ ERROR the parameter type `T` may not live long enough
// See `correct_region`
require(&x, &y)
- //~^ WARNING not reporting region error due to nll
})
}
-warning: not reporting region error due to nll
- --> $DIR/ty-param-closure-outlives-from-where-clause.rs:44:9
- |
-LL | require(&x, &y)
- | ^^^^^^^
-
-warning: not reporting region error due to nll
- --> $DIR/ty-param-closure-outlives-from-where-clause.rs:78:9
- |
-LL | require(&x, &y)
- | ^^^^^^^
-
note: External requirements
--> $DIR/ty-param-closure-outlives-from-where-clause.rs:37:26
|
LL | | //
LL | | // See `correct_region`, which explains the point of this
... |
-LL | | //~^ WARNING not reporting region error due to nll
+LL | | require(&x, &y)
LL | | })
| |_____^
|
LL | | //
LL | | // See `correct_region`, which explains the point of this
... |
-LL | | //~^ WARNING not reporting region error due to nll
+LL | | require(&x, &y)
LL | | })
| |_____^
|
= help: consider adding an explicit lifetime bound `T: ReFree(DefId(0/0:6 ~ ty_param_closure_outlives_from_where_clause[317d]::no_region[0]), BrNamed(crate0:DefIndex(1:14), 'a))`...
note: External requirements
- --> $DIR/ty-param-closure-outlives-from-where-clause.rs:54:26
+ --> $DIR/ty-param-closure-outlives-from-where-clause.rs:53:26
|
LL | with_signature(a, b, |x, y| {
| __________________________^
= note: where T: '_#2r
note: No external requirements
- --> $DIR/ty-param-closure-outlives-from-where-clause.rs:50:1
+ --> $DIR/ty-param-closure-outlives-from-where-clause.rs:49:1
|
LL | / fn correct_region<'a, T>(a: Cell<&'a ()>, b: T)
LL | | where
]
note: External requirements
- --> $DIR/ty-param-closure-outlives-from-where-clause.rs:75:26
+ --> $DIR/ty-param-closure-outlives-from-where-clause.rs:74:26
|
LL | with_signature(a, b, |x, y| {
| __________________________^
LL | | //~^ ERROR the parameter type `T` may not live long enough
LL | | // See `correct_region`
LL | | require(&x, &y)
-LL | | //~^ WARNING not reporting region error due to nll
LL | | })
| |_____^
|
= note: where T: '_#2r
note: No external requirements
- --> $DIR/ty-param-closure-outlives-from-where-clause.rs:71:1
+ --> $DIR/ty-param-closure-outlives-from-where-clause.rs:70:1
|
LL | / fn wrong_region<'a, 'b, T>(a: Cell<&'a ()>, b: T)
LL | | where
]
error[E0309]: the parameter type `T` may not live long enough
- --> $DIR/ty-param-closure-outlives-from-where-clause.rs:75:26
+ --> $DIR/ty-param-closure-outlives-from-where-clause.rs:74:26
|
LL | with_signature(a, b, |x, y| {
| __________________________^
LL | | //~^ ERROR the parameter type `T` may not live long enough
LL | | // See `correct_region`
LL | | require(&x, &y)
-LL | | //~^ WARNING not reporting region error due to nll
LL | | })
| |_____^
|
= help: consider adding an explicit lifetime bound `T: ReFree(DefId(0/0:8 ~ ty_param_closure_outlives_from_where_clause[317d]::wrong_region[0]), BrNamed(crate0:DefIndex(1:20), 'a))`...
note: External requirements
- --> $DIR/ty-param-closure-outlives-from-where-clause.rs:89:26
+ --> $DIR/ty-param-closure-outlives-from-where-clause.rs:87:26
|
LL | with_signature(a, b, |x, y| {
| __________________________^
= note: where T: '_#3r
note: No external requirements
- --> $DIR/ty-param-closure-outlives-from-where-clause.rs:84:1
+ --> $DIR/ty-param-closure-outlives-from-where-clause.rs:82:1
|
LL | / fn outlives_region<'a, 'b, T>(a: Cell<&'a ()>, b: T)
LL | | where
// Error here, because T: 'a is not satisfied.
fn region_static<'a, T>(cell: Cell<&'a usize>, t: T) {
outlives(cell, t)
- //~^ WARNING not reporting region error due to nll
- //~| ERROR the parameter type `T` may not live long enough
+ //~^ ERROR the parameter type `T` may not live long enough
}
fn outlives<'a, T>(x: Cell<&'a usize>, y: T)
-warning: not reporting region error due to nll
- --> $DIR/ty-param-fn-body.rs:29:5
- |
-LL | outlives(cell, t)
- | ^^^^^^^^
-
error[E0309]: the parameter type `T` may not live long enough
--> $DIR/ty-param-fn-body.rs:29:5
|
T: Debug,
{
x
- //~^ WARNING not reporting region error due to nll
- //~| the parameter type `T` may not live long enough
+ //~^ ERROR the parameter type `T` may not live long enough
}
fn correct_region<'a, T>(x: Box<T>) -> Box<Debug + 'a>
T: 'b + Debug,
{
x
- //~^ WARNING not reporting region error due to nll
- //~| the parameter type `T` may not live long enough
+ //~^ ERROR the parameter type `T` may not live long enough
}
fn outlives_region<'a, 'b, T>(x: Box<T>) -> Box<Debug + 'a>
-warning: not reporting region error due to nll
- --> $DIR/ty-param-fn.rs:21:5
- |
-LL | x
- | ^
-
-warning: not reporting region error due to nll
- --> $DIR/ty-param-fn.rs:37:5
- |
-LL | x
- | ^
-
error[E0309]: the parameter type `T` may not live long enough
--> $DIR/ty-param-fn.rs:21:5
|
= help: consider adding an explicit lifetime bound `T: 'a`...
error[E0309]: the parameter type `T` may not live long enough
- --> $DIR/ty-param-fn.rs:37:5
+ --> $DIR/ty-param-fn.rs:36:5
|
LL | x
| ^
fn bar<'a, 'b>(x: &'a u32, y: &'b u32) -> (&'a u32, &'b u32) {
foo(x, y)
//~^ ERROR unsatisfied lifetime constraints
- //~| WARNING not reporting region error due to nll
}
fn main() {}
-warning: not reporting region error due to nll
- --> $DIR/where_clauses_in_functions.rs:23:5
- |
-LL | foo(x, y)
- | ^^^
-
error: unsatisfied lifetime constraints
--> $DIR/where_clauses_in_functions.rs:23:5
|
fn bar<'a, 'b>(x: Cell<&'a u32>, y: Cell<&'b u32>) {
Foo { x, y };
//~^ ERROR unsatisfied lifetime constraints
- //~| WARNING not reporting region error due to nll
}
fn main() {}
-warning: not reporting region error due to nll
- --> $DIR/where_clauses_in_structs.rs:23:5
- |
-LL | Foo { x, y };
- | ^^^
-
error: unsatisfied lifetime constraints
--> $DIR/where_clauses_in_structs.rs:23:11
|
-warning: not reporting region error due to nll
- --> $DIR/object-lifetime-default-elision.rs:81:5
- |
-LL | ss
- | ^^
-
error: unsatisfied lifetime constraints
--> $DIR/object-lifetime-default-elision.rs:81:5
|
-warning: not reporting region error due to nll
- --> $DIR/object-lifetime-default-from-box-error.rs:28:5
- |
-LL | ss.r //~ ERROR explicit lifetime required in the type of `ss` [E0621]
- | ^^^^
-
-warning: not reporting region error due to nll
- --> $DIR/object-lifetime-default-from-box-error.rs:41:12
- |
-LL | ss.r = b; //~ ERROR 41:12: 41:13: explicit lifetime required in the type of `ss` [E0621]
- | ^
-
error[E0621]: explicit lifetime required in the type of `ss`
--> $DIR/object-lifetime-default-from-box-error.rs:28:5
|
-warning: not reporting region error due to nll
- --> $DIR/object-lifetime-default-from-rptr-box-error.rs:25:12
- |
-LL | ss.t = t; //~ ERROR mismatched types
- | ^
-
error: borrowed data escapes outside of function
--> $DIR/object-lifetime-default-from-rptr-box-error.rs:25:5
|
-warning: not reporting region error due to nll
- --> $DIR/object-lifetime-default-from-rptr-struct-error.rs:31:12
- |
-LL | ss.t = t; //~ ERROR mismatched types
- | ^
-
error: borrowed data escapes outside of function
--> $DIR/object-lifetime-default-from-rptr-struct-error.rs:31:5
|
-warning: not reporting region error due to nll
- --> $DIR/object-lifetime-default-mybox.rs:37:5
- |
-LL | a //~ ERROR lifetime mismatch
- | ^
-
-warning: not reporting region error due to nll
- --> $DIR/object-lifetime-default-mybox.rs:41:11
- |
-LL | load0(ss) //~ ERROR mismatched types
- | ^^
-
error: unsatisfied lifetime constraints
--> $DIR/object-lifetime-default-mybox.rs:37:5
|
error: function should have one argument
--> $DIR/panic-handler-bad-signature-3.rs:20:1
|
-LL | / fn panic() -> ! { //~ ERROR function should have one argument
-LL | | loop {}
-LL | | }
- | |_^
+LL | fn panic() -> ! { //~ ERROR function should have one argument
+ | ^^^^^^^^^^^^^^^
error: aborting due to previous error
-warning: not reporting region error due to nll
- --> $DIR/region-invariant-static-error-reporting.rs:24:15
- |
-LL | let bad = if x.is_some() {
- | _______________^
-LL | | x.unwrap()
-LL | | } else {
-LL | | mk_static()
-LL | | };
- | |_____^
-
error: borrowed data escapes outside of function
--> $DIR/region-invariant-static-error-reporting.rs:25:9
|
-warning: not reporting region error due to nll
- --> $DIR/region-lifetime-bounds-on-fns-where-clause.rs:18:10
- |
-LL | *x = *y; //~ ERROR E0623
- | ^^
-
-warning: not reporting region error due to nll
- --> $DIR/region-lifetime-bounds-on-fns-where-clause.rs:24:5
- |
-LL | a(x, y); //~ ERROR 24:7: 24:8: lifetime mismatch [E0623]
- | ^
-
error[E0308]: mismatched types
--> $DIR/region-lifetime-bounds-on-fns-where-clause.rs:30:43
|
-warning: not reporting region error due to nll
- --> $DIR/region-multiple-lifetime-bounds-on-fns-where-clause.rs:19:10
- |
-LL | *x = *y; //~ ERROR E0623
- | ^^
-
-warning: not reporting region error due to nll
- --> $DIR/region-multiple-lifetime-bounds-on-fns-where-clause.rs:20:10
- |
-LL | *z = *y; //~ ERROR E0623
- | ^^
-
-warning: not reporting region error due to nll
- --> $DIR/region-multiple-lifetime-bounds-on-fns-where-clause.rs:26:5
- |
-LL | a(x, y, z); //~ ERROR 26:7: 26:8: lifetime mismatch [E0623]
- | ^
-
error[E0308]: mismatched types
--> $DIR/region-multiple-lifetime-bounds-on-fns-where-clause.rs:32:56
|
-warning: not reporting region error due to nll
- --> $DIR/region-object-lifetime-2.rs:20:7
- |
-LL | x.borrowed() //~ ERROR cannot infer
- | ^^^^^^^^
-
error: unsatisfied lifetime constraints
--> $DIR/region-object-lifetime-2.rs:20:5
|
-warning: not reporting region error due to nll
- --> $DIR/region-object-lifetime-4.rs:22:7
- |
-LL | x.borrowed() //~ ERROR cannot infer
- | ^^^^^^^^
-
error: unsatisfied lifetime constraints
--> $DIR/region-object-lifetime-4.rs:22:5
|
-warning: not reporting region error due to nll
- --> $DIR/region-object-lifetime-in-coercion.rs:18:42
- |
-LL | let x: Box<Foo + 'static> = Box::new(v);
- | ^
-
-warning: not reporting region error due to nll
- --> $DIR/region-object-lifetime-in-coercion.rs:24:14
- |
-LL | Box::new(v)
- | ^
-
-warning: not reporting region error due to nll
- --> $DIR/region-object-lifetime-in-coercion.rs:31:14
- |
-LL | Box::new(v)
- | ^
-
-warning: not reporting region error due to nll
- --> $DIR/region-object-lifetime-in-coercion.rs:36:14
- |
-LL | Box::new(v)
- | ^
-
error[E0621]: explicit lifetime required in the type of `v`
--> $DIR/region-object-lifetime-in-coercion.rs:18:33
|
-warning: not reporting region error due to nll
- --> $DIR/regions-addr-of-self.rs:17:37
- |
-LL | let p: &'static mut usize = &mut self.cats_chased; //~ ERROR cannot infer
- | ^^^^^^^^^^^^^^^^^^^^^
-
error: unsatisfied lifetime constraints
--> $DIR/regions-addr-of-self.rs:17:37
|
-warning: not reporting region error due to nll
- --> $DIR/regions-addr-of-upvar-self.rs:20:41
- |
-LL | let p: &'static mut usize = &mut self.food; //~ ERROR cannot infer
- | ^^^^^^^^^^^^^^
-
error: unsatisfied lifetime constraints
--> $DIR/regions-addr-of-upvar-self.rs:20:41
|
-warning: not reporting region error due to nll
- --> $DIR/regions-bounded-method-type-parameters-cross-crate.rs:30:7
- |
-LL | a.bigger_region(b) //~ ERROR 30:7: 30:20: lifetime mismatch [E0623]
- | ^^^^^^^^^^^^^
-
error: unsatisfied lifetime constraints
--> $DIR/regions-bounded-method-type-parameters-cross-crate.rs:30:5
|
-warning: not reporting region error due to nll
- --> $DIR/regions-bounded-method-type-parameters-trait-bound.rs:30:7
- |
-LL | f.method(b); //~ ERROR 30:7: 30:13: lifetime mismatch [E0623]
- | ^^^^^^
-
error: borrowed data escapes outside of function
--> $DIR/regions-bounded-method-type-parameters-trait-bound.rs:30:5
|
-warning: not reporting region error due to nll
- --> $DIR/regions-bounds.rs:19:12
- |
-LL | return e; //~ ERROR mismatched types
- | ^
-
-warning: not reporting region error due to nll
- --> $DIR/regions-bounds.rs:23:12
- |
-LL | return e; //~ ERROR mismatched types
- | ^
-
error: unsatisfied lifetime constraints
--> $DIR/regions-bounds.rs:19:12
|
-warning: not reporting region error due to nll
- --> $DIR/regions-close-associated-type-into-object.rs:25:5
- |
-LL | Box::new(item) //~ ERROR associated type `<T as Iter>::Item` may not live long enough
- | ^^^^^^^^^^^^^^
-
-warning: not reporting region error due to nll
- --> $DIR/regions-close-associated-type-into-object.rs:32:5
- |
-LL | Box::new(item) //~ ERROR associated type `<T as Iter>::Item` may not live long enough
- | ^^^^^^^^^^^^^^
-
-warning: not reporting region error due to nll
- --> $DIR/regions-close-associated-type-into-object.rs:38:5
- |
-LL | Box::new(item) //~ ERROR associated type `<T as Iter>::Item` may not live long enough
- | ^^^^^^^^^^^^^^
-
-warning: not reporting region error due to nll
- --> $DIR/regions-close-associated-type-into-object.rs:45:5
- |
-LL | Box::new(item) //~ ERROR associated type `<T as Iter>::Item` may not live long enough
- | ^^^^^^^^^^^^^^
-
error[E0310]: the associated type `<T as Iter>::Item` may not live long enough
--> $DIR/regions-close-associated-type-into-object.rs:25:5
|
-warning: not reporting region error due to nll
- --> $DIR/regions-close-object-into-object-2.rs:20:11
- |
-LL | box B(&*v) as Box<X> //~ ERROR cannot infer
- | ^^^
-
error: unsatisfied lifetime constraints
--> $DIR/regions-close-object-into-object-2.rs:20:5
|
-warning: not reporting region error due to nll
- --> $DIR/regions-close-object-into-object-4.rs:20:5
- |
-LL | box B(&*v) as Box<X> //~ ERROR cannot infer
- | ^^^^^^^^^^^^^^^^^^^^
-
-warning: not reporting region error due to nll
- --> $DIR/regions-close-object-into-object-4.rs:20:11
- |
-LL | box B(&*v) as Box<X> //~ ERROR cannot infer
- | ^^^
-
-warning: not reporting region error due to nll
- --> $DIR/regions-close-object-into-object-4.rs:20:9
- |
-LL | box B(&*v) as Box<X> //~ ERROR cannot infer
- | ^
-
-warning: not reporting region error due to nll
- --> $DIR/regions-close-object-into-object-4.rs:20:9
- |
-LL | box B(&*v) as Box<X> //~ ERROR cannot infer
- | ^^^^^^
-
-warning: not reporting region error due to nll
- --> $DIR/regions-close-object-into-object-4.rs:20:5
- |
-LL | box B(&*v) as Box<X> //~ ERROR cannot infer
- | ^^^^^^^^^^
-
error[E0310]: the parameter type `U` may not live long enough
--> $DIR/regions-close-object-into-object-4.rs:20:5
|
-warning: not reporting region error due to nll
- --> $DIR/regions-close-object-into-object-5.rs:27:5
- |
-LL | box B(&*v) as Box<X>
- | ^^^^^^^^^^^^^^^^^^^^
-
-warning: not reporting region error due to nll
- --> $DIR/regions-close-object-into-object-5.rs:27:11
- |
-LL | box B(&*v) as Box<X>
- | ^^^
-
-warning: not reporting region error due to nll
- --> $DIR/regions-close-object-into-object-5.rs:27:9
- |
-LL | box B(&*v) as Box<X>
- | ^
-
-warning: not reporting region error due to nll
- --> $DIR/regions-close-object-into-object-5.rs:27:9
- |
-LL | box B(&*v) as Box<X>
- | ^^^^^^
-
-warning: not reporting region error due to nll
- --> $DIR/regions-close-object-into-object-5.rs:27:5
- |
-LL | box B(&*v) as Box<X>
- | ^^^^^^^^^^
-
error[E0310]: the parameter type `T` may not live long enough
--> $DIR/regions-close-object-into-object-5.rs:27:5
|
-warning: not reporting region error due to nll
- --> $DIR/regions-close-over-type-parameter-1.rs:20:5
- |
-LL | box v as Box<SomeTrait+'static>
- | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
-
-warning: not reporting region error due to nll
- --> $DIR/regions-close-over-type-parameter-1.rs:20:5
- |
-LL | box v as Box<SomeTrait+'static>
- | ^^^^^
-
-warning: not reporting region error due to nll
- --> $DIR/regions-close-over-type-parameter-1.rs:30:5
- |
-LL | box v as Box<SomeTrait+'b>
- | ^^^^^^^^^^^^^^^^^^^^^^^^^^
-
-warning: not reporting region error due to nll
- --> $DIR/regions-close-over-type-parameter-1.rs:30:5
- |
-LL | box v as Box<SomeTrait+'b>
- | ^^^^^
-
error[E0310]: the parameter type `A` may not live long enough
--> $DIR/regions-close-over-type-parameter-1.rs:20:5
|
-warning: not reporting region error due to nll
- --> $DIR/regions-close-over-type-parameter-multiple.rs:30:5
- |
-LL | box v as Box<SomeTrait+'a> //~ ERROR cannot infer an appropriate lifetime
- | ^^^^^^^^^^^^^^^^^^^^^^^^^^
-
error[E0309]: the parameter type `A` may not live long enough
--> $DIR/regions-close-over-type-parameter-multiple.rs:30:5
|
-warning: not reporting region error due to nll
- --> $DIR/regions-close-param-into-object.rs:16:5
- |
-LL | Box::new(v) //~ ERROR parameter type `T` may not live long enough
- | ^^^^^^^^^^^
-
-warning: not reporting region error due to nll
- --> $DIR/regions-close-param-into-object.rs:22:5
- |
-LL | Box::new(v) //~ ERROR parameter type `T` may not live long enough
- | ^^^^^^^^^^^
-
-warning: not reporting region error due to nll
- --> $DIR/regions-close-param-into-object.rs:28:5
- |
-LL | Box::new(v) //~ ERROR parameter type `T` may not live long enough
- | ^^^^^^^^^^^
-
-warning: not reporting region error due to nll
- --> $DIR/regions-close-param-into-object.rs:34:5
- |
-LL | Box::new(v) //~ ERROR parameter type `T` may not live long enough
- | ^^^^^^^^^^^
-
error[E0310]: the parameter type `T` may not live long enough
--> $DIR/regions-close-param-into-object.rs:16:5
|
-warning: not reporting region error due to nll
- --> $DIR/regions-creating-enums3.rs:17:5
- |
-LL | ast::add(x, y) //~ ERROR 17:5: 17:19: lifetime mismatch [E0623]
- | ^^^^^^^^
-
error: unsatisfied lifetime constraints
--> $DIR/regions-creating-enums3.rs:17:5
|
-warning: not reporting region error due to nll
- --> $DIR/regions-creating-enums4.rs:17:5
- |
-LL | ast::add(x, y) //~ ERROR cannot infer
- | ^^^^^^^^
-
error: unsatisfied lifetime constraints
--> $DIR/regions-creating-enums4.rs:17:5
|
-warning: not reporting region error due to nll
- --> $DIR/regions-early-bound-error-method.rs:30:9
- |
-LL | g2.get()
- | ^^^^^^^^
-
error: unsatisfied lifetime constraints
--> $DIR/regions-early-bound-error-method.rs:30:9
|
-warning: not reporting region error due to nll
- --> $DIR/regions-early-bound-error.rs:29:5
- |
-LL | g1.get()
- | ^^^^^^^^
-
error: unsatisfied lifetime constraints
--> $DIR/regions-early-bound-error.rs:29:5
|
-warning: not reporting region error due to nll
- --> $DIR/regions-escape-method.rs:25:13
- |
-LL | s.f(|p| p) //~ ERROR cannot infer
- | ^
-
error: unsatisfied lifetime constraints
--> $DIR/regions-escape-method.rs:25:13
|
-warning: not reporting region error due to nll
- --> $DIR/regions-escape-via-trait-or-not.rs:28:14
- |
-LL | with(|o| o) //~ ERROR cannot infer
- | ^
-
error: unsatisfied lifetime constraints
--> $DIR/regions-escape-via-trait-or-not.rs:28:14
|
-warning: not reporting region error due to nll
- --> $DIR/regions-free-region-ordering-callee.rs:23:5
- |
-LL | &*y //~ ERROR 23:5: 23:8: lifetime mismatch [E0623]
- | ^^^
-
-warning: not reporting region error due to nll
- --> $DIR/regions-free-region-ordering-callee.rs:28:24
- |
-LL | let z: &'b usize = &*x;
- | ^^^
-
error: unsatisfied lifetime constraints
--> $DIR/regions-free-region-ordering-callee.rs:23:5
|
-warning: not reporting region error due to nll
- --> $DIR/regions-free-region-ordering-incorrect.rs:27:15
- |
-LL | None => &self.val //~ ERROR cannot infer
- | ^^^^^^^^^
-
error: unsatisfied lifetime constraints
--> $DIR/regions-free-region-ordering-incorrect.rs:25:5
|
+++ /dev/null
-warning: not reporting region error due to nll
- --> $DIR/regions-glb-free-free.rs:25:13
- |
-LL | Flag { //~ ERROR 25:13: 30:14: explicit lifetime required in the type of `s` [E0621]
- | ^^^^
-
-error[E0621]: explicit lifetime required in the type of `s`
- --> $DIR/regions-glb-free-free.rs:25:13
- |
-LL | pub fn set_desc(self, s: &str) -> Flag<'a> {
- | ---- help: add explicit lifetime `'a` to the type of `s`: `&'a str`
-LL | / Flag { //~ ERROR 25:13: 30:14: explicit lifetime required in the type of `s` [E0621]
-LL | | name: self.name,
-LL | | desc: s,
-LL | | max_count: self.max_count,
-LL | | value: self.value
-LL | | }
- | |_____________^ lifetime `'a` required
-
-error: aborting due to previous error
-
-For more information about this error, try `rustc --explain E0621`.
+++ /dev/null
-warning: not reporting region error due to nll
- --> $DIR/regions-infer-at-fn-not-param.rs:23:57
- |
-LL | fn take1<'a>(p: parameterized1) -> parameterized1<'a> { p }
- | ^
-
-error[E0621]: explicit lifetime required in the type of `p`
- --> $DIR/regions-infer-at-fn-not-param.rs:23:57
- |
-LL | fn take1<'a>(p: parameterized1) -> parameterized1<'a> { p }
- | -------------- ^ lifetime `'a` required
- | |
- | help: add explicit lifetime `'a` to the type of `p`: `parameterized1<'a>`
-
-error: aborting due to previous error
-
-For more information about this error, try `rustc --explain E0621`.
-warning: not reporting region error due to nll
- --> $DIR/regions-infer-bound-from-trait-self.rs:56:9
- |
-LL | check_bound(x, self)
- | ^^^^^^^^^^^
-
error[E0309]: the parameter type `Self` may not live long enough
--> $DIR/regions-infer-bound-from-trait-self.rs:56:9
|
-warning: not reporting region error due to nll
- --> $DIR/regions-infer-bound-from-trait.rs:43:5
- |
-LL | check_bound(x, a) //~ ERROR parameter type `A` may not live long enough
- | ^^^^^^^^^^^
-
-warning: not reporting region error due to nll
- --> $DIR/regions-infer-bound-from-trait.rs:47:5
- |
-LL | check_bound(x, a) //~ ERROR parameter type `A` may not live long enough
- | ^^^^^^^^^^^
-
error[E0309]: the parameter type `A` may not live long enough
--> $DIR/regions-infer-bound-from-trait.rs:43:5
|
-warning: not reporting region error due to nll
- --> $DIR/regions-infer-call-3.rs:18:24
- |
-LL | let z = with(|y| { select(x, y) });
- | ^^^^^^^^^^^^
-
error: unsatisfied lifetime constraints
--> $DIR/regions-infer-call-3.rs:18:24
|
-warning: not reporting region error due to nll
- --> $DIR/regions-infer-invariance-due-to-decl.rs:22:5
- |
-LL | b_isize //~ ERROR mismatched types
- | ^^^^^^^
-
error: unsatisfied lifetime constraints
--> $DIR/regions-infer-invariance-due-to-decl.rs:22:5
|
-warning: not reporting region error due to nll
- --> $DIR/regions-infer-invariance-due-to-mutability-3.rs:21:5
- |
-LL | b_isize //~ ERROR mismatched types
- | ^^^^^^^
-
error: unsatisfied lifetime constraints
--> $DIR/regions-infer-invariance-due-to-mutability-3.rs:21:5
|
-warning: not reporting region error due to nll
- --> $DIR/regions-infer-invariance-due-to-mutability-4.rs:21:5
- |
-LL | b_isize //~ ERROR mismatched types
- | ^^^^^^^
-
error: unsatisfied lifetime constraints
--> $DIR/regions-infer-invariance-due-to-mutability-4.rs:21:5
|
-warning: not reporting region error due to nll
- --> $DIR/regions-infer-not-param.rs:25:54
- |
-LL | fn take_direct<'a,'b>(p: direct<'a>) -> direct<'b> { p } //~ ERROR mismatched types
- | ^
-
-warning: not reporting region error due to nll
- --> $DIR/regions-infer-not-param.rs:29:63
- |
-LL | fn take_indirect2<'a,'b>(p: indirect2<'a>) -> indirect2<'b> { p } //~ ERROR mismatched types
- | ^
-
error: unsatisfied lifetime constraints
--> $DIR/regions-infer-not-param.rs:25:54
|
-warning: not reporting region error due to nll
- --> $DIR/regions-infer-paramd-indirect.rs:33:18
- |
-LL | self.f = b;
- | ^
-
error: borrowed data escapes outside of function
--> $DIR/regions-infer-paramd-indirect.rs:33:9
|
-warning: not reporting region error due to nll
- --> $DIR/regions-lifetime-bounds-on-fns.rs:18:10
- |
-LL | *x = *y; //~ ERROR E0623
- | ^^
-
-warning: not reporting region error due to nll
- --> $DIR/regions-lifetime-bounds-on-fns.rs:24:5
- |
-LL | a(x, y); //~ ERROR 24:7: 24:8: lifetime mismatch [E0623]
- | ^
-
error[E0308]: mismatched types
--> $DIR/regions-lifetime-bounds-on-fns.rs:30:43
|
-warning: not reporting region error due to nll
- --> $DIR/regions-nested-fns.rs:24:27
- |
-LL | if false { return x; } //~ ERROR E0312
- | ^
-
-warning: not reporting region error due to nll
- --> $DIR/regions-nested-fns.rs:15:18
- |
-LL | let mut ay = &y; //~ ERROR E0495
- | ^^
-
error: unsatisfied lifetime constraints
--> $DIR/regions-nested-fns.rs:20:9
|
-warning: not reporting region error due to nll
- --> $DIR/regions-outlives-projection-container-hrtb.rs:42:12
- |
-LL | let _: &'a WithHrAssoc<TheType<'b>> = loop { };
- | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^
-
-warning: not reporting region error due to nll
- --> $DIR/regions-outlives-projection-container-hrtb.rs:63:12
- |
-LL | let _: &'a WithHrAssocSub<TheType<'b>> = loop { };
- | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
-
error: compilation successful
--> $DIR/regions-outlives-projection-container-hrtb.rs:68:1
|
+++ /dev/null
-warning: not reporting region error due to nll
- --> $DIR/regions-proc-bound-capture.rs:19:14
- |
-LL | Box::new(move|| { *x }) //~ ERROR explicit lifetime required in the type of `x` [E0621]
- | ^^^^^^^^^^^^^
-
-error[E0621]: explicit lifetime required in the type of `x`
- --> $DIR/regions-proc-bound-capture.rs:19:5
- |
-LL | fn static_proc(x: &isize) -> Box<FnMut()->(isize) + 'static> {
- | ------ help: add explicit lifetime `'static` to the type of `x`: `&'static isize`
-LL | // This is illegal, because the region bound on `proc` is 'static.
-LL | Box::new(move|| { *x }) //~ ERROR explicit lifetime required in the type of `x` [E0621]
- | ^^^^^^^^^^^^^^^^^^^^^^^ lifetime `'static` required
-
-error: aborting due to previous error
-
-For more information about this error, try `rustc --explain E0621`.
-warning: not reporting region error due to nll
- --> $DIR/regions-reborrow-from-shorter-mut-ref-mut-ref.rs:14:5
- |
-LL | &mut ***p //~ ERROR 14:5: 14:14: lifetime mismatch [E0623]
- | ^^^^^^^^^
-
error: unsatisfied lifetime constraints
--> $DIR/regions-reborrow-from-shorter-mut-ref-mut-ref.rs:14:5
|
-warning: not reporting region error due to nll
- --> $DIR/regions-reborrow-from-shorter-mut-ref.rs:16:5
- |
-LL | &mut **p //~ ERROR 16:5: 16:13: lifetime mismatch [E0623]
- | ^^^^^^^^
-
error: unsatisfied lifetime constraints
--> $DIR/regions-reborrow-from-shorter-mut-ref.rs:16:5
|
-warning: not reporting region error due to nll
- --> $DIR/regions-ret-borrowed-1.rs:20:14
- |
-LL | with(|o| o)
- | ^
-
error: unsatisfied lifetime constraints
--> $DIR/regions-ret-borrowed-1.rs:20:14
|
-warning: not reporting region error due to nll
- --> $DIR/regions-ret-borrowed.rs:23:14
- |
-LL | with(|o| o)
- | ^
-
error: unsatisfied lifetime constraints
--> $DIR/regions-ret-borrowed.rs:23:14
|
-warning: not reporting region error due to nll
- --> $DIR/regions-return-ref-to-upvar-issue-17403.rs:17:24
- |
-LL | let mut f = || &mut x; //~ ERROR cannot infer
- | ^^^^^^
-
error: unsatisfied lifetime constraints
--> $DIR/regions-return-ref-to-upvar-issue-17403.rs:17:24
|
-warning: not reporting region error due to nll
- --> $DIR/regions-static-bound.rs:19:5
- |
-LL | t //[ll]~ ERROR E0312
- | ^
-
-warning: not reporting region error due to nll
- --> $DIR/regions-static-bound.rs:25:5
- |
-LL | static_id(&u); //[ll]~ ERROR explicit lifetime required in the type of `u` [E0621]
- | ^^^^^^^^^
-
-warning: not reporting region error due to nll
- --> $DIR/regions-static-bound.rs:28:5
- |
-LL | static_id_indirect(&v); //[ll]~ ERROR explicit lifetime required in the type of `v` [E0621]
- | ^^^^^^^^^^^^^^^^^^
-
error: unsatisfied lifetime constraints
--> $DIR/regions-static-bound.rs:19:5
|
| ^ returning this value requires that `'a` must outlive `'static`
error[E0621]: explicit lifetime required in the type of `u`
- --> $DIR/regions-static-bound.rs:25:5
+ --> $DIR/regions-static-bound.rs:24:5
|
LL | fn error(u: &(), v: &()) {
| --- help: add explicit lifetime `'static` to the type of `u`: `&'static ()`
| ^^^^^^^^^^^^^ lifetime `'static` required
error[E0621]: explicit lifetime required in the type of `v`
- --> $DIR/regions-static-bound.rs:28:5
+ --> $DIR/regions-static-bound.rs:26:5
|
LL | fn error(u: &(), v: &()) {
| --- help: add explicit lifetime `'static` to the type of `v`: `&'static ()`
| ^^
error[E0621]: explicit lifetime required in the type of `u`
- --> $DIR/regions-static-bound.rs:25:5
+ --> $DIR/regions-static-bound.rs:24:5
|
LL | fn error(u: &(), v: &()) {
| --- help: add explicit lifetime `'static` to the type of `u`: `&'static ()`
| ^^^^^^^^^ lifetime `'static` required
error[E0621]: explicit lifetime required in the type of `v`
- --> $DIR/regions-static-bound.rs:28:5
+ --> $DIR/regions-static-bound.rs:26:5
|
LL | fn error(u: &(), v: &()) {
| --- help: add explicit lifetime `'static` to the type of `v`: `&'static ()`
-warning: not reporting region error due to nll
- --> $DIR/regions-static-bound.rs:19:5
- |
-LL | t //[ll]~ ERROR E0312
- | ^
-
-warning: not reporting region error due to nll
- --> $DIR/regions-static-bound.rs:25:5
- |
-LL | static_id(&u); //[ll]~ ERROR explicit lifetime required in the type of `u` [E0621]
- | ^^^^^^^^^
-
-warning: not reporting region error due to nll
- --> $DIR/regions-static-bound.rs:28:5
- |
-LL | static_id_indirect(&v); //[ll]~ ERROR explicit lifetime required in the type of `v` [E0621]
- | ^^^^^^^^^^^^^^^^^^
-
error: unsatisfied lifetime constraints
--> $DIR/regions-static-bound.rs:19:5
|
| ^ returning this value requires that `'a` must outlive `'static`
error[E0621]: explicit lifetime required in the type of `u`
- --> $DIR/regions-static-bound.rs:25:5
+ --> $DIR/regions-static-bound.rs:24:5
|
LL | fn error(u: &(), v: &()) {
| --- help: add explicit lifetime `'static` to the type of `u`: `&'static ()`
| ^^^^^^^^^^^^^ lifetime `'static` required
error[E0621]: explicit lifetime required in the type of `v`
- --> $DIR/regions-static-bound.rs:28:5
+ --> $DIR/regions-static-bound.rs:26:5
|
LL | fn error(u: &(), v: &()) {
| --- help: add explicit lifetime `'static` to the type of `v`: `&'static ()`
where 'a: 'b, 'b: 'static { t }
fn static_id_wrong_way<'a>(t: &'a ()) -> &'static () where 'static: 'a {
t //[ll]~ ERROR E0312
- //[nll]~^ WARNING not reporting region error due to nll
- //[nll]~| ERROR unsatisfied lifetime constraints
+ //[nll]~^ ERROR unsatisfied lifetime constraints
}
fn error(u: &(), v: &()) {
static_id(&u); //[ll]~ ERROR explicit lifetime required in the type of `u` [E0621]
- //[nll]~^ WARNING not reporting region error due to nll
- //[nll]~| ERROR explicit lifetime required in the type of `u` [E0621]
+ //[nll]~^ ERROR explicit lifetime required in the type of `u` [E0621]
static_id_indirect(&v); //[ll]~ ERROR explicit lifetime required in the type of `v` [E0621]
- //[nll]~^ WARNING not reporting region error due to nll
- //[nll]~| ERROR explicit lifetime required in the type of `v` [E0621]
+ //[nll]~^ ERROR explicit lifetime required in the type of `v` [E0621]
}
fn main() {}
-warning: not reporting region error due to nll
- --> $DIR/regions-trait-object-subtyping.rs:25:5
- |
-LL | x //~ ERROR lifetime bound not satisfied
- | ^
-
-warning: not reporting region error due to nll
- --> $DIR/regions-trait-object-subtyping.rs:32:5
- |
-LL | x //~ ERROR mismatched types
- | ^
-
error: unsatisfied lifetime constraints
--> $DIR/regions-trait-object-subtyping.rs:25:5
|
#[repr(transparent)] //~ ERROR should be applied to struct
static CANT_REPR_THIS: u32 = 0;
+
+fn main() {}
-error[E0601]: `main` function not found in crate `repr_transparent_other_items`
- |
- = note: consider adding a `main` function to `$DIR/repr-transparent-other-items.rs`
-
error[E0517]: attribute should be applied to struct
--> $DIR/repr-transparent-other-items.rs:13:8
|
LL | enum Void {} //~| ERROR should be applied to struct
| ------------ zero-variant enum
-error: aborting due to 8 previous errors
+error: aborting due to 7 previous errors
-Some errors occurred: E0084, E0517, E0601.
+Some errors occurred: E0084, E0517.
For more information about an error, try `rustc --explain E0084`.
#[repr(transparent)] //~ ERROR cannot have other repr
#[repr(C)]
struct SeparateAttributes(*mut u8);
+
+fn main() {}
-error[E0601]: `main` function not found in crate `repr_transparent_other_reprs`
- |
- = note: consider adding a `main` function to `$DIR/repr-transparent-other-reprs.rs`
-
error[E0692]: transparent struct cannot have other repr hints
--> $DIR/repr-transparent-other-reprs.rs:15:8
|
LL | #[repr(C)]
| ^
-error: aborting due to 5 previous errors
+error: aborting due to 4 previous errors
-Some errors occurred: E0601, E0692.
-For more information about an error, try `rustc --explain E0601`.
+For more information about this error, try `rustc --explain E0692`.
#[repr(transparent)]
struct GenericAlign<T>(ZstAlign32<T>, u32); //~ ERROR alignment larger than 1
+
+fn main() {}
-error[E0601]: `main` function not found in crate `repr_transparent`
- |
- = note: consider adding a `main` function to `$DIR/repr-transparent.rs`
-
error[E0690]: transparent struct needs exactly one non-zero-sized field, but has 0
--> $DIR/repr-transparent.rs:21:1
|
LL | struct GenericAlign<T>(ZstAlign32<T>, u32); //~ ERROR alignment larger than 1
| ^^^^^^^^^^^^^
-error: aborting due to 9 previous errors
+error: aborting due to 8 previous errors
-Some errors occurred: E0601, E0690, E0691.
-For more information about an error, try `rustc --explain E0601`.
+Some errors occurred: E0690, E0691.
+For more information about an error, try `rustc --explain E0690`.
fn f<T:SomeNonExistentTrait>() {}
//~^ ERROR cannot find trait `SomeNonExistentTrait` in this scope
+
+fn main() {}
LL | fn f<T:SomeNonExistentTrait>() {}
| ^^^^^^^^^^^^^^^^^^^^ not found in this scope
-error[E0601]: `main` function not found in crate `resolve_unknown_trait`
- |
- = note: consider adding a `main` function to `$DIR/resolve-unknown-trait.rs`
-
-error: aborting due to 4 previous errors
+error: aborting due to 3 previous errors
-Some errors occurred: E0405, E0601.
-For more information about an error, try `rustc --explain E0405`.
+For more information about this error, try `rustc --explain E0405`.
LL | use alloc::HashMap;
| ^^^^^ Did you mean `a::alloc`?
-error[E0601]: `main` function not found in crate `resolve_self_super_hint`
- |
- = note: consider adding a `main` function to `$DIR/resolve_self_super_hint.rs`
-
-error: aborting due to 5 previous errors
+error: aborting due to 4 previous errors
-Some errors occurred: E0432, E0601.
-For more information about an error, try `rustc --explain E0432`.
+For more information about this error, try `rustc --explain E0432`.
| |_^ `main` can only return types that implement `std::process::Termination`
|
= help: the trait `std::process::Termination` is not implemented for `std::result::Result<f32, std::num::ParseIntError>`
- = note: required by `__test::test::assert_test_result`
+ = note: required by `test::assert_test_result`
error: aborting due to previous error
+++ /dev/null
-// Copyright 2018 The Rust Project Developers. See the COPYRIGHT
-// file at the top-level directory of this distribution and at
-// http://rust-lang.org/COPYRIGHT.
-//
-// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
-// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
-// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
-// option. This file may not be copied, modified, or distributed
-// except according to those terms.
-
-// edition:2018
-
-#![feature(uniform_paths)]
-
-use std;
-
-fn main() {}
+++ /dev/null
-error: `std` import is redundant
- --> $DIR/redundant.rs:15:5
- |
-LL | use std;
- | ^^^
- | |
- | refers to external crate `::std`
- | defines `self::std`, shadowing itself
- |
- = help: remove or write `::std` explicitly instead
- = note: relative `use` paths enabled by `#![feature(uniform_paths)]`
-
-error: aborting due to previous error
-
trait Tr {}
default impl !Tr for S {} //~ ERROR negative impls are only allowed for auto traits
+
+fn main() {}
|
= note: only trait implementations may be annotated with default
-error[E0601]: `main` function not found in crate `validation`
- |
- = note: consider adding a `main` function to `$DIR/validation.rs`
-
error: impls of auto traits cannot be default
--> $DIR/validation.rs:19:1
|
LL | default impl !Tr for S {} //~ ERROR negative impls are only allowed for auto traits
| ^^^^^^^^^^^^^^^^^^^^^^^^^
-error: aborting due to 5 previous errors
+error: aborting due to 4 previous errors
-Some errors occurred: E0192, E0601.
-For more information about an error, try `rustc --explain E0192`.
+For more information about this error, try `rustc --explain E0192`.
--- /dev/null
+// Copyright 2018 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+// compile-pass
+// compile-flags:--test
+
+#![deny(warnings)]
+
+macro_rules! foo {
+ () => (fn foo(){})
+}
+
+#[test]
+foo!();
+
+fn main(){}
--- /dev/null
+warning: #[test] attribute should not be used on macros. Use #[cfg(test)] instead.
+ --> $DIR/test-on-macro.rs:21:1
+ |
+LL | foo!();
+ | ^^^^^^^
+
--- /dev/null
+// Copyright 2018 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+#[macro_export]
+macro_rules! test {
+ () => {};
+}
--- /dev/null
+// Copyright 2018 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+// compile-pass
+// aux-build:test_macro.rs
+// compile-flags:--test
+
+#[macro_use] extern crate test_macro;
+
+#[test]
+fn foo(){}
//~^ ERROR expected one of `)` or `,`, found `(`
//~| ERROR cannot find type `foo` in this scope
}
+
+fn main() {}
LL | struct S2(pub((foo)) ());
| ^^^ not found in this scope
-error[E0601]: `main` function not found in crate `test`
- |
- = note: consider adding a `main` function to `$DIR/test.rs`
-
-error: aborting due to 3 previous errors
+error: aborting due to 2 previous errors
-Some errors occurred: E0412, E0601.
-For more information about an error, try `rustc --explain E0412`.
+For more information about this error, try `rustc --explain E0412`.
-warning: not reporting region error due to nll
- --> $DIR/unboxed-closures-infer-argument-types-two-region-pointers.rs:27:15
- |
-LL | x.set(y); //~ ERROR E0312
- | ^
-
error: unsatisfied lifetime constraints
--> $DIR/unboxed-closures-infer-argument-types-two-region-pointers.rs:27:9
|
-warning: not reporting region error due to nll
- --> $DIR/dyn-trait-underscore.rs:18:14
- |
-LL | Box::new(items.iter()) //~ ERROR cannot infer an appropriate lifetime
- | ^^^^^
-
-warning: not reporting region error due to nll
- --> $DIR/dyn-trait-underscore.rs:18:20
- |
-LL | Box::new(items.iter()) //~ ERROR cannot infer an appropriate lifetime
- | ^^^^
-
-warning: not reporting region error due to nll
- --> $DIR/dyn-trait-underscore.rs:18:5
- |
-LL | Box::new(items.iter()) //~ ERROR cannot infer an appropriate lifetime
- | ^^^^^^^^
-
-warning: not reporting region error due to nll
- --> $DIR/dyn-trait-underscore.rs:18:5
- |
-LL | Box::new(items.iter()) //~ ERROR cannot infer an appropriate lifetime
- | ^^^^^^^^^^^^^^^^^^^^^^
-
error: unsatisfied lifetime constraints
--> $DIR/dyn-trait-underscore.rs:18:5
|
-warning: not reporting region error due to nll
- --> $DIR/underscore-lifetime-elison-mismatch.rs:11:49
- |
-LL | fn foo(x: &mut Vec<&'_ u8>, y: &'_ u8) { x.push(y); } //~ ERROR lifetime mismatch
- | ^
-
error: unsatisfied lifetime constraints
--> $DIR/underscore-lifetime-elison-mismatch.rs:11:42
|
fn item() {}
}
+
+fn main() {}
LL | use Enum::*; //~ ERROR unresolved import `Enum` [E0432]
| ^^^^ Did you mean `self::Enum`?
-error[E0601]: `main` function not found in crate `unresolved_import`
- |
- = note: consider adding a `main` function to `$DIR/unresolved-import.rs`
-
-error: aborting due to 7 previous errors
+error: aborting due to 6 previous errors
-Some errors occurred: E0432, E0601.
-For more information about an error, try `rustc --explain E0432`.
+For more information about this error, try `rustc --explain E0432`.
// A quick test of 'unsafe const fn' functionality
-#![feature(const_fn)]
+#![feature(min_const_fn)]
const unsafe fn dummy(v: u32) -> u32 {
!v
#![allow(unused_macros)]
macro_rules! macro_rules { () => {} } //~ ERROR user-defined macros may not be named `macro_rules`
+
+fn main() {}
LL | macro_rules! macro_rules { () => {} } //~ ERROR user-defined macros may not be named `macro_rules`
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
-error[E0601]: `main` function not found in crate `user_defined_macro_rules`
- |
- = note: consider adding a `main` function to `$DIR/user-defined-macro-rules.rs`
-
-error: aborting due to 2 previous errors
+error: aborting due to previous error
-For more information about this error, try `rustc --explain E0601`.
-warning: not reporting region error due to nll
- --> $DIR/variance-btree-invariant-types.rs:16:5
- |
-LL | v //~ ERROR mismatched types
- | ^
-
-warning: not reporting region error due to nll
- --> $DIR/variance-btree-invariant-types.rs:19:5
- |
-LL | v //~ ERROR mismatched types
- | ^
-
-warning: not reporting region error due to nll
- --> $DIR/variance-btree-invariant-types.rs:22:5
- |
-LL | v //~ ERROR mismatched types
- | ^
-
-warning: not reporting region error due to nll
- --> $DIR/variance-btree-invariant-types.rs:25:5
- |
-LL | v //~ ERROR mismatched types
- | ^
-
-warning: not reporting region error due to nll
- --> $DIR/variance-btree-invariant-types.rs:30:5
- |
-LL | v //~ ERROR mismatched types
- | ^
-
-warning: not reporting region error due to nll
- --> $DIR/variance-btree-invariant-types.rs:34:5
- |
-LL | v //~ ERROR mismatched types
- | ^
-
-warning: not reporting region error due to nll
- --> $DIR/variance-btree-invariant-types.rs:38:5
- |
-LL | v //~ ERROR mismatched types
- | ^
-
-warning: not reporting region error due to nll
- --> $DIR/variance-btree-invariant-types.rs:42:5
- |
-LL | v //~ ERROR mismatched types
- | ^
-
-warning: not reporting region error due to nll
- --> $DIR/variance-btree-invariant-types.rs:47:5
- |
-LL | v //~ ERROR mismatched types
- | ^
-
-warning: not reporting region error due to nll
- --> $DIR/variance-btree-invariant-types.rs:51:5
- |
-LL | v //~ ERROR mismatched types
- | ^
-
-warning: not reporting region error due to nll
- --> $DIR/variance-btree-invariant-types.rs:55:5
- |
-LL | v //~ ERROR mismatched types
- | ^
-
-warning: not reporting region error due to nll
- --> $DIR/variance-btree-invariant-types.rs:59:5
- |
-LL | v //~ ERROR mismatched types
- | ^
-
error: unsatisfied lifetime constraints
--> $DIR/variance-btree-invariant-types.rs:16:5
|
-warning: not reporting region error due to nll
- --> $DIR/variance-contravariant-arg-object.rs:24:5
- |
-LL | v //~ ERROR mismatched types
- | ^
-
-warning: not reporting region error due to nll
- --> $DIR/variance-contravariant-arg-object.rs:32:5
- |
-LL | v //~ ERROR mismatched types
- | ^
-
error: unsatisfied lifetime constraints
--> $DIR/variance-contravariant-arg-object.rs:24:5
|
-warning: not reporting region error due to nll
- --> $DIR/variance-covariant-arg-object.rs:25:5
- |
-LL | v //~ ERROR mismatched types
- | ^
-
-warning: not reporting region error due to nll
- --> $DIR/variance-covariant-arg-object.rs:32:5
- |
-LL | v //~ ERROR mismatched types
- | ^
-
error: unsatisfied lifetime constraints
--> $DIR/variance-covariant-arg-object.rs:25:5
|
-warning: not reporting region error due to nll
- --> $DIR/variance-invariant-arg-object.rs:21:5
- |
-LL | v //~ ERROR mismatched types
- | ^
-
-warning: not reporting region error due to nll
- --> $DIR/variance-invariant-arg-object.rs:28:5
- |
-LL | v //~ ERROR mismatched types
- | ^
-
error: unsatisfied lifetime constraints
--> $DIR/variance-invariant-arg-object.rs:21:5
|
-warning: not reporting region error due to nll
- --> $DIR/variance-trait-matching.rs:34:10
- |
-LL | pick(get, &22) //~ ERROR 34:5: 34:9: explicit lifetime required in the type of `get` [E0621]
- | ^^^
-
-warning: not reporting region error due to nll
- --> $DIR/variance-trait-matching.rs:34:5
- |
-LL | pick(get, &22) //~ ERROR 34:5: 34:9: explicit lifetime required in the type of `get` [E0621]
- | ^^^^^^^^^^^^^^
-
-warning: not reporting region error due to nll
- --> $DIR/variance-trait-matching.rs:34:5
- |
-LL | pick(get, &22) //~ ERROR 34:5: 34:9: explicit lifetime required in the type of `get` [E0621]
- | ^^^^
-
error[E0621]: explicit lifetime required in the type of `get`
--> $DIR/variance-trait-matching.rs:34:5
|
-warning: not reporting region error due to nll
- --> $DIR/variance-use-contravariant-struct-1.rs:22:5
- |
-LL | v //~ ERROR mismatched types
- | ^
-
error: unsatisfied lifetime constraints
--> $DIR/variance-use-contravariant-struct-1.rs:22:5
|
-warning: not reporting region error due to nll
- --> $DIR/variance-use-covariant-struct-1.rs:20:5
- |
-LL | v //~ ERROR mismatched types
- | ^
-
error: unsatisfied lifetime constraints
--> $DIR/variance-use-covariant-struct-1.rs:20:5
|
-warning: not reporting region error due to nll
- --> $DIR/variance-use-invariant-struct-1.rs:22:5
- |
-LL | v //~ ERROR mismatched types
- | ^
-
-warning: not reporting region error due to nll
- --> $DIR/variance-use-invariant-struct-1.rs:29:5
- |
-LL | v //~ ERROR mismatched types
- | ^
-
error: unsatisfied lifetime constraints
--> $DIR/variance-use-invariant-struct-1.rs:22:5
|
#[link_section = "test"]
pub static D: &usize = &C; //~ ERROR: no extra levels of indirection
+
+fn main() {}
-error[E0601]: `main` function not found in crate `wasm_custom_section_relocations`
- |
- = note: consider adding a `main` function to `$DIR/wasm-custom-section-relocations.rs`
-
error: statics with a custom `#[link_section]` must be a simple list of bytes on the wasm target with no extra levels of indirection such as references
--> $DIR/wasm-custom-section-relocations.rs:14:1
|
LL | pub static D: &usize = &C; //~ ERROR: no extra levels of indirection
| ^^^^^^^^^^^^^^^^^^^^^^^^^^
-error: aborting due to 3 previous errors
+error: aborting due to 2 previous errors
-For more information about this error, try `rustc --explain E0601`.
// Test that we check where-clauses on fn items.
-#![feature(associated_type_defaults)]
#![feature(rustc_attrs)]
#![allow(dead_code)]
{
}
+fn bar() where Vec<dyn Copy>:, {}
+//~^ ERROR E0277
+//~| ERROR E0038
+
#[rustc_error]
fn main() { }
error[E0277]: the trait bound `U: std::marker::Copy` is not satisfied
- --> $DIR/wf-fn-where-clause.rs:19:1
+ --> $DIR/wf-fn-where-clause.rs:18:1
|
LL | / fn foo<T,U>() where T: ExtraCopy<U> //~ ERROR E0277
LL | | {
|
= help: consider adding a `where U: std::marker::Copy` bound
note: required by `ExtraCopy`
- --> $DIR/wf-fn-where-clause.rs:17:1
+ --> $DIR/wf-fn-where-clause.rs:16:1
|
LL | trait ExtraCopy<T:Copy> { }
| ^^^^^^^^^^^^^^^^^^^^^^^
-error: aborting due to previous error
+error[E0277]: the size for values of type `(dyn std::marker::Copy + 'static)` cannot be known at compilation time
+ --> $DIR/wf-fn-where-clause.rs:22:1
+ |
+LL | fn bar() where Vec<dyn Copy>:, {}
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ doesn't have a size known at compile-time
+ |
+ = help: the trait `std::marker::Sized` is not implemented for `(dyn std::marker::Copy + 'static)`
+ = note: to learn more, visit <https://doc.rust-lang.org/book/second-edition/ch19-04-advanced-types.html#dynamically-sized-types-and-the-sized-trait>
+ = note: required by `std::vec::Vec`
+
+error[E0038]: the trait `std::marker::Copy` cannot be made into an object
+ --> $DIR/wf-fn-where-clause.rs:22:1
+ |
+LL | fn bar() where Vec<dyn Copy>:, {}
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ the trait `std::marker::Copy` cannot be made into an object
+ |
+ = note: the trait cannot require that `Self : Sized`
+
+error: aborting due to 3 previous errors
-For more information about this error, try `rustc --explain E0277`.
+Some errors occurred: E0038, E0277.
+For more information about an error, try `rustc --explain E0038`.
-warning: not reporting region error due to nll
- --> $DIR/wf-static-method.rs:27:9
- |
-LL | u //~ ERROR E0312
- | ^
-
-warning: not reporting region error due to nll
- --> $DIR/wf-static-method.rs:36:18
- |
-LL | let me = Self::make_me(); //~ ERROR lifetime bound not satisfied
- | ^^^^^^^^^^^^^
-
-warning: not reporting region error due to nll
- --> $DIR/wf-static-method.rs:43:9
- |
-LL | u //~ ERROR E0312
- | ^
-
-warning: not reporting region error due to nll
- --> $DIR/wf-static-method.rs:51:5
- |
-LL | <()>::static_evil(b) //~ ERROR cannot infer an appropriate lifetime
- | ^^^^^^^^^^^^^^^^^
-
-warning: not reporting region error due to nll
- --> $DIR/wf-static-method.rs:55:5
- |
-LL | <IndirectEvil>::static_evil(b)
- | ^^^^^^^^^^^^^^^^^^^^^^^^^^^
-
error: unsatisfied lifetime constraints
--> $DIR/wf-static-method.rs:27:9
|
--- /dev/null
+# build-manifest
+
+This tool generates the manifests uploaded to static.rust-lang.org and used by
+rustup. The tool is invoked by the bootstrap tool.
+
+## Testing changes locally
+
+In order to test the changes locally you need to have a valid dist directory
+available locally. If you don't want to build all the compiler, you can easily
+create one from the nightly artifacts with:
+
+```
+#!/bin/bash
+for cmpn in rust rustc rust-std rust-docs cargo; do
+ wget https://static.rust-lang.org/dist/${cmpn}-nightly-x86_64-unknown-linux-gnu.tar.gz
+done
+```
+
+Then, you can generate the manifest and all the packages from `path/to/dist` to
+`path/to/output` with:
+
+```
+$ BUILD_MANIFEST_DISABLE_SIGNING=1 cargo +nightly run \
+ path/to/dist path/to/output 1970-01-01 \
+ nightly nightly nightly nightly nightly nightly nightly \
+ http://example.com
+```
+
+In the future, if the tool complains about missing arguments just add more
+`nightly`s in the middle.
"powerpc64-unknown-linux-gnu",
"powerpc64le-unknown-linux-gnu",
"powerpc64le-unknown-linux-musl",
+ "riscv32imc-unknown-none-elf",
"riscv32imac-unknown-none-elf",
"s390x-unknown-linux-gnu",
"sparc-unknown-linux-gnu",
"x86_64-unknown-redox",
];
+static DOCS_TARGETS: &'static [&'static str] = &[
+ "i686-apple-darwin",
+ "i686-pc-windows-gnu",
+ "i686-pc-windows-msvc",
+ "i686-unknown-linux-gnu",
+ "x86_64-apple-darwin",
+ "x86_64-pc-windows-gnu",
+ "x86_64-pc-windows-msvc",
+ "x86_64-unknown-linux-gnu",
+];
+
static MINGW: &'static [&'static str] = &[
"i686-pc-windows-gnu",
"x86_64-pc-windows-gnu",
rustfmt_git_commit_hash: Option<String>,
llvm_tools_git_commit_hash: Option<String>,
lldb_git_commit_hash: Option<String>,
+
+ should_sign: bool,
}
fn main() {
+ // Avoid signing packages while manually testing
+ // Do NOT set this envvar in CI
+ let should_sign = env::var("BUILD_MANIFEST_DISABLE_SIGNING").is_err();
+
+ // Safety check to ensure signing is always enabled on CI
+ // The CI environment variable is set by both Travis and AppVeyor
+ if !should_sign && env::var("CI").is_ok() {
+ println!("The 'BUILD_MANIFEST_DISABLE_SIGNING' env var can't be enabled on CI.");
+ println!("If you're not running this on CI, unset the 'CI' env var.");
+ panic!();
+ }
+
let mut args = env::args().skip(1);
let input = PathBuf::from(args.next().unwrap());
let output = PathBuf::from(args.next().unwrap());
let llvm_tools_release = args.next().unwrap();
let lldb_release = args.next().unwrap();
let s3_address = args.next().unwrap();
+
+ // Do not ask for a passphrase while manually testing
let mut passphrase = String::new();
- t!(io::stdin().read_to_string(&mut passphrase));
+ if should_sign {
+ t!(io::stdin().read_to_string(&mut passphrase));
+ }
Builder {
rust_release,
rustfmt_git_commit_hash: None,
llvm_tools_git_commit_hash: None,
lldb_git_commit_hash: None,
+
+ should_sign,
}.build();
}
self.package("cargo", &mut manifest.pkg, HOSTS);
self.package("rust-mingw", &mut manifest.pkg, MINGW);
self.package("rust-std", &mut manifest.pkg, TARGETS);
- self.package("rust-docs", &mut manifest.pkg, TARGETS);
+ self.package("rust-docs", &mut manifest.pkg, DOCS_TARGETS);
self.package("rust-src", &mut manifest.pkg, &["*"]);
self.package("rls-preview", &mut manifest.pkg, HOSTS);
self.package("clippy-preview", &mut manifest.pkg, HOSTS);
Some(p) => p,
None => return false,
};
- let target = match pkg.target.get(&c.target) {
- Some(t) => t,
- None => return false,
- };
- target.available
+ pkg.target.get(&c.target).is_some()
};
extensions.retain(&has_component);
components.retain(&has_component);
}
fn sign(&self, path: &Path) {
+ if !self.should_sign {
+ return;
+ }
+
let filename = path.file_name().unwrap().to_str().unwrap();
let asc = self.output.join(format!("{}.asc", filename));
println!("signing: {:?}", path);
-Subproject commit 2a284a70e26997273c296afe06586ffdf3a142fd
+Subproject commit d0fc1788123de9844c8088b977cd142021cea1f2
-Subproject commit d99cea0f16633556871a59500c610782b07233b9
+Subproject commit 131c8f86b2b712d4d9b00f486b6c67f97782228a
filetime = "0.2"
getopts = "0.2"
log = "0.4"
-regex = "0.2"
+regex = "1.0"
serde = "1.0"
serde_json = "1.0"
serde_derive = "1.0"
-Subproject commit 813b3b952c07b6b85732c3fbdf3eb74f61a9fa96
+Subproject commit 2a9b88b8b419d094fb2185c0ca31c28d31bdca00
-Subproject commit 3dbe998969d457c5cef245f61b48bdaed0f5c059
+Subproject commit 7728fa22bebea288abfea3b70cf795c60b93df3a
-Subproject commit e67fd48f1aa2a31daee70dc3e80621077a31c52d
+Subproject commit cf6358a00540a83dcc6e8c243f3306ccdbb9c354
-Subproject commit 5c9a2b6c13d3b6f8d3f9c02b130bb4b54fd489fb
+Subproject commit 1c408818c8a752dd584e7858b4afd3ceb011a7da
Crate("kernel32-sys"),
Crate("lazy_static"),
Crate("libc"),
+ Crate("lock_api"),
Crate("log"),
Crate("log_settings"),
Crate("memchr"),
+ Crate("memmap"),
Crate("memoffset"),
Crate("miniz-sys"),
Crate("nodrop"),
Crate("owning_ref"),
Crate("parking_lot"),
Crate("parking_lot_core"),
- Crate("polonius-engine"),
Crate("pkg-config"),
+ Crate("polonius-engine"),
Crate("quick-error"),
Crate("rand"),
Crate("rand_core"),
Crate("winapi"),
Crate("winapi-build"),
Crate("winapi-i686-pc-windows-gnu"),
+ Crate("winapi-util"),
Crate("winapi-x86_64-pc-windows-gnu"),
Crate("wincolor"),
];