Auto merge of #67084 - Pagten:feature/print-msg-from-elf-entrypoint, r=Amanieu
SGX: Change ELF entrypoint
This fixes [rust-sgx issue #148](https://github.com/fortanix/rust-sgx/issues/148).
A new entry point is created for the ELF file generated by `rustc`, separate from the enclave entry point. When the ELF file is executed as a Linux binary, the error message below is written to stderr.
> Error: This file is an SGX enclave which cannot be executed as a standard Linux binary.
> See the installation guide at https://edp.fortanix.com/docs/installation/guide/ on how to use 'cargo run' or follow the steps at https://edp.fortanix.com/docs/tasks/deployment/ for manual deployment.
When the ELF file is converted to an SGXS using `elf2sgxs`, the old entry point is still set as the enclave entry point. In a future pull request in the rust-sgx repository, `elf2sgxs` will be modified to remove the code in the ELF entry point, since this code is not needed in the enclave.
diff --git a/Cargo.lock b/Cargo.lock
index 5e83513..1af0442 100644
--- a/Cargo.lock
+++ b/Cargo.lock
@@ -570,9 +570,9 @@
[[package]]
name = "compiler_builtins"
-version = "0.1.18"
+version = "0.1.22"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "ef1c086a06d6f52f9c0d50cacdc021bfb6034ddeec9fb7e62f099f13f65472f4"
+checksum = "e6f083abf9bb9005a27d2da62706f661245278cb7096da37ab27410eaf60f2c1"
dependencies = [
"cc",
"rustc-std-workspace-core",
@@ -726,21 +726,11 @@
[[package]]
name = "crossbeam-deque"
-version = "0.2.0"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "f739f8c5363aca78cfb059edf753d8f0d36908c348f3d8d1503f03d8b75d9cf3"
-dependencies = [
- "crossbeam-epoch 0.3.1",
- "crossbeam-utils 0.2.2",
-]
-
-[[package]]
-name = "crossbeam-deque"
version = "0.6.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "05e44b8cf3e1a625844d1750e1f7820da46044ff6d28f4d43e455ba3e5bb2c13"
dependencies = [
- "crossbeam-epoch 0.7.2",
+ "crossbeam-epoch",
"crossbeam-utils 0.6.5",
]
@@ -750,27 +740,12 @@
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "b18cd2e169ad86297e6bc0ad9aa679aee9daa4f19e8163860faf7c164e4f5a71"
dependencies = [
- "crossbeam-epoch 0.7.2",
+ "crossbeam-epoch",
"crossbeam-utils 0.6.5",
]
[[package]]
name = "crossbeam-epoch"
-version = "0.3.1"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "927121f5407de9956180ff5e936fe3cf4324279280001cd56b669d28ee7e9150"
-dependencies = [
- "arrayvec",
- "cfg-if",
- "crossbeam-utils 0.2.2",
- "lazy_static 1.3.0",
- "memoffset 0.2.1",
- "nodrop",
- "scopeguard 0.3.3",
-]
-
-[[package]]
-name = "crossbeam-epoch"
version = "0.7.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "fedcd6772e37f3da2a9af9bf12ebe046c0dfe657992377b4df982a2b54cd37a9"
@@ -779,7 +754,7 @@
"cfg-if",
"crossbeam-utils 0.6.5",
"lazy_static 1.3.0",
- "memoffset 0.5.1",
+ "memoffset",
"scopeguard 1.0.0",
]
@@ -794,15 +769,6 @@
[[package]]
name = "crossbeam-utils"
-version = "0.2.2"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "2760899e32a1d58d5abb31129f8fae5de75220bc2176e77ff7c627ae45c918d9"
-dependencies = [
- "cfg-if",
-]
-
-[[package]]
-name = "crossbeam-utils"
version = "0.6.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "f8306fcef4a7b563b76b7dd949ca48f52bc1141aa067d2ea09565f3e2652aa5c"
@@ -1456,7 +1422,7 @@
"markup5ever",
"proc-macro2 1.0.3",
"quote 1.0.2",
- "syn 1.0.5",
+ "syn 1.0.11",
]
[[package]]
@@ -2055,12 +2021,13 @@
[[package]]
name = "measureme"
-version = "0.4.0"
+version = "0.5.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "cd21b0e6e1af976b269ce062038fe5e1b9ca2f817ab7a3af09ec4210aebf0d30"
+checksum = "c420bbc064623934620b5ab2dc0cf96451b34163329e82f95e7fa1b7b99a6ac8"
dependencies = [
"byteorder",
"memmap",
+ "parking_lot 0.9.0",
"rustc-hash",
]
@@ -2072,9 +2039,9 @@
[[package]]
name = "memmap"
-version = "0.6.2"
+version = "0.7.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "e2ffa2c986de11a9df78620c01eeaaf27d94d3ff02bf81bfcca953102dd0c6ff"
+checksum = "6585fd95e7bb50d6cc31e20d4cf9afb4e2ba16c5846fc76793f11218da9c475b"
dependencies = [
"libc",
"winapi 0.3.8",
@@ -2082,12 +2049,6 @@
[[package]]
name = "memoffset"
-version = "0.2.1"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "0f9dc261e2b62d7a622bf416ea3c5245cdd5d9a7fcc428c0d06804dfce1775b3"
-
-[[package]]
-name = "memoffset"
version = "0.5.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "ce6075db033bbbb7ee5a0bbd3a3186bbae616f57fb001c485c7ff77955f8177f"
@@ -2213,6 +2174,7 @@
"rand 0.7.0",
"rustc-workspace-hack",
"rustc_version",
+ "serde",
"shell-escape",
"vergen",
]
@@ -2575,9 +2537,9 @@
[[package]]
name = "polonius-engine"
-version = "0.10.0"
+version = "0.11.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "50fa9dbfd0d3d60594da338cfe6f94028433eecae4b11b7e83fd99759227bbfe"
+checksum = "1e478d7c38eb785c6416cbe58df12aa55d7aefa3759b6d3e044b2ed03f423cec"
dependencies = [
"datafrog",
"log",
@@ -2634,7 +2596,7 @@
dependencies = [
"proc-macro2 1.0.3",
"quote 1.0.2",
- "syn 1.0.5",
+ "syn 1.0.11",
]
[[package]]
@@ -2745,9 +2707,9 @@
[[package]]
name = "racer"
-version = "2.1.28"
+version = "2.1.29"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "acc70369054bad4ad0c16a3f45cd73e0695361a3af35c7b465e619ac2674f064"
+checksum = "7a6d7ffceb4da3e0a29c18986f0469c209f4db3ab9f2ffe286eaa1104a3e5028"
dependencies = [
"bitflags",
"clap",
@@ -3046,7 +3008,7 @@
[[package]]
name = "rls"
-version = "1.40.0"
+version = "1.41.0"
dependencies = [
"cargo",
"cargo_metadata 0.8.0",
@@ -3195,8 +3157,8 @@
"num_cpus",
"parking_lot 0.9.0",
"polonius-engine",
- "rustc-rayon 0.3.0",
- "rustc-rayon-core 0.3.0",
+ "rustc-rayon",
+ "rustc-rayon-core",
"rustc_apfloat",
"rustc_data_structures",
"rustc_error_codes",
@@ -3216,9 +3178,9 @@
[[package]]
name = "rustc-ap-arena"
-version = "606.0.0"
+version = "610.0.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "a623fd4805842e9bd0bb6e6dace63efede0ee22de4522a0b03b7c3d15a22f009"
+checksum = "7475f4c707269b56eb7144c53591e3cd6369a5aa1d66434829ea11df96d5e7e3"
dependencies = [
"rustc-ap-rustc_data_structures",
"smallvec 0.6.10",
@@ -3226,15 +3188,15 @@
[[package]]
name = "rustc-ap-graphviz"
-version = "606.0.0"
+version = "610.0.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "ee549ade784b444ef10c0240c3487ed785aa65d711071f7984246b15329a17b6"
+checksum = "6e59a55520f140a70a3e0fad80a36e807caa85e9d7016167b91a5b521ea929be"
[[package]]
name = "rustc-ap-rustc_data_structures"
-version = "606.0.0"
+version = "610.0.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "ca545744a5a9b42e3d0410d6290d40de96dd567253fe77f310c1de4afd213dd4"
+checksum = "6420857d5a088f680ec1ba736ffba4ee9c1964b0d397e6318f38d461f4f7d5cb"
dependencies = [
"cfg-if",
"crossbeam-utils 0.6.5",
@@ -3248,17 +3210,17 @@
"rustc-ap-rustc_index",
"rustc-ap-serialize",
"rustc-hash",
- "rustc-rayon 0.2.0",
- "rustc-rayon-core 0.2.0",
+ "rustc-rayon",
+ "rustc-rayon-core",
"smallvec 0.6.10",
"stable_deref_trait",
]
[[package]]
name = "rustc-ap-rustc_errors"
-version = "606.0.0"
+version = "610.0.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "a6967a41ed38ef4bce0f559fe9a4801d8ba12ac032f40a12a55e72f79d52c9bb"
+checksum = "8abfca0960131262254a91d02ff4903526a261ede730d7a2c75b4234c867cdc0"
dependencies = [
"annotate-snippets",
"atty",
@@ -3273,9 +3235,9 @@
[[package]]
name = "rustc-ap-rustc_index"
-version = "606.0.0"
+version = "610.0.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "457a5c204ae2fdaa5bdb5b196e58ca59896870d80445fe423063c9453496e3ea"
+checksum = "5a395509dcb90a92c1479c085639594624e06b4ab3fc7c1b795b46a61f2d4f65"
dependencies = [
"rustc-ap-serialize",
"smallvec 0.6.10",
@@ -3283,31 +3245,31 @@
[[package]]
name = "rustc-ap-rustc_lexer"
-version = "606.0.0"
+version = "610.0.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "ed0c064676f8a08e42a36b0d4e4a102465fb0f4b75e11436cb7f66d2c3fa7139"
+checksum = "64eac8a0e6efb8f55292aa24be0208c7c0538236c613e79952fd1fa3d54bcf8e"
dependencies = [
"unicode-xid 0.2.0",
]
[[package]]
name = "rustc-ap-rustc_macros"
-version = "606.0.0"
+version = "610.0.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "b2d77e46159c5288c585decbcdc9d742889c65e307c31e104c7a36d63fe1f5d0"
+checksum = "f99795e8be4877e9e05d59f201e1740c1cf673364655def5848606d9e25b75af"
dependencies = [
"itertools 0.8.0",
- "proc-macro2 0.4.30",
- "quote 0.6.12",
- "syn 0.15.35",
- "synstructure 0.10.2",
+ "proc-macro2 1.0.3",
+ "quote 1.0.2",
+ "syn 1.0.11",
+ "synstructure 0.12.1",
]
[[package]]
name = "rustc-ap-rustc_target"
-version = "606.0.0"
+version = "610.0.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "86ca895350b0de14d064b499168c93fa183958d5462eb042c927d93623e41ec1"
+checksum = "f22e21fdd8e1c0030f507158fa79b9f1e080e6241aba994d0f97c14a0a07a826"
dependencies = [
"bitflags",
"log",
@@ -3319,9 +3281,9 @@
[[package]]
name = "rustc-ap-serialize"
-version = "606.0.0"
+version = "610.0.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "92679240e86f4583cc05f8dcf6439bdab87bac9e6555718469176de9bd52ba20"
+checksum = "bb1cd6ef5135408d62559866e79986ca261f4c1333253d500e5e66fe66d1432e"
dependencies = [
"indexmap",
"smallvec 0.6.10",
@@ -3329,9 +3291,9 @@
[[package]]
name = "rustc-ap-syntax"
-version = "606.0.0"
+version = "610.0.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "0a0c30f8e38c847dbfd9e2f1e472ab06d0bd0a23ab53ae4c5a44912842ce834e"
+checksum = "61fc1c901d2cbd24cae95d7bc5a58aa7661ec3dc5320c78c32830a52a685c33c"
dependencies = [
"bitflags",
"lazy_static 1.3.0",
@@ -3349,9 +3311,9 @@
[[package]]
name = "rustc-ap-syntax_pos"
-version = "606.0.0"
+version = "610.0.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "2bdaa0fb40143b4b878256ac4e2b498885daafc269502504d91929eab4744bf4"
+checksum = "230534f638255853bb9f13987537e00a818435a0cc54b68d97221b6822c8f1bc"
dependencies = [
"cfg-if",
"rustc-ap-arena",
@@ -3394,36 +3356,13 @@
[[package]]
name = "rustc-rayon"
-version = "0.2.0"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "0d2e07e19601f21c59aad953c2632172ba70cb27e685771514ea66e4062b3363"
-dependencies = [
- "crossbeam-deque 0.2.0",
- "either",
- "rustc-rayon-core 0.2.0",
-]
-
-[[package]]
-name = "rustc-rayon"
version = "0.3.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "f32767f90d938f1b7199a174ef249ae1924f6e5bbdb9d112fea141e016f25b3a"
dependencies = [
"crossbeam-deque 0.7.1",
"either",
- "rustc-rayon-core 0.3.0",
-]
-
-[[package]]
-name = "rustc-rayon-core"
-version = "0.2.0"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "79d38ca7cbc22fa59f09d8534ea4b27f67b0facf0cbe274433aceea227a02543"
-dependencies = [
- "crossbeam-deque 0.2.0",
- "lazy_static 1.3.0",
- "libc",
- "num_cpus",
+ "rustc-rayon-core",
]
[[package]]
@@ -3496,7 +3435,27 @@
name = "rustc_codegen_llvm"
version = "0.0.0"
dependencies = [
+ "bitflags",
+ "flate2",
+ "libc",
+ "log",
+ "rustc",
+ "rustc-demangle",
+ "rustc_codegen_ssa",
+ "rustc_codegen_utils",
+ "rustc_data_structures",
+ "rustc_errors",
+ "rustc_feature",
+ "rustc_fs_util",
+ "rustc_incremental",
+ "rustc_index",
"rustc_llvm",
+ "rustc_session",
+ "rustc_target",
+ "smallvec 0.6.10",
+ "syntax",
+ "syntax_expand",
+ "syntax_pos",
]
[[package]]
@@ -3558,8 +3517,8 @@
"measureme",
"parking_lot 0.9.0",
"rustc-hash",
- "rustc-rayon 0.3.0",
- "rustc-rayon-core 0.3.0",
+ "rustc-rayon",
+ "rustc-rayon-core",
"rustc_index",
"serialize",
"smallvec 1.0.0",
@@ -3657,7 +3616,8 @@
"log",
"once_cell",
"rustc",
- "rustc-rayon 0.3.0",
+ "rustc-rayon",
+ "rustc_codegen_llvm",
"rustc_codegen_ssa",
"rustc_codegen_utils",
"rustc_data_structures",
@@ -3712,6 +3672,7 @@
dependencies = [
"build_helper",
"cc",
+ "libc",
]
[[package]]
@@ -3732,7 +3693,7 @@
"itertools 0.8.0",
"proc-macro2 1.0.3",
"quote 1.0.2",
- "syn 1.0.5",
+ "syn 1.0.11",
"synstructure 0.12.1",
]
@@ -3806,7 +3767,6 @@
"rustc_errors",
"rustc_feature",
"rustc_lexer",
- "rustc_target",
"smallvec 1.0.0",
"syntax",
"syntax_pos",
@@ -3985,7 +3945,9 @@
dependencies = [
"minifier",
"pulldown-cmark 0.5.3",
- "rustc-rayon 0.3.0",
+ "rustc-rayon",
+ "serde",
+ "serde_json",
"tempfile",
]
@@ -4019,12 +3981,12 @@
"proc-macro2 1.0.3",
"quote 1.0.2",
"serde",
- "syn 1.0.5",
+ "syn 1.0.11",
]
[[package]]
name = "rustfmt-nightly"
-version = "1.4.9"
+version = "1.4.11"
dependencies = [
"annotate-snippets",
"bytecount",
@@ -4189,7 +4151,7 @@
dependencies = [
"proc-macro2 1.0.3",
"quote 1.0.2",
- "syn 1.0.5",
+ "syn 1.0.11",
]
[[package]]
@@ -4402,7 +4364,7 @@
"proc-macro-error",
"proc-macro2 1.0.3",
"quote 1.0.2",
- "syn 1.0.5",
+ "syn 1.0.11",
]
[[package]]
@@ -4436,9 +4398,9 @@
[[package]]
name = "syn"
-version = "1.0.5"
+version = "1.0.11"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "66850e97125af79138385e9b88339cbcd037e3f28ceab8c5ad98e64f0f1f80bf"
+checksum = "dff0acdb207ae2fe6d5976617f887eb1e35a2ba52c13c7234c790960cdad9238"
dependencies = [
"proc-macro2 1.0.3",
"quote 1.0.2",
@@ -4465,7 +4427,7 @@
dependencies = [
"proc-macro2 1.0.3",
"quote 1.0.2",
- "syn 1.0.5",
+ "syn 1.0.11",
"unicode-xid 0.2.0",
]
diff --git a/RELEASES.md b/RELEASES.md
index 5313987..5afc6f9 100644
--- a/RELEASES.md
+++ b/RELEASES.md
@@ -1,3 +1,140 @@
+Version 1.40.0 (2019-12-19)
+===========================
+
+Language
+--------
+- [You can now use tuple `struct`s and tuple `enum` variant's constructors in
+ `const` contexts.][65188] e.g.
+
+ ```rust
+ pub struct Point(i32, i32);
+
+ const ORIGIN: Point = {
+ let constructor = Point;
+
+ constructor(0, 0)
+ };
+ ```
+
+- [You can now mark `struct`s, `enum`s, and `enum` variants with the `#[non_exhaustive]` attribute to
+ indicate that there may be variants or fields added in the future.][64639]
+ For example this requires adding a wild-card branch (`_ => {}`) to any match
+ statements on a non-exhaustive `enum`. [(RFC 2008)]
+- [You can now use function-like procedural macros in `extern` blocks and in
+ type positions.][63931] e.g. `type Generated = macro!();`
+- [Function-like and attribute procedural macros can now emit
+ `macro_rules!` items, so you can now have your macros generate macros.][64035]
+- [The `meta` pattern matcher in `macro_rules!` now correctly matches the modern
+ attribute syntax.][63674] For example `(#[$m:meta])` now matches `#[attr]`,
+ `#[attr{tokens}]`, `#[attr[tokens]]`, and `#[attr(tokens)]`.
+
+Compiler
+--------
+- [Added tier 3 support\* for the
+ `thumbv7neon-unknown-linux-musleabihf` target.][66103]
+- [Added tier 3 support for the
+ `aarch64-unknown-none-softfloat` target.][64589]
+- [Added tier 3 support for the `mips64-unknown-linux-muslabi64`, and
+ `mips64el-unknown-linux-muslabi64` targets.][65843]
+
+\* Refer to Rust's [platform support page][forge-platform-support] for more
+ information on Rust's tiered platform support.
+
+Libraries
+---------
+- [The `is_power_of_two` method on unsigned numeric types is now a `const` function.][65092]
+
+Stabilized APIs
+---------------
+- [`BTreeMap::get_key_value`]
+- [`HashMap::get_key_value`]
+- [`Option::as_deref_mut`]
+- [`Option::as_deref`]
+- [`Option::flatten`]
+- [`UdpSocket::peer_addr`]
+- [`f32::to_be_bytes`]
+- [`f32::to_le_bytes`]
+- [`f32::to_ne_bytes`]
+- [`f64::to_be_bytes`]
+- [`f64::to_le_bytes`]
+- [`f64::to_ne_bytes`]
+- [`f32::from_be_bytes`]
+- [`f32::from_le_bytes`]
+- [`f32::from_ne_bytes`]
+- [`f64::from_be_bytes`]
+- [`f64::from_le_bytes`]
+- [`f64::from_ne_bytes`]
+- [`mem::take`]
+- [`slice::repeat`]
+- [`todo!`]
+
+Cargo
+-----
+- [Cargo will now always display warnings, rather than only on
+ fresh builds.][cargo/7450]
+- [Feature flags (except `--all-features`) passed to a virtual workspace will
+ now produce an error.][cargo/7507] Previously these flags were ignored.
+- [You can now publish `dev-dependencies` without including
+ a `version`.][cargo/7333]
+
+Misc
+----
+- [You can now specify the `#[cfg(doctest)]` attribute to include an item only
+ when running documentation tests with `rustdoc`.][63803]
+
+Compatibility Notes
+-------------------
+- [As previously announced, any previous NLL warnings in the 2015 edition are
+ now hard errors.][64221]
+- [The `include!` macro will now warn if it failed to include the
+ entire file.][64284] The `include!` macro unintentionally only includes the
+ first _expression_ in a file, and this can be unintuitive. This will become
+ either a hard error in a future release, or the behavior may be fixed to include all expressions as expected.
+- [Using `#[inline]` on function prototypes and consts now emits a warning under
+ `unused_attribute` lint.][65294] Using `#[inline]` anywhere else inside traits
+ or `extern` blocks now correctly emits a hard error.
+
+[65294]: https://github.com/rust-lang/rust/pull/65294/
+[66103]: https://github.com/rust-lang/rust/pull/66103/
+[65843]: https://github.com/rust-lang/rust/pull/65843/
+[65188]: https://github.com/rust-lang/rust/pull/65188/
+[65092]: https://github.com/rust-lang/rust/pull/65092/
+[64589]: https://github.com/rust-lang/rust/pull/64589/
+[64639]: https://github.com/rust-lang/rust/pull/64639/
+[64221]: https://github.com/rust-lang/rust/pull/64221/
+[64284]: https://github.com/rust-lang/rust/pull/64284/
+[63931]: https://github.com/rust-lang/rust/pull/63931/
+[64035]: https://github.com/rust-lang/rust/pull/64035/
+[63674]: https://github.com/rust-lang/rust/pull/63674/
+[63803]: https://github.com/rust-lang/rust/pull/63803/
+[cargo/7450]: https://github.com/rust-lang/cargo/pull/7450/
+[cargo/7507]: https://github.com/rust-lang/cargo/pull/7507/
+[cargo/7525]: https://github.com/rust-lang/cargo/pull/7525/
+[cargo/7333]: https://github.com/rust-lang/cargo/pull/7333/
+[(rfc 2008)]: https://rust-lang.github.io/rfcs/2008-non-exhaustive.html
+[`f32::to_be_bytes`]: https://doc.rust-lang.org/std/primitive.f32.html#method.to_be_bytes
+[`f32::to_le_bytes`]: https://doc.rust-lang.org/std/primitive.f32.html#method.to_le_bytes
+[`f32::to_ne_bytes`]: https://doc.rust-lang.org/std/primitive.f32.html#method.to_ne_bytes
+[`f64::to_be_bytes`]: https://doc.rust-lang.org/std/primitive.f64.html#method.to_be_bytes
+[`f64::to_le_bytes`]: https://doc.rust-lang.org/std/primitive.f64.html#method.to_le_bytes
+[`f64::to_ne_bytes`]: https://doc.rust-lang.org/std/primitive.f64.html#method.to_ne_bytes
+[`f32::from_be_bytes`]: https://doc.rust-lang.org/std/primitive.f32.html#method.from_be_bytes
+[`f32::from_le_bytes`]: https://doc.rust-lang.org/std/primitive.f32.html#method.from_le_bytes
+[`f32::from_ne_bytes`]: https://doc.rust-lang.org/std/primitive.f32.html#method.from_ne_bytes
+[`f64::from_be_bytes`]: https://doc.rust-lang.org/std/primitive.f64.html#method.from_be_bytes
+[`f64::from_le_bytes`]: https://doc.rust-lang.org/std/primitive.f64.html#method.from_le_bytes
+[`f64::from_ne_bytes`]: https://doc.rust-lang.org/std/primitive.f64.html#method.from_ne_bytes
+[`option::flatten`]: https://doc.rust-lang.org/std/option/enum.Option.html#method.flatten
+[`option::as_deref`]: https://doc.rust-lang.org/std/option/enum.Option.html#method.as_deref
+[`option::as_deref_mut`]: https://doc.rust-lang.org/std/option/enum.Option.html#method.as_deref_mut
+[`hashmap::get_key_value`]: https://doc.rust-lang.org/std/collections/struct.HashMap.html#method.get_key_value
+[`btreemap::get_key_value`]: https://doc.rust-lang.org/std/collections/struct.BTreeMap.html#method.get_key_value
+[`slice::repeat`]: https://doc.rust-lang.org/std/primitive.slice.html#method.repeat
+[`mem::take`]: https://doc.rust-lang.org/std/mem/fn.take.html
+[`udpsocket::peer_addr`]: https://doc.rust-lang.org/std/net/struct.UdpSocket.html#method.peer_addr
+[`todo!`]: https://doc.rust-lang.org/std/macro.todo.html
+
+
Version 1.39.0 (2019-11-07)
===========================
diff --git a/config.toml.example b/config.toml.example
index e832570..5152a6c 100644
--- a/config.toml.example
+++ b/config.toml.example
@@ -379,9 +379,6 @@
# and currently the only standard option supported is `"llvm"`
#codegen-backends = ["llvm"]
-# This is the name of the directory in which codegen backends will get installed
-#codegen-backends-dir = "codegen-backends"
-
# Indicates whether LLD will be compiled and made available in the sysroot for
# rustc to execute.
#lld = false
diff --git a/src/bootstrap/builder.rs b/src/bootstrap/builder.rs
index 99b8ddf..8b0ad16 100644
--- a/src/bootstrap/builder.rs
+++ b/src/bootstrap/builder.rs
@@ -339,7 +339,6 @@
Kind::Build => describe!(
compile::Std,
compile::Rustc,
- compile::CodegenBackend,
compile::StartupObjects,
tool::BuildManifest,
tool::Rustbook,
@@ -364,10 +363,10 @@
Kind::Check | Kind::Clippy | Kind::Fix => describe!(
check::Std,
check::Rustc,
- check::CodegenBackend,
check::Rustdoc
),
Kind::Test => describe!(
+ crate::toolstate::ToolStateCheck,
test::Tidy,
test::Ui,
test::CompileFail,
@@ -631,11 +630,6 @@
self.ensure(Libdir { compiler, target })
}
- pub fn sysroot_codegen_backends(&self, compiler: Compiler) -> PathBuf {
- self.sysroot_libdir(compiler, compiler.host)
- .with_file_name(self.config.rust_codegen_backends_dir.clone())
- }
-
/// Returns the compiler's libdir where it stores the dynamic libraries that
/// it itself links against.
///
@@ -706,15 +700,6 @@
}
}
- /// Gets the paths to all of the compiler's codegen backends.
- fn codegen_backends(&self, compiler: Compiler) -> impl Iterator<Item = PathBuf> {
- fs::read_dir(self.sysroot_codegen_backends(compiler))
- .into_iter()
- .flatten()
- .filter_map(Result::ok)
- .map(|entry| entry.path())
- }
-
pub fn rustdoc(&self, compiler: Compiler) -> PathBuf {
self.ensure(tool::Rustdoc { compiler })
}
@@ -758,12 +743,6 @@
let mut cargo = Command::new(&self.initial_cargo);
let out_dir = self.stage_out(compiler, mode);
- // Codegen backends are not yet tracked by -Zbinary-dep-depinfo,
- // so we need to explicitly clear out if they've been updated.
- for backend in self.codegen_backends(compiler) {
- self.clear_if_dirty(&out_dir, &backend);
- }
-
if cmd == "doc" || cmd == "rustdoc" {
let my_out = match mode {
// This is the intended out directory for compiler documentation.
@@ -980,7 +959,7 @@
// argument manually via `-C link-args=-Wl,-rpath,...`. Plus isn't it
// fun to pass a flag to a tool to pass a flag to pass a flag to a tool
// to change a flag in a binary?
- if self.config.rust_rpath {
+ if self.config.rust_rpath && util::use_host_linker(&target) {
let rpath = if target.contains("apple") {
// Note that we need to take one extra step on macOS to also pass
@@ -990,10 +969,7 @@
// flesh out rpath support more fully in the future.
rustflags.arg("-Zosx-rpath-install-name");
Some("-Wl,-rpath,@loader_path/../lib")
- } else if !target.contains("windows") &&
- !target.contains("wasm32") &&
- !target.contains("emscripten") &&
- !target.contains("fuchsia") {
+ } else if !target.contains("windows") {
Some("-Wl,-rpath,$ORIGIN/../lib")
} else {
None
diff --git a/src/bootstrap/builder/tests.rs b/src/bootstrap/builder/tests.rs
index 2bb90fd..b9d97fb 100644
--- a/src/bootstrap/builder/tests.rs
+++ b/src/bootstrap/builder/tests.rs
@@ -363,6 +363,10 @@
compiler: Compiler { host: a, stage: 1 },
target: b,
},
+ compile::Std {
+ compiler: Compiler { host: a, stage: 2 },
+ target: b,
+ },
]
);
assert_eq!(
diff --git a/src/bootstrap/check.rs b/src/bootstrap/check.rs
index df1c725..f5c427d 100644
--- a/src/bootstrap/check.rs
+++ b/src/bootstrap/check.rs
@@ -1,11 +1,10 @@
//! Implementation of compiling the compiler and standard library, in "check"-based modes.
-use crate::compile::{run_cargo, std_cargo, rustc_cargo, rustc_cargo_env,
- add_to_sysroot};
+use crate::compile::{run_cargo, std_cargo, rustc_cargo, add_to_sysroot};
use crate::builder::{RunConfig, Builder, Kind, ShouldRun, Step};
use crate::tool::{prepare_tool_cargo, SourceType};
use crate::{Compiler, Mode};
-use crate::cache::{INTERNER, Interned};
+use crate::cache::Interned;
use std::path::PathBuf;
#[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)]
@@ -97,7 +96,7 @@
let mut cargo = builder.cargo(compiler, Mode::Rustc, target,
cargo_subcommand(builder.kind));
- rustc_cargo(builder, &mut cargo);
+ rustc_cargo(builder, &mut cargo, target);
builder.info(&format!("Checking compiler artifacts ({} -> {})", &compiler.host, target));
run_cargo(builder,
@@ -114,55 +113,6 @@
}
#[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)]
-pub struct CodegenBackend {
- pub target: Interned<String>,
- pub backend: Interned<String>,
-}
-
-impl Step for CodegenBackend {
- type Output = ();
- const ONLY_HOSTS: bool = true;
- const DEFAULT: bool = true;
-
- fn should_run(run: ShouldRun<'_>) -> ShouldRun<'_> {
- run.all_krates("rustc_codegen_llvm")
- }
-
- fn make_run(run: RunConfig<'_>) {
- let backend = run.builder.config.rust_codegen_backends.get(0);
- let backend = backend.cloned().unwrap_or_else(|| {
- INTERNER.intern_str("llvm")
- });
- run.builder.ensure(CodegenBackend {
- target: run.target,
- backend,
- });
- }
-
- fn run(self, builder: &Builder<'_>) {
- let compiler = builder.compiler(0, builder.config.build);
- let target = self.target;
- let backend = self.backend;
-
- builder.ensure(Rustc { target });
-
- let mut cargo = builder.cargo(compiler, Mode::Codegen, target,
- cargo_subcommand(builder.kind));
- cargo.arg("--manifest-path").arg(builder.src.join("src/librustc_codegen_llvm/Cargo.toml"));
- rustc_cargo_env(builder, &mut cargo);
-
- // We won't build LLVM if it's not available, as it shouldn't affect `check`.
-
- run_cargo(builder,
- cargo,
- args(builder.kind),
- &codegen_backend_stamp(builder, compiler, target, backend),
- vec![],
- true);
- }
-}
-
-#[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)]
pub struct Rustdoc {
pub target: Interned<String>,
}
@@ -231,16 +181,6 @@
builder.cargo_out(compiler, Mode::Rustc, target).join(".librustc-check.stamp")
}
-/// Cargo's output path for librustc_codegen_llvm in a given stage, compiled by a particular
-/// compiler for the specified target and backend.
-fn codegen_backend_stamp(builder: &Builder<'_>,
- compiler: Compiler,
- target: Interned<String>,
- backend: Interned<String>) -> PathBuf {
- builder.cargo_out(compiler, Mode::Codegen, target)
- .join(format!(".librustc_codegen_llvm-{}-check.stamp", backend))
-}
-
/// Cargo's output path for rustdoc in a given stage, compiled by a particular
/// compiler for the specified target.
pub fn rustdoc_stamp(
diff --git a/src/bootstrap/compile.rs b/src/bootstrap/compile.rs
index f686dfe..baf9aab 100644
--- a/src/bootstrap/compile.rs
+++ b/src/bootstrap/compile.rs
@@ -27,7 +27,7 @@
use crate::native;
use crate::cache::{INTERNER, Interned};
-use crate::builder::{Step, RunConfig, ShouldRun, Builder};
+use crate::builder::{Step, RunConfig, ShouldRun, Builder, Kind};
#[derive(Debug, PartialOrd, Ord, Copy, Clone, PartialEq, Eq, Hash)]
pub struct Std {
@@ -445,7 +445,7 @@
});
let mut cargo = builder.cargo(compiler, Mode::Rustc, target, "build");
- rustc_cargo(builder, &mut cargo);
+ rustc_cargo(builder, &mut cargo, target);
builder.info(&format!("Building stage{} compiler artifacts ({} -> {})",
compiler.stage, &compiler.host, target));
@@ -456,6 +456,44 @@
vec![],
false);
+ // We used to build librustc_codegen_llvm as a separate step,
+ // which produced a dylib that the compiler would dlopen() at runtime.
+ // This meant that we only needed to make sure that libLLVM.so was
+ // installed by the time we went to run a tool using it - since
+ // librustc_codegen_llvm was effectively a standalone artifact,
+ // other crates were completely oblivious to its dependency
+ // on `libLLVM.so` during build time.
+ //
+ // However, librustc_codegen_llvm is now built as an ordinary
+ // crate during the same step as the rest of the compiler crates.
+ // This means that any crates depending on it will see the fact
+ // that it uses `libLLVM.so` as a native library, and will
+ // cause us to pass `-llibLLVM.so` to the linker when we link
+ // a binary.
+ //
+ // For `rustc` itself, this works out fine.
+ // During the `Assemble` step, we call `dist::maybe_install_llvm_dylib`
+ // to copy libLLVM.so into the `stage` directory. We then link
+ // the compiler binary, which will find `libLLVM.so` in the correct place.
+ //
+ // However, this is insufficient for tools that are build against stage0
+ // (e.g. stage1 rustdoc). Since `Assemble` for stage0 doesn't actually do anything,
+ // we won't have `libLLVM.so` in the stage0 sysroot. In the past, this wasn't
+ // a problem - we would copy the tool binary into its correct stage directory
+ // (e.g. stage1 for a stage1 rustdoc built against a stage0 compiler).
+ // Since libLLVM.so wasn't resolved until runtime, it was fine for it to
+ // not exist while we were building it.
+ //
+ // To ensure that we can still build stage1 tools against a stage0 compiler,
+ // we explicitly copy libLLVM.so into the stage0 sysroot when building
+ // the stage0 compiler. This ensures that tools built against stage0
+ // will see libLLVM.so at build time, making the linker happy.
+ if compiler.stage == 0 {
+ builder.info(&format!("Installing libLLVM.so to stage 0 ({})", compiler.host));
+ let sysroot = builder.sysroot(compiler);
+ dist::maybe_install_llvm_dylib(builder, compiler.host, &sysroot);
+ }
+
builder.ensure(RustcLink {
compiler: builder.compiler(compiler.stage, builder.config.build),
target_compiler: compiler,
@@ -464,21 +502,20 @@
}
}
-pub fn rustc_cargo(builder: &Builder<'_>, cargo: &mut Cargo) {
+pub fn rustc_cargo(builder: &Builder<'_>, cargo: &mut Cargo, target: Interned<String>) {
cargo.arg("--features").arg(builder.rustc_features())
.arg("--manifest-path")
.arg(builder.src.join("src/rustc/Cargo.toml"));
- rustc_cargo_env(builder, cargo);
+ rustc_cargo_env(builder, cargo, target);
}
-pub fn rustc_cargo_env(builder: &Builder<'_>, cargo: &mut Cargo) {
+pub fn rustc_cargo_env(builder: &Builder<'_>, cargo: &mut Cargo, target: Interned<String>) {
// Set some configuration variables picked up by build scripts and
// the compiler alike
cargo.env("CFG_RELEASE", builder.rust_release())
.env("CFG_RELEASE_CHANNEL", &builder.config.channel)
.env("CFG_VERSION", builder.rust_version())
- .env("CFG_PREFIX", builder.config.prefix.clone().unwrap_or_default())
- .env("CFG_CODEGEN_BACKENDS_DIR", &builder.config.rust_codegen_backends_dir);
+ .env("CFG_PREFIX", builder.config.prefix.clone().unwrap_or_default());
let libdir_relative = builder.config.libdir_relative().unwrap_or(Path::new("lib"));
cargo.env("CFG_LIBDIR_RELATIVE", libdir_relative);
@@ -501,6 +538,49 @@
if builder.config.rust_verify_llvm_ir {
cargo.env("RUSTC_VERIFY_LLVM_IR", "1");
}
+
+ // Pass down configuration from the LLVM build into the build of
+ // librustc_llvm and librustc_codegen_llvm.
+ //
+ // Note that this is disabled if LLVM itself is disabled or we're in a check
+ // build, where if we're in a check build there's no need to build all of
+ // LLVM and such.
+ if builder.config.llvm_enabled() && builder.kind != Kind::Check {
+ if builder.is_rust_llvm(target) {
+ cargo.env("LLVM_RUSTLLVM", "1");
+ }
+ let llvm_config = builder.ensure(native::Llvm { target });
+ cargo.env("LLVM_CONFIG", &llvm_config);
+ let target_config = builder.config.target_config.get(&target);
+ if let Some(s) = target_config.and_then(|c| c.llvm_config.as_ref()) {
+ cargo.env("CFG_LLVM_ROOT", s);
+ }
+ // Some LLVM linker flags (-L and -l) may be needed to link librustc_llvm.
+ if let Some(ref s) = builder.config.llvm_ldflags {
+ cargo.env("LLVM_LINKER_FLAGS", s);
+ }
+ // Building with a static libstdc++ is only supported on linux right now,
+ // not for MSVC or macOS
+ if builder.config.llvm_static_stdcpp &&
+ !target.contains("freebsd") &&
+ !target.contains("windows") &&
+ !target.contains("apple") {
+ let file = compiler_file(builder,
+ builder.cxx(target).unwrap(),
+ target,
+ "libstdc++.a");
+ cargo.env("LLVM_STATIC_STDCPP", file);
+ }
+ if builder.config.llvm_link_shared || builder.config.llvm_thin_lto {
+ cargo.env("LLVM_LINK_SHARED", "1");
+ }
+ if builder.config.llvm_use_libcxx {
+ cargo.env("LLVM_USE_LIBCXX", "1");
+ }
+ if builder.config.llvm_optimize && !builder.config.llvm_release_debuginfo {
+ cargo.env("LLVM_NDEBUG", "1");
+ }
+ }
}
#[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)]
@@ -537,215 +617,6 @@
}
}
-#[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)]
-pub struct CodegenBackend {
- pub compiler: Compiler,
- pub target: Interned<String>,
- pub backend: Interned<String>,
-}
-
-impl Step for CodegenBackend {
- type Output = ();
- const ONLY_HOSTS: bool = true;
- const DEFAULT: bool = true;
-
- fn should_run(run: ShouldRun<'_>) -> ShouldRun<'_> {
- run.all_krates("rustc_codegen_llvm")
- }
-
- fn make_run(run: RunConfig<'_>) {
- let backend = run.builder.config.rust_codegen_backends.get(0);
- let backend = backend.cloned().unwrap_or_else(|| {
- INTERNER.intern_str("llvm")
- });
- run.builder.ensure(CodegenBackend {
- compiler: run.builder.compiler(run.builder.top_stage, run.host),
- target: run.target,
- backend,
- });
- }
-
- fn run(self, builder: &Builder<'_>) {
- let compiler = self.compiler;
- let target = self.target;
- let backend = self.backend;
-
- builder.ensure(Rustc { compiler, target });
-
- if builder.config.keep_stage.contains(&compiler.stage) {
- builder.info("Warning: Using a potentially old codegen backend. \
- This may not behave well.");
- // Codegen backends are linked separately from this step today, so we don't do
- // anything here.
- return;
- }
-
- let compiler_to_use = builder.compiler_for(compiler.stage, compiler.host, target);
- if compiler_to_use != compiler {
- builder.ensure(CodegenBackend {
- compiler: compiler_to_use,
- target,
- backend,
- });
- return;
- }
-
- let out_dir = builder.cargo_out(compiler, Mode::Codegen, target);
-
- let mut cargo = builder.cargo(compiler, Mode::Codegen, target, "build");
- cargo.arg("--manifest-path")
- .arg(builder.src.join("src/librustc_codegen_llvm/Cargo.toml"));
- rustc_cargo_env(builder, &mut cargo);
-
- let features = build_codegen_backend(&builder, &mut cargo, &compiler, target, backend);
- cargo.arg("--features").arg(features);
-
- let tmp_stamp = out_dir.join(".tmp.stamp");
-
- let files = run_cargo(builder, cargo, vec![], &tmp_stamp, vec![], false);
- if builder.config.dry_run {
- return;
- }
- let mut files = files.into_iter()
- .filter(|f| {
- let filename = f.file_name().unwrap().to_str().unwrap();
- is_dylib(filename) && filename.contains("rustc_codegen_llvm-")
- });
- let codegen_backend = match files.next() {
- Some(f) => f,
- None => panic!("no dylibs built for codegen backend?"),
- };
- if let Some(f) = files.next() {
- panic!("codegen backend built two dylibs:\n{}\n{}",
- codegen_backend.display(),
- f.display());
- }
- let stamp = codegen_backend_stamp(builder, compiler, target, backend);
- let codegen_backend = codegen_backend.to_str().unwrap();
- t!(fs::write(&stamp, &codegen_backend));
- }
-}
-
-pub fn build_codegen_backend(builder: &Builder<'_>,
- cargo: &mut Cargo,
- compiler: &Compiler,
- target: Interned<String>,
- backend: Interned<String>) -> String {
- match &*backend {
- "llvm" => {
- // Build LLVM for our target. This will implicitly build the
- // host LLVM if necessary.
- let llvm_config = builder.ensure(native::Llvm {
- target,
- });
-
- builder.info(&format!("Building stage{} codegen artifacts ({} -> {}, {})",
- compiler.stage, &compiler.host, target, backend));
-
- // Pass down configuration from the LLVM build into the build of
- // librustc_llvm and librustc_codegen_llvm.
- if builder.is_rust_llvm(target) {
- cargo.env("LLVM_RUSTLLVM", "1");
- }
-
- cargo.env("LLVM_CONFIG", &llvm_config);
- let target_config = builder.config.target_config.get(&target);
- if let Some(s) = target_config.and_then(|c| c.llvm_config.as_ref()) {
- cargo.env("CFG_LLVM_ROOT", s);
- }
- // Some LLVM linker flags (-L and -l) may be needed to link librustc_llvm.
- if let Some(ref s) = builder.config.llvm_ldflags {
- cargo.env("LLVM_LINKER_FLAGS", s);
- }
- // Building with a static libstdc++ is only supported on linux and mingw right now,
- // not for MSVC or macOS
- if builder.config.llvm_static_stdcpp &&
- !target.contains("freebsd") &&
- !target.contains("msvc") &&
- !target.contains("apple") {
- let file = compiler_file(builder,
- builder.cxx(target).unwrap(),
- target,
- "libstdc++.a");
- cargo.env("LLVM_STATIC_STDCPP", file);
- }
- if builder.config.llvm_link_shared || builder.config.llvm_thin_lto {
- cargo.env("LLVM_LINK_SHARED", "1");
- }
- if builder.config.llvm_use_libcxx {
- cargo.env("LLVM_USE_LIBCXX", "1");
- }
- if builder.config.llvm_optimize && !builder.config.llvm_release_debuginfo {
- cargo.env("LLVM_NDEBUG", "1");
- }
- }
- _ => panic!("unknown backend: {}", backend),
- }
- String::new()
-}
-
-/// Creates the `codegen-backends` folder for a compiler that's about to be
-/// assembled as a complete compiler.
-///
-/// This will take the codegen artifacts produced by `compiler` and link them
-/// into an appropriate location for `target_compiler` to be a functional
-/// compiler.
-fn copy_codegen_backends_to_sysroot(builder: &Builder<'_>,
- compiler: Compiler,
- target_compiler: Compiler) {
- let target = target_compiler.host;
-
- // Note that this step is different than all the other `*Link` steps in
- // that it's not assembling a bunch of libraries but rather is primarily
- // moving the codegen backend into place. The codegen backend of rustc is
- // not linked into the main compiler by default but is rather dynamically
- // selected at runtime for inclusion.
- //
- // Here we're looking for the output dylib of the `CodegenBackend` step and
- // we're copying that into the `codegen-backends` folder.
- let dst = builder.sysroot_codegen_backends(target_compiler);
- t!(fs::create_dir_all(&dst));
-
- if builder.config.dry_run {
- return;
- }
-
- for backend in builder.config.rust_codegen_backends.iter() {
- let stamp = codegen_backend_stamp(builder, compiler, target, *backend);
- let dylib = t!(fs::read_to_string(&stamp));
- let file = Path::new(&dylib);
- let filename = file.file_name().unwrap().to_str().unwrap();
- // change `librustc_codegen_llvm-xxxxxx.so` to `librustc_codegen_llvm-llvm.so`
- let target_filename = {
- let dash = filename.find('-').unwrap();
- let dot = filename.find('.').unwrap();
- format!("{}-{}{}",
- &filename[..dash],
- backend,
- &filename[dot..])
- };
- builder.copy(&file, &dst.join(target_filename));
- }
-}
-
-fn copy_lld_to_sysroot(builder: &Builder<'_>,
- target_compiler: Compiler,
- lld_install_root: &Path) {
- let target = target_compiler.host;
-
- let dst = builder.sysroot_libdir(target_compiler, target)
- .parent()
- .unwrap()
- .join("bin");
- t!(fs::create_dir_all(&dst));
-
- let src_exe = exe("lld", &target);
- let dst_exe = exe("rust-lld", &target);
- // we prepend this bin directory to the user PATH when linking Rust binaries. To
- // avoid shadowing the system LLD we rename the LLD we provide to `rust-lld`.
- builder.copy(&lld_install_root.join("bin").join(&src_exe), &dst.join(&dst_exe));
-}
-
/// Cargo's output path for the standard library in a given stage, compiled
/// by a particular compiler for the specified target.
pub fn libstd_stamp(
@@ -766,16 +637,6 @@
builder.cargo_out(compiler, Mode::Rustc, target).join(".librustc.stamp")
}
-/// Cargo's output path for librustc_codegen_llvm in a given stage, compiled by a particular
-/// compiler for the specified target and backend.
-fn codegen_backend_stamp(builder: &Builder<'_>,
- compiler: Compiler,
- target: Interned<String>,
- backend: Interned<String>) -> PathBuf {
- builder.cargo_out(compiler, Mode::Codegen, target)
- .join(format!(".librustc_codegen_llvm-{}.stamp", backend))
-}
-
pub fn compiler_file(
builder: &Builder<'_>,
compiler: &Path,
@@ -879,13 +740,6 @@
compiler: build_compiler,
target: target_compiler.host,
});
- for &backend in builder.config.rust_codegen_backends.iter() {
- builder.ensure(CodegenBackend {
- compiler: build_compiler,
- target: target_compiler.host,
- backend,
- });
- }
let lld_install = if builder.config.lld_enabled {
Some(builder.ensure(native::Lld {
@@ -911,13 +765,19 @@
}
}
- copy_codegen_backends_to_sysroot(builder,
- build_compiler,
- target_compiler);
+ let libdir = builder.sysroot_libdir(target_compiler, target_compiler.host);
if let Some(lld_install) = lld_install {
- copy_lld_to_sysroot(builder, target_compiler, &lld_install);
+ let src_exe = exe("lld", &target_compiler.host);
+ let dst_exe = exe("rust-lld", &target_compiler.host);
+ // we prepend this bin directory to the user PATH when linking Rust binaries. To
+ // avoid shadowing the system LLD we rename the LLD we provide to `rust-lld`.
+ let dst = libdir.parent().unwrap().join("bin");
+ t!(fs::create_dir_all(&dst));
+ builder.copy(&lld_install.join("bin").join(&src_exe), &dst.join(&dst_exe));
}
+ // Ensure that `libLLVM.so` ends up in the newly build compiler directory,
+ // so that it can be found when the newly built `rustc` is run.
dist::maybe_install_llvm_dylib(builder, target_compiler.host, &sysroot);
// Link the compiler binary itself into place
diff --git a/src/bootstrap/config.rs b/src/bootstrap/config.rs
index 0c03b95..5f2ef01 100644
--- a/src/bootstrap/config.rs
+++ b/src/bootstrap/config.rs
@@ -105,7 +105,6 @@
pub rust_optimize_tests: bool,
pub rust_dist_src: bool,
pub rust_codegen_backends: Vec<Interned<String>>,
- pub rust_codegen_backends_dir: String,
pub rust_verify_llvm_ir: bool,
pub rust_remap_debuginfo: bool,
@@ -316,7 +315,6 @@
dist_src: Option<bool>,
save_toolstates: Option<String>,
codegen_backends: Option<Vec<String>>,
- codegen_backends_dir: Option<String>,
lld: Option<bool>,
llvm_tools: Option<bool>,
lldb: Option<bool>,
@@ -372,7 +370,6 @@
config.ignore_git = false;
config.rust_dist_src = true;
config.rust_codegen_backends = vec![INTERNER.intern_str("llvm")];
- config.rust_codegen_backends_dir = "codegen-backends".to_owned();
config.deny_warnings = true;
config.missing_tools = false;
@@ -575,8 +572,6 @@
.collect();
}
- set(&mut config.rust_codegen_backends_dir, rust.codegen_backends_dir.clone());
-
config.rust_codegen_units = rust.codegen_units.map(threads_from_config);
config.rust_codegen_units_std = rust.codegen_units_std.map(threads_from_config);
}
diff --git a/src/bootstrap/dist.rs b/src/bootstrap/dist.rs
index d0c9e0d..0253394 100644
--- a/src/bootstrap/dist.rs
+++ b/src/bootstrap/dist.rs
@@ -498,16 +498,6 @@
}
}
- // Copy over the codegen backends
- let backends_src = builder.sysroot_codegen_backends(compiler);
- let backends_rel = backends_src.strip_prefix(&src).unwrap()
- .strip_prefix(builder.sysroot_libdir_relative(compiler)).unwrap();
- // Don't use custom libdir here because ^lib/ will be resolved again with installer
- let backends_dst = image.join("lib").join(&backends_rel);
-
- 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
@@ -2134,6 +2124,10 @@
// Maybe add libLLVM.so to the lib-dir. It will only have been built if
// LLVM tools are linked dynamically.
+//
+// We add this to both the libdir of the rustc binary itself (for it to load at
+// runtime) and also to the target directory so it can find it at link-time.
+//
// Note: This function does no yet support Windows but we also don't support
// linking LLVM tools dynamically on Windows yet.
pub fn maybe_install_llvm_dylib(builder: &Builder<'_>,
@@ -2142,13 +2136,19 @@
let src_libdir = builder
.llvm_out(target)
.join("lib");
- let dst_libdir = sysroot.join("lib/rustlib").join(&*target).join("lib");
- t!(fs::create_dir_all(&dst_libdir));
+ let dst_libdir1 = sysroot.join("lib/rustlib").join(&*target).join("lib");
+ let dst_libdir2 = sysroot.join(builder.sysroot_libdir_relative(Compiler {
+ stage: 1,
+ host: target,
+ }));
+ t!(fs::create_dir_all(&dst_libdir1));
+ t!(fs::create_dir_all(&dst_libdir2));
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);
+ builder.install(&llvm_dylib_path, &dst_libdir1, 0o644);
+ builder.install(&llvm_dylib_path, &dst_libdir2, 0o644);
}
return
}
@@ -2164,7 +2164,8 @@
});
- builder.install(&llvm_dylib_path, &dst_libdir, 0o644);
+ builder.install(&llvm_dylib_path, &dst_libdir1, 0o644);
+ builder.install(&llvm_dylib_path, &dst_libdir2, 0o644);
}
}
diff --git a/src/bootstrap/doc.rs b/src/bootstrap/doc.rs
index 4ee8cd2..608cee0 100644
--- a/src/bootstrap/doc.rs
+++ b/src/bootstrap/doc.rs
@@ -433,7 +433,7 @@
builder.info(&format!("Documenting stage{} std ({})", stage, target));
let out = builder.doc_out(target);
t!(fs::create_dir_all(&out));
- let compiler = builder.compiler_for(stage, builder.config.build, target);
+ let compiler = builder.compiler(stage, builder.config.build);
builder.ensure(compile::Std { compiler, target });
let out_dir = builder.stage_out(compiler, Mode::Std)
@@ -541,7 +541,7 @@
// Build cargo command.
let mut cargo = builder.cargo(compiler, Mode::Rustc, target, "doc");
cargo.env("RUSTDOCFLAGS", "--document-private-items --passes strip-hidden");
- compile::rustc_cargo(builder, &mut cargo);
+ compile::rustc_cargo(builder, &mut cargo, target);
// Only include compiler crates, no dependencies of those, such as `libc`.
cargo.arg("--no-deps");
diff --git a/src/bootstrap/lib.rs b/src/bootstrap/lib.rs
index 39d7ea9..080bef6 100644
--- a/src/bootstrap/lib.rs
+++ b/src/bootstrap/lib.rs
@@ -169,7 +169,6 @@
pub use crate::config::Config;
use crate::flags::Subcommand;
use crate::cache::{Interned, INTERNER};
-use crate::toolstate::ToolState;
const LLVM_TOOLS: &[&str] = &[
"llvm-nm", // used to inspect binaries; it shows symbol names, their sizes and visibility
@@ -501,6 +500,9 @@
if self.config.jemalloc {
features.push_str("jemalloc");
}
+ if self.config.llvm_enabled() {
+ features.push_str(" llvm");
+ }
features
}
@@ -806,11 +808,8 @@
.and_then(|c| c.linker.as_ref()) {
Some(linker)
} else if target != self.config.build &&
- !target.contains("msvc") &&
- !target.contains("emscripten") &&
- !target.contains("wasm32") &&
- !target.contains("nvptx") &&
- !target.contains("fuchsia") {
+ util::use_host_linker(&target) &&
+ !target.contains("msvc") {
Some(self.cc(target))
} else {
None
@@ -1073,32 +1072,6 @@
}
}
- /// Updates the actual toolstate of a tool.
- ///
- /// The toolstates are saved to the file specified by the key
- /// `rust.save-toolstates` in `config.toml`. If unspecified, nothing will be
- /// done. The file is updated immediately after this function completes.
- pub fn save_toolstate(&self, tool: &str, state: ToolState) {
- if let Some(ref path) = self.config.save_toolstates {
- if let Some(parent) = path.parent() {
- // Ensure the parent directory always exists
- t!(std::fs::create_dir_all(parent));
- }
- let mut file = t!(fs::OpenOptions::new()
- .create(true)
- .read(true)
- .write(true)
- .open(path));
-
- let mut current_toolstates: HashMap<Box<str>, ToolState> =
- serde_json::from_reader(&mut file).unwrap_or_default();
- current_toolstates.insert(tool.into(), state);
- t!(file.seek(SeekFrom::Start(0)));
- t!(file.set_len(0));
- t!(serde_json::to_writer(file, ¤t_toolstates));
- }
- }
-
fn in_tree_crates(&self, root: &str) -> Vec<&Crate> {
let mut ret = Vec::new();
let mut list = vec![INTERNER.intern_str(root)];
diff --git a/src/bootstrap/test.rs b/src/bootstrap/test.rs
index a858ed4..f3b2a73 100644
--- a/src/bootstrap/test.rs
+++ b/src/bootstrap/test.rs
@@ -1773,7 +1773,7 @@
}
Mode::Rustc => {
builder.ensure(compile::Rustc { compiler, target });
- compile::rustc_cargo(builder, &mut cargo);
+ compile::rustc_cargo(builder, &mut cargo, target);
}
_ => panic!("can only test libraries"),
};
diff --git a/src/bootstrap/toolstate.rs b/src/bootstrap/toolstate.rs
index e86209b..a6d9ef3 100644
--- a/src/bootstrap/toolstate.rs
+++ b/src/bootstrap/toolstate.rs
@@ -1,4 +1,28 @@
use serde::{Deserialize, Serialize};
+use build_helper::t;
+use std::time;
+use std::fs;
+use std::io::{Seek, SeekFrom};
+use std::collections::HashMap;
+use crate::builder::{Builder, RunConfig, ShouldRun, Step};
+use std::fmt;
+use std::process::Command;
+use std::path::PathBuf;
+use std::env;
+
+// Each cycle is 42 days long (6 weeks); the last week is 35..=42 then.
+const BETA_WEEK_START: u64 = 35;
+
+#[cfg(linux)]
+const OS: Option<&str> = Some("linux");
+
+#[cfg(windows)]
+const OS: Option<&str> = Some("windows");
+
+#[cfg(all(not(linux), not(windows)))]
+const OS: Option<&str> = None;
+
+type ToolstateData = HashMap<Box<str>, ToolState>;
#[derive(Copy, Clone, Debug, Deserialize, Serialize, PartialEq, Eq)]
#[serde(rename_all = "kebab-case")]
@@ -12,9 +36,392 @@
BuildFail = 0,
}
+impl fmt::Display for ToolState {
+ fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
+ write!(f, "{}", match self {
+ ToolState::TestFail => "test-fail",
+ ToolState::TestPass => "test-pass",
+ ToolState::BuildFail => "build-fail",
+ })
+ }
+}
+
impl Default for ToolState {
fn default() -> Self {
// err on the safe side
ToolState::BuildFail
}
}
+
+/// Number of days after the last promotion of beta.
+/// Its value is 41 on the Tuesday where "Promote master to beta (T-2)" happens.
+/// The Wednesday after this has value 0.
+/// We track this value to prevent regressing tools in the last week of the 6-week cycle.
+fn days_since_beta_promotion() -> u64 {
+ let since_epoch = t!(time::SystemTime::UNIX_EPOCH.elapsed());
+ (since_epoch.as_secs() / 86400 - 20) % 42
+}
+
+// These tools must test-pass on the beta/stable channels.
+//
+// On the nightly channel, their build step must be attempted, but they may not
+// be able to build successfully.
+static STABLE_TOOLS: &[(&str, &str)] = &[
+ ("book", "src/doc/book"),
+ ("nomicon", "src/doc/nomicon"),
+ ("reference", "src/doc/reference"),
+ ("rust-by-example", "src/doc/rust-by-example"),
+ ("edition-guide", "src/doc/edition-guide"),
+ ("rls", "src/tools/rls"),
+ ("rustfmt", "src/tools/rustfmt"),
+ ("clippy-driver", "src/tools/clippy"),
+];
+
+// These tools are permitted to not build on the beta/stable channels.
+//
+// We do require that we checked whether they build or not on the tools builder,
+// though, as otherwise we will be unable to file an issue if they start
+// failing.
+static NIGHTLY_TOOLS: &[(&str, &str)] = &[
+ ("miri", "src/tools/miri"),
+ ("embedded-book", "src/doc/embedded-book"),
+ ("rustc-guide", "src/doc/rustc-guide"),
+];
+
+fn print_error(tool: &str, submodule: &str) {
+ eprintln!("");
+ eprintln!("We detected that this PR updated '{}', but its tests failed.", tool);
+ eprintln!("");
+ eprintln!("If you do intend to update '{}', please check the error messages above and", tool);
+ eprintln!("commit another update.");
+ eprintln!("");
+ eprintln!("If you do NOT intend to update '{}', please ensure you did not accidentally", tool);
+ eprintln!("change the submodule at '{}'. You may ask your reviewer for the", submodule);
+ eprintln!("proper steps.");
+ std::process::exit(3);
+}
+
+fn check_changed_files(toolstates: &HashMap<Box<str>, ToolState>) {
+ // Changed files
+ let output = std::process::Command::new("git")
+ .arg("diff")
+ .arg("--name-status")
+ .arg("HEAD")
+ .arg("HEAD^")
+ .output();
+ let output = match output {
+ Ok(o) => o,
+ Err(e) => {
+ eprintln!("Failed to get changed files: {:?}", e);
+ std::process::exit(1);
+ }
+ };
+
+ let output = t!(String::from_utf8(output.stdout));
+
+ for (tool, submodule) in STABLE_TOOLS.iter().chain(NIGHTLY_TOOLS.iter()) {
+ let changed = output.lines().any(|l| {
+ l.starts_with("M") && l.ends_with(submodule)
+ });
+ eprintln!("Verifying status of {}...", tool);
+ if !changed {
+ continue;
+ }
+
+ eprintln!("This PR updated '{}', verifying if status is 'test-pass'...", submodule);
+ if toolstates[*tool] != ToolState::TestPass {
+ print_error(tool, submodule);
+ }
+ }
+}
+
+#[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)]
+pub struct ToolStateCheck;
+
+impl Step for ToolStateCheck {
+ type Output = ();
+
+ /// Runs the `linkchecker` tool as compiled in `stage` by the `host` compiler.
+ ///
+ /// This tool in `src/tools` will verify the validity of all our links in the
+ /// documentation to ensure we don't have a bunch of dead ones.
+ fn run(self, builder: &Builder<'_>) {
+ if builder.config.dry_run {
+ return;
+ }
+
+ let days_since_beta_promotion = days_since_beta_promotion();
+ let in_beta_week = days_since_beta_promotion >= BETA_WEEK_START;
+ let is_nightly = !(builder.config.channel == "beta" || builder.config.channel == "stable");
+ let toolstates = builder.toolstates();
+
+ let mut did_error = false;
+
+ for (tool, _) in STABLE_TOOLS.iter().chain(NIGHTLY_TOOLS.iter()) {
+ if !toolstates.contains_key(*tool) {
+ did_error = true;
+ eprintln!("error: Tool `{}` was not recorded in tool state.", tool);
+ }
+ }
+
+ if did_error {
+ std::process::exit(1);
+ }
+
+ check_changed_files(&toolstates);
+
+ for (tool, _) in STABLE_TOOLS.iter() {
+ let state = toolstates[*tool];
+
+ if state != ToolState::TestPass {
+ if !is_nightly {
+ did_error = true;
+ eprintln!("error: Tool `{}` should be test-pass but is {}", tool, state);
+ } else if in_beta_week {
+ did_error = true;
+ eprintln!("error: Tool `{}` should be test-pass but is {} during beta week.",
+ tool, state);
+ }
+ }
+ }
+
+ if did_error {
+ std::process::exit(1);
+ }
+
+ if builder.config.channel == "nightly" && env::var_os("TOOLSTATE_PUBLISH").is_some() {
+ commit_toolstate_change(&toolstates, in_beta_week);
+ }
+ }
+
+ fn should_run(run: ShouldRun<'_>) -> ShouldRun<'_> {
+ run.path("check-tools")
+ }
+
+ fn make_run(run: RunConfig<'_>) {
+ run.builder.ensure(ToolStateCheck);
+ }
+}
+
+impl Builder<'_> {
+ fn toolstates(&self) -> HashMap<Box<str>, ToolState> {
+ if let Some(ref path) = self.config.save_toolstates {
+ if let Some(parent) = path.parent() {
+ // Ensure the parent directory always exists
+ t!(std::fs::create_dir_all(parent));
+ }
+ let mut file = t!(fs::OpenOptions::new()
+ .create(true)
+ .write(true)
+ .read(true)
+ .open(path));
+
+ serde_json::from_reader(&mut file).unwrap_or_default()
+ } else {
+ Default::default()
+ }
+ }
+
+ /// Updates the actual toolstate of a tool.
+ ///
+ /// The toolstates are saved to the file specified by the key
+ /// `rust.save-toolstates` in `config.toml`. If unspecified, nothing will be
+ /// done. The file is updated immediately after this function completes.
+ pub fn save_toolstate(&self, tool: &str, state: ToolState) {
+ if let Some(ref path) = self.config.save_toolstates {
+ if let Some(parent) = path.parent() {
+ // Ensure the parent directory always exists
+ t!(std::fs::create_dir_all(parent));
+ }
+ let mut file = t!(fs::OpenOptions::new()
+ .create(true)
+ .read(true)
+ .write(true)
+ .open(path));
+
+ let mut current_toolstates: HashMap<Box<str>, ToolState> =
+ serde_json::from_reader(&mut file).unwrap_or_default();
+ current_toolstates.insert(tool.into(), state);
+ t!(file.seek(SeekFrom::Start(0)));
+ t!(file.set_len(0));
+ t!(serde_json::to_writer(file, ¤t_toolstates));
+ }
+ }
+}
+
+/// This function `commit_toolstate_change` provides functionality for pushing a change
+/// to the `rust-toolstate` repository.
+///
+/// The function relies on a GitHub bot user, which should have a Personal access
+/// token defined in the environment variable $TOOLSTATE_REPO_ACCESS_TOKEN. If for
+/// some reason you need to change the token, please update the Azure Pipelines
+/// variable group.
+///
+/// 1. Generate a new Personal access token:
+///
+/// * Login to the bot account, and go to Settings -> Developer settings ->
+/// Personal access tokens
+/// * Click "Generate new token"
+/// * Enable the "public_repo" permission, then click "Generate token"
+/// * Copy the generated token (should be a 40-digit hexadecimal number).
+/// Save it somewhere secure, as the token would be gone once you leave
+/// the page.
+///
+/// 2. Update the variable group in Azure Pipelines
+///
+/// * Ping a member of the infrastructure team to do this.
+///
+/// 4. Replace the email address below if the bot account identity is changed
+///
+/// * See <https://help.github.com/articles/about-commit-email-addresses/>
+/// if a private email by GitHub is wanted.
+fn commit_toolstate_change(
+ current_toolstate: &ToolstateData,
+ in_beta_week: bool,
+) {
+ fn git_config(key: &str, value: &str) {
+ let status = Command::new("git").arg("config").arg("--global").arg(key).arg(value).status();
+ let success = match status {
+ Ok(s) => s.success(),
+ Err(_) => false,
+ };
+ if !success {
+ panic!("git config key={} value={} successful (status: {:?})", key, value, status);
+ }
+ }
+
+ // If changing anything here, then please check that src/ci/publish_toolstate.sh is up to date
+ // as well.
+ git_config("user.email", "7378925+rust-toolstate-update@users.noreply.github.com");
+ git_config("user.name", "Rust Toolstate Update");
+ git_config("credential.helper", "store");
+
+ let credential = format!(
+ "https://{}:x-oauth-basic@github.com\n",
+ t!(env::var("TOOLSTATE_REPO_ACCESS_TOKEN")),
+ );
+ let git_credential_path = PathBuf::from(t!(env::var("HOME"))).join(".git-credentials");
+ t!(fs::write(&git_credential_path, credential));
+
+ let status = Command::new("git").arg("clone")
+ .arg("--depth=1")
+ .arg(t!(env::var("TOOLSTATE_REPO")))
+ .status();
+ let success = match status {
+ Ok(s) => s.success(),
+ Err(_) => false,
+ };
+ if !success {
+ panic!("git clone successful (status: {:?})", status);
+ }
+
+ let old_toolstate = t!(fs::read("rust-toolstate/_data/latest.json"));
+ let old_toolstate: Vec<RepoState> = t!(serde_json::from_slice(&old_toolstate));
+
+ let message = format!("({} CI update)", OS.expect("linux/windows only"));
+ let mut success = false;
+ for _ in 1..=5 {
+ // Update the toolstate results (the new commit-to-toolstate mapping) in the toolstate repo.
+ change_toolstate(¤t_toolstate, &old_toolstate, in_beta_week);
+
+ // `git commit` failing means nothing to commit.
+ let status = t!(Command::new("git")
+ .current_dir("rust-toolstate")
+ .arg("commit")
+ .arg("-a")
+ .arg("-m")
+ .arg(&message)
+ .status());
+ if !status.success() {
+ success = true;
+ break;
+ }
+
+ let status = t!(Command::new("git")
+ .current_dir("rust-toolstate")
+ .arg("push")
+ .arg("origin")
+ .arg("master")
+ .status());
+ // If we successfully push, exit.
+ if status.success() {
+ success = true;
+ break;
+ }
+ eprintln!("Sleeping for 3 seconds before retrying push");
+ std::thread::sleep(std::time::Duration::from_secs(3));
+ let status = t!(Command::new("git")
+ .current_dir("rust-toolstate")
+ .arg("fetch")
+ .arg("origin")
+ .arg("master")
+ .status());
+ assert!(status.success());
+ let status = t!(Command::new("git")
+ .current_dir("rust-toolstate")
+ .arg("reset")
+ .arg("--hard")
+ .arg("origin/master")
+ .status());
+ assert!(status.success());
+ }
+
+ if !success {
+ panic!("Failed to update toolstate repository with new data");
+ }
+}
+
+fn change_toolstate(
+ current_toolstate: &ToolstateData,
+ old_toolstate: &[RepoState],
+ in_beta_week: bool,
+) {
+ let mut regressed = false;
+ for repo_state in old_toolstate {
+ let tool = &repo_state.tool;
+ let state = if cfg!(linux) {
+ &repo_state.linux
+ } else if cfg!(windows) {
+ &repo_state.windows
+ } else {
+ unimplemented!()
+ };
+ let new_state = current_toolstate[tool.as_str()];
+
+ if new_state != *state {
+ eprintln!("The state of `{}` has changed from `{}` to `{}`", tool, state, new_state);
+ if (new_state as u8) < (*state as u8) {
+ if !["rustc-guide", "miri", "embedded-book"].contains(&tool.as_str()) {
+ regressed = true;
+ }
+ }
+ }
+ }
+
+ if regressed && in_beta_week {
+ std::process::exit(1);
+ }
+
+ let commit = t!(std::process::Command::new("git")
+ .arg("rev-parse")
+ .arg("HEAD")
+ .output());
+ let commit = t!(String::from_utf8(commit.stdout));
+
+ let toolstate_serialized = t!(serde_json::to_string(¤t_toolstate));
+
+ let history_path = format!("rust-toolstate/history/{}.tsv", OS.expect("linux/windows only"));
+ let mut file = t!(fs::read_to_string(&history_path));
+ let end_of_first_line = file.find('\n').unwrap();
+ file.insert_str(end_of_first_line, &format!("{}\t{}\n", commit, toolstate_serialized));
+ t!(fs::write(&history_path, file));
+}
+
+#[derive(Debug, Serialize, Deserialize)]
+struct RepoState {
+ tool: String,
+ windows: ToolState,
+ linux: ToolState,
+ commit: String,
+ datetime: String,
+}
diff --git a/src/bootstrap/util.rs b/src/bootstrap/util.rs
index 6f8a630..6824b7a 100644
--- a/src/bootstrap/util.rs
+++ b/src/bootstrap/util.rs
@@ -15,6 +15,7 @@
use crate::config::Config;
use crate::builder::Builder;
+use crate::cache::Interned;
/// Returns the `name` as the filename of a static library for `target`.
pub fn staticlib(name: &str, target: &str) -> String {
@@ -306,3 +307,15 @@
false
}
}
+
+pub fn use_host_linker(target: &Interned<String>) -> bool {
+ // FIXME: this information should be gotten by checking the linker flavor
+ // of the rustc target
+ !(
+ target.contains("emscripten") ||
+ target.contains("wasm32") ||
+ target.contains("nvptx") ||
+ target.contains("fortanix") ||
+ target.contains("fuchsia")
+ )
+}
diff --git a/src/ci/azure-pipelines/auto.yml b/src/ci/azure-pipelines/auto.yml
index 70d6bad..5248e41 100644
--- a/src/ci/azure-pipelines/auto.yml
+++ b/src/ci/azure-pipelines/auto.yml
@@ -163,7 +163,7 @@
NO_LLVM_ASSERTIONS: 1
# MSVC tools tests
x86_64-msvc-tools:
- SCRIPT: src/ci/docker/x86_64-gnu-tools/checktools.sh x.py /tmp/toolstate/toolstates.json windows
+ SCRIPT: src/ci/docker/x86_64-gnu-tools/checktools.sh x.py
RUST_CONFIGURE_ARGS: --build=x86_64-pc-windows-msvc --save-toolstates=/tmp/toolstate/toolstates.json
# 32/64-bit MinGW builds.
diff --git a/src/ci/azure-pipelines/master.yml b/src/ci/azure-pipelines/master.yml
index e2baa92..9c5a15a 100644
--- a/src/ci/azure-pipelines/master.yml
+++ b/src/ci/azure-pipelines/master.yml
@@ -16,10 +16,7 @@
- checkout: self
fetchDepth: 2
-- script: |
- export MESSAGE_FILE=$(mktemp -t msg.XXXXXX)
- . src/ci/docker/x86_64-gnu-tools/repo.sh
- commit_toolstate_change "$MESSAGE_FILE" "$BUILD_SOURCESDIRECTORY/src/tools/publish_toolstate.py" "$(git rev-parse HEAD)" "$(git log --format=%s -n1 HEAD)" "$MESSAGE_FILE" "$TOOLSTATE_REPO_ACCESS_TOKEN"
+- script: src/ci/publish_toolstate.sh
displayName: Publish toolstate
env:
TOOLSTATE_REPO_ACCESS_TOKEN: $(TOOLSTATE_REPO_ACCESS_TOKEN)
diff --git a/src/ci/docker/README.md b/src/ci/docker/README.md
index a2d83ec..872f2c3 100644
--- a/src/ci/docker/README.md
+++ b/src/ci/docker/README.md
@@ -16,6 +16,13 @@
Images will output artifacts in an `obj` dir at the root of a repository.
+**NOTE**: Re-using the same `obj` dir with different docker images with
+the same target triple (e.g. `dist-x86_64-linux` and `dist-various-1`)
+may result in strange linker errors, due shared library versions differing between platforms.
+
+If you encounter any issues when using multiple Docker images, try deleting your `obj` directory
+before running your command.
+
## Filesystem layout
- Each directory, excluding `scripts` and `disabled`, corresponds to a docker image
diff --git a/src/ci/docker/dist-various-2/build-wasi-toolchain.sh b/src/ci/docker/dist-various-2/build-wasi-toolchain.sh
index 17aa789..925d5ca 100755
--- a/src/ci/docker/dist-various-2/build-wasi-toolchain.sh
+++ b/src/ci/docker/dist-various-2/build-wasi-toolchain.sh
@@ -12,7 +12,7 @@
git clone https://github.com/CraneStation/wasi-libc
cd wasi-libc
-git reset --hard a94d2d04e7722b323573da2bd04e909a5763d35b
+git reset --hard f645f498dfbbbc00a7a97874d33082d3605c3f21
make -j$(nproc) INSTALL_DIR=/wasm32-wasi install
cd ..
diff --git a/src/ci/docker/x86_64-gnu-tools/Dockerfile b/src/ci/docker/x86_64-gnu-tools/Dockerfile
index 7687a6c..5119340 100644
--- a/src/ci/docker/x86_64-gnu-tools/Dockerfile
+++ b/src/ci/docker/x86_64-gnu-tools/Dockerfile
@@ -17,9 +17,7 @@
COPY scripts/sccache.sh /scripts/
RUN sh /scripts/sccache.sh
-COPY x86_64-gnu-tools/checkregression.py /tmp/
COPY x86_64-gnu-tools/checktools.sh /tmp/
-COPY x86_64-gnu-tools/repo.sh /tmp/
# Run rustbook with `linkcheck` feature enabled
ENV CHECK_LINKS 1
@@ -27,4 +25,4 @@
ENV RUST_CONFIGURE_ARGS \
--build=x86_64-unknown-linux-gnu \
--save-toolstates=/tmp/toolstate/toolstates.json
-ENV SCRIPT /tmp/checktools.sh ../x.py /tmp/toolstate/toolstates.json linux
+ENV SCRIPT /tmp/checktools.sh ../x.py
diff --git a/src/ci/docker/x86_64-gnu-tools/checkregression.py b/src/ci/docker/x86_64-gnu-tools/checkregression.py
deleted file mode 100755
index 4fbb8c4..0000000
--- a/src/ci/docker/x86_64-gnu-tools/checkregression.py
+++ /dev/null
@@ -1,48 +0,0 @@
-#!/usr/bin/env python
-# -*- coding: utf-8 -*-
-
-## This script has two purposes: detect any tool that *regressed*, which is used
-## during the week before the beta branches to reject PRs; and detect any tool
-## that *changed* to see if we need to update the toolstate repo.
-
-import sys
-import json
-
-# Regressions for these tools during the beta cutoff week do not cause failure.
-# See `status_check` in `checktools.sh` for tools that have to pass on the
-# beta/stable branches.
-REGRESSION_OK = ["rustc-guide", "miri", "embedded-book"]
-
-if __name__ == '__main__':
- os_name = sys.argv[1]
- toolstate_file = sys.argv[2]
- current_state = sys.argv[3]
- verb = sys.argv[4] # 'regressed' or 'changed'
-
- with open(toolstate_file, 'r') as f:
- toolstate = json.load(f)
- with open(current_state, 'r') as f:
- current = json.load(f)
-
- regressed = False
- for cur in current:
- tool = cur['tool']
- state = cur[os_name]
- new_state = toolstate.get(tool, '')
- if verb == 'regressed':
- updated = new_state < state
- elif verb == 'changed':
- updated = new_state != state
- else:
- print('Unknown verb {}'.format(updated))
- sys.exit(2)
- if updated:
- print(
- 'The state of "{}" has {} from "{}" to "{}"'
- .format(tool, verb, state, new_state)
- )
- if not (verb == 'regressed' and tool in REGRESSION_OK):
- regressed = True
-
- if regressed:
- sys.exit(1)
diff --git a/src/ci/docker/x86_64-gnu-tools/checktools.sh b/src/ci/docker/x86_64-gnu-tools/checktools.sh
index ebb8c0b..e57fe22 100755
--- a/src/ci/docker/x86_64-gnu-tools/checktools.sh
+++ b/src/ci/docker/x86_64-gnu-tools/checktools.sh
@@ -3,18 +3,6 @@
set -eu
X_PY="$1"
-TOOLSTATE_FILE="$(realpath -m $2)"
-OS="$3"
-COMMIT="$(git rev-parse HEAD)"
-CHANGED_FILES="$(git diff --name-status HEAD HEAD^)"
-SIX_WEEK_CYCLE="$(( ($(date +%s) / 86400 - 20) % 42 ))"
-# ^ Number of days after the last promotion of beta.
-# Its value is 41 on the Tuesday where "Promote master to beta (T-2)" happens.
-# The Wednesday after this has value 0.
-# We track this value to prevent regressing tools in the last week of the 6-week cycle.
-
-mkdir -p "$(dirname $TOOLSTATE_FILE)"
-touch "$TOOLSTATE_FILE"
# Try to test all the tools and store the build/test success in the TOOLSTATE_FILE
@@ -34,106 +22,4 @@
set -e
-cat "$TOOLSTATE_FILE"
-echo
-
-# This function checks if a particular tool is *not* in status "test-pass".
-check_tool_failed() {
- grep -vq '"'"$1"'":"test-pass"' "$TOOLSTATE_FILE"
-}
-
-# This function checks that if a tool's submodule changed, the tool's state must improve
-verify_submodule_changed() {
- echo "Verifying status of $1..."
- if echo "$CHANGED_FILES" | grep -q "^M[[:blank:]]$2$"; then
- echo "This PR updated '$2', verifying if status is 'test-pass'..."
- if check_tool_failed "$1"; then
- echo
- echo "⚠️ We detected that this PR updated '$1', but its tests failed."
- echo
- echo "If you do intend to update '$1', please check the error messages above and"
- echo "commit another update."
- echo
- echo "If you do NOT intend to update '$1', please ensure you did not accidentally"
- echo "change the submodule at '$2'. You may ask your reviewer for the"
- echo "proper steps."
- exit 3
- fi
- fi
-}
-
-# deduplicates the submodule check and the assertion that on beta some tools MUST be passing.
-# $1 should be "submodule_changed" to only check tools that got changed by this PR,
-# or "beta_required" to check all tools that have $2 set to "beta".
-check_dispatch() {
- if [ "$1" = submodule_changed ]; then
- # ignore $2 (branch id)
- verify_submodule_changed $3 $4
- elif [ "$2" = beta ]; then
- echo "Requiring test passing for $3..."
- if check_tool_failed "$3"; then
- exit 4
- fi
- fi
-}
-
-# List all tools here.
-# This function gets called with "submodule_changed" for each PR that changed a submodule,
-# and with "beta_required" for each PR that lands on beta/stable.
-# The purpose of this function is to *reject* PRs if a tool is not "test-pass" and
-# (a) the tool's submodule has been updated, or (b) we landed on beta/stable and the
-# tool has to "test-pass" on that branch.
-status_check() {
- check_dispatch $1 beta book src/doc/book
- check_dispatch $1 beta nomicon src/doc/nomicon
- check_dispatch $1 beta reference src/doc/reference
- check_dispatch $1 beta rust-by-example src/doc/rust-by-example
- check_dispatch $1 beta edition-guide src/doc/edition-guide
- check_dispatch $1 beta rls src/tools/rls
- check_dispatch $1 beta rustfmt src/tools/rustfmt
- check_dispatch $1 beta clippy-driver src/tools/clippy
- # These tools are not required on the beta/stable branches, but they *do* cause
- # PRs to fail if a submodule update does not fix them.
- # They will still cause failure during the beta cutoff week, unless `checkregression.py`
- # exempts them from that.
- check_dispatch $1 nightly miri src/tools/miri
- check_dispatch $1 nightly embedded-book src/doc/embedded-book
- check_dispatch $1 nightly rustc-guide src/doc/rustc-guide
-}
-
-# If this PR is intended to update one of these tools, do not let the build pass
-# when they do not test-pass.
-
-status_check "submodule_changed"
-
-CHECK_NOT="$(readlink -f "$(dirname $0)/checkregression.py")"
-# This callback is called by `commit_toolstate_change`, see `repo.sh`.
-change_toolstate() {
- # only update the history
- if python2.7 "$CHECK_NOT" "$OS" "$TOOLSTATE_FILE" "_data/latest.json" changed; then
- echo 'Toolstate is not changed. Not updating.'
- else
- if [ $SIX_WEEK_CYCLE -ge 35 ]; then
- # Reject any regressions during the week before beta cutoff.
- python2.7 "$CHECK_NOT" "$OS" "$TOOLSTATE_FILE" "_data/latest.json" regressed
- fi
- sed -i "1 a\\
-$COMMIT\t$(cat "$TOOLSTATE_FILE")
-" "history/$OS.tsv"
- fi
-}
-
-if [ "$RUST_RELEASE_CHANNEL" = nightly ]; then
- if [ -n "${TOOLSTATE_PUBLISH+is_set}" ]; then
- . "$(dirname $0)/repo.sh"
- MESSAGE_FILE=$(mktemp -t msg.XXXXXX)
- echo "($OS CI update)" > "$MESSAGE_FILE"
- commit_toolstate_change "$MESSAGE_FILE" change_toolstate
- rm -f "$MESSAGE_FILE"
- fi
- exit 0
-fi
-
-# abort compilation if an important tool doesn't build
-# (this code is reachable if not on the nightly channel)
-status_check "beta_required"
+python2.7 "$X_PY" test check-tools
diff --git a/src/ci/docker/x86_64-gnu-tools/repo.sh b/src/ci/docker/x86_64-gnu-tools/repo.sh
deleted file mode 100644
index 82700a0..0000000
--- a/src/ci/docker/x86_64-gnu-tools/repo.sh
+++ /dev/null
@@ -1,68 +0,0 @@
-#!/bin/sh
-
-# This file provides the function `commit_toolstate_change` for pushing a change
-# to the `rust-toolstate` repository.
-#
-# The function relies on a GitHub bot user, which should have a Personal access
-# token defined in the environment variable $TOOLSTATE_REPO_ACCESS_TOKEN. If for
-# some reason you need to change the token, please update the Azure Pipelines
-# variable group.
-#
-# 1. Generate a new Personal access token:
-#
-# * Login to the bot account, and go to Settings -> Developer settings ->
-# Personal access tokens
-# * Click "Generate new token"
-# * Enable the "public_repo" permission, then click "Generate token"
-# * Copy the generated token (should be a 40-digit hexadecimal number).
-# Save it somewhere secure, as the token would be gone once you leave
-# the page.
-#
-# 2. Update the variable group in Azure Pipelines
-#
-# * Ping a member of the infrastructure team to do this.
-#
-# 4. Replace the email address below if the bot account identity is changed
-#
-# * See <https://help.github.com/articles/about-commit-email-addresses/>
-# if a private email by GitHub is wanted.
-
-commit_toolstate_change() {
- OLDFLAGS="$-"
- set -eu
-
- git config --global user.email '7378925+rust-toolstate-update@users.noreply.github.com'
- git config --global user.name 'Rust Toolstate Update'
- git config --global credential.helper store
- printf 'https://%s:x-oauth-basic@github.com\n' "$TOOLSTATE_REPO_ACCESS_TOKEN" \
- > "$HOME/.git-credentials"
- git clone --depth=1 $TOOLSTATE_REPO
-
- cd rust-toolstate
- FAILURE=1
- MESSAGE_FILE="$1"
- shift
- for RETRY_COUNT in 1 2 3 4 5; do
- # Call the callback.
- # - If we are in the `auto` branch (pre-landing), this is called from `checktools.sh` and
- # the callback is `change_toolstate` in that file. The purpose of this is to publish the
- # test results (the new commit-to-toolstate mapping) in the toolstate repo.
- # - If we are in the `master` branch (post-landing), this is called by the CI pipeline
- # and the callback is `src/tools/publish_toolstate.py`. The purpose is to publish
- # the new "current" toolstate in the toolstate repo.
- "$@"
- # `git commit` failing means nothing to commit.
- FAILURE=0
- git commit -a -F "$MESSAGE_FILE" || break
- # On failure randomly sleep for 0 to 3 seconds as a crude way to introduce jittering.
- git push origin master && break || sleep $(LC_ALL=C tr -cd 0-3 < /dev/urandom | head -c 1)
- FAILURE=1
- git fetch origin master
- git reset --hard origin/master
- done
- cd ..
-
- set +eu
- set "-$OLDFLAGS"
- return $FAILURE
-}
diff --git a/src/ci/publish_toolstate.sh b/src/ci/publish_toolstate.sh
new file mode 100755
index 0000000..d8ff740
--- /dev/null
+++ b/src/ci/publish_toolstate.sh
@@ -0,0 +1,33 @@
+#!/bin/sh
+
+set -eu
+
+# The following lines are also found in src/bootstrap/toolstate.rs,
+# so if updating here, please also update that file.
+
+export MESSAGE_FILE=$(mktemp -t msg.XXXXXX)
+
+git config --global user.email '7378925+rust-toolstate-update@users.noreply.github.com'
+git config --global user.name 'Rust Toolstate Update'
+git config --global credential.helper store
+printf 'https://%s:x-oauth-basic@github.com\n' "$TOOLSTATE_REPO_ACCESS_TOKEN" \
+ > "$HOME/.git-credentials"
+git clone --depth=1 $TOOLSTATE_REPO
+
+cd rust-toolstate
+FAILURE=1
+for RETRY_COUNT in 1 2 3 4 5; do
+ # The purpose is to publish the new "current" toolstate in the toolstate repo.
+ "$BUILD_SOURCESDIRECTORY/src/tools/publish_toolstate.py" "$(git rev-parse HEAD)" \
+ "$(git log --format=%s -n1 HEAD)" \
+ "$MESSAGE_FILE" \
+ "$TOOLSTATE_REPO_ACCESS_TOKEN"
+ # `git commit` failing means nothing to commit.
+ FAILURE=0
+ git commit -a -F "$MESSAGE_FILE" || break
+ # On failure randomly sleep for 0 to 3 seconds as a crude way to introduce jittering.
+ git push origin master && break || sleep $(LC_ALL=C tr -cd 0-3 < /dev/urandom | head -c 1)
+ FAILURE=1
+ git fetch origin master
+ git reset --hard origin/master
+done
diff --git a/src/ci/run.sh b/src/ci/run.sh
index ae5b224..38d1d2b 100755
--- a/src/ci/run.sh
+++ b/src/ci/run.sh
@@ -23,7 +23,7 @@
ci_dir=`cd $(dirname $0) && pwd`
source "$ci_dir/shared.sh"
-if [ ! isCI ] || isCiBranch auto || isCiBranch beta; then
+if ! isCI || isCiBranch auto || isCiBranch beta; then
RUST_CONFIGURE_ARGS="$RUST_CONFIGURE_ARGS --set build.print-step-timings --enable-verbose-tests"
fi
diff --git a/src/doc/rustc-guide b/src/doc/rustc-guide
index 934380b..7c56708 160000
--- a/src/doc/rustc-guide
+++ b/src/doc/rustc-guide
@@ -1 +1 @@
-Subproject commit 934380b7cfceaaa4e1b9bb0de4a372f32725520b
+Subproject commit 7c56708aab7986ca390221e8e8902f7de7f9b076
diff --git a/src/liballoc/alloc/tests.rs b/src/liballoc/alloc/tests.rs
index 956298d..c902971 100644
--- a/src/liballoc/alloc/tests.rs
+++ b/src/liballoc/alloc/tests.rs
@@ -22,7 +22,7 @@
}
#[bench]
-#[cfg(not(miri))] // Miri does not support benchmarks
+#[cfg_attr(miri, ignore)] // Miri does not support benchmarks
fn alloc_owned_small(b: &mut Bencher) {
b.iter(|| {
let _: Box<_> = box 10;
diff --git a/src/liballoc/borrow.rs b/src/liballoc/borrow.rs
index d2bdda8..fc96045 100644
--- a/src/liballoc/borrow.rs
+++ b/src/liballoc/borrow.rs
@@ -195,14 +195,10 @@
}
fn clone_from(&mut self, source: &Self) {
- if let Owned(ref mut dest) = *self {
- if let Owned(ref o) = *source {
- o.borrow().clone_into(dest);
- return;
- }
+ match (self, source) {
+ (&mut Owned(ref mut dest), &Owned(ref o)) => o.borrow().clone_into(dest),
+ (t, s) => *t = s.clone(),
}
-
- *self = source.clone();
}
}
@@ -449,9 +445,7 @@
fn add_assign(&mut self, rhs: &'a str) {
if self.is_empty() {
*self = Cow::Borrowed(rhs)
- } else if rhs.is_empty() {
- return;
- } else {
+ } else if !rhs.is_empty() {
if let Cow::Borrowed(lhs) = *self {
let mut s = String::with_capacity(lhs.len() + rhs.len());
s.push_str(lhs);
@@ -467,9 +461,7 @@
fn add_assign(&mut self, rhs: Cow<'a, str>) {
if self.is_empty() {
*self = rhs
- } else if rhs.is_empty() {
- return;
- } else {
+ } else if !rhs.is_empty() {
if let Cow::Borrowed(lhs) = *self {
let mut s = String::with_capacity(lhs.len() + rhs.len());
s.push_str(lhs);
diff --git a/src/liballoc/boxed.rs b/src/liballoc/boxed.rs
index 51ad3a0..1c39a37 100644
--- a/src/liballoc/boxed.rs
+++ b/src/liballoc/boxed.rs
@@ -61,7 +61,60 @@
//! T` obtained from [`Box::<T>::into_raw`] may be deallocated using the
//! [`Global`] allocator with [`Layout::for_value(&*value)`].
//!
+//! So long as `T: Sized`, a `Box<T>` is guaranteed to be represented
+//! as a single pointer and is also ABI-compatible with C pointers
+//! (i.e. the C type `T*`). This means that if you have extern "C"
+//! Rust functions that will be called from C, you can define those
+//! Rust functions using `Box<T>` types, and use `T*` as corresponding
+//! type on the C side. As an example, consider this C header which
+//! declares functions that create and destroy some kind of `Foo`
+//! value:
//!
+//! ```c
+//! /* C header */
+//!
+//! /* Returns ownership to the caller */
+//! struct Foo* foo_new(void);
+//!
+//! /* Takes ownership from the caller; no-op when invoked with NULL */
+//! void foo_delete(struct Foo*);
+//! ```
+//!
+//! These two functions might be implemented in Rust as follows. Here, the
+//! `struct Foo*` type from C is translated to `Box<Foo>`, which captures
+//! the ownership constraints. Note also that the nullable argument to
+//! `foo_delete` is represented in Rust as `Option<Box<Foo>>`, since `Box<Foo>`
+//! cannot be null.
+//!
+//! ```
+//! #[repr(C)]
+//! pub struct Foo;
+//!
+//! #[no_mangle]
+//! pub extern "C" fn foo_new() -> Box<Foo> {
+//! Box::new(Foo)
+//! }
+//!
+//! #[no_mangle]
+//! pub extern "C" fn foo_delete(_: Option<Box<Foo>>) {}
+//! ```
+//!
+//! Even though `Box<T>` has the same representation and C ABI as a C pointer,
+//! this does not mean that you can convert an arbitrary `T*` into a `Box<T>`
+//! and expect things to work. `Box<T>` values will always be fully aligned,
+//! non-null pointers. Moreover, the destructor for `Box<T>` will attempt to
+//! free the value with the global allocator. In general, the best practice
+//! is to only use `Box<T>` for pointers that originated from the global
+//! allocator.
+//!
+//! **Important.** At least at present, you should avoid using
+//! `Box<T>` types for functions that are defined in C but invoked
+//! from Rust. In those cases, you should directly mirror the C types
+//! as closely as possible. Using types like `Box<T>` where the C
+//! definition is just using `T*` can lead to undefined behavior, as
+//! described in [rust-lang/unsafe-code-guidelines#198][ucg#198].
+//!
+//! [ucg#198]: https://github.com/rust-lang/unsafe-code-guidelines/issues/198
//! [dereferencing]: ../../std/ops/trait.Deref.html
//! [`Box`]: struct.Box.html
//! [`Box<T>`]: struct.Box.html
diff --git a/src/liballoc/collections/linked_list.rs b/src/liballoc/collections/linked_list.rs
index a0c9263..6ee2283 100644
--- a/src/liballoc/collections/linked_list.rs
+++ b/src/liballoc/collections/linked_list.rs
@@ -808,7 +808,21 @@
#[stable(feature = "rust1", since = "1.0.0")]
unsafe impl<#[may_dangle] T> Drop for LinkedList<T> {
fn drop(&mut self) {
- while let Some(_) = self.pop_front_node() {}
+ struct DropGuard<'a, T>(&'a mut LinkedList<T>);
+
+ impl<'a, T> Drop for DropGuard<'a, T> {
+ fn drop(&mut self) {
+ // Continue the same loop we do below. This only runs when a destructor has
+ // panicked. If another one panics this will abort.
+ while let Some(_) = self.0.pop_front_node() {}
+ }
+ }
+
+ while let Some(node) = self.pop_front_node() {
+ let guard = DropGuard(self);
+ drop(node);
+ mem::forget(guard);
+ }
}
}
diff --git a/src/liballoc/collections/linked_list/tests.rs b/src/liballoc/collections/linked_list/tests.rs
index 94b92df..1b1d8ea 100644
--- a/src/liballoc/collections/linked_list/tests.rs
+++ b/src/liballoc/collections/linked_list/tests.rs
@@ -182,7 +182,7 @@
#[test]
#[cfg_attr(target_os = "emscripten", ignore)]
-#[cfg(not(miri))] // Miri does not support threads
+#[cfg_attr(miri, ignore)] // Miri does not support threads
fn test_send() {
let n = list_from(&[1, 2, 3]);
thread::spawn(move || {
diff --git a/src/liballoc/collections/vec_deque.rs b/src/liballoc/collections/vec_deque.rs
index 7795083..9136136 100644
--- a/src/liballoc/collections/vec_deque.rs
+++ b/src/liballoc/collections/vec_deque.rs
@@ -144,11 +144,23 @@
#[stable(feature = "rust1", since = "1.0.0")]
unsafe impl<#[may_dangle] T> Drop for VecDeque<T> {
fn drop(&mut self) {
+ /// Runs the destructor for all items in the slice when it gets dropped (normally or
+ /// during unwinding).
+ struct Dropper<'a, T>(&'a mut [T]);
+
+ impl<'a, T> Drop for Dropper<'a, T> {
+ fn drop(&mut self) {
+ unsafe {
+ ptr::drop_in_place(self.0);
+ }
+ }
+ }
+
let (front, back) = self.as_mut_slices();
unsafe {
+ let _back_dropper = Dropper(back);
// use drop for [T]
ptr::drop_in_place(front);
- ptr::drop_in_place(back);
}
// RawVec handles deallocation
}
@@ -2809,7 +2821,22 @@
#[stable(feature = "rust1", since = "1.0.0")]
impl<A> Extend<A> for VecDeque<A> {
fn extend<T: IntoIterator<Item = A>>(&mut self, iter: T) {
- iter.into_iter().for_each(move |elt| self.push_back(elt));
+ // This function should be the moral equivalent of:
+ //
+ // for item in iter.into_iter() {
+ // self.push_back(item);
+ // }
+ let mut iter = iter.into_iter();
+ while let Some(element) = iter.next() {
+ if self.len() == self.capacity() {
+ let (lower, _) = iter.size_hint();
+ self.reserve(lower.saturating_add(1));
+ }
+
+ let head = self.head;
+ self.head = self.wrap_add(self.head, 1);
+ unsafe { self.buffer_write(head, element); }
+ }
}
}
diff --git a/src/liballoc/collections/vec_deque/tests.rs b/src/liballoc/collections/vec_deque/tests.rs
index 8dc097c..f2ce5b1 100644
--- a/src/liballoc/collections/vec_deque/tests.rs
+++ b/src/liballoc/collections/vec_deque/tests.rs
@@ -3,7 +3,7 @@
use ::test;
#[bench]
-#[cfg(not(miri))] // Miri does not support benchmarks
+#[cfg_attr(miri, ignore)] // Miri does not support benchmarks
fn bench_push_back_100(b: &mut test::Bencher) {
let mut deq = VecDeque::with_capacity(101);
b.iter(|| {
@@ -16,7 +16,7 @@
}
#[bench]
-#[cfg(not(miri))] // Miri does not support benchmarks
+#[cfg_attr(miri, ignore)] // Miri does not support benchmarks
fn bench_push_front_100(b: &mut test::Bencher) {
let mut deq = VecDeque::with_capacity(101);
b.iter(|| {
@@ -29,7 +29,7 @@
}
#[bench]
-#[cfg(not(miri))] // Miri does not support benchmarks
+#[cfg_attr(miri, ignore)] // Miri does not support benchmarks
fn bench_pop_back_100(b: &mut test::Bencher) {
let mut deq = VecDeque::<i32>::with_capacity(101);
@@ -43,7 +43,7 @@
}
#[bench]
-#[cfg(not(miri))] // Miri does not support benchmarks
+#[cfg_attr(miri, ignore)] // Miri does not support benchmarks
fn bench_pop_front_100(b: &mut test::Bencher) {
let mut deq = VecDeque::<i32>::with_capacity(101);
diff --git a/src/liballoc/rc.rs b/src/liballoc/rc.rs
index 2254cde..1ff1c3c 100644
--- a/src/liballoc/rc.rs
+++ b/src/liballoc/rc.rs
@@ -1648,10 +1648,8 @@
/// Returns a raw pointer to the object `T` pointed to by this `Weak<T>`.
///
- /// It is up to the caller to ensure that the object is still alive when accessing it through
- /// the pointer.
- ///
- /// The pointer may be [`null`] or be dangling in case the object has already been destroyed.
+ /// The pointer is valid only if there are some strong references. The pointer may be dangling
+ /// or even [`null`] otherwise.
///
/// # Examples
///
@@ -1731,14 +1729,18 @@
/// This can be used to safely get a strong reference (by calling [`upgrade`]
/// later) or to deallocate the weak count by dropping the `Weak<T>`.
///
- /// It takes ownership of one weak count. In case a [`null`] is passed, a dangling [`Weak`] is
- /// returned.
+ /// It takes ownership of one weak count (with the exception of pointers created by [`new`],
+ /// as these don't have any corresponding weak count).
///
/// # Safety
///
- /// The pointer must represent one valid weak count. In other words, it must point to `T` which
- /// is or *was* managed by an [`Rc`] and the weak count of that [`Rc`] must not have reached
- /// 0. It is allowed for the strong count to be 0.
+ /// The pointer must have originated from the [`into_raw`] (or [`as_raw`], provided there was
+ /// a corresponding [`forget`] on the `Weak<T>`) and must still own its potential weak reference
+ /// count.
+ ///
+ /// It is allowed for the strong count to be 0 at the time of calling this, but the weak count
+ /// must be non-zero or the pointer must have originated from a dangling `Weak<T>` (one created
+ /// by [`new`]).
///
/// # Examples
///
@@ -1763,11 +1765,13 @@
/// assert!(unsafe { Weak::from_raw(raw_2) }.upgrade().is_none());
/// ```
///
- /// [`null`]: ../../std/ptr/fn.null.html
/// [`into_raw`]: struct.Weak.html#method.into_raw
/// [`upgrade`]: struct.Weak.html#method.upgrade
/// [`Rc`]: struct.Rc.html
/// [`Weak`]: struct.Weak.html
+ /// [`as_raw`]: struct.Weak.html#method.as_raw
+ /// [`new`]: struct.Weak.html#method.new
+ /// [`forget`]: ../../std/mem/fn.forget.html
#[unstable(feature = "weak_into_raw", issue = "60728")]
pub unsafe fn from_raw(ptr: *const T) -> Self {
if ptr.is_null() {
diff --git a/src/liballoc/sync.rs b/src/liballoc/sync.rs
index 7bf2ff1..19b0086 100644
--- a/src/liballoc/sync.rs
+++ b/src/liballoc/sync.rs
@@ -1324,10 +1324,8 @@
/// Returns a raw pointer to the object `T` pointed to by this `Weak<T>`.
///
- /// It is up to the caller to ensure that the object is still alive when accessing it through
- /// the pointer.
- ///
- /// The pointer may be [`null`] or be dangling in case the object has already been destroyed.
+ /// The pointer is valid only if there are some strong references. The pointer may be dangling
+ /// or even [`null`] otherwise.
///
/// # Examples
///
@@ -1408,14 +1406,18 @@
/// This can be used to safely get a strong reference (by calling [`upgrade`]
/// later) or to deallocate the weak count by dropping the `Weak<T>`.
///
- /// It takes ownership of one weak count. In case a [`null`] is passed, a dangling [`Weak`] is
- /// returned.
+ /// It takes ownership of one weak count (with the exception of pointers created by [`new`],
+ /// as these don't have any corresponding weak count).
///
/// # Safety
///
- /// The pointer must represent one valid weak count. In other words, it must point to `T` which
- /// is or *was* managed by an [`Arc`] and the weak count of that [`Arc`] must not have reached
- /// 0. It is allowed for the strong count to be 0.
+ /// The pointer must have originated from the [`into_raw`] (or [`as_raw'], provided there was
+ /// a corresponding [`forget`] on the `Weak<T>`) and must still own its potential weak reference
+ /// count.
+ ///
+ /// It is allowed for the strong count to be 0 at the time of calling this, but the weak count
+ /// must be non-zero or the pointer must have originated from a dangling `Weak<T>` (one created
+ /// by [`new`]).
///
/// # Examples
///
@@ -1440,11 +1442,13 @@
/// assert!(unsafe { Weak::from_raw(raw_2) }.upgrade().is_none());
/// ```
///
- /// [`null`]: ../../std/ptr/fn.null.html
+ /// [`as_raw`]: struct.Weak.html#method.as_raw
+ /// [`new`]: struct.Weak.html#method.new
/// [`into_raw`]: struct.Weak.html#method.into_raw
/// [`upgrade`]: struct.Weak.html#method.upgrade
/// [`Weak`]: struct.Weak.html
/// [`Arc`]: struct.Arc.html
+ /// [`forget`]: ../../std/mem/fn.forget.html
#[unstable(feature = "weak_into_raw", issue = "60728")]
pub unsafe fn from_raw(ptr: *const T) -> Self {
if ptr.is_null() {
diff --git a/src/liballoc/sync/tests.rs b/src/liballoc/sync/tests.rs
index 9220f5e..9ddba49 100644
--- a/src/liballoc/sync/tests.rs
+++ b/src/liballoc/sync/tests.rs
@@ -29,7 +29,7 @@
#[test]
#[cfg_attr(target_os = "emscripten", ignore)]
-#[cfg(not(miri))] // Miri does not support threads
+#[cfg_attr(miri, ignore)] // Miri does not support threads
fn manually_share_arc() {
let v = vec![1, 2, 3, 4, 5, 6, 7, 8, 9, 10];
let arc_v = Arc::new(v);
@@ -334,7 +334,7 @@
#[test]
#[cfg_attr(target_os = "emscripten", ignore)]
-#[cfg(not(miri))] // Miri does not support threads
+#[cfg_attr(miri, ignore)] // Miri does not support threads
fn test_weak_count_locked() {
let mut a = Arc::new(atomic::AtomicBool::new(false));
let a2 = a.clone();
diff --git a/src/liballoc/tests/cow_str.rs b/src/liballoc/tests/cow_str.rs
index 6f357ed..62a5c24 100644
--- a/src/liballoc/tests/cow_str.rs
+++ b/src/liballoc/tests/cow_str.rs
@@ -138,4 +138,7 @@
let c2: Cow<'_, str> = Cow::Owned(s);
c1.clone_from(&c2);
assert!(c1.into_owned().capacity() >= 25);
+ let mut c3: Cow<'_, str> = Cow::Borrowed("bye");
+ c3.clone_from(&c2);
+ assert_eq!(c2, c3);
}
diff --git a/src/liballoc/tests/linked_list.rs b/src/liballoc/tests/linked_list.rs
index daa49c4..54a77d6 100644
--- a/src/liballoc/tests/linked_list.rs
+++ b/src/liballoc/tests/linked_list.rs
@@ -1,4 +1,5 @@
use std::collections::LinkedList;
+use std::panic::catch_unwind;
#[test]
fn test_basic() {
@@ -529,3 +530,109 @@
assert_eq!(list.into_iter().collect::<Vec<_>>(), vec![1, 3, 5, 7, 9, 11, 13, 15, 17, 19]);
}
}
+
+
+#[test]
+fn test_drop() {
+ static mut DROPS: i32 = 0;
+ struct Elem;
+ impl Drop for Elem {
+ fn drop(&mut self) {
+ unsafe {
+ DROPS += 1;
+ }
+ }
+ }
+
+ let mut ring = LinkedList::new();
+ ring.push_back(Elem);
+ ring.push_front(Elem);
+ ring.push_back(Elem);
+ ring.push_front(Elem);
+ drop(ring);
+
+ assert_eq!(unsafe { DROPS }, 4);
+}
+
+#[test]
+fn test_drop_with_pop() {
+ static mut DROPS: i32 = 0;
+ struct Elem;
+ impl Drop for Elem {
+ fn drop(&mut self) {
+ unsafe {
+ DROPS += 1;
+ }
+ }
+ }
+
+ let mut ring = LinkedList::new();
+ ring.push_back(Elem);
+ ring.push_front(Elem);
+ ring.push_back(Elem);
+ ring.push_front(Elem);
+
+ drop(ring.pop_back());
+ drop(ring.pop_front());
+ assert_eq!(unsafe { DROPS }, 2);
+
+ drop(ring);
+ assert_eq!(unsafe { DROPS }, 4);
+}
+
+#[test]
+fn test_drop_clear() {
+ static mut DROPS: i32 = 0;
+ struct Elem;
+ impl Drop for Elem {
+ fn drop(&mut self) {
+ unsafe {
+ DROPS += 1;
+ }
+ }
+ }
+
+ let mut ring = LinkedList::new();
+ ring.push_back(Elem);
+ ring.push_front(Elem);
+ ring.push_back(Elem);
+ ring.push_front(Elem);
+ ring.clear();
+ assert_eq!(unsafe { DROPS }, 4);
+
+ drop(ring);
+ assert_eq!(unsafe { DROPS }, 4);
+}
+
+#[test]
+fn test_drop_panic() {
+ static mut DROPS: i32 = 0;
+
+ struct D(bool);
+
+ impl Drop for D {
+ fn drop(&mut self) {
+ unsafe {
+ DROPS += 1;
+ }
+
+ if self.0 {
+ panic!("panic in `drop`");
+ }
+ }
+ }
+
+ let mut q = LinkedList::new();
+ q.push_back(D(false));
+ q.push_back(D(false));
+ q.push_back(D(false));
+ q.push_back(D(false));
+ q.push_back(D(false));
+ q.push_front(D(false));
+ q.push_front(D(false));
+ q.push_front(D(true));
+
+ catch_unwind(move || drop(q)).ok();
+
+ assert_eq!(unsafe { DROPS }, 8);
+}
diff --git a/src/liballoc/tests/slice.rs b/src/liballoc/tests/slice.rs
index d9707b9..ec45de7 100644
--- a/src/liballoc/tests/slice.rs
+++ b/src/liballoc/tests/slice.rs
@@ -388,7 +388,7 @@
}
#[test]
-#[cfg(not(miri))] // Miri is too slow
+#[cfg_attr(miri, ignore)] // Miri is too slow
fn test_sort() {
let mut rng = thread_rng();
@@ -1610,7 +1610,7 @@
let moduli = &[5, 20, 50];
#[cfg(miri)]
- let lens = (1..13);
+ let lens = 1..13;
#[cfg(miri)]
let moduli = &[10];
diff --git a/src/liballoc/tests/str.rs b/src/liballoc/tests/str.rs
index cb73c7c..1b01124 100644
--- a/src/liballoc/tests/str.rs
+++ b/src/liballoc/tests/str.rs
@@ -166,7 +166,7 @@
}
#[test]
-#[cfg(not(miri))] // Miri is too slow
+#[cfg_attr(miri, ignore)] // Miri is too slow
fn test_unsafe_slice() {
assert_eq!("ab", unsafe {"abc".get_unchecked(0..2)});
assert_eq!("bc", unsafe {"abc".get_unchecked(1..3)});
@@ -483,8 +483,8 @@
}
#[test]
- #[cfg(not(target_os = "emscripten"))] // hits an OOM
- #[cfg(not(miri))] // Miri is too slow
+ #[cfg_attr(target_os = "emscripten", ignore)] // hits an OOM
+ #[cfg_attr(miri, ignore)] // Miri is too slow
fn simple_big() {
fn a_million_letter_x() -> String {
let mut i = 0;
@@ -1069,7 +1069,7 @@
}
#[test]
-#[cfg(not(miri))] // Miri is too slow
+#[cfg_attr(miri, ignore)] // Miri is too slow
fn test_chars_decoding() {
let mut bytes = [0; 4];
for c in (0..0x110000).filter_map(std::char::from_u32) {
@@ -1081,7 +1081,7 @@
}
#[test]
-#[cfg(not(miri))] // Miri is too slow
+#[cfg_attr(miri, ignore)] // Miri is too slow
fn test_chars_rev_decoding() {
let mut bytes = [0; 4];
for c in (0..0x110000).filter_map(std::char::from_u32) {
@@ -1380,7 +1380,6 @@
assert_eq!("not even a boolean".parse::<bool>().ok(), None);
}
-#[cfg(not(miri))] // Miri is too slow
fn check_contains_all_substrings(s: &str) {
assert!(s.contains(""));
for i in 0..s.len() {
@@ -1391,7 +1390,7 @@
}
#[test]
-#[cfg(not(miri))] // Miri is too slow
+#[cfg_attr(miri, ignore)] // Miri is too slow
fn strslice_issue_16589() {
assert!("bananas".contains("nana"));
@@ -1408,7 +1407,7 @@
#[test]
-#[cfg(not(miri))] // Miri is too slow
+#[cfg_attr(miri, ignore)] // Miri is too slow
fn test_strslice_contains() {
let x = "There are moments, Jeeves, when one asks oneself, 'Do trousers matter?'";
check_contains_all_substrings(x);
diff --git a/src/liballoc/tests/string.rs b/src/liballoc/tests/string.rs
index 55edf56..fe7b4ff 100644
--- a/src/liballoc/tests/string.rs
+++ b/src/liballoc/tests/string.rs
@@ -523,7 +523,7 @@
}
#[test]
-#[cfg(not(miri))] // Miri does not support signalling OOM
+#[cfg_attr(miri, ignore)] // Miri does not support signalling OOM
fn test_try_reserve() {
// These are the interesting cases:
@@ -601,7 +601,7 @@
}
#[test]
-#[cfg(not(miri))] // Miri does not support signalling OOM
+#[cfg_attr(miri, ignore)] // Miri does not support signalling OOM
fn test_try_reserve_exact() {
// This is exactly the same as test_try_reserve with the method changed.
diff --git a/src/liballoc/tests/vec.rs b/src/liballoc/tests/vec.rs
index 9ee254f..5e788d6 100644
--- a/src/liballoc/tests/vec.rs
+++ b/src/liballoc/tests/vec.rs
@@ -1080,7 +1080,7 @@
}
#[test]
-#[cfg(not(miri))] // Miri does not support signalling OOM
+#[cfg_attr(miri, ignore)] // Miri does not support signalling OOM
fn test_try_reserve() {
// These are the interesting cases:
@@ -1183,7 +1183,7 @@
}
#[test]
-#[cfg(not(miri))] // Miri does not support signalling OOM
+#[cfg_attr(miri, ignore)] // Miri does not support signalling OOM
fn test_try_reserve_exact() {
// This is exactly the same as test_try_reserve with the method changed.
diff --git a/src/liballoc/tests/vec_deque.rs b/src/liballoc/tests/vec_deque.rs
index 5a0162a..1ab3694 100644
--- a/src/liballoc/tests/vec_deque.rs
+++ b/src/liballoc/tests/vec_deque.rs
@@ -2,6 +2,7 @@
use std::collections::{vec_deque::Drain, VecDeque};
use std::fmt::Debug;
use std::mem::size_of;
+use std::panic::catch_unwind;
use std::{isize, usize};
use crate::hash;
@@ -710,6 +711,39 @@
}
#[test]
+fn test_drop_panic() {
+ static mut DROPS: i32 = 0;
+
+ struct D(bool);
+
+ impl Drop for D {
+ fn drop(&mut self) {
+ unsafe {
+ DROPS += 1;
+ }
+
+ if self.0 {
+ panic!("panic in `drop`");
+ }
+ }
+ }
+
+ let mut q = VecDeque::new();
+ q.push_back(D(false));
+ q.push_back(D(false));
+ q.push_back(D(false));
+ q.push_back(D(false));
+ q.push_back(D(false));
+ q.push_front(D(false));
+ q.push_front(D(false));
+ q.push_front(D(true));
+
+ catch_unwind(move || drop(q)).ok();
+
+ assert_eq!(unsafe { DROPS }, 8);
+}
+
+#[test]
fn test_reserve_grow() {
// test growth path A
// [T o o H] -> [T o o H . . . . ]
@@ -1100,7 +1134,7 @@
}
#[test]
-#[cfg(not(miri))] // Miri does not support signalling OOM
+#[cfg_attr(miri, ignore)] // Miri does not support signalling OOM
fn test_try_reserve() {
// These are the interesting cases:
// * exactly isize::MAX should never trigger a CapacityOverflow (can be OOM)
@@ -1214,7 +1248,7 @@
}
#[test]
-#[cfg(not(miri))] // Miri does not support signalling OOM
+#[cfg_attr(miri, ignore)] // Miri does not support signalling OOM
fn test_try_reserve_exact() {
// This is exactly the same as test_try_reserve with the method changed.
// See that test for comments.
diff --git a/src/liballoc/vec.rs b/src/liballoc/vec.rs
index 1a700b9..6e165cc 100644
--- a/src/liballoc/vec.rs
+++ b/src/liballoc/vec.rs
@@ -92,7 +92,7 @@
/// vec[0] = 7;
/// assert_eq!(vec[0], 7);
///
-/// vec.extend([1, 2, 3].iter().cloned());
+/// vec.extend([1, 2, 3].iter().copied());
///
/// for x in &vec {
/// println!("{}", x);
diff --git a/src/libarena/lib.rs b/src/libarena/lib.rs
index 66d27a2..854942d 100644
--- a/src/libarena/lib.rs
+++ b/src/libarena/lib.rs
@@ -202,53 +202,18 @@
#[inline]
pub fn alloc_from_iter<I: IntoIterator<Item = T>>(&self, iter: I) -> &mut [T] {
assert!(mem::size_of::<T>() != 0);
- let mut iter = iter.into_iter();
- let size_hint = iter.size_hint();
-
- match size_hint {
- (min, Some(max)) if min == max => {
- // We know the exact number of elements the iterator will produce here
- let len = min;
-
- if len == 0 {
- return &mut [];
- }
-
- self.ensure_capacity(len);
-
- let slice = self.ptr.get();
-
- unsafe {
- let mut ptr = self.ptr.get();
- for _ in 0..len {
- // Write into uninitialized memory.
- ptr::write(ptr, iter.next().unwrap());
- // Advance the pointer.
- ptr = ptr.offset(1);
- // Update the pointer per iteration so if `iter.next()` panics
- // we destroy the correct amount
- self.ptr.set(ptr);
- }
- slice::from_raw_parts_mut(slice, len)
- }
- }
- _ => {
- cold_path(move || -> &mut [T] {
- let mut vec: SmallVec<[_; 8]> = iter.collect();
- if vec.is_empty() {
- return &mut [];
- }
- // Move the content to the arena by copying it and then forgetting
- // the content of the SmallVec
- unsafe {
- let len = vec.len();
- let start_ptr = self.alloc_raw_slice(len);
- vec.as_ptr().copy_to_nonoverlapping(start_ptr, len);
- vec.set_len(0);
- slice::from_raw_parts_mut(start_ptr, len)
- }
- })
- }
+ let mut vec: SmallVec<[_; 8]> = iter.into_iter().collect();
+ if vec.is_empty() {
+ return &mut [];
+ }
+ // Move the content to the arena by copying it and then forgetting
+ // the content of the SmallVec
+ unsafe {
+ let len = vec.len();
+ let start_ptr = self.alloc_raw_slice(len);
+ vec.as_ptr().copy_to_nonoverlapping(start_ptr, len);
+ vec.set_len(0);
+ slice::from_raw_parts_mut(start_ptr, len)
}
}
diff --git a/src/libcore/alloc.rs b/src/libcore/alloc.rs
index 4798769..5c24e3d 100644
--- a/src/libcore/alloc.rs
+++ b/src/libcore/alloc.rs
@@ -53,7 +53,7 @@
impl Layout {
/// Constructs a `Layout` from a given `size` and `align`,
- /// or returns `LayoutErr` if either of the following conditions
+ /// or returns `LayoutErr` if any of the following conditions
/// are not met:
///
/// * `align` must not be zero,
@@ -137,7 +137,7 @@
#[inline]
pub fn for_value<T: ?Sized>(t: &T) -> Self {
let (size, align) = (mem::size_of_val(t), mem::align_of_val(t));
- // See rationale in `new` for why this us using an unsafe variant below
+ // See rationale in `new` for why this is using an unsafe variant below
debug_assert!(Layout::from_size_align(size, align).is_ok());
unsafe {
Layout::from_size_align_unchecked(size, align)
@@ -196,7 +196,7 @@
// valid.
//
// 2. `len + align - 1` can overflow by at most `align - 1`,
- // so the &-mask wth `!(align - 1)` will ensure that in the
+ // so the &-mask with `!(align - 1)` will ensure that in the
// case of overflow, `len_rounded_up` will itself be 0.
// Thus the returned padding, when added to `len`, yields 0,
// which trivially satisfies the alignment `align`.
@@ -239,8 +239,11 @@
#[unstable(feature = "alloc_layout_extra", issue = "55724")]
#[inline]
pub fn repeat(&self, n: usize) -> Result<(Self, usize), LayoutErr> {
- let padded_size = self.size().checked_add(self.padding_needed_for(self.align()))
- .ok_or(LayoutErr { private: () })?;
+ // This cannot overflow. Quoting from the invariant of Layout:
+ // > `size`, when rounded up to the nearest multiple of `align`,
+ // > must not overflow (i.e., the rounded value must be less than
+ // > `usize::MAX`)
+ let padded_size = self.size() + self.padding_needed_for(self.align());
let alloc_size = padded_size.checked_mul(n)
.ok_or(LayoutErr { private: () })?;
@@ -253,7 +256,7 @@
/// Creates a layout describing the record for `self` followed by
/// `next`, including any necessary padding to ensure that `next`
- /// will be properly aligned. Note that the result layout will
+ /// will be properly aligned. Note that the resulting layout will
/// satisfy the alignment properties of both `self` and `next`.
///
/// The resulting layout will be the same as that of a C struct containing
@@ -310,8 +313,7 @@
pub fn extend_packed(&self, next: Self) -> Result<Self, LayoutErr> {
let new_size = self.size().checked_add(next.size())
.ok_or(LayoutErr { private: () })?;
- let layout = Layout::from_size_align(new_size, self.align())?;
- Ok(layout)
+ Layout::from_size_align(new_size, self.align())
}
/// Creates a layout describing the record for a `[T; n]`.
@@ -388,7 +390,7 @@
}
/// A memory allocator that can be registered as the standard library’s default
-/// though the `#[global_allocator]` attributes.
+/// through the `#[global_allocator]` attribute.
///
/// Some of the methods require that a memory block be *currently
/// allocated* via an allocator. This means that:
@@ -459,7 +461,7 @@
/// # Errors
///
/// Returning a null pointer indicates that either memory is exhausted
- /// or `layout` does not meet allocator's size or alignment constraints.
+ /// or `layout` does not meet this allocator's size or alignment constraints.
///
/// Implementations are encouraged to return null on memory
/// exhaustion rather than aborting, but this is not
@@ -1046,7 +1048,7 @@
/// Captures a common usage pattern for allocators.
///
/// The returned block is suitable for passing to the
- /// `alloc`/`realloc` methods of this allocator.
+ /// `realloc`/`dealloc` methods of this allocator.
///
/// Note to implementors: If this returns `Ok(ptr)`, then `ptr`
/// must be considered "currently allocated" and must be
@@ -1112,7 +1114,7 @@
/// Captures a common usage pattern for allocators.
///
/// The returned block is suitable for passing to the
- /// `alloc`/`realloc` methods of this allocator.
+ /// `realloc`/`dealloc` methods of this allocator.
///
/// Note to implementors: If this returns `Ok(ptr)`, then `ptr`
/// must be considered "currently allocated" and must be
@@ -1143,9 +1145,9 @@
where Self: Sized
{
match Layout::array::<T>(n) {
- Ok(ref layout) if layout.size() > 0 => {
+ Ok(layout) if layout.size() > 0 => {
unsafe {
- self.alloc(layout.clone()).map(|p| p.cast())
+ self.alloc(layout).map(|p| p.cast())
}
}
_ => Err(AllocErr),
@@ -1159,7 +1161,7 @@
/// Captures a common usage pattern for allocators.
///
/// The returned block is suitable for passing to the
- /// `alloc`/`realloc` methods of this allocator.
+ /// `realloc`/`dealloc` methods of this allocator.
///
/// # Safety
///
@@ -1193,9 +1195,9 @@
where Self: Sized
{
match (Layout::array::<T>(n_old), Layout::array::<T>(n_new)) {
- (Ok(ref k_old), Ok(ref k_new)) if k_old.size() > 0 && k_new.size() > 0 => {
+ (Ok(k_old), Ok(k_new)) if k_old.size() > 0 && k_new.size() > 0 => {
debug_assert!(k_old.align() == k_new.align());
- self.realloc(ptr.cast(), k_old.clone(), k_new.size()).map(NonNull::cast)
+ self.realloc(ptr.cast(), k_old, k_new.size()).map(NonNull::cast)
}
_ => {
Err(AllocErr)
@@ -1227,8 +1229,8 @@
where Self: Sized
{
match Layout::array::<T>(n) {
- Ok(ref k) if k.size() > 0 => {
- Ok(self.dealloc(ptr.cast(), k.clone()))
+ Ok(k) if k.size() > 0 => {
+ Ok(self.dealloc(ptr.cast(), k))
}
_ => {
Err(AllocErr)
diff --git a/src/libcore/benches/any.rs b/src/libcore/benches/any.rs
index ceb507a..53099b7 100644
--- a/src/libcore/benches/any.rs
+++ b/src/libcore/benches/any.rs
@@ -1,5 +1,5 @@
use core::any::*;
-use test::{Bencher, black_box};
+use test::{black_box, Bencher};
#[bench]
fn bench_downcast_ref(b: &mut Bencher) {
diff --git a/src/libcore/benches/ascii.rs b/src/libcore/benches/ascii.rs
index e921dd1..76ccd3d 100644
--- a/src/libcore/benches/ascii.rs
+++ b/src/libcore/benches/ascii.rs
@@ -22,17 +22,9 @@
//
// Therefore:
fn branchless_to_ascii_upper_case(byte: u8) -> u8 {
- byte &
- !(
- (
- byte.wrapping_add(0x1f) &
- !byte.wrapping_add(0x05) &
- 0x80
- ) >> 2
- )
+ byte & !((byte.wrapping_add(0x1f) & !byte.wrapping_add(0x05) & 0x80) >> 2)
}
-
macro_rules! benches {
($( fn $name: ident($arg: ident: &mut [u8]) $body: block )+ @iter $( $is_: ident, )+) => {
benches! {@
@@ -254,12 +246,15 @@
}
macro_rules! repeat {
- ($s: expr) => { concat!($s, $s, $s, $s, $s, $s, $s, $s, $s, $s) }
+ ($s: expr) => {
+ concat!($s, $s, $s, $s, $s, $s, $s, $s, $s, $s)
+ };
}
const SHORT: &'static str = "Alice's";
const MEDIUM: &'static str = "Alice's Adventures in Wonderland";
-const LONG: &'static str = repeat!(r#"
+const LONG: &'static str = repeat!(
+ r#"
La Guida di Bragia, a Ballad Opera for the Marionette Theatre (around 1850)
Alice's Adventures in Wonderland (1865)
Phantasmagoria and Other Poems (1869)
@@ -275,8 +270,10 @@
What the Tortoise Said to Achilles (1895)
Three Sunsets and Other Poems (1898)
The Manlet (1903)[106]
-"#);
+"#
+);
+#[rustfmt::skip]
const ASCII_UPPERCASE_MAP: [u8; 256] = [
0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07,
0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f,
@@ -330,6 +327,7 @@
}
use self::AsciiCharacterClass::*;
+#[rustfmt::skip]
static ASCII_CHARACTER_CLASS: [AsciiCharacterClass; 256] = [
// _0 _1 _2 _3 _4 _5 _6 _7 _8 _9 _a _b _c _d _e _f
C, C, C, C, C, C, C, C, C, Cw,Cw,C, Cw,Cw,C, C, // 0_
diff --git a/src/libcore/benches/char/methods.rs b/src/libcore/benches/char/methods.rs
index af934c1..a9a08a4 100644
--- a/src/libcore/benches/char/methods.rs
+++ b/src/libcore/benches/char/methods.rs
@@ -25,8 +25,13 @@
#[bench]
fn bench_to_digit_radix_var(b: &mut Bencher) {
- b.iter(|| CHARS.iter().cycle()
- .zip(RADIX.iter().cycle())
- .take(10_000)
- .map(|(c, radix)| c.to_digit(*radix)).min())
+ b.iter(|| {
+ CHARS
+ .iter()
+ .cycle()
+ .zip(RADIX.iter().cycle())
+ .take(10_000)
+ .map(|(c, radix)| c.to_digit(*radix))
+ .min()
+ })
}
diff --git a/src/libcore/benches/fmt.rs b/src/libcore/benches/fmt.rs
index 92f10c7..dd72a33 100644
--- a/src/libcore/benches/fmt.rs
+++ b/src/libcore/benches/fmt.rs
@@ -1,5 +1,5 @@
-use std::io::{self, Write as IoWrite};
use std::fmt::{self, Write as FmtWrite};
+use std::io::{self, Write as IoWrite};
use test::Bencher;
#[bench]
diff --git a/src/libcore/benches/hash/sip.rs b/src/libcore/benches/hash/sip.rs
index 5baba42..725c864 100644
--- a/src/libcore/benches/hash/sip.rs
+++ b/src/libcore/benches/hash/sip.rs
@@ -1,7 +1,7 @@
#![allow(deprecated)]
use core::hash::*;
-use test::{Bencher, black_box};
+use test::{black_box, Bencher};
fn hash_bytes<H: Hasher>(mut s: H, x: &[u8]) -> u64 {
Hasher::write(&mut s, x);
@@ -44,11 +44,11 @@
#[bench]
fn bench_long_str(b: &mut Bencher) {
let s = "Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod tempor \
-incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud \
-exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute \
-irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla \
-pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui \
-officia deserunt mollit anim id est laborum.";
+ incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud \
+ exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute \
+ irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla \
+ pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui \
+ officia deserunt mollit anim id est laborum.";
b.iter(|| {
assert_eq!(hash(&s), 17717065544121360093);
})
@@ -58,9 +58,7 @@
fn bench_u32(b: &mut Bencher) {
let u = 162629500u32;
let u = black_box(u);
- b.iter(|| {
- hash(&u)
- });
+ b.iter(|| hash(&u));
b.bytes = 8;
}
@@ -70,9 +68,7 @@
let u = black_box(u);
let k1 = black_box(0x1);
let k2 = black_box(0x2);
- b.iter(|| {
- hash_with(SipHasher::new_with_keys(k1, k2), &u)
- });
+ b.iter(|| hash_with(SipHasher::new_with_keys(k1, k2), &u));
b.bytes = 8;
}
@@ -80,62 +76,48 @@
fn bench_u64(b: &mut Bencher) {
let u = 16262950014981195938u64;
let u = black_box(u);
- b.iter(|| {
- hash(&u)
- });
+ b.iter(|| hash(&u));
b.bytes = 8;
}
#[bench]
fn bench_bytes_4(b: &mut Bencher) {
let data = black_box([b' '; 4]);
- b.iter(|| {
- hash_bytes(SipHasher::default(), &data)
- });
+ b.iter(|| hash_bytes(SipHasher::default(), &data));
b.bytes = 4;
}
#[bench]
fn bench_bytes_7(b: &mut Bencher) {
let data = black_box([b' '; 7]);
- b.iter(|| {
- hash_bytes(SipHasher::default(), &data)
- });
+ b.iter(|| hash_bytes(SipHasher::default(), &data));
b.bytes = 7;
}
#[bench]
fn bench_bytes_8(b: &mut Bencher) {
let data = black_box([b' '; 8]);
- b.iter(|| {
- hash_bytes(SipHasher::default(), &data)
- });
+ b.iter(|| hash_bytes(SipHasher::default(), &data));
b.bytes = 8;
}
#[bench]
fn bench_bytes_a_16(b: &mut Bencher) {
let data = black_box([b' '; 16]);
- b.iter(|| {
- hash_bytes(SipHasher::default(), &data)
- });
+ b.iter(|| hash_bytes(SipHasher::default(), &data));
b.bytes = 16;
}
#[bench]
fn bench_bytes_b_32(b: &mut Bencher) {
let data = black_box([b' '; 32]);
- b.iter(|| {
- hash_bytes(SipHasher::default(), &data)
- });
+ b.iter(|| hash_bytes(SipHasher::default(), &data));
b.bytes = 32;
}
#[bench]
fn bench_bytes_c_128(b: &mut Bencher) {
let data = black_box([b' '; 128]);
- b.iter(|| {
- hash_bytes(SipHasher::default(), &data)
- });
+ b.iter(|| hash_bytes(SipHasher::default(), &data));
b.bytes = 128;
}
diff --git a/src/libcore/benches/iter.rs b/src/libcore/benches/iter.rs
index 7dcfad8..fb6b4b7 100644
--- a/src/libcore/benches/iter.rs
+++ b/src/libcore/benches/iter.rs
@@ -1,5 +1,5 @@
use core::iter::*;
-use test::{Bencher, black_box};
+use test::{black_box, Bencher};
#[bench]
fn bench_rposition(b: &mut Bencher) {
@@ -14,7 +14,11 @@
b.iter(|| {
let it = 0..100;
let mut sum = 0;
- it.skip_while(|&x| { sum += x; sum < 4000 }).all(|_| true);
+ it.skip_while(|&x| {
+ sum += x;
+ sum < 4000
+ })
+ .all(|_| true);
});
}
@@ -29,7 +33,9 @@
});
}
-fn scatter(x: i32) -> i32 { (x * 31) % 127 }
+fn scatter(x: i32) -> i32 {
+ (x * 31) % 127
+}
#[bench]
fn bench_max_by_key(b: &mut Bencher) {
@@ -76,23 +82,21 @@
fn bench_zip_copy(b: &mut Bencher) {
let source = vec![0u8; 16 * 1024];
let mut dst = black_box(vec![0u8; 16 * 1024]);
- b.iter(|| {
- copy_zip(&source, &mut dst)
- })
+ b.iter(|| copy_zip(&source, &mut dst))
}
#[bench]
fn bench_zip_add(b: &mut Bencher) {
let source = vec![1.; 16 * 1024];
let mut dst = vec![0.; 16 * 1024];
- b.iter(|| {
- add_zip(&source, &mut dst)
- });
+ b.iter(|| add_zip(&source, &mut dst));
}
/// `Iterator::for_each` implemented as a plain loop.
-fn for_each_loop<I, F>(iter: I, mut f: F) where
- I: Iterator, F: FnMut(I::Item)
+fn for_each_loop<I, F>(iter: I, mut f: F)
+where
+ I: Iterator,
+ F: FnMut(I::Item),
{
for item in iter {
f(item);
@@ -101,8 +105,10 @@
/// `Iterator::for_each` implemented with `fold` for internal iteration.
/// (except when `by_ref()` effectively disables that optimization.)
-fn for_each_fold<I, F>(iter: I, mut f: F) where
- I: Iterator, F: FnMut(I::Item)
+fn for_each_fold<I, F>(iter: I, mut f: F)
+where
+ I: Iterator,
+ F: FnMut(I::Item),
{
iter.fold((), move |(), item| f(item));
}
@@ -137,25 +143,20 @@
});
}
-
/// Helper to benchmark `sum` for iterators taken by value which
/// can optimize `fold`, and by reference which cannot.
macro_rules! bench_sums {
($bench_sum:ident, $bench_ref_sum:ident, $iter:expr) => {
#[bench]
fn $bench_sum(b: &mut Bencher) {
- b.iter(|| -> i64 {
- $iter.map(black_box).sum()
- });
+ b.iter(|| -> i64 { $iter.map(black_box).sum() });
}
#[bench]
fn $bench_ref_sum(b: &mut Bencher) {
- b.iter(|| -> i64 {
- $iter.map(black_box).by_ref().sum()
- });
+ b.iter(|| -> i64 { $iter.map(black_box).by_ref().sum() });
}
- }
+ };
}
bench_sums! {
@@ -286,7 +287,10 @@
let t: Vec<_> = (0..100_000).collect();
b.iter(|| {
- let s = v.iter().zip(t.iter()).skip(10000)
+ let s = v
+ .iter()
+ .zip(t.iter())
+ .skip(10000)
.take_while(|t| *t.0 < 10100)
.map(|(a, b)| *a + *b)
.sum::<u64>();
@@ -299,7 +303,10 @@
let t: Vec<_> = (0..100_000).collect();
b.iter(|| {
- let s = v.iter().skip(10000).zip(t.iter().skip(10000))
+ let s = v
+ .iter()
+ .skip(10000)
+ .zip(t.iter().skip(10000))
.take_while(|t| *t.0 < 10100)
.map(|(a, b)| *a + *b)
.sum::<u64>();
@@ -309,23 +316,17 @@
#[bench]
fn bench_filter_count(b: &mut Bencher) {
- b.iter(|| {
- (0i64..1000000).map(black_box).filter(|x| x % 3 == 0).count()
- })
+ b.iter(|| (0i64..1000000).map(black_box).filter(|x| x % 3 == 0).count())
}
#[bench]
fn bench_filter_ref_count(b: &mut Bencher) {
- b.iter(|| {
- (0i64..1000000).map(black_box).by_ref().filter(|x| x % 3 == 0).count()
- })
+ b.iter(|| (0i64..1000000).map(black_box).by_ref().filter(|x| x % 3 == 0).count())
}
#[bench]
fn bench_filter_chain_count(b: &mut Bencher) {
- b.iter(|| {
- (0i64..1000000).chain(0..1000000).map(black_box).filter(|x| x % 3 == 0).count()
- })
+ b.iter(|| (0i64..1000000).chain(0..1000000).map(black_box).filter(|x| x % 3 == 0).count())
}
#[bench]
diff --git a/src/libcore/benches/lib.rs b/src/libcore/benches/lib.rs
index dea2963d..6932c7f 100644
--- a/src/libcore/benches/lib.rs
+++ b/src/libcore/benches/lib.rs
@@ -6,9 +6,9 @@
mod any;
mod ascii;
mod char;
+mod fmt;
mod hash;
mod iter;
mod num;
mod ops;
mod slice;
-mod fmt;
diff --git a/src/libcore/benches/num/flt2dec/mod.rs b/src/libcore/benches/num/flt2dec/mod.rs
index 4153745..b810dd1 100644
--- a/src/libcore/benches/num/flt2dec/mod.rs
+++ b/src/libcore/benches/num/flt2dec/mod.rs
@@ -3,17 +3,17 @@
mod grisu;
}
+use core::num::flt2dec::MAX_SIG_DIGITS;
+use core::num::flt2dec::{decode, DecodableFloat, Decoded, FullDecoded};
use std::f64;
use std::io::Write;
use std::vec::Vec;
use test::Bencher;
-use core::num::flt2dec::{decode, DecodableFloat, FullDecoded, Decoded};
-use core::num::flt2dec::MAX_SIG_DIGITS;
pub fn decode_finite<T: DecodableFloat>(v: T) -> Decoded {
match decode(v).1 {
FullDecoded::Finite(decoded) => decoded,
- full_decoded => panic!("expected finite, got {:?} instead", full_decoded)
+ full_decoded => panic!("expected finite, got {:?} instead", full_decoded),
}
}
diff --git a/src/libcore/benches/num/flt2dec/strategy/dragon.rs b/src/libcore/benches/num/flt2dec/strategy/dragon.rs
index 60660b1..4052fec 100644
--- a/src/libcore/benches/num/flt2dec/strategy/dragon.rs
+++ b/src/libcore/benches/num/flt2dec/strategy/dragon.rs
@@ -1,6 +1,6 @@
-use std::{i16, f64};
use super::super::*;
use core::num::flt2dec::strategy::dragon::*;
+use std::{f64, i16};
use test::Bencher;
#[bench]
diff --git a/src/libcore/benches/num/flt2dec/strategy/grisu.rs b/src/libcore/benches/num/flt2dec/strategy/grisu.rs
index 841feba..4950747 100644
--- a/src/libcore/benches/num/flt2dec/strategy/grisu.rs
+++ b/src/libcore/benches/num/flt2dec/strategy/grisu.rs
@@ -1,12 +1,12 @@
-use std::{i16, f64};
use super::super::*;
use core::num::flt2dec::strategy::grisu::*;
+use std::{f64, i16};
use test::Bencher;
pub fn decode_finite<T: DecodableFloat>(v: T) -> Decoded {
match decode(v).1 {
FullDecoded::Finite(decoded) => decoded,
- full_decoded => panic!("expected finite, got {:?} instead", full_decoded)
+ full_decoded => panic!("expected finite, got {:?} instead", full_decoded),
}
}
diff --git a/src/libcore/benches/num/mod.rs b/src/libcore/benches/num/mod.rs
index 2dcdf2b..852d4e4 100644
--- a/src/libcore/benches/num/mod.rs
+++ b/src/libcore/benches/num/mod.rs
@@ -1,8 +1,8 @@
-mod flt2dec;
mod dec2flt;
+mod flt2dec;
-use test::Bencher;
use std::str::FromStr;
+use test::Bencher;
const ASCII_NUMBERS: [&str; 19] = [
"0",
@@ -27,7 +27,7 @@
];
macro_rules! from_str_bench {
- ($mac:ident, $t:ty) => (
+ ($mac:ident, $t:ty) => {
#[bench]
fn $mac(b: &mut Bencher) {
b.iter(|| {
@@ -39,11 +39,11 @@
.max()
})
}
- )
+ };
}
macro_rules! from_str_radix_bench {
- ($mac:ident, $t:ty, $radix:expr) => (
+ ($mac:ident, $t:ty, $radix:expr) => {
#[bench]
fn $mac(b: &mut Bencher) {
b.iter(|| {
@@ -55,7 +55,7 @@
.max()
})
}
- )
+ };
}
from_str_bench!(bench_u8_from_str, u8);
diff --git a/src/libcore/benches/ops.rs b/src/libcore/benches/ops.rs
index 80649f3..0a2be8a2 100644
--- a/src/libcore/benches/ops.rs
+++ b/src/libcore/benches/ops.rs
@@ -4,17 +4,16 @@
// Overhead of dtors
struct HasDtor {
- _x: isize
+ _x: isize,
}
impl Drop for HasDtor {
- fn drop(&mut self) {
- }
+ fn drop(&mut self) {}
}
#[bench]
fn alloc_obj_with_dtor(b: &mut Bencher) {
b.iter(|| {
- HasDtor { _x : 10 };
+ HasDtor { _x: 10 };
})
}
diff --git a/src/libcore/benches/slice.rs b/src/libcore/benches/slice.rs
index 711a8df..06b37cb 100644
--- a/src/libcore/benches/slice.rs
+++ b/src/libcore/benches/slice.rs
@@ -8,11 +8,12 @@
}
fn binary_search<F>(b: &mut Bencher, cache: Cache, mapper: F)
- where F: Fn(usize) -> usize
+where
+ F: Fn(usize) -> usize,
{
let size = match cache {
- Cache::L1 => 1000, // 8kb
- Cache::L2 => 10_000, // 80kb
+ Cache::L1 => 1000, // 8kb
+ Cache::L2 => 10_000, // 80kb
Cache::L3 => 1_000_000, // 8Mb
};
let v = (0..size).map(&mapper).collect::<Vec<_>>();
diff --git a/src/libcore/bool.rs b/src/libcore/bool.rs
index 617bdd2..6e0865e 100644
--- a/src/libcore/bool.rs
+++ b/src/libcore/bool.rs
@@ -9,17 +9,13 @@
/// ```
/// #![feature(bool_to_option)]
///
- /// assert_eq!(false.then(0), None);
- /// assert_eq!(true.then(0), Some(0));
+ /// assert_eq!(false.then_some(0), None);
+ /// assert_eq!(true.then_some(0), Some(0));
/// ```
#[unstable(feature = "bool_to_option", issue = "64260")]
#[inline]
- pub fn then<T>(self, t: T) -> Option<T> {
- if self {
- Some(t)
- } else {
- None
- }
+ pub fn then_some<T>(self, t: T) -> Option<T> {
+ if self { Some(t) } else { None }
}
/// Returns `Some(f())` if the `bool` is `true`, or `None` otherwise.
@@ -29,16 +25,12 @@
/// ```
/// #![feature(bool_to_option)]
///
- /// assert_eq!(false.then_with(|| 0), None);
- /// assert_eq!(true.then_with(|| 0), Some(0));
+ /// assert_eq!(false.then(|| 0), None);
+ /// assert_eq!(true.then(|| 0), Some(0));
/// ```
#[unstable(feature = "bool_to_option", issue = "64260")]
#[inline]
- pub fn then_with<T, F: FnOnce() -> T>(self, f: F) -> Option<T> {
- if self {
- Some(f())
- } else {
- None
- }
+ pub fn then<T, F: FnOnce() -> T>(self, f: F) -> Option<T> {
+ if self { Some(f()) } else { None }
}
}
diff --git a/src/libcore/char/methods.rs b/src/libcore/char/methods.rs
index 1ec614e..5c63eeb 100644
--- a/src/libcore/char/methods.rs
+++ b/src/libcore/char/methods.rs
@@ -553,8 +553,7 @@
pub fn is_alphabetic(self) -> bool {
match self {
'a'..='z' | 'A'..='Z' => true,
- c if c > '\x7f' => derived_property::Alphabetic(c),
- _ => false,
+ c => c > '\x7f' && derived_property::Alphabetic(c),
}
}
@@ -585,8 +584,7 @@
pub fn is_lowercase(self) -> bool {
match self {
'a'..='z' => true,
- c if c > '\x7f' => derived_property::Lowercase(c),
- _ => false,
+ c => c > '\x7f' && derived_property::Lowercase(c),
}
}
@@ -617,8 +615,7 @@
pub fn is_uppercase(self) -> bool {
match self {
'A'..='Z' => true,
- c if c > '\x7f' => derived_property::Uppercase(c),
- _ => false,
+ c => c > '\x7f' && derived_property::Uppercase(c),
}
}
@@ -646,8 +643,7 @@
pub fn is_whitespace(self) -> bool {
match self {
' ' | '\x09'..='\x0d' => true,
- c if c > '\x7f' => property::White_Space(c),
- _ => false,
+ c => c > '\x7f' && property::White_Space(c),
}
}
@@ -744,8 +740,7 @@
pub fn is_numeric(self) -> bool {
match self {
'0'..='9' => true,
- c if c > '\x7f' => general_category::N(c),
- _ => false,
+ c => c > '\x7f' && general_category::N(c),
}
}
diff --git a/src/libcore/cmp.rs b/src/libcore/cmp.rs
index a5f355c..fd4be02 100644
--- a/src/libcore/cmp.rs
+++ b/src/libcore/cmp.rs
@@ -1005,6 +1005,7 @@
// Implementation of PartialEq, Eq, PartialOrd and Ord for primitive types
mod impls {
+ use crate::hint::unreachable_unchecked;
use crate::cmp::Ordering::{self, Less, Greater, Equal};
macro_rules! partial_eq_impl {
@@ -1125,7 +1126,16 @@
impl Ord for bool {
#[inline]
fn cmp(&self, other: &bool) -> Ordering {
- (*self as u8).cmp(&(*other as u8))
+ // Casting to i8's and converting the difference to an Ordering generates
+ // more optimal assembly.
+ // See <https://github.com/rust-lang/rust/issues/66780> for more info.
+ match (*self as i8) - (*other as i8) {
+ -1 => Less,
+ 0 => Equal,
+ 1 => Greater,
+ // SAFETY: bool as i8 returns 0 or 1, so the difference can't be anything else
+ _ => unsafe { unreachable_unchecked() },
+ }
}
}
diff --git a/src/libcore/convert.rs b/src/libcore/convert/mod.rs
similarity index 98%
rename from src/libcore/convert.rs
rename to src/libcore/convert/mod.rs
index 08802b3..b7db3e4 100644
--- a/src/libcore/convert.rs
+++ b/src/libcore/convert/mod.rs
@@ -40,6 +40,11 @@
#![stable(feature = "rust1", since = "1.0.0")]
+mod num;
+
+#[unstable(feature = "convert_float_to_int", issue = "67057")]
+pub use num::FloatToInt;
+
/// The identity function.
///
/// Two things are important to note about this function:
@@ -286,7 +291,7 @@
/// [`Into`].
///
/// One should always prefer implementing `From` over [`Into`]
-/// because implementing `From` automatically provides one with a implementation of [`Into`]
+/// because implementing `From` automatically provides one with an implementation of [`Into`]
/// thanks to the blanket implementation in the standard library.
///
/// Only implement [`Into`] if a conversion to a type outside the current crate is required.
@@ -562,6 +567,7 @@
///
/// [#64715]: https://github.com/rust-lang/rust/issues/64715
#[stable(feature = "convert_infallible", since = "1.34.0")]
+#[allow(unused_attributes)] // FIXME(#58633): do a principled fix instead.
#[rustc_reservation_impl = "permitting this impl would forbid us from adding \
`impl<T> From<!> for T` later; see rust-lang/rust#64715 for details"]
impl<T> From<!> for T {
diff --git a/src/libcore/convert/num.rs b/src/libcore/convert/num.rs
new file mode 100644
index 0000000..6f5ee75
--- /dev/null
+++ b/src/libcore/convert/num.rs
@@ -0,0 +1,449 @@
+use super::{From, TryFrom};
+use crate::num::TryFromIntError;
+
+mod private {
+ /// This trait being unreachable from outside the crate
+ /// prevents other implementations of the `FloatToInt` trait,
+ /// which allows potentially adding more trait methods after the trait is `#[stable]`.
+ #[unstable(feature = "convert_float_to_int", issue = "67057")]
+ pub trait Sealed {}
+}
+
+/// Supporting trait for inherent methods of `f32` and `f64` such as `round_unchecked_to`.
+/// Typically doesn’t need to be used directly.
+#[unstable(feature = "convert_float_to_int", issue = "67057")]
+pub trait FloatToInt<Int>: private::Sealed + Sized {
+ #[cfg(not(bootstrap))]
+ #[unstable(feature = "float_approx_unchecked_to", issue = "67058")]
+ #[doc(hidden)]
+ unsafe fn approx_unchecked(self) -> Int;
+}
+
+macro_rules! impl_float_to_int {
+ ( $Float: ident => $( $Int: ident )+ ) => {
+ #[unstable(feature = "convert_float_to_int", issue = "67057")]
+ impl private::Sealed for $Float {}
+ $(
+ #[unstable(feature = "convert_float_to_int", issue = "67057")]
+ impl FloatToInt<$Int> for $Float {
+ #[cfg(not(bootstrap))]
+ #[doc(hidden)]
+ #[inline]
+ unsafe fn approx_unchecked(self) -> $Int {
+ crate::intrinsics::float_to_int_approx_unchecked(self)
+ }
+ }
+ )+
+ }
+}
+
+impl_float_to_int!(f32 => u8 u16 u32 u64 u128 usize i8 i16 i32 i64 i128 isize);
+impl_float_to_int!(f64 => u8 u16 u32 u64 u128 usize i8 i16 i32 i64 i128 isize);
+
+// Conversion traits for primitive integer and float types
+// Conversions T -> T are covered by a blanket impl and therefore excluded
+// Some conversions from and to usize/isize are not implemented due to portability concerns
+macro_rules! impl_from {
+ ($Small: ty, $Large: ty, #[$attr:meta], $doc: expr) => {
+ #[$attr]
+ #[doc = $doc]
+ impl From<$Small> for $Large {
+ #[inline]
+ fn from(small: $Small) -> $Large {
+ small as $Large
+ }
+ }
+ };
+ ($Small: ty, $Large: ty, #[$attr:meta]) => {
+ impl_from!($Small,
+ $Large,
+ #[$attr],
+ concat!("Converts `",
+ stringify!($Small),
+ "` to `",
+ stringify!($Large),
+ "` losslessly."));
+ }
+}
+
+macro_rules! impl_from_bool {
+ ($target: ty, #[$attr:meta]) => {
+ impl_from!(bool, $target, #[$attr], concat!("Converts a `bool` to a `",
+ stringify!($target), "`. The resulting value is `0` for `false` and `1` for `true`
+values.
+
+# Examples
+
+```
+assert_eq!(", stringify!($target), "::from(true), 1);
+assert_eq!(", stringify!($target), "::from(false), 0);
+```"));
+ };
+}
+
+// Bool -> Any
+impl_from_bool! { u8, #[stable(feature = "from_bool", since = "1.28.0")] }
+impl_from_bool! { u16, #[stable(feature = "from_bool", since = "1.28.0")] }
+impl_from_bool! { u32, #[stable(feature = "from_bool", since = "1.28.0")] }
+impl_from_bool! { u64, #[stable(feature = "from_bool", since = "1.28.0")] }
+impl_from_bool! { u128, #[stable(feature = "from_bool", since = "1.28.0")] }
+impl_from_bool! { usize, #[stable(feature = "from_bool", since = "1.28.0")] }
+impl_from_bool! { i8, #[stable(feature = "from_bool", since = "1.28.0")] }
+impl_from_bool! { i16, #[stable(feature = "from_bool", since = "1.28.0")] }
+impl_from_bool! { i32, #[stable(feature = "from_bool", since = "1.28.0")] }
+impl_from_bool! { i64, #[stable(feature = "from_bool", since = "1.28.0")] }
+impl_from_bool! { i128, #[stable(feature = "from_bool", since = "1.28.0")] }
+impl_from_bool! { isize, #[stable(feature = "from_bool", since = "1.28.0")] }
+
+// Unsigned -> Unsigned
+impl_from! { u8, u16, #[stable(feature = "lossless_int_conv", since = "1.5.0")] }
+impl_from! { u8, u32, #[stable(feature = "lossless_int_conv", since = "1.5.0")] }
+impl_from! { u8, u64, #[stable(feature = "lossless_int_conv", since = "1.5.0")] }
+impl_from! { u8, u128, #[stable(feature = "i128", since = "1.26.0")] }
+impl_from! { u8, usize, #[stable(feature = "lossless_int_conv", since = "1.5.0")] }
+impl_from! { u16, u32, #[stable(feature = "lossless_int_conv", since = "1.5.0")] }
+impl_from! { u16, u64, #[stable(feature = "lossless_int_conv", since = "1.5.0")] }
+impl_from! { u16, u128, #[stable(feature = "i128", since = "1.26.0")] }
+impl_from! { u32, u64, #[stable(feature = "lossless_int_conv", since = "1.5.0")] }
+impl_from! { u32, u128, #[stable(feature = "i128", since = "1.26.0")] }
+impl_from! { u64, u128, #[stable(feature = "i128", since = "1.26.0")] }
+
+// Signed -> Signed
+impl_from! { i8, i16, #[stable(feature = "lossless_int_conv", since = "1.5.0")] }
+impl_from! { i8, i32, #[stable(feature = "lossless_int_conv", since = "1.5.0")] }
+impl_from! { i8, i64, #[stable(feature = "lossless_int_conv", since = "1.5.0")] }
+impl_from! { i8, i128, #[stable(feature = "i128", since = "1.26.0")] }
+impl_from! { i8, isize, #[stable(feature = "lossless_int_conv", since = "1.5.0")] }
+impl_from! { i16, i32, #[stable(feature = "lossless_int_conv", since = "1.5.0")] }
+impl_from! { i16, i64, #[stable(feature = "lossless_int_conv", since = "1.5.0")] }
+impl_from! { i16, i128, #[stable(feature = "i128", since = "1.26.0")] }
+impl_from! { i32, i64, #[stable(feature = "lossless_int_conv", since = "1.5.0")] }
+impl_from! { i32, i128, #[stable(feature = "i128", since = "1.26.0")] }
+impl_from! { i64, i128, #[stable(feature = "i128", since = "1.26.0")] }
+
+// Unsigned -> Signed
+impl_from! { u8, i16, #[stable(feature = "lossless_int_conv", since = "1.5.0")] }
+impl_from! { u8, i32, #[stable(feature = "lossless_int_conv", since = "1.5.0")] }
+impl_from! { u8, i64, #[stable(feature = "lossless_int_conv", since = "1.5.0")] }
+impl_from! { u8, i128, #[stable(feature = "i128", since = "1.26.0")] }
+impl_from! { u16, i32, #[stable(feature = "lossless_int_conv", since = "1.5.0")] }
+impl_from! { u16, i64, #[stable(feature = "lossless_int_conv", since = "1.5.0")] }
+impl_from! { u16, i128, #[stable(feature = "i128", since = "1.26.0")] }
+impl_from! { u32, i64, #[stable(feature = "lossless_int_conv", since = "1.5.0")] }
+impl_from! { u32, i128, #[stable(feature = "i128", since = "1.26.0")] }
+impl_from! { u64, i128, #[stable(feature = "i128", since = "1.26.0")] }
+
+// The C99 standard defines bounds on INTPTR_MIN, INTPTR_MAX, and UINTPTR_MAX
+// which imply that pointer-sized integers must be at least 16 bits:
+// https://port70.net/~nsz/c/c99/n1256.html#7.18.2.4
+impl_from! { u16, usize, #[stable(feature = "lossless_iusize_conv", since = "1.26.0")] }
+impl_from! { u8, isize, #[stable(feature = "lossless_iusize_conv", since = "1.26.0")] }
+impl_from! { i16, isize, #[stable(feature = "lossless_iusize_conv", since = "1.26.0")] }
+
+// RISC-V defines the possibility of a 128-bit address space (RV128).
+
+// CHERI proposes 256-bit “capabilities”. Unclear if this would be relevant to usize/isize.
+// https://www.cl.cam.ac.uk/research/security/ctsrd/pdfs/20171017a-cheri-poster.pdf
+// http://www.csl.sri.com/users/neumann/2012resolve-cheri.pdf
+
+// Note: integers can only be represented with full precision in a float if
+// they fit in the significand, which is 24 bits in f32 and 53 bits in f64.
+// Lossy float conversions are not implemented at this time.
+
+// Signed -> Float
+impl_from! { i8, f32, #[stable(feature = "lossless_float_conv", since = "1.6.0")] }
+impl_from! { i8, f64, #[stable(feature = "lossless_float_conv", since = "1.6.0")] }
+impl_from! { i16, f32, #[stable(feature = "lossless_float_conv", since = "1.6.0")] }
+impl_from! { i16, f64, #[stable(feature = "lossless_float_conv", since = "1.6.0")] }
+impl_from! { i32, f64, #[stable(feature = "lossless_float_conv", since = "1.6.0")] }
+
+// Unsigned -> Float
+impl_from! { u8, f32, #[stable(feature = "lossless_float_conv", since = "1.6.0")] }
+impl_from! { u8, f64, #[stable(feature = "lossless_float_conv", since = "1.6.0")] }
+impl_from! { u16, f32, #[stable(feature = "lossless_float_conv", since = "1.6.0")] }
+impl_from! { u16, f64, #[stable(feature = "lossless_float_conv", since = "1.6.0")] }
+impl_from! { u32, f64, #[stable(feature = "lossless_float_conv", since = "1.6.0")] }
+
+// Float -> Float
+impl_from! { f32, f64, #[stable(feature = "lossless_float_conv", since = "1.6.0")] }
+
+// no possible bounds violation
+macro_rules! try_from_unbounded {
+ ($source:ty, $($target:ty),*) => {$(
+ #[stable(feature = "try_from", since = "1.34.0")]
+ impl TryFrom<$source> for $target {
+ type Error = TryFromIntError;
+
+ /// Try to create the target number type from a source
+ /// number type. This returns an error if the source value
+ /// is outside of the range of the target type.
+ #[inline]
+ fn try_from(value: $source) -> Result<Self, Self::Error> {
+ Ok(value as $target)
+ }
+ }
+ )*}
+}
+
+// only negative bounds
+macro_rules! try_from_lower_bounded {
+ ($source:ty, $($target:ty),*) => {$(
+ #[stable(feature = "try_from", since = "1.34.0")]
+ impl TryFrom<$source> for $target {
+ type Error = TryFromIntError;
+
+ /// Try to create the target number type from a source
+ /// number type. This returns an error if the source value
+ /// is outside of the range of the target type.
+ #[inline]
+ fn try_from(u: $source) -> Result<$target, TryFromIntError> {
+ if u >= 0 {
+ Ok(u as $target)
+ } else {
+ Err(TryFromIntError(()))
+ }
+ }
+ }
+ )*}
+}
+
+// unsigned to signed (only positive bound)
+macro_rules! try_from_upper_bounded {
+ ($source:ty, $($target:ty),*) => {$(
+ #[stable(feature = "try_from", since = "1.34.0")]
+ impl TryFrom<$source> for $target {
+ type Error = TryFromIntError;
+
+ /// Try to create the target number type from a source
+ /// number type. This returns an error if the source value
+ /// is outside of the range of the target type.
+ #[inline]
+ fn try_from(u: $source) -> Result<$target, TryFromIntError> {
+ if u > (<$target>::max_value() as $source) {
+ Err(TryFromIntError(()))
+ } else {
+ Ok(u as $target)
+ }
+ }
+ }
+ )*}
+}
+
+// all other cases
+macro_rules! try_from_both_bounded {
+ ($source:ty, $($target:ty),*) => {$(
+ #[stable(feature = "try_from", since = "1.34.0")]
+ impl TryFrom<$source> for $target {
+ type Error = TryFromIntError;
+
+ /// Try to create the target number type from a source
+ /// number type. This returns an error if the source value
+ /// is outside of the range of the target type.
+ #[inline]
+ fn try_from(u: $source) -> Result<$target, TryFromIntError> {
+ let min = <$target>::min_value() as $source;
+ let max = <$target>::max_value() as $source;
+ if u < min || u > max {
+ Err(TryFromIntError(()))
+ } else {
+ Ok(u as $target)
+ }
+ }
+ }
+ )*}
+}
+
+macro_rules! rev {
+ ($mac:ident, $source:ty, $($target:ty),*) => {$(
+ $mac!($target, $source);
+ )*}
+}
+
+// intra-sign conversions
+try_from_upper_bounded!(u16, u8);
+try_from_upper_bounded!(u32, u16, u8);
+try_from_upper_bounded!(u64, u32, u16, u8);
+try_from_upper_bounded!(u128, u64, u32, u16, u8);
+
+try_from_both_bounded!(i16, i8);
+try_from_both_bounded!(i32, i16, i8);
+try_from_both_bounded!(i64, i32, i16, i8);
+try_from_both_bounded!(i128, i64, i32, i16, i8);
+
+// unsigned-to-signed
+try_from_upper_bounded!(u8, i8);
+try_from_upper_bounded!(u16, i8, i16);
+try_from_upper_bounded!(u32, i8, i16, i32);
+try_from_upper_bounded!(u64, i8, i16, i32, i64);
+try_from_upper_bounded!(u128, i8, i16, i32, i64, i128);
+
+// signed-to-unsigned
+try_from_lower_bounded!(i8, u8, u16, u32, u64, u128);
+try_from_lower_bounded!(i16, u16, u32, u64, u128);
+try_from_lower_bounded!(i32, u32, u64, u128);
+try_from_lower_bounded!(i64, u64, u128);
+try_from_lower_bounded!(i128, u128);
+try_from_both_bounded!(i16, u8);
+try_from_both_bounded!(i32, u16, u8);
+try_from_both_bounded!(i64, u32, u16, u8);
+try_from_both_bounded!(i128, u64, u32, u16, u8);
+
+// usize/isize
+try_from_upper_bounded!(usize, isize);
+try_from_lower_bounded!(isize, usize);
+
+#[cfg(target_pointer_width = "16")]
+mod ptr_try_from_impls {
+ use super::TryFromIntError;
+ use crate::convert::TryFrom;
+
+ try_from_upper_bounded!(usize, u8);
+ try_from_unbounded!(usize, u16, u32, u64, u128);
+ try_from_upper_bounded!(usize, i8, i16);
+ try_from_unbounded!(usize, i32, i64, i128);
+
+ try_from_both_bounded!(isize, u8);
+ try_from_lower_bounded!(isize, u16, u32, u64, u128);
+ try_from_both_bounded!(isize, i8);
+ try_from_unbounded!(isize, i16, i32, i64, i128);
+
+ rev!(try_from_upper_bounded, usize, u32, u64, u128);
+ rev!(try_from_lower_bounded, usize, i8, i16);
+ rev!(try_from_both_bounded, usize, i32, i64, i128);
+
+ rev!(try_from_upper_bounded, isize, u16, u32, u64, u128);
+ rev!(try_from_both_bounded, isize, i32, i64, i128);
+}
+
+#[cfg(target_pointer_width = "32")]
+mod ptr_try_from_impls {
+ use super::TryFromIntError;
+ use crate::convert::TryFrom;
+
+ try_from_upper_bounded!(usize, u8, u16);
+ try_from_unbounded!(usize, u32, u64, u128);
+ try_from_upper_bounded!(usize, i8, i16, i32);
+ try_from_unbounded!(usize, i64, i128);
+
+ try_from_both_bounded!(isize, u8, u16);
+ try_from_lower_bounded!(isize, u32, u64, u128);
+ try_from_both_bounded!(isize, i8, i16);
+ try_from_unbounded!(isize, i32, i64, i128);
+
+ rev!(try_from_unbounded, usize, u32);
+ rev!(try_from_upper_bounded, usize, u64, u128);
+ rev!(try_from_lower_bounded, usize, i8, i16, i32);
+ rev!(try_from_both_bounded, usize, i64, i128);
+
+ rev!(try_from_unbounded, isize, u16);
+ rev!(try_from_upper_bounded, isize, u32, u64, u128);
+ rev!(try_from_unbounded, isize, i32);
+ rev!(try_from_both_bounded, isize, i64, i128);
+}
+
+#[cfg(target_pointer_width = "64")]
+mod ptr_try_from_impls {
+ use super::TryFromIntError;
+ use crate::convert::TryFrom;
+
+ try_from_upper_bounded!(usize, u8, u16, u32);
+ try_from_unbounded!(usize, u64, u128);
+ try_from_upper_bounded!(usize, i8, i16, i32, i64);
+ try_from_unbounded!(usize, i128);
+
+ try_from_both_bounded!(isize, u8, u16, u32);
+ try_from_lower_bounded!(isize, u64, u128);
+ try_from_both_bounded!(isize, i8, i16, i32);
+ try_from_unbounded!(isize, i64, i128);
+
+ rev!(try_from_unbounded, usize, u32, u64);
+ rev!(try_from_upper_bounded, usize, u128);
+ rev!(try_from_lower_bounded, usize, i8, i16, i32, i64);
+ rev!(try_from_both_bounded, usize, i128);
+
+ rev!(try_from_unbounded, isize, u16, u32);
+ rev!(try_from_upper_bounded, isize, u64, u128);
+ rev!(try_from_unbounded, isize, i32, i64);
+ rev!(try_from_both_bounded, isize, i128);
+}
+
+// Conversion traits for non-zero integer types
+use crate::num::NonZeroI128;
+use crate::num::NonZeroI16;
+use crate::num::NonZeroI32;
+use crate::num::NonZeroI64;
+use crate::num::NonZeroI8;
+use crate::num::NonZeroIsize;
+use crate::num::NonZeroU128;
+use crate::num::NonZeroU16;
+use crate::num::NonZeroU32;
+use crate::num::NonZeroU64;
+use crate::num::NonZeroU8;
+use crate::num::NonZeroUsize;
+
+macro_rules! nzint_impl_from {
+ ($Small: ty, $Large: ty, #[$attr:meta], $doc: expr) => {
+ #[$attr]
+ #[doc = $doc]
+ impl From<$Small> for $Large {
+ #[inline]
+ fn from(small: $Small) -> $Large {
+ // SAFETY: input type guarantees the value is non-zero
+ unsafe {
+ <$Large>::new_unchecked(small.get().into())
+ }
+ }
+ }
+ };
+ ($Small: ty, $Large: ty, #[$attr:meta]) => {
+ nzint_impl_from!($Small,
+ $Large,
+ #[$attr],
+ concat!("Converts `",
+ stringify!($Small),
+ "` to `",
+ stringify!($Large),
+ "` losslessly."));
+ }
+}
+
+// Non-zero Unsigned -> Non-zero Unsigned
+nzint_impl_from! { NonZeroU8, NonZeroU16, #[stable(feature = "nz_int_conv", since = "1.41.0")] }
+nzint_impl_from! { NonZeroU8, NonZeroU32, #[stable(feature = "nz_int_conv", since = "1.41.0")] }
+nzint_impl_from! { NonZeroU8, NonZeroU64, #[stable(feature = "nz_int_conv", since = "1.41.0")] }
+nzint_impl_from! { NonZeroU8, NonZeroU128, #[stable(feature = "nz_int_conv", since = "1.41.0")] }
+nzint_impl_from! { NonZeroU8, NonZeroUsize, #[stable(feature = "nz_int_conv", since = "1.41.0")] }
+nzint_impl_from! { NonZeroU16, NonZeroU32, #[stable(feature = "nz_int_conv", since = "1.41.0")] }
+nzint_impl_from! { NonZeroU16, NonZeroU64, #[stable(feature = "nz_int_conv", since = "1.41.0")] }
+nzint_impl_from! { NonZeroU16, NonZeroU128, #[stable(feature = "nz_int_conv", since = "1.41.0")] }
+nzint_impl_from! { NonZeroU16, NonZeroUsize, #[stable(feature = "nz_int_conv", since = "1.41.0")] }
+nzint_impl_from! { NonZeroU32, NonZeroU64, #[stable(feature = "nz_int_conv", since = "1.41.0")] }
+nzint_impl_from! { NonZeroU32, NonZeroU128, #[stable(feature = "nz_int_conv", since = "1.41.0")] }
+nzint_impl_from! { NonZeroU64, NonZeroU128, #[stable(feature = "nz_int_conv", since = "1.41.0")] }
+
+// Non-zero Signed -> Non-zero Signed
+nzint_impl_from! { NonZeroI8, NonZeroI16, #[stable(feature = "nz_int_conv", since = "1.41.0")] }
+nzint_impl_from! { NonZeroI8, NonZeroI32, #[stable(feature = "nz_int_conv", since = "1.41.0")] }
+nzint_impl_from! { NonZeroI8, NonZeroI64, #[stable(feature = "nz_int_conv", since = "1.41.0")] }
+nzint_impl_from! { NonZeroI8, NonZeroI128, #[stable(feature = "nz_int_conv", since = "1.41.0")] }
+nzint_impl_from! { NonZeroI8, NonZeroIsize, #[stable(feature = "nz_int_conv", since = "1.41.0")] }
+nzint_impl_from! { NonZeroI16, NonZeroI32, #[stable(feature = "nz_int_conv", since = "1.41.0")] }
+nzint_impl_from! { NonZeroI16, NonZeroI64, #[stable(feature = "nz_int_conv", since = "1.41.0")] }
+nzint_impl_from! { NonZeroI16, NonZeroI128, #[stable(feature = "nz_int_conv", since = "1.41.0")] }
+nzint_impl_from! { NonZeroI16, NonZeroIsize, #[stable(feature = "nz_int_conv", since = "1.41.0")] }
+nzint_impl_from! { NonZeroI32, NonZeroI64, #[stable(feature = "nz_int_conv", since = "1.41.0")] }
+nzint_impl_from! { NonZeroI32, NonZeroI128, #[stable(feature = "nz_int_conv", since = "1.41.0")] }
+nzint_impl_from! { NonZeroI64, NonZeroI128, #[stable(feature = "nz_int_conv", since = "1.41.0")] }
+
+// NonZero UnSigned -> Non-zero Signed
+nzint_impl_from! { NonZeroU8, NonZeroI16, #[stable(feature = "nz_int_conv", since = "1.41.0")] }
+nzint_impl_from! { NonZeroU8, NonZeroI32, #[stable(feature = "nz_int_conv", since = "1.41.0")] }
+nzint_impl_from! { NonZeroU8, NonZeroI64, #[stable(feature = "nz_int_conv", since = "1.41.0")] }
+nzint_impl_from! { NonZeroU8, NonZeroI128, #[stable(feature = "nz_int_conv", since = "1.41.0")] }
+nzint_impl_from! { NonZeroU8, NonZeroIsize, #[stable(feature = "nz_int_conv", since = "1.41.0")] }
+nzint_impl_from! { NonZeroU16, NonZeroI32, #[stable(feature = "nz_int_conv", since = "1.41.0")] }
+nzint_impl_from! { NonZeroU16, NonZeroI64, #[stable(feature = "nz_int_conv", since = "1.41.0")] }
+nzint_impl_from! { NonZeroU16, NonZeroI128, #[stable(feature = "nz_int_conv", since = "1.41.0")] }
+nzint_impl_from! { NonZeroU32, NonZeroI64, #[stable(feature = "nz_int_conv", since = "1.41.0")] }
+nzint_impl_from! { NonZeroU32, NonZeroI128, #[stable(feature = "nz_int_conv", since = "1.41.0")] }
+nzint_impl_from! { NonZeroU64, NonZeroI128, #[stable(feature = "nz_int_conv", since = "1.41.0")] }
diff --git a/src/libcore/fmt/mod.rs b/src/libcore/fmt/mod.rs
index 4c941e2..e2f49ee 100644
--- a/src/libcore/fmt/mod.rs
+++ b/src/libcore/fmt/mod.rs
@@ -662,7 +662,7 @@
/// fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
/// let val = self.0;
///
-/// write!(f, "{:o}", val) // delegate to i32's implementation
+/// fmt::Octal::fmt(&val, f) // delegate to i32's implementation
/// }
/// }
///
@@ -712,7 +712,7 @@
/// fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
/// let val = self.0;
///
-/// write!(f, "{:b}", val) // delegate to i32's implementation
+/// fmt::Binary::fmt(&val, f) // delegate to i32's implementation
/// }
/// }
///
@@ -771,7 +771,7 @@
/// fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
/// let val = self.0;
///
-/// write!(f, "{:x}", val) // delegate to i32's implementation
+/// fmt::LowerHex::fmt(&val, f) // delegate to i32's implementation
/// }
/// }
///
@@ -824,7 +824,7 @@
/// fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
/// let val = self.0;
///
-/// write!(f, "{:X}", val) // delegate to i32's implementation
+/// fmt::UpperHex::fmt(&val, f) // delegate to i32's implementation
/// }
/// }
///
@@ -869,7 +869,8 @@
/// fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
/// // use `as` to convert to a `*const T`, which implements Pointer, which we can use
///
-/// write!(f, "{:p}", self as *const Length)
+/// let ptr = self as *const Self;
+/// fmt::Pointer::fmt(&ptr, f)
/// }
/// }
///
diff --git a/src/libcore/hint.rs b/src/libcore/hint.rs
index a295e65..f4fb9ab 100644
--- a/src/libcore/hint.rs
+++ b/src/libcore/hint.rs
@@ -64,31 +64,27 @@
#[inline]
#[unstable(feature = "renamed_spin_loop", issue = "55002")]
pub fn spin_loop() {
- #[cfg(
- all(
- any(target_arch = "x86", target_arch = "x86_64"),
- target_feature = "sse2"
- )
- )] {
- #[cfg(target_arch = "x86")] {
+ #[cfg(all(any(target_arch = "x86", target_arch = "x86_64"), target_feature = "sse2"))]
+ {
+ #[cfg(target_arch = "x86")]
+ {
unsafe { crate::arch::x86::_mm_pause() };
}
- #[cfg(target_arch = "x86_64")] {
+ #[cfg(target_arch = "x86_64")]
+ {
unsafe { crate::arch::x86_64::_mm_pause() };
}
}
- #[cfg(
- any(
- target_arch = "aarch64",
- all(target_arch = "arm", target_feature = "v6")
- )
- )] {
- #[cfg(target_arch = "aarch64")] {
+ #[cfg(any(target_arch = "aarch64", all(target_arch = "arm", target_feature = "v6")))]
+ {
+ #[cfg(target_arch = "aarch64")]
+ {
unsafe { crate::arch::aarch64::__yield() };
}
- #[cfg(target_arch = "arm")] {
+ #[cfg(target_arch = "arm")]
+ {
unsafe { crate::arch::arm::__yield() };
}
}
diff --git a/src/libcore/intrinsics.rs b/src/libcore/intrinsics.rs
index 19928f3..18aae59 100644
--- a/src/libcore/intrinsics.rs
+++ b/src/libcore/intrinsics.rs
@@ -1144,6 +1144,11 @@
/// May assume inputs are finite.
pub fn frem_fast<T>(a: T, b: T) -> T;
+ /// Convert with LLVM’s fptoui/fptosi, which may return undef for values out of range
+ /// https://github.com/rust-lang/rust/issues/10184
+ #[cfg(not(bootstrap))]
+ pub fn float_to_int_approx_unchecked<Float, Int>(value: Float) -> Int;
+
/// Returns the number of bits set in an integer type `T`
pub fn ctpop<T>(x: T) -> T;
diff --git a/src/libcore/iter/traits/collect.rs b/src/libcore/iter/traits/collect.rs
index bbdb169..f21ab8d 100644
--- a/src/libcore/iter/traits/collect.rs
+++ b/src/libcore/iter/traits/collect.rs
@@ -91,9 +91,9 @@
/// ```
#[stable(feature = "rust1", since = "1.0.0")]
#[rustc_on_unimplemented(
- message="a collection of type `{Self}` cannot be built from an iterator \
- over elements of type `{A}`",
- label="a collection of type `{Self}` cannot be built from `std::iter::Iterator<Item={A}>`",
+ message = "a value of type `{Self}` cannot be built from an iterator \
+ over elements of type `{A}`",
+ label = "value of type `{Self}` cannot be built from `std::iter::Iterator<Item={A}>`"
)]
pub trait FromIterator<A>: Sized {
/// Creates a value from an iterator.
@@ -116,7 +116,7 @@
/// assert_eq!(v, vec![5, 5, 5, 5, 5]);
/// ```
#[stable(feature = "rust1", since = "1.0.0")]
- fn from_iter<T: IntoIterator<Item=A>>(iter: T) -> Self;
+ fn from_iter<T: IntoIterator<Item = A>>(iter: T) -> Self;
}
/// Conversion into an `Iterator`.
@@ -214,7 +214,7 @@
/// Which kind of iterator are we turning this into?
#[stable(feature = "rust1", since = "1.0.0")]
- type IntoIter: Iterator<Item=Self::Item>;
+ type IntoIter: Iterator<Item = Self::Item>;
/// Creates an iterator from a value.
///
@@ -340,7 +340,7 @@
/// assert_eq!("abcdef", &message);
/// ```
#[stable(feature = "rust1", since = "1.0.0")]
- fn extend<T: IntoIterator<Item=A>>(&mut self, iter: T);
+ fn extend<T: IntoIterator<Item = A>>(&mut self, iter: T);
}
#[stable(feature = "extend_for_unit", since = "1.28.0")]
diff --git a/src/libcore/lib.rs b/src/libcore/lib.rs
index ec19392..8a514f1 100644
--- a/src/libcore/lib.rs
+++ b/src/libcore/lib.rs
@@ -74,6 +74,8 @@
#![feature(const_fn)]
#![feature(const_fn_union)]
#![feature(const_generics)]
+#![cfg_attr(not(bootstrap), feature(const_ptr_offset_from))]
+#![cfg_attr(not(bootstrap), feature(const_type_name))]
#![feature(custom_inner_attributes)]
#![feature(decl_macro)]
#![feature(doc_cfg)]
@@ -100,6 +102,7 @@
#![feature(staged_api)]
#![feature(std_internals)]
#![feature(stmt_expr_attributes)]
+#![cfg_attr(not(bootstrap), feature(track_caller))]
#![feature(transparent_unions)]
#![feature(unboxed_closures)]
#![feature(unsized_locals)]
diff --git a/src/libcore/marker.rs b/src/libcore/marker.rs
index 86ee673..288017b 100644
--- a/src/libcore/marker.rs
+++ b/src/libcore/marker.rs
@@ -29,6 +29,7 @@
/// [arc]: ../../std/sync/struct.Arc.html
/// [ub]: ../../reference/behavior-considered-undefined.html
#[stable(feature = "rust1", since = "1.0.0")]
+#[cfg_attr(not(test), rustc_diagnostic_item = "send_trait")]
#[rustc_on_unimplemented(
message="`{Self}` cannot be sent between threads safely",
label="`{Self}` cannot be sent between threads safely"
@@ -440,6 +441,7 @@
/// [ub]: ../../reference/behavior-considered-undefined.html
/// [transmute]: ../../std/mem/fn.transmute.html
#[stable(feature = "rust1", since = "1.0.0")]
+#[cfg_attr(not(test), rustc_diagnostic_item = "sync_trait")]
#[lang = "sync"]
#[rustc_on_unimplemented(
message="`{Self}` cannot be shared between threads safely",
diff --git a/src/libcore/mem/mod.rs b/src/libcore/mem/mod.rs
index bba4414..ec926aa 100644
--- a/src/libcore/mem/mod.rs
+++ b/src/libcore/mem/mod.rs
@@ -510,7 +510,9 @@
/// **This function is deprecated.** Use [`MaybeUninit<T>`] instead.
///
/// The reason for deprecation is that the function basically cannot be used
-/// correctly: [the Rust compiler assumes][inv] that values are properly initialized.
+/// correctly: it has the same effect as [`MaybeUninit::uninit().assume_init()`][uninit].
+/// As the [`assume_init` documentation][assume_init] explains,
+/// [the Rust compiler assumes][inv] that values are properly initialized.
/// As a consequence, calling e.g. `mem::uninitialized::<bool>()` causes immediate
/// undefined behavior for returning a `bool` that is not definitely either `true`
/// or `false`. Worse, truly uninitialized memory like what gets returned here
@@ -521,6 +523,8 @@
/// until they are, it is advisable to avoid them.)
///
/// [`MaybeUninit<T>`]: union.MaybeUninit.html
+/// [uninit]: union.MaybeUninit.html#method.uninit
+/// [assume_init]: union.MaybeUninit.html#method.assume_init
/// [inv]: union.MaybeUninit.html#initialization-invariant
#[inline]
#[rustc_deprecated(since = "1.39.0", reason = "use `mem::MaybeUninit` instead")]
diff --git a/src/libcore/num/f32.rs b/src/libcore/num/f32.rs
index 913c0f9..ac06f95 100644
--- a/src/libcore/num/f32.rs
+++ b/src/libcore/num/f32.rs
@@ -7,9 +7,10 @@
#![stable(feature = "rust1", since = "1.0.0")]
+#[cfg(not(bootstrap))]
+use crate::convert::FloatToInt;
#[cfg(not(test))]
use crate::intrinsics;
-
use crate::mem;
use crate::num::FpCategory;
@@ -400,6 +401,35 @@
intrinsics::minnumf32(self, other)
}
+ /// Rounds toward zero and converts to any primitive integer type,
+ /// assuming that the value is finite and fits in that type.
+ ///
+ /// ```
+ /// #![feature(float_approx_unchecked_to)]
+ ///
+ /// let value = 4.6_f32;
+ /// let rounded = unsafe { value.approx_unchecked_to::<u16>() };
+ /// assert_eq!(rounded, 4);
+ ///
+ /// let value = -128.9_f32;
+ /// let rounded = unsafe { value.approx_unchecked_to::<i8>() };
+ /// assert_eq!(rounded, std::i8::MIN);
+ /// ```
+ ///
+ /// # Safety
+ ///
+ /// The value must:
+ ///
+ /// * Not be `NaN`
+ /// * Not be infinite
+ /// * Be representable in the return type `Int`, after truncating off its fractional part
+ #[cfg(not(bootstrap))]
+ #[unstable(feature = "float_approx_unchecked_to", issue = "67058")]
+ #[inline]
+ pub unsafe fn approx_unchecked_to<Int>(self) -> Int where Self: FloatToInt<Int> {
+ FloatToInt::<Int>::approx_unchecked(self)
+ }
+
/// Raw transmutation to `u32`.
///
/// This is currently identical to `transmute::<f32, u32>(self)` on all platforms.
diff --git a/src/libcore/num/f64.rs b/src/libcore/num/f64.rs
index 6ca830b..5446ce3 100644
--- a/src/libcore/num/f64.rs
+++ b/src/libcore/num/f64.rs
@@ -7,9 +7,10 @@
#![stable(feature = "rust1", since = "1.0.0")]
+#[cfg(not(bootstrap))]
+use crate::convert::FloatToInt;
#[cfg(not(test))]
use crate::intrinsics;
-
use crate::mem;
use crate::num::FpCategory;
@@ -413,6 +414,38 @@
intrinsics::minnumf64(self, other)
}
+ /// Rounds toward zero and converts to any primitive integer type,
+ /// assuming that the value is finite and fits in that type.
+ ///
+ /// ```
+ /// #![feature(float_approx_unchecked_to)]
+ ///
+ /// let value = 4.6_f32;
+ /// let rounded = unsafe { value.approx_unchecked_to::<u16>() };
+ /// assert_eq!(rounded, 4);
+ ///
+ /// let value = -128.9_f32;
+ /// let rounded = unsafe { value.approx_unchecked_to::<i8>() };
+ /// assert_eq!(rounded, std::i8::MIN);
+ /// ```
+ ///
+ /// # Safety
+ ///
+ /// The value must:
+ ///
+ /// * Not be `NaN`
+ /// * Not be infinite
+ /// * Be representable in the return type `Int`, after truncating off its fractional part
+ #[cfg(not(bootstrap))]
+ #[unstable(feature = "float_approx_unchecked_to", issue = "67058")]
+ #[inline]
+ pub unsafe fn approx_unchecked_to<Int>(self) -> Int
+ where
+ Self: FloatToInt<Int>,
+ {
+ FloatToInt::<Int>::approx_unchecked(self)
+ }
+
/// Raw transmutation to `u64`.
///
/// This is currently identical to `transmute::<f64, u64>(self)` on all platforms.
diff --git a/src/libcore/num/mod.rs b/src/libcore/num/mod.rs
index 4313248..d1f518d 100644
--- a/src/libcore/num/mod.rs
+++ b/src/libcore/num/mod.rs
@@ -4,7 +4,6 @@
#![stable(feature = "rust1", since = "1.0.0")]
-use crate::convert::TryFrom;
use crate::fmt;
use crate::intrinsics;
use crate::mem;
@@ -132,7 +131,7 @@
}
from_str_radix_nzint_impl! { NonZeroU8 NonZeroU16 NonZeroU32 NonZeroU64 NonZeroU128 NonZeroUsize
- NonZeroI8 NonZeroI16 NonZeroI32 NonZeroI64 NonZeroI128 NonZeroIsize }
+NonZeroI8 NonZeroI16 NonZeroI32 NonZeroI64 NonZeroI128 NonZeroIsize }
/// Provides intentionally-wrapped arithmetic on `T`.
///
@@ -163,8 +162,7 @@
#[stable(feature = "rust1", since = "1.0.0")]
#[derive(PartialEq, Eq, PartialOrd, Ord, Clone, Copy, Default, Hash)]
#[repr(transparent)]
-pub struct Wrapping<T>(#[stable(feature = "rust1", since = "1.0.0")]
- pub T);
+pub struct Wrapping<T>(#[stable(feature = "rust1", since = "1.0.0")] pub T);
#[stable(feature = "rust1", since = "1.0.0")]
impl<T: fmt::Debug> fmt::Debug for Wrapping<T> {
@@ -209,30 +207,33 @@
}
// All these modules are technically private and only exposed for coretests:
-pub mod flt2dec;
-pub mod dec2flt;
pub mod bignum;
+pub mod dec2flt;
pub mod diy_float;
+pub mod flt2dec;
mod wrapping;
macro_rules! usize_isize_to_xe_bytes_doc {
- () => {"
+ () => {
+ "
**Note**: This function returns an array of length 2, 4 or 8 bytes
depending on the target pointer size.
-"}
+"
+ };
}
-
macro_rules! usize_isize_from_xe_bytes_doc {
- () => {"
+ () => {
+ "
**Note**: This function takes an array of length 2, 4 or 8 bytes
depending on the target pointer size.
-"}
+"
+ };
}
macro_rules! int_impl {
@@ -2239,67 +2240,67 @@
#[lang = "i8"]
impl i8 {
int_impl! { i8, i8, u8, 8, -128, 127, "", "", 2, "-0x7e", "0xa", "0x12", "0x12", "0x48",
- "[0x12]", "[0x12]", "", "" }
+ "[0x12]", "[0x12]", "", "" }
}
#[lang = "i16"]
impl i16 {
int_impl! { i16, i16, u16, 16, -32768, 32767, "", "", 4, "-0x5ffd", "0x3a", "0x1234", "0x3412",
- "0x2c48", "[0x34, 0x12]", "[0x12, 0x34]", "", "" }
+ "0x2c48", "[0x34, 0x12]", "[0x12, 0x34]", "", "" }
}
#[lang = "i32"]
impl i32 {
int_impl! { i32, i32, u32, 32, -2147483648, 2147483647, "", "", 8, "0x10000b3", "0xb301",
- "0x12345678", "0x78563412", "0x1e6a2c48", "[0x78, 0x56, 0x34, 0x12]",
- "[0x12, 0x34, 0x56, 0x78]", "", "" }
+ "0x12345678", "0x78563412", "0x1e6a2c48", "[0x78, 0x56, 0x34, 0x12]",
+ "[0x12, 0x34, 0x56, 0x78]", "", "" }
}
#[lang = "i64"]
impl i64 {
int_impl! { i64, i64, u64, 64, -9223372036854775808, 9223372036854775807, "", "", 12,
- "0xaa00000000006e1", "0x6e10aa", "0x1234567890123456", "0x5634129078563412",
- "0x6a2c48091e6a2c48", "[0x56, 0x34, 0x12, 0x90, 0x78, 0x56, 0x34, 0x12]",
- "[0x12, 0x34, 0x56, 0x78, 0x90, 0x12, 0x34, 0x56]", "", "" }
+ "0xaa00000000006e1", "0x6e10aa", "0x1234567890123456", "0x5634129078563412",
+ "0x6a2c48091e6a2c48", "[0x56, 0x34, 0x12, 0x90, 0x78, 0x56, 0x34, 0x12]",
+ "[0x12, 0x34, 0x56, 0x78, 0x90, 0x12, 0x34, 0x56]", "", "" }
}
#[lang = "i128"]
impl i128 {
int_impl! { i128, i128, u128, 128, -170141183460469231731687303715884105728,
- 170141183460469231731687303715884105727, "", "", 16,
- "0x13f40000000000000000000000004f76", "0x4f7613f4", "0x12345678901234567890123456789012",
- "0x12907856341290785634129078563412", "0x48091e6a2c48091e6a2c48091e6a2c48",
- "[0x12, 0x90, 0x78, 0x56, 0x34, 0x12, 0x90, 0x78, \
- 0x56, 0x34, 0x12, 0x90, 0x78, 0x56, 0x34, 0x12]",
- "[0x12, 0x34, 0x56, 0x78, 0x90, 0x12, 0x34, 0x56, \
- 0x78, 0x90, 0x12, 0x34, 0x56, 0x78, 0x90, 0x12]", "", "" }
+ 170141183460469231731687303715884105727, "", "", 16,
+ "0x13f40000000000000000000000004f76", "0x4f7613f4", "0x12345678901234567890123456789012",
+ "0x12907856341290785634129078563412", "0x48091e6a2c48091e6a2c48091e6a2c48",
+ "[0x12, 0x90, 0x78, 0x56, 0x34, 0x12, 0x90, 0x78, \
+ 0x56, 0x34, 0x12, 0x90, 0x78, 0x56, 0x34, 0x12]",
+ "[0x12, 0x34, 0x56, 0x78, 0x90, 0x12, 0x34, 0x56, \
+ 0x78, 0x90, 0x12, 0x34, 0x56, 0x78, 0x90, 0x12]", "", "" }
}
#[cfg(target_pointer_width = "16")]
#[lang = "isize"]
impl isize {
int_impl! { isize, i16, u16, 16, -32768, 32767, "", "", 4, "-0x5ffd", "0x3a", "0x1234",
- "0x3412", "0x2c48", "[0x34, 0x12]", "[0x12, 0x34]",
- usize_isize_to_xe_bytes_doc!(), usize_isize_from_xe_bytes_doc!() }
+ "0x3412", "0x2c48", "[0x34, 0x12]", "[0x12, 0x34]",
+ usize_isize_to_xe_bytes_doc!(), usize_isize_from_xe_bytes_doc!() }
}
#[cfg(target_pointer_width = "32")]
#[lang = "isize"]
impl isize {
int_impl! { isize, i32, u32, 32, -2147483648, 2147483647, "", "", 8, "0x10000b3", "0xb301",
- "0x12345678", "0x78563412", "0x1e6a2c48", "[0x78, 0x56, 0x34, 0x12]",
- "[0x12, 0x34, 0x56, 0x78]",
- usize_isize_to_xe_bytes_doc!(), usize_isize_from_xe_bytes_doc!() }
+ "0x12345678", "0x78563412", "0x1e6a2c48", "[0x78, 0x56, 0x34, 0x12]",
+ "[0x12, 0x34, 0x56, 0x78]",
+ usize_isize_to_xe_bytes_doc!(), usize_isize_from_xe_bytes_doc!() }
}
#[cfg(target_pointer_width = "64")]
#[lang = "isize"]
impl isize {
int_impl! { isize, i64, u64, 64, -9223372036854775808, 9223372036854775807, "", "",
- 12, "0xaa00000000006e1", "0x6e10aa", "0x1234567890123456", "0x5634129078563412",
- "0x6a2c48091e6a2c48", "[0x56, 0x34, 0x12, 0x90, 0x78, 0x56, 0x34, 0x12]",
- "[0x12, 0x34, 0x56, 0x78, 0x90, 0x12, 0x34, 0x56]",
- usize_isize_to_xe_bytes_doc!(), usize_isize_from_xe_bytes_doc!() }
+ 12, "0xaa00000000006e1", "0x6e10aa", "0x1234567890123456", "0x5634129078563412",
+ "0x6a2c48091e6a2c48", "[0x56, 0x34, 0x12, 0x90, 0x78, 0x56, 0x34, 0x12]",
+ "[0x12, 0x34, 0x56, 0x78, 0x90, 0x12, 0x34, 0x56]",
+ usize_isize_to_xe_bytes_doc!(), usize_isize_from_xe_bytes_doc!() }
}
macro_rules! uint_impl {
@@ -4061,8 +4062,7 @@
#[lang = "u8"]
impl u8 {
uint_impl! { u8, u8, 8, 255, "", "", 2, "0x82", "0xa", "0x12", "0x12", "0x48", "[0x12]",
- "[0x12]", "", "" }
-
+ "[0x12]", "", "" }
/// Checks if the value is within the ASCII range.
///
@@ -4228,7 +4228,7 @@
pub fn is_ascii_alphabetic(&self) -> bool {
match *self {
b'A'..=b'Z' | b'a'..=b'z' => true,
- _ => false
+ _ => false,
}
}
@@ -4263,7 +4263,7 @@
pub fn is_ascii_uppercase(&self) -> bool {
match *self {
b'A'..=b'Z' => true,
- _ => false
+ _ => false,
}
}
@@ -4298,7 +4298,7 @@
pub fn is_ascii_lowercase(&self) -> bool {
match *self {
b'a'..=b'z' => true,
- _ => false
+ _ => false,
}
}
@@ -4336,7 +4336,7 @@
pub fn is_ascii_alphanumeric(&self) -> bool {
match *self {
b'0'..=b'9' | b'A'..=b'Z' | b'a'..=b'z' => true,
- _ => false
+ _ => false,
}
}
@@ -4371,7 +4371,7 @@
pub fn is_ascii_digit(&self) -> bool {
match *self {
b'0'..=b'9' => true,
- _ => false
+ _ => false,
}
}
@@ -4409,7 +4409,7 @@
pub fn is_ascii_hexdigit(&self) -> bool {
match *self {
b'0'..=b'9' | b'A'..=b'F' | b'a'..=b'f' => true,
- _ => false
+ _ => false,
}
}
@@ -4448,7 +4448,7 @@
pub fn is_ascii_punctuation(&self) -> bool {
match *self {
b'!'..=b'/' | b':'..=b'@' | b'['..=b'`' | b'{'..=b'~' => true,
- _ => false
+ _ => false,
}
}
@@ -4483,7 +4483,7 @@
pub fn is_ascii_graphic(&self) -> bool {
match *self {
b'!'..=b'~' => true,
- _ => false
+ _ => false,
}
}
@@ -4535,7 +4535,7 @@
pub fn is_ascii_whitespace(&self) -> bool {
match *self {
b'\t' | b'\n' | b'\x0C' | b'\r' | b' ' => true,
- _ => false
+ _ => false,
}
}
@@ -4572,7 +4572,7 @@
pub fn is_ascii_control(&self) -> bool {
match *self {
b'\0'..=b'\x1F' | b'\x7F' => true,
- _ => false
+ _ => false,
}
}
}
@@ -4580,59 +4580,59 @@
#[lang = "u16"]
impl u16 {
uint_impl! { u16, u16, 16, 65535, "", "", 4, "0xa003", "0x3a", "0x1234", "0x3412", "0x2c48",
- "[0x34, 0x12]", "[0x12, 0x34]", "", "" }
+ "[0x34, 0x12]", "[0x12, 0x34]", "", "" }
}
#[lang = "u32"]
impl u32 {
uint_impl! { u32, u32, 32, 4294967295, "", "", 8, "0x10000b3", "0xb301", "0x12345678",
- "0x78563412", "0x1e6a2c48", "[0x78, 0x56, 0x34, 0x12]", "[0x12, 0x34, 0x56, 0x78]", "", "" }
+ "0x78563412", "0x1e6a2c48", "[0x78, 0x56, 0x34, 0x12]", "[0x12, 0x34, 0x56, 0x78]", "", "" }
}
#[lang = "u64"]
impl u64 {
uint_impl! { u64, u64, 64, 18446744073709551615, "", "", 12, "0xaa00000000006e1", "0x6e10aa",
- "0x1234567890123456", "0x5634129078563412", "0x6a2c48091e6a2c48",
- "[0x56, 0x34, 0x12, 0x90, 0x78, 0x56, 0x34, 0x12]",
- "[0x12, 0x34, 0x56, 0x78, 0x90, 0x12, 0x34, 0x56]",
- "", ""}
+ "0x1234567890123456", "0x5634129078563412", "0x6a2c48091e6a2c48",
+ "[0x56, 0x34, 0x12, 0x90, 0x78, 0x56, 0x34, 0x12]",
+ "[0x12, 0x34, 0x56, 0x78, 0x90, 0x12, 0x34, 0x56]",
+ "", ""}
}
#[lang = "u128"]
impl u128 {
uint_impl! { u128, u128, 128, 340282366920938463463374607431768211455, "", "", 16,
- "0x13f40000000000000000000000004f76", "0x4f7613f4", "0x12345678901234567890123456789012",
- "0x12907856341290785634129078563412", "0x48091e6a2c48091e6a2c48091e6a2c48",
- "[0x12, 0x90, 0x78, 0x56, 0x34, 0x12, 0x90, 0x78, \
- 0x56, 0x34, 0x12, 0x90, 0x78, 0x56, 0x34, 0x12]",
- "[0x12, 0x34, 0x56, 0x78, 0x90, 0x12, 0x34, 0x56, \
- 0x78, 0x90, 0x12, 0x34, 0x56, 0x78, 0x90, 0x12]",
- "", ""}
+ "0x13f40000000000000000000000004f76", "0x4f7613f4", "0x12345678901234567890123456789012",
+ "0x12907856341290785634129078563412", "0x48091e6a2c48091e6a2c48091e6a2c48",
+ "[0x12, 0x90, 0x78, 0x56, 0x34, 0x12, 0x90, 0x78, \
+ 0x56, 0x34, 0x12, 0x90, 0x78, 0x56, 0x34, 0x12]",
+ "[0x12, 0x34, 0x56, 0x78, 0x90, 0x12, 0x34, 0x56, \
+ 0x78, 0x90, 0x12, 0x34, 0x56, 0x78, 0x90, 0x12]",
+ "", ""}
}
#[cfg(target_pointer_width = "16")]
#[lang = "usize"]
impl usize {
uint_impl! { usize, u16, 16, 65535, "", "", 4, "0xa003", "0x3a", "0x1234", "0x3412", "0x2c48",
- "[0x34, 0x12]", "[0x12, 0x34]",
- usize_isize_to_xe_bytes_doc!(), usize_isize_from_xe_bytes_doc!() }
+ "[0x34, 0x12]", "[0x12, 0x34]",
+ usize_isize_to_xe_bytes_doc!(), usize_isize_from_xe_bytes_doc!() }
}
#[cfg(target_pointer_width = "32")]
#[lang = "usize"]
impl usize {
uint_impl! { usize, u32, 32, 4294967295, "", "", 8, "0x10000b3", "0xb301", "0x12345678",
- "0x78563412", "0x1e6a2c48", "[0x78, 0x56, 0x34, 0x12]", "[0x12, 0x34, 0x56, 0x78]",
- usize_isize_to_xe_bytes_doc!(), usize_isize_from_xe_bytes_doc!() }
+ "0x78563412", "0x1e6a2c48", "[0x78, 0x56, 0x34, 0x12]", "[0x12, 0x34, 0x56, 0x78]",
+ usize_isize_to_xe_bytes_doc!(), usize_isize_from_xe_bytes_doc!() }
}
#[cfg(target_pointer_width = "64")]
#[lang = "usize"]
impl usize {
uint_impl! { usize, u64, 64, 18446744073709551615, "", "", 12, "0xaa00000000006e1", "0x6e10aa",
- "0x1234567890123456", "0x5634129078563412", "0x6a2c48091e6a2c48",
- "[0x56, 0x34, 0x12, 0x90, 0x78, 0x56, 0x34, 0x12]",
- "[0x12, 0x34, 0x56, 0x78, 0x90, 0x12, 0x34, 0x56]",
- usize_isize_to_xe_bytes_doc!(), usize_isize_from_xe_bytes_doc!() }
+ "0x1234567890123456", "0x5634129078563412", "0x6a2c48091e6a2c48",
+ "[0x56, 0x34, 0x12, 0x90, 0x78, 0x56, 0x34, 0x12]",
+ "[0x12, 0x34, 0x56, 0x78, 0x90, 0x12, 0x34, 0x56]",
+ usize_isize_to_xe_bytes_doc!(), usize_isize_from_xe_bytes_doc!() }
}
/// A classification of floating point numbers.
@@ -4701,13 +4701,15 @@
/// The error type returned when a checked integral type conversion fails.
#[stable(feature = "try_from", since = "1.34.0")]
#[derive(Debug, Copy, Clone, PartialEq, Eq)]
-pub struct TryFromIntError(());
+pub struct TryFromIntError(pub(crate) ());
impl TryFromIntError {
- #[unstable(feature = "int_error_internals",
- reason = "available through Error trait and this method should \
- not be exposed publicly",
- issue = "0")]
+ #[unstable(
+ feature = "int_error_internals",
+ reason = "available through Error trait and this method should \
+ not be exposed publicly",
+ issue = "0"
+ )]
#[doc(hidden)]
pub fn __description(&self) -> &str {
"out of range integral type conversion attempted"
@@ -4728,206 +4730,6 @@
}
}
-// no possible bounds violation
-macro_rules! try_from_unbounded {
- ($source:ty, $($target:ty),*) => {$(
- #[stable(feature = "try_from", since = "1.34.0")]
- impl TryFrom<$source> for $target {
- type Error = TryFromIntError;
-
- /// Try to create the target number type from a source
- /// number type. This returns an error if the source value
- /// is outside of the range of the target type.
- #[inline]
- fn try_from(value: $source) -> Result<Self, Self::Error> {
- Ok(value as $target)
- }
- }
- )*}
-}
-
-// only negative bounds
-macro_rules! try_from_lower_bounded {
- ($source:ty, $($target:ty),*) => {$(
- #[stable(feature = "try_from", since = "1.34.0")]
- impl TryFrom<$source> for $target {
- type Error = TryFromIntError;
-
- /// Try to create the target number type from a source
- /// number type. This returns an error if the source value
- /// is outside of the range of the target type.
- #[inline]
- fn try_from(u: $source) -> Result<$target, TryFromIntError> {
- if u >= 0 {
- Ok(u as $target)
- } else {
- Err(TryFromIntError(()))
- }
- }
- }
- )*}
-}
-
-// unsigned to signed (only positive bound)
-macro_rules! try_from_upper_bounded {
- ($source:ty, $($target:ty),*) => {$(
- #[stable(feature = "try_from", since = "1.34.0")]
- impl TryFrom<$source> for $target {
- type Error = TryFromIntError;
-
- /// Try to create the target number type from a source
- /// number type. This returns an error if the source value
- /// is outside of the range of the target type.
- #[inline]
- fn try_from(u: $source) -> Result<$target, TryFromIntError> {
- if u > (<$target>::max_value() as $source) {
- Err(TryFromIntError(()))
- } else {
- Ok(u as $target)
- }
- }
- }
- )*}
-}
-
-// all other cases
-macro_rules! try_from_both_bounded {
- ($source:ty, $($target:ty),*) => {$(
- #[stable(feature = "try_from", since = "1.34.0")]
- impl TryFrom<$source> for $target {
- type Error = TryFromIntError;
-
- /// Try to create the target number type from a source
- /// number type. This returns an error if the source value
- /// is outside of the range of the target type.
- #[inline]
- fn try_from(u: $source) -> Result<$target, TryFromIntError> {
- let min = <$target>::min_value() as $source;
- let max = <$target>::max_value() as $source;
- if u < min || u > max {
- Err(TryFromIntError(()))
- } else {
- Ok(u as $target)
- }
- }
- }
- )*}
-}
-
-macro_rules! rev {
- ($mac:ident, $source:ty, $($target:ty),*) => {$(
- $mac!($target, $source);
- )*}
-}
-
-// intra-sign conversions
-try_from_upper_bounded!(u16, u8);
-try_from_upper_bounded!(u32, u16, u8);
-try_from_upper_bounded!(u64, u32, u16, u8);
-try_from_upper_bounded!(u128, u64, u32, u16, u8);
-
-try_from_both_bounded!(i16, i8);
-try_from_both_bounded!(i32, i16, i8);
-try_from_both_bounded!(i64, i32, i16, i8);
-try_from_both_bounded!(i128, i64, i32, i16, i8);
-
-// unsigned-to-signed
-try_from_upper_bounded!(u8, i8);
-try_from_upper_bounded!(u16, i8, i16);
-try_from_upper_bounded!(u32, i8, i16, i32);
-try_from_upper_bounded!(u64, i8, i16, i32, i64);
-try_from_upper_bounded!(u128, i8, i16, i32, i64, i128);
-
-// signed-to-unsigned
-try_from_lower_bounded!(i8, u8, u16, u32, u64, u128);
-try_from_lower_bounded!(i16, u16, u32, u64, u128);
-try_from_lower_bounded!(i32, u32, u64, u128);
-try_from_lower_bounded!(i64, u64, u128);
-try_from_lower_bounded!(i128, u128);
-try_from_both_bounded!(i16, u8);
-try_from_both_bounded!(i32, u16, u8);
-try_from_both_bounded!(i64, u32, u16, u8);
-try_from_both_bounded!(i128, u64, u32, u16, u8);
-
-// usize/isize
-try_from_upper_bounded!(usize, isize);
-try_from_lower_bounded!(isize, usize);
-
-#[cfg(target_pointer_width = "16")]
-mod ptr_try_from_impls {
- use super::TryFromIntError;
- use crate::convert::TryFrom;
-
- try_from_upper_bounded!(usize, u8);
- try_from_unbounded!(usize, u16, u32, u64, u128);
- try_from_upper_bounded!(usize, i8, i16);
- try_from_unbounded!(usize, i32, i64, i128);
-
- try_from_both_bounded!(isize, u8);
- try_from_lower_bounded!(isize, u16, u32, u64, u128);
- try_from_both_bounded!(isize, i8);
- try_from_unbounded!(isize, i16, i32, i64, i128);
-
- rev!(try_from_upper_bounded, usize, u32, u64, u128);
- rev!(try_from_lower_bounded, usize, i8, i16);
- rev!(try_from_both_bounded, usize, i32, i64, i128);
-
- rev!(try_from_upper_bounded, isize, u16, u32, u64, u128);
- rev!(try_from_both_bounded, isize, i32, i64, i128);
-}
-
-#[cfg(target_pointer_width = "32")]
-mod ptr_try_from_impls {
- use super::TryFromIntError;
- use crate::convert::TryFrom;
-
- try_from_upper_bounded!(usize, u8, u16);
- try_from_unbounded!(usize, u32, u64, u128);
- try_from_upper_bounded!(usize, i8, i16, i32);
- try_from_unbounded!(usize, i64, i128);
-
- try_from_both_bounded!(isize, u8, u16);
- try_from_lower_bounded!(isize, u32, u64, u128);
- try_from_both_bounded!(isize, i8, i16);
- try_from_unbounded!(isize, i32, i64, i128);
-
- rev!(try_from_unbounded, usize, u32);
- rev!(try_from_upper_bounded, usize, u64, u128);
- rev!(try_from_lower_bounded, usize, i8, i16, i32);
- rev!(try_from_both_bounded, usize, i64, i128);
-
- rev!(try_from_unbounded, isize, u16);
- rev!(try_from_upper_bounded, isize, u32, u64, u128);
- rev!(try_from_unbounded, isize, i32);
- rev!(try_from_both_bounded, isize, i64, i128);
-}
-
-#[cfg(target_pointer_width = "64")]
-mod ptr_try_from_impls {
- use super::TryFromIntError;
- use crate::convert::TryFrom;
-
- try_from_upper_bounded!(usize, u8, u16, u32);
- try_from_unbounded!(usize, u64, u128);
- try_from_upper_bounded!(usize, i8, i16, i32, i64);
- try_from_unbounded!(usize, i128);
-
- try_from_both_bounded!(isize, u8, u16, u32);
- try_from_lower_bounded!(isize, u64, u128);
- try_from_both_bounded!(isize, i8, i16, i32);
- try_from_unbounded!(isize, i64, i128);
-
- rev!(try_from_unbounded, usize, u32, u64);
- rev!(try_from_upper_bounded, usize, u128);
- rev!(try_from_lower_bounded, usize, i8, i16, i32, i64);
- rev!(try_from_both_bounded, usize, i128);
-
- rev!(try_from_unbounded, isize, u16, u32);
- rev!(try_from_upper_bounded, isize, u64, u128);
- rev!(try_from_unbounded, isize, i32, i64);
- rev!(try_from_both_bounded, isize, i128);
-}
-
#[doc(hidden)]
trait FromStrRadixHelper: PartialOrd + Copy {
fn min_value() -> Self;
@@ -4966,9 +4768,11 @@
use self::IntErrorKind::*;
use self::ParseIntError as PIE;
- assert!(radix >= 2 && radix <= 36,
- "from_str_radix_int: must lie in the range `[2, 36]` - found {}",
- radix);
+ assert!(
+ radix >= 2 && radix <= 36,
+ "from_str_radix_int: must lie in the range `[2, 36]` - found {}",
+ radix
+ );
if src.is_empty() {
return Err(PIE { kind: Empty });
@@ -5049,10 +4853,12 @@
}
/// Enum to store the various types of errors that can cause parsing an integer to fail.
-#[unstable(feature = "int_error_matching",
- reason = "it can be useful to match errors when making error messages \
- for integer parsing",
- issue = "22639")]
+#[unstable(
+ feature = "int_error_matching",
+ reason = "it can be useful to match errors when making error messages \
+ for integer parsing",
+ issue = "22639"
+)]
#[derive(Debug, Clone, PartialEq, Eq)]
#[non_exhaustive]
pub enum IntErrorKind {
@@ -5078,17 +4884,21 @@
impl ParseIntError {
/// Outputs the detailed cause of parsing an integer failing.
- #[unstable(feature = "int_error_matching",
- reason = "it can be useful to match errors when making error messages \
- for integer parsing",
- issue = "22639")]
+ #[unstable(
+ feature = "int_error_matching",
+ reason = "it can be useful to match errors when making error messages \
+ for integer parsing",
+ issue = "22639"
+ )]
pub fn kind(&self) -> &IntErrorKind {
&self.kind
}
- #[unstable(feature = "int_error_internals",
- reason = "available through Error trait and this method should \
- not be exposed publicly",
- issue = "0")]
+ #[unstable(
+ feature = "int_error_internals",
+ reason = "available through Error trait and this method should \
+ not be exposed publicly",
+ issue = "0"
+ )]
#[doc(hidden)]
pub fn __description(&self) -> &str {
match self.kind {
@@ -5110,131 +4920,3 @@
#[stable(feature = "rust1", since = "1.0.0")]
pub use crate::num::dec2flt::ParseFloatError;
-
-// Conversion traits for primitive integer and float types
-// Conversions T -> T are covered by a blanket impl and therefore excluded
-// Some conversions from and to usize/isize are not implemented due to portability concerns
-macro_rules! impl_from {
- ($Small: ty, $Large: ty, #[$attr:meta], $doc: expr) => {
- #[$attr]
- #[doc = $doc]
- impl From<$Small> for $Large {
- #[inline]
- fn from(small: $Small) -> $Large {
- small as $Large
- }
- }
- };
- ($Small: ty, $Large: ty, #[$attr:meta]) => {
- impl_from!($Small,
- $Large,
- #[$attr],
- concat!("Converts `",
- stringify!($Small),
- "` to `",
- stringify!($Large),
- "` losslessly."));
- }
-}
-
-macro_rules! impl_from_bool {
- ($target: ty, #[$attr:meta]) => {
- impl_from!(bool, $target, #[$attr], concat!("Converts a `bool` to a `",
- stringify!($target), "`. The resulting value is `0` for `false` and `1` for `true`
-values.
-
-# Examples
-
-```
-assert_eq!(", stringify!($target), "::from(true), 1);
-assert_eq!(", stringify!($target), "::from(false), 0);
-```"));
- };
-}
-
-// Bool -> Any
-impl_from_bool! { u8, #[stable(feature = "from_bool", since = "1.28.0")] }
-impl_from_bool! { u16, #[stable(feature = "from_bool", since = "1.28.0")] }
-impl_from_bool! { u32, #[stable(feature = "from_bool", since = "1.28.0")] }
-impl_from_bool! { u64, #[stable(feature = "from_bool", since = "1.28.0")] }
-impl_from_bool! { u128, #[stable(feature = "from_bool", since = "1.28.0")] }
-impl_from_bool! { usize, #[stable(feature = "from_bool", since = "1.28.0")] }
-impl_from_bool! { i8, #[stable(feature = "from_bool", since = "1.28.0")] }
-impl_from_bool! { i16, #[stable(feature = "from_bool", since = "1.28.0")] }
-impl_from_bool! { i32, #[stable(feature = "from_bool", since = "1.28.0")] }
-impl_from_bool! { i64, #[stable(feature = "from_bool", since = "1.28.0")] }
-impl_from_bool! { i128, #[stable(feature = "from_bool", since = "1.28.0")] }
-impl_from_bool! { isize, #[stable(feature = "from_bool", since = "1.28.0")] }
-
-// Unsigned -> Unsigned
-impl_from! { u8, u16, #[stable(feature = "lossless_int_conv", since = "1.5.0")] }
-impl_from! { u8, u32, #[stable(feature = "lossless_int_conv", since = "1.5.0")] }
-impl_from! { u8, u64, #[stable(feature = "lossless_int_conv", since = "1.5.0")] }
-impl_from! { u8, u128, #[stable(feature = "i128", since = "1.26.0")] }
-impl_from! { u8, usize, #[stable(feature = "lossless_int_conv", since = "1.5.0")] }
-impl_from! { u16, u32, #[stable(feature = "lossless_int_conv", since = "1.5.0")] }
-impl_from! { u16, u64, #[stable(feature = "lossless_int_conv", since = "1.5.0")] }
-impl_from! { u16, u128, #[stable(feature = "i128", since = "1.26.0")] }
-impl_from! { u32, u64, #[stable(feature = "lossless_int_conv", since = "1.5.0")] }
-impl_from! { u32, u128, #[stable(feature = "i128", since = "1.26.0")] }
-impl_from! { u64, u128, #[stable(feature = "i128", since = "1.26.0")] }
-
-// Signed -> Signed
-impl_from! { i8, i16, #[stable(feature = "lossless_int_conv", since = "1.5.0")] }
-impl_from! { i8, i32, #[stable(feature = "lossless_int_conv", since = "1.5.0")] }
-impl_from! { i8, i64, #[stable(feature = "lossless_int_conv", since = "1.5.0")] }
-impl_from! { i8, i128, #[stable(feature = "i128", since = "1.26.0")] }
-impl_from! { i8, isize, #[stable(feature = "lossless_int_conv", since = "1.5.0")] }
-impl_from! { i16, i32, #[stable(feature = "lossless_int_conv", since = "1.5.0")] }
-impl_from! { i16, i64, #[stable(feature = "lossless_int_conv", since = "1.5.0")] }
-impl_from! { i16, i128, #[stable(feature = "i128", since = "1.26.0")] }
-impl_from! { i32, i64, #[stable(feature = "lossless_int_conv", since = "1.5.0")] }
-impl_from! { i32, i128, #[stable(feature = "i128", since = "1.26.0")] }
-impl_from! { i64, i128, #[stable(feature = "i128", since = "1.26.0")] }
-
-// Unsigned -> Signed
-impl_from! { u8, i16, #[stable(feature = "lossless_int_conv", since = "1.5.0")] }
-impl_from! { u8, i32, #[stable(feature = "lossless_int_conv", since = "1.5.0")] }
-impl_from! { u8, i64, #[stable(feature = "lossless_int_conv", since = "1.5.0")] }
-impl_from! { u8, i128, #[stable(feature = "i128", since = "1.26.0")] }
-impl_from! { u16, i32, #[stable(feature = "lossless_int_conv", since = "1.5.0")] }
-impl_from! { u16, i64, #[stable(feature = "lossless_int_conv", since = "1.5.0")] }
-impl_from! { u16, i128, #[stable(feature = "i128", since = "1.26.0")] }
-impl_from! { u32, i64, #[stable(feature = "lossless_int_conv", since = "1.5.0")] }
-impl_from! { u32, i128, #[stable(feature = "i128", since = "1.26.0")] }
-impl_from! { u64, i128, #[stable(feature = "i128", since = "1.26.0")] }
-
-// The C99 standard defines bounds on INTPTR_MIN, INTPTR_MAX, and UINTPTR_MAX
-// which imply that pointer-sized integers must be at least 16 bits:
-// https://port70.net/~nsz/c/c99/n1256.html#7.18.2.4
-impl_from! { u16, usize, #[stable(feature = "lossless_iusize_conv", since = "1.26.0")] }
-impl_from! { u8, isize, #[stable(feature = "lossless_iusize_conv", since = "1.26.0")] }
-impl_from! { i16, isize, #[stable(feature = "lossless_iusize_conv", since = "1.26.0")] }
-
-// RISC-V defines the possibility of a 128-bit address space (RV128).
-
-// CHERI proposes 256-bit “capabilities”. Unclear if this would be relevant to usize/isize.
-// https://www.cl.cam.ac.uk/research/security/ctsrd/pdfs/20171017a-cheri-poster.pdf
-// http://www.csl.sri.com/users/neumann/2012resolve-cheri.pdf
-
-
-// Note: integers can only be represented with full precision in a float if
-// they fit in the significand, which is 24 bits in f32 and 53 bits in f64.
-// Lossy float conversions are not implemented at this time.
-
-// Signed -> Float
-impl_from! { i8, f32, #[stable(feature = "lossless_float_conv", since = "1.6.0")] }
-impl_from! { i8, f64, #[stable(feature = "lossless_float_conv", since = "1.6.0")] }
-impl_from! { i16, f32, #[stable(feature = "lossless_float_conv", since = "1.6.0")] }
-impl_from! { i16, f64, #[stable(feature = "lossless_float_conv", since = "1.6.0")] }
-impl_from! { i32, f64, #[stable(feature = "lossless_float_conv", since = "1.6.0")] }
-
-// Unsigned -> Float
-impl_from! { u8, f32, #[stable(feature = "lossless_float_conv", since = "1.6.0")] }
-impl_from! { u8, f64, #[stable(feature = "lossless_float_conv", since = "1.6.0")] }
-impl_from! { u16, f32, #[stable(feature = "lossless_float_conv", since = "1.6.0")] }
-impl_from! { u16, f64, #[stable(feature = "lossless_float_conv", since = "1.6.0")] }
-impl_from! { u32, f64, #[stable(feature = "lossless_float_conv", since = "1.6.0")] }
-
-// Float -> Float
-impl_from! { f32, f64, #[stable(feature = "lossless_float_conv", since = "1.6.0")] }
diff --git a/src/libcore/ops/try.rs b/src/libcore/ops/try.rs
index a748ee8..22ba97b 100644
--- a/src/libcore/ops/try.rs
+++ b/src/libcore/ops/try.rs
@@ -5,20 +5,28 @@
/// extracting those success or failure values from an existing instance and
/// creating a new instance from a success or failure value.
#[unstable(feature = "try_trait", issue = "42327")]
-#[cfg_attr(not(bootstrap), rustc_on_unimplemented(
-on(all(
-any(from_method="from_error", from_method="from_ok"),
-from_desugaring="QuestionMark"),
-message="the `?` operator can only be used in {ItemContext} \
- that returns `Result` or `Option` \
- (or another type that implements `{Try}`)",
-label="cannot use the `?` operator in {ItemContext} that returns `{Self}`",
-enclosing_scope="this function should return `Result` or `Option` to accept `?`"),
-on(all(from_method="into_result", from_desugaring="QuestionMark"),
-message="the `?` operator can only be applied to values \
- that implement `{Try}`",
-label="the `?` operator cannot be applied to type `{Self}`")
-))]
+#[cfg_attr(
+ not(bootstrap),
+ rustc_on_unimplemented(
+ on(
+ all(
+ any(from_method = "from_error", from_method = "from_ok"),
+ from_desugaring = "QuestionMark"
+ ),
+ message = "the `?` operator can only be used in {ItemContext} \
+ that returns `Result` or `Option` \
+ (or another type that implements `{Try}`)",
+ label = "cannot use the `?` operator in {ItemContext} that returns `{Self}`",
+ enclosing_scope = "this function should return `Result` or `Option` to accept `?`"
+ ),
+ on(
+ all(from_method = "into_result", from_desugaring = "QuestionMark"),
+ message = "the `?` operator can only be applied to values \
+ that implement `{Try}`",
+ label = "the `?` operator cannot be applied to type `{Self}`"
+ )
+ )
+)]
#[doc(alias = "?")]
pub trait Try {
/// The type of this value when viewed as successful.
diff --git a/src/libcore/panic.rs b/src/libcore/panic.rs
index 99b372d..e924ee2 100644
--- a/src/libcore/panic.rs
+++ b/src/libcore/panic.rs
@@ -177,6 +177,60 @@
}
impl<'a> Location<'a> {
+ /// Returns the source location of the caller of this function. If that function's caller is
+ /// annotated then its call location will be returned, and so on up the stack to the first call
+ /// within a non-tracked function body.
+ ///
+ /// # Examples
+ ///
+ /// ```
+ /// #![feature(track_caller)]
+ /// use core::panic::Location;
+ ///
+ /// /// Returns the [`Location`] at which it is called.
+ /// #[track_caller]
+ /// fn get_caller_location() -> &'static Location<'static> {
+ /// Location::caller()
+ /// }
+ ///
+ /// /// Returns a [`Location`] from within this function's definition.
+ /// fn get_just_one_location() -> &'static Location<'static> {
+ /// get_caller_location()
+ /// }
+ ///
+ /// let fixed_location = get_just_one_location();
+ /// assert_eq!(fixed_location.file(), file!());
+ /// assert_eq!(fixed_location.line(), 15);
+ /// assert_eq!(fixed_location.column(), 5);
+ ///
+ /// // running the same untracked function in a different location gives us the same result
+ /// let second_fixed_location = get_just_one_location();
+ /// assert_eq!(fixed_location.file(), second_fixed_location.file());
+ /// assert_eq!(fixed_location.line(), second_fixed_location.line());
+ /// assert_eq!(fixed_location.column(), second_fixed_location.column());
+ ///
+ /// let this_location = get_caller_location();
+ /// assert_eq!(this_location.file(), file!());
+ /// assert_eq!(this_location.line(), 29);
+ /// assert_eq!(this_location.column(), 21);
+ ///
+ /// // running the tracked function in a different location produces a different value
+ /// let another_location = get_caller_location();
+ /// assert_eq!(this_location.file(), another_location.file());
+ /// assert_ne!(this_location.line(), another_location.line());
+ /// assert_ne!(this_location.column(), another_location.column());
+ /// ```
+ #[cfg(not(bootstrap))]
+ #[unstable(feature = "track_caller",
+ reason = "uses #[track_caller] which is not yet stable",
+ issue = "47809")]
+ #[track_caller]
+ pub const fn caller() -> &'static Location<'static> {
+ crate::intrinsics::caller_location()
+ }
+}
+
+impl<'a> Location<'a> {
#![unstable(feature = "panic_internals",
reason = "internal details of the implementation of the `panic!` \
and related macros",
diff --git a/src/libcore/panicking.rs b/src/libcore/panicking.rs
index 5a8d647..4857b11 100644
--- a/src/libcore/panicking.rs
+++ b/src/libcore/panicking.rs
@@ -22,10 +22,12 @@
// ignore-tidy-undocumented-unsafe
#![allow(dead_code, missing_docs)]
-#![unstable(feature = "core_panic",
- reason = "internal details of the implementation of the `panic!` \
- and related macros",
- issue = "0")]
+#![unstable(
+ feature = "core_panic",
+ reason = "internal details of the implementation of the `panic!` \
+ and related macros",
+ issue = "0"
+)]
use crate::fmt;
use crate::panic::{Location, PanicInfo};
@@ -33,7 +35,7 @@
#[cold]
// never inline unless panic_immediate_abort to avoid code
// bloat at the call sites as much as possible
-#[cfg_attr(not(feature="panic_immediate_abort"),inline(never))]
+#[cfg_attr(not(feature = "panic_immediate_abort"), inline(never))]
#[lang = "panic"] // needed by codegen for panic on overflow and other `Assert` MIR terminators
pub fn panic(expr: &str, location: &Location<'_>) -> ! {
if cfg!(feature = "panic_immediate_abort") {
@@ -50,7 +52,7 @@
}
#[cold]
-#[cfg_attr(not(feature="panic_immediate_abort"),inline(never))]
+#[cfg_attr(not(feature = "panic_immediate_abort"), inline(never))]
#[lang = "panic_bounds_check"] // needed by codegen for panic on OOB array/slice access
fn panic_bounds_check(location: &Location<'_>, index: usize, len: usize) -> ! {
if cfg!(feature = "panic_immediate_abort") {
@@ -59,13 +61,13 @@
panic_fmt(
format_args!("index out of bounds: the len is {} but the index is {}", len, index),
- location
+ location,
)
}
#[cold]
-#[cfg_attr(not(feature="panic_immediate_abort"),inline(never))]
-#[cfg_attr( feature="panic_immediate_abort" ,inline)]
+#[cfg_attr(not(feature = "panic_immediate_abort"), inline(never))]
+#[cfg_attr(feature = "panic_immediate_abort", inline)]
pub fn panic_fmt(fmt: fmt::Arguments<'_>, location: &Location<'_>) -> ! {
if cfg!(feature = "panic_immediate_abort") {
unsafe { super::intrinsics::abort() }
diff --git a/src/libcore/pin.rs b/src/libcore/pin.rs
index 88fa718..6a0c5bb 100644
--- a/src/libcore/pin.rs
+++ b/src/libcore/pin.rs
@@ -376,6 +376,7 @@
use crate::cmp::{self, PartialEq, PartialOrd};
use crate::fmt;
+use crate::hash::{Hash, Hasher};
use crate::marker::{Sized, Unpin};
use crate::ops::{CoerceUnsized, Deref, DerefMut, DispatchFromDyn, Receiver};
@@ -390,55 +391,78 @@
/// [`Unpin`]: ../../std/marker/trait.Unpin.html
/// [`pin` module]: ../../std/pin/index.html
//
-// Note: the derives below, and the explicit `PartialEq` and `PartialOrd`
-// implementations, are allowed because they all only use `&P`, so they cannot move
-// the value behind `pointer`.
+// Note: the `Clone` derive below causes unsoundness as it's possible to implement
+// `Clone` for mutable references.
+// See <https://internals.rust-lang.org/t/unsoundness-in-pin/11311> for more details.
#[stable(feature = "pin", since = "1.33.0")]
#[lang = "pin"]
#[fundamental]
#[repr(transparent)]
-#[derive(Copy, Clone, Hash, Eq, Ord)]
+#[derive(Copy, Clone)]
pub struct Pin<P> {
pointer: P,
}
-#[stable(feature = "pin_partialeq_partialord_impl_applicability", since = "1.34.0")]
-impl<P, Q> PartialEq<Pin<Q>> for Pin<P>
+// The following implementations aren't derived in order to avoid soundness
+// issues. `&self.pointer` should not be accessible to untrusted trait
+// implementations.
+//
+// See <https://internals.rust-lang.org/t/unsoundness-in-pin/11311/73> for more details.
+
+#[stable(feature = "pin_trait_impls", since = "1.41.0")]
+impl<P: Deref, Q: Deref> PartialEq<Pin<Q>> for Pin<P>
where
- P: PartialEq<Q>,
+ P::Target: PartialEq<Q::Target>,
{
fn eq(&self, other: &Pin<Q>) -> bool {
- self.pointer == other.pointer
+ P::Target::eq(self, other)
}
fn ne(&self, other: &Pin<Q>) -> bool {
- self.pointer != other.pointer
+ P::Target::ne(self, other)
}
}
-#[stable(feature = "pin_partialeq_partialord_impl_applicability", since = "1.34.0")]
-impl<P, Q> PartialOrd<Pin<Q>> for Pin<P>
+#[stable(feature = "pin_trait_impls", since = "1.41.0")]
+impl<P: Deref<Target: Eq>> Eq for Pin<P> {}
+
+#[stable(feature = "pin_trait_impls", since = "1.41.0")]
+impl<P: Deref, Q: Deref> PartialOrd<Pin<Q>> for Pin<P>
where
- P: PartialOrd<Q>,
+ P::Target: PartialOrd<Q::Target>,
{
fn partial_cmp(&self, other: &Pin<Q>) -> Option<cmp::Ordering> {
- self.pointer.partial_cmp(&other.pointer)
+ P::Target::partial_cmp(self, other)
}
fn lt(&self, other: &Pin<Q>) -> bool {
- self.pointer < other.pointer
+ P::Target::lt(self, other)
}
fn le(&self, other: &Pin<Q>) -> bool {
- self.pointer <= other.pointer
+ P::Target::le(self, other)
}
fn gt(&self, other: &Pin<Q>) -> bool {
- self.pointer > other.pointer
+ P::Target::gt(self, other)
}
fn ge(&self, other: &Pin<Q>) -> bool {
- self.pointer >= other.pointer
+ P::Target::ge(self, other)
+ }
+}
+
+#[stable(feature = "pin_trait_impls", since = "1.41.0")]
+impl<P: Deref<Target: Ord>> Ord for Pin<P> {
+ fn cmp(&self, other: &Self) -> cmp::Ordering {
+ P::Target::cmp(self, other)
+ }
+}
+
+#[stable(feature = "pin_trait_impls", since = "1.41.0")]
+impl<P: Deref<Target: Hash>> Hash for Pin<P> {
+ fn hash<H: Hasher>(&self, state: &mut H) {
+ P::Target::hash(self, state);
}
}
diff --git a/src/libcore/ptr/mod.rs b/src/libcore/ptr/mod.rs
index 1e051db..24ffa34 100644
--- a/src/libcore/ptr/mod.rs
+++ b/src/libcore/ptr/mod.rs
@@ -65,15 +65,16 @@
//! [`write_volatile`]: ./fn.write_volatile.html
//! [`NonNull::dangling`]: ./struct.NonNull.html#method.dangling
+// ignore-tidy-filelength
// ignore-tidy-undocumented-unsafe
#![stable(feature = "rust1", since = "1.0.0")]
-use crate::intrinsics;
+use crate::cmp::Ordering::{self, Equal, Greater, Less};
use crate::fmt;
use crate::hash;
+use crate::intrinsics;
use crate::mem::{self, MaybeUninit};
-use crate::cmp::Ordering::{self, Less, Equal, Greater};
#[stable(feature = "rust1", since = "1.0.0")]
pub use crate::intrinsics::copy_nonoverlapping;
@@ -197,7 +198,9 @@
#[inline(always)]
#[stable(feature = "rust1", since = "1.0.0")]
#[rustc_promotable]
-pub const fn null<T>() -> *const T { 0 as *const T }
+pub const fn null<T>() -> *const T {
+ 0 as *const T
+}
/// Creates a null mutable raw pointer.
///
@@ -212,7 +215,9 @@
#[inline(always)]
#[stable(feature = "rust1", since = "1.0.0")]
#[rustc_promotable]
-pub const fn null_mut<T>() -> *mut T { 0 as *mut T }
+pub const fn null_mut<T>() -> *mut T {
+ 0 as *mut T
+}
#[repr(C)]
pub(crate) union Repr<T> {
@@ -704,9 +709,7 @@
#[stable(feature = "ptr_unaligned", since = "1.17.0")]
pub unsafe fn read_unaligned<T>(src: *const T) -> T {
let mut tmp = MaybeUninit::<T>::uninit();
- copy_nonoverlapping(src as *const u8,
- tmp.as_mut_ptr() as *mut u8,
- mem::size_of::<T>());
+ copy_nonoverlapping(src as *const u8, tmp.as_mut_ptr() as *mut u8, mem::size_of::<T>());
tmp.assume_init()
}
@@ -889,9 +892,7 @@
#[inline]
#[stable(feature = "ptr_unaligned", since = "1.17.0")]
pub unsafe fn write_unaligned<T>(dst: *mut T, src: T) {
- copy_nonoverlapping(&src as *const T as *const u8,
- dst as *mut u8,
- mem::size_of::<T>());
+ copy_nonoverlapping(&src as *const T as *const u8, dst as *mut u8, mem::size_of::<T>());
mem::forget(src);
}
@@ -1122,11 +1123,7 @@
#[stable(feature = "ptr_as_ref", since = "1.9.0")]
#[inline]
pub unsafe fn as_ref<'a>(self) -> Option<&'a T> {
- if self.is_null() {
- None
- } else {
- Some(&*self)
- }
+ if self.is_null() { None } else { Some(&*self) }
}
/// Calculates the offset from a pointer.
@@ -1182,7 +1179,10 @@
/// ```
#[stable(feature = "rust1", since = "1.0.0")]
#[inline]
- pub unsafe fn offset(self, count: isize) -> *const T where T: Sized {
+ pub unsafe fn offset(self, count: isize) -> *const T
+ where
+ T: Sized,
+ {
intrinsics::offset(self, count)
}
@@ -1237,10 +1237,11 @@
/// ```
#[stable(feature = "ptr_wrapping_offset", since = "1.16.0")]
#[inline]
- pub fn wrapping_offset(self, count: isize) -> *const T where T: Sized {
- unsafe {
- intrinsics::arith_offset(self, count)
- }
+ pub fn wrapping_offset(self, count: isize) -> *const T
+ where
+ T: Sized,
+ {
+ unsafe { intrinsics::arith_offset(self, count) }
}
/// Calculates the distance between two pointers. The returned value is in
@@ -1308,7 +1309,10 @@
#[unstable(feature = "ptr_offset_from", issue = "41079")]
#[rustc_const_unstable(feature = "const_ptr_offset_from")]
#[inline]
- pub const unsafe fn offset_from(self, origin: *const T) -> isize where T: Sized {
+ pub const unsafe fn offset_from(self, origin: *const T) -> isize
+ where
+ T: Sized,
+ {
let pointee_size = mem::size_of::<T>();
let ok = 0 < pointee_size && pointee_size <= isize::max_value() as usize;
// assert that the pointee size is valid in a const eval compatible way
@@ -1353,7 +1357,10 @@
/// ```
#[unstable(feature = "ptr_wrapping_offset_from", issue = "41079")]
#[inline]
- pub fn wrapping_offset_from(self, origin: *const T) -> isize where T: Sized {
+ pub fn wrapping_offset_from(self, origin: *const T) -> isize
+ where
+ T: Sized,
+ {
let pointee_size = mem::size_of::<T>();
assert!(0 < pointee_size && pointee_size <= isize::max_value() as usize);
@@ -1415,7 +1422,8 @@
#[stable(feature = "pointer_methods", since = "1.26.0")]
#[inline]
pub unsafe fn add(self, count: usize) -> Self
- where T: Sized,
+ where
+ T: Sized,
{
self.offset(count as isize)
}
@@ -1475,7 +1483,8 @@
#[stable(feature = "pointer_methods", since = "1.26.0")]
#[inline]
pub unsafe fn sub(self, count: usize) -> Self
- where T: Sized,
+ where
+ T: Sized,
{
self.offset((count as isize).wrapping_neg())
}
@@ -1529,7 +1538,8 @@
#[stable(feature = "pointer_methods", since = "1.26.0")]
#[inline]
pub fn wrapping_add(self, count: usize) -> Self
- where T: Sized,
+ where
+ T: Sized,
{
self.wrapping_offset(count as isize)
}
@@ -1583,7 +1593,8 @@
#[stable(feature = "pointer_methods", since = "1.26.0")]
#[inline]
pub fn wrapping_sub(self, count: usize) -> Self
- where T: Sized,
+ where
+ T: Sized,
{
self.wrapping_offset((count as isize).wrapping_neg())
}
@@ -1597,7 +1608,8 @@
#[stable(feature = "pointer_methods", since = "1.26.0")]
#[inline]
pub unsafe fn read(self) -> T
- where T: Sized,
+ where
+ T: Sized,
{
read(self)
}
@@ -1615,7 +1627,8 @@
#[stable(feature = "pointer_methods", since = "1.26.0")]
#[inline]
pub unsafe fn read_volatile(self) -> T
- where T: Sized,
+ where
+ T: Sized,
{
read_volatile(self)
}
@@ -1631,7 +1644,8 @@
#[stable(feature = "pointer_methods", since = "1.26.0")]
#[inline]
pub unsafe fn read_unaligned(self) -> T
- where T: Sized,
+ where
+ T: Sized,
{
read_unaligned(self)
}
@@ -1647,7 +1661,8 @@
#[stable(feature = "pointer_methods", since = "1.26.0")]
#[inline]
pub unsafe fn copy_to(self, dest: *mut T, count: usize)
- where T: Sized,
+ where
+ T: Sized,
{
copy(self, dest, count)
}
@@ -1663,7 +1678,8 @@
#[stable(feature = "pointer_methods", since = "1.26.0")]
#[inline]
pub unsafe fn copy_to_nonoverlapping(self, dest: *mut T, count: usize)
- where T: Sized,
+ where
+ T: Sized,
{
copy_nonoverlapping(self, dest, count)
}
@@ -1708,17 +1724,17 @@
/// # } }
/// ```
#[stable(feature = "align_offset", since = "1.36.0")]
- pub fn align_offset(self, align: usize) -> usize where T: Sized {
+ pub fn align_offset(self, align: usize) -> usize
+ where
+ T: Sized,
+ {
if !align.is_power_of_two() {
panic!("align_offset: align is not a power-of-two");
}
- unsafe {
- align_offset(self, align)
- }
+ unsafe { align_offset(self, align) }
}
}
-
#[lang = "mut_ptr"]
impl<T: ?Sized> *mut T {
/// Returns `true` if the pointer is null.
@@ -1805,11 +1821,7 @@
#[stable(feature = "ptr_as_ref", since = "1.9.0")]
#[inline]
pub unsafe fn as_ref<'a>(self) -> Option<&'a T> {
- if self.is_null() {
- None
- } else {
- Some(&*self)
- }
+ if self.is_null() { None } else { Some(&*self) }
}
/// Calculates the offset from a pointer.
@@ -1865,7 +1877,10 @@
/// ```
#[stable(feature = "rust1", since = "1.0.0")]
#[inline]
- pub unsafe fn offset(self, count: isize) -> *mut T where T: Sized {
+ pub unsafe fn offset(self, count: isize) -> *mut T
+ where
+ T: Sized,
+ {
intrinsics::offset(self, count) as *mut T
}
@@ -1919,10 +1934,11 @@
/// ```
#[stable(feature = "ptr_wrapping_offset", since = "1.16.0")]
#[inline]
- pub fn wrapping_offset(self, count: isize) -> *mut T where T: Sized {
- unsafe {
- intrinsics::arith_offset(self, count) as *mut T
- }
+ pub fn wrapping_offset(self, count: isize) -> *mut T
+ where
+ T: Sized,
+ {
+ unsafe { intrinsics::arith_offset(self, count) as *mut T }
}
/// Returns `None` if the pointer is null, or else returns a mutable
@@ -1967,11 +1983,7 @@
#[stable(feature = "ptr_as_ref", since = "1.9.0")]
#[inline]
pub unsafe fn as_mut<'a>(self) -> Option<&'a mut T> {
- if self.is_null() {
- None
- } else {
- Some(&mut *self)
- }
+ if self.is_null() { None } else { Some(&mut *self) }
}
/// Calculates the distance between two pointers. The returned value is in
@@ -2039,7 +2051,10 @@
#[unstable(feature = "ptr_offset_from", issue = "41079")]
#[rustc_const_unstable(feature = "const_ptr_offset_from")]
#[inline]
- pub const unsafe fn offset_from(self, origin: *const T) -> isize where T: Sized {
+ pub const unsafe fn offset_from(self, origin: *const T) -> isize
+ where
+ T: Sized,
+ {
(self as *const T).offset_from(origin)
}
@@ -2079,7 +2094,10 @@
/// ```
#[unstable(feature = "ptr_wrapping_offset_from", issue = "41079")]
#[inline]
- pub fn wrapping_offset_from(self, origin: *const T) -> isize where T: Sized {
+ pub fn wrapping_offset_from(self, origin: *const T) -> isize
+ where
+ T: Sized,
+ {
(self as *const T).wrapping_offset_from(origin)
}
@@ -2137,7 +2155,8 @@
#[stable(feature = "pointer_methods", since = "1.26.0")]
#[inline]
pub unsafe fn add(self, count: usize) -> Self
- where T: Sized,
+ where
+ T: Sized,
{
self.offset(count as isize)
}
@@ -2197,7 +2216,8 @@
#[stable(feature = "pointer_methods", since = "1.26.0")]
#[inline]
pub unsafe fn sub(self, count: usize) -> Self
- where T: Sized,
+ where
+ T: Sized,
{
self.offset((count as isize).wrapping_neg())
}
@@ -2251,7 +2271,8 @@
#[stable(feature = "pointer_methods", since = "1.26.0")]
#[inline]
pub fn wrapping_add(self, count: usize) -> Self
- where T: Sized,
+ where
+ T: Sized,
{
self.wrapping_offset(count as isize)
}
@@ -2305,7 +2326,8 @@
#[stable(feature = "pointer_methods", since = "1.26.0")]
#[inline]
pub fn wrapping_sub(self, count: usize) -> Self
- where T: Sized,
+ where
+ T: Sized,
{
self.wrapping_offset((count as isize).wrapping_neg())
}
@@ -2319,7 +2341,8 @@
#[stable(feature = "pointer_methods", since = "1.26.0")]
#[inline]
pub unsafe fn read(self) -> T
- where T: Sized,
+ where
+ T: Sized,
{
read(self)
}
@@ -2337,7 +2360,8 @@
#[stable(feature = "pointer_methods", since = "1.26.0")]
#[inline]
pub unsafe fn read_volatile(self) -> T
- where T: Sized,
+ where
+ T: Sized,
{
read_volatile(self)
}
@@ -2353,7 +2377,8 @@
#[stable(feature = "pointer_methods", since = "1.26.0")]
#[inline]
pub unsafe fn read_unaligned(self) -> T
- where T: Sized,
+ where
+ T: Sized,
{
read_unaligned(self)
}
@@ -2369,7 +2394,8 @@
#[stable(feature = "pointer_methods", since = "1.26.0")]
#[inline]
pub unsafe fn copy_to(self, dest: *mut T, count: usize)
- where T: Sized,
+ where
+ T: Sized,
{
copy(self, dest, count)
}
@@ -2385,7 +2411,8 @@
#[stable(feature = "pointer_methods", since = "1.26.0")]
#[inline]
pub unsafe fn copy_to_nonoverlapping(self, dest: *mut T, count: usize)
- where T: Sized,
+ where
+ T: Sized,
{
copy_nonoverlapping(self, dest, count)
}
@@ -2401,7 +2428,8 @@
#[stable(feature = "pointer_methods", since = "1.26.0")]
#[inline]
pub unsafe fn copy_from(self, src: *const T, count: usize)
- where T: Sized,
+ where
+ T: Sized,
{
copy(src, self, count)
}
@@ -2417,7 +2445,8 @@
#[stable(feature = "pointer_methods", since = "1.26.0")]
#[inline]
pub unsafe fn copy_from_nonoverlapping(self, src: *const T, count: usize)
- where T: Sized,
+ where
+ T: Sized,
{
copy_nonoverlapping(src, self, count)
}
@@ -2442,7 +2471,8 @@
#[stable(feature = "pointer_methods", since = "1.26.0")]
#[inline]
pub unsafe fn write(self, val: T)
- where T: Sized,
+ where
+ T: Sized,
{
write(self, val)
}
@@ -2456,7 +2486,8 @@
#[stable(feature = "pointer_methods", since = "1.26.0")]
#[inline]
pub unsafe fn write_bytes(self, val: u8, count: usize)
- where T: Sized,
+ where
+ T: Sized,
{
write_bytes(self, val, count)
}
@@ -2474,7 +2505,8 @@
#[stable(feature = "pointer_methods", since = "1.26.0")]
#[inline]
pub unsafe fn write_volatile(self, val: T)
- where T: Sized,
+ where
+ T: Sized,
{
write_volatile(self, val)
}
@@ -2490,7 +2522,8 @@
#[stable(feature = "pointer_methods", since = "1.26.0")]
#[inline]
pub unsafe fn write_unaligned(self, val: T)
- where T: Sized,
+ where
+ T: Sized,
{
write_unaligned(self, val)
}
@@ -2504,7 +2537,8 @@
#[stable(feature = "pointer_methods", since = "1.26.0")]
#[inline]
pub unsafe fn replace(self, src: T) -> T
- where T: Sized,
+ where
+ T: Sized,
{
replace(self, src)
}
@@ -2519,7 +2553,8 @@
#[stable(feature = "pointer_methods", since = "1.26.0")]
#[inline]
pub unsafe fn swap(self, with: *mut T)
- where T: Sized,
+ where
+ T: Sized,
{
swap(self, with)
}
@@ -2564,13 +2599,14 @@
/// # } }
/// ```
#[stable(feature = "align_offset", since = "1.36.0")]
- pub fn align_offset(self, align: usize) -> usize where T: Sized {
+ pub fn align_offset(self, align: usize) -> usize
+ where
+ T: Sized,
+ {
if !align.is_power_of_two() {
panic!("align_offset: align is not a power-of-two");
}
- unsafe {
- align_offset(self, align)
- }
+ unsafe { align_offset(self, align) }
}
}
@@ -2588,7 +2624,7 @@
/// than trying to adapt this to accommodate that change.
///
/// Any questions go to @nagisa.
-#[lang="align_offset"]
+#[lang = "align_offset"]
pub(crate) unsafe fn align_offset<T: Sized>(p: *const T, a: usize) -> usize {
/// Calculate multiplicative modular inverse of `x` modulo `m`.
///
@@ -2628,9 +2664,8 @@
// uses e.g., subtraction `mod n`. It is entirely fine to do them `mod
// usize::max_value()` instead, because we take the result `mod n` at the end
// anyway.
- inverse = inverse.wrapping_mul(
- 2usize.wrapping_sub(x.wrapping_mul(inverse))
- ) & (going_mod - 1);
+ inverse = inverse.wrapping_mul(2usize.wrapping_sub(x.wrapping_mul(inverse)))
+ & (going_mod - 1);
if going_mod > m {
return inverse & (m - 1);
}
@@ -2689,13 +2724,13 @@
usize::max_value()
}
-
-
// Equality for pointers
#[stable(feature = "rust1", since = "1.0.0")]
impl<T: ?Sized> PartialEq for *const T {
#[inline]
- fn eq(&self, other: &*const T) -> bool { *self == *other }
+ fn eq(&self, other: &*const T) -> bool {
+ *self == *other
+ }
}
#[stable(feature = "rust1", since = "1.0.0")]
@@ -2704,7 +2739,9 @@
#[stable(feature = "rust1", since = "1.0.0")]
impl<T: ?Sized> PartialEq for *mut T {
#[inline]
- fn eq(&self, other: &*mut T) -> bool { *self == *other }
+ fn eq(&self, other: &*mut T) -> bool {
+ *self == *other
+ }
}
#[stable(feature = "rust1", since = "1.0.0")]
@@ -2890,7 +2927,7 @@
};
}
-fnptr_impls_args! { }
+fnptr_impls_args! {}
fnptr_impls_args! { A }
fnptr_impls_args! { A, B }
fnptr_impls_args! { A, B, C }
@@ -2927,16 +2964,24 @@
}
#[inline]
- fn lt(&self, other: &*const T) -> bool { *self < *other }
+ fn lt(&self, other: &*const T) -> bool {
+ *self < *other
+ }
#[inline]
- fn le(&self, other: &*const T) -> bool { *self <= *other }
+ fn le(&self, other: &*const T) -> bool {
+ *self <= *other
+ }
#[inline]
- fn gt(&self, other: &*const T) -> bool { *self > *other }
+ fn gt(&self, other: &*const T) -> bool {
+ *self > *other
+ }
#[inline]
- fn ge(&self, other: &*const T) -> bool { *self >= *other }
+ fn ge(&self, other: &*const T) -> bool {
+ *self >= *other
+ }
}
#[stable(feature = "rust1", since = "1.0.0")]
@@ -2961,14 +3006,22 @@
}
#[inline]
- fn lt(&self, other: &*mut T) -> bool { *self < *other }
+ fn lt(&self, other: &*mut T) -> bool {
+ *self < *other
+ }
#[inline]
- fn le(&self, other: &*mut T) -> bool { *self <= *other }
+ fn le(&self, other: &*mut T) -> bool {
+ *self <= *other
+ }
#[inline]
- fn gt(&self, other: &*mut T) -> bool { *self > *other }
+ fn gt(&self, other: &*mut T) -> bool {
+ *self > *other
+ }
#[inline]
- fn ge(&self, other: &*mut T) -> bool { *self >= *other }
+ fn ge(&self, other: &*mut T) -> bool {
+ *self >= *other
+ }
}
diff --git a/src/libcore/str/mod.rs b/src/libcore/str/mod.rs
index 25b7eec..b2a420f 100644
--- a/src/libcore/str/mod.rs
+++ b/src/libcore/str/mod.rs
@@ -3371,8 +3371,8 @@
/// An iterator over the disjoint matches of a pattern within the given string
/// slice.
///
- /// The pattern can be any type that implements the Pattern trait. Notable
- /// examples are `&str`, [`char`], and closures that determines the split.
+ /// The pattern can be a `&str`, [`char`], or a closure that determines if
+ /// a character matches.
///
/// # Iterator behavior
///
diff --git a/src/libcore/str/pattern.rs b/src/libcore/str/pattern.rs
index a494274..1037da1 100644
--- a/src/libcore/str/pattern.rs
+++ b/src/libcore/str/pattern.rs
@@ -296,12 +296,7 @@
fn next_match(&mut self) -> Option<(usize, usize)> {
loop {
// get the haystack after the last character found
- let bytes = if let Some(slice) = self.haystack.as_bytes()
- .get(self.finger..self.finger_back) {
- slice
- } else {
- return None;
- };
+ let bytes = self.haystack.as_bytes().get(self.finger..self.finger_back)?;
// the last byte of the utf8 encoded needle
let last_byte = unsafe { *self.utf8_encoded.get_unchecked(self.utf8_size - 1) };
if let Some(index) = memchr::memchr(last_byte, bytes) {
diff --git a/src/libcore/sync/atomic.rs b/src/libcore/sync/atomic.rs
index 251d49d..6e1aac0 100644
--- a/src/libcore/sync/atomic.rs
+++ b/src/libcore/sync/atomic.rs
@@ -27,7 +27,7 @@
//!
//! Atomic variables are safe to share between threads (they implement [`Sync`])
//! but they do not themselves provide the mechanism for sharing and follow the
-//! [threading model](../../../std/thread/index.html#the-threading-model) of rust.
+//! [threading model](../../../std/thread/index.html#the-threading-model) of Rust.
//! The most common way to share an atomic variable is to put it into an [`Arc`][arc] (an
//! atomically-reference-counted shared pointer).
//!
diff --git a/src/libcore/tests/any.rs b/src/libcore/tests/any.rs
index 62bebcb..b0dc990 100644
--- a/src/libcore/tests/any.rs
+++ b/src/libcore/tests/any.rs
@@ -24,11 +24,8 @@
#[test]
fn any_owning() {
- let (a, b, c) = (
- box 5_usize as Box<dyn Any>,
- box TEST as Box<dyn Any>,
- box Test as Box<dyn Any>,
- );
+ let (a, b, c) =
+ (box 5_usize as Box<dyn Any>, box TEST as Box<dyn Any>, box Test as Box<dyn Any>);
assert!(a.is::<usize>());
assert!(!b.is::<usize>());
@@ -49,12 +46,12 @@
match a.downcast_ref::<usize>() {
Some(&5) => {}
- x => panic!("Unexpected value {:?}", x)
+ x => panic!("Unexpected value {:?}", x),
}
match a.downcast_ref::<Test>() {
None => {}
- x => panic!("Unexpected value {:?}", x)
+ x => panic!("Unexpected value {:?}", x),
}
}
@@ -72,7 +69,7 @@
assert_eq!(*x, 5);
*x = 612;
}
- x => panic!("Unexpected value {:?}", x)
+ x => panic!("Unexpected value {:?}", x),
}
match b_r.downcast_mut::<usize>() {
@@ -80,27 +77,27 @@
assert_eq!(*x, 7);
*x = 413;
}
- x => panic!("Unexpected value {:?}", x)
+ x => panic!("Unexpected value {:?}", x),
}
match a_r.downcast_mut::<Test>() {
None => (),
- x => panic!("Unexpected value {:?}", x)
+ x => panic!("Unexpected value {:?}", x),
}
match b_r.downcast_mut::<Test>() {
None => (),
- x => panic!("Unexpected value {:?}", x)
+ x => panic!("Unexpected value {:?}", x),
}
match a_r.downcast_mut::<usize>() {
Some(&mut 612) => {}
- x => panic!("Unexpected value {:?}", x)
+ x => panic!("Unexpected value {:?}", x),
}
match b_r.downcast_mut::<usize>() {
Some(&mut 413) => {}
- x => panic!("Unexpected value {:?}", x)
+ x => panic!("Unexpected value {:?}", x),
}
}
diff --git a/src/libcore/tests/array.rs b/src/libcore/tests/array.rs
index 4f3b79c..c2a816f 100644
--- a/src/libcore/tests/array.rs
+++ b/src/libcore/tests/array.rs
@@ -41,7 +41,6 @@
}
}
-
#[test]
fn iterator_collect() {
let arr = [0, 1, 2, 5, 9];
@@ -150,10 +149,7 @@
#[test]
fn iterator_debug() {
let arr = [0, 1, 2, 5, 9];
- assert_eq!(
- format!("{:?}", IntoIter::new(arr)),
- "IntoIter([0, 1, 2, 5, 9])",
- );
+ assert_eq!(format!("{:?}", IntoIter::new(arr)), "IntoIter([0, 1, 2, 5, 9])",);
}
#[test]
@@ -168,7 +164,7 @@
struct Foo<'a>(&'a Cell<usize>);
impl Drop for Foo<'_> {
- fn drop(&mut self) {
+ fn drop(&mut self) {
self.0.set(self.0.get() + 1);
}
}
diff --git a/src/libcore/tests/ascii.rs b/src/libcore/tests/ascii.rs
index 439ed0c..71275d4 100644
--- a/src/libcore/tests/ascii.rs
+++ b/src/libcore/tests/ascii.rs
@@ -22,10 +22,12 @@
assert_eq!("hıKß".to_ascii_uppercase(), "HıKß");
for i in 0..501 {
- let upper = if 'a' as u32 <= i && i <= 'z' as u32 { i + 'A' as u32 - 'a' as u32 }
- else { i };
- assert_eq!((from_u32(i).unwrap()).to_string().to_ascii_uppercase(),
- (from_u32(upper).unwrap()).to_string());
+ let upper =
+ if 'a' as u32 <= i && i <= 'z' as u32 { i + 'A' as u32 - 'a' as u32 } else { i };
+ assert_eq!(
+ (from_u32(i).unwrap()).to_string().to_ascii_uppercase(),
+ (from_u32(upper).unwrap()).to_string()
+ );
}
}
@@ -36,23 +38,23 @@
assert_eq!("HİKß".to_ascii_lowercase(), "hİKß");
for i in 0..501 {
- let lower = if 'A' as u32 <= i && i <= 'Z' as u32 { i + 'a' as u32 - 'A' as u32 }
- else { i };
- assert_eq!((from_u32(i).unwrap()).to_string().to_ascii_lowercase(),
- (from_u32(lower).unwrap()).to_string());
+ let lower =
+ if 'A' as u32 <= i && i <= 'Z' as u32 { i + 'a' as u32 - 'A' as u32 } else { i };
+ assert_eq!(
+ (from_u32(i).unwrap()).to_string().to_ascii_lowercase(),
+ (from_u32(lower).unwrap()).to_string()
+ );
}
}
#[test]
fn test_make_ascii_lower_case() {
macro_rules! test {
- ($from: expr, $to: expr) => {
- {
- let mut x = $from;
- x.make_ascii_lowercase();
- assert_eq!(x, $to);
- }
- }
+ ($from: expr, $to: expr) => {{
+ let mut x = $from;
+ x.make_ascii_lowercase();
+ assert_eq!(x, $to);
+ }};
}
test!(b'A', b'a');
test!(b'a', b'a');
@@ -65,17 +67,14 @@
test!("HİKß".to_string(), "hİKß");
}
-
#[test]
fn test_make_ascii_upper_case() {
macro_rules! test {
- ($from: expr, $to: expr) => {
- {
- let mut x = $from;
- x.make_ascii_uppercase();
- assert_eq!(x, $to);
- }
- }
+ ($from: expr, $to: expr) => {{
+ let mut x = $from;
+ x.make_ascii_uppercase();
+ assert_eq!(x, $to);
+ }};
}
test!(b'a', b'A');
test!(b'A', b'A');
@@ -88,7 +87,7 @@
test!("hıKß".to_string(), "HıKß");
let mut x = "Hello".to_string();
- x[..3].make_ascii_uppercase(); // Test IndexMut on String.
+ x[..3].make_ascii_uppercase(); // Test IndexMut on String.
assert_eq!(x, "HELlo")
}
@@ -103,10 +102,13 @@
assert!(!"ß".eq_ignore_ascii_case("s"));
for i in 0..501 {
- let lower = if 'A' as u32 <= i && i <= 'Z' as u32 { i + 'a' as u32 - 'A' as u32 }
- else { i };
- assert!((from_u32(i).unwrap()).to_string().eq_ignore_ascii_case(
- &from_u32(lower).unwrap().to_string()));
+ let lower =
+ if 'A' as u32 <= i && i <= 'Z' as u32 { i + 'a' as u32 - 'A' as u32 } else { i };
+ assert!(
+ (from_u32(i).unwrap())
+ .to_string()
+ .eq_ignore_ascii_case(&from_u32(lower).unwrap().to_string())
+ );
}
}
@@ -158,12 +160,14 @@
#[test]
fn test_is_ascii_alphabetic() {
- assert_all!(is_ascii_alphabetic,
+ assert_all!(
+ is_ascii_alphabetic,
"",
"abcdefghijklmnopqrstuvwxyz",
"ABCDEFGHIJKLMNOQPRSTUVWXYZ",
);
- assert_none!(is_ascii_alphabetic,
+ assert_none!(
+ is_ascii_alphabetic,
"0123456789",
"!\"#$%&'()*+,-./:;<=>?@[\\]^_`{|}~",
" \t\n\x0c\r",
@@ -177,11 +181,9 @@
#[test]
fn test_is_ascii_uppercase() {
- assert_all!(is_ascii_uppercase,
- "",
- "ABCDEFGHIJKLMNOQPRSTUVWXYZ",
- );
- assert_none!(is_ascii_uppercase,
+ assert_all!(is_ascii_uppercase, "", "ABCDEFGHIJKLMNOQPRSTUVWXYZ",);
+ assert_none!(
+ is_ascii_uppercase,
"abcdefghijklmnopqrstuvwxyz",
"0123456789",
"!\"#$%&'()*+,-./:;<=>?@[\\]^_`{|}~",
@@ -196,10 +198,9 @@
#[test]
fn test_is_ascii_lowercase() {
- assert_all!(is_ascii_lowercase,
- "abcdefghijklmnopqrstuvwxyz",
- );
- assert_none!(is_ascii_lowercase,
+ assert_all!(is_ascii_lowercase, "abcdefghijklmnopqrstuvwxyz",);
+ assert_none!(
+ is_ascii_lowercase,
"ABCDEFGHIJKLMNOQPRSTUVWXYZ",
"0123456789",
"!\"#$%&'()*+,-./:;<=>?@[\\]^_`{|}~",
@@ -214,13 +215,15 @@
#[test]
fn test_is_ascii_alphanumeric() {
- assert_all!(is_ascii_alphanumeric,
+ assert_all!(
+ is_ascii_alphanumeric,
"",
"abcdefghijklmnopqrstuvwxyz",
"ABCDEFGHIJKLMNOQPRSTUVWXYZ",
"0123456789",
);
- assert_none!(is_ascii_alphanumeric,
+ assert_none!(
+ is_ascii_alphanumeric,
"!\"#$%&'()*+,-./:;<=>?@[\\]^_`{|}~",
" \t\n\x0c\r",
"\x00\x01\x02\x03\x04\x05\x06\x07",
@@ -233,11 +236,9 @@
#[test]
fn test_is_ascii_digit() {
- assert_all!(is_ascii_digit,
- "",
- "0123456789",
- );
- assert_none!(is_ascii_digit,
+ assert_all!(is_ascii_digit, "", "0123456789",);
+ assert_none!(
+ is_ascii_digit,
"abcdefghijklmnopqrstuvwxyz",
"ABCDEFGHIJKLMNOQPRSTUVWXYZ",
"!\"#$%&'()*+,-./:;<=>?@[\\]^_`{|}~",
@@ -252,12 +253,9 @@
#[test]
fn test_is_ascii_hexdigit() {
- assert_all!(is_ascii_hexdigit,
- "",
- "0123456789",
- "abcdefABCDEF",
- );
- assert_none!(is_ascii_hexdigit,
+ assert_all!(is_ascii_hexdigit, "", "0123456789", "abcdefABCDEF",);
+ assert_none!(
+ is_ascii_hexdigit,
"ghijklmnopqrstuvwxyz",
"GHIJKLMNOQPRSTUVWXYZ",
"!\"#$%&'()*+,-./:;<=>?@[\\]^_`{|}~",
@@ -272,11 +270,9 @@
#[test]
fn test_is_ascii_punctuation() {
- assert_all!(is_ascii_punctuation,
- "",
- "!\"#$%&'()*+,-./:;<=>?@[\\]^_`{|}~",
- );
- assert_none!(is_ascii_punctuation,
+ assert_all!(is_ascii_punctuation, "", "!\"#$%&'()*+,-./:;<=>?@[\\]^_`{|}~",);
+ assert_none!(
+ is_ascii_punctuation,
"abcdefghijklmnopqrstuvwxyz",
"ABCDEFGHIJKLMNOQPRSTUVWXYZ",
"0123456789",
@@ -291,14 +287,16 @@
#[test]
fn test_is_ascii_graphic() {
- assert_all!(is_ascii_graphic,
+ assert_all!(
+ is_ascii_graphic,
"",
"abcdefghijklmnopqrstuvwxyz",
"ABCDEFGHIJKLMNOQPRSTUVWXYZ",
"0123456789",
"!\"#$%&'()*+,-./:;<=>?@[\\]^_`{|}~",
);
- assert_none!(is_ascii_graphic,
+ assert_none!(
+ is_ascii_graphic,
" \t\n\x0c\r",
"\x00\x01\x02\x03\x04\x05\x06\x07",
"\x08\x09\x0a\x0b\x0c\x0d\x0e\x0f",
@@ -310,11 +308,9 @@
#[test]
fn test_is_ascii_whitespace() {
- assert_all!(is_ascii_whitespace,
- "",
- " \t\n\x0c\r",
- );
- assert_none!(is_ascii_whitespace,
+ assert_all!(is_ascii_whitespace, "", " \t\n\x0c\r",);
+ assert_none!(
+ is_ascii_whitespace,
"abcdefghijklmnopqrstuvwxyz",
"ABCDEFGHIJKLMNOQPRSTUVWXYZ",
"0123456789",
@@ -329,7 +325,8 @@
#[test]
fn test_is_ascii_control() {
- assert_all!(is_ascii_control,
+ assert_all!(
+ is_ascii_control,
"",
"\x00\x01\x02\x03\x04\x05\x06\x07",
"\x08\x09\x0a\x0b\x0c\x0d\x0e\x0f",
@@ -337,7 +334,8 @@
"\x18\x19\x1a\x1b\x1c\x1d\x1e\x1f",
"\x7f",
);
- assert_none!(is_ascii_control,
+ assert_none!(
+ is_ascii_control,
"abcdefghijklmnopqrstuvwxyz",
"ABCDEFGHIJKLMNOQPRSTUVWXYZ",
"0123456789",
diff --git a/src/libcore/tests/atomic.rs b/src/libcore/tests/atomic.rs
index 05fe846..acbd913 100644
--- a/src/libcore/tests/atomic.rs
+++ b/src/libcore/tests/atomic.rs
@@ -1,5 +1,5 @@
-use core::sync::atomic::*;
use core::sync::atomic::Ordering::SeqCst;
+use core::sync::atomic::*;
#[test]
fn bool_() {
@@ -15,7 +15,7 @@
fn bool_and() {
let a = AtomicBool::new(true);
assert_eq!(a.fetch_and(false, SeqCst), true);
- assert_eq!(a.load(SeqCst),false);
+ assert_eq!(a.load(SeqCst), false);
}
#[test]
@@ -89,7 +89,7 @@
static S_FALSE: AtomicBool = AtomicBool::new(false);
static S_TRUE: AtomicBool = AtomicBool::new(true);
-static S_INT: AtomicIsize = AtomicIsize::new(0);
+static S_INT: AtomicIsize = AtomicIsize::new(0);
static S_UINT: AtomicUsize = AtomicUsize::new(0);
#[test]
diff --git a/src/libcore/tests/bool.rs b/src/libcore/tests/bool.rs
index 0f1e6e8..e89eb2c 100644
--- a/src/libcore/tests/bool.rs
+++ b/src/libcore/tests/bool.rs
@@ -1,7 +1,7 @@
#[test]
fn test_bool_to_option() {
- assert_eq!(false.then(0), None);
- assert_eq!(true.then(0), Some(0));
- assert_eq!(false.then_with(|| 0), None);
- assert_eq!(true.then_with(|| 0), Some(0));
+ assert_eq!(false.then_some(0), None);
+ assert_eq!(true.then_some(0), Some(0));
+ assert_eq!(false.then(|| 0), None);
+ assert_eq!(true.then(|| 0), Some(0));
}
diff --git a/src/libcore/tests/cell.rs b/src/libcore/tests/cell.rs
index 4dfd884..801b60b 100644
--- a/src/libcore/tests/cell.rs
+++ b/src/libcore/tests/cell.rs
@@ -236,7 +236,7 @@
}
let x = X(RefCell::new((7, 'z')));
{
- let mut d: RefMut<'_ ,u32> = x.accessor();
+ let mut d: RefMut<'_, u32> = x.accessor();
assert_eq!(*d, 7);
*d += 1;
}
@@ -250,7 +250,9 @@
assert_eq!(1, unsafe { *c1.as_ptr() });
let c2: Cell<usize> = Cell::new(0);
- unsafe { *c2.as_ptr() = 1; }
+ unsafe {
+ *c2.as_ptr() = 1;
+ }
assert_eq!(1, c2.get());
let r1: RefCell<usize> = RefCell::new(0);
@@ -258,7 +260,9 @@
assert_eq!(1, unsafe { *r1.as_ptr() });
let r2: RefCell<usize> = RefCell::new(0);
- unsafe { *r2.as_ptr() = 1; }
+ unsafe {
+ *r2.as_ptr() = 1;
+ }
assert_eq!(1, *r2.borrow());
}
diff --git a/src/libcore/tests/char.rs b/src/libcore/tests/char.rs
index 57e9f4e..c16f540 100644
--- a/src/libcore/tests/char.rs
+++ b/src/libcore/tests/char.rs
@@ -1,6 +1,6 @@
-use std::{char,str};
use std::convert::TryFrom;
use std::str::FromStr;
+use std::{char, str};
#[test]
fn test_convert() {
@@ -143,13 +143,13 @@
#[test]
fn test_is_numeric() {
- assert!('2'.is_numeric());
- assert!('7'.is_numeric());
- assert!('¾'.is_numeric());
- assert!(!'c'.is_numeric());
- assert!(!'i'.is_numeric());
- assert!(!'z'.is_numeric());
- assert!(!'Q'.is_numeric());
+ assert!('2'.is_numeric());
+ assert!('7'.is_numeric());
+ assert!('¾'.is_numeric());
+ assert!(!'c'.is_numeric());
+ assert!(!'i'.is_numeric());
+ assert!(!'z'.is_numeric());
+ assert!(!'Q'.is_numeric());
}
#[test]
@@ -176,9 +176,9 @@
assert_eq!(string('\u{ff}'), "\u{ff}");
assert_eq!(string('\u{11b}'), "\u{11b}");
assert_eq!(string('\u{1d4b6}'), "\u{1d4b6}");
- assert_eq!(string('\u{301}'), "\\u{301}"); // combining character
- assert_eq!(string('\u{200b}'),"\\u{200b}"); // zero width space
- assert_eq!(string('\u{e000}'), "\\u{e000}"); // private use 1
+ assert_eq!(string('\u{301}'), "\\u{301}"); // combining character
+ assert_eq!(string('\u{200b}'), "\\u{200b}"); // zero width space
+ assert_eq!(string('\u{e000}'), "\\u{e000}"); // private use 1
assert_eq!(string('\u{100000}'), "\\u{100000}"); // private use 2
}
@@ -272,8 +272,8 @@
fn test_decode_utf16() {
fn check(s: &[u16], expected: &[Result<char, u16>]) {
let v = char::decode_utf16(s.iter().cloned())
- .map(|r| r.map_err(|e| e.unpaired_surrogate()))
- .collect::<Vec<_>>();
+ .map(|r| r.map_err(|e| e.unpaired_surrogate()))
+ .collect::<Vec<_>>();
assert_eq!(v, expected);
}
check(&[0xD800, 0x41, 0x42], &[Err(0xD800), Ok('A'), Ok('B')]);
diff --git a/src/libcore/tests/cmp.rs b/src/libcore/tests/cmp.rs
index 5e6778e..56a2f4a 100644
--- a/src/libcore/tests/cmp.rs
+++ b/src/libcore/tests/cmp.rs
@@ -10,6 +10,14 @@
}
#[test]
+fn test_bool_totalord() {
+ assert_eq!(true.cmp(&false), Greater);
+ assert_eq!(false.cmp(&true), Less);
+ assert_eq!(true.cmp(&true), Equal);
+ assert_eq!(false.cmp(&false), Equal);
+}
+
+#[test]
fn test_mut_int_totalord() {
assert_eq!((&mut 5).cmp(&&mut 10), Less);
assert_eq!((&mut 10).cmp(&&mut 5), Greater);
diff --git a/src/libcore/tests/hash/mod.rs b/src/libcore/tests/hash/mod.rs
index 1000088..ba0220f 100644
--- a/src/libcore/tests/hash/mod.rs
+++ b/src/libcore/tests/hash/mod.rs
@@ -1,7 +1,7 @@
mod sip;
-use std::hash::{Hash, Hasher};
use std::default::Default;
+use std::hash::{Hash, Hasher};
use std::rc::Rc;
struct MyHasher {
@@ -20,10 +20,11 @@
self.hash += *byte as u64;
}
}
- fn finish(&self) -> u64 { self.hash }
+ fn finish(&self) -> u64 {
+ self.hash
+ }
}
-
#[test]
fn test_writer_hasher() {
fn hash<T: Hash>(t: &T) -> u64 {
@@ -52,17 +53,17 @@
assert_eq!(hash(&'a'), 97);
let s: &str = "a";
- assert_eq!(hash(& s), 97 + 0xFF);
+ assert_eq!(hash(&s), 97 + 0xFF);
let s: Box<str> = String::from("a").into_boxed_str();
- assert_eq!(hash(& s), 97 + 0xFF);
+ assert_eq!(hash(&s), 97 + 0xFF);
let s: Rc<&str> = Rc::new("a");
assert_eq!(hash(&s), 97 + 0xFF);
let cs: &[u8] = &[1, 2, 3];
- assert_eq!(hash(& cs), 9);
+ assert_eq!(hash(&cs), 9);
let cs: Box<[u8]> = Box::new([1, 2, 3]);
- assert_eq!(hash(& cs), 9);
+ assert_eq!(hash(&cs), 9);
let cs: Rc<[u8]> = Rc::new([1, 2, 3]);
- assert_eq!(hash(& cs), 9);
+ assert_eq!(hash(&cs), 9);
let ptr = 5_usize as *const i32;
assert_eq!(hash(&ptr), 5);
@@ -70,24 +71,36 @@
let ptr = 5_usize as *mut i32;
assert_eq!(hash(&ptr), 5);
+ if cfg!(miri) { // Miri cannot hash pointers
+ return;
+ }
+
let cs: &mut [u8] = &mut [1, 2, 3];
let ptr = cs.as_ptr();
let slice_ptr = cs as *const [u8];
- #[cfg(not(miri))] // Miri cannot hash pointers
assert_eq!(hash(&slice_ptr), hash(&ptr) + cs.len() as u64);
let slice_ptr = cs as *mut [u8];
- #[cfg(not(miri))] // Miri cannot hash pointers
assert_eq!(hash(&slice_ptr), hash(&ptr) + cs.len() as u64);
}
-struct Custom { hash: u64 }
-struct CustomHasher { output: u64 }
+struct Custom {
+ hash: u64,
+}
+struct CustomHasher {
+ output: u64,
+}
impl Hasher for CustomHasher {
- fn finish(&self) -> u64 { self.output }
- fn write(&mut self, _: &[u8]) { panic!() }
- fn write_u64(&mut self, data: u64) { self.output = data; }
+ fn finish(&self) -> u64 {
+ self.output
+ }
+ fn write(&mut self, _: &[u8]) {
+ panic!()
+ }
+ fn write_u64(&mut self, data: u64) {
+ self.output = data;
+ }
}
impl Default for CustomHasher {
diff --git a/src/libcore/tests/hash/sip.rs b/src/libcore/tests/hash/sip.rs
index b615cfd..0f09554 100644
--- a/src/libcore/tests/hash/sip.rs
+++ b/src/libcore/tests/hash/sip.rs
@@ -2,7 +2,7 @@
use core::hash::{Hash, Hasher};
use core::hash::{SipHasher, SipHasher13};
-use core::{slice, mem};
+use core::{mem, slice};
// Hash just the bytes of the slice, without length prefix
struct Bytes<'a>(&'a [u8]);
@@ -16,25 +16,25 @@
}
macro_rules! u8to64_le {
- ($buf:expr, $i:expr) =>
- ($buf[0+$i] as u64 |
- ($buf[1+$i] as u64) << 8 |
- ($buf[2+$i] as u64) << 16 |
- ($buf[3+$i] as u64) << 24 |
- ($buf[4+$i] as u64) << 32 |
- ($buf[5+$i] as u64) << 40 |
- ($buf[6+$i] as u64) << 48 |
- ($buf[7+$i] as u64) << 56);
- ($buf:expr, $i:expr, $len:expr) =>
- ({
+ ($buf:expr, $i:expr) => {
+ $buf[0 + $i] as u64
+ | ($buf[1 + $i] as u64) << 8
+ | ($buf[2 + $i] as u64) << 16
+ | ($buf[3 + $i] as u64) << 24
+ | ($buf[4 + $i] as u64) << 32
+ | ($buf[5 + $i] as u64) << 40
+ | ($buf[6 + $i] as u64) << 48
+ | ($buf[7 + $i] as u64) << 56
+ };
+ ($buf:expr, $i:expr, $len:expr) => {{
let mut t = 0;
let mut out = 0;
while t < $len {
- out |= ($buf[t+$i] as u64) << t*8;
+ out |= ($buf[t + $i] as u64) << t * 8;
t += 1;
}
out
- });
+ }};
}
fn hash_with<H: Hasher, T: Hash>(mut st: H, x: &T) -> u64 {
@@ -49,71 +49,71 @@
#[test]
#[allow(unused_must_use)]
fn test_siphash_1_3() {
- let vecs : [[u8; 8]; 64] = [
- [ 0xdc, 0xc4, 0x0f, 0x05, 0x58, 0x01, 0xac, 0xab ],
- [ 0x93, 0xca, 0x57, 0x7d, 0xf3, 0x9b, 0xf4, 0xc9 ],
- [ 0x4d, 0xd4, 0xc7, 0x4d, 0x02, 0x9b, 0xcb, 0x82 ],
- [ 0xfb, 0xf7, 0xdd, 0xe7, 0xb8, 0x0a, 0xf8, 0x8b ],
- [ 0x28, 0x83, 0xd3, 0x88, 0x60, 0x57, 0x75, 0xcf ],
- [ 0x67, 0x3b, 0x53, 0x49, 0x2f, 0xd5, 0xf9, 0xde ],
- [ 0xa7, 0x22, 0x9f, 0xc5, 0x50, 0x2b, 0x0d, 0xc5 ],
- [ 0x40, 0x11, 0xb1, 0x9b, 0x98, 0x7d, 0x92, 0xd3 ],
- [ 0x8e, 0x9a, 0x29, 0x8d, 0x11, 0x95, 0x90, 0x36 ],
- [ 0xe4, 0x3d, 0x06, 0x6c, 0xb3, 0x8e, 0xa4, 0x25 ],
- [ 0x7f, 0x09, 0xff, 0x92, 0xee, 0x85, 0xde, 0x79 ],
- [ 0x52, 0xc3, 0x4d, 0xf9, 0xc1, 0x18, 0xc1, 0x70 ],
- [ 0xa2, 0xd9, 0xb4, 0x57, 0xb1, 0x84, 0xa3, 0x78 ],
- [ 0xa7, 0xff, 0x29, 0x12, 0x0c, 0x76, 0x6f, 0x30 ],
- [ 0x34, 0x5d, 0xf9, 0xc0, 0x11, 0xa1, 0x5a, 0x60 ],
- [ 0x56, 0x99, 0x51, 0x2a, 0x6d, 0xd8, 0x20, 0xd3 ],
- [ 0x66, 0x8b, 0x90, 0x7d, 0x1a, 0xdd, 0x4f, 0xcc ],
- [ 0x0c, 0xd8, 0xdb, 0x63, 0x90, 0x68, 0xf2, 0x9c ],
- [ 0x3e, 0xe6, 0x73, 0xb4, 0x9c, 0x38, 0xfc, 0x8f ],
- [ 0x1c, 0x7d, 0x29, 0x8d, 0xe5, 0x9d, 0x1f, 0xf2 ],
- [ 0x40, 0xe0, 0xcc, 0xa6, 0x46, 0x2f, 0xdc, 0xc0 ],
- [ 0x44, 0xf8, 0x45, 0x2b, 0xfe, 0xab, 0x92, 0xb9 ],
- [ 0x2e, 0x87, 0x20, 0xa3, 0x9b, 0x7b, 0xfe, 0x7f ],
- [ 0x23, 0xc1, 0xe6, 0xda, 0x7f, 0x0e, 0x5a, 0x52 ],
- [ 0x8c, 0x9c, 0x34, 0x67, 0xb2, 0xae, 0x64, 0xf4 ],
- [ 0x79, 0x09, 0x5b, 0x70, 0x28, 0x59, 0xcd, 0x45 ],
- [ 0xa5, 0x13, 0x99, 0xca, 0xe3, 0x35, 0x3e, 0x3a ],
- [ 0x35, 0x3b, 0xde, 0x4a, 0x4e, 0xc7, 0x1d, 0xa9 ],
- [ 0x0d, 0xd0, 0x6c, 0xef, 0x02, 0xed, 0x0b, 0xfb ],
- [ 0xf4, 0xe1, 0xb1, 0x4a, 0xb4, 0x3c, 0xd9, 0x88 ],
- [ 0x63, 0xe6, 0xc5, 0x43, 0xd6, 0x11, 0x0f, 0x54 ],
- [ 0xbc, 0xd1, 0x21, 0x8c, 0x1f, 0xdd, 0x70, 0x23 ],
- [ 0x0d, 0xb6, 0xa7, 0x16, 0x6c, 0x7b, 0x15, 0x81 ],
- [ 0xbf, 0xf9, 0x8f, 0x7a, 0xe5, 0xb9, 0x54, 0x4d ],
- [ 0x3e, 0x75, 0x2a, 0x1f, 0x78, 0x12, 0x9f, 0x75 ],
- [ 0x91, 0x6b, 0x18, 0xbf, 0xbe, 0xa3, 0xa1, 0xce ],
- [ 0x06, 0x62, 0xa2, 0xad, 0xd3, 0x08, 0xf5, 0x2c ],
- [ 0x57, 0x30, 0xc3, 0xa3, 0x2d, 0x1c, 0x10, 0xb6 ],
- [ 0xa1, 0x36, 0x3a, 0xae, 0x96, 0x74, 0xf4, 0xb3 ],
- [ 0x92, 0x83, 0x10, 0x7b, 0x54, 0x57, 0x6b, 0x62 ],
- [ 0x31, 0x15, 0xe4, 0x99, 0x32, 0x36, 0xd2, 0xc1 ],
- [ 0x44, 0xd9, 0x1a, 0x3f, 0x92, 0xc1, 0x7c, 0x66 ],
- [ 0x25, 0x88, 0x13, 0xc8, 0xfe, 0x4f, 0x70, 0x65 ],
- [ 0xa6, 0x49, 0x89, 0xc2, 0xd1, 0x80, 0xf2, 0x24 ],
- [ 0x6b, 0x87, 0xf8, 0xfa, 0xed, 0x1c, 0xca, 0xc2 ],
- [ 0x96, 0x21, 0x04, 0x9f, 0xfc, 0x4b, 0x16, 0xc2 ],
- [ 0x23, 0xd6, 0xb1, 0x68, 0x93, 0x9c, 0x6e, 0xa1 ],
- [ 0xfd, 0x14, 0x51, 0x8b, 0x9c, 0x16, 0xfb, 0x49 ],
- [ 0x46, 0x4c, 0x07, 0xdf, 0xf8, 0x43, 0x31, 0x9f ],
- [ 0xb3, 0x86, 0xcc, 0x12, 0x24, 0xaf, 0xfd, 0xc6 ],
- [ 0x8f, 0x09, 0x52, 0x0a, 0xd1, 0x49, 0xaf, 0x7e ],
- [ 0x9a, 0x2f, 0x29, 0x9d, 0x55, 0x13, 0xf3, 0x1c ],
- [ 0x12, 0x1f, 0xf4, 0xa2, 0xdd, 0x30, 0x4a, 0xc4 ],
- [ 0xd0, 0x1e, 0xa7, 0x43, 0x89, 0xe9, 0xfa, 0x36 ],
- [ 0xe6, 0xbc, 0xf0, 0x73, 0x4c, 0xb3, 0x8f, 0x31 ],
- [ 0x80, 0xe9, 0xa7, 0x70, 0x36, 0xbf, 0x7a, 0xa2 ],
- [ 0x75, 0x6d, 0x3c, 0x24, 0xdb, 0xc0, 0xbc, 0xb4 ],
- [ 0x13, 0x15, 0xb7, 0xfd, 0x52, 0xd8, 0xf8, 0x23 ],
- [ 0x08, 0x8a, 0x7d, 0xa6, 0x4d, 0x5f, 0x03, 0x8f ],
- [ 0x48, 0xf1, 0xe8, 0xb7, 0xe5, 0xd0, 0x9c, 0xd8 ],
- [ 0xee, 0x44, 0xa6, 0xf7, 0xbc, 0xe6, 0xf4, 0xf6 ],
- [ 0xf2, 0x37, 0x18, 0x0f, 0xd8, 0x9a, 0xc5, 0xae ],
- [ 0xe0, 0x94, 0x66, 0x4b, 0x15, 0xf6, 0xb2, 0xc3 ],
- [ 0xa8, 0xb3, 0xbb, 0xb7, 0x62, 0x90, 0x19, 0x9d ]
+ let vecs: [[u8; 8]; 64] = [
+ [0xdc, 0xc4, 0x0f, 0x05, 0x58, 0x01, 0xac, 0xab],
+ [0x93, 0xca, 0x57, 0x7d, 0xf3, 0x9b, 0xf4, 0xc9],
+ [0x4d, 0xd4, 0xc7, 0x4d, 0x02, 0x9b, 0xcb, 0x82],
+ [0xfb, 0xf7, 0xdd, 0xe7, 0xb8, 0x0a, 0xf8, 0x8b],
+ [0x28, 0x83, 0xd3, 0x88, 0x60, 0x57, 0x75, 0xcf],
+ [0x67, 0x3b, 0x53, 0x49, 0x2f, 0xd5, 0xf9, 0xde],
+ [0xa7, 0x22, 0x9f, 0xc5, 0x50, 0x2b, 0x0d, 0xc5],
+ [0x40, 0x11, 0xb1, 0x9b, 0x98, 0x7d, 0x92, 0xd3],
+ [0x8e, 0x9a, 0x29, 0x8d, 0x11, 0x95, 0x90, 0x36],
+ [0xe4, 0x3d, 0x06, 0x6c, 0xb3, 0x8e, 0xa4, 0x25],
+ [0x7f, 0x09, 0xff, 0x92, 0xee, 0x85, 0xde, 0x79],
+ [0x52, 0xc3, 0x4d, 0xf9, 0xc1, 0x18, 0xc1, 0x70],
+ [0xa2, 0xd9, 0xb4, 0x57, 0xb1, 0x84, 0xa3, 0x78],
+ [0xa7, 0xff, 0x29, 0x12, 0x0c, 0x76, 0x6f, 0x30],
+ [0x34, 0x5d, 0xf9, 0xc0, 0x11, 0xa1, 0x5a, 0x60],
+ [0x56, 0x99, 0x51, 0x2a, 0x6d, 0xd8, 0x20, 0xd3],
+ [0x66, 0x8b, 0x90, 0x7d, 0x1a, 0xdd, 0x4f, 0xcc],
+ [0x0c, 0xd8, 0xdb, 0x63, 0x90, 0x68, 0xf2, 0x9c],
+ [0x3e, 0xe6, 0x73, 0xb4, 0x9c, 0x38, 0xfc, 0x8f],
+ [0x1c, 0x7d, 0x29, 0x8d, 0xe5, 0x9d, 0x1f, 0xf2],
+ [0x40, 0xe0, 0xcc, 0xa6, 0x46, 0x2f, 0xdc, 0xc0],
+ [0x44, 0xf8, 0x45, 0x2b, 0xfe, 0xab, 0x92, 0xb9],
+ [0x2e, 0x87, 0x20, 0xa3, 0x9b, 0x7b, 0xfe, 0x7f],
+ [0x23, 0xc1, 0xe6, 0xda, 0x7f, 0x0e, 0x5a, 0x52],
+ [0x8c, 0x9c, 0x34, 0x67, 0xb2, 0xae, 0x64, 0xf4],
+ [0x79, 0x09, 0x5b, 0x70, 0x28, 0x59, 0xcd, 0x45],
+ [0xa5, 0x13, 0x99, 0xca, 0xe3, 0x35, 0x3e, 0x3a],
+ [0x35, 0x3b, 0xde, 0x4a, 0x4e, 0xc7, 0x1d, 0xa9],
+ [0x0d, 0xd0, 0x6c, 0xef, 0x02, 0xed, 0x0b, 0xfb],
+ [0xf4, 0xe1, 0xb1, 0x4a, 0xb4, 0x3c, 0xd9, 0x88],
+ [0x63, 0xe6, 0xc5, 0x43, 0xd6, 0x11, 0x0f, 0x54],
+ [0xbc, 0xd1, 0x21, 0x8c, 0x1f, 0xdd, 0x70, 0x23],
+ [0x0d, 0xb6, 0xa7, 0x16, 0x6c, 0x7b, 0x15, 0x81],
+ [0xbf, 0xf9, 0x8f, 0x7a, 0xe5, 0xb9, 0x54, 0x4d],
+ [0x3e, 0x75, 0x2a, 0x1f, 0x78, 0x12, 0x9f, 0x75],
+ [0x91, 0x6b, 0x18, 0xbf, 0xbe, 0xa3, 0xa1, 0xce],
+ [0x06, 0x62, 0xa2, 0xad, 0xd3, 0x08, 0xf5, 0x2c],
+ [0x57, 0x30, 0xc3, 0xa3, 0x2d, 0x1c, 0x10, 0xb6],
+ [0xa1, 0x36, 0x3a, 0xae, 0x96, 0x74, 0xf4, 0xb3],
+ [0x92, 0x83, 0x10, 0x7b, 0x54, 0x57, 0x6b, 0x62],
+ [0x31, 0x15, 0xe4, 0x99, 0x32, 0x36, 0xd2, 0xc1],
+ [0x44, 0xd9, 0x1a, 0x3f, 0x92, 0xc1, 0x7c, 0x66],
+ [0x25, 0x88, 0x13, 0xc8, 0xfe, 0x4f, 0x70, 0x65],
+ [0xa6, 0x49, 0x89, 0xc2, 0xd1, 0x80, 0xf2, 0x24],
+ [0x6b, 0x87, 0xf8, 0xfa, 0xed, 0x1c, 0xca, 0xc2],
+ [0x96, 0x21, 0x04, 0x9f, 0xfc, 0x4b, 0x16, 0xc2],
+ [0x23, 0xd6, 0xb1, 0x68, 0x93, 0x9c, 0x6e, 0xa1],
+ [0xfd, 0x14, 0x51, 0x8b, 0x9c, 0x16, 0xfb, 0x49],
+ [0x46, 0x4c, 0x07, 0xdf, 0xf8, 0x43, 0x31, 0x9f],
+ [0xb3, 0x86, 0xcc, 0x12, 0x24, 0xaf, 0xfd, 0xc6],
+ [0x8f, 0x09, 0x52, 0x0a, 0xd1, 0x49, 0xaf, 0x7e],
+ [0x9a, 0x2f, 0x29, 0x9d, 0x55, 0x13, 0xf3, 0x1c],
+ [0x12, 0x1f, 0xf4, 0xa2, 0xdd, 0x30, 0x4a, 0xc4],
+ [0xd0, 0x1e, 0xa7, 0x43, 0x89, 0xe9, 0xfa, 0x36],
+ [0xe6, 0xbc, 0xf0, 0x73, 0x4c, 0xb3, 0x8f, 0x31],
+ [0x80, 0xe9, 0xa7, 0x70, 0x36, 0xbf, 0x7a, 0xa2],
+ [0x75, 0x6d, 0x3c, 0x24, 0xdb, 0xc0, 0xbc, 0xb4],
+ [0x13, 0x15, 0xb7, 0xfd, 0x52, 0xd8, 0xf8, 0x23],
+ [0x08, 0x8a, 0x7d, 0xa6, 0x4d, 0x5f, 0x03, 0x8f],
+ [0x48, 0xf1, 0xe8, 0xb7, 0xe5, 0xd0, 0x9c, 0xd8],
+ [0xee, 0x44, 0xa6, 0xf7, 0xbc, 0xe6, 0xf4, 0xf6],
+ [0xf2, 0x37, 0x18, 0x0f, 0xd8, 0x9a, 0xc5, 0xae],
+ [0xe0, 0x94, 0x66, 0x4b, 0x15, 0xf6, 0xb2, 0xc3],
+ [0xa8, 0xb3, 0xbb, 0xb7, 0x62, 0x90, 0x19, 0x9d],
];
let k0 = 0x_07_06_05_04_03_02_01_00;
@@ -143,71 +143,71 @@
#[test]
#[allow(unused_must_use)]
fn test_siphash_2_4() {
- let vecs : [[u8; 8]; 64] = [
- [ 0x31, 0x0e, 0x0e, 0xdd, 0x47, 0xdb, 0x6f, 0x72, ],
- [ 0xfd, 0x67, 0xdc, 0x93, 0xc5, 0x39, 0xf8, 0x74, ],
- [ 0x5a, 0x4f, 0xa9, 0xd9, 0x09, 0x80, 0x6c, 0x0d, ],
- [ 0x2d, 0x7e, 0xfb, 0xd7, 0x96, 0x66, 0x67, 0x85, ],
- [ 0xb7, 0x87, 0x71, 0x27, 0xe0, 0x94, 0x27, 0xcf, ],
- [ 0x8d, 0xa6, 0x99, 0xcd, 0x64, 0x55, 0x76, 0x18, ],
- [ 0xce, 0xe3, 0xfe, 0x58, 0x6e, 0x46, 0xc9, 0xcb, ],
- [ 0x37, 0xd1, 0x01, 0x8b, 0xf5, 0x00, 0x02, 0xab, ],
- [ 0x62, 0x24, 0x93, 0x9a, 0x79, 0xf5, 0xf5, 0x93, ],
- [ 0xb0, 0xe4, 0xa9, 0x0b, 0xdf, 0x82, 0x00, 0x9e, ],
- [ 0xf3, 0xb9, 0xdd, 0x94, 0xc5, 0xbb, 0x5d, 0x7a, ],
- [ 0xa7, 0xad, 0x6b, 0x22, 0x46, 0x2f, 0xb3, 0xf4, ],
- [ 0xfb, 0xe5, 0x0e, 0x86, 0xbc, 0x8f, 0x1e, 0x75, ],
- [ 0x90, 0x3d, 0x84, 0xc0, 0x27, 0x56, 0xea, 0x14, ],
- [ 0xee, 0xf2, 0x7a, 0x8e, 0x90, 0xca, 0x23, 0xf7, ],
- [ 0xe5, 0x45, 0xbe, 0x49, 0x61, 0xca, 0x29, 0xa1, ],
- [ 0xdb, 0x9b, 0xc2, 0x57, 0x7f, 0xcc, 0x2a, 0x3f, ],
- [ 0x94, 0x47, 0xbe, 0x2c, 0xf5, 0xe9, 0x9a, 0x69, ],
- [ 0x9c, 0xd3, 0x8d, 0x96, 0xf0, 0xb3, 0xc1, 0x4b, ],
- [ 0xbd, 0x61, 0x79, 0xa7, 0x1d, 0xc9, 0x6d, 0xbb, ],
- [ 0x98, 0xee, 0xa2, 0x1a, 0xf2, 0x5c, 0xd6, 0xbe, ],
- [ 0xc7, 0x67, 0x3b, 0x2e, 0xb0, 0xcb, 0xf2, 0xd0, ],
- [ 0x88, 0x3e, 0xa3, 0xe3, 0x95, 0x67, 0x53, 0x93, ],
- [ 0xc8, 0xce, 0x5c, 0xcd, 0x8c, 0x03, 0x0c, 0xa8, ],
- [ 0x94, 0xaf, 0x49, 0xf6, 0xc6, 0x50, 0xad, 0xb8, ],
- [ 0xea, 0xb8, 0x85, 0x8a, 0xde, 0x92, 0xe1, 0xbc, ],
- [ 0xf3, 0x15, 0xbb, 0x5b, 0xb8, 0x35, 0xd8, 0x17, ],
- [ 0xad, 0xcf, 0x6b, 0x07, 0x63, 0x61, 0x2e, 0x2f, ],
- [ 0xa5, 0xc9, 0x1d, 0xa7, 0xac, 0xaa, 0x4d, 0xde, ],
- [ 0x71, 0x65, 0x95, 0x87, 0x66, 0x50, 0xa2, 0xa6, ],
- [ 0x28, 0xef, 0x49, 0x5c, 0x53, 0xa3, 0x87, 0xad, ],
- [ 0x42, 0xc3, 0x41, 0xd8, 0xfa, 0x92, 0xd8, 0x32, ],
- [ 0xce, 0x7c, 0xf2, 0x72, 0x2f, 0x51, 0x27, 0x71, ],
- [ 0xe3, 0x78, 0x59, 0xf9, 0x46, 0x23, 0xf3, 0xa7, ],
- [ 0x38, 0x12, 0x05, 0xbb, 0x1a, 0xb0, 0xe0, 0x12, ],
- [ 0xae, 0x97, 0xa1, 0x0f, 0xd4, 0x34, 0xe0, 0x15, ],
- [ 0xb4, 0xa3, 0x15, 0x08, 0xbe, 0xff, 0x4d, 0x31, ],
- [ 0x81, 0x39, 0x62, 0x29, 0xf0, 0x90, 0x79, 0x02, ],
- [ 0x4d, 0x0c, 0xf4, 0x9e, 0xe5, 0xd4, 0xdc, 0xca, ],
- [ 0x5c, 0x73, 0x33, 0x6a, 0x76, 0xd8, 0xbf, 0x9a, ],
- [ 0xd0, 0xa7, 0x04, 0x53, 0x6b, 0xa9, 0x3e, 0x0e, ],
- [ 0x92, 0x59, 0x58, 0xfc, 0xd6, 0x42, 0x0c, 0xad, ],
- [ 0xa9, 0x15, 0xc2, 0x9b, 0xc8, 0x06, 0x73, 0x18, ],
- [ 0x95, 0x2b, 0x79, 0xf3, 0xbc, 0x0a, 0xa6, 0xd4, ],
- [ 0xf2, 0x1d, 0xf2, 0xe4, 0x1d, 0x45, 0x35, 0xf9, ],
- [ 0x87, 0x57, 0x75, 0x19, 0x04, 0x8f, 0x53, 0xa9, ],
- [ 0x10, 0xa5, 0x6c, 0xf5, 0xdf, 0xcd, 0x9a, 0xdb, ],
- [ 0xeb, 0x75, 0x09, 0x5c, 0xcd, 0x98, 0x6c, 0xd0, ],
- [ 0x51, 0xa9, 0xcb, 0x9e, 0xcb, 0xa3, 0x12, 0xe6, ],
- [ 0x96, 0xaf, 0xad, 0xfc, 0x2c, 0xe6, 0x66, 0xc7, ],
- [ 0x72, 0xfe, 0x52, 0x97, 0x5a, 0x43, 0x64, 0xee, ],
- [ 0x5a, 0x16, 0x45, 0xb2, 0x76, 0xd5, 0x92, 0xa1, ],
- [ 0xb2, 0x74, 0xcb, 0x8e, 0xbf, 0x87, 0x87, 0x0a, ],
- [ 0x6f, 0x9b, 0xb4, 0x20, 0x3d, 0xe7, 0xb3, 0x81, ],
- [ 0xea, 0xec, 0xb2, 0xa3, 0x0b, 0x22, 0xa8, 0x7f, ],
- [ 0x99, 0x24, 0xa4, 0x3c, 0xc1, 0x31, 0x57, 0x24, ],
- [ 0xbd, 0x83, 0x8d, 0x3a, 0xaf, 0xbf, 0x8d, 0xb7, ],
- [ 0x0b, 0x1a, 0x2a, 0x32, 0x65, 0xd5, 0x1a, 0xea, ],
- [ 0x13, 0x50, 0x79, 0xa3, 0x23, 0x1c, 0xe6, 0x60, ],
- [ 0x93, 0x2b, 0x28, 0x46, 0xe4, 0xd7, 0x06, 0x66, ],
- [ 0xe1, 0x91, 0x5f, 0x5c, 0xb1, 0xec, 0xa4, 0x6c, ],
- [ 0xf3, 0x25, 0x96, 0x5c, 0xa1, 0x6d, 0x62, 0x9f, ],
- [ 0x57, 0x5f, 0xf2, 0x8e, 0x60, 0x38, 0x1b, 0xe5, ],
- [ 0x72, 0x45, 0x06, 0xeb, 0x4c, 0x32, 0x8a, 0x95, ]
+ let vecs: [[u8; 8]; 64] = [
+ [0x31, 0x0e, 0x0e, 0xdd, 0x47, 0xdb, 0x6f, 0x72],
+ [0xfd, 0x67, 0xdc, 0x93, 0xc5, 0x39, 0xf8, 0x74],
+ [0x5a, 0x4f, 0xa9, 0xd9, 0x09, 0x80, 0x6c, 0x0d],
+ [0x2d, 0x7e, 0xfb, 0xd7, 0x96, 0x66, 0x67, 0x85],
+ [0xb7, 0x87, 0x71, 0x27, 0xe0, 0x94, 0x27, 0xcf],
+ [0x8d, 0xa6, 0x99, 0xcd, 0x64, 0x55, 0x76, 0x18],
+ [0xce, 0xe3, 0xfe, 0x58, 0x6e, 0x46, 0xc9, 0xcb],
+ [0x37, 0xd1, 0x01, 0x8b, 0xf5, 0x00, 0x02, 0xab],
+ [0x62, 0x24, 0x93, 0x9a, 0x79, 0xf5, 0xf5, 0x93],
+ [0xb0, 0xe4, 0xa9, 0x0b, 0xdf, 0x82, 0x00, 0x9e],
+ [0xf3, 0xb9, 0xdd, 0x94, 0xc5, 0xbb, 0x5d, 0x7a],
+ [0xa7, 0xad, 0x6b, 0x22, 0x46, 0x2f, 0xb3, 0xf4],
+ [0xfb, 0xe5, 0x0e, 0x86, 0xbc, 0x8f, 0x1e, 0x75],
+ [0x90, 0x3d, 0x84, 0xc0, 0x27, 0x56, 0xea, 0x14],
+ [0xee, 0xf2, 0x7a, 0x8e, 0x90, 0xca, 0x23, 0xf7],
+ [0xe5, 0x45, 0xbe, 0x49, 0x61, 0xca, 0x29, 0xa1],
+ [0xdb, 0x9b, 0xc2, 0x57, 0x7f, 0xcc, 0x2a, 0x3f],
+ [0x94, 0x47, 0xbe, 0x2c, 0xf5, 0xe9, 0x9a, 0x69],
+ [0x9c, 0xd3, 0x8d, 0x96, 0xf0, 0xb3, 0xc1, 0x4b],
+ [0xbd, 0x61, 0x79, 0xa7, 0x1d, 0xc9, 0x6d, 0xbb],
+ [0x98, 0xee, 0xa2, 0x1a, 0xf2, 0x5c, 0xd6, 0xbe],
+ [0xc7, 0x67, 0x3b, 0x2e, 0xb0, 0xcb, 0xf2, 0xd0],
+ [0x88, 0x3e, 0xa3, 0xe3, 0x95, 0x67, 0x53, 0x93],
+ [0xc8, 0xce, 0x5c, 0xcd, 0x8c, 0x03, 0x0c, 0xa8],
+ [0x94, 0xaf, 0x49, 0xf6, 0xc6, 0x50, 0xad, 0xb8],
+ [0xea, 0xb8, 0x85, 0x8a, 0xde, 0x92, 0xe1, 0xbc],
+ [0xf3, 0x15, 0xbb, 0x5b, 0xb8, 0x35, 0xd8, 0x17],
+ [0xad, 0xcf, 0x6b, 0x07, 0x63, 0x61, 0x2e, 0x2f],
+ [0xa5, 0xc9, 0x1d, 0xa7, 0xac, 0xaa, 0x4d, 0xde],
+ [0x71, 0x65, 0x95, 0x87, 0x66, 0x50, 0xa2, 0xa6],
+ [0x28, 0xef, 0x49, 0x5c, 0x53, 0xa3, 0x87, 0xad],
+ [0x42, 0xc3, 0x41, 0xd8, 0xfa, 0x92, 0xd8, 0x32],
+ [0xce, 0x7c, 0xf2, 0x72, 0x2f, 0x51, 0x27, 0x71],
+ [0xe3, 0x78, 0x59, 0xf9, 0x46, 0x23, 0xf3, 0xa7],
+ [0x38, 0x12, 0x05, 0xbb, 0x1a, 0xb0, 0xe0, 0x12],
+ [0xae, 0x97, 0xa1, 0x0f, 0xd4, 0x34, 0xe0, 0x15],
+ [0xb4, 0xa3, 0x15, 0x08, 0xbe, 0xff, 0x4d, 0x31],
+ [0x81, 0x39, 0x62, 0x29, 0xf0, 0x90, 0x79, 0x02],
+ [0x4d, 0x0c, 0xf4, 0x9e, 0xe5, 0xd4, 0xdc, 0xca],
+ [0x5c, 0x73, 0x33, 0x6a, 0x76, 0xd8, 0xbf, 0x9a],
+ [0xd0, 0xa7, 0x04, 0x53, 0x6b, 0xa9, 0x3e, 0x0e],
+ [0x92, 0x59, 0x58, 0xfc, 0xd6, 0x42, 0x0c, 0xad],
+ [0xa9, 0x15, 0xc2, 0x9b, 0xc8, 0x06, 0x73, 0x18],
+ [0x95, 0x2b, 0x79, 0xf3, 0xbc, 0x0a, 0xa6, 0xd4],
+ [0xf2, 0x1d, 0xf2, 0xe4, 0x1d, 0x45, 0x35, 0xf9],
+ [0x87, 0x57, 0x75, 0x19, 0x04, 0x8f, 0x53, 0xa9],
+ [0x10, 0xa5, 0x6c, 0xf5, 0xdf, 0xcd, 0x9a, 0xdb],
+ [0xeb, 0x75, 0x09, 0x5c, 0xcd, 0x98, 0x6c, 0xd0],
+ [0x51, 0xa9, 0xcb, 0x9e, 0xcb, 0xa3, 0x12, 0xe6],
+ [0x96, 0xaf, 0xad, 0xfc, 0x2c, 0xe6, 0x66, 0xc7],
+ [0x72, 0xfe, 0x52, 0x97, 0x5a, 0x43, 0x64, 0xee],
+ [0x5a, 0x16, 0x45, 0xb2, 0x76, 0xd5, 0x92, 0xa1],
+ [0xb2, 0x74, 0xcb, 0x8e, 0xbf, 0x87, 0x87, 0x0a],
+ [0x6f, 0x9b, 0xb4, 0x20, 0x3d, 0xe7, 0xb3, 0x81],
+ [0xea, 0xec, 0xb2, 0xa3, 0x0b, 0x22, 0xa8, 0x7f],
+ [0x99, 0x24, 0xa4, 0x3c, 0xc1, 0x31, 0x57, 0x24],
+ [0xbd, 0x83, 0x8d, 0x3a, 0xaf, 0xbf, 0x8d, 0xb7],
+ [0x0b, 0x1a, 0x2a, 0x32, 0x65, 0xd5, 0x1a, 0xea],
+ [0x13, 0x50, 0x79, 0xa3, 0x23, 0x1c, 0xe6, 0x60],
+ [0x93, 0x2b, 0x28, 0x46, 0xe4, 0xd7, 0x06, 0x66],
+ [0xe1, 0x91, 0x5f, 0x5c, 0xb1, 0xec, 0xa4, 0x6c],
+ [0xf3, 0x25, 0x96, 0x5c, 0xa1, 0x6d, 0x62, 0x9f],
+ [0x57, 0x5f, 0xf2, 0x8e, 0x60, 0x38, 0x1b, 0xe5],
+ [0x72, 0x45, 0x06, 0xeb, 0x4c, 0x32, 0x8a, 0x95],
];
let k0 = 0x_07_06_05_04_03_02_01_00;
@@ -320,8 +320,7 @@
h1.write_u8(0x01u8);
let mut h2 = SipHasher::new();
h2.write(unsafe {
- slice::from_raw_parts(&test_usize as *const _ as *const u8,
- mem::size_of::<usize>())
+ slice::from_raw_parts(&test_usize as *const _ as *const u8, mem::size_of::<usize>())
});
h2.write(b"bytes");
h2.write(b"string");
diff --git a/src/libcore/tests/intrinsics.rs b/src/libcore/tests/intrinsics.rs
index 7544c13..fed7c4a 100644
--- a/src/libcore/tests/intrinsics.rs
+++ b/src/libcore/tests/intrinsics.rs
@@ -2,7 +2,8 @@
#[test]
fn test_typeid_sized_types() {
- struct X; struct Y(u32);
+ struct X;
+ struct Y(u32);
assert_eq!(TypeId::of::<X>(), TypeId::of::<X>());
assert_eq!(TypeId::of::<Y>(), TypeId::of::<Y>());
@@ -12,7 +13,8 @@
#[test]
fn test_typeid_unsized_types() {
trait Z {}
- struct X(str); struct Y(dyn Z + 'static);
+ struct X(str);
+ struct Y(dyn Z + 'static);
assert_eq!(TypeId::of::<X>(), TypeId::of::<X>());
assert_eq!(TypeId::of::<Y>(), TypeId::of::<Y>());
diff --git a/src/libcore/tests/manually_drop.rs b/src/libcore/tests/manually_drop.rs
index 49a1c18..77a338d 100644
--- a/src/libcore/tests/manually_drop.rs
+++ b/src/libcore/tests/manually_drop.rs
@@ -13,7 +13,7 @@
drop(x);
// also test unsizing
- let x : Box<ManuallyDrop<[TypeWithDrop]>> =
+ let x: Box<ManuallyDrop<[TypeWithDrop]>> =
Box::new(ManuallyDrop::new([TypeWithDrop, TypeWithDrop]));
drop(x);
}
diff --git a/src/libcore/tests/mem.rs b/src/libcore/tests/mem.rs
index f5b2419..59588d9 100644
--- a/src/libcore/tests/mem.rs
+++ b/src/libcore/tests/mem.rs
@@ -96,7 +96,9 @@
#[test]
fn test_transmute() {
- trait Foo { fn dummy(&self) { } }
+ trait Foo {
+ fn dummy(&self) {}
+ }
impl Foo for isize {}
let a = box 100isize as Box<dyn Foo>;
@@ -116,13 +118,13 @@
fn test_discriminant_send_sync() {
enum Regular {
A,
- B(i32)
+ B(i32),
}
enum NotSendSync {
- A(*const i32)
+ A(*const i32),
}
- fn is_send_sync<T: Send + Sync>() { }
+ fn is_send_sync<T: Send + Sync>() {}
is_send_sync::<Discriminant<Regular>>();
is_send_sync::<Discriminant<NotSendSync>>();
diff --git a/src/libcore/tests/nonzero.rs b/src/libcore/tests/nonzero.rs
index 77e4846..6c5d198 100644
--- a/src/libcore/tests/nonzero.rs
+++ b/src/libcore/tests/nonzero.rs
@@ -4,9 +4,7 @@
#[test]
fn test_create_nonzero_instance() {
- let _a = unsafe {
- NonZeroU32::new_unchecked(21)
- };
+ let _a = unsafe { NonZeroU32::new_unchecked(21) };
}
#[test]
@@ -17,17 +15,15 @@
#[test]
fn test_match_on_nonzero_option() {
- let a = Some(unsafe {
- NonZeroU32::new_unchecked(42)
- });
+ let a = Some(unsafe { NonZeroU32::new_unchecked(42) });
match a {
Some(val) => assert_eq!(val.get(), 42),
- None => panic!("unexpected None while matching on Some(NonZeroU32(_))")
+ None => panic!("unexpected None while matching on Some(NonZeroU32(_))"),
}
match unsafe { Some(NonZeroU32::new_unchecked(43)) } {
Some(val) => assert_eq!(val.get(), 43),
- None => panic!("unexpected None while matching on Some(NonZeroU32(_))")
+ None => panic!("unexpected None while matching on Some(NonZeroU32(_))"),
}
}
@@ -45,7 +41,7 @@
let a = Some(vec![1, 2, 3, 4]);
match a {
Some(v) => assert_eq!(v, [1, 2, 3, 4]),
- None => panic!("unexpected None while matching on Some(vec![1, 2, 3, 4])")
+ None => panic!("unexpected None while matching on Some(vec![1, 2, 3, 4])"),
}
}
@@ -56,7 +52,7 @@
let five = Rc::new(5);
match Some(five) {
Some(r) => assert_eq!(*r, 5),
- None => panic!("unexpected None while matching on Some(Rc::new(5))")
+ None => panic!("unexpected None while matching on Some(Rc::new(5))"),
}
}
@@ -67,7 +63,7 @@
let five = Arc::new(5);
match Some(five) {
Some(a) => assert_eq!(*a, 5),
- None => panic!("unexpected None while matching on Some(Arc::new(5))")
+ None => panic!("unexpected None while matching on Some(Arc::new(5))"),
}
}
@@ -85,7 +81,7 @@
let five = "Five".to_string();
match Some(five) {
Some(s) => assert_eq!(s, "Five"),
- None => panic!("unexpected None while matching on Some(String { ... })")
+ None => panic!("unexpected None while matching on Some(String { ... })"),
}
}
@@ -100,7 +96,9 @@
}
macro_rules! atom {
- ("foo") => { atom::FOO_ATOM }
+ ("foo") => {
+ atom::FOO_ATOM
+ };
}
#[test]
@@ -108,7 +106,7 @@
match atom!("foo") {
// Using as a pattern is supported by the compiler:
atom!("foo") => {}
- _ => panic!("Expected the const item as a pattern to match.")
+ _ => panic!("Expected the const item as a pattern to match."),
}
}
@@ -129,10 +127,7 @@
#[test]
fn test_from_str() {
assert_eq!("123".parse::<NonZeroU8>(), Ok(NonZeroU8::new(123).unwrap()));
- assert_eq!(
- "0".parse::<NonZeroU8>().err().map(|e| e.kind().clone()),
- Some(IntErrorKind::Zero)
- );
+ assert_eq!("0".parse::<NonZeroU8>().err().map(|e| e.kind().clone()), Some(IntErrorKind::Zero));
assert_eq!(
"-1".parse::<NonZeroU8>().err().map(|e| e.kind().clone()),
Some(IntErrorKind::InvalidDigit)
diff --git a/src/libcore/tests/num/bignum.rs b/src/libcore/tests/num/bignum.rs
index 50a3ec0..1457064 100644
--- a/src/libcore/tests/num/bignum.rs
+++ b/src/libcore/tests/num/bignum.rs
@@ -70,7 +70,7 @@
fn test_mul_small() {
assert_eq!(*Big::from_small(7).mul_small(5), Big::from_small(35));
assert_eq!(*Big::from_small(0xff).mul_small(0xff), Big::from_u64(0xfe01));
- assert_eq!(*Big::from_u64(0xffffff/13).mul_small(13), Big::from_u64(0xffffff));
+ assert_eq!(*Big::from_u64(0xffffff / 13).mul_small(13), Big::from_u64(0xffffff));
}
#[test]
@@ -134,7 +134,7 @@
assert_eq!(*Big::from_u64(0x123).mul_digits(&[0x56, 0x4]), Big::from_u64(0x4edc2));
assert_eq!(*Big::from_u64(0x12345).mul_digits(&[0x67]), Big::from_u64(0x7530c3));
assert_eq!(*Big::from_small(0x12).mul_digits(&[0x67, 0x45, 0x3]), Big::from_u64(0x3ae13e));
- assert_eq!(*Big::from_u64(0xffffff/13).mul_digits(&[13]), Big::from_u64(0xffffff));
+ assert_eq!(*Big::from_u64(0xffffff / 13).mul_digits(&[13]), Big::from_u64(0xffffff));
assert_eq!(*Big::from_small(13).mul_digits(&[0x3b, 0xb1, 0x13]), Big::from_u64(0xffffff));
}
@@ -156,10 +156,14 @@
assert_eq!(as_val(Big::from_small(0xff).div_rem_small(15)), (Big::from_small(17), 0));
assert_eq!(as_val(Big::from_small(0xff).div_rem_small(16)), (Big::from_small(15), 15));
assert_eq!(as_val(Big::from_small(3).div_rem_small(40)), (Big::from_small(0), 3));
- assert_eq!(as_val(Big::from_u64(0xffffff).div_rem_small(123)),
- (Big::from_u64(0xffffff / 123), (0xffffffu64 % 123) as u8));
- assert_eq!(as_val(Big::from_u64(0x10000).div_rem_small(123)),
- (Big::from_u64(0x10000 / 123), (0x10000u64 % 123) as u8));
+ assert_eq!(
+ as_val(Big::from_u64(0xffffff).div_rem_small(123)),
+ (Big::from_u64(0xffffff / 123), (0xffffffu64 % 123) as u8)
+ );
+ assert_eq!(
+ as_val(Big::from_u64(0x10000).div_rem_small(123)),
+ (Big::from_u64(0x10000 / 123), (0x10000u64 % 123) as u8)
+ );
}
#[test]
diff --git a/src/libcore/tests/num/dec2flt/mod.rs b/src/libcore/tests/num/dec2flt/mod.rs
index 46eacb4..6bb348f 100644
--- a/src/libcore/tests/num/dec2flt/mod.rs
+++ b/src/libcore/tests/num/dec2flt/mod.rs
@@ -1,6 +1,6 @@
#![allow(overflowing_literals)]
-use std::{i64, f32, f64};
+use std::{f32, f64, i64};
mod parse;
mod rawfp;
@@ -9,7 +9,7 @@
// to be correct) and see if those strings are parsed back to the value of the literal.
// Requires a *polymorphic literal*, i.e., one that can serve as f64 as well as f32.
macro_rules! test_literal {
- ($x: expr) => ({
+ ($x: expr) => {{
let x32: f32 = $x;
let x64: f64 = $x;
let inputs = &[stringify!($x).into(), format!("{:?}", x64), format!("{:e}", x64)];
@@ -20,7 +20,7 @@
assert_eq!(neg_input.parse(), Ok(-x64));
assert_eq!(neg_input.parse(), Ok(-x32));
}
- })
+ }};
}
#[cfg_attr(all(target_arch = "wasm32", target_os = "emscripten"), ignore)] // issue 42630
@@ -31,7 +31,11 @@
test_literal!(0.1);
test_literal!(12345.);
test_literal!(0.9999999);
- #[cfg(not(miri))] // Miri is too slow
+
+ if cfg!(miri) { // Miri is too slow
+ return;
+ }
+
test_literal!(2.2250738585072014e-308);
}
@@ -53,7 +57,7 @@
}
#[test]
-#[cfg(not(miri))] // Miri is too slow
+#[cfg_attr(miri, ignore)] // Miri is too slow
fn subnormals() {
test_literal!(5e-324);
test_literal!(91e-324);
@@ -65,7 +69,7 @@
}
#[test]
-#[cfg(not(miri))] // Miri is too slow
+#[cfg_attr(miri, ignore)] // Miri is too slow
fn infinity() {
test_literal!(1e400);
test_literal!(1e309);
@@ -77,9 +81,12 @@
fn zero() {
test_literal!(0.0);
test_literal!(1e-325);
- #[cfg(not(miri))] // Miri is too slow
+
+ if cfg!(miri) { // Miri is too slow
+ return;
+ }
+
test_literal!(1e-326);
- #[cfg(not(miri))] // Miri is too slow
test_literal!(1e-500);
}
diff --git a/src/libcore/tests/num/dec2flt/parse.rs b/src/libcore/tests/num/dec2flt/parse.rs
index 1eac484..bb7e51d 100644
--- a/src/libcore/tests/num/dec2flt/parse.rs
+++ b/src/libcore/tests/num/dec2flt/parse.rs
@@ -1,5 +1,5 @@
-use core::num::dec2flt::parse::{Decimal, parse_decimal};
-use core::num::dec2flt::parse::ParseResult::{Valid, Invalid};
+use core::num::dec2flt::parse::ParseResult::{Invalid, Valid};
+use core::num::dec2flt::parse::{parse_decimal, Decimal};
#[test]
fn missing_pieces() {
diff --git a/src/libcore/tests/num/dec2flt/rawfp.rs b/src/libcore/tests/num/dec2flt/rawfp.rs
index 747c1bf..665fb6b 100644
--- a/src/libcore/tests/num/dec2flt/rawfp.rs
+++ b/src/libcore/tests/num/dec2flt/rawfp.rs
@@ -1,8 +1,8 @@
+use core::num::dec2flt::rawfp::RawFloat;
+use core::num::dec2flt::rawfp::{fp_to_float, next_float, prev_float, round_normal};
+use core::num::diy_float::Fp;
use std::f32;
use std::f64;
-use core::num::diy_float::Fp;
-use core::num::dec2flt::rawfp::{fp_to_float, prev_float, next_float, round_normal};
-use core::num::dec2flt::rawfp::RawFloat;
fn integer_decode(f: f64) -> (u64, i16, i8) {
RawFloat::integer_decode(f)
@@ -53,16 +53,23 @@
assert_eq!(fp_to_float::<f64>(Fp { f: 4, e: -3 }), 0.5);
}
-const SOME_FLOATS: [f64; 9] =
- [0.1f64, 33.568, 42.1e-5, 777.0e9, 1.1111, 0.347997,
- 9843579834.35892, 12456.0e-150, 54389573.0e-150];
-
+const SOME_FLOATS: [f64; 9] = [
+ 0.1f64,
+ 33.568,
+ 42.1e-5,
+ 777.0e9,
+ 1.1111,
+ 0.347997,
+ 9843579834.35892,
+ 12456.0e-150,
+ 54389573.0e-150,
+];
#[test]
fn human_f64_roundtrip() {
for &x in &SOME_FLOATS {
let (f, e, _) = integer_decode(x);
- let fp = Fp { f: f, e: e};
+ let fp = Fp { f: f, e: e };
assert_eq!(fp_to_float::<f64>(fp), x);
}
}
diff --git a/src/libcore/tests/num/flt2dec/estimator.rs b/src/libcore/tests/num/flt2dec/estimator.rs
index c514517..8ee06d8 100644
--- a/src/libcore/tests/num/flt2dec/estimator.rs
+++ b/src/libcore/tests/num/flt2dec/estimator.rs
@@ -3,14 +3,24 @@
#[test]
fn test_estimate_scaling_factor() {
macro_rules! assert_almost_eq {
- ($actual:expr, $expected:expr) => ({
+ ($actual:expr, $expected:expr) => {{
let actual = $actual;
let expected = $expected;
- println!("{} - {} = {} - {} = {}", stringify!($expected), stringify!($actual),
- expected, actual, expected - actual);
- assert!(expected == actual || expected == actual + 1,
- "expected {}, actual {}", expected, actual);
- })
+ println!(
+ "{} - {} = {} - {} = {}",
+ stringify!($expected),
+ stringify!($actual),
+ expected,
+ actual,
+ expected - actual
+ );
+ assert!(
+ expected == actual || expected == actual + 1,
+ "expected {}, actual {}",
+ expected,
+ actual
+ );
+ }};
}
assert_almost_eq!(estimate_scaling_factor(1, 0), 0);
diff --git a/src/libcore/tests/num/flt2dec/mod.rs b/src/libcore/tests/num/flt2dec/mod.rs
index f85369c..2f94ea2 100644
--- a/src/libcore/tests/num/flt2dec/mod.rs
+++ b/src/libcore/tests/num/flt2dec/mod.rs
@@ -256,7 +256,6 @@
check_shortest!(f(minf32) => b"1", -44);
}
-#[cfg(not(miri))] // Miri is too slow
pub fn f32_exact_sanity_test<F>(mut f: F)
where F: FnMut(&Decoded, &mut [u8], i16) -> (usize, i16) {
let minf32 = ldexp_f32(1.0, -149);
@@ -362,7 +361,6 @@
check_shortest!(f(minf64) => b"5", -323);
}
-#[cfg(not(miri))] // Miri is too slow
pub fn f64_exact_sanity_test<F>(mut f: F)
where F: FnMut(&Decoded, &mut [u8], i16) -> (usize, i16) {
let minf64 = ldexp_f64(1.0, -1074);
diff --git a/src/libcore/tests/num/flt2dec/random.rs b/src/libcore/tests/num/flt2dec/random.rs
index d954379..ecdfc4b 100644
--- a/src/libcore/tests/num/flt2dec/random.rs
+++ b/src/libcore/tests/num/flt2dec/random.rs
@@ -3,27 +3,28 @@
use std::i16;
use std::str;
-use core::num::flt2dec::MAX_SIG_DIGITS;
use core::num::flt2dec::strategy::grisu::format_exact_opt;
use core::num::flt2dec::strategy::grisu::format_shortest_opt;
-use core::num::flt2dec::{decode, DecodableFloat, FullDecoded, Decoded};
+use core::num::flt2dec::MAX_SIG_DIGITS;
+use core::num::flt2dec::{decode, DecodableFloat, Decoded, FullDecoded};
-use rand::SeedableRng;
-use rand::rngs::StdRng;
use rand::distributions::{Distribution, Uniform};
+use rand::rngs::StdRng;
+use rand::SeedableRng;
pub fn decode_finite<T: DecodableFloat>(v: T) -> Decoded {
match decode(v).1 {
FullDecoded::Finite(decoded) => decoded,
- full_decoded => panic!("expected finite, got {:?} instead", full_decoded)
+ full_decoded => panic!("expected finite, got {:?} instead", full_decoded),
}
}
-
fn iterate<F, G, V>(func: &str, k: usize, n: usize, mut f: F, mut g: G, mut v: V) -> (usize, usize)
- where F: FnMut(&Decoded, &mut [u8]) -> Option<(usize, i16)>,
- G: FnMut(&Decoded, &mut [u8]) -> (usize, i16),
- V: FnMut(usize) -> Decoded {
+where
+ F: FnMut(&Decoded, &mut [u8]) -> Option<(usize, i16)>,
+ G: FnMut(&Decoded, &mut [u8]) -> (usize, i16),
+ V: FnMut(usize) -> Decoded,
+{
assert!(k <= 1024);
let mut npassed = 0; // f(x) = Some(g(x))
@@ -31,8 +32,14 @@
for i in 0..n {
if (i & 0xfffff) == 0 {
- println!("in progress, {:x}/{:x} (ignored={} passed={} failed={})",
- i, n, nignored, npassed, i - nignored - npassed);
+ println!(
+ "in progress, {:x}/{:x} (ignored={} passed={} failed={})",
+ i,
+ n,
+ nignored,
+ npassed,
+ i - nignored - npassed
+ );
}
let decoded = v(i);
@@ -43,27 +50,47 @@
if e1 == e2 && &buf1[..len1] == &buf2[..len2] {
npassed += 1;
} else {
- println!("equivalence test failed, {:x}/{:x}: {:?} f(i)={}e{} g(i)={}e{}",
- i, n, decoded, str::from_utf8(&buf1[..len1]).unwrap(), e1,
- str::from_utf8(&buf2[..len2]).unwrap(), e2);
+ println!(
+ "equivalence test failed, {:x}/{:x}: {:?} f(i)={}e{} g(i)={}e{}",
+ i,
+ n,
+ decoded,
+ str::from_utf8(&buf1[..len1]).unwrap(),
+ e1,
+ str::from_utf8(&buf2[..len2]).unwrap(),
+ e2
+ );
}
} else {
nignored += 1;
}
}
- println!("{}({}): done, ignored={} passed={} failed={}",
- func, k, nignored, npassed, n - nignored - npassed);
- assert!(nignored + npassed == n,
- "{}({}): {} out of {} values returns an incorrect value!",
- func, k, n - nignored - npassed, n);
+ println!(
+ "{}({}): done, ignored={} passed={} failed={}",
+ func,
+ k,
+ nignored,
+ npassed,
+ n - nignored - npassed
+ );
+ assert!(
+ nignored + npassed == n,
+ "{}({}): {} out of {} values returns an incorrect value!",
+ func,
+ k,
+ n - nignored - npassed,
+ n
+ );
(npassed, nignored)
}
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) {
+where
+ F: FnMut(&Decoded, &mut [u8]) -> Option<(usize, i16)>,
+ G: FnMut(&Decoded, &mut [u8]) -> (usize, i16),
+{
if cfg!(target_os = "emscripten") {
- return // using rng pulls in i128 support, which doesn't work
+ return; // using rng pulls in i128 support, which doesn't work
}
let mut rng = StdRng::from_entropy();
let f32_range = Uniform::new(0x0000_0001u32, 0x7f80_0000);
@@ -74,10 +101,12 @@
}
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) {
+where
+ F: FnMut(&Decoded, &mut [u8]) -> Option<(usize, i16)>,
+ G: FnMut(&Decoded, &mut [u8]) -> (usize, i16),
+{
if cfg!(target_os = "emscripten") {
- return // using rng pulls in i128 support, which doesn't work
+ return; // using rng pulls in i128 support, which doesn't work
}
let mut rng = StdRng::from_entropy();
let f64_range = Uniform::new(0x0000_0000_0000_0001u64, 0x7ff0_0000_0000_0000);
@@ -88,8 +117,10 @@
}
pub fn f32_exhaustive_equivalence_test<F, G>(f: F, g: G, k: usize)
- where F: FnMut(&Decoded, &mut [u8]) -> Option<(usize, i16)>,
- G: FnMut(&Decoded, &mut [u8]) -> (usize, i16) {
+where
+ F: FnMut(&Decoded, &mut [u8]) -> Option<(usize, i16)>,
+ G: FnMut(&Decoded, &mut [u8]) -> (usize, i16),
+{
// we have only 2^23 * (2^8 - 1) - 1 = 2,139,095,039 positive finite f32 values,
// so why not simply testing all of them?
//
@@ -97,12 +128,11 @@
// but with `-C opt-level=3 -C lto` this only takes about an hour or so.
// iterate from 0x0000_0001 to 0x7f7f_ffff, i.e., all finite ranges
- let (npassed, nignored) = iterate("f32_exhaustive_equivalence_test",
- k, 0x7f7f_ffff, f, g, |i: usize| {
-
- let x = f32::from_bits(i as u32 + 1);
- decode_finite(x)
- });
+ let (npassed, nignored) =
+ iterate("f32_exhaustive_equivalence_test", k, 0x7f7f_ffff, f, g, |i: usize| {
+ let x = f32::from_bits(i as u32 + 1);
+ decode_finite(x)
+ });
assert_eq!((npassed, nignored), (2121451881, 17643158));
}
@@ -118,7 +148,8 @@
f32_random_equivalence_test(format_shortest_opt, fallback, MAX_SIG_DIGITS, N);
}
-#[test] #[ignore] // it is too expensive
+#[test]
+#[ignore] // it is too expensive
fn shortest_f32_exhaustive_equivalence_test() {
// it is hard to directly test the optimality of the output, but we can at least test if
// two different algorithms agree to each other.
@@ -131,13 +162,13 @@
f32_exhaustive_equivalence_test(format_shortest_opt, fallback, MAX_SIG_DIGITS);
}
-#[test] #[ignore] // it is too expensive
+#[test]
+#[ignore] // it is too expensive
fn shortest_f64_hard_random_equivalence_test() {
// this again probably has to use appropriate rustc flags.
use core::num::flt2dec::strategy::dragon::format_shortest as fallback;
- f64_random_equivalence_test(format_shortest_opt, fallback,
- MAX_SIG_DIGITS, 100_000_000);
+ f64_random_equivalence_test(format_shortest_opt, fallback, MAX_SIG_DIGITS, 100_000_000);
}
#[test]
@@ -149,8 +180,12 @@
const N: usize = 3;
for k in 1..21 {
- f32_random_equivalence_test(|d, buf| format_exact_opt(d, buf, i16::MIN),
- |d, buf| fallback(d, buf, i16::MIN), k, N);
+ f32_random_equivalence_test(
+ |d, buf| format_exact_opt(d, buf, i16::MIN),
+ |d, buf| fallback(d, buf, i16::MIN),
+ k,
+ N,
+ );
}
}
@@ -163,7 +198,11 @@
const N: usize = 3;
for k in 1..21 {
- f64_random_equivalence_test(|d, buf| format_exact_opt(d, buf, i16::MIN),
- |d, buf| fallback(d, buf, i16::MIN), k, N);
+ f64_random_equivalence_test(
+ |d, buf| format_exact_opt(d, buf, i16::MIN),
+ |d, buf| fallback(d, buf, i16::MIN),
+ k,
+ N,
+ );
}
}
diff --git a/src/libcore/tests/num/flt2dec/strategy/dragon.rs b/src/libcore/tests/num/flt2dec/strategy/dragon.rs
index 0c545b4..3d985c6 100644
--- a/src/libcore/tests/num/flt2dec/strategy/dragon.rs
+++ b/src/libcore/tests/num/flt2dec/strategy/dragon.rs
@@ -22,7 +22,7 @@
}
#[test]
-#[cfg(not(miri))] // Miri is too slow
+#[cfg_attr(miri, ignore)] // Miri is too slow
fn exact_sanity_test() {
// This test ends up running what I can only assume is some corner-ish case
// of the `exp2` library function, defined in whatever C runtime we're
diff --git a/src/libcore/tests/num/flt2dec/strategy/grisu.rs b/src/libcore/tests/num/flt2dec/strategy/grisu.rs
index f8bdddf..ff8373c 100644
--- a/src/libcore/tests/num/flt2dec/strategy/grisu.rs
+++ b/src/libcore/tests/num/flt2dec/strategy/grisu.rs
@@ -6,12 +6,18 @@
assert_eq!(CACHED_POW10.first().unwrap().1, CACHED_POW10_FIRST_E);
assert_eq!(CACHED_POW10.last().unwrap().1, CACHED_POW10_LAST_E);
- for e in -1137..961 { // full range for f64
+ for e in -1137..961 {
+ // full range for f64
let low = ALPHA - e - 64;
let high = GAMMA - e - 64;
let (_k, cached) = cached_power(low, high);
- assert!(low <= cached.e && cached.e <= high,
- "cached_power({}, {}) = {:?} is incorrect", low, high, cached);
+ assert!(
+ low <= cached.e && cached.e <= high,
+ "cached_power({}, {}) = {:?} is incorrect",
+ low,
+ high,
+ cached
+ );
}
}
@@ -26,7 +32,6 @@
}
}
-
#[cfg_attr(all(target_arch = "wasm32", target_os = "emscripten"), ignore)] // issue 42630
#[test]
fn shortest_sanity_test() {
@@ -36,7 +41,7 @@
}
#[test]
-#[cfg(not(miri))] // Miri is too slow
+#[cfg_attr(miri, ignore)] // Miri is too slow
fn exact_sanity_test() {
// See comments in dragon.rs's exact_sanity_test for why this test is
// ignored on MSVC
diff --git a/src/libcore/tests/num/int_macros.rs b/src/libcore/tests/num/int_macros.rs
index 0475aeb..4a44b5f 100644
--- a/src/libcore/tests/num/int_macros.rs
+++ b/src/libcore/tests/num/int_macros.rs
@@ -1,240 +1,241 @@
-macro_rules! int_module { ($T:ident, $T_i:ident) => (
-#[cfg(test)]
-mod tests {
- use core::$T_i::*;
- use core::isize;
- use core::ops::{Shl, Shr, Not, BitXor, BitAnd, BitOr};
- use core::mem;
+macro_rules! int_module {
+ ($T:ident, $T_i:ident) => {
+ #[cfg(test)]
+ mod tests {
+ use core::isize;
+ use core::mem;
+ use core::ops::{BitAnd, BitOr, BitXor, Not, Shl, Shr};
+ use core::$T_i::*;
- use crate::num;
+ use crate::num;
- #[test]
- fn test_overflows() {
- assert!(MAX > 0);
- assert!(MIN <= 0);
- assert_eq!(MIN + MAX + 1, 0);
- }
+ #[test]
+ fn test_overflows() {
+ assert!(MAX > 0);
+ assert!(MIN <= 0);
+ assert_eq!(MIN + MAX + 1, 0);
+ }
- #[test]
- fn test_num() {
- num::test_num(10 as $T, 2 as $T);
- }
+ #[test]
+ fn test_num() {
+ num::test_num(10 as $T, 2 as $T);
+ }
- #[test]
- fn test_rem_euclid() {
- assert_eq!((-1 as $T).rem_euclid(MIN), MAX);
- }
+ #[test]
+ fn test_rem_euclid() {
+ assert_eq!((-1 as $T).rem_euclid(MIN), MAX);
+ }
- #[test]
- pub fn test_abs() {
- assert_eq!((1 as $T).abs(), 1 as $T);
- assert_eq!((0 as $T).abs(), 0 as $T);
- assert_eq!((-1 as $T).abs(), 1 as $T);
- }
+ #[test]
+ pub fn test_abs() {
+ assert_eq!((1 as $T).abs(), 1 as $T);
+ assert_eq!((0 as $T).abs(), 0 as $T);
+ assert_eq!((-1 as $T).abs(), 1 as $T);
+ }
- #[test]
- fn test_signum() {
- assert_eq!((1 as $T).signum(), 1 as $T);
- assert_eq!((0 as $T).signum(), 0 as $T);
- assert_eq!((-0 as $T).signum(), 0 as $T);
- assert_eq!((-1 as $T).signum(), -1 as $T);
- }
+ #[test]
+ fn test_signum() {
+ assert_eq!((1 as $T).signum(), 1 as $T);
+ assert_eq!((0 as $T).signum(), 0 as $T);
+ assert_eq!((-0 as $T).signum(), 0 as $T);
+ assert_eq!((-1 as $T).signum(), -1 as $T);
+ }
- #[test]
- fn test_is_positive() {
- assert!((1 as $T).is_positive());
- assert!(!(0 as $T).is_positive());
- assert!(!(-0 as $T).is_positive());
- assert!(!(-1 as $T).is_positive());
- }
+ #[test]
+ fn test_is_positive() {
+ assert!((1 as $T).is_positive());
+ assert!(!(0 as $T).is_positive());
+ assert!(!(-0 as $T).is_positive());
+ assert!(!(-1 as $T).is_positive());
+ }
- #[test]
- fn test_is_negative() {
- assert!(!(1 as $T).is_negative());
- assert!(!(0 as $T).is_negative());
- assert!(!(-0 as $T).is_negative());
- assert!((-1 as $T).is_negative());
- }
+ #[test]
+ fn test_is_negative() {
+ assert!(!(1 as $T).is_negative());
+ assert!(!(0 as $T).is_negative());
+ assert!(!(-0 as $T).is_negative());
+ assert!((-1 as $T).is_negative());
+ }
- #[test]
- fn test_bitwise_operators() {
- assert_eq!(0b1110 as $T, (0b1100 as $T).bitor(0b1010 as $T));
- assert_eq!(0b1000 as $T, (0b1100 as $T).bitand(0b1010 as $T));
- assert_eq!(0b0110 as $T, (0b1100 as $T).bitxor(0b1010 as $T));
- assert_eq!(0b1110 as $T, (0b0111 as $T).shl(1));
- assert_eq!(0b0111 as $T, (0b1110 as $T).shr(1));
- assert_eq!(-(0b11 as $T) - (1 as $T), (0b11 as $T).not());
- }
+ #[test]
+ fn test_bitwise_operators() {
+ assert_eq!(0b1110 as $T, (0b1100 as $T).bitor(0b1010 as $T));
+ assert_eq!(0b1000 as $T, (0b1100 as $T).bitand(0b1010 as $T));
+ assert_eq!(0b0110 as $T, (0b1100 as $T).bitxor(0b1010 as $T));
+ assert_eq!(0b1110 as $T, (0b0111 as $T).shl(1));
+ assert_eq!(0b0111 as $T, (0b1110 as $T).shr(1));
+ assert_eq!(-(0b11 as $T) - (1 as $T), (0b11 as $T).not());
+ }
- const A: $T = 0b0101100;
- const B: $T = 0b0100001;
- const C: $T = 0b1111001;
+ const A: $T = 0b0101100;
+ const B: $T = 0b0100001;
+ const C: $T = 0b1111001;
- const _0: $T = 0;
- const _1: $T = !0;
+ const _0: $T = 0;
+ const _1: $T = !0;
- #[test]
- fn test_count_ones() {
- assert_eq!(A.count_ones(), 3);
- assert_eq!(B.count_ones(), 2);
- assert_eq!(C.count_ones(), 5);
- }
+ #[test]
+ fn test_count_ones() {
+ assert_eq!(A.count_ones(), 3);
+ assert_eq!(B.count_ones(), 2);
+ assert_eq!(C.count_ones(), 5);
+ }
- #[test]
- fn test_count_zeros() {
- let bits = mem::size_of::<$T>() * 8;
- assert_eq!(A.count_zeros(), bits as u32 - 3);
- assert_eq!(B.count_zeros(), bits as u32 - 2);
- assert_eq!(C.count_zeros(), bits as u32 - 5);
- }
+ #[test]
+ fn test_count_zeros() {
+ let bits = mem::size_of::<$T>() * 8;
+ assert_eq!(A.count_zeros(), bits as u32 - 3);
+ assert_eq!(B.count_zeros(), bits as u32 - 2);
+ assert_eq!(C.count_zeros(), bits as u32 - 5);
+ }
- #[test]
- fn test_rotate() {
- assert_eq!(A.rotate_left(6).rotate_right(2).rotate_right(4), A);
- assert_eq!(B.rotate_left(3).rotate_left(2).rotate_right(5), B);
- assert_eq!(C.rotate_left(6).rotate_right(2).rotate_right(4), C);
+ #[test]
+ fn test_rotate() {
+ assert_eq!(A.rotate_left(6).rotate_right(2).rotate_right(4), A);
+ assert_eq!(B.rotate_left(3).rotate_left(2).rotate_right(5), B);
+ assert_eq!(C.rotate_left(6).rotate_right(2).rotate_right(4), C);
- // Rotating these should make no difference
- //
- // We test using 124 bits because to ensure that overlong bit shifts do
- // not cause undefined behaviour. See #10183.
- assert_eq!(_0.rotate_left(124), _0);
- assert_eq!(_1.rotate_left(124), _1);
- assert_eq!(_0.rotate_right(124), _0);
- assert_eq!(_1.rotate_right(124), _1);
+ // Rotating these should make no difference
+ //
+ // We test using 124 bits because to ensure that overlong bit shifts do
+ // not cause undefined behaviour. See #10183.
+ assert_eq!(_0.rotate_left(124), _0);
+ assert_eq!(_1.rotate_left(124), _1);
+ assert_eq!(_0.rotate_right(124), _0);
+ assert_eq!(_1.rotate_right(124), _1);
- // Rotating by 0 should have no effect
- assert_eq!(A.rotate_left(0), A);
- assert_eq!(B.rotate_left(0), B);
- assert_eq!(C.rotate_left(0), C);
- // Rotating by a multiple of word size should also have no effect
- assert_eq!(A.rotate_left(64), A);
- assert_eq!(B.rotate_left(64), B);
- assert_eq!(C.rotate_left(64), C);
- }
+ // Rotating by 0 should have no effect
+ assert_eq!(A.rotate_left(0), A);
+ assert_eq!(B.rotate_left(0), B);
+ assert_eq!(C.rotate_left(0), C);
+ // Rotating by a multiple of word size should also have no effect
+ assert_eq!(A.rotate_left(64), A);
+ assert_eq!(B.rotate_left(64), B);
+ assert_eq!(C.rotate_left(64), C);
+ }
- #[test]
- fn test_swap_bytes() {
- assert_eq!(A.swap_bytes().swap_bytes(), A);
- assert_eq!(B.swap_bytes().swap_bytes(), B);
- assert_eq!(C.swap_bytes().swap_bytes(), C);
+ #[test]
+ fn test_swap_bytes() {
+ assert_eq!(A.swap_bytes().swap_bytes(), A);
+ assert_eq!(B.swap_bytes().swap_bytes(), B);
+ assert_eq!(C.swap_bytes().swap_bytes(), C);
- // Swapping these should make no difference
- assert_eq!(_0.swap_bytes(), _0);
- assert_eq!(_1.swap_bytes(), _1);
- }
+ // Swapping these should make no difference
+ assert_eq!(_0.swap_bytes(), _0);
+ assert_eq!(_1.swap_bytes(), _1);
+ }
- #[test]
- fn test_le() {
- assert_eq!($T::from_le(A.to_le()), A);
- assert_eq!($T::from_le(B.to_le()), B);
- assert_eq!($T::from_le(C.to_le()), C);
- assert_eq!($T::from_le(_0), _0);
- assert_eq!($T::from_le(_1), _1);
- assert_eq!(_0.to_le(), _0);
- assert_eq!(_1.to_le(), _1);
- }
+ #[test]
+ fn test_le() {
+ assert_eq!($T::from_le(A.to_le()), A);
+ assert_eq!($T::from_le(B.to_le()), B);
+ assert_eq!($T::from_le(C.to_le()), C);
+ assert_eq!($T::from_le(_0), _0);
+ assert_eq!($T::from_le(_1), _1);
+ assert_eq!(_0.to_le(), _0);
+ assert_eq!(_1.to_le(), _1);
+ }
- #[test]
- fn test_be() {
- assert_eq!($T::from_be(A.to_be()), A);
- assert_eq!($T::from_be(B.to_be()), B);
- assert_eq!($T::from_be(C.to_be()), C);
- assert_eq!($T::from_be(_0), _0);
- assert_eq!($T::from_be(_1), _1);
- assert_eq!(_0.to_be(), _0);
- assert_eq!(_1.to_be(), _1);
- }
+ #[test]
+ fn test_be() {
+ assert_eq!($T::from_be(A.to_be()), A);
+ assert_eq!($T::from_be(B.to_be()), B);
+ assert_eq!($T::from_be(C.to_be()), C);
+ assert_eq!($T::from_be(_0), _0);
+ assert_eq!($T::from_be(_1), _1);
+ assert_eq!(_0.to_be(), _0);
+ assert_eq!(_1.to_be(), _1);
+ }
- #[test]
- fn test_signed_checked_div() {
- assert_eq!((10 as $T).checked_div(2), Some(5));
- assert_eq!((5 as $T).checked_div(0), None);
- assert_eq!(isize::MIN.checked_div(-1), None);
- }
+ #[test]
+ fn test_signed_checked_div() {
+ assert_eq!((10 as $T).checked_div(2), Some(5));
+ assert_eq!((5 as $T).checked_div(0), None);
+ assert_eq!(isize::MIN.checked_div(-1), None);
+ }
- #[test]
- fn test_saturating_abs() {
- assert_eq!((0 as $T).saturating_abs(), 0);
- assert_eq!((123 as $T).saturating_abs(), 123);
- assert_eq!((-123 as $T).saturating_abs(), 123);
- assert_eq!((MAX - 2).saturating_abs(), MAX - 2);
- assert_eq!((MAX - 1).saturating_abs(), MAX - 1);
- assert_eq!(MAX.saturating_abs(), MAX);
- assert_eq!((MIN + 2).saturating_abs(), MAX - 1);
- assert_eq!((MIN + 1).saturating_abs(), MAX);
- assert_eq!(MIN.saturating_abs(), MAX);
- }
+ #[test]
+ fn test_saturating_abs() {
+ assert_eq!((0 as $T).saturating_abs(), 0);
+ assert_eq!((123 as $T).saturating_abs(), 123);
+ assert_eq!((-123 as $T).saturating_abs(), 123);
+ assert_eq!((MAX - 2).saturating_abs(), MAX - 2);
+ assert_eq!((MAX - 1).saturating_abs(), MAX - 1);
+ assert_eq!(MAX.saturating_abs(), MAX);
+ assert_eq!((MIN + 2).saturating_abs(), MAX - 1);
+ assert_eq!((MIN + 1).saturating_abs(), MAX);
+ assert_eq!(MIN.saturating_abs(), MAX);
+ }
- #[test]
- fn test_saturating_neg() {
- assert_eq!((0 as $T).saturating_neg(), 0);
- assert_eq!((123 as $T).saturating_neg(), -123);
- assert_eq!((-123 as $T).saturating_neg(), 123);
- assert_eq!((MAX - 2).saturating_neg(), MIN + 3);
- assert_eq!((MAX - 1).saturating_neg(), MIN + 2);
- assert_eq!(MAX.saturating_neg(), MIN + 1);
- assert_eq!((MIN + 2).saturating_neg(), MAX - 1);
- assert_eq!((MIN + 1).saturating_neg(), MAX);
- assert_eq!(MIN.saturating_neg(), MAX);
- }
+ #[test]
+ fn test_saturating_neg() {
+ assert_eq!((0 as $T).saturating_neg(), 0);
+ assert_eq!((123 as $T).saturating_neg(), -123);
+ assert_eq!((-123 as $T).saturating_neg(), 123);
+ assert_eq!((MAX - 2).saturating_neg(), MIN + 3);
+ assert_eq!((MAX - 1).saturating_neg(), MIN + 2);
+ assert_eq!(MAX.saturating_neg(), MIN + 1);
+ assert_eq!((MIN + 2).saturating_neg(), MAX - 1);
+ assert_eq!((MIN + 1).saturating_neg(), MAX);
+ assert_eq!(MIN.saturating_neg(), MAX);
+ }
- #[test]
- fn test_from_str() {
- fn from_str<T: ::std::str::FromStr>(t: &str) -> Option<T> {
- ::std::str::FromStr::from_str(t).ok()
+ #[test]
+ fn test_from_str() {
+ fn from_str<T: ::std::str::FromStr>(t: &str) -> Option<T> {
+ ::std::str::FromStr::from_str(t).ok()
+ }
+ assert_eq!(from_str::<$T>("0"), Some(0 as $T));
+ assert_eq!(from_str::<$T>("3"), Some(3 as $T));
+ assert_eq!(from_str::<$T>("10"), Some(10 as $T));
+ assert_eq!(from_str::<i32>("123456789"), Some(123456789 as i32));
+ assert_eq!(from_str::<$T>("00100"), Some(100 as $T));
+
+ assert_eq!(from_str::<$T>("-1"), Some(-1 as $T));
+ assert_eq!(from_str::<$T>("-3"), Some(-3 as $T));
+ assert_eq!(from_str::<$T>("-10"), Some(-10 as $T));
+ assert_eq!(from_str::<i32>("-123456789"), Some(-123456789 as i32));
+ assert_eq!(from_str::<$T>("-00100"), Some(-100 as $T));
+
+ assert_eq!(from_str::<$T>(""), None);
+ assert_eq!(from_str::<$T>(" "), None);
+ assert_eq!(from_str::<$T>("x"), None);
+ }
+
+ #[test]
+ fn test_from_str_radix() {
+ assert_eq!($T::from_str_radix("123", 10), Ok(123 as $T));
+ assert_eq!($T::from_str_radix("1001", 2), Ok(9 as $T));
+ assert_eq!($T::from_str_radix("123", 8), Ok(83 as $T));
+ assert_eq!(i32::from_str_radix("123", 16), Ok(291 as i32));
+ assert_eq!(i32::from_str_radix("ffff", 16), Ok(65535 as i32));
+ assert_eq!(i32::from_str_radix("FFFF", 16), Ok(65535 as i32));
+ assert_eq!($T::from_str_radix("z", 36), Ok(35 as $T));
+ assert_eq!($T::from_str_radix("Z", 36), Ok(35 as $T));
+
+ assert_eq!($T::from_str_radix("-123", 10), Ok(-123 as $T));
+ assert_eq!($T::from_str_radix("-1001", 2), Ok(-9 as $T));
+ assert_eq!($T::from_str_radix("-123", 8), Ok(-83 as $T));
+ assert_eq!(i32::from_str_radix("-123", 16), Ok(-291 as i32));
+ assert_eq!(i32::from_str_radix("-ffff", 16), Ok(-65535 as i32));
+ assert_eq!(i32::from_str_radix("-FFFF", 16), Ok(-65535 as i32));
+ assert_eq!($T::from_str_radix("-z", 36), Ok(-35 as $T));
+ assert_eq!($T::from_str_radix("-Z", 36), Ok(-35 as $T));
+
+ assert_eq!($T::from_str_radix("Z", 35).ok(), None::<$T>);
+ assert_eq!($T::from_str_radix("-9", 2).ok(), None::<$T>);
+ }
+
+ #[test]
+ fn test_pow() {
+ let mut r = 2 as $T;
+
+ assert_eq!(r.pow(2), 4 as $T);
+ assert_eq!(r.pow(0), 1 as $T);
+ r = -2 as $T;
+ assert_eq!(r.pow(2), 4 as $T);
+ assert_eq!(r.pow(3), -8 as $T);
+ }
}
- assert_eq!(from_str::<$T>("0"), Some(0 as $T));
- assert_eq!(from_str::<$T>("3"), Some(3 as $T));
- assert_eq!(from_str::<$T>("10"), Some(10 as $T));
- assert_eq!(from_str::<i32>("123456789"), Some(123456789 as i32));
- assert_eq!(from_str::<$T>("00100"), Some(100 as $T));
-
- assert_eq!(from_str::<$T>("-1"), Some(-1 as $T));
- assert_eq!(from_str::<$T>("-3"), Some(-3 as $T));
- assert_eq!(from_str::<$T>("-10"), Some(-10 as $T));
- assert_eq!(from_str::<i32>("-123456789"), Some(-123456789 as i32));
- assert_eq!(from_str::<$T>("-00100"), Some(-100 as $T));
-
- assert_eq!(from_str::<$T>(""), None);
- assert_eq!(from_str::<$T>(" "), None);
- assert_eq!(from_str::<$T>("x"), None);
- }
-
- #[test]
- fn test_from_str_radix() {
- assert_eq!($T::from_str_radix("123", 10), Ok(123 as $T));
- assert_eq!($T::from_str_radix("1001", 2), Ok(9 as $T));
- assert_eq!($T::from_str_radix("123", 8), Ok(83 as $T));
- assert_eq!(i32::from_str_radix("123", 16), Ok(291 as i32));
- assert_eq!(i32::from_str_radix("ffff", 16), Ok(65535 as i32));
- assert_eq!(i32::from_str_radix("FFFF", 16), Ok(65535 as i32));
- assert_eq!($T::from_str_radix("z", 36), Ok(35 as $T));
- assert_eq!($T::from_str_radix("Z", 36), Ok(35 as $T));
-
- assert_eq!($T::from_str_radix("-123", 10), Ok(-123 as $T));
- assert_eq!($T::from_str_radix("-1001", 2), Ok(-9 as $T));
- assert_eq!($T::from_str_radix("-123", 8), Ok(-83 as $T));
- assert_eq!(i32::from_str_radix("-123", 16), Ok(-291 as i32));
- assert_eq!(i32::from_str_radix("-ffff", 16), Ok(-65535 as i32));
- assert_eq!(i32::from_str_radix("-FFFF", 16), Ok(-65535 as i32));
- assert_eq!($T::from_str_radix("-z", 36), Ok(-35 as $T));
- assert_eq!($T::from_str_radix("-Z", 36), Ok(-35 as $T));
-
- assert_eq!($T::from_str_radix("Z", 35).ok(), None::<$T>);
- assert_eq!($T::from_str_radix("-9", 2).ok(), None::<$T>);
- }
-
- #[test]
- fn test_pow() {
- let mut r = 2 as $T;
-
- assert_eq!(r.pow(2), 4 as $T);
- assert_eq!(r.pow(0), 1 as $T);
- r = -2 as $T;
- assert_eq!(r.pow(2), 4 as $T);
- assert_eq!(r.pow(3), -8 as $T);
- }
+ };
}
-
-)}
diff --git a/src/libcore/tests/num/uint_macros.rs b/src/libcore/tests/num/uint_macros.rs
index 04ed14f..f94b2f5 100644
--- a/src/libcore/tests/num/uint_macros.rs
+++ b/src/libcore/tests/num/uint_macros.rs
@@ -1,160 +1,162 @@
-macro_rules! uint_module { ($T:ident, $T_i:ident) => (
-#[cfg(test)]
-mod tests {
- use core::$T_i::*;
- use core::ops::{BitOr, BitAnd, BitXor, Shl, Shr, Not};
- use std::str::FromStr;
- use std::mem;
+macro_rules! uint_module {
+ ($T:ident, $T_i:ident) => {
+ #[cfg(test)]
+ mod tests {
+ use core::ops::{BitAnd, BitOr, BitXor, Not, Shl, Shr};
+ use core::$T_i::*;
+ use std::mem;
+ use std::str::FromStr;
- use crate::num;
+ use crate::num;
- #[test]
- fn test_overflows() {
- assert!(MAX > 0);
- assert!(MIN <= 0);
- assert!((MIN + MAX).wrapping_add(1) == 0);
- }
+ #[test]
+ fn test_overflows() {
+ assert!(MAX > 0);
+ assert!(MIN <= 0);
+ assert!((MIN + MAX).wrapping_add(1) == 0);
+ }
- #[test]
- fn test_num() {
- num::test_num(10 as $T, 2 as $T);
- }
+ #[test]
+ fn test_num() {
+ num::test_num(10 as $T, 2 as $T);
+ }
- #[test]
- fn test_bitwise_operators() {
- assert!(0b1110 as $T == (0b1100 as $T).bitor(0b1010 as $T));
- assert!(0b1000 as $T == (0b1100 as $T).bitand(0b1010 as $T));
- assert!(0b0110 as $T == (0b1100 as $T).bitxor(0b1010 as $T));
- assert!(0b1110 as $T == (0b0111 as $T).shl(1));
- assert!(0b0111 as $T == (0b1110 as $T).shr(1));
- assert!(MAX - (0b1011 as $T) == (0b1011 as $T).not());
- }
+ #[test]
+ fn test_bitwise_operators() {
+ assert!(0b1110 as $T == (0b1100 as $T).bitor(0b1010 as $T));
+ assert!(0b1000 as $T == (0b1100 as $T).bitand(0b1010 as $T));
+ assert!(0b0110 as $T == (0b1100 as $T).bitxor(0b1010 as $T));
+ assert!(0b1110 as $T == (0b0111 as $T).shl(1));
+ assert!(0b0111 as $T == (0b1110 as $T).shr(1));
+ assert!(MAX - (0b1011 as $T) == (0b1011 as $T).not());
+ }
- const A: $T = 0b0101100;
- const B: $T = 0b0100001;
- const C: $T = 0b1111001;
+ const A: $T = 0b0101100;
+ const B: $T = 0b0100001;
+ const C: $T = 0b1111001;
- const _0: $T = 0;
- const _1: $T = !0;
+ const _0: $T = 0;
+ const _1: $T = !0;
- #[test]
- fn test_count_ones() {
- assert!(A.count_ones() == 3);
- assert!(B.count_ones() == 2);
- assert!(C.count_ones() == 5);
- }
+ #[test]
+ fn test_count_ones() {
+ assert!(A.count_ones() == 3);
+ assert!(B.count_ones() == 2);
+ assert!(C.count_ones() == 5);
+ }
- #[test]
- fn test_count_zeros() {
- let bits = mem::size_of::<$T>() * 8;
- assert!(A.count_zeros() == bits as u32 - 3);
- assert!(B.count_zeros() == bits as u32 - 2);
- assert!(C.count_zeros() == bits as u32 - 5);
- }
+ #[test]
+ fn test_count_zeros() {
+ let bits = mem::size_of::<$T>() * 8;
+ assert!(A.count_zeros() == bits as u32 - 3);
+ assert!(B.count_zeros() == bits as u32 - 2);
+ assert!(C.count_zeros() == bits as u32 - 5);
+ }
- #[test]
- fn test_rotate() {
- assert_eq!(A.rotate_left(6).rotate_right(2).rotate_right(4), A);
- assert_eq!(B.rotate_left(3).rotate_left(2).rotate_right(5), B);
- assert_eq!(C.rotate_left(6).rotate_right(2).rotate_right(4), C);
+ #[test]
+ fn test_rotate() {
+ assert_eq!(A.rotate_left(6).rotate_right(2).rotate_right(4), A);
+ assert_eq!(B.rotate_left(3).rotate_left(2).rotate_right(5), B);
+ assert_eq!(C.rotate_left(6).rotate_right(2).rotate_right(4), C);
- // Rotating these should make no difference
- //
- // We test using 124 bits because to ensure that overlong bit shifts do
- // not cause undefined behaviour. See #10183.
- assert_eq!(_0.rotate_left(124), _0);
- assert_eq!(_1.rotate_left(124), _1);
- assert_eq!(_0.rotate_right(124), _0);
- assert_eq!(_1.rotate_right(124), _1);
+ // Rotating these should make no difference
+ //
+ // We test using 124 bits because to ensure that overlong bit shifts do
+ // not cause undefined behaviour. See #10183.
+ assert_eq!(_0.rotate_left(124), _0);
+ assert_eq!(_1.rotate_left(124), _1);
+ assert_eq!(_0.rotate_right(124), _0);
+ assert_eq!(_1.rotate_right(124), _1);
- // Rotating by 0 should have no effect
- assert_eq!(A.rotate_left(0), A);
- assert_eq!(B.rotate_left(0), B);
- assert_eq!(C.rotate_left(0), C);
- // Rotating by a multiple of word size should also have no effect
- assert_eq!(A.rotate_left(64), A);
- assert_eq!(B.rotate_left(64), B);
- assert_eq!(C.rotate_left(64), C);
- }
+ // Rotating by 0 should have no effect
+ assert_eq!(A.rotate_left(0), A);
+ assert_eq!(B.rotate_left(0), B);
+ assert_eq!(C.rotate_left(0), C);
+ // Rotating by a multiple of word size should also have no effect
+ assert_eq!(A.rotate_left(64), A);
+ assert_eq!(B.rotate_left(64), B);
+ assert_eq!(C.rotate_left(64), C);
+ }
- #[test]
- fn test_swap_bytes() {
- assert_eq!(A.swap_bytes().swap_bytes(), A);
- assert_eq!(B.swap_bytes().swap_bytes(), B);
- assert_eq!(C.swap_bytes().swap_bytes(), C);
+ #[test]
+ fn test_swap_bytes() {
+ assert_eq!(A.swap_bytes().swap_bytes(), A);
+ assert_eq!(B.swap_bytes().swap_bytes(), B);
+ assert_eq!(C.swap_bytes().swap_bytes(), C);
- // Swapping these should make no difference
- assert_eq!(_0.swap_bytes(), _0);
- assert_eq!(_1.swap_bytes(), _1);
- }
+ // Swapping these should make no difference
+ assert_eq!(_0.swap_bytes(), _0);
+ assert_eq!(_1.swap_bytes(), _1);
+ }
- #[test]
- fn test_reverse_bits() {
- assert_eq!(A.reverse_bits().reverse_bits(), A);
- assert_eq!(B.reverse_bits().reverse_bits(), B);
- assert_eq!(C.reverse_bits().reverse_bits(), C);
+ #[test]
+ fn test_reverse_bits() {
+ assert_eq!(A.reverse_bits().reverse_bits(), A);
+ assert_eq!(B.reverse_bits().reverse_bits(), B);
+ assert_eq!(C.reverse_bits().reverse_bits(), C);
- // Swapping these should make no difference
- assert_eq!(_0.reverse_bits(), _0);
- assert_eq!(_1.reverse_bits(), _1);
- }
+ // Swapping these should make no difference
+ assert_eq!(_0.reverse_bits(), _0);
+ assert_eq!(_1.reverse_bits(), _1);
+ }
- #[test]
- fn test_le() {
- assert_eq!($T::from_le(A.to_le()), A);
- assert_eq!($T::from_le(B.to_le()), B);
- assert_eq!($T::from_le(C.to_le()), C);
- assert_eq!($T::from_le(_0), _0);
- assert_eq!($T::from_le(_1), _1);
- assert_eq!(_0.to_le(), _0);
- assert_eq!(_1.to_le(), _1);
- }
+ #[test]
+ fn test_le() {
+ assert_eq!($T::from_le(A.to_le()), A);
+ assert_eq!($T::from_le(B.to_le()), B);
+ assert_eq!($T::from_le(C.to_le()), C);
+ assert_eq!($T::from_le(_0), _0);
+ assert_eq!($T::from_le(_1), _1);
+ assert_eq!(_0.to_le(), _0);
+ assert_eq!(_1.to_le(), _1);
+ }
- #[test]
- fn test_be() {
- assert_eq!($T::from_be(A.to_be()), A);
- assert_eq!($T::from_be(B.to_be()), B);
- assert_eq!($T::from_be(C.to_be()), C);
- assert_eq!($T::from_be(_0), _0);
- assert_eq!($T::from_be(_1), _1);
- assert_eq!(_0.to_be(), _0);
- assert_eq!(_1.to_be(), _1);
- }
+ #[test]
+ fn test_be() {
+ assert_eq!($T::from_be(A.to_be()), A);
+ assert_eq!($T::from_be(B.to_be()), B);
+ assert_eq!($T::from_be(C.to_be()), C);
+ assert_eq!($T::from_be(_0), _0);
+ assert_eq!($T::from_be(_1), _1);
+ assert_eq!(_0.to_be(), _0);
+ assert_eq!(_1.to_be(), _1);
+ }
- #[test]
- fn test_unsigned_checked_div() {
- assert!((10 as $T).checked_div(2) == Some(5));
- assert!((5 as $T).checked_div(0) == None);
- }
+ #[test]
+ fn test_unsigned_checked_div() {
+ assert!((10 as $T).checked_div(2) == Some(5));
+ assert!((5 as $T).checked_div(0) == None);
+ }
- fn from_str<T: FromStr>(t: &str) -> Option<T> {
- FromStr::from_str(t).ok()
- }
+ fn from_str<T: FromStr>(t: &str) -> Option<T> {
+ FromStr::from_str(t).ok()
+ }
- #[test]
- pub fn test_from_str() {
- assert_eq!(from_str::<$T>("0"), Some(0 as $T));
- assert_eq!(from_str::<$T>("3"), Some(3 as $T));
- assert_eq!(from_str::<$T>("10"), Some(10 as $T));
- assert_eq!(from_str::<u32>("123456789"), Some(123456789 as u32));
- assert_eq!(from_str::<$T>("00100"), Some(100 as $T));
+ #[test]
+ pub fn test_from_str() {
+ assert_eq!(from_str::<$T>("0"), Some(0 as $T));
+ assert_eq!(from_str::<$T>("3"), Some(3 as $T));
+ assert_eq!(from_str::<$T>("10"), Some(10 as $T));
+ assert_eq!(from_str::<u32>("123456789"), Some(123456789 as u32));
+ assert_eq!(from_str::<$T>("00100"), Some(100 as $T));
- assert_eq!(from_str::<$T>(""), None);
- assert_eq!(from_str::<$T>(" "), None);
- assert_eq!(from_str::<$T>("x"), None);
- }
+ assert_eq!(from_str::<$T>(""), None);
+ assert_eq!(from_str::<$T>(" "), None);
+ assert_eq!(from_str::<$T>("x"), None);
+ }
- #[test]
- pub fn test_parse_bytes() {
- assert_eq!($T::from_str_radix("123", 10), Ok(123 as $T));
- assert_eq!($T::from_str_radix("1001", 2), Ok(9 as $T));
- assert_eq!($T::from_str_radix("123", 8), Ok(83 as $T));
- assert_eq!(u16::from_str_radix("123", 16), Ok(291 as u16));
- assert_eq!(u16::from_str_radix("ffff", 16), Ok(65535 as u16));
- assert_eq!($T::from_str_radix("z", 36), Ok(35 as $T));
+ #[test]
+ pub fn test_parse_bytes() {
+ assert_eq!($T::from_str_radix("123", 10), Ok(123 as $T));
+ assert_eq!($T::from_str_radix("1001", 2), Ok(9 as $T));
+ assert_eq!($T::from_str_radix("123", 8), Ok(83 as $T));
+ assert_eq!(u16::from_str_radix("123", 16), Ok(291 as u16));
+ assert_eq!(u16::from_str_radix("ffff", 16), Ok(65535 as u16));
+ assert_eq!($T::from_str_radix("z", 36), Ok(35 as $T));
- assert_eq!($T::from_str_radix("Z", 10).ok(), None::<$T>);
- assert_eq!($T::from_str_radix("_", 2).ok(), None::<$T>);
- }
+ assert_eq!($T::from_str_radix("Z", 10).ok(), None::<$T>);
+ assert_eq!($T::from_str_radix("_", 2).ok(), None::<$T>);
+ }
+ }
+ };
}
-)}
diff --git a/src/libcore/tests/ops.rs b/src/libcore/tests/ops.rs
index 48755ae..43eb498 100644
--- a/src/libcore/tests/ops.rs
+++ b/src/libcore/tests/ops.rs
@@ -1,4 +1,4 @@
-use core::ops::{Bound, Range, RangeFull, RangeFrom, RangeTo, RangeInclusive};
+use core::ops::{Bound, Range, RangeFrom, RangeFull, RangeInclusive, RangeTo};
// Test the Range structs without the syntactic sugar.
@@ -59,28 +59,27 @@
assert_eq!(r.next(), None);
}
-
#[test]
fn test_range_is_empty() {
use core::f32::*;
- assert!(!(0.0 .. 10.0).is_empty());
- assert!( (-0.0 .. 0.0).is_empty());
- assert!( (10.0 .. 0.0).is_empty());
+ assert!(!(0.0..10.0).is_empty());
+ assert!((-0.0..0.0).is_empty());
+ assert!((10.0..0.0).is_empty());
- assert!(!(NEG_INFINITY .. INFINITY).is_empty());
- assert!( (EPSILON .. NAN).is_empty());
- assert!( (NAN .. EPSILON).is_empty());
- assert!( (NAN .. NAN).is_empty());
+ assert!(!(NEG_INFINITY..INFINITY).is_empty());
+ assert!((EPSILON..NAN).is_empty());
+ assert!((NAN..EPSILON).is_empty());
+ assert!((NAN..NAN).is_empty());
- assert!(!(0.0 ..= 10.0).is_empty());
- assert!(!(-0.0 ..= 0.0).is_empty());
- assert!( (10.0 ..= 0.0).is_empty());
+ assert!(!(0.0..=10.0).is_empty());
+ assert!(!(-0.0..=0.0).is_empty());
+ assert!((10.0..=0.0).is_empty());
- assert!(!(NEG_INFINITY ..= INFINITY).is_empty());
- assert!( (EPSILON ..= NAN).is_empty());
- assert!( (NAN ..= EPSILON).is_empty());
- assert!( (NAN ..= NAN).is_empty());
+ assert!(!(NEG_INFINITY..=INFINITY).is_empty());
+ assert!((EPSILON..=NAN).is_empty());
+ assert!((NAN..=EPSILON).is_empty());
+ assert!((NAN..=NAN).is_empty());
}
#[test]
diff --git a/src/libcore/tests/option.rs b/src/libcore/tests/option.rs
index ff43fc4..fa30816 100644
--- a/src/libcore/tests/option.rs
+++ b/src/libcore/tests/option.rs
@@ -1,8 +1,8 @@
-use core::option::*;
-use core::mem;
-use core::clone::Clone;
use core::array::FixedSizeArray;
+use core::clone::Clone;
+use core::mem;
use core::ops::DerefMut;
+use core::option::*;
#[test]
fn test_get_ptr() {
@@ -28,15 +28,15 @@
#[test]
fn test_get_resource() {
- use std::rc::Rc;
use core::cell::RefCell;
+ use std::rc::Rc;
struct R {
- i: Rc<RefCell<isize>>,
+ i: Rc<RefCell<isize>>,
}
- impl Drop for R {
- fn drop(&mut self) {
+ impl Drop for R {
+ fn drop(&mut self) {
let ii = &*self.i;
let i = *ii.borrow();
*ii.borrow_mut() = i + 1;
@@ -44,9 +44,7 @@
}
fn r(i: Rc<RefCell<isize>>) -> R {
- R {
- i,
- }
+ R { i }
}
let i = Rc::new(RefCell::new(0));
@@ -70,7 +68,8 @@
assert!(y.is_none());
}
-#[test] #[should_panic]
+#[test]
+#[should_panic]
fn test_option_too_much_dance() {
struct A;
let mut y = Some(A);
@@ -210,7 +209,7 @@
fn test_ord() {
let small = Some(1.0f64);
let big = Some(5.0f64);
- let nan = Some(0.0f64/0.0);
+ let nan = Some(0.0f64 / 0.0);
assert!(!(nan < big));
assert!(!(nan > big));
assert!(small < big);
@@ -226,9 +225,7 @@
let v: Option<Vec<isize>> = (0..3).map(|x| Some(x)).collect();
assert!(v == Some(vec![0, 1, 2]));
- let v: Option<Vec<isize>> = (0..3).map(|x| {
- if x > 1 { None } else { Some(x) }
- }).collect();
+ let v: Option<Vec<isize>> = (0..3).map(|x| if x > 1 { None } else { Some(x) }).collect();
assert!(v == None);
// test that it does not take more elements than it needs
diff --git a/src/libcore/tests/ptr.rs b/src/libcore/tests/ptr.rs
index 1a6be3a..eea736b 100644
--- a/src/libcore/tests/ptr.rs
+++ b/src/libcore/tests/ptr.rs
@@ -1,14 +1,14 @@
-use core::ptr::*;
use core::cell::RefCell;
+use core::ptr::*;
#[test]
fn test() {
unsafe {
struct Pair {
fst: isize,
- snd: isize
+ snd: isize,
};
- let mut p = Pair {fst: 10, snd: 20};
+ let mut p = Pair { fst: 10, snd: 20 };
let pptr: *mut Pair = &mut p;
let iptr: *mut isize = pptr as *mut isize;
assert_eq!(*iptr, 10);
@@ -16,7 +16,7 @@
assert_eq!(*iptr, 30);
assert_eq!(p.fst, 30);
- *pptr = Pair {fst: 50, snd: 60};
+ *pptr = Pair { fst: 50, snd: 60 };
assert_eq!(*iptr, 50);
assert_eq!(p.fst, 50);
assert_eq!(p.snd, 60);
@@ -25,17 +25,11 @@
let mut v1 = vec![0u16, 0u16, 0u16];
copy(v0.as_ptr().offset(1), v1.as_mut_ptr().offset(1), 1);
- assert!((v1[0] == 0u16 &&
- v1[1] == 32001u16 &&
- v1[2] == 0u16));
+ assert!((v1[0] == 0u16 && v1[1] == 32001u16 && v1[2] == 0u16));
copy(v0.as_ptr().offset(2), v1.as_mut_ptr(), 1);
- assert!((v1[0] == 32002u16 &&
- v1[1] == 32001u16 &&
- v1[2] == 0u16));
+ assert!((v1[0] == 32002u16 && v1[1] == 32001u16 && v1[2] == 0u16));
copy(v0.as_ptr(), v1.as_mut_ptr().offset(2), 1);
- assert!((v1[0] == 32002u16 &&
- v1[1] == 32001u16 &&
- v1[2] == 32000u16));
+ assert!((v1[0] == 32002u16 && v1[1] == 32001u16 && v1[2] == 32000u16));
}
}
@@ -208,7 +202,7 @@
#[test]
fn test_ptr_subtraction() {
unsafe {
- let xs = vec![0,1,2,3,4,5,6,7,8,9];
+ let xs = vec![0, 1, 2, 3, 4, 5, 6, 7, 8, 9];
let mut idx = 9;
let ptr = xs.as_ptr();
@@ -229,7 +223,7 @@
m_ptr = m_ptr.offset(-1);
}
- assert_eq!(xs_mut, [0,2,4,6,8,10,12,14,16,18]);
+ assert_eq!(xs_mut, [0, 2, 4, 6, 8, 10, 12, 14, 16, 18]);
}
}
@@ -237,7 +231,9 @@
fn test_set_memory() {
let mut xs = [0u8; 20];
let ptr = xs.as_mut_ptr();
- unsafe { write_bytes(ptr, 5u8, xs.len()); }
+ unsafe {
+ write_bytes(ptr, 5u8, xs.len());
+ }
assert!(xs == [5u8; 20]);
}
@@ -257,10 +253,10 @@
#[no_mangle]
pub fn test_variadic_fnptr() {
use core::hash::{Hash, SipHasher};
- extern {
+ extern "C" {
fn test_variadic_fnptr(_: u64, ...) -> f64;
}
- let p: unsafe extern fn(u64, ...) -> f64 = test_variadic_fnptr;
+ let p: unsafe extern "C" fn(u64, ...) -> f64 = test_variadic_fnptr;
let q = p.clone();
assert_eq!(p, q);
assert!(!(p < q));
@@ -285,13 +281,15 @@
{
let c = Dropper(0);
let mut t = Dropper(1);
- unsafe { write_unaligned(&mut t, c); }
+ unsafe {
+ write_unaligned(&mut t, c);
+ }
}
DROPS.with(|d| assert_eq!(*d.borrow(), [0]));
}
#[test]
-#[cfg(not(miri))] // Miri does not compute a maximal `mid` for `align_offset`
+#[cfg_attr(miri, ignore)] // Miri does not compute a maximal `mid` for `align_offset`
fn align_offset_zst() {
// For pointers of stride = 0, the pointer is already aligned or it cannot be aligned at
// all, because no amount of elements will align the pointer.
@@ -306,24 +304,29 @@
}
#[test]
-#[cfg(not(miri))] // Miri does not compute a maximal `mid` for `align_offset`
+#[cfg_attr(miri, ignore)] // Miri does not compute a maximal `mid` for `align_offset`
fn align_offset_stride1() {
// For pointers of stride = 1, the pointer can always be aligned. The offset is equal to
// number of bytes.
let mut align = 1;
while align < 1024 {
- for ptr in 1..2*align {
+ for ptr in 1..2 * align {
let expected = ptr % align;
let offset = if expected == 0 { 0 } else { align - expected };
- assert_eq!((ptr as *const u8).align_offset(align), offset,
- "ptr = {}, align = {}, size = 1", ptr, align);
+ assert_eq!(
+ (ptr as *const u8).align_offset(align),
+ offset,
+ "ptr = {}, align = {}, size = 1",
+ ptr,
+ align
+ );
}
align = (align + 1).next_power_of_two();
}
}
#[test]
-#[cfg(not(miri))] // Miri is too slow
+#[cfg_attr(miri, ignore)] // Miri is too slow
fn align_offset_weird_strides() {
#[repr(packed)]
struct A3(u16, u8);
@@ -353,8 +356,14 @@
}
let got = ptr.align_offset(align);
if got != expected {
- eprintln!("aligning {:p} (with stride of {}) to {}, expected {}, got {}", ptr,
- ::std::mem::size_of::<T>(), align, expected, got);
+ eprintln!(
+ "aligning {:p} (with stride of {}) to {}, expected {}, got {}",
+ ptr,
+ ::std::mem::size_of::<T>(),
+ align,
+ expected,
+ got
+ );
return true;
}
return false;
@@ -365,7 +374,7 @@
let mut align = 1;
let mut x = false;
while align < 1024 {
- for ptr in 1usize..4*align {
+ for ptr in 1usize..4 * align {
unsafe {
x |= test_weird_stride::<A3>(ptr as *const A3, align);
x |= test_weird_stride::<A4>(ptr as *const A4, align);
diff --git a/src/libcore/tests/slice.rs b/src/libcore/tests/slice.rs
index 6609bc3..cc274b4 100644
--- a/src/libcore/tests/slice.rs
+++ b/src/libcore/tests/slice.rs
@@ -1,4 +1,4 @@
-use core::result::Result::{Ok, Err};
+use core::result::Result::{Err, Ok};
#[test]
fn test_position() {
@@ -50,8 +50,14 @@
assert_eq!(b.binary_search(&0), Err(0));
assert_eq!(b.binary_search(&1), Ok(0));
assert_eq!(b.binary_search(&2), Err(1));
- assert!(match b.binary_search(&3) { Ok(1..=3) => true, _ => false });
- assert!(match b.binary_search(&3) { Ok(1..=3) => true, _ => false });
+ assert!(match b.binary_search(&3) {
+ Ok(1..=3) => true,
+ _ => false,
+ });
+ assert!(match b.binary_search(&3) {
+ Ok(1..=3) => true,
+ _ => false,
+ });
assert_eq!(b.binary_search(&4), Err(4));
assert_eq!(b.binary_search(&5), Err(4));
assert_eq!(b.binary_search(&6), Err(4));
@@ -187,7 +193,8 @@
let v1: &[i32] = &[0, 1, 2, 3, 4];
let v2: &[i32] = &[6, 7, 8, 9, 10];
- let res = v1.chunks(2)
+ let res = v1
+ .chunks(2)
.zip(v2.chunks(2))
.map(|(a, b)| a.iter().sum::<i32>() + b.iter().sum::<i32>())
.collect::<Vec<_>>();
@@ -339,7 +346,8 @@
let v1: &[i32] = &[0, 1, 2, 3, 4];
let v2: &[i32] = &[6, 7, 8, 9, 10];
- let res = v1.chunks_exact(2)
+ let res = v1
+ .chunks_exact(2)
.zip(v2.chunks_exact(2))
.map(|(a, b)| a.iter().sum::<i32>() + b.iter().sum::<i32>())
.collect::<Vec<_>>();
@@ -482,7 +490,8 @@
let v1: &[i32] = &[0, 1, 2, 3, 4];
let v2: &[i32] = &[6, 7, 8, 9, 10];
- let res = v1.rchunks(2)
+ let res = v1
+ .rchunks(2)
.zip(v2.rchunks(2))
.map(|(a, b)| a.iter().sum::<i32>() + b.iter().sum::<i32>())
.collect::<Vec<_>>();
@@ -619,7 +628,8 @@
let v1: &[i32] = &[0, 1, 2, 3, 4];
let v2: &[i32] = &[6, 7, 8, 9, 10];
- let res = v1.rchunks_exact(2)
+ let res = v1
+ .rchunks_exact(2)
.zip(v2.rchunks_exact(2))
.map(|(a, b)| a.iter().sum::<i32>() + b.iter().sum::<i32>())
.collect::<Vec<_>>();
@@ -756,7 +766,8 @@
let v1: &[i32] = &[0, 1, 2, 3, 4];
let v2: &[i32] = &[6, 7, 8, 9, 10];
- let res = v1.windows(2)
+ let res = v1
+ .windows(2)
.zip(v2.windows(2))
.map(|(a, b)| a.iter().sum::<i32>() + b.iter().sum::<i32>())
.collect::<Vec<_>>();
@@ -769,11 +780,11 @@
fn test_iter_ref_consistency() {
use std::fmt::Debug;
- fn test<T : Copy + Debug + PartialEq>(x : T) {
- let v : &[T] = &[x, x, x];
- let v_ptrs : [*const T; 3] = match v {
+ fn test<T: Copy + Debug + PartialEq>(x: T) {
+ let v: &[T] = &[x, x, x];
+ let v_ptrs: [*const T; 3] = match v {
[ref v1, ref v2, ref v3] => [v1 as *const _, v2 as *const _, v3 as *const _],
- _ => unreachable!()
+ _ => unreachable!(),
};
let len = v.len();
@@ -817,19 +828,20 @@
assert_eq!(it.size_hint(), (remaining, Some(remaining)));
let prev = it.next_back().unwrap();
- assert_eq!(prev as *const _, v_ptrs[remaining-1]);
+ assert_eq!(prev as *const _, v_ptrs[remaining - 1]);
}
assert_eq!(it.size_hint(), (0, Some(0)));
assert_eq!(it.next_back(), None, "The final call to next_back() should return None");
}
}
- fn test_mut<T : Copy + Debug + PartialEq>(x : T) {
- let v : &mut [T] = &mut [x, x, x];
- let v_ptrs : [*mut T; 3] = match v {
- [ref v1, ref v2, ref v3] =>
- [v1 as *const _ as *mut _, v2 as *const _ as *mut _, v3 as *const _ as *mut _],
- _ => unreachable!()
+ fn test_mut<T: Copy + Debug + PartialEq>(x: T) {
+ let v: &mut [T] = &mut [x, x, x];
+ let v_ptrs: [*mut T; 3] = match v {
+ [ref v1, ref v2, ref v3] => {
+ [v1 as *const _ as *mut _, v2 as *const _ as *mut _, v3 as *const _ as *mut _]
+ }
+ _ => unreachable!(),
};
let len = v.len();
@@ -873,7 +885,7 @@
assert_eq!(it.size_hint(), (remaining, Some(remaining)));
let prev = it.next_back().unwrap();
- assert_eq!(prev as *mut _, v_ptrs[remaining-1]);
+ assert_eq!(prev as *mut _, v_ptrs[remaining - 1]);
}
assert_eq!(it.size_hint(), (0, Some(0)));
assert_eq!(it.next_back(), None, "The final call to next_back() should return None");
@@ -897,8 +909,7 @@
// This checks all six indexing methods, given an input range that
// should succeed. (it is NOT suitable for testing invalid inputs)
macro_rules! assert_range_eq {
- ($arr:expr, $range:expr, $expected:expr)
- => {
+ ($arr:expr, $range:expr, $expected:expr) => {
let mut arr = $arr;
let mut expected = $expected;
{
@@ -909,7 +920,8 @@
assert_eq!(s.get($range), Some(expected), "(in assertion for: get)");
unsafe {
assert_eq!(
- s.get_unchecked($range), expected,
+ s.get_unchecked($range),
+ expected,
"(in assertion for: get_unchecked)",
);
}
@@ -918,22 +930,21 @@
let s: &mut [_] = &mut arr;
let expected: &mut [_] = &mut expected;
+ assert_eq!(&mut s[$range], expected, "(in assertion for: index_mut)",);
assert_eq!(
- &mut s[$range], expected,
- "(in assertion for: index_mut)",
- );
- assert_eq!(
- s.get_mut($range), Some(&mut expected[..]),
+ s.get_mut($range),
+ Some(&mut expected[..]),
"(in assertion for: get_mut)",
);
unsafe {
assert_eq!(
- s.get_unchecked_mut($range), expected,
+ s.get_unchecked_mut($range),
+ expected,
"(in assertion for: get_unchecked_mut)",
);
}
}
- }
+ };
}
// Make sure the macro can actually detect bugs,
@@ -1126,8 +1137,8 @@
#[test]
fn test_iter_folds() {
let a = [1, 2, 3, 4, 5]; // len>4 so the unroll is used
- assert_eq!(a.iter().fold(0, |acc, &x| 2*acc + x), 57);
- assert_eq!(a.iter().rfold(0, |acc, &x| 2*acc + x), 129);
+ assert_eq!(a.iter().fold(0, |acc, &x| 2 * acc + x), 57);
+ assert_eq!(a.iter().rfold(0, |acc, &x| 2 * acc + x), 129);
let fold = |acc: i32, &x| acc.checked_mul(2)?.checked_add(x);
assert_eq!(a.iter().try_fold(0, &fold), Some(57));
assert_eq!(a.iter().try_rfold(0, &fold), Some(129));
@@ -1172,7 +1183,7 @@
}
#[test]
-#[cfg(not(miri))] // Miri is too slow
+#[cfg_attr(miri, ignore)] // Miri is too slow
fn brute_force_rotate_test_0() {
// In case of edge cases involving multiple algorithms
let n = 300;
@@ -1214,7 +1225,7 @@
fn sort_unstable() {
use core::cmp::Ordering::{Equal, Greater, Less};
use core::slice::heapsort;
- use rand::{SeedableRng, Rng, rngs::StdRng, seq::SliceRandom};
+ use rand::{rngs::StdRng, seq::SliceRandom, Rng, SeedableRng};
#[cfg(not(miri))] // Miri is too slow
let large_range = 500..510;
@@ -1291,12 +1302,12 @@
#[test]
#[cfg(not(target_arch = "wasm32"))]
-#[cfg(not(miri))] // Miri is too slow
+#[cfg_attr(miri, ignore)] // Miri is too slow
fn partition_at_index() {
use core::cmp::Ordering::{Equal, Greater, Less};
use rand::rngs::StdRng;
use rand::seq::SliceRandom;
- use rand::{SeedableRng, Rng};
+ use rand::{Rng, SeedableRng};
let mut rng = StdRng::from_entropy();
@@ -1494,7 +1505,7 @@
}
#[test]
-#[cfg(not(miri))] // Miri does not compute a maximal `mid` for `align_offset`
+#[cfg_attr(miri, ignore)] // Miri does not compute a maximal `mid` for `align_offset`
fn test_align_to_simple() {
let bytes = [1u8, 2, 3, 4, 5, 6, 7];
let (prefix, aligned, suffix) = unsafe { bytes.align_to::<u16>() };
@@ -1504,9 +1515,15 @@
let expect2 = [1 | 2 << 8, 3 | 4 << 8, 5 | 6 << 8];
let expect3 = [2 << 8 | 3, 4 << 8 | 5, 6 << 8 | 7];
let expect4 = [2 | 3 << 8, 4 | 5 << 8, 6 | 7 << 8];
- assert!(aligned == expect1 || aligned == expect2 || aligned == expect3 || aligned == expect4,
- "aligned={:?} expected={:?} || {:?} || {:?} || {:?}",
- aligned, expect1, expect2, expect3, expect4);
+ assert!(
+ aligned == expect1 || aligned == expect2 || aligned == expect3 || aligned == expect4,
+ "aligned={:?} expected={:?} || {:?} || {:?} || {:?}",
+ aligned,
+ expect1,
+ expect2,
+ expect3,
+ expect4
+ );
}
#[test]
@@ -1518,12 +1535,22 @@
}
#[test]
-#[cfg(not(miri))] // Miri does not compute a maximal `mid` for `align_offset`
+#[cfg_attr(miri, ignore)] // Miri does not compute a maximal `mid` for `align_offset`
fn test_align_to_non_trivial() {
- #[repr(align(8))] struct U64(u64, u64);
- #[repr(align(8))] struct U64U64U32(u64, u64, u32);
- let data = [U64(1, 2), U64(3, 4), U64(5, 6), U64(7, 8), U64(9, 10), U64(11, 12), U64(13, 14),
- U64(15, 16)];
+ #[repr(align(8))]
+ struct U64(u64, u64);
+ #[repr(align(8))]
+ struct U64U64U32(u64, u64, u32);
+ let data = [
+ U64(1, 2),
+ U64(3, 4),
+ U64(5, 6),
+ U64(7, 8),
+ U64(9, 10),
+ U64(11, 12),
+ U64(13, 14),
+ U64(15, 16),
+ ];
let (prefix, aligned, suffix) = unsafe { data.align_to::<U64U64U32>() };
assert_eq!(aligned.len(), 4);
assert_eq!(prefix.len() + suffix.len(), 2);
@@ -1538,7 +1565,7 @@
let bytes = [1, 2, 3, 4, 5, 6, 7];
type Chunk = u32;
for offset in 0..4 {
- let (_, mid, _) = unsafe { bytes[offset..offset+1].align_to::<Chunk>() };
+ let (_, mid, _) = unsafe { bytes[offset..offset + 1].align_to::<Chunk>() };
assert_eq!(mid.as_ptr() as usize % mem::align_of::<Chunk>(), 0);
}
}
diff --git a/src/libcore/tests/str_lossy.rs b/src/libcore/tests/str_lossy.rs
index f9fd333..d4b47a4 100644
--- a/src/libcore/tests/str_lossy.rs
+++ b/src/libcore/tests/str_lossy.rs
@@ -3,65 +3,65 @@
#[test]
fn chunks() {
let mut iter = Utf8Lossy::from_bytes(b"hello").chunks();
- assert_eq!(Some(Utf8LossyChunk { valid: "hello", broken: b"", }), iter.next());
+ assert_eq!(Some(Utf8LossyChunk { valid: "hello", broken: b"" }), iter.next());
assert_eq!(None, iter.next());
let mut iter = Utf8Lossy::from_bytes("ศไทย中华Việt Nam".as_bytes()).chunks();
- assert_eq!(Some(Utf8LossyChunk { valid: "ศไทย中华Việt Nam", broken: b"", }), iter.next());
+ assert_eq!(Some(Utf8LossyChunk { valid: "ศไทย中华Việt Nam", broken: b"" }), iter.next());
assert_eq!(None, iter.next());
let mut iter = Utf8Lossy::from_bytes(b"Hello\xC2 There\xFF Goodbye").chunks();
- assert_eq!(Some(Utf8LossyChunk { valid: "Hello", broken: b"\xC2", }), iter.next());
- assert_eq!(Some(Utf8LossyChunk { valid: " There", broken: b"\xFF", }), iter.next());
- assert_eq!(Some(Utf8LossyChunk { valid: " Goodbye", broken: b"", }), iter.next());
+ assert_eq!(Some(Utf8LossyChunk { valid: "Hello", broken: b"\xC2" }), iter.next());
+ assert_eq!(Some(Utf8LossyChunk { valid: " There", broken: b"\xFF" }), iter.next());
+ assert_eq!(Some(Utf8LossyChunk { valid: " Goodbye", broken: b"" }), iter.next());
assert_eq!(None, iter.next());
let mut iter = Utf8Lossy::from_bytes(b"Hello\xC0\x80 There\xE6\x83 Goodbye").chunks();
- assert_eq!(Some(Utf8LossyChunk { valid: "Hello", broken: b"\xC0", }), iter.next());
- assert_eq!(Some(Utf8LossyChunk { valid: "", broken: b"\x80", }), iter.next());
- assert_eq!(Some(Utf8LossyChunk { valid: " There", broken: b"\xE6\x83", }), iter.next());
- assert_eq!(Some(Utf8LossyChunk { valid: " Goodbye", broken: b"", }), iter.next());
+ assert_eq!(Some(Utf8LossyChunk { valid: "Hello", broken: b"\xC0" }), iter.next());
+ assert_eq!(Some(Utf8LossyChunk { valid: "", broken: b"\x80" }), iter.next());
+ assert_eq!(Some(Utf8LossyChunk { valid: " There", broken: b"\xE6\x83" }), iter.next());
+ assert_eq!(Some(Utf8LossyChunk { valid: " Goodbye", broken: b"" }), iter.next());
assert_eq!(None, iter.next());
let mut iter = Utf8Lossy::from_bytes(b"\xF5foo\xF5\x80bar").chunks();
- assert_eq!(Some(Utf8LossyChunk { valid: "", broken: b"\xF5", }), iter.next());
- assert_eq!(Some(Utf8LossyChunk { valid: "foo", broken: b"\xF5", }), iter.next());
- assert_eq!(Some(Utf8LossyChunk { valid: "", broken: b"\x80", }), iter.next());
- assert_eq!(Some(Utf8LossyChunk { valid: "bar", broken: b"", }), iter.next());
+ assert_eq!(Some(Utf8LossyChunk { valid: "", broken: b"\xF5" }), iter.next());
+ assert_eq!(Some(Utf8LossyChunk { valid: "foo", broken: b"\xF5" }), iter.next());
+ assert_eq!(Some(Utf8LossyChunk { valid: "", broken: b"\x80" }), iter.next());
+ assert_eq!(Some(Utf8LossyChunk { valid: "bar", broken: b"" }), iter.next());
assert_eq!(None, iter.next());
let mut iter = Utf8Lossy::from_bytes(b"\xF1foo\xF1\x80bar\xF1\x80\x80baz").chunks();
- assert_eq!(Some(Utf8LossyChunk { valid: "", broken: b"\xF1", }), iter.next());
- assert_eq!(Some(Utf8LossyChunk { valid: "foo", broken: b"\xF1\x80", }), iter.next());
- assert_eq!(Some(Utf8LossyChunk { valid: "bar", broken: b"\xF1\x80\x80", }), iter.next());
- assert_eq!(Some(Utf8LossyChunk { valid: "baz", broken: b"", }), iter.next());
+ assert_eq!(Some(Utf8LossyChunk { valid: "", broken: b"\xF1" }), iter.next());
+ assert_eq!(Some(Utf8LossyChunk { valid: "foo", broken: b"\xF1\x80" }), iter.next());
+ assert_eq!(Some(Utf8LossyChunk { valid: "bar", broken: b"\xF1\x80\x80" }), iter.next());
+ assert_eq!(Some(Utf8LossyChunk { valid: "baz", broken: b"" }), iter.next());
assert_eq!(None, iter.next());
let mut iter = Utf8Lossy::from_bytes(b"\xF4foo\xF4\x80bar\xF4\xBFbaz").chunks();
- assert_eq!(Some(Utf8LossyChunk { valid: "", broken: b"\xF4", }), iter.next());
- assert_eq!(Some(Utf8LossyChunk { valid: "foo", broken: b"\xF4\x80", }), iter.next());
- assert_eq!(Some(Utf8LossyChunk { valid: "bar", broken: b"\xF4", }), iter.next());
- assert_eq!(Some(Utf8LossyChunk { valid: "", broken: b"\xBF", }), iter.next());
- assert_eq!(Some(Utf8LossyChunk { valid: "baz", broken: b"", }), iter.next());
+ assert_eq!(Some(Utf8LossyChunk { valid: "", broken: b"\xF4" }), iter.next());
+ assert_eq!(Some(Utf8LossyChunk { valid: "foo", broken: b"\xF4\x80" }), iter.next());
+ assert_eq!(Some(Utf8LossyChunk { valid: "bar", broken: b"\xF4" }), iter.next());
+ assert_eq!(Some(Utf8LossyChunk { valid: "", broken: b"\xBF" }), iter.next());
+ assert_eq!(Some(Utf8LossyChunk { valid: "baz", broken: b"" }), iter.next());
assert_eq!(None, iter.next());
let mut iter = Utf8Lossy::from_bytes(b"\xF0\x80\x80\x80foo\xF0\x90\x80\x80bar").chunks();
- assert_eq!(Some(Utf8LossyChunk { valid: "", broken: b"\xF0", }), iter.next());
- assert_eq!(Some(Utf8LossyChunk { valid: "", broken: b"\x80", }), iter.next());
- assert_eq!(Some(Utf8LossyChunk { valid: "", broken: b"\x80", }), iter.next());
- assert_eq!(Some(Utf8LossyChunk { valid: "", broken: b"\x80", }), iter.next());
- assert_eq!(Some(Utf8LossyChunk { valid: "foo\u{10000}bar", broken: b"", }), iter.next());
+ assert_eq!(Some(Utf8LossyChunk { valid: "", broken: b"\xF0" }), iter.next());
+ assert_eq!(Some(Utf8LossyChunk { valid: "", broken: b"\x80" }), iter.next());
+ assert_eq!(Some(Utf8LossyChunk { valid: "", broken: b"\x80" }), iter.next());
+ assert_eq!(Some(Utf8LossyChunk { valid: "", broken: b"\x80" }), iter.next());
+ assert_eq!(Some(Utf8LossyChunk { valid: "foo\u{10000}bar", broken: b"" }), iter.next());
assert_eq!(None, iter.next());
// surrogates
let mut iter = Utf8Lossy::from_bytes(b"\xED\xA0\x80foo\xED\xBF\xBFbar").chunks();
- assert_eq!(Some(Utf8LossyChunk { valid: "", broken: b"\xED", }), iter.next());
- assert_eq!(Some(Utf8LossyChunk { valid: "", broken: b"\xA0", }), iter.next());
- assert_eq!(Some(Utf8LossyChunk { valid: "", broken: b"\x80", }), iter.next());
- assert_eq!(Some(Utf8LossyChunk { valid: "foo", broken: b"\xED", }), iter.next());
- assert_eq!(Some(Utf8LossyChunk { valid: "", broken: b"\xBF", }), iter.next());
- assert_eq!(Some(Utf8LossyChunk { valid: "", broken: b"\xBF", }), iter.next());
- assert_eq!(Some(Utf8LossyChunk { valid: "bar", broken: b"", }), iter.next());
+ assert_eq!(Some(Utf8LossyChunk { valid: "", broken: b"\xED" }), iter.next());
+ assert_eq!(Some(Utf8LossyChunk { valid: "", broken: b"\xA0" }), iter.next());
+ assert_eq!(Some(Utf8LossyChunk { valid: "", broken: b"\x80" }), iter.next());
+ assert_eq!(Some(Utf8LossyChunk { valid: "foo", broken: b"\xED" }), iter.next());
+ assert_eq!(Some(Utf8LossyChunk { valid: "", broken: b"\xBF" }), iter.next());
+ assert_eq!(Some(Utf8LossyChunk { valid: "", broken: b"\xBF" }), iter.next());
+ assert_eq!(Some(Utf8LossyChunk { valid: "bar", broken: b"" }), iter.next());
assert_eq!(None, iter.next());
}
@@ -69,13 +69,17 @@
fn display() {
assert_eq!(
"Hello\u{FFFD}\u{FFFD} There\u{FFFD} Goodbye",
- &Utf8Lossy::from_bytes(b"Hello\xC0\x80 There\xE6\x83 Goodbye").to_string());
+ &Utf8Lossy::from_bytes(b"Hello\xC0\x80 There\xE6\x83 Goodbye").to_string()
+ );
}
#[test]
fn debug() {
assert_eq!(
"\"Hello\\xc0\\x80 There\\xe6\\x83 Goodbye\\u{10d4ea}\"",
- &format!("{:?}", Utf8Lossy::from_bytes(
- b"Hello\xC0\x80 There\xE6\x83 Goodbye\xf4\x8d\x93\xaa")));
+ &format!(
+ "{:?}",
+ Utf8Lossy::from_bytes(b"Hello\xC0\x80 There\xE6\x83 Goodbye\xf4\x8d\x93\xaa")
+ )
+ );
}
diff --git a/src/libcore/tests/time.rs b/src/libcore/tests/time.rs
index fac70c4..273f125 100644
--- a/src/libcore/tests/time.rs
+++ b/src/libcore/tests/time.rs
@@ -3,10 +3,11 @@
#[test]
fn creation() {
assert_ne!(Duration::from_secs(1), Duration::from_secs(0));
- assert_eq!(Duration::from_secs(1) + Duration::from_secs(2),
- Duration::from_secs(3));
- assert_eq!(Duration::from_millis(10) + Duration::from_secs(4),
- Duration::new(4, 10 * 1_000_000));
+ assert_eq!(Duration::from_secs(1) + Duration::from_secs(2), Duration::from_secs(3));
+ assert_eq!(
+ Duration::from_millis(10) + Duration::from_secs(4),
+ Duration::new(4, 10 * 1_000_000)
+ );
assert_eq!(Duration::from_millis(4000), Duration::new(4, 0));
}
@@ -68,29 +69,25 @@
#[test]
fn add() {
- assert_eq!(Duration::new(0, 0) + Duration::new(0, 1),
- Duration::new(0, 1));
- assert_eq!(Duration::new(0, 500_000_000) + Duration::new(0, 500_000_001),
- Duration::new(1, 1));
+ assert_eq!(Duration::new(0, 0) + Duration::new(0, 1), Duration::new(0, 1));
+ assert_eq!(Duration::new(0, 500_000_000) + Duration::new(0, 500_000_001), Duration::new(1, 1));
}
#[test]
fn checked_add() {
- assert_eq!(Duration::new(0, 0).checked_add(Duration::new(0, 1)),
- Some(Duration::new(0, 1)));
- assert_eq!(Duration::new(0, 500_000_000).checked_add(Duration::new(0, 500_000_001)),
- Some(Duration::new(1, 1)));
+ assert_eq!(Duration::new(0, 0).checked_add(Duration::new(0, 1)), Some(Duration::new(0, 1)));
+ assert_eq!(
+ Duration::new(0, 500_000_000).checked_add(Duration::new(0, 500_000_001)),
+ Some(Duration::new(1, 1))
+ );
assert_eq!(Duration::new(1, 0).checked_add(Duration::new(::core::u64::MAX, 0)), None);
}
#[test]
fn sub() {
- assert_eq!(Duration::new(0, 1) - Duration::new(0, 0),
- Duration::new(0, 1));
- assert_eq!(Duration::new(0, 500_000_001) - Duration::new(0, 500_000_000),
- Duration::new(0, 1));
- assert_eq!(Duration::new(1, 0) - Duration::new(0, 1),
- Duration::new(0, 999_999_999));
+ assert_eq!(Duration::new(0, 1) - Duration::new(0, 0), Duration::new(0, 1));
+ assert_eq!(Duration::new(0, 500_000_001) - Duration::new(0, 500_000_000), Duration::new(0, 1));
+ assert_eq!(Duration::new(1, 0) - Duration::new(0, 1), Duration::new(0, 999_999_999));
}
#[test]
@@ -99,8 +96,7 @@
let one_nano = Duration::new(0, 1);
let one_sec = Duration::new(1, 0);
assert_eq!(one_nano.checked_sub(zero), Some(Duration::new(0, 1)));
- assert_eq!(one_sec.checked_sub(one_nano),
- Some(Duration::new(0, 999_999_999)));
+ assert_eq!(one_sec.checked_sub(one_nano), Some(Duration::new(0, 999_999_999)));
assert_eq!(zero.checked_sub(one_nano), None);
assert_eq!(zero.checked_sub(one_sec), None);
}
@@ -122,8 +118,7 @@
assert_eq!(Duration::new(0, 1) * 2, Duration::new(0, 2));
assert_eq!(Duration::new(1, 1) * 3, Duration::new(3, 3));
assert_eq!(Duration::new(0, 500_000_001) * 4, Duration::new(2, 4));
- assert_eq!(Duration::new(0, 500_000_001) * 4000,
- Duration::new(2000, 4000));
+ assert_eq!(Duration::new(0, 500_000_001) * 4000, Duration::new(2000, 4000));
}
#[test]
@@ -131,8 +126,7 @@
assert_eq!(Duration::new(0, 1).checked_mul(2), Some(Duration::new(0, 2)));
assert_eq!(Duration::new(1, 1).checked_mul(3), Some(Duration::new(3, 3)));
assert_eq!(Duration::new(0, 500_000_001).checked_mul(4), Some(Duration::new(2, 4)));
- assert_eq!(Duration::new(0, 500_000_001).checked_mul(4000),
- Some(Duration::new(2000, 4000)));
+ assert_eq!(Duration::new(0, 500_000_001).checked_mul(4000), Some(Duration::new(2000, 4000)));
assert_eq!(Duration::new(::core::u64::MAX - 1, 0).checked_mul(2), None);
}
@@ -140,8 +134,7 @@
fn div() {
assert_eq!(Duration::new(0, 1) / 2, Duration::new(0, 0));
assert_eq!(Duration::new(1, 1) / 3, Duration::new(0, 333_333_333));
- assert_eq!(Duration::new(99, 999_999_000) / 100,
- Duration::new(0, 999_999_990));
+ assert_eq!(Duration::new(99, 999_999_000) / 100, Duration::new(0, 999_999_990));
}
#[test]
@@ -162,7 +155,7 @@
Duration::new(5, 0),
];
let sum = durations.iter().sum::<Duration>();
- assert_eq!(sum, Duration::new(1+2+5+4, 1_000_000_000 - 5));
+ assert_eq!(sum, Duration::new(1 + 2 + 5 + 4, 1_000_000_000 - 5));
}
#[test]
@@ -286,9 +279,9 @@
#[test]
fn debug_formatting_precision_high() {
- assert_eq!(format!("{:.5?}", Duration::new(0, 23_678)), "23.67800µs");
+ assert_eq!(format!("{:.5?}", Duration::new(0, 23_678)), "23.67800µs");
- assert_eq!(format!("{:.9?}", Duration::new(1, 000_000_000)), "1.000000000s");
+ assert_eq!(format!("{:.9?}", Duration::new(1, 000_000_000)), "1.000000000s");
assert_eq!(format!("{:.10?}", Duration::new(4, 001_000_000)), "4.0010000000s");
assert_eq!(format!("{:.20?}", Duration::new(4, 001_000_000)), "4.00100000000000000000s");
}
diff --git a/src/libcore/tests/tuple.rs b/src/libcore/tests/tuple.rs
index c7ed161..3a29146 100644
--- a/src/libcore/tests/tuple.rs
+++ b/src/libcore/tests/tuple.rs
@@ -1,4 +1,4 @@
-use std::cmp::Ordering::{Equal, Less, Greater};
+use std::cmp::Ordering::{Equal, Greater, Less};
use std::f64::NAN;
#[test]
diff --git a/src/libfmt_macros/lib.rs b/src/libfmt_macros/lib.rs
index 900c6ed..2ecbe77 100644
--- a/src/libfmt_macros/lib.rs
+++ b/src/libfmt_macros/lib.rs
@@ -11,6 +11,7 @@
#![feature(nll)]
#![feature(rustc_private)]
#![feature(unicode_internals)]
+#![feature(bool_to_option)]
pub use Piece::*;
pub use Position::*;
@@ -644,11 +645,7 @@
break;
}
}
- if found {
- Some(cur)
- } else {
- None
- }
+ found.then_some(cur)
}
}
diff --git a/src/librustc/Cargo.toml b/src/librustc/Cargo.toml
index f8ad6f8..a4536bb 100644
--- a/src/librustc/Cargo.toml
+++ b/src/librustc/Cargo.toml
@@ -20,7 +20,7 @@
log = { version = "0.4", features = ["release_max_level_info", "std"] }
rustc-rayon = "0.3.0"
rustc-rayon-core = "0.3.0"
-polonius-engine = "0.10.0"
+polonius-engine = "0.11.0"
rustc_apfloat = { path = "../librustc_apfloat" }
rustc_feature = { path = "../librustc_feature" }
rustc_target = { path = "../librustc_target" }
@@ -37,6 +37,6 @@
chalk-engine = { version = "0.9.0", default-features=false }
rustc_fs_util = { path = "../librustc_fs_util" }
smallvec = { version = "1.0", features = ["union", "may_dangle"] }
-measureme = "0.4"
+measureme = "0.5"
rustc_error_codes = { path = "../librustc_error_codes" }
rustc_session = { path = "../librustc_session" }
diff --git a/src/librustc/arena.rs b/src/librustc/arena.rs
index 364a35f..eb7a170 100644
--- a/src/librustc/arena.rs
+++ b/src/librustc/arena.rs
@@ -23,17 +23,17 @@
[] generics: rustc::ty::Generics,
[] trait_def: rustc::ty::TraitDef,
[] adt_def: rustc::ty::AdtDef,
- [] steal_mir: rustc::ty::steal::Steal<rustc::mir::BodyCache<$tcx>>,
- [] mir: rustc::mir::BodyCache<$tcx>,
+ [] steal_mir: rustc::ty::steal::Steal<rustc::mir::BodyAndCache<$tcx>>,
+ [] mir: rustc::mir::BodyAndCache<$tcx>,
[] steal_promoted: rustc::ty::steal::Steal<
rustc_index::vec::IndexVec<
rustc::mir::Promoted,
- rustc::mir::BodyCache<$tcx>
+ rustc::mir::BodyAndCache<$tcx>
>
>,
[] promoted: rustc_index::vec::IndexVec<
rustc::mir::Promoted,
- rustc::mir::BodyCache<$tcx>
+ rustc::mir::BodyAndCache<$tcx>
>,
[] tables: rustc::ty::TypeckTables<$tcx>,
[] const_allocs: rustc::mir::interpret::Allocation,
diff --git a/src/librustc/dep_graph/graph.rs b/src/librustc/dep_graph/graph.rs
index 0104507..d952bf7 100644
--- a/src/librustc/dep_graph/graph.rs
+++ b/src/librustc/dep_graph/graph.rs
@@ -710,14 +710,25 @@
return None
}
None => {
- if !tcx.sess.has_errors() {
+ if !tcx.sess.has_errors_or_delayed_span_bugs() {
bug!("try_mark_previous_green() - Forcing the DepNode \
should have set its color")
} else {
- // If the query we just forced has resulted
- // in some kind of compilation error, we
- // don't expect that the corresponding
- // dep-node color has been updated.
+ // If the query we just forced has resulted in
+ // some kind of compilation error, we cannot rely on
+ // the dep-node color having been properly updated.
+ // This means that the query system has reached an
+ // invalid state. We let the compiler continue (by
+ // returning `None`) so it can emit error messages
+ // and wind down, but rely on the fact that this
+ // invalid state will not be persisted to the
+ // incremental compilation cache because of
+ // compilation errors being present.
+ debug!("try_mark_previous_green({:?}) - END - \
+ dependency {:?} resulted in compilation error",
+ dep_node,
+ dep_dep_node);
+ return None
}
}
}
diff --git a/src/librustc/hir/map/blocks.rs b/src/librustc/hir/map/blocks.rs
index f25f3b5..8f9f398 100644
--- a/src/librustc/hir/map/blocks.rs
+++ b/src/librustc/hir/map/blocks.rs
@@ -147,13 +147,7 @@
map::Node::Expr(e) => e.is_fn_like(),
_ => false
};
- if fn_like {
- Some(FnLikeNode {
- node,
- })
- } else {
- None
- }
+ fn_like.then_some(FnLikeNode { node })
}
pub fn body(self) -> ast::BodyId {
diff --git a/src/librustc/infer/error_reporting/mod.rs b/src/librustc/infer/error_reporting/mod.rs
index 5a940f2..c9d5770 100644
--- a/src/librustc/infer/error_reporting/mod.rs
+++ b/src/librustc/infer/error_reporting/mod.rs
@@ -70,6 +70,7 @@
mod note;
mod need_type_info;
+pub use need_type_info::TypeAnnotationNeeded;
pub mod nice_region_error;
@@ -1809,12 +1810,17 @@
sub_region,
"...",
);
- err.note(&format!(
- "...so that the {}:\nexpected {}\n found {}",
- sup_trace.cause.as_requirement_str(),
- sup_expected.content(),
- sup_found.content()
+ err.span_note(sup_trace.cause.span, &format!(
+ "...so that the {}",
+ sup_trace.cause.as_requirement_str()
));
+
+ err.note_expected_found(
+ &"",
+ sup_expected,
+ &"",
+ sup_found
+ );
err.emit();
return;
}
diff --git a/src/librustc/infer/error_reporting/need_type_info.rs b/src/librustc/infer/error_reporting/need_type_info.rs
index 32eecdf..8878683 100644
--- a/src/librustc/infer/error_reporting/need_type_info.rs
+++ b/src/librustc/infer/error_reporting/need_type_info.rs
@@ -1,4 +1,4 @@
-use crate::hir::def::Namespace;
+use crate::hir::def::{DefKind, Namespace};
use crate::hir::{self, Body, FunctionRetTy, Expr, ExprKind, HirId, Local, Pat};
use crate::hir::intravisit::{self, Visitor, NestedVisitorMap};
use crate::infer::InferCtxt;
@@ -6,8 +6,10 @@
use crate::ty::{self, Ty, Infer, TyVar};
use crate::ty::print::Print;
use syntax::source_map::DesugaringKind;
+use syntax::symbol::kw;
use syntax_pos::Span;
use errors::{Applicability, DiagnosticBuilder};
+use std::borrow::Cow;
use rustc_error_codes::*;
@@ -19,6 +21,7 @@
found_arg_pattern: Option<&'tcx Pat>,
found_ty: Option<Ty<'tcx>>,
found_closure: Option<&'tcx ExprKind>,
+ found_method_call: Option<&'tcx Expr>,
}
impl<'a, 'tcx> FindLocalByTypeVisitor<'a, 'tcx> {
@@ -35,6 +38,7 @@
found_arg_pattern: None,
found_ty: None,
found_closure: None,
+ found_method_call: None,
}
}
@@ -93,11 +97,12 @@
}
fn visit_expr(&mut self, expr: &'tcx Expr) {
- if let (ExprKind::Closure(_, _fn_decl, _id, _sp, _), Some(_)) = (
- &expr.kind,
- self.node_matches_type(expr.hir_id),
- ) {
- self.found_closure = Some(&expr.kind);
+ if self.node_matches_type(expr.hir_id).is_some() {
+ match expr.kind {
+ ExprKind::Closure(..) => self.found_closure = Some(&expr.kind),
+ ExprKind::MethodCall(..) => self.found_method_call = Some(&expr),
+ _ => {}
+ }
}
intravisit::walk_expr(self, expr);
}
@@ -109,6 +114,7 @@
err: &mut DiagnosticBuilder<'_>,
output: &FunctionRetTy,
body: &Body,
+ descr: &str,
name: &str,
ret: &str,
) {
@@ -132,7 +138,7 @@
suggestion,
Applicability::HasPlaceholders,
);
- err.span_label(span, InferCtxt::missing_type_msg(&name));
+ err.span_label(span, InferCtxt::missing_type_msg(&name, &descr));
}
/// Given a closure signature, return a `String` containing a list of all its argument types.
@@ -147,17 +153,42 @@
.unwrap_or_default()
}
+pub enum TypeAnnotationNeeded {
+ E0282,
+ E0283,
+ E0284,
+}
+
+impl Into<errors::DiagnosticId> for TypeAnnotationNeeded {
+ fn into(self) -> errors::DiagnosticId {
+ syntax::diagnostic_used!(E0282);
+ syntax::diagnostic_used!(E0283);
+ syntax::diagnostic_used!(E0284);
+ errors::DiagnosticId::Error(match self {
+ Self::E0282 => "E0282".to_string(),
+ Self::E0283 => "E0283".to_string(),
+ Self::E0284 => "E0284".to_string(),
+ })
+ }
+}
+
impl<'a, 'tcx> InferCtxt<'a, 'tcx> {
pub fn extract_type_name(
&self,
ty: Ty<'tcx>,
highlight: Option<ty::print::RegionHighlightMode>,
- ) -> (String, Option<Span>) {
+ ) -> (String, Option<Span>, Cow<'static, str>) {
if let ty::Infer(ty::TyVar(ty_vid)) = ty.kind {
let ty_vars = self.type_variables.borrow();
let var_origin = ty_vars.var_origin(ty_vid);
if let TypeVariableOriginKind::TypeParameterDefinition(name) = var_origin.kind {
- return (name.to_string(), Some(var_origin.span));
+ if name != kw::SelfUpper {
+ return (
+ name.to_string(),
+ Some(var_origin.span),
+ "type parameter".into(),
+ );
+ }
}
}
@@ -167,7 +198,7 @@
printer.region_highlight_mode = highlight;
}
let _ = ty.print(printer);
- (s, None)
+ (s, None, ty.prefix_string())
}
pub fn need_type_info_err(
@@ -175,9 +206,10 @@
body_id: Option<hir::BodyId>,
span: Span,
ty: Ty<'tcx>,
+ error_code: TypeAnnotationNeeded,
) -> DiagnosticBuilder<'tcx> {
let ty = self.resolve_vars_if_possible(&ty);
- let (name, name_sp) = self.extract_type_name(&ty, None);
+ let (name, name_sp, descr) = self.extract_type_name(&ty, None);
let mut local_visitor = FindLocalByTypeVisitor::new(&self, ty, &self.tcx.hir());
let ty_to_string = |ty: Ty<'tcx>| -> String {
@@ -185,8 +217,8 @@
let mut printer = ty::print::FmtPrinter::new(self.tcx, &mut s, Namespace::TypeNS);
let ty_vars = self.type_variables.borrow();
let getter = move |ty_vid| {
- if let TypeVariableOriginKind::TypeParameterDefinition(name) =
- ty_vars.var_origin(ty_vid).kind {
+ let var_origin = ty_vars.var_origin(ty_vid);
+ if let TypeVariableOriginKind::TypeParameterDefinition(name) = var_origin.kind {
return Some(name.to_string());
}
None
@@ -210,6 +242,22 @@
// 3 | let _ = x.sum() as f64;
// | ^^^ cannot infer type for `S`
span
+ } else if let Some(
+ ExprKind::MethodCall(_, call_span, _),
+ ) = local_visitor.found_method_call.map(|e| &e.kind) {
+ // Point at the call instead of the whole expression:
+ // error[E0284]: type annotations needed
+ // --> file.rs:2:5
+ // |
+ // 2 | vec![Ok(2)].into_iter().collect()?;
+ // | ^^^^^^^ cannot infer type
+ // |
+ // = note: cannot resolve `<_ as std::ops::Try>::Ok == _`
+ if span.contains(*call_span) {
+ *call_span
+ } else {
+ span
+ }
} else {
span
};
@@ -247,12 +295,11 @@
// | consider giving `b` the explicit type `std::result::Result<i32, E>`, where
// | the type parameter `E` is specified
// ```
- let mut err = struct_span_err!(
- self.tcx.sess,
+ let error_code = error_code.into();
+ let mut err = self.tcx.sess.struct_span_err_with_code(
err_span,
- E0282,
- "type annotations needed{}",
- ty_msg,
+ &format!("type annotations needed{}", ty_msg),
+ error_code,
);
let suffix = match local_visitor.found_ty {
@@ -267,6 +314,7 @@
&mut err,
&decl.output,
&body,
+ &descr,
&name,
&ret,
);
@@ -334,6 +382,36 @@
format!("consider giving this pattern {}", suffix)
};
err.span_label(pattern.span, msg);
+ } else if let Some(e) = local_visitor.found_method_call {
+ if let ExprKind::MethodCall(segment, ..) = &e.kind {
+ // Suggest specifiying type params or point out the return type of the call:
+ //
+ // error[E0282]: type annotations needed
+ // --> $DIR/type-annotations-needed-expr.rs:2:39
+ // |
+ // LL | let _ = x.into_iter().sum() as f64;
+ // | ^^^
+ // | |
+ // | cannot infer type for `S`
+ // | help: consider specifying the type argument in
+ // | the method call: `sum::<S>`
+ // |
+ // = note: type must be known at this point
+ //
+ // or
+ //
+ // error[E0282]: type annotations needed
+ // --> $DIR/issue-65611.rs:59:20
+ // |
+ // LL | let x = buffer.last().unwrap().0.clone();
+ // | -------^^^^--
+ // | | |
+ // | | cannot infer type for `T`
+ // | this method call resolves to `std::option::Option<&T>`
+ // |
+ // = note: type must be known at this point
+ self.annotate_method_call(segment, e, &mut err);
+ }
}
// Instead of the following:
// error[E0282]: type annotations needed
@@ -351,17 +429,66 @@
// | ^^^ cannot infer type for `S`
// |
// = note: type must be known at this point
- let span = name_sp.unwrap_or(span);
+ let span = name_sp.unwrap_or(err_span);
if !err.span.span_labels().iter().any(|span_label| {
span_label.label.is_some() && span_label.span == span
}) && local_visitor.found_arg_pattern.is_none()
{ // Avoid multiple labels pointing at `span`.
- err.span_label(span, InferCtxt::missing_type_msg(&name));
+ err.span_label(span, InferCtxt::missing_type_msg(&name, &descr));
}
err
}
+ /// If the `FnSig` for the method call can be found and type arguments are identified as
+ /// needed, suggest annotating the call, otherwise point out the resulting type of the call.
+ fn annotate_method_call(
+ &self,
+ segment: &hir::ptr::P<hir::PathSegment>,
+ e: &Expr,
+ err: &mut DiagnosticBuilder<'_>,
+ ) {
+ if let (Ok(snippet), Some(tables), None) = (
+ self.tcx.sess.source_map().span_to_snippet(segment.ident.span),
+ self.in_progress_tables,
+ &segment.args,
+ ) {
+ let borrow = tables.borrow();
+ if let Some((DefKind::Method, did)) = borrow.type_dependent_def(e.hir_id) {
+ let generics = self.tcx.generics_of(did);
+ if !generics.params.is_empty() {
+ err.span_suggestion(
+ segment.ident.span,
+ &format!(
+ "consider specifying the type argument{} in the method call",
+ if generics.params.len() > 1 {
+ "s"
+ } else {
+ ""
+ },
+ ),
+ format!("{}::<{}>", snippet, generics.params.iter()
+ .map(|p| p.name.to_string())
+ .collect::<Vec<String>>()
+ .join(", ")),
+ Applicability::HasPlaceholders,
+ );
+ } else {
+ let sig = self.tcx.fn_sig(did);
+ let bound_output = sig.output();
+ let output = bound_output.skip_binder();
+ err.span_label(e.span, &format!("this method call resolves to `{:?}`", output));
+ let kind = &output.kind;
+ if let ty::Projection(proj) | ty::UnnormalizedProjection(proj) = kind {
+ if let Some(span) = self.tcx.hir().span_if_local(proj.item_def_id) {
+ err.span_label(span, &format!("`{:?}` defined here", output));
+ }
+ }
+ }
+ }
+ }
+ }
+
pub fn need_type_info_err_in_generator(
&self,
kind: hir::GeneratorKind,
@@ -369,19 +496,19 @@
ty: Ty<'tcx>,
) -> DiagnosticBuilder<'tcx> {
let ty = self.resolve_vars_if_possible(&ty);
- let name = self.extract_type_name(&ty, None).0;
+ let (name, _, descr) = self.extract_type_name(&ty, None);
let mut err = struct_span_err!(
self.tcx.sess, span, E0698, "type inside {} must be known in this context", kind,
);
- err.span_label(span, InferCtxt::missing_type_msg(&name));
+ err.span_label(span, InferCtxt::missing_type_msg(&name, &descr));
err
}
- fn missing_type_msg(type_name: &str) -> String {
+ fn missing_type_msg(type_name: &str, descr: &str) -> Cow<'static, str>{
if type_name == "_" {
- "cannot infer type".to_owned()
+ "cannot infer type".into()
} else {
- format!("cannot infer type for `{}`", type_name)
+ format!("cannot infer type for {} `{}`", descr, type_name).into()
}
}
}
diff --git a/src/librustc/infer/error_reporting/note.rs b/src/librustc/infer/error_reporting/note.rs
index c1f840a..4b93373 100644
--- a/src/librustc/infer/error_reporting/note.rs
+++ b/src/librustc/infer/error_reporting/note.rs
@@ -13,12 +13,20 @@
match *origin {
infer::Subtype(ref trace) => {
if let Some((expected, found)) = self.values_str(&trace.values) {
- let expected = expected.content();
- let found = found.content();
- err.note(&format!("...so that the {}:\nexpected {}\n found {}",
- trace.cause.as_requirement_str(),
- expected,
- found));
+ err.span_note(
+ trace.cause.span,
+ &format!(
+ "...so that the {}",
+ trace.cause.as_requirement_str()
+ )
+ );
+
+ err.note_expected_found(
+ &"",
+ expected,
+ &"",
+ found
+ );
} else {
// FIXME: this really should be handled at some earlier stage. Our
// handling of region checking when type errors are present is
diff --git a/src/librustc/infer/mod.rs b/src/librustc/infer/mod.rs
index b3ddffc..73977878 100644
--- a/src/librustc/infer/mod.rs
+++ b/src/librustc/infer/mod.rs
@@ -1618,37 +1618,37 @@
// inlined, despite being large, because it has only two call sites that
// are extremely hot.
#[inline(always)]
- pub fn shallow_resolve_changed(&mut self, typ: Ty<'tcx>) -> bool {
- match typ.kind {
- ty::Infer(ty::TyVar(v)) => {
+ pub fn shallow_resolve_changed(&self, infer: ty::InferTy) -> bool {
+ match infer {
+ ty::TyVar(v) => {
use self::type_variable::TypeVariableValue;
- // See the comment in `shallow_resolve()`.
+ // If `inlined_probe` returns a `Known` value its `kind` never
+ // matches `infer`.
match self.infcx.type_variables.borrow_mut().inlined_probe(v) {
- TypeVariableValue::Known { value: t } => self.fold_ty(t) != typ,
TypeVariableValue::Unknown { .. } => false,
+ TypeVariableValue::Known { .. } => true,
}
}
- ty::Infer(ty::IntVar(v)) => {
- match self.infcx.int_unification_table.borrow_mut().inlined_probe_value(v) {
- Some(v) => v.to_type(self.infcx.tcx) != typ,
- None => false,
- }
+ ty::IntVar(v) => {
+ // If inlined_probe_value returns a value it's always a
+ // `ty::Int(_)` or `ty::UInt(_)`, which nevers matches a
+ // `ty::Infer(_)`.
+ self.infcx.int_unification_table.borrow_mut().inlined_probe_value(v).is_some()
}
- ty::Infer(ty::FloatVar(v)) => {
+ ty::FloatVar(v) => {
+ // If inlined_probe_value returns a value it's always a
+ // `ty::Float(_)`, which nevers matches a `ty::Infer(_)`.
+ //
// Not `inlined_probe_value(v)` because this call site is colder.
- match self.infcx.float_unification_table.borrow_mut().probe_value(v) {
- Some(v) => v.to_type(self.infcx.tcx) != typ,
- None => false,
- }
+ self.infcx.float_unification_table.borrow_mut().probe_value(v).is_some()
}
- _ => false,
+ _ => unreachable!(),
}
}
-
}
impl<'a, 'tcx> TypeFolder<'tcx> for ShallowResolver<'a, 'tcx> {
diff --git a/src/librustc/infer/outlives/verify.rs b/src/librustc/infer/outlives/verify.rs
index 3110b02..3e28145 100644
--- a/src/librustc/infer/outlives/verify.rs
+++ b/src/librustc/infer/outlives/verify.rs
@@ -211,11 +211,7 @@
(r, p)
);
let p_ty = p.to_ty(tcx);
- if compare_ty(p_ty) {
- Some(ty::OutlivesPredicate(p_ty, r))
- } else {
- None
- }
+ compare_ty(p_ty).then_some(ty::OutlivesPredicate(p_ty, r))
});
param_bounds
diff --git a/src/librustc/lib.rs b/src/librustc/lib.rs
index e708c5a..24b87ff 100644
--- a/src/librustc/lib.rs
+++ b/src/librustc/lib.rs
@@ -29,6 +29,7 @@
#![doc(html_root_url = "https://doc.rust-lang.org/nightly/")]
#![feature(arbitrary_self_types)]
+#![feature(bool_to_option)]
#![feature(box_patterns)]
#![feature(box_syntax)]
#![feature(const_fn)]
diff --git a/src/librustc/lint/builtin.rs b/src/librustc/lint/builtin.rs
index 1aba73e..c4bc977 100644
--- a/src/librustc/lint/builtin.rs
+++ b/src/librustc/lint/builtin.rs
@@ -329,7 +329,7 @@
declare_lint! {
pub UNUSED_LABELS,
- Allow,
+ Warn,
"detects labels that are never used"
}
diff --git a/src/librustc/mir/cache.rs b/src/librustc/mir/cache.rs
index 95e9f09..0704771 100644
--- a/src/librustc/mir/cache.rs
+++ b/src/librustc/mir/cache.rs
@@ -115,16 +115,16 @@
}
#[derive(Clone, Debug, HashStable, RustcEncodable, RustcDecodable, TypeFoldable)]
-pub struct BodyCache<'tcx> {
- cache: Cache,
+pub struct BodyAndCache<'tcx> {
body: Body<'tcx>,
+ cache: Cache,
}
-impl BodyCache<'tcx> {
+impl BodyAndCache<'tcx> {
pub fn new(body: Body<'tcx>) -> Self {
Self {
- cache: Cache::new(),
body,
+ cache: Cache::new(),
}
}
}
@@ -139,7 +139,7 @@
};
}
-impl BodyCache<'tcx> {
+impl BodyAndCache<'tcx> {
pub fn ensure_predecessors(&mut self) {
self.cache.ensure_predecessors(&self.body);
}
@@ -148,8 +148,8 @@
self.cache.predecessors(&self.body)
}
- pub fn unwrap_read_only(&self) -> ReadOnlyBodyCache<'_, 'tcx> {
- ReadOnlyBodyCache::new(&self.cache, &self.body)
+ pub fn unwrap_read_only(&self) -> ReadOnlyBodyAndCache<'_, 'tcx> {
+ ReadOnlyBodyAndCache::new(&self.body, &self.cache)
}
pub fn basic_blocks_mut(&mut self) -> &mut IndexVec<BasicBlock, BasicBlockData<'tcx>> {
@@ -163,7 +163,7 @@
}
}
-impl<'tcx> Index<BasicBlock> for BodyCache<'tcx> {
+impl<'tcx> Index<BasicBlock> for BodyAndCache<'tcx> {
type Output = BasicBlockData<'tcx>;
fn index(&self, index: BasicBlock) -> &BasicBlockData<'tcx> {
@@ -171,13 +171,13 @@
}
}
-impl<'tcx> IndexMut<BasicBlock> for BodyCache<'tcx> {
+impl<'tcx> IndexMut<BasicBlock> for BodyAndCache<'tcx> {
fn index_mut(&mut self, index: BasicBlock) -> &mut Self::Output {
&mut self.basic_blocks_mut()[index]
}
}
-impl<'tcx> Deref for BodyCache<'tcx> {
+impl<'tcx> Deref for BodyAndCache<'tcx> {
type Target = Body<'tcx>;
fn deref(&self) -> &Self::Target {
@@ -185,26 +185,26 @@
}
}
-impl<'tcx> DerefMut for BodyCache<'tcx> {
+impl<'tcx> DerefMut for BodyAndCache<'tcx> {
fn deref_mut(&mut self) -> &mut Self::Target {
&mut self.body
}
}
#[derive(Copy, Clone, Debug)]
-pub struct ReadOnlyBodyCache<'a, 'tcx> {
- cache: &'a Cache,
+pub struct ReadOnlyBodyAndCache<'a, 'tcx> {
body: &'a Body<'tcx>,
+ cache: &'a Cache,
}
-impl ReadOnlyBodyCache<'a, 'tcx> {
- fn new(cache: &'a Cache, body: &'a Body<'tcx>) -> Self {
+impl ReadOnlyBodyAndCache<'a, 'tcx> {
+ fn new(body: &'a Body<'tcx>, cache: &'a Cache) -> Self {
assert!(
cache.predecessors.is_some(),
- "Cannot construct ReadOnlyBodyCache without computed predecessors");
+ "Cannot construct ReadOnlyBodyAndCache without computed predecessors");
Self {
- cache,
body,
+ cache,
}
}
@@ -220,10 +220,6 @@
self.cache.unwrap_predecessor_locations(loc, self.body)
}
- pub fn body(&self) -> &'a Body<'tcx> {
- self.body
- }
-
pub fn basic_blocks(&self) -> &IndexVec<BasicBlock, BasicBlockData<'tcx>> {
&self.body.basic_blocks
}
@@ -233,16 +229,16 @@
}
}
-impl graph::DirectedGraph for ReadOnlyBodyCache<'a, 'tcx> {
+impl graph::DirectedGraph for ReadOnlyBodyAndCache<'a, 'tcx> {
type Node = BasicBlock;
}
-impl graph::GraphPredecessors<'graph> for ReadOnlyBodyCache<'a, 'tcx> {
+impl graph::GraphPredecessors<'graph> for ReadOnlyBodyAndCache<'a, 'tcx> {
type Item = BasicBlock;
type Iter = IntoIter<BasicBlock>;
}
-impl graph::WithPredecessors for ReadOnlyBodyCache<'a, 'tcx> {
+impl graph::WithPredecessors for ReadOnlyBodyAndCache<'a, 'tcx> {
fn predecessors(
&self,
node: Self::Node,
@@ -251,19 +247,19 @@
}
}
-impl graph::WithNumNodes for ReadOnlyBodyCache<'a, 'tcx> {
+impl graph::WithNumNodes for ReadOnlyBodyAndCache<'a, 'tcx> {
fn num_nodes(&self) -> usize {
self.body.num_nodes()
}
}
-impl graph::WithStartNode for ReadOnlyBodyCache<'a, 'tcx> {
+impl graph::WithStartNode for ReadOnlyBodyAndCache<'a, 'tcx> {
fn start_node(&self) -> Self::Node {
self.body.start_node()
}
}
-impl graph::WithSuccessors for ReadOnlyBodyCache<'a, 'tcx> {
+impl graph::WithSuccessors for ReadOnlyBodyAndCache<'a, 'tcx> {
fn successors(
&self,
node: Self::Node,
@@ -272,13 +268,13 @@
}
}
-impl<'a, 'b, 'tcx> graph::GraphSuccessors<'b> for ReadOnlyBodyCache<'a, 'tcx> {
+impl<'a, 'b, 'tcx> graph::GraphSuccessors<'b> for ReadOnlyBodyAndCache<'a, 'tcx> {
type Item = BasicBlock;
type Iter = iter::Cloned<Successors<'b>>;
}
-impl Deref for ReadOnlyBodyCache<'a, 'tcx> {
+impl Deref for ReadOnlyBodyAndCache<'a, 'tcx> {
type Target = &'a Body<'tcx>;
fn deref(&self) -> &Self::Target {
diff --git a/src/librustc/mir/interpret/error.rs b/src/librustc/mir/interpret/error.rs
index 5573106..0dec7c0 100644
--- a/src/librustc/mir/interpret/error.rs
+++ b/src/librustc/mir/interpret/error.rs
@@ -370,6 +370,14 @@
Unreachable,
/// An enum discriminant was set to a value which was outside the range of valid values.
InvalidDiscriminant(ScalarMaybeUndef),
+ /// A slice/array index projection went out-of-bounds.
+ BoundsCheckFailed { len: u64, index: u64 },
+ /// Something was divided by 0 (x / 0).
+ DivisionByZero,
+ /// Something was "remainded" by 0 (x % 0).
+ RemainderByZero,
+ /// Overflowing inbounds pointer arithmetic.
+ PointerArithOverflow,
}
impl fmt::Debug for UndefinedBehaviorInfo {
@@ -379,9 +387,18 @@
Ub(msg) | UbExperimental(msg) =>
write!(f, "{}", msg),
Unreachable =>
- write!(f, "entered unreachable code"),
+ write!(f, "entering unreachable code"),
InvalidDiscriminant(val) =>
- write!(f, "encountered invalid enum discriminant {}", val),
+ write!(f, "encountering invalid enum discriminant {}", val),
+ BoundsCheckFailed { ref len, ref index } =>
+ write!(f, "indexing out of bounds: the len is {:?} but the index is {:?}",
+ len, index),
+ DivisionByZero =>
+ write!(f, "dividing by zero"),
+ RemainderByZero =>
+ write!(f, "calculating the remainder with a divisor of zero"),
+ PointerArithOverflow =>
+ write!(f, "overflowing in-bounds pointer arithmetic"),
}
}
}
diff --git a/src/librustc/mir/interpret/pointer.rs b/src/librustc/mir/interpret/pointer.rs
index 78320c7..0b27f51 100644
--- a/src/librustc/mir/interpret/pointer.rs
+++ b/src/librustc/mir/interpret/pointer.rs
@@ -1,6 +1,5 @@
use super::{AllocId, InterpResult};
-use crate::mir;
use crate::ty::layout::{self, HasDataLayout, Size};
use rustc_macros::HashStable;
@@ -88,13 +87,13 @@
#[inline]
fn offset<'tcx>(&self, val: u64, i: u64) -> InterpResult<'tcx, u64> {
let (res, over) = self.overflowing_offset(val, i);
- if over { throw_panic!(Overflow(mir::BinOp::Add)) } else { Ok(res) }
+ if over { throw_ub!(PointerArithOverflow) } else { Ok(res) }
}
#[inline]
fn signed_offset<'tcx>(&self, val: u64, i: i64) -> InterpResult<'tcx, u64> {
let (res, over) = self.overflowing_signed_offset(val, i128::from(i));
- if over { throw_panic!(Overflow(mir::BinOp::Add)) } else { Ok(res) }
+ if over { throw_ub!(PointerArithOverflow) } else { Ok(res) }
}
}
diff --git a/src/librustc/mir/mod.rs b/src/librustc/mir/mod.rs
index df5d499..ba8feb4 100644
--- a/src/librustc/mir/mod.rs
+++ b/src/librustc/mir/mod.rs
@@ -38,7 +38,7 @@
use syntax_pos::{Span, DUMMY_SP};
pub use crate::mir::interpret::AssertMessage;
-pub use crate::mir::cache::{BodyCache, ReadOnlyBodyCache};
+pub use crate::mir::cache::{BodyAndCache, ReadOnlyBodyAndCache};
pub use crate::read_only;
mod cache;
@@ -108,7 +108,7 @@
pub yield_ty: Option<Ty<'tcx>>,
/// Generator drop glue.
- pub generator_drop: Option<Box<BodyCache<'tcx>>>,
+ pub generator_drop: Option<Box<BodyAndCache<'tcx>>>,
/// The layout of a generator. Produced by the state transformation.
pub generator_layout: Option<GeneratorLayout<'tcx>>,
@@ -242,11 +242,7 @@
pub fn vars_iter<'a>(&'a self) -> impl Iterator<Item = Local> + 'a {
(self.arg_count + 1..self.local_decls.len()).filter_map(move |index| {
let local = Local::new(index);
- if self.local_decls[local].is_user_variable() {
- Some(local)
- } else {
- None
- }
+ self.local_decls[local].is_user_variable().then_some(local)
})
}
@@ -282,15 +278,15 @@
/// Returns an iterator over all function arguments.
#[inline]
- pub fn args_iter(&self) -> impl Iterator<Item = Local> {
+ pub fn args_iter(&self) -> impl Iterator<Item = Local> + ExactSizeIterator {
let arg_count = self.arg_count;
- (1..=arg_count).map(Local::new)
+ (1..arg_count + 1).map(Local::new)
}
/// Returns an iterator over all user-defined variables and compiler-generated temporaries (all
/// locals that are neither arguments nor the return place).
#[inline]
- pub fn vars_and_temps_iter(&self) -> impl Iterator<Item = Local> {
+ pub fn vars_and_temps_iter(&self) -> impl Iterator<Item = Local> + ExactSizeIterator {
let arg_count = self.arg_count;
let local_count = self.local_decls.len();
(arg_count + 1..local_count).map(Local::new)
@@ -1718,18 +1714,25 @@
ConstantIndex {
/// index or -index (in Python terms), depending on from_end
offset: u32,
- /// thing being indexed must be at least this long
+ /// The thing being indexed must be at least this long. For arrays this
+ /// is always the exact length.
min_length: u32,
- /// counting backwards from end?
+ /// Counting backwards from end? This is always false when indexing an
+ /// array.
from_end: bool,
},
/// These indices are generated by slice patterns.
///
- /// slice[from:-to] in Python terms.
+ /// If `from_end` is true `slice[from..slice.len() - to]`.
+ /// Otherwise `array[from..to]`.
Subslice {
from: u32,
to: u32,
+ /// Whether `to` counts from the start or end of the array/slice.
+ /// For `PlaceElem`s this is `true` if and only if the base is a slice.
+ /// For `ProjectionKind`, this can also be `true` for arrays.
+ from_end: bool,
},
/// "Downcast" to a variant of an ADT. Currently, we only introduce
@@ -1918,15 +1921,18 @@
ProjectionElem::ConstantIndex { offset, min_length, from_end: true } => {
write!(fmt, "[-{:?} of {:?}]", offset, min_length)?;
}
- ProjectionElem::Subslice { from, to } if *to == 0 => {
+ ProjectionElem::Subslice { from, to, from_end: true } if *to == 0 => {
write!(fmt, "[{:?}:]", from)?;
}
- ProjectionElem::Subslice { from, to } if *from == 0 => {
+ ProjectionElem::Subslice { from, to, from_end: true } if *from == 0 => {
write!(fmt, "[:-{:?}]", to)?;
}
- ProjectionElem::Subslice { from, to } => {
+ ProjectionElem::Subslice { from, to, from_end: true } => {
write!(fmt, "[{:?}:-{:?}]", from, to)?;
}
+ ProjectionElem::Subslice { from, to, from_end: false } => {
+ write!(fmt, "[{:?}..{:?}]", from, to)?;
+ }
}
}
@@ -2384,11 +2390,15 @@
UserTypeProjections { contents: projs.collect() }
}
- pub fn projections_and_spans(&self) -> impl Iterator<Item = &(UserTypeProjection, Span)> {
+ pub fn projections_and_spans(&self)
+ -> impl Iterator<Item = &(UserTypeProjection, Span)> + ExactSizeIterator
+ {
self.contents.iter()
}
- pub fn projections(&self) -> impl Iterator<Item = &UserTypeProjection> {
+ pub fn projections(&self)
+ -> impl Iterator<Item = &UserTypeProjection> + ExactSizeIterator
+ {
self.contents.iter().map(|&(ref user_type, _span)| user_type)
}
@@ -2456,7 +2466,7 @@
}
pub(crate) fn subslice(mut self, from: u32, to: u32) -> Self {
- self.projs.push(ProjectionElem::Subslice { from, to });
+ self.projs.push(ProjectionElem::Subslice { from, to, from_end: true });
self
}
@@ -2601,7 +2611,7 @@
pub fn is_predecessor_of<'tcx>(
&self,
other: Location,
- body: ReadOnlyBodyCache<'_, 'tcx>
+ body: ReadOnlyBodyAndCache<'_, 'tcx>
) -> bool {
// If we are in the same block as the other location and are an earlier statement
// then we are a predecessor of `other`.
diff --git a/src/librustc/mir/tcx.rs b/src/librustc/mir/tcx.rs
index a66a49f..445fa6e 100644
--- a/src/librustc/mir/tcx.rs
+++ b/src/librustc/mir/tcx.rs
@@ -88,14 +88,17 @@
}
ProjectionElem::Index(_) | ProjectionElem::ConstantIndex { .. } =>
PlaceTy::from_ty(self.ty.builtin_index().unwrap()),
- ProjectionElem::Subslice { from, to } => {
+ ProjectionElem::Subslice { from, to, from_end } => {
PlaceTy::from_ty(match self.ty.kind {
- ty::Array(inner, size) => {
+ ty::Slice(..) => self.ty,
+ ty::Array(inner, _) if !from_end => {
+ tcx.mk_array(inner, (to - from) as u64)
+ }
+ ty::Array(inner, size) if from_end => {
let size = size.eval_usize(tcx, param_env);
let len = size - (from as u64) - (to as u64);
tcx.mk_array(inner, len)
}
- ty::Slice(..) => self.ty,
_ => {
bug!("cannot subslice non-array type: `{:?}`", self)
}
diff --git a/src/librustc/mir/visit.rs b/src/librustc/mir/visit.rs
index 47a1d67..5d273fe 100644
--- a/src/librustc/mir/visit.rs
+++ b/src/librustc/mir/visit.rs
@@ -67,10 +67,10 @@
macro_rules! body_cache_type {
(mut $a:lifetime, $tcx:lifetime) => {
- &mut BodyCache<$tcx>
+ &mut BodyAndCache<$tcx>
};
($a:lifetime, $tcx:lifetime) => {
- ReadOnlyBodyCache<$a, $tcx>
+ ReadOnlyBodyAndCache<$a, $tcx>
};
}
@@ -954,7 +954,7 @@
);
}
ProjectionElem::Deref |
- ProjectionElem::Subslice { from: _, to: _ } |
+ ProjectionElem::Subslice { from: _, to: _, from_end: _ } |
ProjectionElem::ConstantIndex { offset: _,
min_length: _,
from_end: _ } |
diff --git a/src/librustc/query/mod.rs b/src/librustc/query/mod.rs
index a6d7e5c..538b13c 100644
--- a/src/librustc/query/mod.rs
+++ b/src/librustc/query/mod.rs
@@ -106,30 +106,30 @@
/// Fetch the MIR for a given `DefId` right after it's built - this includes
/// unreachable code.
- query mir_built(_: DefId) -> &'tcx Steal<mir::BodyCache<'tcx>> {}
+ query mir_built(_: DefId) -> &'tcx Steal<mir::BodyAndCache<'tcx>> {}
/// Fetch the MIR for a given `DefId` up till the point where it is
/// ready for const evaluation.
///
/// See the README for the `mir` module for details.
- query mir_const(_: DefId) -> &'tcx Steal<mir::BodyCache<'tcx>> {
+ query mir_const(_: DefId) -> &'tcx Steal<mir::BodyAndCache<'tcx>> {
no_hash
}
query mir_validated(_: DefId) ->
(
- &'tcx Steal<mir::BodyCache<'tcx>>,
- &'tcx Steal<IndexVec<mir::Promoted, mir::BodyCache<'tcx>>>
+ &'tcx Steal<mir::BodyAndCache<'tcx>>,
+ &'tcx Steal<IndexVec<mir::Promoted, mir::BodyAndCache<'tcx>>>
) {
no_hash
}
/// MIR after our optimization passes have run. This is MIR that is ready
/// for codegen. This is also the only query that can fetch non-local MIR, at present.
- query optimized_mir(key: DefId) -> &'tcx mir::BodyCache<'tcx> {
+ query optimized_mir(key: DefId) -> &'tcx mir::BodyAndCache<'tcx> {
cache_on_disk_if { key.is_local() }
load_cached(tcx, id) {
- let mir: Option<crate::mir::BodyCache<'tcx>>
+ let mir: Option<crate::mir::BodyAndCache<'tcx>>
= tcx.queries.on_disk_cache.try_load_query_result(tcx, id);
mir.map(|x| {
let cache = tcx.arena.alloc(x);
@@ -139,13 +139,13 @@
}
}
- query promoted_mir(key: DefId) -> &'tcx IndexVec<mir::Promoted, mir::BodyCache<'tcx>> {
+ query promoted_mir(key: DefId) -> &'tcx IndexVec<mir::Promoted, mir::BodyAndCache<'tcx>> {
cache_on_disk_if { key.is_local() }
load_cached(tcx, id) {
let promoted: Option<
rustc_index::vec::IndexVec<
crate::mir::Promoted,
- crate::mir::BodyCache<'tcx>
+ crate::mir::BodyAndCache<'tcx>
>> = tcx.queries.on_disk_cache.try_load_query_result(tcx, id);
promoted.map(|p| {
let cache = tcx.arena.alloc(p);
@@ -512,7 +512,7 @@
/// in the case of closures, this will be redirected to the enclosing function.
query region_scope_tree(_: DefId) -> &'tcx region::ScopeTree {}
- query mir_shims(key: ty::InstanceDef<'tcx>) -> &'tcx mir::BodyCache<'tcx> {
+ query mir_shims(key: ty::InstanceDef<'tcx>) -> &'tcx mir::BodyAndCache<'tcx> {
no_force
desc { |tcx| "generating MIR shim for `{}`", tcx.def_path_str(key.def_id()) }
}
diff --git a/src/librustc/traits/error_reporting.rs b/src/librustc/traits/error_reporting.rs
index ba44c6c..da36b31 100644
--- a/src/librustc/traits/error_reporting.rs
+++ b/src/librustc/traits/error_reporting.rs
@@ -22,9 +22,11 @@
use crate::hir::Node;
use crate::hir::def_id::DefId;
use crate::infer::{self, InferCtxt};
+use crate::infer::error_reporting::TypeAnnotationNeeded as ErrorCode;
use crate::infer::type_variable::{TypeVariableOrigin, TypeVariableOriginKind};
use crate::session::DiagnosticMessageId;
use crate::ty::{self, AdtKind, DefIdTree, ToPredicate, ToPolyTraitRef, Ty, TyCtxt, TypeFoldable};
+use crate::ty::TypeckTables;
use crate::ty::GenericParamDefKind;
use crate::ty::error::ExpectedFound;
use crate::ty::fast_reject;
@@ -363,11 +365,7 @@
return None
};
- if tcx.has_attr(impl_def_id, sym::rustc_on_unimplemented) {
- Some(impl_def_id)
- } else {
- None
- }
+ tcx.has_attr(impl_def_id, sym::rustc_on_unimplemented).then_some(impl_def_id)
}
fn describe_generator(&self, body_id: hir::BodyId) -> Option<&'static str> {
@@ -1955,7 +1953,7 @@
return;
}
- match predicate {
+ let mut err = match predicate {
ty::Predicate::Trait(ref data) => {
let trait_ref = data.to_poly_trait_ref();
let self_ty = trait_ref.self_ty();
@@ -1989,59 +1987,109 @@
// avoid inundating the user with unnecessary errors, but we now
// check upstream for type errors and dont add the obligations to
// begin with in those cases.
- if
- self.tcx.lang_items().sized_trait()
+ if self.tcx.lang_items().sized_trait()
.map_or(false, |sized_id| sized_id == trait_ref.def_id())
{
- self.need_type_info_err(body_id, span, self_ty).emit();
- } else {
- let mut err = struct_span_err!(
- self.tcx.sess,
- span,
- E0283,
- "type annotations needed: cannot resolve `{}`",
- predicate,
- );
- self.note_obligation_cause(&mut err, obligation);
- err.emit();
+ self.need_type_info_err(body_id, span, self_ty, ErrorCode::E0282).emit();
+ return;
}
+ let mut err = self.need_type_info_err(body_id, span, self_ty, ErrorCode::E0283);
+ err.note(&format!("cannot resolve `{}`", predicate));
+ if let (Ok(ref snippet), ObligationCauseCode::BindingObligation(ref def_id, _)) = (
+ self.tcx.sess.source_map().span_to_snippet(span),
+ &obligation.cause.code,
+ ) {
+ let generics = self.tcx.generics_of(*def_id);
+ if !generics.params.is_empty() && !snippet.ends_with('>'){
+ // FIXME: To avoid spurious suggestions in functions where type arguments
+ // where already supplied, we check the snippet to make sure it doesn't
+ // end with a turbofish. Ideally we would have access to a `PathSegment`
+ // instead. Otherwise we would produce the following output:
+ //
+ // error[E0283]: type annotations needed
+ // --> $DIR/issue-54954.rs:3:24
+ // |
+ // LL | const ARR_LEN: usize = Tt::const_val::<[i8; 123]>();
+ // | ^^^^^^^^^^^^^^^^^^^^^^^^^^
+ // | |
+ // | cannot infer type
+ // | help: consider specifying the type argument
+ // | in the function call:
+ // | `Tt::const_val::<[i8; 123]>::<T>`
+ // ...
+ // LL | const fn const_val<T: Sized>() -> usize {
+ // | --------- - required by this bound in `Tt::const_val`
+ // |
+ // = note: cannot resolve `_: Tt`
+
+ err.span_suggestion(
+ span,
+ &format!(
+ "consider specifying the type argument{} in the function call",
+ if generics.params.len() > 1 {
+ "s"
+ } else {
+ ""
+ },
+ ),
+ format!("{}::<{}>", snippet, generics.params.iter()
+ .map(|p| p.name.to_string())
+ .collect::<Vec<String>>()
+ .join(", ")),
+ Applicability::HasPlaceholders,
+ );
+ }
+ }
+ err
}
ty::Predicate::WellFormed(ty) => {
// Same hacky approach as above to avoid deluging user
// with error messages.
- if !ty.references_error() && !self.tcx.sess.has_errors() {
- self.need_type_info_err(body_id, span, ty).emit();
+ if ty.references_error() || self.tcx.sess.has_errors() {
+ return;
}
+ self.need_type_info_err(body_id, span, ty, ErrorCode::E0282)
}
ty::Predicate::Subtype(ref data) => {
if data.references_error() || self.tcx.sess.has_errors() {
// no need to overload user in such cases
- } else {
- let &SubtypePredicate { a_is_expected: _, a, b } = data.skip_binder();
- // both must be type variables, or the other would've been instantiated
- assert!(a.is_ty_var() && b.is_ty_var());
- self.need_type_info_err(body_id,
- obligation.cause.span,
- a).emit();
+ return
}
+ let &SubtypePredicate { a_is_expected: _, a, b } = data.skip_binder();
+ // both must be type variables, or the other would've been instantiated
+ assert!(a.is_ty_var() && b.is_ty_var());
+ self.need_type_info_err(body_id, span, a, ErrorCode::E0282)
+ }
+ ty::Predicate::Projection(ref data) => {
+ let trait_ref = data.to_poly_trait_ref(self.tcx);
+ let self_ty = trait_ref.self_ty();
+ if predicate.references_error() {
+ return;
+ }
+ let mut err = self.need_type_info_err(body_id, span, self_ty, ErrorCode::E0284);
+ err.note(&format!("cannot resolve `{}`", predicate));
+ err
}
_ => {
- if !self.tcx.sess.has_errors() {
- let mut err = struct_span_err!(
- self.tcx.sess,
- obligation.cause.span,
- E0284,
- "type annotations needed: cannot resolve `{}`",
- predicate,
- );
- self.note_obligation_cause(&mut err, obligation);
- err.emit();
+ if self.tcx.sess.has_errors() {
+ return;
}
+ let mut err = struct_span_err!(
+ self.tcx.sess,
+ span,
+ E0284,
+ "type annotations needed: cannot resolve `{}`",
+ predicate,
+ );
+ err.span_label(span, &format!("cannot resolve `{}`", predicate));
+ err
}
- }
+ };
+ self.note_obligation_cause(&mut err, obligation);
+ err.emit();
}
/// Returns `true` if the trait predicate may apply for *some* assignment
@@ -2108,52 +2156,69 @@
) {
// First, attempt to add note to this error with an async-await-specific
// message, and fall back to regular note otherwise.
- if !self.note_obligation_cause_for_async_await(err, obligation) {
+ if !self.maybe_note_obligation_cause_for_async_await(err, obligation) {
self.note_obligation_cause_code(err, &obligation.predicate, &obligation.cause.code,
&mut vec![]);
}
}
- /// Adds an async-await specific note to the diagnostic:
+ /// Adds an async-await specific note to the diagnostic when the future does not implement
+ /// an auto trait because of a captured type.
///
/// ```ignore (diagnostic)
- /// note: future does not implement `std::marker::Send` because this value is used across an
- /// await
- /// --> $DIR/issue-64130-non-send-future-diags.rs:15:5
+ /// note: future does not implement `Qux` as this value is used across an await
+ /// --> $DIR/issue-64130-3-other.rs:17:5
/// |
- /// LL | let g = x.lock().unwrap();
- /// | - has type `std::sync::MutexGuard<'_, u32>`
+ /// LL | let x = Foo;
+ /// | - has type `Foo`
/// LL | baz().await;
- /// | ^^^^^^^^^^^ await occurs here, with `g` maybe used later
+ /// | ^^^^^^^^^^^ await occurs here, with `x` maybe used later
/// LL | }
- /// | - `g` is later dropped here
+ /// | - `x` is later dropped here
+ /// ```
+ ///
+ /// When the diagnostic does not implement `Send` or `Sync` specifically, then the diagnostic
+ /// is "replaced" with a different message and a more specific error.
+ ///
+ /// ```ignore (diagnostic)
+ /// error: future cannot be sent between threads safely
+ /// --> $DIR/issue-64130-2-send.rs:21:5
+ /// |
+ /// LL | fn is_send<T: Send>(t: T) { }
+ /// | ------- ---- required by this bound in `is_send`
+ /// ...
+ /// LL | is_send(bar());
+ /// | ^^^^^^^ future returned by `bar` is not send
+ /// |
+ /// = help: within `impl std::future::Future`, the trait `std::marker::Send` is not
+ /// implemented for `Foo`
+ /// note: future is not send as this value is used across an await
+ /// --> $DIR/issue-64130-2-send.rs:15:5
+ /// |
+ /// LL | let x = Foo;
+ /// | - has type `Foo`
+ /// LL | baz().await;
+ /// | ^^^^^^^^^^^ await occurs here, with `x` maybe used later
+ /// LL | }
+ /// | - `x` is later dropped here
/// ```
///
/// Returns `true` if an async-await specific note was added to the diagnostic.
- fn note_obligation_cause_for_async_await(
+ fn maybe_note_obligation_cause_for_async_await(
&self,
err: &mut DiagnosticBuilder<'_>,
obligation: &PredicateObligation<'tcx>,
) -> bool {
- debug!("note_obligation_cause_for_async_await: obligation.predicate={:?} \
+ debug!("maybe_note_obligation_cause_for_async_await: obligation.predicate={:?} \
obligation.cause.span={:?}", obligation.predicate, obligation.cause.span);
let source_map = self.tcx.sess.source_map();
- // Look into the obligation predicate to determine the type in the generator which meant
- // that the predicate was not satisifed.
- let (trait_ref, target_ty) = match obligation.predicate {
- ty::Predicate::Trait(trait_predicate) =>
- (trait_predicate.skip_binder().trait_ref, trait_predicate.skip_binder().self_ty()),
- _ => return false,
- };
- debug!("note_obligation_cause_for_async_await: target_ty={:?}", target_ty);
-
// Attempt to detect an async-await error by looking at the obligation causes, looking
- // for only generators, generator witnesses, opaque types or `std::future::GenFuture` to
- // be present.
+ // for a generator to be present.
//
// When a future does not implement a trait because of a captured type in one of the
// generators somewhere in the call stack, then the result is a chain of obligations.
+ //
// Given a `async fn` A that calls a `async fn` B which captures a non-send type and that
// future is passed as an argument to a function C which requires a `Send` type, then the
// chain looks something like this:
@@ -2170,98 +2235,224 @@
// - `BuiltinDerivedObligation` with `impl std::future::Future` (A)
// - `BindingObligation` with `impl_send (Send requirement)
//
- // The first obligations in the chain can be used to get the details of the type that is
- // captured but the entire chain must be inspected to detect this case.
+ // The first obligation in the chain is the most useful and has the generator that captured
+ // the type. The last generator has information about where the bound was introduced. At
+ // least one generator should be present for this diagnostic to be modified.
+ let (mut trait_ref, mut target_ty) = match obligation.predicate {
+ ty::Predicate::Trait(p) =>
+ (Some(p.skip_binder().trait_ref), Some(p.skip_binder().self_ty())),
+ _ => (None, None),
+ };
let mut generator = None;
+ let mut last_generator = None;
let mut next_code = Some(&obligation.cause.code);
while let Some(code) = next_code {
- debug!("note_obligation_cause_for_async_await: code={:?}", code);
+ debug!("maybe_note_obligation_cause_for_async_await: code={:?}", code);
match code {
ObligationCauseCode::BuiltinDerivedObligation(derived_obligation) |
ObligationCauseCode::ImplDerivedObligation(derived_obligation) => {
- debug!("note_obligation_cause_for_async_await: self_ty.kind={:?}",
- derived_obligation.parent_trait_ref.self_ty().kind);
- match derived_obligation.parent_trait_ref.self_ty().kind {
- ty::Adt(ty::AdtDef { did, .. }, ..) if
- self.tcx.is_diagnostic_item(sym::gen_future, *did) => {},
- ty::Generator(did, ..) => generator = generator.or(Some(did)),
- ty::GeneratorWitness(_) | ty::Opaque(..) => {},
- _ => return false,
+ let ty = derived_obligation.parent_trait_ref.self_ty();
+ debug!("maybe_note_obligation_cause_for_async_await: \
+ parent_trait_ref={:?} self_ty.kind={:?}",
+ derived_obligation.parent_trait_ref, ty.kind);
+
+ match ty.kind {
+ ty::Generator(did, ..) => {
+ generator = generator.or(Some(did));
+ last_generator = Some(did);
+ },
+ ty::GeneratorWitness(..) => {},
+ _ if generator.is_none() => {
+ trait_ref = Some(*derived_obligation.parent_trait_ref.skip_binder());
+ target_ty = Some(ty);
+ },
+ _ => {},
}
next_code = Some(derived_obligation.parent_code.as_ref());
},
- ObligationCauseCode::ItemObligation(_) | ObligationCauseCode::BindingObligation(..)
- if generator.is_some() => break,
- _ => return false,
+ _ => break,
}
}
- let generator_did = generator.expect("can only reach this if there was a generator");
-
- // Only continue to add a note if the generator is from an `async` function.
- let parent_node = self.tcx.parent(generator_did)
- .and_then(|parent_did| self.tcx.hir().get_if_local(parent_did));
- debug!("note_obligation_cause_for_async_await: parent_node={:?}", parent_node);
- if let Some(hir::Node::Item(hir::Item {
- kind: hir::ItemKind::Fn(sig, _, _),
- ..
- })) = parent_node {
- debug!("note_obligation_cause_for_async_await: header={:?}", sig.header);
- if sig.header.asyncness != hir::IsAsync::Async {
- return false;
- }
- }
+ // Only continue if a generator was found.
+ debug!("maybe_note_obligation_cause_for_async_await: generator={:?} trait_ref={:?} \
+ target_ty={:?}", generator, trait_ref, target_ty);
+ let (generator_did, trait_ref, target_ty) = match (generator, trait_ref, target_ty) {
+ (Some(generator_did), Some(trait_ref), Some(target_ty)) =>
+ (generator_did, trait_ref, target_ty),
+ _ => return false,
+ };
let span = self.tcx.def_span(generator_did);
- let tables = self.tcx.typeck_tables_of(generator_did);
- debug!("note_obligation_cause_for_async_await: generator_did={:?} span={:?} ",
- generator_did, span);
+
+ // Do not ICE on closure typeck (#66868).
+ if let None = self.tcx.hir().as_local_hir_id(generator_did) {
+ return false;
+ }
+
+ // Get the tables from the infcx if the generator is the function we are
+ // currently type-checking; otherwise, get them by performing a query.
+ // This is needed to avoid cycles.
+ let in_progress_tables = self.in_progress_tables.map(|t| t.borrow());
+ let generator_did_root = self.tcx.closure_base_def_id(generator_did);
+ debug!("maybe_note_obligation_cause_for_async_await: generator_did={:?} \
+ generator_did_root={:?} in_progress_tables.local_id_root={:?} span={:?}",
+ generator_did, generator_did_root,
+ in_progress_tables.as_ref().map(|t| t.local_id_root), span);
+ let query_tables;
+ let tables: &TypeckTables<'tcx> = match &in_progress_tables {
+ Some(t) if t.local_id_root == Some(generator_did_root) => t,
+ _ => {
+ query_tables = self.tcx.typeck_tables_of(generator_did);
+ &query_tables
+ }
+ };
// Look for a type inside the generator interior that matches the target type to get
// a span.
+ let target_ty_erased = self.tcx.erase_regions(&target_ty);
let target_span = tables.generator_interior_types.iter()
- .find(|ty::GeneratorInteriorTypeCause { ty, .. }| ty::TyS::same_type(*ty, target_ty))
+ .find(|ty::GeneratorInteriorTypeCause { ty, .. }| {
+ // Careful: the regions for types that appear in the
+ // generator interior are not generally known, so we
+ // want to erase them when comparing (and anyway,
+ // `Send` and other bounds are generally unaffected by
+ // the choice of region). When erasing regions, we
+ // also have to erase late-bound regions. This is
+ // because the types that appear in the generator
+ // interior generally contain "bound regions" to
+ // represent regions that are part of the suspended
+ // generator frame. Bound regions are preserved by
+ // `erase_regions` and so we must also call
+ // `erase_late_bound_regions`.
+ let ty_erased = self.tcx.erase_late_bound_regions(&ty::Binder::bind(*ty));
+ let ty_erased = self.tcx.erase_regions(&ty_erased);
+ let eq = ty::TyS::same_type(ty_erased, target_ty_erased);
+ debug!("maybe_note_obligation_cause_for_async_await: ty_erased={:?} \
+ target_ty_erased={:?} eq={:?}", ty_erased, target_ty_erased, eq);
+ eq
+ })
.map(|ty::GeneratorInteriorTypeCause { span, scope_span, .. }|
(span, source_map.span_to_snippet(*span), scope_span));
+ debug!("maybe_note_obligation_cause_for_async_await: target_ty={:?} \
+ generator_interior_types={:?} target_span={:?}",
+ target_ty, tables.generator_interior_types, target_span);
if let Some((target_span, Ok(snippet), scope_span)) = target_span {
- // Look at the last interior type to get a span for the `.await`.
- let await_span = tables.generator_interior_types.iter().map(|i| i.span).last().unwrap();
- let mut span = MultiSpan::from_span(await_span);
- span.push_span_label(
- await_span, format!("await occurs here, with `{}` maybe used later", snippet));
-
- span.push_span_label(*target_span, format!("has type `{}`", target_ty));
-
- // If available, use the scope span to annotate the drop location.
- if let Some(scope_span) = scope_span {
- span.push_span_label(
- source_map.end_point(*scope_span),
- format!("`{}` is later dropped here", snippet),
- );
- }
-
- err.span_note(span, &format!(
- "future does not implement `{}` as this value is used across an await",
- trait_ref.print_only_trait_path(),
- ));
-
- // Add a note for the item obligation that remains - normally a note pointing to the
- // bound that introduced the obligation (e.g. `T: Send`).
- debug!("note_obligation_cause_for_async_await: next_code={:?}", next_code);
- self.note_obligation_cause_code(
- err,
- &obligation.predicate,
- next_code.unwrap(),
- &mut Vec::new(),
+ self.note_obligation_cause_for_async_await(
+ err, *target_span, scope_span, snippet, generator_did, last_generator,
+ trait_ref, target_ty, tables, obligation, next_code,
);
-
true
} else {
false
}
}
+ /// Unconditionally adds the diagnostic note described in
+ /// `maybe_note_obligation_cause_for_async_await`'s documentation comment.
+ fn note_obligation_cause_for_async_await(
+ &self,
+ err: &mut DiagnosticBuilder<'_>,
+ target_span: Span,
+ scope_span: &Option<Span>,
+ snippet: String,
+ first_generator: DefId,
+ last_generator: Option<DefId>,
+ trait_ref: ty::TraitRef<'_>,
+ target_ty: Ty<'tcx>,
+ tables: &ty::TypeckTables<'_>,
+ obligation: &PredicateObligation<'tcx>,
+ next_code: Option<&ObligationCauseCode<'tcx>>,
+ ) {
+ let source_map = self.tcx.sess.source_map();
+
+ let is_async_fn = self.tcx.parent(first_generator)
+ .map(|parent_did| self.tcx.asyncness(parent_did))
+ .map(|parent_asyncness| parent_asyncness == hir::IsAsync::Async)
+ .unwrap_or(false);
+ let is_async_move = self.tcx.hir().as_local_hir_id(first_generator)
+ .and_then(|hir_id| self.tcx.hir().maybe_body_owned_by(hir_id))
+ .map(|body_id| self.tcx.hir().body(body_id))
+ .and_then(|body| body.generator_kind())
+ .map(|generator_kind| match generator_kind {
+ hir::GeneratorKind::Async(..) => true,
+ _ => false,
+ })
+ .unwrap_or(false);
+ let await_or_yield = if is_async_fn || is_async_move { "await" } else { "yield" };
+
+ // Special case the primary error message when send or sync is the trait that was
+ // not implemented.
+ let is_send = self.tcx.is_diagnostic_item(sym::send_trait, trait_ref.def_id);
+ let is_sync = self.tcx.is_diagnostic_item(sym::sync_trait, trait_ref.def_id);
+ let trait_explanation = if is_send || is_sync {
+ let (trait_name, trait_verb) = if is_send {
+ ("`Send`", "sent")
+ } else {
+ ("`Sync`", "shared")
+ };
+
+ err.clear_code();
+ err.set_primary_message(
+ format!("future cannot be {} between threads safely", trait_verb)
+ );
+
+ let original_span = err.span.primary_span().unwrap();
+ let mut span = MultiSpan::from_span(original_span);
+
+ let message = if let Some(name) = last_generator
+ .and_then(|generator_did| self.tcx.parent(generator_did))
+ .and_then(|parent_did| self.tcx.hir().as_local_hir_id(parent_did))
+ .map(|parent_hir_id| self.tcx.hir().name(parent_hir_id))
+ {
+ format!("future returned by `{}` is not {}", name, trait_name)
+ } else {
+ format!("future is not {}", trait_name)
+ };
+
+ span.push_span_label(original_span, message);
+ err.set_span(span);
+
+ format!("is not {}", trait_name)
+ } else {
+ format!("does not implement `{}`", trait_ref.print_only_trait_path())
+ };
+
+ // Look at the last interior type to get a span for the `.await`.
+ let await_span = tables.generator_interior_types.iter().map(|i| i.span).last().unwrap();
+ let mut span = MultiSpan::from_span(await_span);
+ span.push_span_label(
+ await_span,
+ format!("{} occurs here, with `{}` maybe used later", await_or_yield, snippet));
+
+ span.push_span_label(target_span, format!("has type `{}`", target_ty));
+
+ // If available, use the scope span to annotate the drop location.
+ if let Some(scope_span) = scope_span {
+ span.push_span_label(
+ source_map.end_point(*scope_span),
+ format!("`{}` is later dropped here", snippet),
+ );
+ }
+
+ err.span_note(span, &format!(
+ "future {} as this value is used across an {}",
+ trait_explanation,
+ await_or_yield,
+ ));
+
+ // Add a note for the item obligation that remains - normally a note pointing to the
+ // bound that introduced the obligation (e.g. `T: Send`).
+ debug!("note_obligation_cause_for_async_await: next_code={:?}", next_code);
+ self.note_obligation_cause_code(
+ err,
+ &obligation.predicate,
+ next_code.unwrap(),
+ &mut Vec::new(),
+ );
+ }
+
fn note_obligation_cause_code<T>(&self,
err: &mut DiagnosticBuilder<'_>,
predicate: &T,
diff --git a/src/librustc/traits/fulfill.rs b/src/librustc/traits/fulfill.rs
index a981162..2773199 100644
--- a/src/librustc/traits/fulfill.rs
+++ b/src/librustc/traits/fulfill.rs
@@ -65,7 +65,7 @@
#[derive(Clone, Debug)]
pub struct PendingPredicateObligation<'tcx> {
pub obligation: PredicateObligation<'tcx>,
- pub stalled_on: Vec<Ty<'tcx>>,
+ pub stalled_on: Vec<ty::InferTy>,
}
// `PendingPredicateObligation` is used a lot. Make sure it doesn't unintentionally get bigger.
@@ -263,8 +263,8 @@
// Match arms are in order of frequency, which matters because this
// code is so hot. 1 and 0 dominate; 2+ is fairly rare.
1 => {
- let ty = pending_obligation.stalled_on[0];
- ShallowResolver::new(self.selcx.infcx()).shallow_resolve_changed(ty)
+ let infer = pending_obligation.stalled_on[0];
+ ShallowResolver::new(self.selcx.infcx()).shallow_resolve_changed(infer)
}
0 => {
// In this case we haven't changed, but wish to make a change.
@@ -274,8 +274,8 @@
// This `for` loop was once a call to `all()`, but this lower-level
// form was a perf win. See #64545 for details.
(|| {
- for &ty in &pending_obligation.stalled_on {
- if ShallowResolver::new(self.selcx.infcx()).shallow_resolve_changed(ty) {
+ for &infer in &pending_obligation.stalled_on {
+ if ShallowResolver::new(self.selcx.infcx()).shallow_resolve_changed(infer) {
return true;
}
}
@@ -305,6 +305,13 @@
debug!("process_obligation: obligation = {:?} cause = {:?}", obligation, obligation.cause);
+ fn infer_ty(ty: Ty<'tcx>) -> ty::InferTy {
+ match ty.kind {
+ ty::Infer(infer) => infer,
+ _ => panic!(),
+ }
+ }
+
match obligation.predicate {
ty::Predicate::Trait(ref data) => {
let trait_obligation = obligation.with(data.clone());
@@ -459,7 +466,7 @@
obligation.cause.span,
) {
None => {
- pending_obligation.stalled_on = vec![ty];
+ pending_obligation.stalled_on = vec![infer_ty(ty)];
ProcessResult::Unchanged
}
Some(os) => ProcessResult::Changed(mk_pending(os))
@@ -472,8 +479,8 @@
subtype) {
None => {
// None means that both are unresolved.
- pending_obligation.stalled_on = vec![subtype.skip_binder().a,
- subtype.skip_binder().b];
+ pending_obligation.stalled_on = vec![infer_ty(subtype.skip_binder().a),
+ infer_ty(subtype.skip_binder().b)];
ProcessResult::Unchanged
}
Some(Ok(ok)) => {
@@ -517,7 +524,8 @@
))
}
} else {
- pending_obligation.stalled_on = substs.types().collect();
+ pending_obligation.stalled_on =
+ substs.types().map(|ty| infer_ty(ty)).collect();
ProcessResult::Unchanged
}
}
@@ -542,13 +550,13 @@
fn trait_ref_type_vars<'a, 'tcx>(
selcx: &mut SelectionContext<'a, 'tcx>,
t: ty::PolyTraitRef<'tcx>,
-) -> Vec<Ty<'tcx>> {
+) -> Vec<ty::InferTy> {
t.skip_binder() // ok b/c this check doesn't care about regions
.input_types()
.map(|t| selcx.infcx().resolve_vars_if_possible(&t))
.filter(|t| t.has_infer_types())
.flat_map(|t| t.walk())
- .filter(|t| match t.kind { ty::Infer(_) => true, _ => false })
+ .filter_map(|t| match t.kind { ty::Infer(infer) => Some(infer), _ => None })
.collect()
}
diff --git a/src/librustc/traits/project.rs b/src/librustc/traits/project.rs
index c345b9a..1fdec5f 100644
--- a/src/librustc/traits/project.rs
+++ b/src/librustc/traits/project.rs
@@ -1079,12 +1079,10 @@
if !is_default {
true
} else if obligation.param_env.reveal == Reveal::All {
- debug_assert!(!poly_trait_ref.needs_infer());
- if !poly_trait_ref.needs_subst() {
- true
- } else {
- false
- }
+ // NOTE(eddyb) inference variables can resolve to parameters, so
+ // assume `poly_trait_ref` isn't monomorphic, if it contains any.
+ let poly_trait_ref = selcx.infcx().resolve_vars_if_possible(&poly_trait_ref);
+ !poly_trait_ref.needs_infer() && !poly_trait_ref.needs_subst()
} else {
false
}
diff --git a/src/librustc/traits/select.rs b/src/librustc/traits/select.rs
index 5f32452..94a77c5 100644
--- a/src/librustc/traits/select.rs
+++ b/src/librustc/traits/select.rs
@@ -204,7 +204,10 @@
#[derive(Clone, Default)]
pub struct SelectionCache<'tcx> {
hashmap: Lock<
- FxHashMap<ty::TraitRef<'tcx>, WithDepNode<SelectionResult<'tcx, SelectionCandidate<'tcx>>>>,
+ FxHashMap<
+ ty::ParamEnvAnd<'tcx, ty::TraitRef<'tcx>>,
+ WithDepNode<SelectionResult<'tcx, SelectionCandidate<'tcx>>>,
+ >,
>,
}
@@ -490,7 +493,9 @@
#[derive(Clone, Default)]
pub struct EvaluationCache<'tcx> {
- hashmap: Lock<FxHashMap<ty::PolyTraitRef<'tcx>, WithDepNode<EvaluationResult>>>,
+ hashmap: Lock<
+ FxHashMap<ty::ParamEnvAnd<'tcx, ty::PolyTraitRef<'tcx>>, WithDepNode<EvaluationResult>>,
+ >,
}
impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
@@ -1143,7 +1148,7 @@
let tcx = self.tcx();
if self.can_use_global_caches(param_env) {
let cache = tcx.evaluation_cache.hashmap.borrow();
- if let Some(cached) = cache.get(&trait_ref) {
+ if let Some(cached) = cache.get(¶m_env.and(trait_ref)) {
return Some(cached.get(tcx));
}
}
@@ -1151,7 +1156,7 @@
.evaluation_cache
.hashmap
.borrow()
- .get(&trait_ref)
+ .get(¶m_env.and(trait_ref))
.map(|v| v.get(tcx))
}
@@ -1182,7 +1187,7 @@
.evaluation_cache
.hashmap
.borrow_mut()
- .insert(trait_ref, WithDepNode::new(dep_node, result));
+ .insert(param_env.and(trait_ref), WithDepNode::new(dep_node, result));
return;
}
}
@@ -1195,7 +1200,7 @@
.evaluation_cache
.hashmap
.borrow_mut()
- .insert(trait_ref, WithDepNode::new(dep_node, result));
+ .insert(param_env.and(trait_ref), WithDepNode::new(dep_node, result));
}
/// For various reasons, it's possible for a subobligation
@@ -1567,14 +1572,10 @@
/// Do note that if the type itself is not in the
/// global tcx, the local caches will be used.
fn can_use_global_caches(&self, param_env: ty::ParamEnv<'tcx>) -> bool {
- // If there are any where-clauses in scope, then we always use
- // a cache local to this particular scope. Otherwise, we
- // switch to a global cache. We used to try and draw
- // finer-grained distinctions, but that led to a serious of
- // annoying and weird bugs like #22019 and #18290. This simple
- // rule seems to be pretty clearly safe and also still retains
- // a very high hit rate (~95% when compiling rustc).
- if !param_env.caller_bounds.is_empty() {
+ // If there are any e.g. inference variables in the `ParamEnv`, then we
+ // always use a cache local to this particular scope. Otherwise, we
+ // switch to a global cache.
+ if param_env.has_local_value() {
return false;
}
@@ -1602,7 +1603,7 @@
let trait_ref = &cache_fresh_trait_pred.skip_binder().trait_ref;
if self.can_use_global_caches(param_env) {
let cache = tcx.selection_cache.hashmap.borrow();
- if let Some(cached) = cache.get(&trait_ref) {
+ if let Some(cached) = cache.get(¶m_env.and(*trait_ref)) {
return Some(cached.get(tcx));
}
}
@@ -1610,7 +1611,7 @@
.selection_cache
.hashmap
.borrow()
- .get(trait_ref)
+ .get(¶m_env.and(*trait_ref))
.map(|v| v.get(tcx))
}
@@ -1671,7 +1672,7 @@
tcx.selection_cache
.hashmap
.borrow_mut()
- .insert(trait_ref, WithDepNode::new(dep_node, candidate));
+ .insert(param_env.and(trait_ref), WithDepNode::new(dep_node, candidate));
return;
}
}
@@ -1685,7 +1686,7 @@
.selection_cache
.hashmap
.borrow_mut()
- .insert(trait_ref, WithDepNode::new(dep_node, candidate));
+ .insert(param_env.and(trait_ref), WithDepNode::new(dep_node, candidate));
}
fn assemble_candidates<'o>(
diff --git a/src/librustc/ty/context.rs b/src/librustc/ty/context.rs
index 6a0002c..f7e422b 100644
--- a/src/librustc/ty/context.rs
+++ b/src/librustc/ty/context.rs
@@ -8,6 +8,7 @@
use crate::session::config::{BorrowckMode, OutputFilenames};
use crate::session::config::CrateType;
use crate::middle;
+use crate::middle::lang_items::PanicLocationLangItem;
use crate::hir::{self, TraitCandidate, HirId, ItemKind, ItemLocalId, Node};
use crate::hir::def::{Res, DefKind, Export};
use crate::hir::def_id::{CrateNum, DefId, DefIndex, LOCAL_CRATE};
@@ -22,7 +23,7 @@
use crate::middle::lang_items;
use crate::middle::resolve_lifetime::{self, ObjectLifetimeDefault};
use crate::middle::stability;
-use crate::mir::{BodyCache, Field, interpret, Local, Place, PlaceElem, ProjectionKind, Promoted};
+use crate::mir::{BodyAndCache, Field, interpret, Local, Place, PlaceElem, ProjectionKind, Promoted};
use crate::mir::interpret::{ConstValue, Allocation, Scalar};
use crate::ty::subst::{GenericArg, InternalSubsts, SubstsRef, Subst};
use crate::ty::ReprOptions;
@@ -1083,17 +1084,17 @@
&self.hir_map
}
- pub fn alloc_steal_mir(self, mir: BodyCache<'tcx>) -> &'tcx Steal<BodyCache<'tcx>> {
+ pub fn alloc_steal_mir(self, mir: BodyAndCache<'tcx>) -> &'tcx Steal<BodyAndCache<'tcx>> {
self.arena.alloc(Steal::new(mir))
}
- pub fn alloc_steal_promoted(self, promoted: IndexVec<Promoted, BodyCache<'tcx>>) ->
- &'tcx Steal<IndexVec<Promoted, BodyCache<'tcx>>> {
+ pub fn alloc_steal_promoted(self, promoted: IndexVec<Promoted, BodyAndCache<'tcx>>) ->
+ &'tcx Steal<IndexVec<Promoted, BodyAndCache<'tcx>>> {
self.arena.alloc(Steal::new(promoted))
}
- pub fn intern_promoted(self, promoted: IndexVec<Promoted, BodyCache<'tcx>>) ->
- &'tcx IndexVec<Promoted, BodyCache<'tcx>> {
+ pub fn intern_promoted(self, promoted: IndexVec<Promoted, BodyAndCache<'tcx>>) ->
+ &'tcx IndexVec<Promoted, BodyAndCache<'tcx>> {
self.arena.alloc(promoted)
}
@@ -1588,6 +1589,15 @@
pub fn has_strict_asm_symbol_naming(&self) -> bool {
self.sess.target.target.arch.contains("nvptx")
}
+
+ /// Returns `&'static core::panic::Location<'static>`.
+ pub fn caller_location_ty(&self) -> Ty<'tcx> {
+ self.mk_imm_ref(
+ self.lifetimes.re_static,
+ self.type_of(self.require_lang_item(PanicLocationLangItem, None))
+ .subst(*self, self.mk_substs([self.lifetimes.re_static.into()].iter())),
+ )
+ }
}
impl<'tcx> GlobalCtxt<'tcx> {
diff --git a/src/librustc/ty/instance.rs b/src/librustc/ty/instance.rs
index 801dfa8..366951b 100644
--- a/src/librustc/ty/instance.rs
+++ b/src/librustc/ty/instance.rs
@@ -116,6 +116,10 @@
}
tcx.codegen_fn_attrs(self.def_id()).requests_inline()
}
+
+ pub fn requires_caller_location(&self, tcx: TyCtxt<'_>) -> bool {
+ tcx.codegen_fn_attrs(self.def_id()).flags.contains(CodegenFnAttrFlags::TRACK_CALLER)
+ }
}
impl<'tcx> fmt::Display for Instance<'tcx> {
@@ -255,11 +259,8 @@
) -> Option<Instance<'tcx>> {
debug!("resolve(def_id={:?}, substs={:?})", def_id, substs);
Instance::resolve(tcx, param_env, def_id, substs).map(|mut resolved| {
- let has_track_caller = |def| tcx.codegen_fn_attrs(def).flags
- .contains(CodegenFnAttrFlags::TRACK_CALLER);
-
match resolved.def {
- InstanceDef::Item(def_id) if has_track_caller(def_id) => {
+ InstanceDef::Item(def_id) if resolved.def.requires_caller_location(tcx) => {
debug!(" => fn pointer created for function with #[track_caller]");
resolved.def = InstanceDef::ReifyShim(def_id);
}
diff --git a/src/librustc/ty/layout.rs b/src/librustc/ty/layout.rs
index 7f93e8c..c7278dc 100644
--- a/src/librustc/ty/layout.rs
+++ b/src/librustc/ty/layout.rs
@@ -2434,6 +2434,7 @@
cx: &C,
sig: ty::PolyFnSig<'tcx>,
extra_args: &[Ty<'tcx>],
+ caller_location: Option<Ty<'tcx>>,
mk_arg_type: impl Fn(Ty<'tcx>, Option<usize>) -> ArgAbi<'tcx, Ty<'tcx>>,
) -> Self;
fn adjust_for_abi(&mut self, cx: &C, abi: SpecAbi);
@@ -2448,13 +2449,19 @@
+ HasParamEnv<'tcx>,
{
fn of_fn_ptr(cx: &C, sig: ty::PolyFnSig<'tcx>, extra_args: &[Ty<'tcx>]) -> Self {
- call::FnAbi::new_internal(cx, sig, extra_args, |ty, _| ArgAbi::new(cx.layout_of(ty)))
+ call::FnAbi::new_internal(cx, sig, extra_args, None, |ty, _| ArgAbi::new(cx.layout_of(ty)))
}
fn of_instance(cx: &C, instance: ty::Instance<'tcx>, extra_args: &[Ty<'tcx>]) -> Self {
let sig = instance.fn_sig_for_fn_abi(cx.tcx());
- call::FnAbi::new_internal(cx, sig, extra_args, |ty, arg_idx| {
+ let caller_location = if instance.def.requires_caller_location(cx.tcx()) {
+ Some(cx.tcx().caller_location_ty())
+ } else {
+ None
+ };
+
+ call::FnAbi::new_internal(cx, sig, extra_args, caller_location, |ty, arg_idx| {
let mut layout = cx.layout_of(ty);
// Don't pass the vtable, it's not an argument of the virtual fn.
// Instead, pass just the data pointer, but give it the type `*const/mut dyn Trait`
@@ -2479,7 +2486,7 @@
'descend_newtypes: while !fat_pointer_layout.ty.is_unsafe_ptr()
&& !fat_pointer_layout.ty.is_region_ptr()
{
- 'iter_fields: for i in 0..fat_pointer_layout.fields.count() {
+ for i in 0..fat_pointer_layout.fields.count() {
let field_layout = fat_pointer_layout.field(cx, i);
if !field_layout.is_zst() {
@@ -2512,6 +2519,7 @@
cx: &C,
sig: ty::PolyFnSig<'tcx>,
extra_args: &[Ty<'tcx>],
+ caller_location: Option<Ty<'tcx>>,
mk_arg_type: impl Fn(Ty<'tcx>, Option<usize>) -> ArgAbi<'tcx, Ty<'tcx>>,
) -> Self {
debug!("FnAbi::new_internal({:?}, {:?})", sig, extra_args);
@@ -2684,6 +2692,7 @@
.iter()
.cloned()
.chain(extra_args)
+ .chain(caller_location)
.enumerate()
.map(|(i, ty)| arg_of(ty, Some(i)))
.collect(),
diff --git a/src/librustc/ty/mod.rs b/src/librustc/ty/mod.rs
index c9a934e..78a31f4 100644
--- a/src/librustc/ty/mod.rs
+++ b/src/librustc/ty/mod.rs
@@ -18,7 +18,7 @@
use crate::middle::cstore::CrateStoreDyn;
use crate::middle::lang_items::{FnTraitLangItem, FnMutTraitLangItem, FnOnceTraitLangItem};
use crate::middle::resolve_lifetime::ObjectLifetimeDefault;
-use crate::mir::ReadOnlyBodyCache;
+use crate::mir::ReadOnlyBodyAndCache;
use crate::mir::interpret::{GlobalId, ErrorHandled};
use crate::mir::GeneratorLayout;
use crate::session::CrateDisambiguator;
@@ -2784,11 +2784,7 @@
}
};
- if is_associated_item {
- Some(self.associated_item(def_id))
- } else {
- None
- }
+ is_associated_item.then(|| self.associated_item(def_id))
}
fn associated_item_from_trait_item_ref(self,
@@ -2985,7 +2981,7 @@
}
/// Returns the possibly-auto-generated MIR of a `(DefId, Subst)` pair.
- pub fn instance_mir(self, instance: ty::InstanceDef<'tcx>) -> ReadOnlyBodyCache<'tcx, 'tcx> {
+ pub fn instance_mir(self, instance: ty::InstanceDef<'tcx>) -> ReadOnlyBodyAndCache<'tcx, 'tcx> {
match instance {
ty::InstanceDef::Item(did) => {
self.optimized_mir(did).unwrap_read_only()
@@ -3253,7 +3249,7 @@
let unnormalized_env = ty::ParamEnv::new(
tcx.intern_predicates(&predicates),
traits::Reveal::UserFacing,
- if tcx.sess.opts.debugging_opts.chalk { Some(def_id) } else { None }
+ tcx.sess.opts.debugging_opts.chalk.then_some(def_id),
);
let body_id = tcx.hir().as_local_hir_id(def_id).map_or(hir::DUMMY_HIR_ID, |id| {
diff --git a/src/librustc/ty/print/pretty.rs b/src/librustc/ty/print/pretty.rs
index fff2f06..745f7d0 100644
--- a/src/librustc/ty/print/pretty.rs
+++ b/src/librustc/ty/print/pretty.rs
@@ -1282,6 +1282,9 @@
if !self.empty_path {
write!(self, "::")?;
}
+ if ast::Ident::from_str(&name).is_raw_guess() {
+ write!(self, "r#")?;
+ }
write!(self, "{}", name)?;
// FIXME(eddyb) this will print e.g. `{{closure}}#3`, but it
diff --git a/src/librustc/ty/query/job.rs b/src/librustc/ty/query/job.rs
index e5f4e79..2f30b79 100644
--- a/src/librustc/ty/query/job.rs
+++ b/src/librustc/ty/query/job.rs
@@ -303,13 +303,8 @@
return true;
}
- visit_waiters(query, |_, successor| {
- if connected_to_root(successor, visited) {
- Some(None)
- } else {
- None
- }
- }).is_some()
+ visit_waiters(query, |_, successor| connected_to_root(successor, visited).then_some(None))
+ .is_some()
}
// Deterministically pick an query from a list
diff --git a/src/librustc_codegen_llvm/Cargo.toml b/src/librustc_codegen_llvm/Cargo.toml
index 867bbd2..71cfacf 100644
--- a/src/librustc_codegen_llvm/Cargo.toml
+++ b/src/librustc_codegen_llvm/Cargo.toml
@@ -7,8 +7,28 @@
[lib]
name = "rustc_codegen_llvm"
path = "lib.rs"
-crate-type = ["dylib"]
test = false
+doctest = false
[dependencies]
+bitflags = "1.0"
+flate2 = "1.0"
+libc = "0.2"
+log = "0.4"
+rustc = { path = "../librustc" }
+rustc-demangle = "0.1"
+rustc_codegen_ssa = { path = "../librustc_codegen_ssa" }
+rustc_codegen_utils = { path = "../librustc_codegen_utils" }
+rustc_data_structures = { path = "../librustc_data_structures" }
+rustc_errors = { path = "../librustc_errors" }
+rustc_feature = { path = "../librustc_feature" }
+rustc_fs_util = { path = "../librustc_fs_util" }
+rustc_incremental = { path = "../librustc_incremental" }
+rustc_index = { path = "../librustc_index" }
rustc_llvm = { path = "../librustc_llvm" }
+rustc_session = { path = "../librustc_session" }
+rustc_target = { path = "../librustc_target" }
+smallvec = { version = "0.6.7", features = ["union", "may_dangle"] }
+syntax = { path = "../libsyntax" }
+syntax_expand = { path = "../libsyntax_expand" }
+syntax_pos = { path = "../libsyntax_pos" }
diff --git a/src/librustc_codegen_llvm/abi.rs b/src/librustc_codegen_llvm/abi.rs
index 1f3c8e1..2607a49 100644
--- a/src/librustc_codegen_llvm/abi.rs
+++ b/src/librustc_codegen_llvm/abi.rs
@@ -8,6 +8,7 @@
use rustc_codegen_ssa::MemFlags;
use rustc_codegen_ssa::mir::place::PlaceRef;
use rustc_codegen_ssa::mir::operand::OperandValue;
+use rustc::bug;
use rustc_codegen_ssa::traits::*;
use rustc_target::abi::call::ArgAbi;
use rustc_target::abi::{HasDataLayout, LayoutOf};
diff --git a/src/librustc_codegen_llvm/allocator.rs b/src/librustc_codegen_llvm/allocator.rs
index 11b6e0b..e1d56b9 100644
--- a/src/librustc_codegen_llvm/allocator.rs
+++ b/src/librustc_codegen_llvm/allocator.rs
@@ -4,6 +4,7 @@
use libc::c_uint;
use rustc::ty::TyCtxt;
use syntax::expand::allocator::{AllocatorKind, AllocatorTy, ALLOCATOR_METHODS};
+use rustc::bug;
use crate::ModuleLlvm;
use crate::llvm::{self, False, True};
diff --git a/src/librustc_codegen_llvm/asm.rs b/src/librustc_codegen_llvm/asm.rs
index abdd2e3..fa43e08 100644
--- a/src/librustc_codegen_llvm/asm.rs
+++ b/src/librustc_codegen_llvm/asm.rs
@@ -12,7 +12,7 @@
use std::ffi::{CStr, CString};
use libc::{c_uint, c_char};
-
+use log::debug;
impl AsmBuilderMethods<'tcx> for Builder<'a, 'll, 'tcx> {
fn codegen_inline_asm(
diff --git a/src/librustc_codegen_llvm/attributes.rs b/src/librustc_codegen_llvm/attributes.rs
index 33dc251..5479a1f 100644
--- a/src/librustc_codegen_llvm/attributes.rs
+++ b/src/librustc_codegen_llvm/attributes.rs
@@ -12,6 +12,7 @@
use rustc_data_structures::small_c_str::SmallCStr;
use rustc_data_structures::fx::FxHashMap;
use rustc_target::abi::call::Conv;
+use rustc_data_structures::const_cstr;
use rustc_target::spec::PanicStrategy;
use rustc_codegen_ssa::traits::*;
@@ -375,11 +376,7 @@
let native_libs = tcx.native_libraries(cnum);
let def_id_to_native_lib = native_libs.iter().filter_map(|lib|
- if let Some(id) = lib.foreign_module {
- Some((id, lib))
- } else {
- None
- }
+ lib.foreign_module.map(|id| (id, lib))
).collect::<FxHashMap<_, _>>();
let mut ret = FxHashMap::default();
diff --git a/src/librustc_codegen_llvm/back/lto.rs b/src/librustc_codegen_llvm/back/lto.rs
index 858dd59..0e4e4e2 100644
--- a/src/librustc_codegen_llvm/back/lto.rs
+++ b/src/librustc_codegen_llvm/back/lto.rs
@@ -4,11 +4,12 @@
use crate::llvm::archive_ro::ArchiveRO;
use crate::llvm::{self, True, False};
use crate::{ModuleLlvm, LlvmCodegenBackend};
+use rustc::bug;
use rustc_codegen_ssa::back::symbol_export;
use rustc_codegen_ssa::back::write::{ModuleConfig, CodegenContext, FatLTOInput};
use rustc_codegen_ssa::back::lto::{SerializedModule, LtoModuleCodegen, ThinShared, ThinModule};
use rustc_codegen_ssa::traits::*;
-use errors::{FatalError, Handler};
+use rustc_errors::{FatalError, Handler};
use rustc::dep_graph::WorkProduct;
use rustc_session::cgu_reuse_tracker::CguReuse;
use rustc::hir::def_id::LOCAL_CRATE;
@@ -17,6 +18,7 @@
use rustc::util::common::time_ext;
use rustc_data_structures::fx::FxHashMap;
use rustc_codegen_ssa::{RLIB_BYTECODE_EXTENSION, ModuleCodegen, ModuleKind};
+use log::{info, debug};
use std::ffi::{CStr, CString};
use std::ptr;
diff --git a/src/librustc_codegen_llvm/back/write.rs b/src/librustc_codegen_llvm/back/write.rs
index 48bbc13..796ea7a 100644
--- a/src/librustc_codegen_llvm/back/write.rs
+++ b/src/librustc_codegen_llvm/back/write.rs
@@ -10,6 +10,7 @@
use crate::context::{is_pie_binary, get_reloc_model};
use crate::common;
use crate::LlvmCodegenBackend;
+use rustc::bug;
use rustc::hir::def_id::LOCAL_CRATE;
use rustc_codegen_ssa::back::write::{CodegenContext, ModuleConfig, run_assembler};
use rustc_codegen_ssa::traits::*;
@@ -20,9 +21,10 @@
use rustc::util::common::time_ext;
use rustc_fs_util::{path_to_c_string, link_or_copy};
use rustc_data_structures::small_c_str::SmallCStr;
-use errors::{Handler, FatalError};
+use rustc_errors::{Handler, FatalError};
+use log::debug;
-use std::ffi::{CString, CStr};
+use std::ffi::CString;
use std::fs;
use std::io::{self, Write};
use std::path::{Path, PathBuf};
@@ -55,7 +57,7 @@
("local-exec", llvm::ThreadLocalMode::LocalExec),
];
-pub fn llvm_err(handler: &errors::Handler, msg: &str) -> FatalError {
+pub fn llvm_err(handler: &rustc_errors::Handler, msg: &str) -> FatalError {
match llvm::last_error() {
Some(err) => handler.fatal(&format!("{}: {}", msg, err)),
None => handler.fatal(&msg),
@@ -63,7 +65,7 @@
}
pub fn write_output_file(
- handler: &errors::Handler,
+ handler: &rustc_errors::Handler,
target: &'ll llvm::TargetMachine,
pm: &llvm::PassManager<'ll>,
m: &'ll llvm::Module,
@@ -588,14 +590,11 @@
cursor.position() as size_t
}
- with_codegen(tm, llmod, config.no_builtins, |cpm| {
- let result =
- llvm::LLVMRustPrintModule(cpm, llmod, out_c.as_ptr(), demangle_callback);
- llvm::LLVMDisposePassManager(cpm);
- result.into_result().map_err(|()| {
- let msg = format!("failed to write LLVM IR to {}", out.display());
- llvm_err(diag_handler, &msg)
- })
+ let result =
+ llvm::LLVMRustPrintModule(llmod, out_c.as_ptr(), demangle_callback);
+ result.into_result().map_err(|()| {
+ let msg = format!("failed to write LLVM IR to {}", out.display());
+ llvm_err(diag_handler, &msg)
})?;
}
@@ -836,8 +835,8 @@
})
.filter_map(|val| {
// Exclude some symbols that we know are not Rust symbols.
- let name = CStr::from_ptr(llvm::LLVMGetValueName(val));
- if ignored(name.to_bytes()) {
+ let name = llvm::get_value_name(val);
+ if ignored(name) {
None
} else {
Some((val, name))
@@ -845,7 +844,7 @@
})
.map(move |(val, name)| {
let mut imp_name = prefix.as_bytes().to_vec();
- imp_name.extend(name.to_bytes());
+ imp_name.extend(name);
let imp_name = CString::new(imp_name).unwrap();
(imp_name, val)
})
diff --git a/src/librustc_codegen_llvm/builder.rs b/src/librustc_codegen_llvm/builder.rs
index 6f72466..7509584 100644
--- a/src/librustc_codegen_llvm/builder.rs
+++ b/src/librustc_codegen_llvm/builder.rs
@@ -23,6 +23,8 @@
use std::ops::{Deref, Range};
use std::ptr;
use std::iter::TrustedLen;
+use rustc_data_structures::const_cstr;
+use log::debug;
// All Builders must have an llfn associated with them
#[must_use]
diff --git a/src/librustc_codegen_llvm/callee.rs b/src/librustc_codegen_llvm/callee.rs
index e0db7ca..c0be87b 100644
--- a/src/librustc_codegen_llvm/callee.rs
+++ b/src/librustc_codegen_llvm/callee.rs
@@ -10,6 +10,7 @@
use crate::context::CodegenCx;
use crate::value::Value;
use rustc_codegen_ssa::traits::*;
+use log::debug;
use rustc::ty::{TypeFoldable, Instance};
use rustc::ty::layout::{FnAbiExt, HasTyCtxt};
diff --git a/src/librustc_codegen_llvm/common.rs b/src/librustc_codegen_llvm/common.rs
index f38f9df..ff03c1f 100644
--- a/src/librustc_codegen_llvm/common.rs
+++ b/src/librustc_codegen_llvm/common.rs
@@ -8,6 +8,8 @@
use crate::type_of::LayoutLlvmExt;
use crate::value::Value;
use rustc_codegen_ssa::traits::*;
+use rustc::bug;
+use log::debug;
use crate::consts::const_alloc_to_llvm;
use rustc::ty::layout::{HasDataLayout, LayoutOf, self, TyLayout, Size};
@@ -245,11 +247,7 @@
let (mut lo, mut hi) = (0u64, 0u64);
let success = llvm::LLVMRustConstInt128Get(v, sign_ext,
&mut hi, &mut lo);
- if success {
- Some(hi_lo_to_u128(lo, hi))
- } else {
- None
- }
+ success.then_some(hi_lo_to_u128(lo, hi))
})
}
diff --git a/src/librustc_codegen_llvm/consts.rs b/src/librustc_codegen_llvm/consts.rs
index 541b3d9..11a105c 100644
--- a/src/librustc_codegen_llvm/consts.rs
+++ b/src/librustc_codegen_llvm/consts.rs
@@ -16,12 +16,14 @@
use rustc_codegen_ssa::traits::*;
use syntax::symbol::{Symbol, sym};
use syntax_pos::Span;
+use rustc::{bug, span_bug};
+use log::debug;
use rustc::ty::layout::{self, Size, Align, LayoutOf};
use rustc::hir::{self, CodegenFnAttrs, CodegenFnAttrFlags};
-use std::ffi::{CStr, CString};
+use std::ffi::CStr;
pub fn const_alloc_to_llvm(cx: &CodegenCx<'ll, '_>, alloc: &Allocation) -> &'ll Value {
let mut llvals = Vec::with_capacity(alloc.relocations().len() + 1);
@@ -392,16 +394,14 @@
} else {
// If we created the global with the wrong type,
// correct the type.
- let empty_string = const_cstr!("");
- let name_str_ref = CStr::from_ptr(llvm::LLVMGetValueName(g));
- let name_string = CString::new(name_str_ref.to_bytes()).unwrap();
- llvm::LLVMSetValueName(g, empty_string.as_ptr());
+ let name = llvm::get_value_name(g).to_vec();
+ llvm::set_value_name(g, b"");
let linkage = llvm::LLVMRustGetLinkage(g);
let visibility = llvm::LLVMRustGetVisibility(g);
let new_g = llvm::LLVMRustGetOrInsertGlobal(
- self.llmod, name_string.as_ptr(), val_llty);
+ self.llmod, name.as_ptr().cast(), name.len(), val_llty);
llvm::LLVMRustSetLinkage(new_g, linkage);
llvm::LLVMRustSetVisibility(new_g, visibility);
diff --git a/src/librustc_codegen_llvm/context.rs b/src/librustc_codegen_llvm/context.rs
index 39ea1f6..2c894a5 100644
--- a/src/librustc_codegen_llvm/context.rs
+++ b/src/librustc_codegen_llvm/context.rs
@@ -12,6 +12,7 @@
use rustc_data_structures::base_n;
use rustc_data_structures::small_c_str::SmallCStr;
+use rustc::bug;
use rustc::mir::mono::CodegenUnit;
use rustc::session::config::{self, DebugInfo};
use rustc::session::Session;
@@ -23,6 +24,7 @@
use rustc_target::spec::{HasTargetSpec, Target};
use rustc_codegen_ssa::base::wants_msvc_seh;
use crate::callee::get_fn;
+use rustc_data_structures::const_cstr;
use std::ffi::CStr;
use std::cell::{Cell, RefCell};
diff --git a/src/librustc_codegen_llvm/debuginfo/gdb.rs b/src/librustc_codegen_llvm/debuginfo/gdb.rs
index 9ed1c17..739437a 100644
--- a/src/librustc_codegen_llvm/debuginfo/gdb.rs
+++ b/src/librustc_codegen_llvm/debuginfo/gdb.rs
@@ -7,6 +7,7 @@
use crate::value::Value;
use rustc::session::config::DebugInfo;
use rustc_codegen_ssa::traits::*;
+use rustc::bug;
use syntax::attr;
use syntax::symbol::sym;
diff --git a/src/librustc_codegen_llvm/debuginfo/metadata.rs b/src/librustc_codegen_llvm/debuginfo/metadata.rs
index 1847e4e..8327ff2 100644
--- a/src/librustc_codegen_llvm/debuginfo/metadata.rs
+++ b/src/librustc_codegen_llvm/debuginfo/metadata.rs
@@ -35,10 +35,13 @@
use rustc::util::nodemap::FxHashMap;
use rustc_fs_util::path_to_c_string;
use rustc_data_structures::small_c_str::SmallCStr;
+use rustc_data_structures::const_cstr;
use rustc_target::abi::HasDataLayout;
use syntax::ast;
use syntax::symbol::{Interner, Symbol};
use syntax_pos::{self, Span, FileName};
+use rustc::{bug, span_bug};
+use log::debug;
use libc::{c_uint, c_longlong};
use std::collections::hash_map::Entry;
diff --git a/src/librustc_codegen_llvm/debuginfo/mod.rs b/src/librustc_codegen_llvm/debuginfo/mod.rs
index c2359a2..1de298d 100644
--- a/src/librustc_codegen_llvm/debuginfo/mod.rs
+++ b/src/librustc_codegen_llvm/debuginfo/mod.rs
@@ -32,7 +32,8 @@
use libc::c_uint;
use std::cell::RefCell;
-use std::ffi::{CStr, CString};
+use std::ffi::CString;
+use log::debug;
use smallvec::SmallVec;
use syntax_pos::{self, BytePos, Span, Pos};
@@ -255,23 +256,11 @@
return;
}
- let old_name = unsafe {
- CStr::from_ptr(llvm::LLVMGetValueName(value))
- };
- match old_name.to_str() {
- Ok("") => {}
- Ok(_) => {
- // Avoid replacing the name if it already exists.
- // While we could combine the names somehow, it'd
- // get noisy quick, and the usefulness is dubious.
- return;
- }
- Err(_) => return,
- }
-
- let cname = SmallCStr::new(name);
- unsafe {
- llvm::LLVMSetValueName(value, cname.as_ptr());
+ // Avoid replacing the name if it already exists.
+ // While we could combine the names somehow, it'd
+ // get noisy quick, and the usefulness is dubious.
+ if llvm::get_value_name(value).is_empty() {
+ llvm::set_value_name(value, name.as_bytes());
}
}
}
diff --git a/src/librustc_codegen_llvm/debuginfo/source_loc.rs b/src/librustc_codegen_llvm/debuginfo/source_loc.rs
index ccb3bde..82183fa 100644
--- a/src/librustc_codegen_llvm/debuginfo/source_loc.rs
+++ b/src/librustc_codegen_llvm/debuginfo/source_loc.rs
@@ -8,6 +8,7 @@
use crate::llvm::debuginfo::DIScope;
use crate::builder::Builder;
use rustc_codegen_ssa::traits::*;
+use log::debug;
use libc::c_uint;
use syntax_pos::{Span, Pos};
diff --git a/src/librustc_codegen_llvm/declare.rs b/src/librustc_codegen_llvm/declare.rs
index 8b6fedc..5144b92 100644
--- a/src/librustc_codegen_llvm/declare.rs
+++ b/src/librustc_codegen_llvm/declare.rs
@@ -22,6 +22,7 @@
use rustc::session::config::Sanitizer;
use rustc_data_structures::small_c_str::SmallCStr;
use rustc_codegen_ssa::traits::*;
+use log::debug;
/// Declare a function.
///
@@ -76,9 +77,8 @@
name: &str, ty: &'ll Type
) -> &'ll Value {
debug!("declare_global(name={:?})", name);
- let namebuf = SmallCStr::new(name);
unsafe {
- llvm::LLVMRustGetOrInsertGlobal(self.llmod, namebuf.as_ptr(), ty)
+ llvm::LLVMRustGetOrInsertGlobal(self.llmod, name.as_ptr().cast(), name.len(), ty)
}
}
diff --git a/src/librustc_codegen_llvm/intrinsic.rs b/src/librustc_codegen_llvm/intrinsic.rs
index 9df75a8..900f2d2 100644
--- a/src/librustc_codegen_llvm/intrinsic.rs
+++ b/src/librustc_codegen_llvm/intrinsic.rs
@@ -19,6 +19,7 @@
use rustc::hir;
use rustc_target::abi::HasDataLayout;
use syntax::ast;
+use rustc::{bug, span_bug};
use rustc_codegen_ssa::common::span_invalid_monomorphization_error;
use rustc_codegen_ssa::traits::*;
@@ -516,9 +517,36 @@
return;
}
}
-
},
+ "float_to_int_approx_unchecked" => {
+ if float_type_width(arg_tys[0]).is_none() {
+ span_invalid_monomorphization_error(
+ tcx.sess, span,
+ &format!("invalid monomorphization of `float_to_int_approx_unchecked` \
+ intrinsic: expected basic float type, \
+ found `{}`", arg_tys[0]));
+ return;
+ }
+ match int_type_width_signed(ret_ty, self.cx) {
+ Some((width, signed)) => {
+ if signed {
+ self.fptosi(args[0].immediate(), self.cx.type_ix(width))
+ } else {
+ self.fptoui(args[0].immediate(), self.cx.type_ix(width))
+ }
+ }
+ None => {
+ span_invalid_monomorphization_error(
+ tcx.sess, span,
+ &format!("invalid monomorphization of `float_to_int_approx_unchecked` \
+ intrinsic: expected basic integer type, \
+ found `{}`", ret_ty));
+ return;
+ }
+ }
+ }
+
"discriminant_value" => {
args[0].deref(self.cx()).codegen_get_discr(self, ret_ty)
}
diff --git a/src/librustc_codegen_llvm/lib.rs b/src/librustc_codegen_llvm/lib.rs
index 2ff5872..1e1d74c 100644
--- a/src/librustc_codegen_llvm/lib.rs
+++ b/src/librustc_codegen_llvm/lib.rs
@@ -6,6 +6,7 @@
#![doc(html_root_url = "https://doc.rust-lang.org/nightly/")]
+#![feature(bool_to_option)]
#![feature(box_patterns)]
#![feature(box_syntax)]
#![feature(const_cstr_unchecked)]
@@ -23,33 +24,11 @@
use back::write::{create_target_machine, create_informational_target_machine};
use syntax_pos::symbol::Symbol;
-extern crate rustc_demangle;
-extern crate flate2;
-#[macro_use] extern crate bitflags;
-extern crate libc;
-#[macro_use] extern crate rustc;
-extern crate rustc_target;
-#[macro_use] extern crate rustc_data_structures;
-extern crate rustc_feature;
-extern crate rustc_index;
-extern crate rustc_incremental;
-extern crate rustc_codegen_utils;
-extern crate rustc_codegen_ssa;
-extern crate rustc_fs_util;
-extern crate rustc_driver as _;
-
-#[macro_use] extern crate log;
-extern crate smallvec;
-extern crate syntax;
-extern crate syntax_pos;
-extern crate rustc_errors as errors;
-extern crate rustc_session;
-
use rustc_codegen_ssa::traits::*;
use rustc_codegen_ssa::back::write::{CodegenContext, ModuleConfig, FatLTOInput};
use rustc_codegen_ssa::back::lto::{SerializedModule, LtoModuleCodegen, ThinModule};
use rustc_codegen_ssa::CompiledModule;
-use errors::{FatalError, Handler};
+use rustc_errors::{FatalError, Handler};
use rustc::dep_graph::WorkProduct;
use syntax::expand::allocator::AllocatorKind;
pub use llvm_util::target_features;
@@ -338,12 +317,6 @@
}
}
-/// This is the entrypoint for a hot plugged rustc_codegen_llvm
-#[no_mangle]
-pub fn __rustc_codegen_backend() -> Box<dyn CodegenBackend> {
- LlvmCodegenBackend::new()
-}
-
pub struct ModuleLlvm {
llcx: &'static mut llvm::Context,
llmod_raw: *const llvm::Module,
diff --git a/src/librustc_codegen_llvm/llvm/ffi.rs b/src/librustc_codegen_llvm/llvm/ffi.rs
index fd31e65..b8a1003 100644
--- a/src/librustc_codegen_llvm/llvm/ffi.rs
+++ b/src/librustc_codegen_llvm/llvm/ffi.rs
@@ -544,6 +544,7 @@
pub mod debuginfo {
use super::{InvariantOpaque, Metadata};
+ use bitflags::bitflags;
#[repr(C)]
pub struct DIBuilder<'a>(InvariantOpaque<'a>);
@@ -701,8 +702,8 @@
// Operations on all values
pub fn LLVMTypeOf(Val: &Value) -> &Type;
- pub fn LLVMGetValueName(Val: &Value) -> *const c_char;
- pub fn LLVMSetValueName(Val: &Value, Name: *const c_char);
+ pub fn LLVMGetValueName2(Val: &Value, Length: *mut size_t) -> *const c_char;
+ pub fn LLVMSetValueName2(Val: &Value, Name: *const c_char, NameLen: size_t);
pub fn LLVMReplaceAllUsesWith(OldVal: &'a Value, NewVal: &'a Value);
pub fn LLVMSetMetadata(Val: &'a Value, KindID: c_uint, Node: &'a Value);
@@ -774,7 +775,8 @@
pub fn LLVMIsAGlobalVariable(GlobalVar: &Value) -> Option<&Value>;
pub fn LLVMAddGlobal(M: &'a Module, Ty: &'a Type, Name: *const c_char) -> &'a Value;
pub fn LLVMGetNamedGlobal(M: &Module, Name: *const c_char) -> Option<&Value>;
- pub fn LLVMRustGetOrInsertGlobal(M: &'a Module, Name: *const c_char, T: &'a Type) -> &'a Value;
+ pub fn LLVMRustGetOrInsertGlobal(M: &'a Module, Name: *const c_char, NameLen: size_t,
+ T: &'a Type) -> &'a Value;
pub fn LLVMRustInsertPrivateGlobal(M: &'a Module, T: &'a Type) -> &'a Value;
pub fn LLVMGetFirstGlobal(M: &Module) -> Option<&Value>;
pub fn LLVMGetNextGlobal(GlobalVar: &Value) -> Option<&Value>;
@@ -1727,8 +1729,7 @@
Output: *const c_char,
FileType: FileType)
-> LLVMRustResult;
- pub fn LLVMRustPrintModule(PM: &PassManager<'a>,
- M: &'a Module,
+ pub fn LLVMRustPrintModule(M: &'a Module,
Output: *const c_char,
Demangle: extern fn(*const c_char,
size_t,
@@ -1812,7 +1813,7 @@
pub fn LLVMRustPositionBuilderAtStart(B: &Builder<'a>, BB: &'a BasicBlock);
- pub fn LLVMRustSetComdat(M: &'a Module, V: &'a Value, Name: *const c_char);
+ pub fn LLVMRustSetComdat(M: &'a Module, V: &'a Value, Name: *const c_char, NameLen: size_t);
pub fn LLVMRustUnsetComdat(V: &Value);
pub fn LLVMRustSetModulePICLevel(M: &Module);
pub fn LLVMRustSetModulePIELevel(M: &Module);
diff --git a/src/librustc_codegen_llvm/llvm/mod.rs b/src/librustc_codegen_llvm/llvm/mod.rs
index 5781593..9757567 100644
--- a/src/librustc_codegen_llvm/llvm/mod.rs
+++ b/src/librustc_codegen_llvm/llvm/mod.rs
@@ -10,11 +10,11 @@
use std::str::FromStr;
use std::string::FromUtf8Error;
-use std::slice;
use std::ffi::CStr;
use std::cell::RefCell;
-use libc::{c_uint, c_char, size_t};
+use libc::c_uint;
use rustc_data_structures::small_c_str::SmallCStr;
+use rustc_llvm::RustString;
pub mod archive_ro;
pub mod diagnostic;
@@ -81,21 +81,6 @@
}
}
-#[repr(C)]
-pub struct RustString {
- bytes: RefCell<Vec<u8>>,
-}
-
-/// Appending to a Rust string -- used by RawRustStringOstream.
-#[no_mangle]
-pub unsafe extern "C" fn LLVMRustStringWriteImpl(sr: &RustString,
- ptr: *const c_char,
- size: size_t) {
- let slice = slice::from_raw_parts(ptr as *const u8, size as usize);
-
- sr.bytes.borrow_mut().extend_from_slice(slice);
-}
-
pub fn SetInstructionCallConv(instr: &'a Value, cc: CallConv) {
unsafe {
LLVMSetInstructionCallConv(instr, cc as c_uint);
@@ -115,7 +100,8 @@
// For more details on COMDAT sections see e.g., http://www.airs.com/blog/archives/52
pub fn SetUniqueComdat(llmod: &Module, val: &'a Value) {
unsafe {
- LLVMRustSetComdat(llmod, val, LLVMGetValueName(val));
+ let name = get_value_name(val);
+ LLVMRustSetComdat(llmod, val, name.as_ptr().cast(), name.len());
}
}
@@ -217,6 +203,23 @@
}
}
+/// Safe wrapper for `LLVMGetValueName2` into a byte slice
+pub fn get_value_name(value: &'a Value) -> &'a [u8] {
+ unsafe {
+ let mut len = 0;
+ let data = LLVMGetValueName2(value, &mut len);
+ std::slice::from_raw_parts(data.cast(), len)
+ }
+}
+
+/// Safe wrapper for `LLVMSetValueName2` from a byte slice
+pub fn set_value_name(value: &Value, name: &[u8]) {
+ unsafe {
+ let data = name.as_ptr().cast();
+ LLVMSetValueName2(value, data, name.len());
+ }
+}
+
pub fn build_string(f: impl FnOnce(&RustString)) -> Result<String, FromUtf8Error> {
let sr = RustString {
bytes: RefCell::new(Vec::new()),
diff --git a/src/librustc_codegen_llvm/llvm_util.rs b/src/librustc_codegen_llvm/llvm_util.rs
index 72612c4..4073938 100644
--- a/src/librustc_codegen_llvm/llvm_util.rs
+++ b/src/librustc_codegen_llvm/llvm_util.rs
@@ -8,6 +8,7 @@
use std::ffi::CString;
use rustc_feature::UnstableFeatures;
use syntax::symbol::sym;
+use rustc::bug;
use std::str;
use std::slice;
diff --git a/src/librustc_codegen_llvm/metadata.rs b/src/librustc_codegen_llvm/metadata.rs
index cd72558..bbe42e3 100644
--- a/src/librustc_codegen_llvm/metadata.rs
+++ b/src/librustc_codegen_llvm/metadata.rs
@@ -6,6 +6,8 @@
use rustc_data_structures::owning_ref::OwningRef;
use rustc_codegen_ssa::METADATA_FILENAME;
+use log::debug;
+use rustc_data_structures::rustc_erase_owner;
use std::path::Path;
use std::slice;
diff --git a/src/librustc_codegen_llvm/mono_item.rs b/src/librustc_codegen_llvm/mono_item.rs
index cbc8af4..9f6bdd2 100644
--- a/src/librustc_codegen_llvm/mono_item.rs
+++ b/src/librustc_codegen_llvm/mono_item.rs
@@ -9,6 +9,7 @@
use rustc::ty::{TypeFoldable, Instance};
use rustc::ty::layout::{FnAbiExt, LayoutOf};
use rustc_codegen_ssa::traits::*;
+use log::debug;
pub use rustc::mir::mono::MonoItem;
diff --git a/src/librustc_codegen_llvm/type_.rs b/src/librustc_codegen_llvm/type_.rs
index f936367..e6677f3 100644
--- a/src/librustc_codegen_llvm/type_.rs
+++ b/src/librustc_codegen_llvm/type_.rs
@@ -5,6 +5,7 @@
use crate::context::CodegenCx;
use crate::value::Value;
use rustc_codegen_ssa::traits::*;
+use rustc::bug;
use crate::common;
use crate::type_of::LayoutLlvmExt;
diff --git a/src/librustc_codegen_llvm/type_of.rs b/src/librustc_codegen_llvm/type_of.rs
index d77bbb2..f9cbf4b 100644
--- a/src/librustc_codegen_llvm/type_of.rs
+++ b/src/librustc_codegen_llvm/type_of.rs
@@ -6,6 +6,8 @@
use rustc_target::abi::TyLayoutMethods;
use rustc::ty::print::obsolete::DefPathBasedNames;
use rustc_codegen_ssa::traits::*;
+use log::debug;
+use rustc::bug;
use std::fmt::Write;
diff --git a/src/librustc_codegen_ssa/Cargo.toml b/src/librustc_codegen_ssa/Cargo.toml
index 53d3c51..d489852 100644
--- a/src/librustc_codegen_ssa/Cargo.toml
+++ b/src/librustc_codegen_ssa/Cargo.toml
@@ -13,7 +13,7 @@
bitflags = "1.2.1"
cc = "1.0.1"
num_cpus = "1.0"
-memmap = "0.6"
+memmap = "0.7"
log = "0.4.5"
libc = "0.2.44"
jobserver = "0.1.11"
diff --git a/src/librustc_codegen_ssa/back/rpath.rs b/src/librustc_codegen_ssa/back/rpath.rs
index e27cb6d..cd3d999 100644
--- a/src/librustc_codegen_ssa/back/rpath.rs
+++ b/src/librustc_codegen_ssa/back/rpath.rs
@@ -119,11 +119,7 @@
use std::path::Component;
if path.is_absolute() != base.is_absolute() {
- if path.is_absolute() {
- Some(PathBuf::from(path))
- } else {
- None
- }
+ path.is_absolute().then(|| PathBuf::from(path))
} else {
let mut ita = path.components();
let mut itb = base.components();
diff --git a/src/librustc_codegen_ssa/back/symbol_export.rs b/src/librustc_codegen_ssa/back/symbol_export.rs
index f8b3e0f..cea5dc1 100644
--- a/src/librustc_codegen_ssa/back/symbol_export.rs
+++ b/src/librustc_codegen_ssa/back/symbol_export.rs
@@ -85,11 +85,7 @@
match tcx.hir().get(hir_id) {
Node::ForeignItem(..) => {
let def_id = tcx.hir().local_def_id(hir_id);
- if tcx.is_statically_included_foreign_item(def_id) {
- Some(def_id)
- } else {
- None
- }
+ tcx.is_statically_included_foreign_item(def_id).then_some(def_id)
}
// Only consider nodes that actually have exported symbols.
diff --git a/src/librustc_codegen_ssa/lib.rs b/src/librustc_codegen_ssa/lib.rs
index 9784d87..9919666 100644
--- a/src/librustc_codegen_ssa/lib.rs
+++ b/src/librustc_codegen_ssa/lib.rs
@@ -1,5 +1,6 @@
#![doc(html_root_url = "https://doc.rust-lang.org/nightly/")]
+#![feature(bool_to_option)]
#![feature(box_patterns)]
#![feature(box_syntax)]
#![feature(core_intrinsics)]
@@ -68,22 +69,14 @@
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 {
- None
- };
- let bytecode = if emit_bc {
- Some(outputs.temp_path(OutputType::Bitcode, Some(&self.name)))
- } else {
- None
- };
- let bytecode_compressed = if emit_bc_compressed {
- Some(outputs.temp_path(OutputType::Bitcode, Some(&self.name))
- .with_extension(RLIB_BYTECODE_EXTENSION))
- } else {
- None
- };
+ let object = emit_obj
+ .then(|| outputs.temp_path(OutputType::Object, Some(&self.name)));
+ let bytecode = emit_bc
+ .then(|| outputs.temp_path(OutputType::Bitcode, Some(&self.name)));
+ let bytecode_compressed = emit_bc_compressed.then(|| {
+ outputs.temp_path(OutputType::Bitcode, Some(&self.name))
+ .with_extension(RLIB_BYTECODE_EXTENSION)
+ });
CompiledModule {
name: self.name.clone(),
diff --git a/src/librustc_codegen_ssa/mir/block.rs b/src/librustc_codegen_ssa/mir/block.rs
index 6dccf32..dabd097 100644
--- a/src/librustc_codegen_ssa/mir/block.rs
+++ b/src/librustc_codegen_ssa/mir/block.rs
@@ -153,7 +153,7 @@
// a loop.
fn maybe_sideeffect<Bx: BuilderMethods<'a, 'tcx>>(
&self,
- mir: mir::ReadOnlyBodyCache<'tcx, 'tcx>,
+ mir: mir::ReadOnlyBodyAndCache<'tcx, 'tcx>,
bx: &mut Bx,
targets: &[mir::BasicBlock],
) {
@@ -261,7 +261,11 @@
if self.fn_abi.ret.layout.abi.is_uninhabited() {
// Functions with uninhabited return values are marked `noreturn`,
// so we should make sure that we never actually do.
+ // We play it safe by using a well-defined `abort`, but we could go for immediate UB
+ // if that turns out to be helpful.
bx.abort();
+ // `abort` does not terminate the block, so we still need to generate
+ // an `unreachable` terminator after it.
bx.unreachable();
return;
}
@@ -714,7 +718,7 @@
'descend_newtypes: while !op.layout.ty.is_unsafe_ptr()
&& !op.layout.ty.is_region_ptr()
{
- 'iter_fields: for i in 0..op.layout.fields.count() {
+ for i in 0..op.layout.fields.count() {
let field = op.extract_field(&mut bx, i);
if !field.layout.is_zst() {
// we found the one non-zero-sized field that is allowed
@@ -770,6 +774,18 @@
&fn_abi.args[first_args.len()..])
}
+ let needs_location =
+ instance.map_or(false, |i| i.def.requires_caller_location(self.cx.tcx()));
+ if needs_location {
+ assert_eq!(
+ fn_abi.args.len(), args.len() + 1,
+ "#[track_caller] fn's must have 1 more argument in their ABI than in their MIR",
+ );
+ let location = self.get_caller_location(&mut bx, span);
+ let last_arg = fn_abi.args.last().unwrap();
+ self.codegen_argument(&mut bx, location, &mut llargs, last_arg);
+ }
+
let fn_ptr = match (llfn, instance) {
(Some(llfn), _) => llfn,
(None, Some(instance)) => bx.get_fn_addr(instance),
@@ -825,6 +841,8 @@
mir::TerminatorKind::Abort => {
bx.abort();
+ // `abort` does not terminate the block, so we still need to generate
+ // an `unreachable` terminator after it.
bx.unreachable();
}
@@ -1004,14 +1022,16 @@
bx: &mut Bx,
span: Span,
) -> OperandRef<'tcx, Bx::Value> {
- let topmost = span.ctxt().outer_expn().expansion_cause().unwrap_or(span);
- let caller = bx.tcx().sess.source_map().lookup_char_pos(topmost.lo());
- let const_loc = bx.tcx().const_caller_location((
- Symbol::intern(&caller.file.name.to_string()),
- caller.line as u32,
- caller.col_display as u32 + 1,
- ));
- OperandRef::from_const(bx, const_loc)
+ self.caller_location.unwrap_or_else(|| {
+ let topmost = span.ctxt().outer_expn().expansion_cause().unwrap_or(span);
+ let caller = bx.tcx().sess.source_map().lookup_char_pos(topmost.lo());
+ let const_loc = bx.tcx().const_caller_location((
+ Symbol::intern(&caller.file.name.to_string()),
+ caller.line as u32,
+ caller.col_display as u32 + 1,
+ ));
+ OperandRef::from_const(bx, const_loc)
+ })
}
fn get_personality_slot(
diff --git a/src/librustc_codegen_ssa/mir/constant.rs b/src/librustc_codegen_ssa/mir/constant.rs
index 27891be6..fb8f504 100644
--- a/src/librustc_codegen_ssa/mir/constant.rs
+++ b/src/librustc_codegen_ssa/mir/constant.rs
@@ -16,6 +16,10 @@
constant: &mir::Constant<'tcx>,
) -> Result<OperandRef<'tcx, Bx::Value>, ErrorHandled> {
match constant.literal.val {
+ // Special case unevaluated statics, because statics have an identity and thus should
+ // use `get_static` to get at their id.
+ // FIXME(oli-obk): can we unify this somehow, maybe by making const eval of statics
+ // always produce `&STATIC`. This may also simplify how const eval works with statics.
ty::ConstKind::Unevaluated(def_id, substs)
if self.cx.tcx().is_static(def_id) => {
assert!(substs.is_empty(), "we don't support generic statics yet");
@@ -46,7 +50,10 @@
instance,
promoted: None,
};
- self.cx.tcx().const_eval(ty::ParamEnv::reveal_all().and(cid))
+ self.cx.tcx().const_eval(ty::ParamEnv::reveal_all().and(cid)).map_err(|err| {
+ self.cx.tcx().sess.span_err(constant.span, "erroneous constant encountered");
+ err
+ })
},
_ => Ok(self.monomorphize(&constant.literal)),
}
diff --git a/src/librustc_codegen_ssa/mir/mod.rs b/src/librustc_codegen_ssa/mir/mod.rs
index 3a157ca..e535aec 100644
--- a/src/librustc_codegen_ssa/mir/mod.rs
+++ b/src/librustc_codegen_ssa/mir/mod.rs
@@ -21,7 +21,7 @@
pub struct FunctionCx<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> {
instance: Instance<'tcx>,
- mir: mir::ReadOnlyBodyCache<'tcx, 'tcx>,
+ mir: mir::ReadOnlyBodyAndCache<'tcx, 'tcx>,
debug_context: Option<FunctionDebugContext<Bx::DIScope>>,
@@ -77,6 +77,9 @@
/// All `VarDebuginfo` from the MIR body, partitioned by `Local`.
/// This is `None` if no variable debuginfo/names are needed.
per_local_var_debug_info: Option<IndexVec<mir::Local, Vec<&'tcx mir::VarDebugInfo<'tcx>>>>,
+
+ /// Caller location propagated if this function has `#[track_caller]`.
+ caller_location: Option<OperandRef<'tcx, Bx::Value>>,
}
impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> {
@@ -156,7 +159,7 @@
}).collect();
let (landing_pads, funclets) = create_funclets(&mir, &mut bx, &cleanup_kinds, &block_bxs);
- let mir_body: &mir::Body<'_> = mir.body();
+ let mir_body: &mir::Body<'_> = *mir;
let mut fx = FunctionCx {
instance,
mir,
@@ -172,13 +175,14 @@
locals: IndexVec::new(),
debug_context,
per_local_var_debug_info: debuginfo::per_local_var_debug_info(cx.tcx(), mir_body),
+ caller_location: None,
};
let memory_locals = analyze::non_ssa_locals(&fx);
// Allocate variable and temp allocas
fx.locals = {
- let args = arg_local_refs(&mut bx, &fx, &memory_locals);
+ let args = arg_local_refs(&mut bx, &mut fx, &memory_locals);
let mut allocate_local = |local| {
let decl = &mir_body.local_decls[local];
@@ -320,14 +324,14 @@
/// indirect.
fn arg_local_refs<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>>(
bx: &mut Bx,
- fx: &FunctionCx<'a, 'tcx, Bx>,
+ fx: &mut FunctionCx<'a, 'tcx, Bx>,
memory_locals: &BitSet<mir::Local>,
) -> Vec<LocalRef<'tcx, Bx::Value>> {
let mir = fx.mir;
let mut idx = 0;
let mut llarg_idx = fx.fn_abi.ret.is_indirect() as usize;
- mir.args_iter().enumerate().map(|(arg_index, local)| {
+ let args = mir.args_iter().enumerate().map(|(arg_index, local)| {
let arg_decl = &mir.local_decls[local];
if Some(local) == mir.spread_arg {
@@ -423,7 +427,27 @@
bx.store_fn_arg(arg, &mut llarg_idx, tmp);
LocalRef::Place(tmp)
}
- }).collect()
+ }).collect::<Vec<_>>();
+
+ if fx.instance.def.requires_caller_location(bx.tcx()) {
+ assert_eq!(
+ fx.fn_abi.args.len(), args.len() + 1,
+ "#[track_caller] fn's must have 1 more argument in their ABI than in their MIR",
+ );
+
+ let arg = fx.fn_abi.args.last().unwrap();
+ match arg.mode {
+ PassMode::Direct(_) => (),
+ _ => bug!("caller location must be PassMode::Direct, found {:?}", arg.mode),
+ }
+
+ fx.caller_location = Some(OperandRef {
+ val: OperandValue::Immediate(bx.get_param(llarg_idx)),
+ layout: arg.layout,
+ });
+ }
+
+ args
}
mod analyze;
diff --git a/src/librustc_codegen_ssa/mir/operand.rs b/src/librustc_codegen_ssa/mir/operand.rs
index 310b8ae..a6dec81 100644
--- a/src/librustc_codegen_ssa/mir/operand.rs
+++ b/src/librustc_codegen_ssa/mir/operand.rs
@@ -475,9 +475,10 @@
},
}
// Allow RalfJ to sleep soundly knowing that even refactorings that remove
- // the above error (or silence it under some conditions) will not cause UB
+ // the above error (or silence it under some conditions) will not cause UB.
bx.abort();
- // We've errored, so we don't have to produce working code.
+ // We still have to return an operand but it doesn't matter,
+ // this code is unreachable.
let ty = self.monomorphize(&constant.literal.ty);
let layout = bx.cx().layout_of(ty);
bx.load_operand(PlaceRef::new_sized(
diff --git a/src/librustc_codegen_ssa/mir/place.rs b/src/librustc_codegen_ssa/mir/place.rs
index e250739..5e13cab 100644
--- a/src/librustc_codegen_ssa/mir/place.rs
+++ b/src/librustc_codegen_ssa/mir/place.rs
@@ -333,6 +333,9 @@
variant_index: VariantIdx
) {
if self.layout.for_variant(bx.cx(), variant_index).abi.is_uninhabited() {
+ // We play it safe by using a well-defined `abort`, but we could go for immediate UB
+ // if that turns out to be helpful.
+ bx.abort();
return;
}
match self.layout.variants {
@@ -488,10 +491,12 @@
},
Err(_) => {
// This is unreachable as long as runtime
- // and compile-time agree on values
+ // and compile-time agree perfectly.
// With floats that won't always be true,
- // so we generate an abort.
+ // so we generate a (safe) abort.
bx.abort();
+ // We still have to return a place but it doesn't matter,
+ // this code is unreachable.
let llval = bx.cx().const_undef(
bx.cx().type_ptr_to(bx.cx().backend_type(layout))
);
@@ -560,7 +565,7 @@
let llindex = bx.sub(lllen, lloffset);
cg_base.project_index(bx, llindex)
}
- mir::ProjectionElem::Subslice { from, to } => {
+ mir::ProjectionElem::Subslice { from, to, from_end } => {
let mut subslice = cg_base.project_index(bx,
bx.cx().const_usize(*from as u64));
let projected_ty = PlaceTy::from_ty(cg_base.layout.ty)
@@ -568,6 +573,7 @@
subslice.layout = bx.cx().layout_of(self.monomorphize(&projected_ty));
if subslice.layout.is_unsized() {
+ assert!(from_end, "slice subslices should be `from_end`");
subslice.llextra = Some(bx.sub(cg_base.llextra.unwrap(),
bx.cx().const_usize((*from as u64) + (*to as u64))));
}
diff --git a/src/librustc_data_structures/Cargo.toml b/src/librustc_data_structures/Cargo.toml
index 0fd4711..7fa40b8 100644
--- a/src/librustc_data_structures/Cargo.toml
+++ b/src/librustc_data_structures/Cargo.toml
@@ -26,7 +26,7 @@
smallvec = { version = "1.0", features = ["union", "may_dangle"] }
rustc_index = { path = "../librustc_index", package = "rustc_index" }
bitflags = "1.2.1"
-measureme = "0.4"
+measureme = "0.5"
[dependencies.parking_lot]
version = "0.9"
diff --git a/src/librustc_data_structures/obligation_forest/mod.rs b/src/librustc_data_structures/obligation_forest/mod.rs
index 8a5badd..b1931ca 100644
--- a/src/librustc_data_structures/obligation_forest/mod.rs
+++ b/src/librustc_data_structures/obligation_forest/mod.rs
@@ -128,21 +128,19 @@
::std::iter::Map<::std::ops::RangeFrom<usize>, fn(usize) -> ObligationTreeId>;
pub struct ObligationForest<O: ForestObligation> {
- /// The list of obligations. In between calls to
- /// `process_obligations`, this list only contains nodes in the
- /// `Pending` or `Success` state (with a non-zero number of
- /// incomplete children). During processing, some of those nodes
- /// may be changed to the error state, or we may find that they
- /// are completed (That is, `num_incomplete_children` drops to 0).
- /// At the end of processing, those nodes will be removed by a
- /// call to `compress`.
+ /// The list of obligations. In between calls to `process_obligations`,
+ /// this list only contains nodes in the `Pending` or `Success` state.
///
/// `usize` indices are used here and throughout this module, rather than
- /// `rustc_index::newtype_index!` indices, because this code is hot enough that the
- /// `u32`-to-`usize` conversions that would be required are significant,
- /// and space considerations are not important.
+ /// `rustc_index::newtype_index!` indices, because this code is hot enough
+ /// that the `u32`-to-`usize` conversions that would be required are
+ /// significant, and space considerations are not important.
nodes: Vec<Node<O>>,
+ /// The process generation is 1 on the first call to `process_obligations`,
+ /// 2 on the second call, etc.
+ gen: u32,
+
/// A cache of predicates that have been successfully completed.
done_cache: FxHashSet<O::Predicate>,
@@ -211,31 +209,61 @@
/// represents the current state of processing for the obligation (of
/// type `O`) associated with this node.
///
-/// Outside of ObligationForest methods, nodes should be either Pending
-/// or Waiting.
+/// The non-`Error` state transitions are as follows.
+/// ```
+/// (Pre-creation)
+/// |
+/// | register_obligation_at() (called by process_obligations() and
+/// v from outside the crate)
+/// Pending
+/// |
+/// | process_obligations()
+/// v
+/// Success(not_waiting())
+/// | |
+/// | | mark_still_waiting_nodes()
+/// | v
+/// | Success(still_waiting())
+/// | |
+/// | | compress()
+/// v v
+/// (Removed)
+/// ```
+/// The `Error` state can be introduced in several places, via `error_at()`.
+///
+/// Outside of `ObligationForest` methods, nodes should be either `Pending` or
+/// `Success`.
#[derive(Debug, Copy, Clone, PartialEq, Eq)]
enum NodeState {
- /// Obligations for which selection had not yet returned a
- /// non-ambiguous result.
+ /// This obligation has not yet been selected successfully. Cannot have
+ /// subobligations.
Pending,
- /// This obligation was selected successfully, but may or
- /// may not have subobligations.
- Success,
+ /// This obligation was selected successfully, but it may be waiting on one
+ /// or more pending subobligations, as indicated by the `WaitingState`.
+ Success(WaitingState),
- /// This obligation was selected successfully, but it has
- /// a pending subobligation.
- Waiting,
-
- /// This obligation, along with its subobligations, are complete,
- /// and will be removed in the next collection.
- Done,
-
- /// This obligation was resolved to an error. Error nodes are
- /// removed from the vector by the compression step.
+ /// This obligation was resolved to an error. It will be removed by the
+ /// next compression step.
Error,
}
+/// Indicates when a `Success` node was last (if ever) waiting on one or more
+/// `Pending` nodes. The notion of "when" comes from `ObligationForest::gen`.
+/// - 0: "Not waiting". This is a special value, set by `process_obligation`,
+/// and usable because generation counting starts at 1.
+/// - 1..ObligationForest::gen: "Was waiting" in a previous generation, but
+/// waiting no longer. In other words, finished.
+/// - ObligationForest::gen: "Still waiting" in this generation.
+///
+/// Things to note about this encoding:
+/// - Every time `ObligationForest::gen` is incremented, all the "still
+/// waiting" nodes automatically become "was waiting".
+/// - `ObligationForest::is_still_waiting` is very cheap.
+///
+#[derive(Clone, Copy, Debug, PartialEq, Eq, PartialOrd)]
+struct WaitingState(u32);
+
#[derive(Debug)]
pub struct Outcome<O, E> {
/// Obligations that were completely evaluated, including all
@@ -272,6 +300,7 @@
pub fn new() -> ObligationForest<O> {
ObligationForest {
nodes: vec![],
+ gen: 0,
done_cache: Default::default(),
active_cache: Default::default(),
node_rewrites: RefCell::new(vec![]),
@@ -300,10 +329,7 @@
match self.active_cache.entry(obligation.as_predicate().clone()) {
Entry::Occupied(o) => {
- let index = *o.get();
- debug!("register_obligation_at({:?}, {:?}) - duplicate of {:?}!",
- obligation, parent, index);
- let node = &mut self.nodes[index];
+ let node = &mut self.nodes[*o.get()];
if let Some(parent_index) = parent {
// If the node is already in `active_cache`, it has already
// had its chance to be marked with a parent. So if it's
@@ -320,9 +346,6 @@
}
}
Entry::Vacant(v) => {
- debug!("register_obligation_at({:?}, {:?}) - ok, new index is {}",
- obligation, parent, self.nodes.len());
-
let obligation_tree_id = match parent {
Some(parent_index) => self.nodes[parent_index].obligation_tree_id,
None => self.obligation_tree_id_generator.next().unwrap(),
@@ -382,6 +405,18 @@
.insert(node.obligation.as_predicate().clone());
}
+ fn not_waiting() -> WaitingState {
+ WaitingState(0)
+ }
+
+ fn still_waiting(&self) -> WaitingState {
+ WaitingState(self.gen)
+ }
+
+ fn is_still_waiting(&self, waiting: WaitingState) -> bool {
+ waiting.0 == self.gen
+ }
+
/// Performs a pass through the obligation list. This must
/// be called in a loop until `outcome.stalled` is false.
///
@@ -390,7 +425,7 @@
-> Outcome<O, P::Error>
where P: ObligationProcessor<Obligation=O>
{
- debug!("process_obligations(len={})", self.nodes.len());
+ self.gen += 1;
let mut errors = vec![];
let mut stalled = true;
@@ -407,8 +442,6 @@
while index < self.nodes.len() {
let node = &mut self.nodes[index];
- debug!("process_obligations: node {} == {:?}", index, node);
-
// `processor.process_obligation` can modify the predicate within
// `node.obligation`, and that predicate is the key used for
// `self.active_cache`. This means that `self.active_cache` can get
@@ -418,18 +451,15 @@
index += 1;
continue;
}
- let result = processor.process_obligation(&mut node.obligation);
- debug!("process_obligations: node {} got result {:?}", index, result);
-
- match result {
+ match processor.process_obligation(&mut node.obligation) {
ProcessResult::Unchanged => {
// No change in state.
}
ProcessResult::Changed(children) => {
// We are not (yet) stalled.
stalled = false;
- node.state.set(NodeState::Success);
+ node.state.set(NodeState::Success(Self::not_waiting()));
for child in children {
let st = self.register_obligation_at(
@@ -464,12 +494,10 @@
};
}
- self.mark_as_waiting();
+ self.mark_still_waiting_nodes();
self.process_cycles(processor);
let completed = self.compress(do_completed);
- debug!("process_obligations: complete");
-
Outcome {
completed,
errors,
@@ -477,56 +505,6 @@
}
}
- /// Mark all `NodeState::Success` nodes as `NodeState::Done` and
- /// report all cycles between them. This should be called
- /// after `mark_as_waiting` marks all nodes with pending
- /// subobligations as NodeState::Waiting.
- fn process_cycles<P>(&self, processor: &mut P)
- where P: ObligationProcessor<Obligation=O>
- {
- let mut stack = vec![];
-
- debug!("process_cycles()");
-
- for (index, node) in self.nodes.iter().enumerate() {
- // For some benchmarks this state test is extremely
- // hot. It's a win to handle the no-op cases immediately to avoid
- // the cost of the function call.
- if node.state.get() == NodeState::Success {
- self.find_cycles_from_node(&mut stack, processor, index);
- }
- }
-
- debug!("process_cycles: complete");
-
- debug_assert!(stack.is_empty());
- }
-
- fn find_cycles_from_node<P>(&self, stack: &mut Vec<usize>, processor: &mut P, index: usize)
- where P: ObligationProcessor<Obligation=O>
- {
- let node = &self.nodes[index];
- if node.state.get() == NodeState::Success {
- match stack.iter().rposition(|&n| n == index) {
- None => {
- stack.push(index);
- for &index in node.dependents.iter() {
- self.find_cycles_from_node(stack, processor, index);
- }
- stack.pop();
- node.state.set(NodeState::Done);
- }
- Some(rpos) => {
- // Cycle detected.
- processor.process_backedge(
- stack[rpos..].iter().map(GetObligation(&self.nodes)),
- PhantomData
- );
- }
- }
- }
- }
-
/// Returns a vector of obligations for `p` and all of its
/// ancestors, putting them into the error state in the process.
fn error_at(&self, mut index: usize) -> Vec<O> {
@@ -560,21 +538,28 @@
trace
}
+ /// Mark all `Success` nodes that depend on a pending node as still
+ /// waiting. Upon completion, any `Success` nodes that aren't still waiting
+ /// can be removed by `compress`.
+ fn mark_still_waiting_nodes(&self) {
+ for node in &self.nodes {
+ if node.state.get() == NodeState::Pending {
+ // This call site is hot.
+ self.inlined_mark_dependents_as_still_waiting(node);
+ }
+ }
+ }
+
// This always-inlined function is for the hot call site.
#[inline(always)]
- fn inlined_mark_neighbors_as_waiting_from(&self, node: &Node<O>) {
+ fn inlined_mark_dependents_as_still_waiting(&self, node: &Node<O>) {
for &index in node.dependents.iter() {
let node = &self.nodes[index];
- match node.state.get() {
- NodeState::Waiting | NodeState::Error => {}
- NodeState::Success => {
- node.state.set(NodeState::Waiting);
+ if let NodeState::Success(waiting) = node.state.get() {
+ if !self.is_still_waiting(waiting) {
+ node.state.set(NodeState::Success(self.still_waiting()));
// This call site is cold.
- self.uninlined_mark_neighbors_as_waiting_from(node);
- }
- NodeState::Pending | NodeState::Done => {
- // This call site is cold.
- self.uninlined_mark_neighbors_as_waiting_from(node);
+ self.uninlined_mark_dependents_as_still_waiting(node);
}
}
}
@@ -582,31 +567,65 @@
// This never-inlined function is for the cold call site.
#[inline(never)]
- fn uninlined_mark_neighbors_as_waiting_from(&self, node: &Node<O>) {
- self.inlined_mark_neighbors_as_waiting_from(node)
+ fn uninlined_mark_dependents_as_still_waiting(&self, node: &Node<O>) {
+ self.inlined_mark_dependents_as_still_waiting(node)
}
- /// Marks all nodes that depend on a pending node as `NodeState::Waiting`.
- fn mark_as_waiting(&self) {
- for node in &self.nodes {
- if node.state.get() == NodeState::Waiting {
- node.state.set(NodeState::Success);
+ /// Report cycles between all `Success` nodes that aren't still waiting.
+ /// This must be called after `mark_still_waiting_nodes`.
+ fn process_cycles<P>(&self, processor: &mut P)
+ where P: ObligationProcessor<Obligation=O>
+ {
+ let mut stack = vec![];
+
+ for (index, node) in self.nodes.iter().enumerate() {
+ // For some benchmarks this state test is extremely hot. It's a win
+ // to handle the no-op cases immediately to avoid the cost of the
+ // function call.
+ if let NodeState::Success(waiting) = node.state.get() {
+ if !self.is_still_waiting(waiting) {
+ self.find_cycles_from_node(&mut stack, processor, index, index);
+ }
}
}
- for node in &self.nodes {
- if node.state.get() == NodeState::Pending {
- // This call site is hot.
- self.inlined_mark_neighbors_as_waiting_from(node);
+ debug_assert!(stack.is_empty());
+ }
+
+ fn find_cycles_from_node<P>(&self, stack: &mut Vec<usize>, processor: &mut P, min_index: usize,
+ index: usize)
+ where P: ObligationProcessor<Obligation=O>
+ {
+ let node = &self.nodes[index];
+ if let NodeState::Success(waiting) = node.state.get() {
+ if !self.is_still_waiting(waiting) {
+ match stack.iter().rposition(|&n| n == index) {
+ None => {
+ stack.push(index);
+ for &dep_index in node.dependents.iter() {
+ // The index check avoids re-considering a node.
+ if dep_index >= min_index {
+ self.find_cycles_from_node(stack, processor, min_index, dep_index);
+ }
+ }
+ stack.pop();
+ }
+ Some(rpos) => {
+ // Cycle detected.
+ processor.process_backedge(
+ stack[rpos..].iter().map(GetObligation(&self.nodes)),
+ PhantomData
+ );
+ }
+ }
}
}
}
/// Compresses the vector, removing all popped nodes. This adjusts the
- /// indices and hence invalidates any outstanding indices.
- ///
- /// Beforehand, all nodes must be marked as `Done` and no cycles
- /// on these nodes may be present. This is done by e.g., `process_cycles`.
+ /// indices and hence invalidates any outstanding indices. `process_cycles`
+ /// must be run beforehand to remove any cycles on not-still-waiting
+ /// `Success` nodes.
#[inline(never)]
fn compress(&mut self, do_completed: DoCompleted) -> Option<Vec<O>> {
let orig_nodes_len = self.nodes.len();
@@ -614,10 +633,10 @@
debug_assert!(node_rewrites.is_empty());
node_rewrites.extend(0..orig_nodes_len);
let mut dead_nodes = 0;
- let mut removed_done_obligations: Vec<O> = vec![];
+ let mut removed_success_obligations: Vec<O> = vec![];
- // Now move all Done/Error nodes to the end, preserving the order of
- // the Pending/Waiting nodes.
+ // Move removable nodes to the end, preserving the order of the
+ // remaining nodes.
//
// LOOP INVARIANT:
// self.nodes[0..index - dead_nodes] are the first remaining nodes
@@ -626,13 +645,19 @@
for index in 0..orig_nodes_len {
let node = &self.nodes[index];
match node.state.get() {
- NodeState::Pending | NodeState::Waiting => {
+ NodeState::Pending => {
if dead_nodes > 0 {
self.nodes.swap(index, index - dead_nodes);
node_rewrites[index] -= dead_nodes;
}
}
- NodeState::Done => {
+ NodeState::Success(waiting) if self.is_still_waiting(waiting) => {
+ if dead_nodes > 0 {
+ self.nodes.swap(index, index - dead_nodes);
+ node_rewrites[index] -= dead_nodes;
+ }
+ }
+ NodeState::Success(_) => {
// This lookup can fail because the contents of
// `self.active_cache` are not guaranteed to match those of
// `self.nodes`. See the comment in `process_obligation`
@@ -646,7 +671,7 @@
}
if do_completed == DoCompleted::Yes {
// Extract the success stories.
- removed_done_obligations.push(node.obligation.clone());
+ removed_success_obligations.push(node.obligation.clone());
}
node_rewrites[index] = orig_nodes_len;
dead_nodes += 1;
@@ -660,7 +685,6 @@
node_rewrites[index] = orig_nodes_len;
dead_nodes += 1;
}
- NodeState::Success => unreachable!()
}
}
@@ -674,7 +698,7 @@
self.node_rewrites.replace(node_rewrites);
if do_completed == DoCompleted::Yes {
- Some(removed_done_obligations)
+ Some(removed_success_obligations)
} else {
None
}
diff --git a/src/librustc_data_structures/profiling.rs b/src/librustc_data_structures/profiling.rs
index 86f59bf..f9bfe5a 100644
--- a/src/librustc_data_structures/profiling.rs
+++ b/src/librustc_data_structures/profiling.rs
@@ -7,7 +7,7 @@
use std::thread::ThreadId;
use std::u32;
-use measureme::{StringId, TimestampKind};
+use measureme::{StringId};
/// MmapSerializatioSink is faster on macOS and Linux
/// but FileSerializationSink is faster on Windows
@@ -63,8 +63,8 @@
("incr-cache-load", EventFilter::INCR_CACHE_LOADS),
];
-fn thread_id_to_u64(tid: ThreadId) -> u64 {
- unsafe { mem::transmute::<ThreadId, u64>(tid) }
+fn thread_id_to_u32(tid: ThreadId) -> u32 {
+ unsafe { mem::transmute::<ThreadId, u64>(tid) as u32 }
}
@@ -149,11 +149,10 @@
/// Record a query in-memory cache hit.
#[inline(always)]
pub fn query_cache_hit(&self, query_name: impl QueryName) {
- self.non_guard_query_event(
+ self.instant_query_event(
|profiler| profiler.query_cache_hit_event_kind,
query_name,
EventFilter::QUERY_CACHE_HITS,
- TimestampKind::Instant,
);
}
@@ -184,22 +183,20 @@
}
#[inline(always)]
- fn non_guard_query_event(
+ fn instant_query_event(
&self,
event_kind: fn(&SelfProfiler) -> StringId,
query_name: impl QueryName,
event_filter: EventFilter,
- timestamp_kind: TimestampKind
) {
drop(self.exec(event_filter, |profiler| {
let event_id = SelfProfiler::get_query_name_string_id(query_name);
- let thread_id = thread_id_to_u64(std::thread::current().id());
+ let thread_id = thread_id_to_u32(std::thread::current().id());
- profiler.profiler.record_event(
+ profiler.profiler.record_instant_event(
event_kind(profiler),
event_id,
thread_id,
- timestamp_kind,
);
TimingGuard::none()
@@ -306,7 +303,7 @@
event_kind: StringId,
event_id: StringId,
) -> TimingGuard<'a> {
- let thread_id = thread_id_to_u64(std::thread::current().id());
+ let thread_id = thread_id_to_u32(std::thread::current().id());
let raw_profiler = &profiler.profiler;
let timing_guard = raw_profiler.start_recording_interval_event(event_kind,
event_id,
diff --git a/src/librustc_data_structures/tiny_list.rs b/src/librustc_data_structures/tiny_list.rs
index 371f0f6..78cbc12 100644
--- a/src/librustc_data_structures/tiny_list.rs
+++ b/src/librustc_data_structures/tiny_list.rs
@@ -16,41 +16,29 @@
#[derive(Clone)]
pub struct TinyList<T: PartialEq> {
- head: Option<Element<T>>
+ head: Option<Element<T>>,
}
impl<T: PartialEq> TinyList<T> {
#[inline]
pub fn new() -> TinyList<T> {
- TinyList {
- head: None
- }
+ TinyList { head: None }
}
#[inline]
pub fn new_single(data: T) -> TinyList<T> {
- TinyList {
- head: Some(Element {
- data,
- next: None,
- })
- }
+ TinyList { head: Some(Element { data, next: None }) }
}
#[inline]
pub fn insert(&mut self, data: T) {
- self.head = Some(Element {
- data,
- next: self.head.take().map(Box::new)
- });
+ self.head = Some(Element { data, next: self.head.take().map(Box::new) });
}
#[inline]
pub fn remove(&mut self, data: &T) -> bool {
self.head = match self.head {
- Some(ref mut head) if head.data == *data => {
- head.next.take().map(|x| *x)
- }
+ Some(ref mut head) if head.data == *data => head.next.take().map(|x| *x),
Some(ref mut head) => return head.remove_next(data),
None => return false,
};
@@ -88,12 +76,16 @@
impl<T: PartialEq> Element<T> {
fn remove_next(&mut self, data: &T) -> bool {
- let new_next = match self.next {
- Some(ref mut next) if next.data == *data => next.next.take(),
- Some(ref mut next) => return next.remove_next(data),
- None => return false,
- };
- self.next = new_next;
- true
+ let mut n = self;
+ loop {
+ match n.next {
+ Some(ref mut next) if next.data == *data => {
+ n.next = next.next.take();
+ return true;
+ }
+ Some(ref mut next) => n = next,
+ None => return false,
+ }
+ }
}
}
diff --git a/src/librustc_data_structures/transitive_relation.rs b/src/librustc_data_structures/transitive_relation.rs
index a3926c1..bbf6999 100644
--- a/src/librustc_data_structures/transitive_relation.rs
+++ b/src/librustc_data_structures/transitive_relation.rs
@@ -373,6 +373,14 @@
}
matrix
}
+
+ /// Lists all the base edges in the graph: the initial _non-transitive_ set of element
+ /// relations, which will be later used as the basis for the transitive closure computation.
+ pub fn base_edges(&self) -> impl Iterator<Item=(&T, &T)> {
+ self.edges
+ .iter()
+ .map(move |edge| (&self.elements[edge.source.0], &self.elements[edge.target.0]))
+ }
}
/// Pare down is used as a step in the LUB computation. It edits the
diff --git a/src/librustc_driver/Cargo.toml b/src/librustc_driver/Cargo.toml
index d1cb4cb..043cfc5 100644
--- a/src/librustc_driver/Cargo.toml
+++ b/src/librustc_driver/Cargo.toml
@@ -32,3 +32,6 @@
rustc_resolve = { path = "../librustc_resolve" }
syntax = { path = "../libsyntax" }
syntax_pos = { path = "../libsyntax_pos" }
+
+[features]
+llvm = ['rustc_interface/llvm']
diff --git a/src/librustc_driver/lib.rs b/src/librustc_driver/lib.rs
index 0594550..3230e04 100644
--- a/src/librustc_driver/lib.rs
+++ b/src/librustc_driver/lib.rs
@@ -42,7 +42,7 @@
use rustc_codegen_utils::codegen_backend::CodegenBackend;
use errors::{PResult, registry::Registry};
use rustc_interface::{interface, Queries};
-use rustc_interface::util::get_codegen_sysroot;
+use rustc_interface::util::get_builtin_codegen_backend;
use rustc_data_structures::sync::SeqCst;
use rustc_feature::{find_gated_cfg, UnstableFeatures};
use rustc_serialize::json::ToJson;
@@ -765,7 +765,7 @@
println!("commit-date: {}", unw(commit_date_str()));
println!("host: {}", config::host_triple());
println!("release: {}", unw(release_str()));
- get_codegen_sysroot("llvm")().print_version();
+ get_builtin_codegen_backend("llvm")().print_version();
}
}
@@ -1059,7 +1059,7 @@
}
if cg_flags.iter().any(|x| *x == "passes=list") {
- get_codegen_sysroot("llvm")().print_passes();
+ get_builtin_codegen_backend("llvm")().print_passes();
return None;
}
diff --git a/src/librustc_error_codes/error_codes.rs b/src/librustc_error_codes/error_codes.rs
index 7f111b4..9c1bec3 100644
--- a/src/librustc_error_codes/error_codes.rs
+++ b/src/librustc_error_codes/error_codes.rs
@@ -18,7 +18,6 @@
E0013: include_str!("./error_codes/E0013.md"),
E0014: include_str!("./error_codes/E0014.md"),
E0015: include_str!("./error_codes/E0015.md"),
-E0017: include_str!("./error_codes/E0017.md"),
E0019: include_str!("./error_codes/E0019.md"),
E0023: include_str!("./error_codes/E0023.md"),
E0025: include_str!("./error_codes/E0025.md"),
@@ -347,6 +346,7 @@
E0623: include_str!("./error_codes/E0623.md"),
E0624: include_str!("./error_codes/E0624.md"),
E0626: include_str!("./error_codes/E0626.md"),
+E0631: include_str!("./error_codes/E0631.md"),
E0633: include_str!("./error_codes/E0633.md"),
E0635: include_str!("./error_codes/E0635.md"),
E0636: include_str!("./error_codes/E0636.md"),
@@ -580,7 +580,6 @@
// rustc_const_unstable attribute must be paired with stable/unstable
// attribute
E0630,
- E0631, // type mismatch in closure arguments
E0632, // cannot provide explicit generic arguments when `impl Trait` is
// used in argument position
E0634, // type has conflicting packed representaton hints
diff --git a/src/librustc_error_codes/error_codes/E0017.md b/src/librustc_error_codes/error_codes/E0017.md
deleted file mode 100644
index d5e6857..0000000
--- a/src/librustc_error_codes/error_codes/E0017.md
+++ /dev/null
@@ -1,20 +0,0 @@
-References in statics and constants may only refer to immutable values.
-
-Erroneous code example:
-
-```compile_fail,E0017
-static X: i32 = 1;
-const C: i32 = 2;
-
-// these three are not allowed:
-const CR: &mut i32 = &mut C;
-static STATIC_REF: &'static mut i32 = &mut X;
-static CONST_REF: &'static mut i32 = &mut C;
-```
-
-Statics are shared everywhere, and if they refer to mutable data one might
-violate memory safety since holding multiple mutable references to shared data
-is not allowed.
-
-If you really want global mutable state, try using `static mut` or a global
-`UnsafeCell`.
diff --git a/src/librustc_error_codes/error_codes/E0092.md b/src/librustc_error_codes/error_codes/E0092.md
index 2750a7d..e289534 100644
--- a/src/librustc_error_codes/error_codes/E0092.md
+++ b/src/librustc_error_codes/error_codes/E0092.md
@@ -1,4 +1,5 @@
-You tried to declare an undefined atomic operation function.
+An undefined atomic operation function was declared.
+
Erroneous code example:
```compile_fail,E0092
@@ -11,8 +12,8 @@
```
Please check you didn't make a mistake in the function's name. All intrinsic
-functions are defined in librustc_codegen_llvm/intrinsic.rs and in
-libcore/intrinsics.rs in the Rust source code. Example:
+functions are defined in `librustc_codegen_llvm/intrinsic.rs` and in
+`libcore/intrinsics.rs` in the Rust source code. Example:
```
#![feature(intrinsics)]
diff --git a/src/librustc_error_codes/error_codes/E0093.md b/src/librustc_error_codes/error_codes/E0093.md
index 9633f79..8e7de1a 100644
--- a/src/librustc_error_codes/error_codes/E0093.md
+++ b/src/librustc_error_codes/error_codes/E0093.md
@@ -1,4 +1,6 @@
-You declared an unknown intrinsic function. Erroneous code example:
+An unknown intrinsic function was declared.
+
+Erroneous code example:
```compile_fail,E0093
#![feature(intrinsics)]
@@ -15,8 +17,8 @@
```
Please check you didn't make a mistake in the function's name. All intrinsic
-functions are defined in librustc_codegen_llvm/intrinsic.rs and in
-libcore/intrinsics.rs in the Rust source code. Example:
+functions are defined in `librustc_codegen_llvm/intrinsic.rs` and in
+`libcore/intrinsics.rs` in the Rust source code. Example:
```
#![feature(intrinsics)]
diff --git a/src/librustc_error_codes/error_codes/E0094.md b/src/librustc_error_codes/error_codes/E0094.md
index 4d27f61..42baa65 100644
--- a/src/librustc_error_codes/error_codes/E0094.md
+++ b/src/librustc_error_codes/error_codes/E0094.md
@@ -1,4 +1,5 @@
-You gave an invalid number of type parameters to an intrinsic function.
+An invalid number of type parameters was given to an intrinsic function.
+
Erroneous code example:
```compile_fail,E0094
diff --git a/src/librustc_error_codes/error_codes/E0106.md b/src/librustc_error_codes/error_codes/E0106.md
index 8a49c1f..60ca1dd 100644
--- a/src/librustc_error_codes/error_codes/E0106.md
+++ b/src/librustc_error_codes/error_codes/E0106.md
@@ -2,7 +2,7 @@
inside a function signature, the problem may be with failing to adhere to the
lifetime elision rules (see below).
-Here are some simple examples of where you'll run into this error:
+Erroneous code examples:
```compile_fail,E0106
struct Foo1 { x: &bool }
@@ -27,7 +27,7 @@
For more background on lifetime elision see [the book][book-le].
The lifetime elision rules require that any function signature with an elided
-output lifetime must either have
+output lifetime must either have:
- exactly one input lifetime
- or, multiple input lifetimes, but the function must also be a method with a
diff --git a/src/librustc_error_codes/error_codes/E0107.md b/src/librustc_error_codes/error_codes/E0107.md
index bfe0d21..4d22b17 100644
--- a/src/librustc_error_codes/error_codes/E0107.md
+++ b/src/librustc_error_codes/error_codes/E0107.md
@@ -1,4 +1,6 @@
-This error means that an incorrect number of generic arguments were provided:
+An incorrect number of generic arguments were provided.
+
+Erroneous code example:
```compile_fail,E0107
struct Foo<T> { x: T }
@@ -9,6 +11,7 @@
// expected 1, found 2
fn foo<T, U>(x: T, y: U) {}
+fn f() {}
fn main() {
let x: bool = true;
@@ -16,12 +19,26 @@
// expected 2, found 1
foo::<bool, i32, i32>(x, 2, 4); // error: wrong number of type arguments:
// expected 2, found 3
+ f::<'static>(); // error: wrong number of lifetime arguments
+ // expected 0, found 1
}
+```
+When using/declaring an item with generic arguments, you must provide the exact
+same number:
+
+```
+struct Foo<T> { x: T }
+
+struct Bar<T> { x: Foo<T> } // ok!
+struct Baz<S, T> { x: Foo<S>, y: Foo<T> } // ok!
+
+fn foo<T, U>(x: T, y: U) {}
fn f() {}
fn main() {
- f::<'static>(); // error: wrong number of lifetime arguments:
- // expected 0, found 1
+ let x: bool = true;
+ foo::<bool, u32>(x, 12); // ok!
+ f(); // ok!
}
```
diff --git a/src/librustc_error_codes/error_codes/E0109.md b/src/librustc_error_codes/error_codes/E0109.md
index 5bc229a..2eab972 100644
--- a/src/librustc_error_codes/error_codes/E0109.md
+++ b/src/librustc_error_codes/error_codes/E0109.md
@@ -1,4 +1,5 @@
You tried to provide a generic argument to a type which doesn't need it.
+
Erroneous code example:
```compile_fail,E0109
diff --git a/src/librustc_error_codes/error_codes/E0116.md b/src/librustc_error_codes/error_codes/E0116.md
index 27759a4..ca849c2 100644
--- a/src/librustc_error_codes/error_codes/E0116.md
+++ b/src/librustc_error_codes/error_codes/E0116.md
@@ -1,11 +1,15 @@
-You can only define an inherent implementation for a type in the same crate
-where the type was defined. For example, an `impl` block as below is not allowed
-since `Vec` is defined in the standard library:
+An inherent implementation was defined for a type outside the current crate.
+
+Erroneous code example:
```compile_fail,E0116
impl Vec<u8> { } // error
```
+You can only define an inherent implementation for a type in the same crate
+where the type was defined. For example, an `impl` block as above is not allowed
+since `Vec` is defined in the standard library.
+
To fix this problem, you can do either of these things:
- define a trait that has the desired associated functions/types/constants and
diff --git a/src/librustc_error_codes/error_codes/E0117.md b/src/librustc_error_codes/error_codes/E0117.md
index bd36230..7fa211d 100644
--- a/src/librustc_error_codes/error_codes/E0117.md
+++ b/src/librustc_error_codes/error_codes/E0117.md
@@ -1,3 +1,11 @@
+The `Drop` trait was implemented on a non-struct type.
+
+Erroneous code example:
+
+```compile_fail,E0117
+impl Drop for u32 {}
+```
+
This error indicates a violation of one of Rust's orphan rules for trait
implementations. The rule prohibits any implementation of a foreign trait (a
trait defined in another crate) where
@@ -6,12 +14,6 @@
- all of the parameters being passed to the trait (if there are any) are also
foreign.
-Here's one example of this error:
-
-```compile_fail,E0117
-impl Drop for u32 {}
-```
-
To avoid this kind of error, ensure that at least one local type is referenced
by the `impl`:
diff --git a/src/librustc_error_codes/error_codes/E0118.md b/src/librustc_error_codes/error_codes/E0118.md
index baf35ff..5cb5f50 100644
--- a/src/librustc_error_codes/error_codes/E0118.md
+++ b/src/librustc_error_codes/error_codes/E0118.md
@@ -1,5 +1,7 @@
-You're trying to write an inherent implementation for something which isn't a
-struct nor an enum. Erroneous code example:
+An inherent implementation was defined for something which isn't a struct nor
+an enum.
+
+Erroneous code example:
```compile_fail,E0118
impl (u8, u8) { // error: no base type found for inherent implementation
diff --git a/src/librustc_error_codes/error_codes/E0119.md b/src/librustc_error_codes/error_codes/E0119.md
index 0af3bd4..e596349 100644
--- a/src/librustc_error_codes/error_codes/E0119.md
+++ b/src/librustc_error_codes/error_codes/E0119.md
@@ -1,5 +1,6 @@
There are conflicting trait implementations for the same type.
-Example of erroneous code:
+
+Erroneous code example:
```compile_fail,E0119
trait MyTrait {
diff --git a/src/librustc_error_codes/error_codes/E0478.md b/src/librustc_error_codes/error_codes/E0478.md
index 6634d9b..4bc5fde 100644
--- a/src/librustc_error_codes/error_codes/E0478.md
+++ b/src/librustc_error_codes/error_codes/E0478.md
@@ -21,8 +21,8 @@
```
trait Wedding<'t>: 't { }
-struct Prince<'kiss, 'SnowWhite: 'kiss> { // You say here that 'kiss must live
- // longer than 'SnowWhite.
+struct Prince<'kiss, 'SnowWhite: 'kiss> { // You say here that 'SnowWhite
+ // must live longer than 'kiss.
child: Box<Wedding<'kiss> + 'SnowWhite>, // And now it's all good!
}
```
diff --git a/src/librustc_error_codes/error_codes/E0631.md b/src/librustc_error_codes/error_codes/E0631.md
new file mode 100644
index 0000000..6188d5f
--- /dev/null
+++ b/src/librustc_error_codes/error_codes/E0631.md
@@ -0,0 +1,27 @@
+This error indicates a type mismatch in closure arguments.
+
+Erroneous code example:
+
+```compile_fail,E0631
+fn foo<F: Fn(i32)>(f: F) {
+}
+
+fn main() {
+ foo(|x: &str| {});
+}
+```
+
+The error occurs because `foo` accepts a closure that takes an `i32` argument,
+but in `main`, it is passed a closure with a `&str` argument.
+
+This can be resolved by changing the type annotation or removing it entirely
+if it can be inferred.
+
+```
+fn foo<F: Fn(i32)>(f: F) {
+}
+
+fn main() {
+ foo(|x: i32| {});
+}
+```
diff --git a/src/librustc_errors/diagnostic.rs b/src/librustc_errors/diagnostic.rs
index abec979..744f4a4 100644
--- a/src/librustc_errors/diagnostic.rs
+++ b/src/librustc_errors/diagnostic.rs
@@ -498,10 +498,20 @@
self
}
+ pub fn clear_code(&mut self) -> &mut Self {
+ self.code = None;
+ self
+ }
+
pub fn get_code(&self) -> Option<DiagnosticId> {
self.code.clone()
}
+ pub fn set_primary_message<M: Into<String>>(&mut self, msg: M) -> &mut Self {
+ self.message[0] = (msg.into(), Style::NoStyle);
+ self
+ }
+
pub fn message(&self) -> String {
self.message.iter().map(|i| i.0.as_str()).collect::<String>()
}
diff --git a/src/librustc_feature/active.rs b/src/librustc_feature/active.rs
index fc880b9..363621b 100644
--- a/src/librustc_feature/active.rs
+++ b/src/librustc_feature/active.rs
@@ -523,6 +523,9 @@
/// Allows the use of `#[cfg(sanitize = "option")]`; set when -Zsanitizer is used.
(active, cfg_sanitize, "1.41.0", Some(39699), None),
+ /// Allows using `&mut` in constant functions.
+ (active, const_mut_refs, "1.41.0", Some(57349), None),
+
// -------------------------------------------------------------------------
// feature-group-end: actual feature gates
// -------------------------------------------------------------------------
@@ -538,5 +541,4 @@
sym::or_patterns,
sym::let_chains,
sym::raw_dylib,
- sym::track_caller,
];
diff --git a/src/librustc_interface/Cargo.toml b/src/librustc_interface/Cargo.toml
index 7ab5ec2..58fd928 100644
--- a/src/librustc_interface/Cargo.toml
+++ b/src/librustc_interface/Cargo.toml
@@ -25,6 +25,7 @@
rustc_data_structures = { path = "../librustc_data_structures" }
rustc_codegen_ssa = { path = "../librustc_codegen_ssa" }
rustc_codegen_utils = { path = "../librustc_codegen_utils" }
+rustc_codegen_llvm = { path = "../librustc_codegen_llvm", optional = true }
rustc_metadata = { path = "../librustc_metadata" }
rustc_mir = { path = "../librustc_mir" }
rustc_passes = { path = "../librustc_passes" }
@@ -39,3 +40,6 @@
[dev-dependencies]
rustc_target = { path = "../librustc_target" }
+
+[features]
+llvm = ['rustc_codegen_llvm']
diff --git a/src/librustc_interface/lib.rs b/src/librustc_interface/lib.rs
index 76af434..9bb1878 100644
--- a/src/librustc_interface/lib.rs
+++ b/src/librustc_interface/lib.rs
@@ -1,3 +1,4 @@
+#![feature(bool_to_option)]
#![feature(box_syntax)]
#![feature(set_stdio)]
#![feature(nll)]
diff --git a/src/librustc_interface/passes.rs b/src/librustc_interface/passes.rs
index 2351843..2a4bc41 100644
--- a/src/librustc_interface/passes.rs
+++ b/src/librustc_interface/passes.rs
@@ -547,13 +547,7 @@
}
fn output_conflicts_with_dir(output_paths: &[PathBuf]) -> Option<PathBuf> {
- let check = |output_path: &PathBuf| {
- if output_path.is_dir() {
- Some(output_path.clone())
- } else {
- None
- }
- };
+ let check = |output_path: &PathBuf| output_path.is_dir().then(|| output_path.clone());
check_output(output_paths, check)
}
diff --git a/src/librustc_interface/queries.rs b/src/librustc_interface/queries.rs
index 6103d42..e429b4d 100644
--- a/src/librustc_interface/queries.rs
+++ b/src/librustc_interface/queries.rs
@@ -22,7 +22,7 @@
use syntax::{self, ast};
/// Represent the result of a query.
-/// This result can be stolen with the `take` method and returned with the `give` method.
+/// This result can be stolen with the `take` method and generated with the `compute` method.
pub struct Query<T> {
result: RefCell<Option<Result<T>>>,
}
@@ -37,7 +37,7 @@
}
/// Takes ownership of the query result. Further attempts to take or peek the query
- /// result will panic unless it is returned by calling the `give` method.
+ /// result will panic unless it is generated by calling the `compute` method.
pub fn take(&self) -> T {
self.result
.borrow_mut()
@@ -117,11 +117,9 @@
pub fn dep_graph_future(&self) -> Result<&Query<Option<DepGraphFuture>>> {
self.dep_graph_future.compute(|| {
- Ok(if self.session().opts.build_dep_graph() {
- Some(rustc_incremental::load_dep_graph(self.session()))
- } else {
- None
- })
+ Ok(self.session().opts.build_dep_graph().then(|| {
+ rustc_incremental::load_dep_graph(self.session())
+ }))
})
}
diff --git a/src/librustc_interface/tests.rs b/src/librustc_interface/tests.rs
index 4c630b5..d4b5e83 100644
--- a/src/librustc_interface/tests.rs
+++ b/src/librustc_interface/tests.rs
@@ -7,7 +7,7 @@
use rustc::session::config::{build_configuration, build_session_options, to_crate_config};
use rustc::session::config::{LtoCli, LinkerPluginLto, SwitchWithOptPath, ExternEntry};
use rustc::session::config::{Externs, OutputType, OutputTypes, SymbolManglingVersion};
-use rustc::session::config::{rustc_optgroups, Options, ErrorOutputType, Passes};
+use rustc::session::config::{rustc_optgroups, Options, ErrorOutputType, Passes, ExternLocation};
use rustc::session::{build_session, Session};
use rustc::session::search_paths::SearchPath;
use std::collections::{BTreeMap, BTreeSet};
@@ -38,14 +38,15 @@
fn new_public_extern_entry<S, I>(locations: I) -> ExternEntry
where
S: Into<String>,
- I: IntoIterator<Item = Option<S>>,
+ I: IntoIterator<Item = S>,
{
- let locations: BTreeSet<_> = locations.into_iter().map(|o| o.map(|s| s.into()))
+ let locations: BTreeSet<_> = locations.into_iter().map(|s| s.into())
.collect();
ExternEntry {
- locations,
- is_private_dep: false
+ location: ExternLocation::ExactPaths(locations),
+ is_private_dep: false,
+ add_prelude: true,
}
}
@@ -160,33 +161,33 @@
v1.externs = Externs::new(mk_map(vec![
(
String::from("a"),
- new_public_extern_entry(vec![Some("b"), Some("c")])
+ new_public_extern_entry(vec!["b", "c"])
),
(
String::from("d"),
- new_public_extern_entry(vec![Some("e"), Some("f")])
+ new_public_extern_entry(vec!["e", "f"])
),
]));
v2.externs = Externs::new(mk_map(vec![
(
String::from("d"),
- new_public_extern_entry(vec![Some("e"), Some("f")])
+ new_public_extern_entry(vec!["e", "f"])
),
(
String::from("a"),
- new_public_extern_entry(vec![Some("b"), Some("c")])
+ new_public_extern_entry(vec!["b", "c"])
),
]));
v3.externs = Externs::new(mk_map(vec![
(
String::from("a"),
- new_public_extern_entry(vec![Some("b"), Some("c")])
+ new_public_extern_entry(vec!["b", "c"])
),
(
String::from("d"),
- new_public_extern_entry(vec![Some("f"), Some("e")])
+ new_public_extern_entry(vec!["f", "e"])
),
]));
diff --git a/src/librustc_interface/util.rs b/src/librustc_interface/util.rs
index d8e20e1..c78b3ee 100644
--- a/src/librustc_interface/util.rs
+++ b/src/librustc_interface/util.rs
@@ -16,11 +16,9 @@
use rustc_metadata::dynamic_lib::DynamicLibrary;
use rustc_resolve::{self, Resolver};
use std::env;
-use std::env::consts::{DLL_PREFIX, DLL_SUFFIX};
use std::io::{self, Write};
use std::mem;
use std::path::{Path, PathBuf};
-use std::sync::atomic::{AtomicBool, Ordering};
use std::sync::{Arc, Mutex, Once};
use std::ops::DerefMut;
use smallvec::SmallVec;
@@ -107,11 +105,7 @@
fn get_stack_size() -> Option<usize> {
// FIXME: Hacks on hacks. If the env is trying to override the stack size
// then *don't* set it explicitly.
- if env::var_os("RUST_MIN_STACK").is_none() {
- Some(STACK_SIZE)
- } else {
- None
- }
+ env::var_os("RUST_MIN_STACK").is_none().then_some(STACK_SIZE)
}
struct Sink(Arc<Mutex<Vec<u8>>>);
@@ -253,7 +247,7 @@
filename if filename.contains(".") => {
load_backend_from_dylib(filename.as_ref())
}
- codegen_name => get_codegen_sysroot(codegen_name),
+ codegen_name => get_builtin_codegen_backend(codegen_name),
};
unsafe {
@@ -285,11 +279,7 @@
} else {
"rustc"
});
- if candidate.exists() {
- Some(candidate)
- } else {
- None
- }
+ candidate.exists().then_some(candidate)
})
.next()
}
@@ -392,83 +382,16 @@
}
}
-pub fn get_codegen_sysroot(backend_name: &str) -> fn() -> Box<dyn CodegenBackend> {
- // For now we only allow this function to be called once as it'll dlopen a
- // few things, which seems to work best if we only do that once. In
- // general this assertion never trips due to the once guard in `get_codegen_backend`,
- // but there's a few manual calls to this function in this file we protect
- // against.
- static LOADED: AtomicBool = AtomicBool::new(false);
- assert!(!LOADED.fetch_or(true, Ordering::SeqCst),
- "cannot load the default codegen backend twice");
-
- let target = session::config::host_triple();
- let sysroot_candidates = sysroot_candidates();
-
- let sysroot = sysroot_candidates.iter()
- .map(|sysroot| {
- let libdir = filesearch::relative_target_lib_path(&sysroot, &target);
- sysroot.join(libdir).with_file_name(
- option_env!("CFG_CODEGEN_BACKENDS_DIR").unwrap_or("codegen-backends"))
- })
- .filter(|f| {
- info!("codegen backend candidate: {}", f.display());
- f.exists()
- })
- .next();
- let sysroot = sysroot.unwrap_or_else(|| {
- let candidates = sysroot_candidates.iter()
- .map(|p| p.display().to_string())
- .collect::<Vec<_>>()
- .join("\n* ");
- let err = format!("failed to find a `codegen-backends` folder \
- in the sysroot candidates:\n* {}", candidates);
- early_error(ErrorOutputType::default(), &err);
- });
- info!("probing {} for a codegen backend", sysroot.display());
-
- let d = sysroot.read_dir().unwrap_or_else(|e| {
- let err = format!("failed to load default codegen backend, couldn't \
- read `{}`: {}", sysroot.display(), e);
- early_error(ErrorOutputType::default(), &err);
- });
-
- let mut file: Option<PathBuf> = None;
-
- let expected_name = format!("rustc_codegen_llvm-{}", backend_name);
- for entry in d.filter_map(|e| e.ok()) {
- let path = entry.path();
- let filename = match path.file_name().and_then(|s| s.to_str()) {
- Some(s) => s,
- None => continue,
- };
- if !(filename.starts_with(DLL_PREFIX) && filename.ends_with(DLL_SUFFIX)) {
- continue
- }
- let name = &filename[DLL_PREFIX.len() .. filename.len() - DLL_SUFFIX.len()];
- if name != expected_name {
- continue
- }
- if let Some(ref prev) = file {
- let err = format!("duplicate codegen backends found\n\
- first: {}\n\
- second: {}\n\
- ", prev.display(), path.display());
- early_error(ErrorOutputType::default(), &err);
- }
- file = Some(path.clone());
- }
-
- match file {
- Some(ref s) => return load_backend_from_dylib(s),
- None => {
- let err = format!("failed to load default codegen backend for `{}`, \
- no appropriate codegen dylib found in `{}`",
- backend_name, sysroot.display());
- early_error(ErrorOutputType::default(), &err);
+pub fn get_builtin_codegen_backend(backend_name: &str) -> fn() -> Box<dyn CodegenBackend> {
+ #[cfg(feature = "llvm")]
+ {
+ if backend_name == "llvm" {
+ return rustc_codegen_llvm::LlvmCodegenBackend::new;
}
}
+ let err = format!("unsupported builtin codegen backend `{}`", backend_name);
+ early_error(ErrorOutputType::default(), &err);
}
pub(crate) fn compute_crate_disambiguator(session: &Session) -> CrateDisambiguator {
diff --git a/src/librustc_lint/builtin.rs b/src/librustc_lint/builtin.rs
index 0fd7145f..10b00d3 100644
--- a/src/librustc_lint/builtin.rs
+++ b/src/librustc_lint/builtin.rs
@@ -1491,11 +1491,7 @@
match pred {
ty::Predicate::TypeOutlives(outlives) => {
let outlives = outlives.skip_binder();
- if outlives.0.is_param(index) {
- Some(outlives.1)
- } else {
- None
- }
+ outlives.0.is_param(index).then_some(outlives.1)
}
_ => None
}
@@ -1554,11 +1550,7 @@
}),
_ => false,
};
- if is_inferred {
- Some((i, bound.span()))
- } else {
- None
- }
+ is_inferred.then_some((i, bound.span()))
} else {
None
}
diff --git a/src/librustc_lint/lib.rs b/src/librustc_lint/lib.rs
index e60c025..b77f2cb 100644
--- a/src/librustc_lint/lib.rs
+++ b/src/librustc_lint/lib.rs
@@ -12,6 +12,7 @@
#![doc(html_root_url = "https://doc.rust-lang.org/nightly/")]
#![cfg_attr(test, feature(test))]
+#![feature(bool_to_option)]
#![feature(box_patterns)]
#![feature(box_syntax)]
#![feature(nll)]
@@ -340,7 +341,7 @@
"converted into hard error, see https://github.com/rust-lang/rust/issues/46205");
store.register_removed("legacy_constructor_visibility",
"converted into hard error, see https://github.com/rust-lang/rust/issues/39207");
- store.register_removed("legacy_disrectory_ownership",
+ store.register_removed("legacy_directory_ownership",
"converted into hard error, see https://github.com/rust-lang/rust/issues/37872");
store.register_removed("safe_extern_statics",
"converted into hard error, see https://github.com/rust-lang/rust/issues/36247");
diff --git a/src/librustc_lint/unused.rs b/src/librustc_lint/unused.rs
index f7de7ec..e6f39cc 100644
--- a/src/librustc_lint/unused.rs
+++ b/src/librustc_lint/unused.rs
@@ -355,7 +355,9 @@
match value.kind {
ast::ExprKind::Paren(ref inner) => {
if !Self::is_expr_parens_necessary(inner, followed_by_block) &&
- value.attrs.is_empty() {
+ value.attrs.is_empty() &&
+ !value.span.from_expansion()
+ {
let expr_text = if let Ok(snippet) = cx.sess().source_map()
.span_to_snippet(value.span) {
snippet
diff --git a/src/librustc_llvm/Cargo.toml b/src/librustc_llvm/Cargo.toml
index 0fe327d..4fc02e3 100644
--- a/src/librustc_llvm/Cargo.toml
+++ b/src/librustc_llvm/Cargo.toml
@@ -13,6 +13,9 @@
static-libstdcpp = []
emscripten = []
+[dependencies]
+libc = "0.2"
+
[build-dependencies]
build_helper = { path = "../build_helper" }
cc = "1.0.1"
diff --git a/src/librustc_llvm/lib.rs b/src/librustc_llvm/lib.rs
index 647d473..9c8943a 100644
--- a/src/librustc_llvm/lib.rs
+++ b/src/librustc_llvm/lib.rs
@@ -5,6 +5,26 @@
// NOTE: This crate only exists to allow linking on mingw targets.
+use std::cell::RefCell;
+use std::slice;
+use libc::{c_char, size_t};
+
+
+#[repr(C)]
+pub struct RustString {
+ pub bytes: RefCell<Vec<u8>>,
+}
+
+/// Appending to a Rust string -- used by RawRustStringOstream.
+#[no_mangle]
+pub unsafe extern "C" fn LLVMRustStringWriteImpl(sr: &RustString,
+ ptr: *const c_char,
+ size: size_t) {
+ let slice = slice::from_raw_parts(ptr as *const u8, size as usize);
+
+ sr.bytes.borrow_mut().extend_from_slice(slice);
+}
+
/// Initialize targets enabled by the build script via `cfg(llvm_component = "...")`.
/// N.B., this function can't be moved to `rustc_codegen_llvm` because of the `cfg`s.
pub fn initialize_available_targets() {
diff --git a/src/librustc_metadata/Cargo.toml b/src/librustc_metadata/Cargo.toml
index b70cc52..88d1c50 100644
--- a/src/librustc_metadata/Cargo.toml
+++ b/src/librustc_metadata/Cargo.toml
@@ -12,7 +12,7 @@
[dependencies]
flate2 = "1.0"
log = "0.4"
-memmap = "0.6"
+memmap = "0.7"
smallvec = { version = "1.0", features = ["union", "may_dangle"] }
rustc = { path = "../librustc" }
rustc_data_structures = { path = "../librustc_data_structures" }
diff --git a/src/librustc_metadata/creader.rs b/src/librustc_metadata/creader.rs
index dbf2dcf..0a0f256 100644
--- a/src/librustc_metadata/creader.rs
+++ b/src/librustc_metadata/creader.rs
@@ -218,13 +218,14 @@
let source = self.cstore.get_crate_data(cnum).source();
if let Some(entry) = self.sess.opts.externs.get(&name.as_str()) {
// Only use `--extern crate_name=path` here, not `--extern crate_name`.
- let found = entry.locations.iter().filter_map(|l| l.as_ref()).any(|l| {
- let l = fs::canonicalize(l).ok();
- source.dylib.as_ref().map(|p| &p.0) == l.as_ref() ||
- source.rlib.as_ref().map(|p| &p.0) == l.as_ref()
- });
- if found {
- ret = Some(cnum);
+ if let Some(mut files) = entry.files() {
+ if files.any(|l| {
+ let l = fs::canonicalize(l).ok();
+ source.dylib.as_ref().map(|p| &p.0) == l.as_ref() ||
+ source.rlib.as_ref().map(|p| &p.0) == l.as_ref()
+ }) {
+ ret = Some(cnum);
+ }
}
return
}
@@ -802,11 +803,8 @@
// First up we check for global allocators. Look at the crate graph here
// and see what's a global allocator, including if we ourselves are a
// global allocator.
- let mut global_allocator = if self.cstore.has_global_allocator {
- Some(Symbol::intern("this crate"))
- } else {
- None
- };
+ let mut global_allocator = self.cstore.has_global_allocator
+ .then(|| Symbol::intern("this crate"));
self.cstore.iter_crate_data(|_, data| {
if !data.has_global_allocator() {
return
diff --git a/src/librustc_metadata/lib.rs b/src/librustc_metadata/lib.rs
index 8c0b734..aaaff7e 100644
--- a/src/librustc_metadata/lib.rs
+++ b/src/librustc_metadata/lib.rs
@@ -1,5 +1,6 @@
#![doc(html_root_url = "https://doc.rust-lang.org/nightly/")]
+#![feature(bool_to_option)]
#![feature(box_patterns)]
#![feature(core_intrinsics)]
#![feature(crate_visibility_modifier)]
diff --git a/src/librustc_metadata/locator.rs b/src/librustc_metadata/locator.rs
index c6fb80e..8a1eeea 100644
--- a/src/librustc_metadata/locator.rs
+++ b/src/librustc_metadata/locator.rs
@@ -328,8 +328,9 @@
crate_name,
exact_paths: if hash.is_none() {
sess.opts.externs.get(&crate_name.as_str()).into_iter()
- .flat_map(|entry| entry.locations.iter())
- .filter_map(|location| location.clone().map(PathBuf::from)).collect()
+ .filter_map(|entry| entry.files())
+ .flatten()
+ .map(|location| PathBuf::from(location)).collect()
} else {
// SVH being specified means this is a transitive dependency,
// so `--extern` options do not apply.
diff --git a/src/librustc_metadata/rmeta/decoder.rs b/src/librustc_metadata/rmeta/decoder.rs
index 6edd17f..0107a22 100644
--- a/src/librustc_metadata/rmeta/decoder.rs
+++ b/src/librustc_metadata/rmeta/decoder.rs
@@ -18,7 +18,7 @@
use rustc_data_structures::svh::Svh;
use rustc::dep_graph::{self, DepNodeIndex};
use rustc::middle::lang_items;
-use rustc::mir::{self, BodyCache, interpret, Promoted};
+use rustc::mir::{self, BodyAndCache, interpret, Promoted};
use rustc::mir::interpret::{AllocDecodingSession, AllocDecodingState};
use rustc::session::Session;
use rustc::ty::{self, Ty, TyCtxt};
@@ -1079,7 +1079,7 @@
self.root.per_def.mir.get(self, id).is_some()
}
- fn get_optimized_mir(&self, tcx: TyCtxt<'tcx>, id: DefIndex) -> BodyCache<'tcx> {
+ fn get_optimized_mir(&self, tcx: TyCtxt<'tcx>, id: DefIndex) -> BodyAndCache<'tcx> {
let mut cache = self.root.per_def.mir.get(self, id)
.filter(|_| !self.is_proc_macro(id))
.unwrap_or_else(|| {
@@ -1094,7 +1094,7 @@
&self,
tcx: TyCtxt<'tcx>,
id: DefIndex,
- ) -> IndexVec<Promoted, BodyCache<'tcx>> {
+ ) -> IndexVec<Promoted, BodyAndCache<'tcx>> {
let mut cache = self.root.per_def.promoted_mir.get(self, id)
.filter(|_| !self.is_proc_macro(id))
.unwrap_or_else(|| {
diff --git a/src/librustc_metadata/rmeta/mod.rs b/src/librustc_metadata/rmeta/mod.rs
index fdf43f0..5abae42 100644
--- a/src/librustc_metadata/rmeta/mod.rs
+++ b/src/librustc_metadata/rmeta/mod.rs
@@ -276,8 +276,8 @@
// Also, as an optimization, a missing entry indicates an empty `&[]`.
inferred_outlives: Table<DefIndex, Lazy!(&'tcx [(ty::Predicate<'tcx>, Span)])>,
super_predicates: Table<DefIndex, Lazy!(ty::GenericPredicates<'tcx>)>,
- mir: Table<DefIndex, Lazy!(mir::BodyCache<'tcx>)>,
- promoted_mir: Table<DefIndex, Lazy!(IndexVec<mir::Promoted, mir::BodyCache<'tcx>>)>,
+ mir: Table<DefIndex, Lazy!(mir::BodyAndCache<'tcx>)>,
+ promoted_mir: Table<DefIndex, Lazy!(IndexVec<mir::Promoted, mir::BodyAndCache<'tcx>>)>,
}
#[derive(Copy, Clone, RustcEncodable, RustcDecodable)]
diff --git a/src/librustc_mir/Cargo.toml b/src/librustc_mir/Cargo.toml
index 4afbb4d..7e3bd98 100644
--- a/src/librustc_mir/Cargo.toml
+++ b/src/librustc_mir/Cargo.toml
@@ -16,7 +16,7 @@
itertools = "0.8"
log = "0.4"
log_settings = "0.1.1"
-polonius-engine = "0.10.0"
+polonius-engine = "0.11.0"
rustc = { path = "../librustc" }
rustc_target = { path = "../librustc_target" }
rustc_data_structures = { path = "../librustc_data_structures" }
diff --git a/src/librustc_mir/borrow_check/borrow_set.rs b/src/librustc_mir/borrow_check/borrow_set.rs
index 802464c..2980483 100644
--- a/src/librustc_mir/borrow_check/borrow_set.rs
+++ b/src/librustc_mir/borrow_check/borrow_set.rs
@@ -5,7 +5,7 @@
use crate::dataflow::move_paths::MoveData;
use rustc::mir::traversal;
use rustc::mir::visit::{PlaceContext, Visitor, NonUseContext, MutatingUseContext};
-use rustc::mir::{self, Location, Body, Local, ReadOnlyBodyCache};
+use rustc::mir::{self, Location, Body, Local, ReadOnlyBodyAndCache};
use rustc::ty::{RegionVid, TyCtxt};
use rustc::util::nodemap::{FxHashMap, FxHashSet};
use rustc_index::vec::IndexVec;
@@ -90,7 +90,7 @@
impl LocalsStateAtExit {
fn build(
locals_are_invalidated_at_exit: bool,
- body: ReadOnlyBodyCache<'_, 'tcx>,
+ body: ReadOnlyBodyAndCache<'_, 'tcx>,
move_data: &MoveData<'tcx>
) -> Self {
struct HasStorageDead(BitSet<Local>);
@@ -124,7 +124,7 @@
impl<'tcx> BorrowSet<'tcx> {
pub fn build(
tcx: TyCtxt<'tcx>,
- body: ReadOnlyBodyCache<'_, 'tcx>,
+ body: ReadOnlyBodyAndCache<'_, 'tcx>,
locals_are_invalidated_at_exit: bool,
move_data: &MoveData<'tcx>,
) -> Self {
diff --git a/src/librustc_mir/borrow_check/nll/constraint_generation.rs b/src/librustc_mir/borrow_check/constraint_generation.rs
similarity index 95%
rename from src/librustc_mir/borrow_check/nll/constraint_generation.rs
rename to src/librustc_mir/borrow_check/constraint_generation.rs
index cae3030..28a631a 100644
--- a/src/librustc_mir/borrow_check/nll/constraint_generation.rs
+++ b/src/librustc_mir/borrow_check/constraint_generation.rs
@@ -1,9 +1,3 @@
-use crate::borrow_check::borrow_set::BorrowSet;
-use crate::borrow_check::location::LocationTable;
-use crate::borrow_check::nll::ToRegionVid;
-use crate::borrow_check::nll::facts::AllFacts;
-use crate::borrow_check::nll::region_infer::values::LivenessValues;
-use crate::borrow_check::places_conflict;
use rustc::infer::InferCtxt;
use rustc::mir::visit::TyContext;
use rustc::mir::visit::Visitor;
@@ -15,6 +9,15 @@
use rustc::ty::{self, RegionVid, Ty};
use rustc::ty::subst::SubstsRef;
+use crate::borrow_check::{
+ borrow_set::BorrowSet,
+ location::LocationTable,
+ nll::ToRegionVid,
+ facts::AllFacts,
+ region_infer::values::LivenessValues,
+ places_conflict,
+};
+
pub(super) fn generate_constraints<'cx, 'tcx>(
infcx: &InferCtxt<'cx, 'tcx>,
param_env: ty::ParamEnv<'tcx>,
@@ -97,6 +100,7 @@
location: Location,
) {
if let Some(all_facts) = self.all_facts {
+ let _prof_timer = self.infcx.tcx.prof.generic_activity("polonius_fact_generation");
all_facts.cfg_edge.push((
self.location_table.start_index(location),
self.location_table.mid_index(location),
@@ -142,6 +146,7 @@
location: Location,
) {
if let Some(all_facts) = self.all_facts {
+ let _prof_timer = self.infcx.tcx.prof.generic_activity("polonius_fact_generation");
all_facts.cfg_edge.push((
self.location_table.start_index(location),
self.location_table.mid_index(location),
@@ -205,6 +210,8 @@
/// as `killed`. For example, when assigning to a local, or on a call's return destination.
fn record_killed_borrows_for_place(&mut self, place: &Place<'tcx>, location: Location) {
if let Some(all_facts) = self.all_facts {
+ let _prof_timer = self.infcx.tcx.prof.generic_activity("polonius_fact_generation");
+
// Depending on the `Place` we're killing:
// - if it's a local, or a single deref of a local,
// we kill all the borrows on the local.
diff --git a/src/librustc_mir/borrow_check/nll/constraints/graph.rs b/src/librustc_mir/borrow_check/constraints/graph.rs
similarity index 97%
rename from src/librustc_mir/borrow_check/nll/constraints/graph.rs
rename to src/librustc_mir/borrow_check/constraints/graph.rs
index b6a9a7e..3e7aa67 100644
--- a/src/librustc_mir/borrow_check/nll/constraints/graph.rs
+++ b/src/librustc_mir/borrow_check/constraints/graph.rs
@@ -1,12 +1,15 @@
-use crate::borrow_check::nll::type_check::Locations;
-use crate::borrow_check::nll::constraints::OutlivesConstraintIndex;
-use crate::borrow_check::nll::constraints::{OutlivesConstraintSet, OutlivesConstraint};
use rustc::mir::ConstraintCategory;
use rustc::ty::RegionVid;
use rustc_data_structures::graph;
use rustc_index::vec::IndexVec;
use syntax_pos::DUMMY_SP;
+use crate::borrow_check::{
+ type_check::Locations,
+ constraints::OutlivesConstraintIndex,
+ constraints::{OutlivesConstraintSet, OutlivesConstraint},
+};
+
/// The construct graph organizes the constraints by their end-points.
/// It can be used to view a `R1: R2` constraint as either an edge `R1
/// -> R2` or `R2 -> R1` depending on the direction type `D`.
diff --git a/src/librustc_mir/borrow_check/nll/constraints/mod.rs b/src/librustc_mir/borrow_check/constraints/mod.rs
similarity index 98%
rename from src/librustc_mir/borrow_check/nll/constraints/mod.rs
rename to src/librustc_mir/borrow_check/constraints/mod.rs
index 8a242b7..96982b6 100644
--- a/src/librustc_mir/borrow_check/nll/constraints/mod.rs
+++ b/src/librustc_mir/borrow_check/constraints/mod.rs
@@ -1,4 +1,3 @@
-use crate::borrow_check::nll::type_check::Locations;
use rustc::mir::ConstraintCategory;
use rustc::ty::RegionVid;
use rustc_data_structures::graph::scc::Sccs;
@@ -6,6 +5,8 @@
use std::fmt;
use std::ops::Index;
+use crate::borrow_check::type_check::Locations;
+
crate mod graph;
/// A set of NLL region constraints. These include "outlives"
diff --git a/src/librustc_mir/borrow_check/conflict_errors.rs b/src/librustc_mir/borrow_check/diagnostics/conflict_errors.rs
similarity index 97%
rename from src/librustc_mir/borrow_check/conflict_errors.rs
rename to src/librustc_mir/borrow_check/diagnostics/conflict_errors.rs
index b1e327c..1cd43d4 100644
--- a/src/librustc_mir/borrow_check/conflict_errors.rs
+++ b/src/librustc_mir/borrow_check/diagnostics/conflict_errors.rs
@@ -14,18 +14,22 @@
use syntax_pos::Span;
use syntax::source_map::DesugaringKind;
-use super::nll::explain_borrow::BorrowExplanation;
-use super::nll::region_infer::{RegionName, RegionNameSource};
-use super::prefixes::IsPrefixOf;
-use super::WriteKind;
-use super::borrow_set::BorrowData;
-use super::MirBorrowckCtxt;
-use super::{InitializationRequiringAction, PrefixSet};
-use super::error_reporting::{IncludingDowncast, UseSpans};
use crate::dataflow::drop_flag_effects;
use crate::dataflow::indexes::{MovePathIndex, MoveOutIndex};
use crate::util::borrowck_errors;
+use crate::borrow_check::{
+ prefixes::IsPrefixOf,
+ WriteKind,
+ borrow_set::BorrowData,
+ MirBorrowckCtxt, InitializationRequiringAction, PrefixSet
+};
+
+use super::{
+ IncludingDowncast, UseSpans, RegionName, RegionNameSource,
+ explain_borrow::BorrowExplanation,
+};
+
#[derive(Debug)]
struct MoveSite {
/// Index of the "move out" that we found. The `MoveData` can
@@ -46,7 +50,7 @@
}
impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
- pub(super) fn report_use_of_moved_or_uninitialized(
+ pub(in crate::borrow_check) fn report_use_of_moved_or_uninitialized(
&mut self,
location: Location,
desired_action: InitializationRequiringAction,
@@ -74,10 +78,7 @@
.collect();
if move_out_indices.is_empty() {
- let root_place = self
- .prefixes(used_place, PrefixSet::All)
- .last()
- .unwrap();
+ let root_place = PlaceRef { projection: &[], ..used_place };
if !self.uninitialized_error_reported.insert(root_place) {
debug!(
@@ -236,15 +237,17 @@
let tcx = self.infcx.tcx;
let generics = tcx.generics_of(self.mir_def_id);
let param = generics.type_param(¶m_ty, tcx);
- let generics = tcx.hir().get_generics(self.mir_def_id).unwrap();
- suggest_constraining_type_param(
- generics,
- &mut err,
- ¶m.name.as_str(),
- "Copy",
- tcx.sess.source_map(),
- span,
- );
+ if let Some(generics) =
+ tcx.hir().get_generics(tcx.closure_base_def_id(self.mir_def_id)) {
+ suggest_constraining_type_param(
+ generics,
+ &mut err,
+ ¶m.name.as_str(),
+ "Copy",
+ tcx.sess.source_map(),
+ span,
+ );
+ }
}
let span = if let Some(local) = place.as_local() {
let decl = &self.body.local_decls[local];
@@ -269,7 +272,7 @@
}
}
- pub(super) fn report_move_out_while_borrowed(
+ pub(in crate::borrow_check) fn report_move_out_while_borrowed(
&mut self,
location: Location,
(place, span): (&Place<'tcx>, Span),
@@ -326,7 +329,7 @@
err.buffer(&mut self.errors_buffer);
}
- pub(super) fn report_use_while_mutably_borrowed(
+ pub(in crate::borrow_check) fn report_use_while_mutably_borrowed(
&mut self,
location: Location,
(place, _span): (&Place<'tcx>, Span),
@@ -368,7 +371,7 @@
err
}
- pub(super) fn report_conflicting_borrow(
+ pub(in crate::borrow_check) fn report_conflicting_borrow(
&mut self,
location: Location,
(place, span): (&Place<'tcx>, Span),
@@ -614,7 +617,7 @@
///
/// > cannot borrow `a.u` (via `a.u.z.c`) as immutable because it is also borrowed as
/// > mutable (via `a.u.s.b`) [E0502]
- pub(super) fn describe_place_for_conflicting_borrow(
+ pub(in crate::borrow_check) fn describe_place_for_conflicting_borrow(
&self,
first_borrowed_place: &Place<'tcx>,
second_borrowed_place: &Place<'tcx>,
@@ -722,7 +725,7 @@
/// short a lifetime. (But sometimes it is more useful to report
/// it as a more direct conflict between the execution of a
/// `Drop::drop` with an aliasing borrow.)
- pub(super) fn report_borrowed_value_does_not_live_long_enough(
+ pub(in crate::borrow_check) fn report_borrowed_value_does_not_live_long_enough(
&mut self,
location: Location,
borrow: &BorrowData<'tcx>,
@@ -1478,7 +1481,7 @@
result
}
- pub(super) fn report_illegal_mutation_of_borrowed(
+ pub(in crate::borrow_check) fn report_illegal_mutation_of_borrowed(
&mut self,
location: Location,
(place, span): (&Place<'tcx>, Span),
@@ -1537,7 +1540,7 @@
/// assigned; `err_place` is a place providing a reason why
/// `place` is not mutable (e.g., the non-`mut` local `x` in an
/// assignment to `x.f`).
- pub(super) fn report_illegal_reassignment(
+ pub(in crate::borrow_check) fn report_illegal_reassignment(
&mut self,
_location: Location,
(place, span): (&Place<'tcx>, Span),
@@ -2080,7 +2083,7 @@
impl<'tcx> AnnotatedBorrowFnSignature<'tcx> {
/// Annotate the provided diagnostic with information about borrow from the fn signature that
/// helps explain.
- pub(super) fn emit(
+ pub(in crate::borrow_check) fn emit(
&self,
cx: &mut MirBorrowckCtxt<'_, 'tcx>,
diag: &mut DiagnosticBuilder<'_>,
diff --git a/src/librustc_mir/borrow_check/nll/explain_borrow/mod.rs b/src/librustc_mir/borrow_check/diagnostics/explain_borrow.rs
similarity index 98%
rename from src/librustc_mir/borrow_check/nll/explain_borrow/mod.rs
rename to src/librustc_mir/borrow_check/diagnostics/explain_borrow.rs
index 43aabac..a463d2c 100644
--- a/src/librustc_mir/borrow_check/nll/explain_borrow/mod.rs
+++ b/src/librustc_mir/borrow_check/diagnostics/explain_borrow.rs
@@ -1,10 +1,7 @@
+//! Print diagnostics to explain why values are borrowed.
+
use std::collections::VecDeque;
-use crate::borrow_check::borrow_set::BorrowData;
-use crate::borrow_check::error_reporting::UseSpans;
-use crate::borrow_check::nll::region_infer::{Cause, RegionName};
-use crate::borrow_check::nll::ConstraintDescription;
-use crate::borrow_check::{MirBorrowckCtxt, WriteKind};
use rustc::mir::{
CastKind, ConstraintCategory, FakeReadCause, Local, Location, Body, Operand, Place, Rvalue,
Statement, StatementKind, TerminatorKind,
@@ -17,7 +14,14 @@
use syntax_pos::Span;
use syntax_pos::symbol::Symbol;
-mod find_use;
+use crate::borrow_check::{
+ borrow_set::BorrowData,
+ region_infer::Cause,
+ nll::ConstraintDescription,
+ MirBorrowckCtxt, WriteKind,
+};
+
+use super::{UseSpans, find_use, RegionName};
#[derive(Debug)]
pub(in crate::borrow_check) enum BorrowExplanation {
diff --git a/src/librustc_mir/borrow_check/nll/explain_borrow/find_use.rs b/src/librustc_mir/borrow_check/diagnostics/find_use.rs
similarity index 96%
rename from src/librustc_mir/borrow_check/nll/explain_borrow/find_use.rs
rename to src/librustc_mir/borrow_check/diagnostics/find_use.rs
index 7ab0692..c557e52 100644
--- a/src/librustc_mir/borrow_check/nll/explain_borrow/find_use.rs
+++ b/src/librustc_mir/borrow_check/diagnostics/find_use.rs
@@ -1,8 +1,7 @@
use std::collections::VecDeque;
use std::rc::Rc;
-use crate::borrow_check::nll::region_infer::{Cause, RegionInferenceContext};
-use crate::borrow_check::nll::ToRegionVid;
+use crate::borrow_check::{nll::ToRegionVid, region_infer::{Cause, RegionInferenceContext}};
use crate::util::liveness::{self, DefUse};
use rustc::mir::visit::{MirVisitable, PlaceContext, Visitor};
use rustc::mir::{Local, Location, Body};
diff --git a/src/librustc_mir/borrow_check/error_reporting.rs b/src/librustc_mir/borrow_check/diagnostics/mod.rs
similarity index 98%
rename from src/librustc_mir/borrow_check/error_reporting.rs
rename to src/librustc_mir/borrow_check/diagnostics/mod.rs
index 9953d28..1a76265 100644
--- a/src/librustc_mir/borrow_check/error_reporting.rs
+++ b/src/librustc_mir/borrow_check/diagnostics/mod.rs
@@ -1,3 +1,5 @@
+//! Borrow checker diagnostics.
+
use rustc::hir;
use rustc::hir::def::Namespace;
use rustc::hir::def_id::DefId;
@@ -17,6 +19,22 @@
use super::MirBorrowckCtxt;
use crate::dataflow::move_paths::{InitLocation, LookupResult};
+mod find_use;
+mod var_name;
+mod region_name;
+mod outlives_suggestion;
+
+mod conflict_errors;
+mod move_errors;
+mod mutability_errors;
+mod region_errors;
+mod explain_borrow;
+
+crate use mutability_errors::AccessKind;
+crate use region_name::{RegionName, RegionNameSource, RegionErrorNamingCtx};
+crate use region_errors::{ErrorReportingCtx, ErrorConstraintInfo};
+crate use outlives_suggestion::OutlivesSuggestionBuilder;
+
pub(super) struct IncludingDowncast(pub(super) bool);
impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
diff --git a/src/librustc_mir/borrow_check/move_errors.rs b/src/librustc_mir/borrow_check/diagnostics/move_errors.rs
similarity index 97%
rename from src/librustc_mir/borrow_check/move_errors.rs
rename to src/librustc_mir/borrow_check/diagnostics/move_errors.rs
index fd77976..cc63410 100644
--- a/src/librustc_mir/borrow_check/move_errors.rs
+++ b/src/librustc_mir/borrow_check/diagnostics/move_errors.rs
@@ -5,7 +5,7 @@
use crate::borrow_check::MirBorrowckCtxt;
use crate::borrow_check::prefixes::PrefixSet;
-use crate::borrow_check::error_reporting::UseSpans;
+use crate::borrow_check::diagnostics::UseSpans;
use crate::dataflow::move_paths::{
IllegalMoveOrigin, IllegalMoveOriginKind,
LookupResult, MoveError, MovePathIndex,
@@ -223,18 +223,24 @@
fn report(&mut self, error: GroupedMoveError<'tcx>) {
let (mut err, err_span) = {
- let (span, original_path, kind): (Span, &Place<'tcx>, &IllegalMoveOriginKind<'_>) =
+ let (span, use_spans, original_path, kind,):
+ (
+ Span,
+ Option<UseSpans>,
+ &Place<'tcx>,
+ &IllegalMoveOriginKind<'_>,
+ ) =
match error {
GroupedMoveError::MovesFromPlace { span, ref original_path, ref kind, .. } |
GroupedMoveError::MovesFromValue { span, ref original_path, ref kind, .. } => {
- (span, original_path, kind)
+ (span, None, original_path, kind)
}
GroupedMoveError::OtherIllegalMove {
use_spans,
ref original_path,
ref kind
} => {
- (use_spans.args_or_use(), original_path, kind)
+ (use_spans.args_or_use(), Some(use_spans), original_path, kind)
},
};
debug!("report: original_path={:?} span={:?}, kind={:?} \
@@ -250,6 +256,7 @@
original_path,
target_place,
span,
+ use_spans,
)
}
IllegalMoveOriginKind::InteriorOfTypeWithDestructor { container_ty: ty } => {
@@ -296,6 +303,7 @@
move_place: &Place<'tcx>,
deref_target_place: &Place<'tcx>,
span: Span,
+ use_spans: Option<UseSpans>,
) -> DiagnosticBuilder<'a> {
// Inspect the type of the content behind the
// borrow to provide feedback about why this
@@ -416,7 +424,7 @@
if let Ok(snippet) = self.infcx.tcx.sess.source_map().span_to_snippet(span) {
let is_option = move_ty.starts_with("std::option::Option");
let is_result = move_ty.starts_with("std::result::Result");
- if is_option || is_result {
+ if (is_option || is_result) && use_spans.map_or(true, |v| !v.for_closure()) {
err.span_suggestion(
span,
&format!("consider borrowing the `{}`'s content", if is_option {
diff --git a/src/librustc_mir/borrow_check/mutability_errors.rs b/src/librustc_mir/borrow_check/diagnostics/mutability_errors.rs
similarity index 98%
rename from src/librustc_mir/borrow_check/mutability_errors.rs
rename to src/librustc_mir/borrow_check/diagnostics/mutability_errors.rs
index 98a7b10..016a319 100644
--- a/src/librustc_mir/borrow_check/mutability_errors.rs
+++ b/src/librustc_mir/borrow_check/diagnostics/mutability_errors.rs
@@ -1,6 +1,6 @@
use rustc::hir;
use rustc::hir::Node;
-use rustc::mir::{self, ClearCrossCrate, Local, LocalInfo, Location, ReadOnlyBodyCache};
+use rustc::mir::{self, ClearCrossCrate, Local, LocalInfo, Location, ReadOnlyBodyAndCache};
use rustc::mir::{Mutability, Place, PlaceRef, PlaceBase, ProjectionElem};
use rustc::ty::{self, Ty, TyCtxt};
use rustc_index::vec::Idx;
@@ -8,18 +8,18 @@
use syntax_pos::symbol::kw;
use crate::borrow_check::MirBorrowckCtxt;
-use crate::borrow_check::error_reporting::BorrowedContentSource;
+use crate::borrow_check::diagnostics::BorrowedContentSource;
use crate::util::collect_writes::FindAssignments;
use rustc_errors::Applicability;
#[derive(Copy, Clone, Debug, Eq, PartialEq)]
-pub(super) enum AccessKind {
+pub(crate) enum AccessKind {
MutableBorrow,
Mutate,
}
impl<'a, 'tcx> MirBorrowckCtxt<'a, 'tcx> {
- pub(super) fn report_mutability_error(
+ pub(crate) fn report_mutability_error(
&mut self,
access_place: &Place<'tcx>,
span: Span,
@@ -533,7 +533,7 @@
// by trying (3.), then (2.) and finally falling back on (1.).
fn suggest_ampmut<'tcx>(
tcx: TyCtxt<'tcx>,
- body: ReadOnlyBodyCache<'_, 'tcx>,
+ body: ReadOnlyBodyAndCache<'_, 'tcx>,
local: Local,
local_decl: &mir::LocalDecl<'tcx>,
opt_ty_info: Option<Span>,
diff --git a/src/librustc_mir/borrow_check/nll/region_infer/error_reporting/outlives_suggestion.rs b/src/librustc_mir/borrow_check/diagnostics/outlives_suggestion.rs
similarity index 97%
rename from src/librustc_mir/borrow_check/nll/region_infer/error_reporting/outlives_suggestion.rs
rename to src/librustc_mir/borrow_check/diagnostics/outlives_suggestion.rs
index 938059c..b61c37b 100644
--- a/src/librustc_mir/borrow_check/nll/region_infer/error_reporting/outlives_suggestion.rs
+++ b/src/librustc_mir/borrow_check/diagnostics/outlives_suggestion.rs
@@ -13,12 +13,10 @@
use smallvec::SmallVec;
-use crate::borrow_check::nll::region_infer::{
- error_reporting::{
- region_name::{RegionName, RegionNameSource},
- ErrorConstraintInfo, ErrorReportingCtx, RegionErrorNamingCtx,
- },
- RegionInferenceContext,
+use crate::borrow_check::region_infer::RegionInferenceContext;
+
+use super::{
+ RegionName, RegionNameSource, ErrorConstraintInfo, ErrorReportingCtx, RegionErrorNamingCtx,
};
/// The different things we could suggest.
diff --git a/src/librustc_mir/borrow_check/nll/region_infer/error_reporting/mod.rs b/src/librustc_mir/borrow_check/diagnostics/region_errors.rs
similarity index 96%
rename from src/librustc_mir/borrow_check/nll/region_infer/error_reporting/mod.rs
rename to src/librustc_mir/borrow_check/diagnostics/region_errors.rs
index 5e79a2f..8a37e2d 100644
--- a/src/librustc_mir/borrow_check/nll/region_infer/error_reporting/mod.rs
+++ b/src/librustc_mir/borrow_check/diagnostics/region_errors.rs
@@ -1,10 +1,5 @@
-use crate::borrow_check::nll::constraints::OutlivesConstraint;
-use crate::borrow_check::nll::region_infer::RegionInferenceContext;
-use crate::borrow_check::nll::type_check::Locations;
-use crate::borrow_check::nll::universal_regions::DefiningTy;
-use crate::borrow_check::nll::ConstraintDescription;
-use crate::borrow_check::Upvar;
-use crate::util::borrowck_errors;
+//! Error reporting machinery for lifetime errors.
+
use rustc::hir::def_id::DefId;
use rustc::infer::error_reporting::nice_region_error::NiceRegionError;
use rustc::infer::InferCtxt;
@@ -19,14 +14,18 @@
use syntax_pos::Span;
use syntax_pos::symbol::Symbol;
-use self::outlives_suggestion::OutlivesSuggestionBuilder;
+use crate::util::borrowck_errors;
-pub mod outlives_suggestion;
+use crate::borrow_check::{
+ constraints::OutlivesConstraint,
+ region_infer::RegionInferenceContext,
+ type_check::Locations,
+ universal_regions::DefiningTy,
+ nll::ConstraintDescription,
+ Upvar,
+};
-mod region_name;
-mod var_name;
-
-crate use self::region_name::{RegionName, RegionNameSource, RegionErrorNamingCtx};
+use super::{OutlivesSuggestionBuilder, RegionName, RegionNameSource, RegionErrorNamingCtx};
impl ConstraintDescription for ConstraintCategory {
fn description(&self) -> &'static str {
@@ -61,36 +60,36 @@
/// Various pieces of state used when reporting borrow checker errors.
pub struct ErrorReportingCtx<'a, 'b, 'tcx> {
/// The region inference context used for borrow chekcing this MIR body.
- region_infcx: &'b RegionInferenceContext<'tcx>,
+ pub(super) region_infcx: &'b RegionInferenceContext<'tcx>,
/// The inference context used for type checking.
- infcx: &'b InferCtxt<'a, 'tcx>,
+ pub(super) infcx: &'b InferCtxt<'a, 'tcx>,
/// The MIR def we are reporting errors on.
- mir_def_id: DefId,
+ pub(super) mir_def_id: DefId,
/// The MIR body we are reporting errors on (for convenience).
- body: &'b Body<'tcx>,
+ pub(super) body: &'b Body<'tcx>,
/// User variable names for MIR locals (where applicable).
- local_names: &'b IndexVec<Local, Option<Symbol>>,
+ pub(super) local_names: &'b IndexVec<Local, Option<Symbol>>,
/// Any upvars for the MIR body we have kept track of during borrow checking.
- upvars: &'b [Upvar],
+ pub(super) upvars: &'b [Upvar],
}
/// Information about the various region constraints involved in a borrow checker error.
#[derive(Clone, Debug)]
pub struct ErrorConstraintInfo {
// fr: outlived_fr
- fr: RegionVid,
- fr_is_local: bool,
- outlived_fr: RegionVid,
- outlived_fr_is_local: bool,
+ pub(super) fr: RegionVid,
+ pub(super) fr_is_local: bool,
+ pub(super) outlived_fr: RegionVid,
+ pub(super) outlived_fr_is_local: bool,
// Category and span for best blame constraint
- category: ConstraintCategory,
- span: Span,
+ pub(super) category: ConstraintCategory,
+ pub(super) span: Span,
}
impl<'tcx> RegionInferenceContext<'tcx> {
@@ -368,7 +367,7 @@
/// ```
///
/// Here we would be invoked with `fr = 'a` and `outlived_fr = `'b`.
- pub(super) fn report_error<'a>(
+ pub(in crate::borrow_check) fn report_error<'a>(
&'a self,
body: &Body<'tcx>,
local_names: &IndexVec<Local, Option<Symbol>>,
diff --git a/src/librustc_mir/borrow_check/nll/region_infer/error_reporting/region_name.rs b/src/librustc_mir/borrow_check/diagnostics/region_name.rs
similarity index 98%
rename from src/librustc_mir/borrow_check/nll/region_infer/error_reporting/region_name.rs
rename to src/librustc_mir/borrow_check/diagnostics/region_name.rs
index 0f5d1c5..720c77b 100644
--- a/src/librustc_mir/borrow_check/nll/region_infer/error_reporting/region_name.rs
+++ b/src/librustc_mir/borrow_check/diagnostics/region_name.rs
@@ -1,12 +1,5 @@
use std::fmt::{self, Display};
-use crate::borrow_check::nll::region_infer::{
- RegionInferenceContext,
- error_reporting::ErrorReportingCtx,
-};
-use crate::borrow_check::nll::universal_regions::DefiningTy;
-use crate::borrow_check::nll::ToRegionVid;
-use crate::borrow_check::Upvar;
use rustc::hir;
use rustc::hir::def::{Res, DefKind};
use rustc::hir::def_id::DefId;
@@ -21,6 +14,14 @@
use rustc_data_structures::fx::FxHashMap;
use syntax_pos::{Span, symbol::Symbol, DUMMY_SP};
+use crate::borrow_check::{
+ diagnostics::region_errors::ErrorReportingCtx,
+ region_infer::RegionInferenceContext,
+ universal_regions::DefiningTy,
+ nll::ToRegionVid,
+ Upvar,
+};
+
/// A name for a particular region used in emitting diagnostics. This name could be a generated
/// name like `'1`, a name used by the user like `'a`, or a name like `'static`.
#[derive(Debug, Clone)]
diff --git a/src/librustc_mir/borrow_check/nll/region_infer/error_reporting/var_name.rs b/src/librustc_mir/borrow_check/diagnostics/var_name.rs
similarity index 97%
rename from src/librustc_mir/borrow_check/nll/region_infer/error_reporting/var_name.rs
rename to src/librustc_mir/borrow_check/diagnostics/var_name.rs
index 1ac44c4..839e09b 100644
--- a/src/librustc_mir/borrow_check/nll/region_infer/error_reporting/var_name.rs
+++ b/src/librustc_mir/borrow_check/diagnostics/var_name.rs
@@ -1,5 +1,4 @@
-use crate::borrow_check::nll::region_infer::RegionInferenceContext;
-use crate::borrow_check::nll::ToRegionVid;
+use crate::borrow_check::{nll::ToRegionVid, region_infer::RegionInferenceContext};
use crate::borrow_check::Upvar;
use rustc::mir::{Local, Body};
use rustc::ty::{RegionVid, TyCtxt};
diff --git a/src/librustc_mir/borrow_check/nll/facts.rs b/src/librustc_mir/borrow_check/facts.rs
similarity index 91%
rename from src/librustc_mir/borrow_check/nll/facts.rs
rename to src/librustc_mir/borrow_check/facts.rs
index 13e5769..a16c36d 100644
--- a/src/librustc_mir/borrow_check/nll/facts.rs
+++ b/src/librustc_mir/borrow_check/facts.rs
@@ -1,6 +1,6 @@
use crate::borrow_check::location::{LocationIndex, LocationTable};
use crate::dataflow::indexes::{BorrowIndex, MovePathIndex};
-use polonius_engine::AllFacts as PoloniusAllFacts;
+use polonius_engine::AllFacts as PoloniusFacts;
use polonius_engine::Atom;
use rustc::mir::Local;
use rustc::ty::{RegionVid, TyCtxt};
@@ -11,7 +11,18 @@
use std::io::Write;
use std::path::Path;
-crate type AllFacts = PoloniusAllFacts<RegionVid, BorrowIndex, LocationIndex, Local, MovePathIndex>;
+#[derive(Copy, Clone, Debug)]
+crate struct RustcFacts;
+
+impl polonius_engine::FactTypes for RustcFacts {
+ type Origin = RegionVid;
+ type Loan = BorrowIndex;
+ type Point = LocationIndex;
+ type Variable = Local;
+ type Path = MovePathIndex;
+}
+
+crate type AllFacts = PoloniusFacts<RustcFacts>;
crate trait AllFactsExt {
/// Returns `true` if there is a need to gather `AllFacts` given the
@@ -55,6 +66,7 @@
wr.write_facts_to_path(self.[
borrow_region,
universal_region,
+ placeholder,
cfg_edge,
killed,
outlives,
@@ -69,6 +81,7 @@
initialized_at,
moved_out_at,
path_accessed_at,
+ known_subset,
])
}
Ok(())
diff --git a/src/librustc_mir/borrow_check/flows.rs b/src/librustc_mir/borrow_check/flows.rs
index ce5d2a1..57c544f 100644
--- a/src/librustc_mir/borrow_check/flows.rs
+++ b/src/librustc_mir/borrow_check/flows.rs
@@ -3,16 +3,15 @@
//! FIXME: this might be better as a "generic" fixed-point combinator,
//! but is not as ugly as it is right now.
-use rustc::mir::{BasicBlock, Local, Location};
-use rustc::ty::RegionVid;
+use rustc::mir::{BasicBlock, Location};
use rustc_index::bit_set::BitIter;
use crate::borrow_check::location::LocationIndex;
-use polonius_engine::Output;
+use crate::borrow_check::nll::PoloniusOutput;
use crate::dataflow::indexes::BorrowIndex;
-use crate::dataflow::move_paths::{HasMoveData, MovePathIndex};
+use crate::dataflow::move_paths::HasMoveData;
use crate::dataflow::Borrows;
use crate::dataflow::EverInitializedPlaces;
use crate::dataflow::MaybeUninitializedPlaces;
@@ -21,8 +20,6 @@
use std::fmt;
use std::rc::Rc;
-crate type PoloniusOutput = Output<RegionVid, BorrowIndex, LocationIndex, Local, MovePathIndex>;
-
crate struct Flows<'b, 'tcx> {
borrows: FlowAtLocation<'tcx, Borrows<'b, 'tcx>>,
pub uninits: FlowAtLocation<'tcx, MaybeUninitializedPlaces<'b, 'tcx>>,
diff --git a/src/librustc_mir/borrow_check/nll/invalidation.rs b/src/librustc_mir/borrow_check/invalidation.rs
similarity index 96%
rename from src/librustc_mir/borrow_check/nll/invalidation.rs
rename to src/librustc_mir/borrow_check/invalidation.rs
index 98679f2..58fac55 100644
--- a/src/librustc_mir/borrow_check/nll/invalidation.rs
+++ b/src/librustc_mir/borrow_check/invalidation.rs
@@ -1,28 +1,28 @@
-use crate::borrow_check::borrow_set::BorrowSet;
-use crate::borrow_check::location::LocationTable;
-use crate::borrow_check::{JustWrite, WriteAndRead};
-use crate::borrow_check::{AccessDepth, Deep, Shallow};
-use crate::borrow_check::{ReadOrWrite, Activation, Read, Reservation, Write};
-use crate::borrow_check::{LocalMutationIsAllowed, MutateMode};
-use crate::borrow_check::ArtificialField;
-use crate::borrow_check::{ReadKind, WriteKind};
-use crate::borrow_check::nll::facts::AllFacts;
-use crate::borrow_check::path_utils::*;
-use crate::dataflow::indexes::BorrowIndex;
use rustc::ty::{self, TyCtxt};
use rustc::mir::visit::Visitor;
-use rustc::mir::{BasicBlock, Location, Body, Place, ReadOnlyBodyCache, Rvalue};
+use rustc::mir::{BasicBlock, Location, Body, Place, ReadOnlyBodyAndCache, Rvalue};
use rustc::mir::{Statement, StatementKind};
use rustc::mir::TerminatorKind;
use rustc::mir::{Operand, BorrowKind};
use rustc_data_structures::graph::dominators::Dominators;
+use crate::dataflow::indexes::BorrowIndex;
+
+use crate::borrow_check::{
+ borrow_set::BorrowSet,
+ location::LocationTable,
+ facts::AllFacts,
+ path_utils::*,
+ JustWrite, WriteAndRead, AccessDepth, Deep, Shallow, ReadOrWrite, Activation, Read,
+ Reservation, Write, LocalMutationIsAllowed, MutateMode, ArtificialField, ReadKind, WriteKind,
+};
+
pub(super) fn generate_invalidates<'tcx>(
tcx: TyCtxt<'tcx>,
param_env: ty::ParamEnv<'tcx>,
all_facts: &mut Option<AllFacts>,
location_table: &LocationTable,
- body: ReadOnlyBodyCache<'_, 'tcx>,
+ body: ReadOnlyBodyAndCache<'_, 'tcx>,
borrow_set: &BorrowSet<'tcx>,
) {
if all_facts.is_none() {
@@ -31,6 +31,7 @@
}
if let Some(all_facts) = all_facts {
+ let _prof_timer = tcx.prof.generic_activity("polonius_fact_generation");
let dominators = body.dominators();
let mut ig = InvalidationGenerator {
all_facts,
diff --git a/src/librustc_mir/borrow_check/nll/member_constraints.rs b/src/librustc_mir/borrow_check/member_constraints.rs
similarity index 100%
rename from src/librustc_mir/borrow_check/nll/member_constraints.rs
rename to src/librustc_mir/borrow_check/member_constraints.rs
diff --git a/src/librustc_mir/borrow_check/mod.rs b/src/librustc_mir/borrow_check/mod.rs
index bacff0b..11012ef 100644
--- a/src/librustc_mir/borrow_check/mod.rs
+++ b/src/librustc_mir/borrow_check/mod.rs
@@ -1,6 +1,5 @@
//! This query borrow-checks the MIR to (further) ensure it is not broken.
-use crate::borrow_check::nll::region_infer::RegionInferenceContext;
use rustc::hir::{self, HirId};
use rustc::hir::Node;
use rustc::hir::def_id::DefId;
@@ -9,8 +8,8 @@
use rustc::lint::builtin::{MUTABLE_BORROW_RESERVATION_CONFLICT};
use rustc::mir::{AggregateKind, BasicBlock, BorrowCheckResult, BorrowKind};
use rustc::mir::{
- ClearCrossCrate, Local, Location, Body, BodyCache, Mutability, Operand, Place, PlaceBase,
- PlaceElem, PlaceRef, ReadOnlyBodyCache, Static, StaticKind, read_only
+ ClearCrossCrate, Local, Location, Body, BodyAndCache, Mutability, Operand, Place, PlaceBase,
+ PlaceElem, PlaceRef, ReadOnlyBodyAndCache, Static, StaticKind, read_only
};
use rustc::mir::{Field, ProjectionElem, Promoted, Rvalue, Statement, StatementKind};
use rustc::mir::{Terminator, TerminatorKind};
@@ -41,29 +40,39 @@
use crate::dataflow::EverInitializedPlaces;
use crate::dataflow::{MaybeInitializedPlaces, MaybeUninitializedPlaces};
-use self::borrow_set::{BorrowData, BorrowSet};
use self::flows::Flows;
use self::location::LocationTable;
use self::prefixes::PrefixSet;
use self::MutateMode::{JustWrite, WriteAndRead};
-use self::mutability_errors::AccessKind;
+use self::diagnostics::AccessKind;
use self::path_utils::*;
-crate mod borrow_set;
-mod error_reporting;
+mod diagnostics;
mod flows;
mod location;
-mod conflict_errors;
-mod move_errors;
-mod mutability_errors;
mod path_utils;
-crate mod place_ext;
-crate mod places_conflict;
mod prefixes;
mod used_muts;
+mod constraint_generation;
+mod facts;
+mod invalidation;
+mod renumber;
+mod member_constraints;
+mod constraints;
+mod universal_regions;
+mod type_check;
+mod region_infer;
+mod borrow_set;
+mod place_ext;
+mod places_conflict;
+mod nll;
-pub(crate) mod nll;
+crate use region_infer::RegionInferenceContext;
+crate use borrow_set::{BorrowSet, BorrowData};
+crate use places_conflict::{places_conflict, PlaceConflictBias};
+crate use place_ext::PlaceExt;
+crate use nll::ToRegionVid;
// FIXME(eddyb) perhaps move this somewhere more centrally.
#[derive(Debug)]
@@ -102,7 +111,7 @@
fn do_mir_borrowck<'a, 'tcx>(
infcx: &InferCtxt<'a, 'tcx>,
input_body: &Body<'tcx>,
- input_promoted: &IndexVec<Promoted, BodyCache<'tcx>>,
+ input_promoted: &IndexVec<Promoted, BodyAndCache<'tcx>>,
def_id: DefId,
) -> BorrowCheckResult<'tcx> {
debug!("do_mir_borrowck(def_id = {:?})", def_id);
@@ -164,7 +173,7 @@
// will have a lifetime tied to the inference context.
let body_clone: Body<'tcx> = input_body.clone();
let mut promoted = input_promoted.clone();
- let mut body = BodyCache::new(body_clone);
+ let mut body = BodyAndCache::new(body_clone);
let free_regions =
nll::replace_regions_in_mir(infcx, def_id, param_env, &mut body, &mut promoted);
let body = read_only!(body); // no further changes
@@ -177,7 +186,7 @@
let mut errors_buffer = Vec::new();
let (move_data, move_errors): (MoveData<'tcx>, Option<Vec<(Place<'tcx>, MoveError<'tcx>)>>) =
- match MoveData::gather_moves(&body, tcx) {
+ match MoveData::gather_moves(&body, tcx, param_env) {
Ok(move_data) => (move_data, None),
Err((move_data, move_errors)) => (move_data, Some(move_errors)),
};
@@ -405,7 +414,7 @@
crate struct MirBorrowckCtxt<'cx, 'tcx> {
crate infcx: &'cx InferCtxt<'cx, 'tcx>,
- body: ReadOnlyBodyCache<'cx, 'tcx>,
+ body: ReadOnlyBodyAndCache<'cx, 'tcx>,
mir_def_id: DefId,
param_env: ty::ParamEnv<'tcx>,
move_data: &'cx MoveData<'tcx>,
@@ -496,7 +505,7 @@
type FlowState = Flows<'cx, 'tcx>;
fn body(&self) -> &'cx Body<'tcx> {
- self.body.body()
+ *self.body
}
fn visit_block_entry(&mut self, bb: BasicBlock, flow_state: &Self::FlowState) {
@@ -1603,7 +1612,6 @@
(prefix, place_span.0, place_span.1),
mpi,
);
- return; // don't bother finding other problems.
}
}
Err(NoMovePathFound::ReachedStatic) => {
@@ -1617,6 +1625,46 @@
}
}
+ /// Subslices correspond to multiple move paths, so we iterate through the
+ /// elements of the base array. For each element we check
+ ///
+ /// * Does this element overlap with our slice.
+ /// * Is any part of it uninitialized.
+ fn check_if_subslice_element_is_moved(
+ &mut self,
+ location: Location,
+ desired_action: InitializationRequiringAction,
+ place_span: (PlaceRef<'cx, 'tcx>, Span),
+ maybe_uninits: &FlowAtLocation<'tcx, MaybeUninitializedPlaces<'cx, 'tcx>>,
+ from: u32,
+ to: u32,
+ ) {
+ if let Some(mpi) = self.move_path_for_place(place_span.0) {
+ let mut child = self.move_data.move_paths[mpi].first_child;
+ while let Some(child_mpi) = child {
+ let child_move_place = &self.move_data.move_paths[child_mpi];
+ let child_place = &child_move_place.place;
+ let last_proj = child_place.projection.last().unwrap();
+ if let ProjectionElem::ConstantIndex { offset, from_end, .. } = last_proj {
+ debug_assert!(!from_end, "Array constant indexing shouldn't be `from_end`.");
+
+ if (from..to).contains(offset) {
+ if let Some(uninit_child) = maybe_uninits.has_any_child_of(child_mpi) {
+ self.report_use_of_moved_or_uninitialized(
+ location,
+ desired_action,
+ (place_span.0, place_span.0, place_span.1),
+ uninit_child,
+ );
+ return; // don't bother finding other problems.
+ }
+ }
+ }
+ child = child_move_place.next_sibling;
+ }
+ }
+ }
+
fn check_if_path_or_subpath_is_moved(
&mut self,
location: Location,
@@ -1643,6 +1691,30 @@
self.check_if_full_path_is_moved(location, desired_action, place_span, flow_state);
+ if let [
+ base_proj @ ..,
+ ProjectionElem::Subslice { from, to, from_end: false },
+ ] = place_span.0.projection {
+ let place_ty = Place::ty_from(
+ place_span.0.base,
+ base_proj,
+ self.body(),
+ self.infcx.tcx,
+ );
+ if let ty::Array(..) = place_ty.ty.kind {
+ let array_place = PlaceRef { base: place_span.0.base, projection: base_proj };
+ self.check_if_subslice_element_is_moved(
+ location,
+ desired_action,
+ (array_place, place_span.1),
+ maybe_uninits,
+ *from,
+ *to,
+ );
+ return;
+ }
+ }
+
// A move of any shallow suffix of `place` also interferes
// with an attempt to use `place`. This is scenario 3 above.
//
@@ -1678,25 +1750,16 @@
/// static variable, as we do not track those in the MoveData.
fn move_path_closest_to(
&mut self,
- place: PlaceRef<'cx, 'tcx>,
+ place: PlaceRef<'_, 'tcx>,
) -> Result<(PlaceRef<'cx, 'tcx>, MovePathIndex), NoMovePathFound> {
- let mut last_prefix = place.base;
-
- for prefix in self.prefixes(place, PrefixSet::All) {
- if let Some(mpi) = self.move_path_for_place(prefix) {
- return Ok((prefix, mpi));
- }
-
- last_prefix = prefix.base;
- }
-
- match last_prefix {
- PlaceBase::Local(_) => panic!("should have move path for every Local"),
- PlaceBase::Static(_) => Err(NoMovePathFound::ReachedStatic),
+ match self.move_data.rev_lookup.find(place) {
+ LookupResult::Parent(Some(mpi))
+ | LookupResult::Exact(mpi) => Ok((self.move_data.move_paths[mpi].place.as_ref(), mpi)),
+ LookupResult::Parent(None) => Err(NoMovePathFound::ReachedStatic),
}
}
- fn move_path_for_place(&mut self, place: PlaceRef<'cx, 'tcx>) -> Option<MovePathIndex> {
+ fn move_path_for_place(&mut self, place: PlaceRef<'_, 'tcx>) -> Option<MovePathIndex> {
// If returns None, then there is no move path corresponding
// to a direct owner of `place` (which means there is nothing
// that borrowck tracks for its analysis).
diff --git a/src/librustc_mir/borrow_check/nll/mod.rs b/src/librustc_mir/borrow_check/nll.rs
similarity index 82%
rename from src/librustc_mir/borrow_check/nll/mod.rs
rename to src/librustc_mir/borrow_check/nll.rs
index 16182fe..6d28a8c 100644
--- a/src/librustc_mir/borrow_check/nll/mod.rs
+++ b/src/librustc_mir/borrow_check/nll.rs
@@ -1,19 +1,10 @@
-use crate::borrow_check::borrow_set::BorrowSet;
-use crate::borrow_check::location::{LocationIndex, LocationTable};
-use crate::borrow_check::nll::facts::AllFactsExt;
-use crate::borrow_check::nll::type_check::{MirTypeckResults, MirTypeckRegionConstraints};
-use crate::borrow_check::nll::region_infer::values::RegionValueElements;
-use crate::dataflow::indexes::BorrowIndex;
-use crate::dataflow::move_paths::{InitLocation, MoveData, MovePathIndex, InitKind};
-use crate::dataflow::FlowAtLocation;
-use crate::dataflow::MaybeInitializedPlaces;
-use crate::transform::MirSource;
-use crate::borrow_check::Upvar;
+//! The entry point of the NLL borrow checker.
+
use rustc::hir::def_id::DefId;
use rustc::infer::InferCtxt;
use rustc::mir::{ClosureOutlivesSubject, ClosureRegionRequirements,
- Local, Location, Body, BodyCache, LocalKind, BasicBlock,
- Promoted, ReadOnlyBodyCache};
+ Local, Location, Body, BodyAndCache, LocalKind, BasicBlock,
+ Promoted, ReadOnlyBodyAndCache};
use rustc::ty::{self, RegionKind, RegionVid};
use rustc_index::vec::IndexVec;
use rustc_errors::Diagnostic;
@@ -28,24 +19,25 @@
use self::mir_util::PassWhere;
use polonius_engine::{Algorithm, Output};
+
use crate::util as mir_util;
use crate::util::pretty;
+use crate::dataflow::move_paths::{InitLocation, MoveData, InitKind};
+use crate::dataflow::FlowAtLocation;
+use crate::dataflow::MaybeInitializedPlaces;
+use crate::transform::MirSource;
-mod constraint_generation;
-pub mod explain_borrow;
-mod facts;
-mod invalidation;
-crate mod region_infer;
-mod renumber;
-crate mod type_check;
-mod universal_regions;
+use crate::borrow_check::{
+ borrow_set::BorrowSet,
+ location::LocationTable,
+ facts::{AllFacts, AllFactsExt, RustcFacts},
+ region_infer::{RegionInferenceContext, values::RegionValueElements},
+ universal_regions::UniversalRegions,
+ type_check::{self, MirTypeckResults, MirTypeckRegionConstraints},
+ Upvar, renumber, constraint_generation, invalidation,
+};
-mod constraints;
-mod member_constraints;
-
-use self::facts::AllFacts;
-use self::region_infer::RegionInferenceContext;
-use self::universal_regions::UniversalRegions;
+crate type PoloniusOutput = Output<RustcFacts>;
/// Rewrites the regions in the MIR to use NLL variables, also
/// scraping out the set of universal regions (e.g., region parameters)
@@ -55,8 +47,8 @@
infcx: &InferCtxt<'cx, 'tcx>,
def_id: DefId,
param_env: ty::ParamEnv<'tcx>,
- body: &mut BodyCache<'tcx>,
- promoted: &mut IndexVec<Promoted, BodyCache<'tcx>>,
+ body: &mut BodyAndCache<'tcx>,
+ promoted: &mut IndexVec<Promoted, BodyAndCache<'tcx>>,
) -> UniversalRegions<'tcx> {
debug!("replace_regions_in_mir(def_id={:?})", def_id);
@@ -158,8 +150,8 @@
infcx: &InferCtxt<'cx, 'tcx>,
def_id: DefId,
universal_regions: UniversalRegions<'tcx>,
- body: ReadOnlyBodyCache<'_, 'tcx>,
- promoted: &IndexVec<Promoted, ReadOnlyBodyCache<'_, 'tcx>>,
+ body: ReadOnlyBodyAndCache<'_, 'tcx>,
+ promoted: &IndexVec<Promoted, ReadOnlyBodyAndCache<'_, 'tcx>>,
local_names: &IndexVec<Local, Option<Symbol>>,
upvars: &[Upvar],
location_table: &LocationTable,
@@ -170,14 +162,10 @@
errors_buffer: &mut Vec<Diagnostic>,
) -> (
RegionInferenceContext<'tcx>,
- Option<Rc<Output<RegionVid, BorrowIndex, LocationIndex, Local, MovePathIndex>>>,
+ Option<Rc<PoloniusOutput>>,
Option<ClosureRegionRequirements<'tcx>>,
) {
- let mut all_facts = if AllFacts::enabled(infcx.tcx) {
- Some(AllFacts::default())
- } else {
- None
- };
+ let mut all_facts = AllFacts::enabled(infcx.tcx).then_some(AllFacts::default());
let universal_regions = Rc::new(universal_regions);
@@ -204,10 +192,44 @@
);
if let Some(all_facts) = &mut all_facts {
+ let _prof_timer = infcx.tcx.prof.generic_activity("polonius_fact_generation");
all_facts
.universal_region
.extend(universal_regions.universal_regions());
populate_polonius_move_facts(all_facts, move_data, location_table, &body);
+
+ // Emit universal regions facts, and their relations, for Polonius.
+ //
+ // 1: universal regions are modeled in Polonius as a pair:
+ // - the universal region vid itself.
+ // - a "placeholder loan" associated to this universal region. Since they don't exist in
+ // the `borrow_set`, their `BorrowIndex` are synthesized as the universal region index
+ // added to the existing number of loans, as if they succeeded them in the set.
+ //
+ let borrow_count = borrow_set.borrows.len();
+ debug!(
+ "compute_regions: polonius placeholders, num_universals={}, borrow_count={}",
+ universal_regions.len(),
+ borrow_count
+ );
+
+ for universal_region in universal_regions.universal_regions() {
+ let universal_region_idx = universal_region.index();
+ let placeholder_loan_idx = borrow_count + universal_region_idx;
+ all_facts.placeholder.push((universal_region, placeholder_loan_idx.into()));
+ }
+
+ // 2: the universal region relations `outlives` constraints are emitted as
+ // `known_subset` facts.
+ for (fr1, fr2) in universal_region_relations.known_outlives() {
+ if fr1 != fr2 {
+ debug!(
+ "compute_regions: emitting polonius `known_subset` fr1={:?}, fr2={:?}",
+ fr1, fr2
+ );
+ all_facts.known_subset.push((*fr1, *fr2));
+ }
+ }
}
// Create the region inference context, taking ownership of the
@@ -269,9 +291,10 @@
if infcx.tcx.sess.opts.debugging_opts.polonius {
let algorithm = env::var("POLONIUS_ALGORITHM")
- .unwrap_or_else(|_| String::from("Hybrid"));
+ .unwrap_or_else(|_| String::from("Naive"));
let algorithm = Algorithm::from_str(&algorithm).unwrap();
debug!("compute_regions: using polonius algorithm {:?}", algorithm);
+ let _prof_timer = infcx.tcx.prof.generic_activity("polonius_analysis");
Some(Rc::new(Output::compute(
&all_facts,
algorithm,
@@ -283,8 +306,15 @@
});
// Solve the region constraints.
- let closure_region_requirements =
- regioncx.solve(infcx, &body, local_names, upvars, def_id, errors_buffer);
+ let closure_region_requirements = regioncx.solve(
+ infcx,
+ &body,
+ local_names,
+ upvars,
+ def_id,
+ errors_buffer,
+ polonius_output.clone(),
+ );
// Dump MIR results into a file, if that is enabled. This let us
// write unit-tests, as well as helping with debugging.
diff --git a/src/librustc_mir/borrow_check/places_conflict.rs b/src/librustc_mir/borrow_check/places_conflict.rs
index 87a431a..9245064f 100644
--- a/src/librustc_mir/borrow_check/places_conflict.rs
+++ b/src/librustc_mir/borrow_check/places_conflict.rs
@@ -503,34 +503,62 @@
Overlap::Disjoint
}
}
- (ProjectionElem::ConstantIndex { offset, min_length: _, from_end: false },
- ProjectionElem::Subslice {from, .. })
- | (ProjectionElem::Subslice {from, .. },
- ProjectionElem::ConstantIndex { offset, min_length: _, from_end: false }) => {
- if offset >= from {
- debug!(
- "place_element_conflict: DISJOINT-OR-EQ-ARRAY-CONSTANT-INDEX-SUBSLICE");
+ (
+ ProjectionElem::ConstantIndex { offset, min_length: _, from_end: false },
+ ProjectionElem::Subslice { from, to, from_end: false }
+ )
+ | (
+ ProjectionElem::Subslice { from, to, from_end: false },
+ ProjectionElem::ConstantIndex { offset, min_length: _, from_end: false }
+ ) => {
+ if (from..to).contains(&offset) {
+ debug!("place_element_conflict: DISJOINT-OR-EQ-ARRAY-CONSTANT-INDEX-SUBSLICE");
Overlap::EqualOrDisjoint
} else {
debug!("place_element_conflict: DISJOINT-ARRAY-CONSTANT-INDEX-SUBSLICE");
Overlap::Disjoint
}
}
- (ProjectionElem::ConstantIndex { offset, min_length: _, from_end: true },
- ProjectionElem::Subslice {from: _, to })
- | (ProjectionElem::Subslice {from: _, to },
- ProjectionElem::ConstantIndex { offset, min_length: _, from_end: true }) => {
- if offset > to {
- debug!("place_element_conflict: \
- DISJOINT-OR-EQ-ARRAY-CONSTANT-INDEX-SUBSLICE-FE");
+ (ProjectionElem::ConstantIndex { offset, min_length: _, from_end: false },
+ ProjectionElem::Subslice {from, .. })
+ | (ProjectionElem::Subslice {from, .. },
+ ProjectionElem::ConstantIndex { offset, min_length: _, from_end: false }) => {
+ if offset >= from {
+ debug!(
+ "place_element_conflict: DISJOINT-OR-EQ-SLICE-CONSTANT-INDEX-SUBSLICE");
Overlap::EqualOrDisjoint
} else {
- debug!("place_element_conflict: DISJOINT-ARRAY-CONSTANT-INDEX-SUBSLICE-FE");
+ debug!("place_element_conflict: DISJOINT-SLICE-CONSTANT-INDEX-SUBSLICE");
Overlap::Disjoint
}
}
+ (ProjectionElem::ConstantIndex { offset, min_length: _, from_end: true },
+ ProjectionElem::Subslice { to, from_end: true, .. })
+ | (ProjectionElem::Subslice { to, from_end: true, .. },
+ ProjectionElem::ConstantIndex { offset, min_length: _, from_end: true }) => {
+ if offset > to {
+ debug!("place_element_conflict: \
+ DISJOINT-OR-EQ-SLICE-CONSTANT-INDEX-SUBSLICE-FE");
+ Overlap::EqualOrDisjoint
+ } else {
+ debug!("place_element_conflict: DISJOINT-SLICE-CONSTANT-INDEX-SUBSLICE-FE");
+ Overlap::Disjoint
+ }
+ }
+ (
+ ProjectionElem::Subslice { from: f1, to: t1, from_end: false },
+ ProjectionElem::Subslice { from: f2, to: t2, from_end: false }
+ ) => {
+ if f2 >= t1 || f1 >= t2 {
+ debug!("place_element_conflict: DISJOINT-ARRAY-SUBSLICES");
+ Overlap::Disjoint
+ } else {
+ debug!("place_element_conflict: DISJOINT-OR-EQ-ARRAY-SUBSLICES");
+ Overlap::EqualOrDisjoint
+ }
+ }
(ProjectionElem::Subslice { .. }, ProjectionElem::Subslice { .. }) => {
- debug!("place_element_conflict: DISJOINT-OR-EQ-ARRAY-SUBSLICES");
+ debug!("place_element_conflict: DISJOINT-OR-EQ-SLICE-SUBSLICES");
Overlap::EqualOrDisjoint
}
(ProjectionElem::Deref, _)
diff --git a/src/librustc_mir/borrow_check/prefixes.rs b/src/librustc_mir/borrow_check/prefixes.rs
index b58bf73..248faa5 100644
--- a/src/librustc_mir/borrow_check/prefixes.rs
+++ b/src/librustc_mir/borrow_check/prefixes.rs
@@ -11,7 +11,7 @@
use rustc::hir;
use rustc::ty::{self, TyCtxt};
-use rustc::mir::{Place, PlaceBase, PlaceRef, ProjectionElem, ReadOnlyBodyCache};
+use rustc::mir::{Place, PlaceBase, PlaceRef, ProjectionElem, ReadOnlyBodyAndCache};
pub trait IsPrefixOf<'cx, 'tcx> {
fn is_prefix_of(&self, other: PlaceRef<'cx, 'tcx>) -> bool;
@@ -26,7 +26,7 @@
}
pub(super) struct Prefixes<'cx, 'tcx> {
- body: ReadOnlyBodyCache<'cx, 'tcx>,
+ body: ReadOnlyBodyAndCache<'cx, 'tcx>,
tcx: TyCtxt<'tcx>,
kind: PrefixSet,
next: Option<PlaceRef<'cx, 'tcx>>,
diff --git a/src/librustc_mir/borrow_check/nll/region_infer/dump_mir.rs b/src/librustc_mir/borrow_check/region_infer/dump_mir.rs
similarity index 100%
rename from src/librustc_mir/borrow_check/nll/region_infer/dump_mir.rs
rename to src/librustc_mir/borrow_check/region_infer/dump_mir.rs
diff --git a/src/librustc_mir/borrow_check/nll/region_infer/graphviz.rs b/src/librustc_mir/borrow_check/region_infer/graphviz.rs
similarity index 98%
rename from src/librustc_mir/borrow_check/nll/region_infer/graphviz.rs
rename to src/librustc_mir/borrow_check/region_infer/graphviz.rs
index fdf2af9..29c6f32 100644
--- a/src/librustc_mir/borrow_check/nll/region_infer/graphviz.rs
+++ b/src/librustc_mir/borrow_check/region_infer/graphviz.rs
@@ -2,11 +2,12 @@
//! libgraphviz traits, specialized to attaching borrowck analysis
//! data to rendered labels.
-use super::*;
-use crate::borrow_check::nll::constraints::OutlivesConstraint;
use std::borrow::Cow;
use std::io::{self, Write};
+use super::*;
+use crate::borrow_check::constraints::OutlivesConstraint;
+
impl<'tcx> RegionInferenceContext<'tcx> {
/// Write out the region constraint graph.
crate fn dump_graphviz_raw_constraints(&self, mut w: &mut dyn Write) -> io::Result<()> {
diff --git a/src/librustc_mir/borrow_check/nll/region_infer/mod.rs b/src/librustc_mir/borrow_check/region_infer/mod.rs
similarity index 87%
rename from src/librustc_mir/borrow_check/nll/region_infer/mod.rs
rename to src/librustc_mir/borrow_check/region_infer/mod.rs
index bd9e97e..b6946e2 100644
--- a/src/librustc_mir/borrow_check/nll/region_infer/mod.rs
+++ b/src/librustc_mir/borrow_check/region_infer/mod.rs
@@ -1,21 +1,5 @@
use std::rc::Rc;
-use crate::borrow_check::nll::{
- constraints::{
- graph::NormalConstraintGraph,
- ConstraintSccIndex,
- OutlivesConstraint,
- OutlivesConstraintSet,
- },
- member_constraints::{MemberConstraintSet, NllMemberConstraintIndex},
- region_infer::values::{
- PlaceholderIndices, RegionElement, ToElementIndex
- },
- region_infer::error_reporting::outlives_suggestion::OutlivesSuggestionBuilder,
- type_check::{free_region_relations::UniversalRegionRelations, Locations},
-};
-use crate::borrow_check::Upvar;
-
use rustc::hir::def_id::DefId;
use rustc::infer::canonical::QueryOutlivesConstraint;
use rustc::infer::opaque_types;
@@ -38,13 +22,28 @@
use syntax_pos::Span;
use syntax_pos::symbol::Symbol;
-crate use self::error_reporting::{RegionName, RegionNameSource, RegionErrorNamingCtx};
-use self::values::{LivenessValues, RegionValueElements, RegionValues};
-use super::universal_regions::UniversalRegions;
-use super::ToRegionVid;
+use crate::borrow_check::{
+ constraints::{
+ graph::NormalConstraintGraph,
+ ConstraintSccIndex,
+ OutlivesConstraint,
+ OutlivesConstraintSet,
+ },
+ member_constraints::{MemberConstraintSet, NllMemberConstraintIndex},
+ region_infer::values::{
+ PlaceholderIndices, RegionElement, ToElementIndex, LivenessValues, RegionValueElements,
+ RegionValues,
+ },
+ type_check::{free_region_relations::UniversalRegionRelations, Locations},
+ diagnostics::{
+ OutlivesSuggestionBuilder, RegionErrorNamingCtx,
+ },
+ nll::{ToRegionVid, PoloniusOutput},
+ universal_regions::UniversalRegions,
+ Upvar,
+};
mod dump_mir;
-mod error_reporting;
mod graphviz;
pub mod values;
@@ -54,48 +53,51 @@
/// variables are identified by their index (`RegionVid`). The
/// definition contains information about where the region came
/// from as well as its final inferred value.
- definitions: IndexVec<RegionVid, RegionDefinition<'tcx>>,
+ pub(in crate::borrow_check) definitions: IndexVec<RegionVid, RegionDefinition<'tcx>>,
/// The liveness constraints added to each region. For most
/// regions, these start out empty and steadily grow, though for
/// each universally quantified region R they start out containing
/// the entire CFG and `end(R)`.
- liveness_constraints: LivenessValues<RegionVid>,
+ pub(in crate::borrow_check) liveness_constraints: LivenessValues<RegionVid>,
/// The outlives constraints computed by the type-check.
- constraints: Rc<OutlivesConstraintSet>,
+ pub(in crate::borrow_check) constraints: Rc<OutlivesConstraintSet>,
/// The constraint-set, but in graph form, making it easy to traverse
/// the constraints adjacent to a particular region. Used to construct
/// the SCC (see `constraint_sccs`) and for error reporting.
- constraint_graph: Rc<NormalConstraintGraph>,
+ pub(in crate::borrow_check) constraint_graph: Rc<NormalConstraintGraph>,
/// The SCC computed from `constraints` and the constraint
/// graph. We have an edge from SCC A to SCC B if `A: B`. Used to
/// compute the values of each region.
- constraint_sccs: Rc<Sccs<RegionVid, ConstraintSccIndex>>,
+ pub(in crate::borrow_check) constraint_sccs: Rc<Sccs<RegionVid, ConstraintSccIndex>>,
/// Reverse of the SCC constraint graph -- i.e., an edge `A -> B`
/// exists if `B: A`. Computed lazilly.
- rev_constraint_graph: Option<Rc<VecGraph<ConstraintSccIndex>>>,
+ pub(in crate::borrow_check) rev_constraint_graph:
+ Option<Rc<VecGraph<ConstraintSccIndex>>>,
/// The "R0 member of [R1..Rn]" constraints, indexed by SCC.
- member_constraints: Rc<MemberConstraintSet<'tcx, ConstraintSccIndex>>,
+ pub(in crate::borrow_check) member_constraints:
+ Rc<MemberConstraintSet<'tcx, ConstraintSccIndex>>,
/// Records the member constraints that we applied to each scc.
/// This is useful for error reporting. Once constraint
/// propagation is done, this vector is sorted according to
/// `member_region_scc`.
- member_constraints_applied: Vec<AppliedMemberConstraint>,
+ pub(in crate::borrow_check) member_constraints_applied: Vec<AppliedMemberConstraint>,
/// Map closure bounds to a `Span` that should be used for error reporting.
- closure_bounds_mapping:
+ pub(in crate::borrow_check) closure_bounds_mapping:
FxHashMap<Location, FxHashMap<(RegionVid, RegionVid), (ConstraintCategory, Span)>>,
/// Contains the minimum universe of any variable within the same
/// SCC. We will ensure that no SCC contains values that are not
/// visible from this index.
- scc_universes: IndexVec<ConstraintSccIndex, ty::UniverseIndex>,
+ pub(in crate::borrow_check) scc_universes:
+ IndexVec<ConstraintSccIndex, ty::UniverseIndex>,
/// Contains a "representative" from each SCC. This will be the
/// minimal RegionVid belonging to that universe. It is used as a
@@ -104,23 +106,25 @@
/// of its SCC and be sure that -- if they have the same repr --
/// they *must* be equal (though not having the same repr does not
/// mean they are unequal).
- scc_representatives: IndexVec<ConstraintSccIndex, ty::RegionVid>,
+ pub(in crate::borrow_check) scc_representatives:
+ IndexVec<ConstraintSccIndex, ty::RegionVid>,
/// The final inferred values of the region variables; we compute
/// one value per SCC. To get the value for any given *region*,
/// you first find which scc it is a part of.
- scc_values: RegionValues<ConstraintSccIndex>,
+ pub(in crate::borrow_check) scc_values: RegionValues<ConstraintSccIndex>,
/// Type constraints that we check after solving.
- type_tests: Vec<TypeTest<'tcx>>,
+ pub(in crate::borrow_check) type_tests: Vec<TypeTest<'tcx>>,
/// Information about the universally quantified regions in scope
/// on this function.
- universal_regions: Rc<UniversalRegions<'tcx>>,
+ pub (in crate::borrow_check) universal_regions: Rc<UniversalRegions<'tcx>>,
/// Information about how the universally quantified regions in
/// scope on this function relate to one another.
- universal_region_relations: Rc<UniversalRegionRelations<'tcx>>,
+ pub(in crate::borrow_check) universal_region_relations:
+ Rc<UniversalRegionRelations<'tcx>>,
}
/// Each time that `apply_member_constraint` is successful, it appends
@@ -132,38 +136,38 @@
/// with `'R: 'O` where `'R` is the pick-region and `'O` is the
/// minimal viable option.
#[derive(Copy, Clone, Debug, Eq, PartialEq, Ord, PartialOrd)]
-struct AppliedMemberConstraint {
+pub(crate) struct AppliedMemberConstraint {
/// The SCC that was affected. (The "member region".)
///
/// The vector if `AppliedMemberConstraint` elements is kept sorted
/// by this field.
- member_region_scc: ConstraintSccIndex,
+ pub(in crate::borrow_check) member_region_scc: ConstraintSccIndex,
/// The "best option" that `apply_member_constraint` found -- this was
/// added as an "ad-hoc" lower-bound to `member_region_scc`.
- min_choice: ty::RegionVid,
+ pub(in crate::borrow_check) min_choice: ty::RegionVid,
/// The "member constraint index" -- we can find out details about
/// the constraint from
/// `set.member_constraints[member_constraint_index]`.
- member_constraint_index: NllMemberConstraintIndex,
+ pub(in crate::borrow_check) member_constraint_index: NllMemberConstraintIndex,
}
-struct RegionDefinition<'tcx> {
+pub(crate) struct RegionDefinition<'tcx> {
/// What kind of variable is this -- a free region? existential
/// variable? etc. (See the `NLLRegionVariableOrigin` for more
/// info.)
- origin: NLLRegionVariableOrigin,
+ pub(in crate::borrow_check) origin: NLLRegionVariableOrigin,
/// Which universe is this region variable defined in? This is
/// most often `ty::UniverseIndex::ROOT`, but when we encounter
/// forall-quantifiers like `for<'a> { 'a = 'b }`, we would create
/// the variable for `'a` in a fresh universe that extends ROOT.
- universe: ty::UniverseIndex,
+ pub(in crate::borrow_check) universe: ty::UniverseIndex,
/// If this is 'static or an early-bound region, then this is
/// `Some(X)` where `X` is the name of the region.
- external_name: Option<ty::Region<'tcx>>,
+ pub(in crate::borrow_check) external_name: Option<ty::Region<'tcx>>,
}
/// N.B., the variants in `Cause` are intentionally ordered. Lower
@@ -455,7 +459,9 @@
/// Once region solving has completed, this function will return
/// the member constraints that were applied to the value of a given
/// region `r`. See `AppliedMemberConstraint`.
- fn applied_member_constraints(&self, r: impl ToRegionVid) -> &[AppliedMemberConstraint] {
+ pub(in crate::borrow_check) fn applied_member_constraints(
+ &self, r: impl ToRegionVid
+ ) -> &[AppliedMemberConstraint] {
let scc = self.constraint_sccs.scc(r.to_region_vid());
binary_search_util::binary_search_slice(
&self.member_constraints_applied,
@@ -475,6 +481,7 @@
upvars: &[Upvar],
mir_def_id: DefId,
errors_buffer: &mut Vec<Diagnostic>,
+ polonius_output: Option<Rc<PoloniusOutput>>,
) -> Option<ClosureRegionRequirements<'tcx>> {
self.propagate_constraints(body);
@@ -484,7 +491,7 @@
// functions below, which will trigger them to report errors
// eagerly.
let mut outlives_requirements =
- if infcx.tcx.is_closure(mir_def_id) { Some(vec![]) } else { None };
+ infcx.tcx.is_closure(mir_def_id).then(|| vec![]);
self.check_type_tests(
infcx,
@@ -500,16 +507,33 @@
// multiple problems.
let mut region_naming = RegionErrorNamingCtx::new();
- self.check_universal_regions(
- infcx,
- body,
- local_names,
- upvars,
- mir_def_id,
- outlives_requirements.as_mut(),
- errors_buffer,
- &mut region_naming,
- );
+ // In Polonius mode, the errors about missing universal region relations are in the output
+ // and need to be emitted or propagated. Otherwise, we need to check whether the
+ // constraints were too strong, and if so, emit or propagate those errors.
+ if infcx.tcx.sess.opts.debugging_opts.polonius {
+ self.check_polonius_subset_errors(
+ infcx,
+ body,
+ local_names,
+ upvars,
+ mir_def_id,
+ outlives_requirements.as_mut(),
+ errors_buffer,
+ &mut region_naming,
+ polonius_output.expect("Polonius output is unavailable despite `-Z polonius`"),
+ );
+ } else {
+ self.check_universal_regions(
+ infcx,
+ body,
+ local_names,
+ upvars,
+ mir_def_id,
+ outlives_requirements.as_mut(),
+ errors_buffer,
+ &mut region_naming,
+ );
+ }
self.check_member_constraints(infcx, mir_def_id, errors_buffer);
@@ -700,14 +724,11 @@
let min = |r1: ty::RegionVid, r2: ty::RegionVid| -> Option<ty::RegionVid> {
let r1_outlives_r2 = self.universal_region_relations.outlives(r1, r2);
let r2_outlives_r1 = self.universal_region_relations.outlives(r2, r1);
- if r1_outlives_r2 && r2_outlives_r1 {
- Some(r1.min(r2))
- } else if r1_outlives_r2 {
- Some(r2)
- } else if r2_outlives_r1 {
- Some(r1)
- } else {
- None
+ match (r1_outlives_r2, r2_outlives_r1) {
+ (true, true) => Some(r1.min(r2)),
+ (true, false) => Some(r2),
+ (false, true) => Some(r1),
+ (false, false) => None,
}
};
let mut min_choice = choice_regions[0];
@@ -1366,6 +1387,114 @@
outlives_suggestion.add_suggestion(body, self, infcx, errors_buffer, region_naming);
}
+ /// Checks if Polonius has found any unexpected free region relations.
+ ///
+ /// In Polonius terms, a "subset error" (or "illegal subset relation error") is the equivalent
+ /// of NLL's "checking if any region constraints were too strong": a placeholder origin `'a`
+ /// was unexpectedly found to be a subset of another placeholder origin `'b`, and means in NLL
+ /// terms that the "longer free region" `'a` outlived the "shorter free region" `'b`.
+ ///
+ /// More details can be found in this blog post by Niko:
+ /// http://smallcultfollowing.com/babysteps/blog/2019/01/17/polonius-and-region-errors/
+ ///
+ /// In the canonical example
+ ///
+ /// fn foo<'a, 'b>(x: &'a u32) -> &'b u32 { x }
+ ///
+ /// returning `x` requires `&'a u32 <: &'b u32` and hence we establish (transitively) a
+ /// constraint that `'a: 'b`. It is an error that we have no evidence that this
+ /// constraint holds.
+ ///
+ /// If `propagated_outlives_requirements` is `Some`, then we will
+ /// push unsatisfied obligations into there. Otherwise, we'll
+ /// report them as errors.
+ fn check_polonius_subset_errors(
+ &self,
+ infcx: &InferCtxt<'_, 'tcx>,
+ body: &Body<'tcx>,
+ local_names: &IndexVec<Local, Option<Symbol>>,
+ upvars: &[Upvar],
+ mir_def_id: DefId,
+ mut propagated_outlives_requirements: Option<&mut Vec<ClosureOutlivesRequirement<'tcx>>>,
+ errors_buffer: &mut Vec<Diagnostic>,
+ region_naming: &mut RegionErrorNamingCtx,
+ polonius_output: Rc<PoloniusOutput>,
+ ) {
+ debug!(
+ "check_polonius_subset_errors: {} subset_errors",
+ polonius_output.subset_errors.len()
+ );
+
+ let mut outlives_suggestion = OutlivesSuggestionBuilder::new(mir_def_id, local_names);
+
+ // Similarly to `check_universal_regions`: a free region relation, which was not explicitly
+ // declared ("known") was found by Polonius, so emit an error, or propagate the
+ // requirements for our caller into the `propagated_outlives_requirements` vector.
+ //
+ // Polonius doesn't model regions ("origins") as CFG-subsets or durations, but the
+ // `longer_fr` and `shorter_fr` terminology will still be used here, for consistency with
+ // the rest of the NLL infrastructure. The "subset origin" is the "longer free region",
+ // and the "superset origin" is the outlived "shorter free region".
+ //
+ // Note: Polonius will produce a subset error at every point where the unexpected
+ // `longer_fr`'s "placeholder loan" is contained in the `shorter_fr`. This can be helpful
+ // for diagnostics in the future, e.g. to point more precisely at the key locations
+ // requiring this constraint to hold. However, the error and diagnostics code downstream
+ // expects that these errors are not duplicated (and that they are in a certain order).
+ // Otherwise, diagnostics messages such as the ones giving names like `'1` to elided or
+ // anonymous lifetimes for example, could give these names differently, while others like
+ // the outlives suggestions or the debug output from `#[rustc_regions]` would be
+ // duplicated. The polonius subset errors are deduplicated here, while keeping the
+ // CFG-location ordering.
+ let mut subset_errors: Vec<_> = polonius_output
+ .subset_errors
+ .iter()
+ .flat_map(|(_location, subset_errors)| subset_errors.iter())
+ .collect();
+ subset_errors.sort();
+ subset_errors.dedup();
+
+ for (longer_fr, shorter_fr) in subset_errors.into_iter() {
+ debug!("check_polonius_subset_errors: subset_error longer_fr={:?},\
+ shorter_fr={:?}", longer_fr, shorter_fr);
+
+ self.report_or_propagate_universal_region_error(
+ *longer_fr,
+ *shorter_fr,
+ infcx,
+ body,
+ local_names,
+ upvars,
+ mir_def_id,
+ &mut propagated_outlives_requirements,
+ &mut outlives_suggestion,
+ errors_buffer,
+ region_naming,
+ );
+ }
+
+ // Handle the placeholder errors as usual, until the chalk-rustc-polonius triumvirate has
+ // a more complete picture on how to separate this responsibility.
+ for (fr, fr_definition) in self.definitions.iter_enumerated() {
+ match fr_definition.origin {
+ NLLRegionVariableOrigin::FreeRegion => {
+ // handled by polonius above
+ }
+
+ NLLRegionVariableOrigin::Placeholder(placeholder) => {
+ self.check_bound_universal_region(infcx, body, mir_def_id, fr, placeholder);
+ }
+
+ NLLRegionVariableOrigin::Existential { .. } => {
+ // nothing to check here
+ }
+ }
+ }
+
+ // Emit outlives suggestions
+ outlives_suggestion.add_suggestion(body, self, infcx, errors_buffer, region_naming);
+ }
+
/// Checks the final value for the free region `fr` to see if it
/// grew too large. In particular, examine what `end(X)` points
/// wound up in `fr`'s final value; for each `end(X)` where `X !=
@@ -1465,8 +1594,37 @@
return None;
}
+ self.report_or_propagate_universal_region_error(
+ longer_fr,
+ shorter_fr,
+ infcx,
+ body,
+ local_names,
+ upvars,
+ mir_def_id,
+ propagated_outlives_requirements,
+ outlives_suggestion,
+ errors_buffer,
+ region_naming,
+ )
+ }
+
+ fn report_or_propagate_universal_region_error(
+ &self,
+ longer_fr: RegionVid,
+ shorter_fr: RegionVid,
+ infcx: &InferCtxt<'_, 'tcx>,
+ body: &Body<'tcx>,
+ local_names: &IndexVec<Local, Option<Symbol>>,
+ upvars: &[Upvar],
+ mir_def_id: DefId,
+ propagated_outlives_requirements: &mut Option<&mut Vec<ClosureOutlivesRequirement<'tcx>>>,
+ outlives_suggestion: &mut OutlivesSuggestionBuilder<'_>,
+ errors_buffer: &mut Vec<Diagnostic>,
+ region_naming: &mut RegionErrorNamingCtx,
+ ) -> Option<ErrorReported> {
debug!(
- "check_universal_region_relation: fr={:?} does not outlive shorter_fr={:?}",
+ "report_or_propagate_universal_region_error: fr={:?} does not outlive shorter_fr={:?}",
longer_fr, shorter_fr,
);
@@ -1475,9 +1633,9 @@
// We'll call it `fr-` -- it's ever so slightly smaller than
// `longer_fr`.
- if let Some(fr_minus) = self.universal_region_relations.non_local_lower_bound(longer_fr)
- {
- debug!("check_universal_region: fr_minus={:?}", fr_minus);
+ if let Some(fr_minus) =
+ self.universal_region_relations.non_local_lower_bound(longer_fr) {
+ debug!("report_or_propagate_universal_region_error: fr_minus={:?}", fr_minus);
let blame_span_category =
self.find_outlives_blame_span(body, longer_fr,
@@ -1486,9 +1644,13 @@
// Grow `shorter_fr` until we find some non-local regions. (We
// always will.) We'll call them `shorter_fr+` -- they're ever
// so slightly larger than `shorter_fr`.
- let shorter_fr_plus =
- self.universal_region_relations.non_local_upper_bounds(&shorter_fr);
- debug!("check_universal_region: shorter_fr_plus={:?}", shorter_fr_plus);
+ let shorter_fr_plus = self
+ .universal_region_relations
+ .non_local_upper_bounds(&shorter_fr);
+ debug!(
+ "report_or_propagate_universal_region_error: shorter_fr_plus={:?}",
+ shorter_fr_plus
+ );
for &&fr in &shorter_fr_plus {
// Push the constraint `fr-: shorter_fr+`
propagated_outlives_requirements.push(ClosureOutlivesRequirement {
diff --git a/src/librustc_mir/borrow_check/nll/region_infer/values.rs b/src/librustc_mir/borrow_check/region_infer/values.rs
similarity index 99%
rename from src/librustc_mir/borrow_check/nll/region_infer/values.rs
rename to src/librustc_mir/borrow_check/region_infer/values.rs
index b4414c5..0bf0cd3 100644
--- a/src/librustc_mir/borrow_check/nll/region_infer/values.rs
+++ b/src/librustc_mir/borrow_check/region_infer/values.rs
@@ -1,4 +1,4 @@
-use rustc::mir::{BasicBlock, Location, Body, ReadOnlyBodyCache};
+use rustc::mir::{BasicBlock, Location, Body, ReadOnlyBodyAndCache};
use rustc::ty::{self, RegionVid};
use rustc_index::bit_set::{HybridBitSet, SparseBitMatrix};
use rustc_data_structures::fx::FxHashMap;
@@ -92,7 +92,7 @@
/// Pushes all predecessors of `index` onto `stack`.
crate fn push_predecessors(
&self,
- body: ReadOnlyBodyCache<'_, '_>,
+ body: ReadOnlyBodyAndCache<'_, '_>,
index: PointIndex,
stack: &mut Vec<PointIndex>,
) {
diff --git a/src/librustc_mir/borrow_check/nll/renumber.rs b/src/librustc_mir/borrow_check/renumber.rs
similarity index 94%
rename from src/librustc_mir/borrow_check/nll/renumber.rs
rename to src/librustc_mir/borrow_check/renumber.rs
index db15d2c..ba323b1 100644
--- a/src/librustc_mir/borrow_check/nll/renumber.rs
+++ b/src/librustc_mir/borrow_check/renumber.rs
@@ -1,6 +1,6 @@
use rustc::ty::subst::SubstsRef;
use rustc::ty::{self, Ty, TyCtxt, TypeFoldable};
-use rustc::mir::{BodyCache, Location, PlaceElem, Promoted};
+use rustc::mir::{BodyAndCache, Location, PlaceElem, Promoted};
use rustc::mir::visit::{MutVisitor, TyContext};
use rustc::infer::{InferCtxt, NLLRegionVariableOrigin};
use rustc_index::vec::IndexVec;
@@ -9,8 +9,8 @@
/// inference variables, returning the number of variables created.
pub fn renumber_mir<'tcx>(
infcx: &InferCtxt<'_, 'tcx>,
- body: &mut BodyCache<'tcx>,
- promoted: &mut IndexVec<Promoted, BodyCache<'tcx>>,
+ body: &mut BodyAndCache<'tcx>,
+ promoted: &mut IndexVec<Promoted, BodyAndCache<'tcx>>,
) {
debug!("renumber_mir()");
debug!("renumber_mir: body.arg_count={:?}", body.arg_count);
diff --git a/src/librustc_mir/borrow_check/nll/type_check/constraint_conversion.rs b/src/librustc_mir/borrow_check/type_check/constraint_conversion.rs
similarity index 95%
rename from src/librustc_mir/borrow_check/nll/type_check/constraint_conversion.rs
rename to src/librustc_mir/borrow_check/type_check/constraint_conversion.rs
index 34ac96b..334477d 100644
--- a/src/librustc_mir/borrow_check/nll/type_check/constraint_conversion.rs
+++ b/src/librustc_mir/borrow_check/type_check/constraint_conversion.rs
@@ -1,8 +1,3 @@
-use crate::borrow_check::nll::constraints::OutlivesConstraint;
-use crate::borrow_check::nll::region_infer::TypeTest;
-use crate::borrow_check::nll::type_check::{Locations, MirTypeckRegionConstraints};
-use crate::borrow_check::nll::universal_regions::UniversalRegions;
-use crate::borrow_check::nll::ToRegionVid;
use rustc::infer::canonical::QueryRegionConstraints;
use rustc::infer::canonical::QueryOutlivesConstraint;
use rustc::infer::outlives::env::RegionBoundPairs;
@@ -14,6 +9,14 @@
use rustc::ty::{self, TyCtxt};
use syntax_pos::DUMMY_SP;
+use crate::borrow_check::{
+ constraints::OutlivesConstraint,
+ region_infer::TypeTest,
+ type_check::{Locations, MirTypeckRegionConstraints},
+ universal_regions::UniversalRegions,
+ nll::ToRegionVid,
+};
+
crate struct ConstraintConversion<'a, 'tcx> {
infcx: &'a InferCtxt<'a, 'tcx>,
tcx: TyCtxt<'tcx>,
diff --git a/src/librustc_mir/borrow_check/nll/type_check/free_region_relations.rs b/src/librustc_mir/borrow_check/type_check/free_region_relations.rs
similarity index 97%
rename from src/librustc_mir/borrow_check/nll/type_check/free_region_relations.rs
rename to src/librustc_mir/borrow_check/type_check/free_region_relations.rs
index d18a8e8..03a7f97 100644
--- a/src/librustc_mir/borrow_check/nll/type_check/free_region_relations.rs
+++ b/src/librustc_mir/borrow_check/type_check/free_region_relations.rs
@@ -1,7 +1,3 @@
-use crate::borrow_check::nll::type_check::constraint_conversion;
-use crate::borrow_check::nll::type_check::{Locations, MirTypeckRegionConstraints};
-use crate::borrow_check::nll::universal_regions::UniversalRegions;
-use crate::borrow_check::nll::ToRegionVid;
use rustc::infer::canonical::QueryRegionConstraints;
use rustc::infer::outlives::free_region_map::FreeRegionRelations;
use rustc::infer::region_constraints::GenericKind;
@@ -14,6 +10,13 @@
use std::rc::Rc;
use syntax_pos::DUMMY_SP;
+use crate::borrow_check::{
+ type_check::constraint_conversion,
+ type_check::{Locations, MirTypeckRegionConstraints},
+ universal_regions::UniversalRegions,
+ nll::ToRegionVid,
+};
+
#[derive(Debug)]
crate struct UniversalRegionRelations<'tcx> {
universal_regions: Rc<UniversalRegions<'tcx>>,
@@ -217,6 +220,11 @@
crate fn regions_outlived_by(&self, fr1: RegionVid) -> Vec<&RegionVid> {
self.outlives.reachable_from(&fr1)
}
+
+ /// Returns the _non-transitive_ set of known `outlives` constraints between free regions.
+ crate fn known_outlives(&self) -> impl Iterator<Item=(&RegionVid, &RegionVid)> {
+ self.outlives.base_edges()
+ }
}
struct UniversalRegionRelationsBuilder<'this, 'tcx> {
diff --git a/src/librustc_mir/borrow_check/nll/type_check/input_output.rs b/src/librustc_mir/borrow_check/type_check/input_output.rs
similarity index 98%
rename from src/librustc_mir/borrow_check/nll/type_check/input_output.rs
rename to src/librustc_mir/borrow_check/type_check/input_output.rs
index 35fb677..3df0490 100644
--- a/src/librustc_mir/borrow_check/nll/type_check/input_output.rs
+++ b/src/librustc_mir/borrow_check/type_check/input_output.rs
@@ -7,7 +7,6 @@
//! `RETURN_PLACE` the MIR arguments) are always fully normalized (and
//! contain revealed `impl Trait` values).
-use crate::borrow_check::nll::universal_regions::UniversalRegions;
use rustc::infer::LateBoundRegionConversionTime;
use rustc::mir::*;
use rustc::ty::Ty;
@@ -15,6 +14,8 @@
use rustc_index::vec::Idx;
use syntax_pos::Span;
+use crate::borrow_check::universal_regions::UniversalRegions;
+
use super::{Locations, TypeChecker};
impl<'a, 'tcx> TypeChecker<'a, 'tcx> {
diff --git a/src/librustc_mir/borrow_check/nll/type_check/liveness/local_use_map.rs b/src/librustc_mir/borrow_check/type_check/liveness/local_use_map.rs
similarity index 96%
rename from src/librustc_mir/borrow_check/nll/type_check/liveness/local_use_map.rs
rename to src/librustc_mir/borrow_check/type_check/liveness/local_use_map.rs
index d6aa314..75e4f61 100644
--- a/src/librustc_mir/borrow_check/nll/type_check/liveness/local_use_map.rs
+++ b/src/librustc_mir/borrow_check/type_check/liveness/local_use_map.rs
@@ -1,10 +1,12 @@
-use crate::borrow_check::nll::region_infer::values::{PointIndex, RegionValueElements};
-use crate::util::liveness::{categorize, DefUse};
use rustc::mir::visit::{PlaceContext, Visitor};
-use rustc::mir::{Local, Location, ReadOnlyBodyCache};
+use rustc::mir::{Local, Location, ReadOnlyBodyAndCache};
use rustc_index::vec::{Idx, IndexVec};
use rustc_data_structures::vec_linked_list as vll;
+use crate::util::liveness::{categorize, DefUse};
+
+use crate::borrow_check::region_infer::values::{PointIndex, RegionValueElements};
+
/// A map that cross references each local with the locations where it
/// is defined (assigned), used, or dropped. Used during liveness
/// computation.
@@ -60,7 +62,7 @@
crate fn build(
live_locals: &Vec<Local>,
elements: &RegionValueElements,
- body: ReadOnlyBodyCache<'_, '_>,
+ body: ReadOnlyBodyAndCache<'_, '_>,
) -> Self {
let nones = IndexVec::from_elem_n(None, body.local_decls.len());
let mut local_use_map = LocalUseMap {
diff --git a/src/librustc_mir/borrow_check/nll/type_check/liveness/mod.rs b/src/librustc_mir/borrow_check/type_check/liveness/mod.rs
similarity index 91%
rename from src/librustc_mir/borrow_check/nll/type_check/liveness/mod.rs
rename to src/librustc_mir/borrow_check/type_check/liveness/mod.rs
index dfd505f..ee3d89e 100644
--- a/src/librustc_mir/borrow_check/nll/type_check/liveness/mod.rs
+++ b/src/librustc_mir/borrow_check/type_check/liveness/mod.rs
@@ -1,17 +1,21 @@
-use crate::borrow_check::location::LocationTable;
-use crate::borrow_check::nll::constraints::OutlivesConstraintSet;
-use crate::borrow_check::nll::facts::{AllFacts, AllFactsExt};
-use crate::borrow_check::nll::region_infer::values::RegionValueElements;
-use crate::borrow_check::nll::universal_regions::UniversalRegions;
-use crate::borrow_check::nll::ToRegionVid;
-use crate::dataflow::move_paths::MoveData;
-use crate::dataflow::FlowAtLocation;
-use crate::dataflow::MaybeInitializedPlaces;
-use rustc::mir::{Body, Local, ReadOnlyBodyCache};
+use rustc::mir::{Body, Local, ReadOnlyBodyAndCache};
use rustc::ty::{RegionVid, TyCtxt};
use rustc_data_structures::fx::FxHashSet;
use std::rc::Rc;
+use crate::dataflow::move_paths::MoveData;
+use crate::dataflow::FlowAtLocation;
+use crate::dataflow::MaybeInitializedPlaces;
+
+use crate::borrow_check::{
+ location::LocationTable,
+ constraints::OutlivesConstraintSet,
+ facts::{AllFacts, AllFactsExt},
+ region_infer::values::RegionValueElements,
+ universal_regions::UniversalRegions,
+ nll::ToRegionVid,
+};
+
use super::TypeChecker;
mod local_use_map;
@@ -28,7 +32,7 @@
/// performed before
pub(super) fn generate<'tcx>(
typeck: &mut TypeChecker<'_, 'tcx>,
- body: ReadOnlyBodyCache<'_, 'tcx>,
+ body: ReadOnlyBodyAndCache<'_, 'tcx>,
elements: &Rc<RegionValueElements>,
flow_inits: &mut FlowAtLocation<'tcx, MaybeInitializedPlaces<'_, 'tcx>>,
move_data: &MoveData<'tcx>,
diff --git a/src/librustc_mir/borrow_check/nll/type_check/liveness/polonius.rs b/src/librustc_mir/borrow_check/type_check/liveness/polonius.rs
similarity index 68%
rename from src/librustc_mir/borrow_check/nll/type_check/liveness/polonius.rs
rename to src/librustc_mir/borrow_check/type_check/liveness/polonius.rs
index e67de6c..0354b0d 100644
--- a/src/librustc_mir/borrow_check/nll/type_check/liveness/polonius.rs
+++ b/src/librustc_mir/borrow_check/type_check/liveness/polonius.rs
@@ -3,22 +3,21 @@
use crate::dataflow::move_paths::{LookupResult, MoveData};
use crate::util::liveness::{categorize, DefUse};
use rustc::mir::visit::{MutatingUseContext, PlaceContext, Visitor};
-use rustc::mir::{Local, Location, Place, ReadOnlyBodyCache};
+use rustc::mir::{Local, Location, Place, ReadOnlyBodyAndCache};
use rustc::ty::subst::GenericArg;
-use rustc::ty::Ty;
use super::TypeChecker;
-type VarPointRelations = Vec<(Local, LocationIndex)>;
-type MovePathPointRelations = Vec<(MovePathIndex, LocationIndex)>;
+type VarPointRelation = Vec<(Local, LocationIndex)>;
+type PathPointRelation = Vec<(MovePathIndex, LocationIndex)>;
struct UseFactsExtractor<'me> {
- var_defined: &'me mut VarPointRelations,
- var_used: &'me mut VarPointRelations,
+ var_defined: &'me mut VarPointRelation,
+ var_used: &'me mut VarPointRelation,
location_table: &'me LocationTable,
var_drop_used: &'me mut Vec<(Local, Location)>,
move_data: &'me MoveData<'me>,
- path_accessed_at: &'me mut MovePathPointRelations,
+ path_accessed_at: &'me mut PathPointRelation,
}
// A Visitor to walk through the MIR and extract point-wise facts
@@ -28,22 +27,22 @@
}
fn insert_def(&mut self, local: Local, location: Location) {
- debug!("LivenessFactsExtractor::insert_def()");
+ debug!("UseFactsExtractor::insert_def()");
self.var_defined.push((local, self.location_to_index(location)));
}
fn insert_use(&mut self, local: Local, location: Location) {
- debug!("LivenessFactsExtractor::insert_use()");
+ debug!("UseFactsExtractor::insert_use()");
self.var_used.push((local, self.location_to_index(location)));
}
fn insert_drop_use(&mut self, local: Local, location: Location) {
- debug!("LivenessFactsExtractor::insert_drop_use()");
+ debug!("UseFactsExtractor::insert_drop_use()");
self.var_drop_used.push((local, location));
}
fn insert_path_access(&mut self, path: MovePathIndex, location: Location) {
- debug!("LivenessFactsExtractor::insert_path_access({:?}, {:?})", path, location);
+ debug!("UseFactsExtractor::insert_path_access({:?}, {:?})", path, location);
self.path_accessed_at.push((path, self.location_to_index(location)));
}
@@ -84,44 +83,39 @@
}
}
-fn add_var_uses_regions(typeck: &mut TypeChecker<'_, 'tcx>, local: Local, ty: Ty<'tcx>) {
- debug!("add_regions(local={:?}, type={:?})", local, ty);
- typeck.tcx().for_each_free_region(&ty, |region| {
- let region_vid = typeck.borrowck_context.universal_regions.to_region_vid(region);
- debug!("add_regions for region {:?}", region_vid);
- if let Some(facts) = typeck.borrowck_context.all_facts {
- facts.var_uses_region.push((local, region_vid));
- }
- });
-}
-
pub(super) fn populate_access_facts(
typeck: &mut TypeChecker<'_, 'tcx>,
- body: ReadOnlyBodyCache<'_, 'tcx>,
+ body: ReadOnlyBodyAndCache<'_, 'tcx>,
location_table: &LocationTable,
move_data: &MoveData<'_>,
drop_used: &mut Vec<(Local, Location)>,
) {
- debug!("populate_var_liveness_facts()");
+ debug!("populate_access_facts()");
if let Some(facts) = typeck.borrowck_context.all_facts.as_mut() {
- UseFactsExtractor {
+ let mut extractor = UseFactsExtractor {
var_defined: &mut facts.var_defined,
var_used: &mut facts.var_used,
var_drop_used: drop_used,
path_accessed_at: &mut facts.path_accessed_at,
location_table,
move_data,
- }
- .visit_body(body);
+ };
+ extractor.visit_body(body);
facts.var_drop_used.extend(drop_used.iter().map(|&(local, location)| {
(local, location_table.mid_index(location))
}));
- }
- for (local, local_decl) in body.local_decls.iter_enumerated() {
- add_var_uses_regions(typeck, local, local_decl.ty);
+ for (local, local_decl) in body.local_decls.iter_enumerated() {
+ debug!("add var_uses_regions facts - local={:?}, type={:?}", local, local_decl.ty);
+ let _prof_timer = typeck.infcx.tcx.prof.generic_activity("polonius_fact_generation");
+ let universal_regions = &typeck.borrowck_context.universal_regions;
+ typeck.infcx.tcx.for_each_free_region(&local_decl.ty, |region| {
+ let region_vid = universal_regions.to_region_vid(region);
+ facts.var_uses_region.push((local, region_vid));
+ });
+ }
}
}
@@ -133,12 +127,12 @@
kind: &GenericArg<'tcx>,
) {
debug!("add_var_drops_region(local={:?}, kind={:?}", local, kind);
- let tcx = typeck.tcx();
-
- tcx.for_each_free_region(kind, |drop_live_region| {
- let region_vid = typeck.borrowck_context.universal_regions.to_region_vid(drop_live_region);
- if let Some(facts) = typeck.borrowck_context.all_facts.as_mut() {
+ if let Some(facts) = typeck.borrowck_context.all_facts.as_mut() {
+ let _prof_timer = typeck.infcx.tcx.prof.generic_activity("polonius_fact_generation");
+ let universal_regions = &typeck.borrowck_context.universal_regions;
+ typeck.infcx.tcx.for_each_free_region(kind, |drop_live_region| {
+ let region_vid = universal_regions.to_region_vid(drop_live_region);
facts.var_drops_region.push((local, region_vid));
- };
- });
+ });
+ }
}
diff --git a/src/librustc_mir/borrow_check/nll/type_check/liveness/trace.rs b/src/librustc_mir/borrow_check/type_check/liveness/trace.rs
similarity index 97%
rename from src/librustc_mir/borrow_check/nll/type_check/liveness/trace.rs
rename to src/librustc_mir/borrow_check/type_check/liveness/trace.rs
index 229cbed..9afd25a 100644
--- a/src/librustc_mir/borrow_check/nll/type_check/liveness/trace.rs
+++ b/src/librustc_mir/borrow_check/type_check/liveness/trace.rs
@@ -1,13 +1,5 @@
-use crate::borrow_check::nll::region_infer::values::{self, PointIndex, RegionValueElements};
-use crate::borrow_check::nll::type_check::liveness::local_use_map::LocalUseMap;
-use crate::borrow_check::nll::type_check::liveness::polonius;
-use crate::borrow_check::nll::type_check::NormalizeLocation;
-use crate::borrow_check::nll::type_check::TypeChecker;
-use crate::dataflow::indexes::MovePathIndex;
-use crate::dataflow::move_paths::MoveData;
-use crate::dataflow::{FlowAtLocation, FlowsAtLocation, MaybeInitializedPlaces};
use rustc::infer::canonical::QueryRegionConstraints;
-use rustc::mir::{BasicBlock, ConstraintCategory, Local, Location, ReadOnlyBodyCache};
+use rustc::mir::{BasicBlock, ConstraintCategory, Local, Location, ReadOnlyBodyAndCache};
use rustc::traits::query::dropck_outlives::DropckOutlivesResult;
use rustc::traits::query::type_op::outlives::DropckOutlives;
use rustc::traits::query::type_op::TypeOp;
@@ -16,6 +8,18 @@
use rustc_data_structures::fx::{FxHashMap, FxHashSet};
use std::rc::Rc;
+use crate::dataflow::indexes::MovePathIndex;
+use crate::dataflow::move_paths::MoveData;
+use crate::dataflow::{FlowAtLocation, FlowsAtLocation, MaybeInitializedPlaces};
+
+use crate::borrow_check::{
+ region_infer::values::{self, PointIndex, RegionValueElements},
+ type_check::liveness::local_use_map::LocalUseMap,
+ type_check::liveness::polonius,
+ type_check::NormalizeLocation,
+ type_check::TypeChecker,
+};
+
/// This is the heart of the liveness computation. For each variable X
/// that requires a liveness computation, it walks over all the uses
/// of X and does a reverse depth-first search ("trace") through the
@@ -32,7 +36,7 @@
/// this respects `#[may_dangle]` annotations).
pub(super) fn trace(
typeck: &mut TypeChecker<'_, 'tcx>,
- body: ReadOnlyBodyCache<'_, 'tcx>,
+ body: ReadOnlyBodyAndCache<'_, 'tcx>,
elements: &Rc<RegionValueElements>,
flow_inits: &mut FlowAtLocation<'tcx, MaybeInitializedPlaces<'_, 'tcx>>,
move_data: &MoveData<'tcx>,
@@ -71,7 +75,7 @@
elements: &'me RegionValueElements,
/// MIR we are analyzing.
- body: ReadOnlyBodyCache<'me, 'tcx>,
+ body: ReadOnlyBodyAndCache<'me, 'tcx>,
/// Mapping to/from the various indices used for initialization tracking.
move_data: &'me MoveData<'tcx>,
@@ -249,7 +253,7 @@
// Reverse DFS. But for drops, we do it a bit differently.
// The stack only ever stores *terminators of blocks*. Within
// a block, we walk back the statements in an inner loop.
- 'next_block: while let Some(term_point) = self.stack.pop() {
+ while let Some(term_point) = self.stack.pop() {
self.compute_drop_live_points_for_block(mpi, term_point);
}
}
diff --git a/src/librustc_mir/borrow_check/nll/type_check/mod.rs b/src/librustc_mir/borrow_check/type_check/mod.rs
similarity index 97%
rename from src/librustc_mir/borrow_check/nll/type_check/mod.rs
rename to src/librustc_mir/borrow_check/type_check/mod.rs
index de30420..663536b 100644
--- a/src/librustc_mir/borrow_check/nll/type_check/mod.rs
+++ b/src/librustc_mir/borrow_check/type_check/mod.rs
@@ -34,30 +34,32 @@
use rustc_index::vec::{Idx, IndexVec};
use syntax_pos::{DUMMY_SP, Span};
-use crate::borrow_check::borrow_set::BorrowSet;
-use crate::borrow_check::location::LocationTable;
-use crate::borrow_check::nll::constraints::{OutlivesConstraint, OutlivesConstraintSet};
-use crate::borrow_check::nll::facts::AllFacts;
-use crate::borrow_check::nll::member_constraints::MemberConstraintSet;
-use crate::borrow_check::nll::region_infer::{ClosureRegionRequirementsExt, TypeTest};
-use crate::borrow_check::nll::region_infer::values::LivenessValues;
-use crate::borrow_check::nll::region_infer::values::PlaceholderIndex;
-use crate::borrow_check::nll::region_infer::values::PlaceholderIndices;
-use crate::borrow_check::nll::region_infer::values::RegionValueElements;
-use crate::borrow_check::nll::renumber;
-use crate::borrow_check::nll::ToRegionVid;
-use crate::borrow_check::nll::type_check::free_region_relations::{
- CreateResult, UniversalRegionRelations,
-};
-use crate::borrow_check::nll::universal_regions::{DefiningTy, UniversalRegions};
use crate::dataflow::FlowAtLocation;
use crate::dataflow::MaybeInitializedPlaces;
use crate::dataflow::move_paths::MoveData;
use crate::transform::promote_consts::should_suggest_const_in_array_repeat_expressions_attribute;
+use crate::borrow_check::{
+ borrow_set::BorrowSet,
+ location::LocationTable,
+ constraints::{OutlivesConstraintSet, OutlivesConstraint},
+ member_constraints::MemberConstraintSet,
+ facts::AllFacts,
+ region_infer::values::{
+ LivenessValues, PlaceholderIndex, PlaceholderIndices, RegionValueElements,
+ },
+ region_infer::{ClosureRegionRequirementsExt, TypeTest},
+ type_check::free_region_relations::{
+ CreateResult, UniversalRegionRelations,
+ },
+ universal_regions::{DefiningTy, UniversalRegions},
+ nll::ToRegionVid,
+ renumber,
+};
+
macro_rules! span_mirbug {
($context:expr, $elem:expr, $($message:tt)*) => ({
- $crate::borrow_check::nll::type_check::mirbug(
+ $crate::borrow_check::type_check::mirbug(
$context.tcx(),
$context.last_span,
&format!(
@@ -117,8 +119,8 @@
pub(crate) fn type_check<'tcx>(
infcx: &InferCtxt<'_, 'tcx>,
param_env: ty::ParamEnv<'tcx>,
- body: ReadOnlyBodyCache<'_, 'tcx>,
- promoted: &IndexVec<Promoted, ReadOnlyBodyCache<'_, 'tcx>>,
+ body: ReadOnlyBodyAndCache<'_, 'tcx>,
+ promoted: &IndexVec<Promoted, ReadOnlyBodyAndCache<'_, 'tcx>>,
mir_def_id: DefId,
universal_regions: &Rc<UniversalRegions<'tcx>>,
location_table: &LocationTable,
@@ -182,7 +184,7 @@
move_data,
location_table);
- translate_outlives_facts(cx.borrowck_context);
+ translate_outlives_facts(&mut cx);
},
);
@@ -196,8 +198,8 @@
infcx: &'a InferCtxt<'a, 'tcx>,
mir_def_id: DefId,
param_env: ty::ParamEnv<'tcx>,
- body: ReadOnlyBodyCache<'a, 'tcx>,
- promoted: &'a IndexVec<Promoted, ReadOnlyBodyCache<'_, 'tcx>>,
+ body: ReadOnlyBodyAndCache<'a, 'tcx>,
+ promoted: &'a IndexVec<Promoted, ReadOnlyBodyAndCache<'_, 'tcx>>,
region_bound_pairs: &'a RegionBoundPairs<'tcx>,
implicit_region_bound: ty::Region<'tcx>,
borrowck_context: &'a mut BorrowCheckContext<'a, 'tcx>,
@@ -206,7 +208,7 @@
) -> R {
let mut checker = TypeChecker::new(
infcx,
- body.body(),
+ *body,
mir_def_id,
param_env,
region_bound_pairs,
@@ -215,7 +217,7 @@
universal_region_relations,
);
let errors_reported = {
- let mut verifier = TypeVerifier::new(&mut checker, body.body(), promoted);
+ let mut verifier = TypeVerifier::new(&mut checker, *body, promoted);
verifier.visit_body(body);
verifier.errors_reported
};
@@ -228,8 +230,10 @@
extra(&mut checker)
}
-fn translate_outlives_facts(cx: &mut BorrowCheckContext<'_, '_>) {
+fn translate_outlives_facts(typeck: &mut TypeChecker<'_, '_>) {
+ let cx = &mut typeck.borrowck_context;
if let Some(facts) = cx.all_facts {
+ let _prof_timer = typeck.infcx.tcx.prof.generic_activity("polonius_fact_generation");
let location_table = cx.location_table;
facts
.outlives
@@ -272,7 +276,7 @@
struct TypeVerifier<'a, 'b, 'tcx> {
cx: &'a mut TypeChecker<'b, 'tcx>,
body: &'b Body<'tcx>,
- promoted: &'b IndexVec<Promoted, ReadOnlyBodyCache<'b, 'tcx>>,
+ promoted: &'b IndexVec<Promoted, ReadOnlyBodyAndCache<'b, 'tcx>>,
last_span: Span,
mir_def_id: DefId,
errors_reported: bool,
@@ -396,7 +400,7 @@
}
}
- fn visit_body(&mut self, body: ReadOnlyBodyCache<'_, 'tcx>) {
+ fn visit_body(&mut self, body: ReadOnlyBodyAndCache<'_, 'tcx>) {
self.sanitize_type(&"return type", body.return_ty());
for local_decl in &body.local_decls {
self.sanitize_type(local_decl, local_decl.ty);
@@ -412,7 +416,7 @@
fn new(
cx: &'a mut TypeChecker<'b, 'tcx>,
body: &'b Body<'tcx>,
- promoted: &'b IndexVec<Promoted, ReadOnlyBodyCache<'b, 'tcx>>,
+ promoted: &'b IndexVec<Promoted, ReadOnlyBodyAndCache<'b, 'tcx>>,
) -> Self {
TypeVerifier {
body,
@@ -548,14 +552,14 @@
fn sanitize_promoted(
&mut self,
- promoted_body: ReadOnlyBodyCache<'b, 'tcx>,
+ promoted_body: ReadOnlyBodyAndCache<'b, 'tcx>,
location: Location
) {
// Determine the constraints from the promoted MIR by running the type
// checker on the promoted MIR, then transfer the constraints back to
// the main MIR, changing the locations to the provided location.
- let parent_body = mem::replace(&mut self.body, promoted_body.body());
+ let parent_body = mem::replace(&mut self.body, *promoted_body);
// Use new sets of constraints and closure bounds so that we can
// modify their locations.
@@ -673,23 +677,16 @@
}),
)
}
- ProjectionElem::Subslice { from, to } => PlaceTy::from_ty(
+ ProjectionElem::Subslice { from, to, from_end } => PlaceTy::from_ty(
match base_ty.kind {
- ty::Array(inner, size) => {
- let size = size.eval_usize(tcx, self.cx.param_env);
- let min_size = (from as u64) + (to as u64);
- if let Some(rest_size) = size.checked_sub(min_size) {
- tcx.mk_array(inner, rest_size)
- } else {
- span_mirbug_and_err!(
- self,
- place,
- "taking too-small slice of {:?}",
- base_ty
- )
- }
+ ty::Array(inner, _) => {
+ assert!(!from_end, "array subslices should not use from_end");
+ tcx.mk_array(inner, (to - from) as u64)
}
- ty::Slice(..) => base_ty,
+ ty::Slice(..) => {
+ assert!(from_end, "slice subslices should use from_end");
+ base_ty
+ },
_ => span_mirbug_and_err!(self, place, "slice of non-array {:?}", base_ty),
},
),
@@ -1378,7 +1375,7 @@
fn check_stmt(
&mut self,
- body: ReadOnlyBodyCache<'_, 'tcx>,
+ body: ReadOnlyBodyAndCache<'_, 'tcx>,
stmt: &Statement<'tcx>,
location: Location)
{
@@ -1994,7 +1991,7 @@
fn check_rvalue(
&mut self,
- body: ReadOnlyBodyCache<'_, 'tcx>,
+ body: ReadOnlyBodyAndCache<'_, 'tcx>,
rvalue: &Rvalue<'tcx>,
location: Location)
{
@@ -2489,6 +2486,7 @@
// that occurs when we are borrowing an unsafe place, for
// example).
if let Some(all_facts) = all_facts {
+ let _prof_timer = self.infcx.tcx.prof.generic_activity("polonius_fact_generation");
if let Some(borrow_index) = borrow_set.location_map.get(&location) {
let region_vid = borrow_region.to_region_vid();
all_facts.borrow_region.push((
@@ -2766,7 +2764,7 @@
})
}
- fn typeck_mir(&mut self, body: ReadOnlyBodyCache<'_, 'tcx>) {
+ fn typeck_mir(&mut self, body: ReadOnlyBodyAndCache<'_, 'tcx>) {
self.last_span = body.span;
debug!("run_on_mir: {:?}", body.span);
diff --git a/src/librustc_mir/borrow_check/nll/type_check/relate_tys.rs b/src/librustc_mir/borrow_check/type_check/relate_tys.rs
similarity index 96%
rename from src/librustc_mir/borrow_check/nll/type_check/relate_tys.rs
rename to src/librustc_mir/borrow_check/type_check/relate_tys.rs
index 80bf047..80da8a8 100644
--- a/src/librustc_mir/borrow_check/nll/type_check/relate_tys.rs
+++ b/src/librustc_mir/borrow_check/type_check/relate_tys.rs
@@ -1,5 +1,3 @@
-use crate::borrow_check::nll::constraints::OutlivesConstraint;
-use crate::borrow_check::nll::type_check::{BorrowCheckContext, Locations};
use rustc::infer::nll_relate::{TypeRelating, TypeRelatingDelegate, NormalizationStrategy};
use rustc::infer::{InferCtxt, NLLRegionVariableOrigin};
use rustc::mir::ConstraintCategory;
@@ -8,6 +6,9 @@
use rustc::ty::relate::TypeRelation;
use rustc::ty::{self, Ty};
+use crate::borrow_check::constraints::OutlivesConstraint;
+use crate::borrow_check::type_check::{BorrowCheckContext, Locations};
+
/// Adds sufficient constraints to ensure that `a R b` where `R` depends on `v`:
///
/// - "Covariant" `a <: b`
diff --git a/src/librustc_mir/borrow_check/nll/universal_regions.rs b/src/librustc_mir/borrow_check/universal_regions.rs
similarity index 97%
rename from src/librustc_mir/borrow_check/nll/universal_regions.rs
rename to src/librustc_mir/borrow_check/universal_regions.rs
index fbedac4..c035303 100644
--- a/src/librustc_mir/borrow_check/nll/universal_regions.rs
+++ b/src/librustc_mir/borrow_check/universal_regions.rs
@@ -25,7 +25,7 @@
use rustc_errors::DiagnosticBuilder;
use std::iter;
-use super::ToRegionVid;
+use crate::borrow_check::nll::ToRegionVid;
#[derive(Debug)]
pub struct UniversalRegions<'tcx> {
@@ -312,9 +312,9 @@
match self.defining_ty {
DefiningTy::Closure(def_id, substs) => {
err.note(&format!(
- "defining type: {:?} with closure substs {:#?}",
- def_id,
- &substs[..]
+ "defining type: {} with closure substs {:#?}",
+ tcx.def_path_str_with_substs(def_id, substs),
+ &substs[tcx.generics_of(def_id).parent_count..],
));
// FIXME: It'd be nice to print the late-bound regions
@@ -332,9 +332,9 @@
}
DefiningTy::Generator(def_id, substs, _) => {
err.note(&format!(
- "defining type: {:?} with generator substs {:#?}",
- def_id,
- &substs[..]
+ "defining type: {} with generator substs {:#?}",
+ tcx.def_path_str_with_substs(def_id, substs),
+ &substs[tcx.generics_of(def_id).parent_count..],
));
// FIXME: As above, we'd like to print out the region
@@ -350,16 +350,14 @@
}
DefiningTy::FnDef(def_id, substs) => {
err.note(&format!(
- "defining type: {:?} with substs {:#?}",
- def_id,
- &substs[..]
+ "defining type: {}",
+ tcx.def_path_str_with_substs(def_id, substs),
));
}
DefiningTy::Const(def_id, substs) => {
err.note(&format!(
- "defining constant type: {:?} with substs {:#?}",
- def_id,
- &substs[..]
+ "defining constant type: {}",
+ tcx.def_path_str_with_substs(def_id, substs),
));
}
}
diff --git a/src/librustc_mir/build/expr/into.rs b/src/librustc_mir/build/expr/into.rs
index f5dc09c..07a44b1 100644
--- a/src/librustc_mir/build/expr/into.rs
+++ b/src/librustc_mir/build/expr/into.rs
@@ -65,7 +65,14 @@
_ => false,
};
- unpack!(block = this.as_local_rvalue(block, source));
+ // (#66975) Source could be a const of type `!`, so has to
+ // exist in the generated MIR.
+ unpack!(block = this.as_temp(
+ block,
+ this.local_scope(),
+ source,
+ Mutability::Mut,
+ ));
// This is an optimization. If the expression was a call then we already have an
// unreachable block. Don't bother to terminate it and create a new one.
diff --git a/src/librustc_mir/build/matches/test.rs b/src/librustc_mir/build/matches/test.rs
index c893d6f..e320811 100644
--- a/src/librustc_mir/build/matches/test.rs
+++ b/src/librustc_mir/build/matches/test.rs
@@ -680,7 +680,7 @@
}
})();
- if no_overlap == Some(true) {
+ if let Some(true) = no_overlap {
// Testing range does not overlap with pattern range,
// so the pattern can be matched only if this test fails.
Some(1)
@@ -690,7 +690,7 @@
}
(&TestKind::Range(range), &PatKind::Constant { value }) => {
- if self.const_range_contains(range, value) == Some(false) {
+ if let Some(false) = self.const_range_contains(range, value) {
// `value` is not contained in the testing range,
// so `value` can be matched only if this test fails.
Some(1)
diff --git a/src/librustc_mir/build/matches/util.rs b/src/librustc_mir/build/matches/util.rs
index aec9e6e..ec8b3c5 100644
--- a/src/librustc_mir/build/matches/util.rs
+++ b/src/librustc_mir/build/matches/util.rs
@@ -2,6 +2,7 @@
use crate::build::matches::MatchPair;
use crate::hair::*;
use rustc::mir::*;
+use rustc::ty;
use smallvec::SmallVec;
use std::u32;
use std::convert::TryInto;
@@ -31,9 +32,17 @@
prefix: &'pat [Pat<'tcx>],
opt_slice: Option<&'pat Pat<'tcx>>,
suffix: &'pat [Pat<'tcx>]) {
- let min_length = prefix.len() + suffix.len();
- let min_length = min_length.try_into().unwrap();
let tcx = self.hir.tcx();
+ let (min_length, exact_size) = match place.ty(&self.local_decls, tcx).ty.kind {
+ ty::Array(_, length) => (
+ length.eval_usize(tcx, self.hir.param_env).try_into().unwrap(),
+ true
+ ),
+ _ => (
+ (prefix.len() + suffix.len()).try_into().unwrap(),
+ false,
+ ),
+ };
match_pairs.extend(
prefix.iter()
@@ -50,10 +59,15 @@
);
if let Some(subslice_pat) = opt_slice {
- let subslice = tcx.mk_place_elem(place.clone(),ProjectionElem::Subslice {
- from: prefix.len() as u32,
- to: suffix.len() as u32
- });
+ let suffix_len = suffix.len() as u32;
+ let subslice = tcx.mk_place_elem(
+ place.clone(),
+ ProjectionElem::Subslice {
+ from: prefix.len() as u32,
+ to: if exact_size { min_length - suffix_len } else { suffix_len },
+ from_end: !exact_size,
+ },
+ );
match_pairs.push(MatchPair::new(subslice, subslice_pat));
}
@@ -62,10 +76,11 @@
.rev()
.enumerate()
.map(|(idx, subpattern)| {
+ let end_offset = (idx + 1) as u32;
let elem = ProjectionElem::ConstantIndex {
- offset: (idx+1) as u32,
+ offset: if exact_size { min_length - end_offset } else { end_offset },
min_length,
- from_end: true,
+ from_end: !exact_size,
};
let place = tcx.mk_place_elem(place.clone(), elem);
MatchPair::new(place, subpattern)
diff --git a/src/librustc_mir/build/mod.rs b/src/librustc_mir/build/mod.rs
index b84461d..0009eb4 100644
--- a/src/librustc_mir/build/mod.rs
+++ b/src/librustc_mir/build/mod.rs
@@ -24,7 +24,7 @@
use super::lints;
/// Construct the MIR for a given `DefId`.
-pub fn mir_build(tcx: TyCtxt<'_>, def_id: DefId) -> BodyCache<'_> {
+pub fn mir_build(tcx: TyCtxt<'_>, def_id: DefId) -> BodyAndCache<'_> {
let id = tcx.hir().as_local_hir_id(def_id).unwrap();
// Figure out what primary body this item has.
@@ -196,7 +196,7 @@
lints::check(tcx, &body, def_id);
- let mut body = BodyCache::new(body);
+ let mut body = BodyAndCache::new(body);
body.ensure_predecessors();
body
})
diff --git a/src/librustc_mir/const_eval.rs b/src/librustc_mir/const_eval.rs
index 968a8a7..b219fec 100644
--- a/src/librustc_mir/const_eval.rs
+++ b/src/librustc_mir/const_eval.rs
@@ -9,11 +9,10 @@
use rustc::hir::def::DefKind;
use rustc::hir::def_id::DefId;
-use rustc::middle::lang_items::PanicLocationLangItem;
use rustc::mir::interpret::{ConstEvalErr, ErrorHandled, ScalarMaybeUndef};
use rustc::mir;
use rustc::ty::{self, Ty, TyCtxt, subst::Subst};
-use rustc::ty::layout::{self, LayoutOf, VariantIdx};
+use rustc::ty::layout::{self, HasTyCtxt, LayoutOf, VariantIdx};
use rustc::traits::Reveal;
use rustc_data_structures::fx::FxHashMap;
use crate::interpret::eval_nullary_intrinsic;
@@ -348,7 +347,11 @@
//
// For the moment we only do this for functions which take no arguments
// (or all arguments are ZSTs) so that we don't memoize too much.
- if args.iter().all(|a| a.layout.is_zst()) {
+ //
+ // Because `#[track_caller]` adds an implicit non-ZST argument, we also cannot
+ // perform this optimization on items tagged with it.
+ let no_implicit_args = !instance.def.requires_caller_location(ecx.tcx());
+ if args.iter().all(|a| a.layout.is_zst()) && no_implicit_args {
let gid = GlobalId { instance, promoted: None };
ecx.eval_const_fn_call(gid, ret)?;
return Ok(None);
@@ -366,7 +369,7 @@
}
// This is a const fn. Call it.
Ok(Some(match ecx.load_mir(instance.def, None) {
- Ok(body) => body.body(),
+ Ok(body) => *body,
Err(err) => {
if let err_unsup!(NoMirFor(ref path)) = err.kind {
return Err(
@@ -559,11 +562,7 @@
trace!("const_caller_location: {}:{}:{}", file, line, col);
let mut ecx = mk_eval_cx(tcx, DUMMY_SP, ty::ParamEnv::reveal_all());
- let loc_ty = tcx.mk_imm_ref(
- tcx.lifetimes.re_static,
- tcx.type_of(tcx.require_lang_item(PanicLocationLangItem, None))
- .subst(tcx, tcx.mk_substs([tcx.lifetimes.re_static.into()].iter())),
- );
+ let loc_ty = tcx.caller_location_ty();
let loc_place = ecx.alloc_caller_location(file, line, col);
intern_const_alloc_recursive(&mut ecx, None, loc_place).unwrap();
let loc_const = ty::Const {
@@ -743,7 +742,7 @@
let res = ecx.load_mir(cid.instance.def, cid.promoted);
res.and_then(
- |body| eval_body_using_ecx(&mut ecx, cid, body.body())
+ |body| eval_body_using_ecx(&mut ecx, cid, *body)
).and_then(|place| {
Ok(RawConst {
alloc_id: place.ptr.assert_ptr().alloc_id,
diff --git a/src/librustc_mir/dataflow/impls/borrows.rs b/src/librustc_mir/dataflow/impls/borrows.rs
index 7e7652c..5433b7f 100644
--- a/src/librustc_mir/dataflow/impls/borrows.rs
+++ b/src/librustc_mir/dataflow/impls/borrows.rs
@@ -1,6 +1,3 @@
-use crate::borrow_check::borrow_set::{BorrowSet, BorrowData};
-use crate::borrow_check::place_ext::PlaceExt;
-
use rustc::mir::{self, Location, Place, PlaceBase, Body};
use rustc::ty::{self, TyCtxt};
use rustc::ty::RegionVid;
@@ -9,10 +6,11 @@
use rustc_data_structures::fx::FxHashMap;
use rustc_index::vec::{Idx, IndexVec};
+use crate::borrow_check::{
+ ToRegionVid, BorrowSet, BorrowData, RegionInferenceContext, PlaceExt, PlaceConflictBias,
+ places_conflict,
+};
use crate::dataflow::{BitDenotation, BottomValue, GenKillSet};
-use crate::borrow_check::nll::region_infer::RegionInferenceContext;
-use crate::borrow_check::nll::ToRegionVid;
-use crate::borrow_check::places_conflict;
use std::rc::Rc;
@@ -221,13 +219,13 @@
// locations.
let definitely_conflicting_borrows = other_borrows_of_local
.filter(|&&i| {
- places_conflict::places_conflict(
+ places_conflict(
self.tcx,
self.param_env,
self.body,
&self.borrow_set.borrows[i].borrowed_place,
place,
- places_conflict::PlaceConflictBias::NoOverlap)
+ PlaceConflictBias::NoOverlap)
});
trans.kill_all(definitely_conflicting_borrows);
diff --git a/src/librustc_mir/dataflow/impls/storage_liveness.rs b/src/librustc_mir/dataflow/impls/storage_liveness.rs
index c4b97d1..b8abe6d 100644
--- a/src/librustc_mir/dataflow/impls/storage_liveness.rs
+++ b/src/librustc_mir/dataflow/impls/storage_liveness.rs
@@ -75,20 +75,20 @@
/// Dataflow analysis that determines whether each local requires storage at a
/// given location; i.e. whether its storage can go away without being observed.
pub struct RequiresStorage<'mir, 'tcx> {
- body: ReadOnlyBodyCache<'mir, 'tcx>,
+ body: ReadOnlyBodyAndCache<'mir, 'tcx>,
borrowed_locals:
RefCell<DataflowResultsRefCursor<'mir, 'tcx, HaveBeenBorrowedLocals<'mir, 'tcx>>>,
}
impl<'mir, 'tcx: 'mir> RequiresStorage<'mir, 'tcx> {
pub fn new(
- body: ReadOnlyBodyCache<'mir, 'tcx>,
+ body: ReadOnlyBodyAndCache<'mir, 'tcx>,
borrowed_locals: &'mir DataflowResults<'tcx, HaveBeenBorrowedLocals<'mir, 'tcx>>,
) -> Self {
RequiresStorage {
body,
borrowed_locals: RefCell::new(
- DataflowResultsCursor::new(borrowed_locals, body.body())
+ DataflowResultsCursor::new(borrowed_locals, *body)
),
}
}
diff --git a/src/librustc_mir/dataflow/move_paths/abs_domain.rs b/src/librustc_mir/dataflow/move_paths/abs_domain.rs
index d97f3b7..0665c0f 100644
--- a/src/librustc_mir/dataflow/move_paths/abs_domain.rs
+++ b/src/librustc_mir/dataflow/move_paths/abs_domain.rs
@@ -49,8 +49,8 @@
ProjectionElem::Deref => ProjectionElem::Deref,
ProjectionElem::Field(ref f, ty) => ProjectionElem::Field(f.clone(), ty.lift()),
ProjectionElem::Index(ref i) => ProjectionElem::Index(i.lift()),
- ProjectionElem::Subslice { from, to } => {
- ProjectionElem::Subslice { from: from, to: to }
+ ProjectionElem::Subslice { from, to, from_end } => {
+ ProjectionElem::Subslice { from, to, from_end }
}
ProjectionElem::ConstantIndex { offset, min_length, from_end } => {
ProjectionElem::ConstantIndex { offset, min_length, from_end }
diff --git a/src/librustc_mir/dataflow/move_paths/builder.rs b/src/librustc_mir/dataflow/move_paths/builder.rs
index 52016d4..fa0864e 100644
--- a/src/librustc_mir/dataflow/move_paths/builder.rs
+++ b/src/librustc_mir/dataflow/move_paths/builder.rs
@@ -4,7 +4,7 @@
use rustc_index::vec::IndexVec;
use smallvec::{smallvec, SmallVec};
-use std::collections::hash_map::Entry;
+use std::convert::TryInto;
use std::mem;
use super::abs_domain::Lift;
@@ -17,12 +17,13 @@
struct MoveDataBuilder<'a, 'tcx> {
body: &'a Body<'tcx>,
tcx: TyCtxt<'tcx>,
+ param_env: ty::ParamEnv<'tcx>,
data: MoveData<'tcx>,
errors: Vec<(Place<'tcx>, MoveError<'tcx>)>,
}
impl<'a, 'tcx> MoveDataBuilder<'a, 'tcx> {
- fn new(body: &'a Body<'tcx>, tcx: TyCtxt<'tcx>) -> Self {
+ fn new(body: &'a Body<'tcx>, tcx: TyCtxt<'tcx>, param_env: ty::ParamEnv<'tcx>) -> Self {
let mut move_paths = IndexVec::new();
let mut path_map = IndexVec::new();
let mut init_path_map = IndexVec::new();
@@ -30,6 +31,7 @@
MoveDataBuilder {
body,
tcx,
+ param_env,
errors: Vec::new(),
data: MoveData {
moves: IndexVec::new(),
@@ -148,42 +150,47 @@
InteriorOfSliceOrArray { ty: place_ty, is_index: true },
));
}
- _ => {
- // FIXME: still badly broken
- }
+ _ => {}
},
_ => {}
};
- let proj = &place.projection[..i+1];
- base = match self
- .builder
- .data
- .rev_lookup
- .projections
- .entry((base, elem.lift()))
- {
- Entry::Occupied(ent) => *ent.get(),
- Entry::Vacant(ent) => {
- let path = MoveDataBuilder::new_move_path(
- &mut self.builder.data.move_paths,
- &mut self.builder.data.path_map,
- &mut self.builder.data.init_path_map,
- Some(base),
- Place {
- base: place.base.clone(),
- projection: tcx.intern_place_elems(proj),
- },
- );
- ent.insert(path);
- path
- }
- };
+ base = self.add_move_path(base, elem, |tcx| {
+ Place {
+ base: place.base.clone(),
+ projection: tcx.intern_place_elems(&place.projection[..i+1]),
+ }
+ });
}
Ok(base)
}
+ fn add_move_path(
+ &mut self,
+ base: MovePathIndex,
+ elem: &PlaceElem<'tcx>,
+ mk_place: impl FnOnce(TyCtxt<'tcx>) -> Place<'tcx>,
+ ) -> MovePathIndex {
+ let MoveDataBuilder {
+ data: MoveData { rev_lookup, move_paths, path_map, init_path_map, .. },
+ tcx,
+ ..
+ } = self.builder;
+ *rev_lookup.projections
+ .entry((base, elem.lift()))
+ .or_insert_with(move || {
+ let path = MoveDataBuilder::new_move_path(
+ move_paths,
+ path_map,
+ init_path_map,
+ Some(base),
+ mk_place(*tcx),
+ );
+ path
+ })
+ }
+
fn create_move_path(&mut self, place: &Place<'tcx>) {
// This is an non-moving access (such as an overwrite or
// drop), so this not being a valid move path is OK.
@@ -214,8 +221,9 @@
pub(super) fn gather_moves<'tcx>(
body: &Body<'tcx>,
tcx: TyCtxt<'tcx>,
+ param_env: ty::ParamEnv<'tcx>,
) -> Result<MoveData<'tcx>, (MoveData<'tcx>, Vec<(Place<'tcx>, MoveError<'tcx>)>)> {
- let mut builder = MoveDataBuilder::new(body, tcx);
+ let mut builder = MoveDataBuilder::new(body, tcx, param_env);
builder.gather_args();
@@ -411,20 +419,67 @@
fn gather_move(&mut self, place: &Place<'tcx>) {
debug!("gather_move({:?}, {:?})", self.loc, place);
- let path = match self.move_path_for(place) {
- Ok(path) | Err(MoveError::UnionMove { path }) => path,
- Err(error @ MoveError::IllegalMove { .. }) => {
- self.builder.errors.push((place.clone(), error));
- return;
+ if let [
+ ref base @ ..,
+ ProjectionElem::Subslice { from, to, from_end: false },
+ ] = **place.projection {
+ // Split `Subslice` patterns into the corresponding list of
+ // `ConstIndex` patterns. This is done to ensure that all move paths
+ // are disjoint, which is expected by drop elaboration.
+ let base_place = Place {
+ base: place.base.clone(),
+ projection: self.builder.tcx.intern_place_elems(base),
+ };
+ let base_path = match self.move_path_for(&base_place) {
+ Ok(path) => path,
+ Err(MoveError::UnionMove { path }) => {
+ self.record_move(place, path);
+ return;
+ }
+ Err(error @ MoveError::IllegalMove { .. }) => {
+ self.builder.errors.push((base_place, error));
+ return;
+ }
+ };
+ let base_ty = base_place.ty(self.builder.body, self.builder.tcx).ty;
+ let len: u32 = match base_ty.kind {
+ ty::Array(_, size) => {
+ let length = size.eval_usize(self.builder.tcx, self.builder.param_env);
+ length.try_into().expect(
+ "slice pattern of array with more than u32::MAX elements"
+ )
+ }
+ _ => bug!("from_end: false slice pattern of non-array type"),
+ };
+ for offset in from..to {
+ let elem = ProjectionElem::ConstantIndex {
+ offset,
+ min_length: len,
+ from_end: false,
+ };
+ let path = self.add_move_path(
+ base_path,
+ &elem,
+ |tcx| tcx.mk_place_elem(base_place.clone(), elem),
+ );
+ self.record_move(place, path);
}
- };
- let move_out = self.builder.data.moves.push(MoveOut { path: path, source: self.loc });
+ } else {
+ match self.move_path_for(place) {
+ Ok(path) | Err(MoveError::UnionMove { path }) => self.record_move(place, path),
+ Err(error @ MoveError::IllegalMove { .. }) => {
+ self.builder.errors.push((place.clone(), error));
+ }
+ };
+ }
+ }
+ fn record_move(&mut self, place: &Place<'tcx>, path: MovePathIndex) {
+ let move_out = self.builder.data.moves.push(MoveOut { path: path, source: self.loc });
debug!(
"gather_move({:?}, {:?}): adding move {:?} of {:?}",
self.loc, place, move_out, path
);
-
self.builder.data.path_map[path].push(move_out);
self.builder.data.loc_map[self.loc].push(move_out);
}
diff --git a/src/librustc_mir/dataflow/move_paths/mod.rs b/src/librustc_mir/dataflow/move_paths/mod.rs
index b599f47..89ef9b2 100644
--- a/src/librustc_mir/dataflow/move_paths/mod.rs
+++ b/src/librustc_mir/dataflow/move_paths/mod.rs
@@ -1,6 +1,6 @@
use core::slice::Iter;
use rustc::mir::*;
-use rustc::ty::{Ty, TyCtxt};
+use rustc::ty::{Ty, TyCtxt, ParamEnv};
use rustc::util::nodemap::FxHashMap;
use rustc_index::vec::{Enumerated, Idx, IndexVec};
use smallvec::SmallVec;
@@ -318,8 +318,9 @@
pub fn gather_moves(
body: &Body<'tcx>,
tcx: TyCtxt<'tcx>,
+ param_env: ParamEnv<'tcx>,
) -> Result<Self, (Self, Vec<(Place<'tcx>, MoveError<'tcx>)>)> {
- builder::gather_moves(body, tcx)
+ builder::gather_moves(body, tcx, param_env)
}
/// For the move path `mpi`, returns the root local variable (if any) that starts the path.
diff --git a/src/librustc_mir/hair/pattern/_match.rs b/src/librustc_mir/hair/pattern/_match.rs
index 37a9381..c372032 100644
--- a/src/librustc_mir/hair/pattern/_match.rs
+++ b/src/librustc_mir/hair/pattern/_match.rs
@@ -238,7 +238,7 @@
use rustc::hir::def_id::DefId;
use rustc::hir::{HirId, RangeEnd};
use rustc::ty::layout::{Integer, IntegerExt, Size, VariantIdx};
-use rustc::ty::{self, Const, Ty, TyCtxt, TypeFoldable};
+use rustc::ty::{self, Const, Ty, TyCtxt, TypeFoldable, VariantDef};
use rustc::lint;
use rustc::mir::interpret::{truncate, AllocId, ConstValue, Pointer, Scalar};
@@ -354,7 +354,7 @@
}
impl<'tcx> Pat<'tcx> {
- fn is_wildcard(&self) -> bool {
+ pub(super) fn is_wildcard(&self) -> bool {
match *self.kind {
PatKind::Binding { subpattern: None, .. } | PatKind::Wild => true,
_ => false,
@@ -596,9 +596,21 @@
}
}
- fn is_local(&self, ty: Ty<'tcx>) -> bool {
+ // Returns whether the given type is an enum from another crate declared `#[non_exhaustive]`.
+ pub fn is_foreign_non_exhaustive_enum(&self, ty: Ty<'tcx>) -> bool {
match ty.kind {
- ty::Adt(adt_def, ..) => adt_def.did.is_local(),
+ ty::Adt(def, ..) => {
+ def.is_enum() && def.is_variant_list_non_exhaustive() && !def.did.is_local()
+ }
+ _ => false,
+ }
+ }
+
+ // Returns whether the given variant is from another crate and has its fields declared
+ // `#[non_exhaustive]`.
+ fn is_foreign_non_exhaustive_variant(&self, ty: Ty<'tcx>, variant: &VariantDef) -> bool {
+ match ty.kind {
+ ty::Adt(def, ..) => variant.is_field_list_non_exhaustive() && !def.did.is_local(),
_ => false,
}
}
@@ -758,6 +770,10 @@
// Returns the set of constructors covered by `self` but not by
// anything in `other_ctors`.
fn subtract_ctors(&self, other_ctors: &Vec<Constructor<'tcx>>) -> Vec<Constructor<'tcx>> {
+ if other_ctors.is_empty() {
+ return vec![self.clone()];
+ }
+
match self {
// Those constructors can only match themselves.
Single | Variant(_) | ConstantValue(..) | FloatRange(..) => {
@@ -858,8 +874,7 @@
vec![Pat::wildcard_from_ty(substs.type_at(0))]
} else {
let variant = &adt.variants[self.variant_index_for_adt(cx, adt)];
- let is_non_exhaustive =
- variant.is_field_list_non_exhaustive() && !cx.is_local(ty);
+ let is_non_exhaustive = cx.is_foreign_non_exhaustive_variant(ty, variant);
variant
.fields
.iter()
@@ -1205,6 +1220,8 @@
///
/// We make sure to omit constructors that are statically impossible. E.g., for
/// `Option<!>`, we do not include `Some(_)` in the returned list of constructors.
+/// Invariant: this returns an empty `Vec` if and only if the type is uninhabited (as determined by
+/// `cx.is_uninhabited()`).
fn all_constructors<'a, 'tcx>(
cx: &mut MatchCheckCtxt<'a, 'tcx>,
pcx: PatCtxt<'tcx>,
@@ -1235,47 +1252,45 @@
vec![Slice(Slice { array_len: None, kind })]
}
ty::Adt(def, substs) if def.is_enum() => {
- let ctors: Vec<_> = def
- .variants
- .iter()
- .filter(|v| {
- !cx.tcx.features().exhaustive_patterns
- || !v
- .uninhabited_from(cx.tcx, substs, def.adt_kind())
+ let ctors: Vec<_> = if cx.tcx.features().exhaustive_patterns {
+ // If `exhaustive_patterns` is enabled, we exclude variants known to be
+ // uninhabited.
+ def.variants
+ .iter()
+ .filter(|v| {
+ !v.uninhabited_from(cx.tcx, substs, def.adt_kind())
.contains(cx.tcx, cx.module)
- })
- .map(|v| Variant(v.def_id))
- .collect();
-
- // If our scrutinee is *privately* an empty enum, we must treat it as though it had an
- // "unknown" constructor (in that case, all other patterns obviously can't be variants)
- // to avoid exposing its emptyness. See the `match_privately_empty` test for details.
- // FIXME: currently the only way I know of something can be a privately-empty enum is
- // when the exhaustive_patterns feature flag is not present, so this is only needed for
- // that case.
- let is_privately_empty = ctors.is_empty() && !cx.is_uninhabited(pcx.ty);
- // If the enum is declared as `#[non_exhaustive]`, we treat it as if it had an
- // additionnal "unknown" constructor.
- let is_declared_nonexhaustive =
- def.is_variant_list_non_exhaustive() && !cx.is_local(pcx.ty);
-
- if is_privately_empty || is_declared_nonexhaustive {
- // There is no point in enumerating all possible variants, because the user can't
- // actually match against them themselves. So we return only the fictitious
- // constructor.
- // E.g., in an example like:
- // ```
- // let err: io::ErrorKind = ...;
- // match err {
- // io::ErrorKind::NotFound => {},
- // }
- // ```
- // we don't want to show every possible IO error, but instead have only `_` as the
- // witness.
- vec![NonExhaustive]
+ })
+ .map(|v| Variant(v.def_id))
+ .collect()
} else {
- ctors
- }
+ def.variants.iter().map(|v| Variant(v.def_id)).collect()
+ };
+
+ // If the enum is declared as `#[non_exhaustive]`, we treat it as if it had an
+ // additional "unknown" constructor.
+ // There is no point in enumerating all possible variants, because the user can't
+ // actually match against them all themselves. So we always return only the fictitious
+ // constructor.
+ // E.g., in an example like:
+ // ```
+ // let err: io::ErrorKind = ...;
+ // match err {
+ // io::ErrorKind::NotFound => {},
+ // }
+ // ```
+ // we don't want to show every possible IO error, but instead have only `_` as the
+ // witness.
+ let is_declared_nonexhaustive = cx.is_foreign_non_exhaustive_enum(pcx.ty);
+
+ // If `exhaustive_patterns` is disabled and our scrutinee is an empty enum, we treat it
+ // as though it had an "unknown" constructor to avoid exposing its emptyness. Note that
+ // an empty match will still be considered exhaustive because that case is handled
+ // separately in `check_match`.
+ let is_secretly_empty =
+ def.variants.is_empty() && !cx.tcx.features().exhaustive_patterns;
+
+ if is_secretly_empty || is_declared_nonexhaustive { vec![NonExhaustive] } else { ctors }
}
ty::Char => {
vec![
@@ -1605,6 +1620,7 @@
v: &PatStack<'p, 'tcx>,
witness_preference: WitnessPreference,
hir_id: HirId,
+ is_top_level: bool,
) -> Usefulness<'tcx, 'p> {
let &Matrix(ref rows) = matrix;
debug!("is_useful({:#?}, {:#?})", matrix, v);
@@ -1632,7 +1648,7 @@
let mut unreachable_pats = Vec::new();
let mut any_is_useful = false;
for v in vs {
- let res = is_useful(cx, &matrix, &v, witness_preference, hir_id);
+ let res = is_useful(cx, &matrix, &v, witness_preference, hir_id, false);
match res {
Useful(pats) => {
any_is_useful = true;
@@ -1732,7 +1748,7 @@
} else {
let matrix = matrix.specialize_wildcard();
let v = v.to_tail();
- let usefulness = is_useful(cx, &matrix, &v, witness_preference, hir_id);
+ let usefulness = is_useful(cx, &matrix, &v, witness_preference, hir_id, false);
// In this case, there's at least one "free"
// constructor that is only matched against by
@@ -1761,7 +1777,10 @@
// `(<direction-1>, <direction-2>, true)` - we are
// satisfied with `(_, _, true)`. In this case,
// `used_ctors` is empty.
- if missing_ctors.all_ctors_are_missing() {
+ // The exception is: if we are at the top-level, for example in an empty match, we
+ // sometimes prefer reporting the list of constructors instead of just `_`.
+ let report_ctors_rather_than_wildcard = is_top_level && !IntRange::is_integral(pcx.ty);
+ if missing_ctors.all_ctors_are_missing() && !report_ctors_rather_than_wildcard {
// All constructors are unused. Add a wild pattern
// rather than each individual constructor.
usefulness.apply_wildcard(pcx.ty)
@@ -1793,7 +1812,7 @@
cx.pattern_arena.alloc_from_iter(ctor.wildcard_subpatterns(cx, lty));
let matrix = matrix.specialize_constructor(cx, &ctor, ctor_wild_subpatterns);
v.specialize_constructor(cx, &ctor, ctor_wild_subpatterns)
- .map(|v| is_useful(cx, &matrix, &v, witness_preference, hir_id))
+ .map(|v| is_useful(cx, &matrix, &v, witness_preference, hir_id, false))
.map(|u| u.apply_constructor(cx, &ctor, lty))
.unwrap_or(NotUseful)
}
@@ -2308,7 +2327,7 @@
PatKind::Variant { adt_def, variant_index, ref subpatterns, .. } => {
let ref variant = adt_def.variants[variant_index];
- let is_non_exhaustive = variant.is_field_list_non_exhaustive() && !cx.is_local(pat.ty);
+ let is_non_exhaustive = cx.is_foreign_non_exhaustive_variant(pat.ty, variant);
Some(Variant(variant.def_id))
.filter(|variant_constructor| variant_constructor == constructor)
.map(|_| {
diff --git a/src/librustc_mir/hair/pattern/check_match.rs b/src/librustc_mir/hair/pattern/check_match.rs
index 737af3e..8156cfe 100644
--- a/src/librustc_mir/hair/pattern/check_match.rs
+++ b/src/librustc_mir/hair/pattern/check_match.rs
@@ -148,8 +148,8 @@
self.tables,
);
patcx.include_lint_checks();
- let pattern: &_ =
- cx.pattern_arena.alloc(expand_pattern(cx, patcx.lower_pattern(&arm.pat)));
+ let pattern = patcx.lower_pattern(&arm.pat);
+ let pattern: &_ = cx.pattern_arena.alloc(expand_pattern(cx, pattern));
if !patcx.errors.is_empty() {
patcx.report_inlining_errors(arm.pat.span);
have_errors = true;
@@ -166,73 +166,12 @@
// Fourth, check for unreachable arms.
let matrix = check_arms(cx, &inlined_arms, source);
- // Then, if the match has no arms, check whether the scrutinee
- // is uninhabited.
- let pat_ty = self.tables.node_type(scrut.hir_id);
- let module = self.tcx.hir().get_module_parent(scrut.hir_id);
- let mut def_span = None;
- let mut missing_variants = vec![];
- if inlined_arms.is_empty() {
- let scrutinee_is_uninhabited = if self.tcx.features().exhaustive_patterns {
- self.tcx.is_ty_uninhabited_from(module, pat_ty)
- } else {
- match pat_ty.kind {
- ty::Never => true,
- ty::Adt(def, _) => {
- def_span = self.tcx.hir().span_if_local(def.did);
- if def.variants.len() < 4 && !def.variants.is_empty() {
- // keep around to point at the definition of non-covered variants
- missing_variants =
- def.variants.iter().map(|variant| variant.ident).collect();
- }
-
- let is_non_exhaustive_and_non_local =
- def.is_variant_list_non_exhaustive() && !def.did.is_local();
-
- !(is_non_exhaustive_and_non_local) && def.variants.is_empty()
- }
- _ => false,
- }
- };
- if !scrutinee_is_uninhabited {
- // We know the type is inhabited, so this must be wrong
- let mut err = create_e0004(
- self.tcx.sess,
- scrut.span,
- format!(
- "non-exhaustive patterns: {}",
- match missing_variants.len() {
- 0 => format!("type `{}` is non-empty", pat_ty),
- 1 => format!(
- "pattern `{}` of type `{}` is not handled",
- missing_variants[0].name, pat_ty,
- ),
- _ => format!(
- "multiple patterns of type `{}` are not handled",
- pat_ty
- ),
- }
- ),
- );
- err.help(
- "ensure that all possible cases are being handled, \
- possibly by adding wildcards or more match arms",
- );
- if let Some(sp) = def_span {
- err.span_label(sp, format!("`{}` defined here", pat_ty));
- }
- // point at the definition of non-covered enum variants
- for variant in &missing_variants {
- err.span_label(variant.span, "variant not covered");
- }
- err.emit();
- }
- // If the type *is* uninhabited, it's vacuously exhaustive
- return;
- }
-
+ // Fifth, check if the match is exhaustive.
let scrut_ty = self.tables.node_type(scrut.hir_id);
- check_exhaustive(cx, scrut_ty, scrut.span, &matrix, scrut.hir_id);
+ // Note: An empty match isn't the same as an empty matrix for diagnostics purposes,
+ // since an empty matrix can occur when there are arms, if those arms all have guards.
+ let is_empty_match = inlined_arms.is_empty();
+ check_exhaustive(cx, scrut_ty, scrut.span, &matrix, scrut.hir_id, is_empty_match);
})
}
@@ -390,7 +329,7 @@
for (arm_index, (pat, hir_pat, has_guard)) in arms.iter().enumerate() {
let v = PatStack::from_pattern(pat);
- match is_useful(cx, &seen, &v, LeaveOutWitness, hir_pat.hir_id) {
+ match is_useful(cx, &seen, &v, LeaveOutWitness, hir_pat.hir_id, true) {
NotUseful => {
match source {
hir::MatchSource::IfDesugar { .. } | hir::MatchSource::WhileDesugar => bug!(),
@@ -478,7 +417,8 @@
hir_id: HirId,
) -> Result<(), Vec<super::Pat<'tcx>>> {
let wild_pattern = cx.pattern_arena.alloc(super::Pat::wildcard_from_ty(ty));
- match is_useful(cx, matrix, &PatStack::from_pattern(wild_pattern), ConstructWitness, hir_id) {
+ let v = PatStack::from_pattern(wild_pattern);
+ match is_useful(cx, matrix, &v, ConstructWitness, hir_id, true) {
NotUseful => Ok(()), // This is good, wildcard pattern isn't reachable.
UsefulWithWitness(pats) => Err(if pats.is_empty() {
bug!("Exhaustiveness check returned no witnesses")
@@ -495,25 +435,60 @@
sp: Span,
matrix: &Matrix<'p, 'tcx>,
hir_id: HirId,
+ is_empty_match: bool,
) {
+ // In the absence of the `exhaustive_patterns` feature, empty matches are not detected by
+ // `is_useful` to exhaustively match uninhabited types, so we manually check here.
+ if is_empty_match && !cx.tcx.features().exhaustive_patterns {
+ let scrutinee_is_visibly_uninhabited = match scrut_ty.kind {
+ ty::Never => true,
+ ty::Adt(def, _) => {
+ def.is_enum()
+ && def.variants.is_empty()
+ && !cx.is_foreign_non_exhaustive_enum(scrut_ty)
+ }
+ _ => false,
+ };
+ if scrutinee_is_visibly_uninhabited {
+ // If the type *is* uninhabited, an empty match is vacuously exhaustive.
+ return;
+ }
+ }
+
let witnesses = match check_not_useful(cx, scrut_ty, matrix, hir_id) {
Ok(_) => return,
Err(err) => err,
};
- let joined_patterns = joined_uncovered_patterns(&witnesses);
- let mut err = create_e0004(
- cx.tcx.sess,
- sp,
- format!("non-exhaustive patterns: {} not covered", joined_patterns),
- );
- err.span_label(sp, pattern_not_covered_label(&witnesses, &joined_patterns));
+ let non_empty_enum = match scrut_ty.kind {
+ ty::Adt(def, _) => def.is_enum() && !def.variants.is_empty(),
+ _ => false,
+ };
+ // In the case of an empty match, replace the '`_` not covered' diagnostic with something more
+ // informative.
+ let mut err;
+ if is_empty_match && !non_empty_enum {
+ err = create_e0004(
+ cx.tcx.sess,
+ sp,
+ format!("non-exhaustive patterns: type `{}` is non-empty", scrut_ty),
+ );
+ } else {
+ let joined_patterns = joined_uncovered_patterns(&witnesses);
+ err = create_e0004(
+ cx.tcx.sess,
+ sp,
+ format!("non-exhaustive patterns: {} not covered", joined_patterns),
+ );
+ err.span_label(sp, pattern_not_covered_label(&witnesses, &joined_patterns));
+ };
+
adt_defined_here(cx, &mut err, scrut_ty, &witnesses);
err.help(
"ensure that all possible cases are being handled, \
possibly by adding wildcards or more match arms",
- )
- .emit();
+ );
+ err.emit();
}
fn joined_uncovered_patterns(witnesses: &[super::Pat<'_>]) -> String {
diff --git a/src/librustc_mir/hair/pattern/mod.rs b/src/librustc_mir/hair/pattern/mod.rs
index 92c7178..0086c3b 100644
--- a/src/librustc_mir/hair/pattern/mod.rs
+++ b/src/librustc_mir/hair/pattern/mod.rs
@@ -1154,13 +1154,7 @@
) -> Option<Ordering> {
trace!("compare_const_vals: {:?}, {:?}", a, b);
- let from_bool = |v: bool| {
- if v {
- Some(Ordering::Equal)
- } else {
- None
- }
- };
+ let from_bool = |v: bool| v.then_some(Ordering::Equal);
let fallback = || from_bool(a == b);
diff --git a/src/librustc_mir/interpret/eval_context.rs b/src/librustc_mir/interpret/eval_context.rs
index 9af47f3..653718c 100644
--- a/src/librustc_mir/interpret/eval_context.rs
+++ b/src/librustc_mir/interpret/eval_context.rs
@@ -312,7 +312,7 @@
&self,
instance: ty::InstanceDef<'tcx>,
promoted: Option<mir::Promoted>,
- ) -> InterpResult<'tcx, mir::ReadOnlyBodyCache<'tcx, 'tcx>> {
+ ) -> InterpResult<'tcx, mir::ReadOnlyBodyAndCache<'tcx, 'tcx>> {
// do not continue if typeck errors occurred (can only occur in local crate)
let did = instance.def_id();
if did.is_local()
diff --git a/src/librustc_mir/interpret/intrinsics.rs b/src/librustc_mir/interpret/intrinsics.rs
index ad5df5a..67f0aed 100644
--- a/src/librustc_mir/interpret/intrinsics.rs
+++ b/src/librustc_mir/interpret/intrinsics.rs
@@ -112,6 +112,7 @@
// `src/librustc/ty/constness.rs`
match intrinsic_name {
sym::caller_location => {
+ let span = self.find_closest_untracked_caller_location().unwrap_or(span);
let location = self.alloc_caller_location_for_span(span);
self.write_scalar(location.ptr, dest)?;
}
diff --git a/src/librustc_mir/interpret/intrinsics/caller_location.rs b/src/librustc_mir/interpret/intrinsics/caller_location.rs
index ecf4b7a..ec843ef 100644
--- a/src/librustc_mir/interpret/intrinsics/caller_location.rs
+++ b/src/librustc_mir/interpret/intrinsics/caller_location.rs
@@ -6,6 +6,21 @@
use crate::interpret::{Scalar, MemoryKind, MPlaceTy, intrinsics::{InterpCx, Machine}};
impl<'mir, 'tcx, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
+ /// Walks up the callstack from the intrinsic's callsite, searching for the first frame which is
+ /// not `#[track_caller]`.
+ crate fn find_closest_untracked_caller_location(&self) -> Option<Span> {
+ let mut caller_span = None;
+ for next_caller in self.stack.iter().rev() {
+ if !next_caller.instance.def.requires_caller_location(*self.tcx) {
+ return caller_span;
+ }
+ caller_span = Some(next_caller.span);
+ }
+
+ caller_span
+ }
+
+ /// Allocate a `const core::panic::Location` with the provided filename and line/column numbers.
crate fn alloc_caller_location(
&mut self,
filename: Symbol,
diff --git a/src/librustc_mir/interpret/memory.rs b/src/librustc_mir/interpret/memory.rs
index ee7fb18..8f177ad 100644
--- a/src/librustc_mir/interpret/memory.rs
+++ b/src/librustc_mir/interpret/memory.rs
@@ -324,7 +324,7 @@
size: Size,
align: Align,
) -> InterpResult<'tcx, Option<Pointer<M::PointerTag>>> {
- let align = if M::CHECK_ALIGN { Some(align) } else { None };
+ let align = M::CHECK_ALIGN.then_some(align);
self.check_ptr_access_align(sptr, size, align, CheckInAllocMsg::MemoryAccessTest)
}
diff --git a/src/librustc_mir/interpret/operator.rs b/src/librustc_mir/interpret/operator.rs
index 176b084..6800429 100644
--- a/src/librustc_mir/interpret/operator.rs
+++ b/src/librustc_mir/interpret/operator.rs
@@ -177,8 +177,8 @@
return Ok((Scalar::from_bool(op(&l, &r)), false, self.tcx.types.bool));
}
let op: Option<fn(i128, i128) -> (i128, bool)> = match bin_op {
- Div if r == 0 => throw_panic!(DivisionByZero),
- Rem if r == 0 => throw_panic!(RemainderByZero),
+ Div if r == 0 => throw_ub!(DivisionByZero),
+ Rem if r == 0 => throw_ub!(RemainderByZero),
Div => Some(i128::overflowing_div),
Rem => Some(i128::overflowing_rem),
Add => Some(i128::overflowing_add),
@@ -234,8 +234,8 @@
Add => u128::overflowing_add,
Sub => u128::overflowing_sub,
Mul => u128::overflowing_mul,
- Div if r == 0 => throw_panic!(DivisionByZero),
- Rem if r == 0 => throw_panic!(RemainderByZero),
+ Div if r == 0 => throw_ub!(DivisionByZero),
+ Rem if r == 0 => throw_ub!(RemainderByZero),
Div => u128::overflowing_div,
Rem => u128::overflowing_rem,
_ => bug!(),
diff --git a/src/librustc_mir/interpret/place.rs b/src/librustc_mir/interpret/place.rs
index 902472d..42fbfec 100644
--- a/src/librustc_mir/interpret/place.rs
+++ b/src/librustc_mir/interpret/place.rs
@@ -384,10 +384,8 @@
layout::FieldPlacement::Array { stride, .. } => {
let len = base.len(self)?;
if field >= len {
- // This can be violated because the index (field) can be a runtime value
- // provided by the user.
- debug!("tried to access element {} of array/slice with length {}", field, len);
- throw_panic!(BoundsCheck { len, index: field });
+ // This can only be reached in ConstProp and non-rustc-MIR.
+ throw_ub!(BoundsCheckFailed { len, index: field });
}
stride * field
}
@@ -453,9 +451,15 @@
base: MPlaceTy<'tcx, M::PointerTag>,
from: u64,
to: u64,
+ from_end: bool,
) -> InterpResult<'tcx, MPlaceTy<'tcx, M::PointerTag>> {
let len = base.len(self)?; // also asserts that we have a type where this makes sense
- assert!(from <= len - to);
+ let actual_to = if from_end {
+ assert!(from <= len - to);
+ len - to
+ } else {
+ to
+ };
// Not using layout method because that works with usize, and does not work with slices
// (that have count 0 in their layout).
@@ -466,7 +470,7 @@
};
// Compute meta and new layout
- let inner_len = len - to - from;
+ let inner_len = actual_to - from;
let (meta, ty) = match base.layout.ty.kind {
// It is not nice to match on the type, but that seems to be the only way to
// implement this.
@@ -530,8 +534,8 @@
self.mplace_field(base, index)?
}
- Subslice { from, to } =>
- self.mplace_subslice(base, u64::from(from), u64::from(to))?,
+ Subslice { from, to, from_end } =>
+ self.mplace_subslice(base, u64::from(from), u64::from(to), from_end)?,
})
}
diff --git a/src/librustc_mir/interpret/step.rs b/src/librustc_mir/interpret/step.rs
index d749333..33ed69a 100644
--- a/src/librustc_mir/interpret/step.rs
+++ b/src/librustc_mir/interpret/step.rs
@@ -157,9 +157,9 @@
}
BinaryOp(bin_op, ref left, ref right) => {
- let layout = if binop_left_homogeneous(bin_op) { Some(dest.layout) } else { None };
+ let layout = binop_left_homogeneous(bin_op).then_some(dest.layout);
let left = self.read_immediate(self.eval_operand(left, layout)?)?;
- let layout = if binop_right_homogeneous(bin_op) { Some(left.layout) } else { None };
+ let layout = binop_right_homogeneous(bin_op).then_some(left.layout);
let right = self.read_immediate(self.eval_operand(right, layout)?)?;
self.binop_ignore_overflow(
bin_op,
@@ -172,7 +172,7 @@
CheckedBinaryOp(bin_op, ref left, ref right) => {
// Due to the extra boolean in the result, we can never reuse the `dest.layout`.
let left = self.read_immediate(self.eval_operand(left, None)?)?;
- let layout = if binop_right_homogeneous(bin_op) { Some(left.layout) } else { None };
+ let layout = binop_right_homogeneous(bin_op).then_some(left.layout);
let right = self.read_immediate(self.eval_operand(right, layout)?)?;
self.binop_with_overflow(
bin_op,
@@ -304,7 +304,9 @@
if !self.stack.is_empty() {
// This should change *something*
debug_assert!(self.cur_frame() != old_stack || self.frame().block != old_bb);
- info!("// {:?}", self.frame().block);
+ if let Some(block) = self.frame().block {
+ info!("// executing {:?}", block);
+ }
}
Ok(())
}
diff --git a/src/librustc_mir/interpret/traits.rs b/src/librustc_mir/interpret/traits.rs
index efa0d26..916ea3dc 100644
--- a/src/librustc_mir/interpret/traits.rs
+++ b/src/librustc_mir/interpret/traits.rs
@@ -140,7 +140,18 @@
let fn_sig = drop_instance.ty(*self.tcx).fn_sig(*self.tcx);
let fn_sig = self.tcx.normalize_erasing_late_bound_regions(self.param_env, &fn_sig);
// The drop function takes `*mut T` where `T` is the type being dropped, so get that.
- let ty = fn_sig.inputs()[0].builtin_deref(true).unwrap().ty;
+ let args = fn_sig.inputs();
+ if args.len() != 1 {
+ throw_ub_format!(
+ "drop fn should have 1 argument, but signature is {:?}", fn_sig
+ );
+ }
+ let ty = args[0].builtin_deref(true)
+ .ok_or_else(|| err_ub_format!(
+ "drop fn argument type {} is not a pointer type",
+ args[0]
+ ))?
+ .ty;
Ok((drop_instance, ty))
}
diff --git a/src/librustc_mir/interpret/validity.rs b/src/librustc_mir/interpret/validity.rs
index e358df2..1dbcfe5 100644
--- a/src/librustc_mir/interpret/validity.rs
+++ b/src/librustc_mir/interpret/validity.rs
@@ -22,28 +22,23 @@
macro_rules! throw_validation_failure {
($what:expr, $where:expr, $details:expr) => {{
- let where_ = path_format(&$where);
- let where_ = if where_.is_empty() {
- String::new()
- } else {
- format!(" at {}", where_)
- };
- throw_unsup!(ValidationFailure(format!(
- "encountered {}{}, but expected {}",
- $what, where_, $details,
- )))
+ let mut msg = format!("encountered {}", $what);
+ let where_ = &$where;
+ if !where_.is_empty() {
+ msg.push_str(" at ");
+ write_path(&mut msg, where_);
+ }
+ write!(&mut msg, ", but expected {}", $details).unwrap();
+ throw_unsup!(ValidationFailure(msg))
}};
($what:expr, $where:expr) => {{
- let where_ = path_format(&$where);
- let where_ = if where_.is_empty() {
- String::new()
- } else {
- format!(" at {}", where_)
- };
- throw_unsup!(ValidationFailure(format!(
- "encountered {}{}",
- $what, where_,
- )))
+ let mut msg = format!("encountered {}", $what);
+ let where_ = &$where;
+ if !where_.is_empty() {
+ msg.push_str(" at ");
+ write_path(&mut msg, where_);
+ }
+ throw_unsup!(ValidationFailure(msg))
}};
}
@@ -60,7 +55,7 @@
Ok(x) => x,
Err(_) => throw_validation_failure!($what, $where),
}
- }}
+ }};
}
/// We want to show a nice path to the invalid field for diagnostics,
@@ -113,10 +108,9 @@
}
/// Format a path
-fn path_format(path: &Vec<PathElem>) -> String {
+fn write_path(out: &mut String, path: &Vec<PathElem>) {
use self::PathElem::*;
- let mut out = String::new();
for elem in path.iter() {
match elem {
Field(name) => write!(out, ".{}", name),
@@ -135,7 +129,6 @@
DynDowncast => write!(out, ".<dyn-downcast>"),
}.unwrap()
}
- out
}
// Test if a range that wraps at overflow contains `test`
@@ -428,7 +421,7 @@
err_unsup!(InvalidNullPointerUsage) =>
throw_validation_failure!("NULL reference", self.path),
err_unsup!(AlignmentCheckFailed { required, has }) =>
- throw_validation_failure!(format!("unaligned reference \
+ throw_validation_failure!(format_args!("unaligned reference \
(required {} byte alignment but found {})",
required.bytes(), has.bytes()), self.path),
err_unsup!(ReadBytesAsPointer) =>
@@ -519,7 +512,7 @@
let value = try_validation!(value.not_undef(),
value,
self.path,
- format!(
+ format_args!(
"something {}",
wrapping_range_format(&layout.valid_range, max_hi),
)
@@ -532,7 +525,7 @@
throw_validation_failure!(
"a potentially NULL pointer",
self.path,
- format!(
+ format_args!(
"something that cannot possibly fail to be {}",
wrapping_range_format(&layout.valid_range, max_hi)
)
@@ -545,7 +538,7 @@
throw_validation_failure!(
"a pointer",
self.path,
- format!(
+ format_args!(
"something that cannot possibly fail to be {}",
wrapping_range_format(&layout.valid_range, max_hi)
)
@@ -562,7 +555,7 @@
throw_validation_failure!(
bits,
self.path,
- format!("something {}", wrapping_range_format(&layout.valid_range, max_hi))
+ format_args!("something {}", wrapping_range_format(&layout.valid_range, max_hi))
)
}
}
diff --git a/src/librustc_mir/lib.rs b/src/librustc_mir/lib.rs
index f4fb9a5..42b72b6 100644
--- a/src/librustc_mir/lib.rs
+++ b/src/librustc_mir/lib.rs
@@ -8,6 +8,7 @@
#![feature(in_band_lifetimes)]
#![feature(inner_deref)]
#![feature(slice_patterns)]
+#![feature(bool_to_option)]
#![feature(box_patterns)]
#![feature(box_syntax)]
#![feature(crate_visibility_modifier)]
@@ -27,7 +28,6 @@
#![feature(associated_type_bounds)]
#![feature(range_is_empty)]
#![feature(stmt_expr_attributes)]
-#![feature(bool_to_option)]
#![feature(trait_alias)]
#![feature(matches_macro)]
diff --git a/src/librustc_mir/monomorphize/partitioning.rs b/src/librustc_mir/monomorphize/partitioning.rs
index 42f0877..591f220 100644
--- a/src/librustc_mir/monomorphize/partitioning.rs
+++ b/src/librustc_mir/monomorphize/partitioning.rs
@@ -761,11 +761,7 @@
.iter()
.map(|part| part.data.as_symbol());
- let volatile_suffix = if volatile {
- Some("volatile")
- } else {
- None
- };
+ let volatile_suffix = volatile.then_some("volatile");
name_builder.build_cgu_name(def_path.krate, components, volatile_suffix)
}).clone()
diff --git a/src/librustc_mir/shim.rs b/src/librustc_mir/shim.rs
index 5b208dd..47b0804 100644
--- a/src/librustc_mir/shim.rs
+++ b/src/librustc_mir/shim.rs
@@ -26,7 +26,7 @@
providers.mir_shims = make_shim;
}
-fn make_shim<'tcx>(tcx: TyCtxt<'tcx>, instance: ty::InstanceDef<'tcx>) -> &'tcx BodyCache<'tcx> {
+fn make_shim<'tcx>(tcx: TyCtxt<'tcx>, instance: ty::InstanceDef<'tcx>) -> &'tcx BodyAndCache<'tcx> {
debug!("make_shim({:?})", instance);
let mut result = match instance {
@@ -170,7 +170,7 @@
fn build_drop_shim<'tcx>(
tcx: TyCtxt<'tcx>, def_id: DefId, ty: Option<Ty<'tcx>>
-) -> BodyCache<'tcx> {
+) -> BodyAndCache<'tcx> {
debug!("build_drop_shim(def_id={:?}, ty={:?})", def_id, ty);
// Check if this is a generator, if so, return the drop glue for it
@@ -208,7 +208,7 @@
sig.inputs().len(),
span);
- let mut body = BodyCache::new(body);
+ let mut body = BodyAndCache::new(body);
if let Some(..) = ty {
// The first argument (index 0), but add 1 for the return value.
@@ -322,7 +322,11 @@
}
/// Builds a `Clone::clone` shim for `self_ty`. Here, `def_id` is `Clone::clone`.
-fn build_clone_shim<'tcx>(tcx: TyCtxt<'tcx>, def_id: DefId, self_ty: Ty<'tcx>) -> BodyCache<'tcx> {
+fn build_clone_shim<'tcx>(
+ tcx: TyCtxt<'tcx>,
+ def_id: DefId,
+ self_ty: Ty<'tcx>,
+) -> BodyAndCache<'tcx> {
debug!("build_clone_shim(def_id={:?})", def_id);
let param_env = tcx.param_env(def_id);
@@ -351,7 +355,7 @@
}
};
- BodyCache::new(builder.into_mir())
+ BodyAndCache::new(builder.into_mir())
}
struct CloneShimBuilder<'tcx> {
@@ -712,7 +716,7 @@
rcvr_adjustment: Adjustment,
call_kind: CallKind,
untuple_args: Option<&[Ty<'tcx>]>,
-) -> BodyCache<'tcx> {
+) -> BodyAndCache<'tcx> {
debug!("build_call_shim(instance={:?}, rcvr_adjustment={:?}, \
call_kind={:?}, untuple_args={:?})",
instance, rcvr_adjustment, call_kind, untuple_args);
@@ -853,10 +857,10 @@
if let Abi::RustCall = sig.abi {
body.spread_arg = Some(Local::new(sig.inputs().len()));
}
- BodyCache::new(body)
+ BodyAndCache::new(body)
}
-pub fn build_adt_ctor(tcx: TyCtxt<'_>, ctor_id: DefId) -> &BodyCache<'_> {
+pub fn build_adt_ctor(tcx: TyCtxt<'_>, ctor_id: DefId) -> &BodyAndCache<'_> {
debug_assert!(tcx.is_constructor(ctor_id));
let span = tcx.hir().span_if_local(ctor_id)
@@ -940,7 +944,7 @@
|_, _| Ok(()),
);
- let mut body = BodyCache::new(body);
+ let mut body = BodyAndCache::new(body);
body.ensure_predecessors();
tcx.arena.alloc(body)
}
diff --git a/src/librustc_mir/transform/add_call_guards.rs b/src/librustc_mir/transform/add_call_guards.rs
index 35238e2..d1832eb 100644
--- a/src/librustc_mir/transform/add_call_guards.rs
+++ b/src/librustc_mir/transform/add_call_guards.rs
@@ -32,14 +32,14 @@
impl<'tcx> MirPass<'tcx> for AddCallGuards {
fn run_pass(
- &self, _tcx: TyCtxt<'tcx>, _src: MirSource<'tcx>, body: &mut BodyCache<'tcx>
+ &self, _tcx: TyCtxt<'tcx>, _src: MirSource<'tcx>, body: &mut BodyAndCache<'tcx>
) {
self.add_call_guards(body);
}
}
impl AddCallGuards {
- pub fn add_call_guards(&self, body: &mut BodyCache<'_>) {
+ pub fn add_call_guards(&self, body: &mut BodyAndCache<'_>) {
let pred_count: IndexVec<_, _> = body.predecessors().iter().map(|ps| ps.len()).collect();
// We need a place to store the new blocks generated
diff --git a/src/librustc_mir/transform/add_moves_for_packed_drops.rs b/src/librustc_mir/transform/add_moves_for_packed_drops.rs
index 98c6a5e..861e7fe 100644
--- a/src/librustc_mir/transform/add_moves_for_packed_drops.rs
+++ b/src/librustc_mir/transform/add_moves_for_packed_drops.rs
@@ -40,14 +40,14 @@
pub struct AddMovesForPackedDrops;
impl<'tcx> MirPass<'tcx> for AddMovesForPackedDrops {
- fn run_pass(&self, tcx: TyCtxt<'tcx>, src: MirSource<'tcx>, body: &mut BodyCache<'tcx>) {
+ fn run_pass(&self, tcx: TyCtxt<'tcx>, src: MirSource<'tcx>, body: &mut BodyAndCache<'tcx>) {
debug!("add_moves_for_packed_drops({:?} @ {:?})", src, body.span);
add_moves_for_packed_drops(tcx, body, src.def_id());
}
}
pub fn add_moves_for_packed_drops<'tcx>(
- tcx: TyCtxt<'tcx>, body: &mut BodyCache<'tcx>, def_id: DefId
+ tcx: TyCtxt<'tcx>, body: &mut BodyAndCache<'tcx>, def_id: DefId
) {
let patch = add_moves_for_packed_drops_patch(tcx, body, def_id);
patch.apply(body);
diff --git a/src/librustc_mir/transform/add_retag.rs b/src/librustc_mir/transform/add_retag.rs
index e6ad37a..dc21c67 100644
--- a/src/librustc_mir/transform/add_retag.rs
+++ b/src/librustc_mir/transform/add_retag.rs
@@ -59,7 +59,7 @@
}
impl<'tcx> MirPass<'tcx> for AddRetag {
- fn run_pass(&self, tcx: TyCtxt<'tcx>, _src: MirSource<'tcx>, body: &mut BodyCache<'tcx>) {
+ fn run_pass(&self, tcx: TyCtxt<'tcx>, _src: MirSource<'tcx>, body: &mut BodyAndCache<'tcx>) {
if !tcx.sess.opts.debugging_opts.mir_emit_retag {
return;
}
diff --git a/src/librustc_mir/transform/check_consts/mod.rs b/src/librustc_mir/transform/check_consts/mod.rs
index 7095b3f..89672e8 100644
--- a/src/librustc_mir/transform/check_consts/mod.rs
+++ b/src/librustc_mir/transform/check_consts/mod.rs
@@ -20,7 +20,7 @@
/// Information about the item currently being const-checked, as well as a reference to the global
/// context.
pub struct Item<'mir, 'tcx> {
- pub body: mir::ReadOnlyBodyCache<'mir, 'tcx>,
+ pub body: mir::ReadOnlyBodyAndCache<'mir, 'tcx>,
pub tcx: TyCtxt<'tcx>,
pub def_id: DefId,
pub param_env: ty::ParamEnv<'tcx>,
@@ -31,7 +31,7 @@
pub fn new(
tcx: TyCtxt<'tcx>,
def_id: DefId,
- body: mir::ReadOnlyBodyCache<'mir, 'tcx>,
+ body: mir::ReadOnlyBodyAndCache<'mir, 'tcx>,
) -> Self {
let param_env = tcx.param_env(def_id);
let const_kind = ConstKind::for_item(tcx, def_id);
@@ -77,7 +77,12 @@
let mode = match tcx.hir().body_owner_kind(hir_id) {
HirKind::Closure => return None,
- HirKind::Fn if tcx.is_const_fn(def_id) => ConstKind::ConstFn,
+ // Note: this is deliberately checking for `is_const_fn_raw`, as the `is_const_fn`
+ // checks take into account the `rustc_const_unstable` attribute combined with enabled
+ // feature gates. Otherwise, const qualification would _not check_ whether this
+ // function body follows the `const fn` rules, as an unstable `const fn` would
+ // be considered "not const". More details are available in issue #67053.
+ HirKind::Fn if tcx.is_const_fn_raw(def_id) => ConstKind::ConstFn,
HirKind::Fn => return None,
HirKind::Const => ConstKind::Const,
diff --git a/src/librustc_mir/transform/check_consts/ops.rs b/src/librustc_mir/transform/check_consts/ops.rs
index aec3cf0..393ae94 100644
--- a/src/librustc_mir/transform/check_consts/ops.rs
+++ b/src/librustc_mir/transform/check_consts/ops.rs
@@ -1,7 +1,6 @@
//! Concrete error types for all operations which may be invalid in a certain const context.
use rustc::hir::def_id::DefId;
-use rustc::mir::BorrowKind;
use rustc::session::config::nightly_options;
use rustc::ty::TyCtxt;
use syntax::feature_gate::feature_err;
@@ -181,38 +180,53 @@
}
#[derive(Debug)]
-pub struct MutBorrow(pub BorrowKind);
-impl NonConstOp for MutBorrow {
+pub struct CellBorrow;
+impl NonConstOp for CellBorrow {
fn emit_error(&self, item: &Item<'_, '_>, span: Span) {
- let kind = self.0;
- if let BorrowKind::Mut { .. } = kind {
- let mut err = struct_span_err!(item.tcx.sess, span, E0017,
- "references in {}s may only refer \
- to immutable values", item.const_kind());
- err.span_label(span, format!("{}s require immutable values",
- item.const_kind()));
- if item.tcx.sess.teach(&err.get_code().unwrap()) {
- err.note("References in statics and constants may only refer \
- to immutable values.\n\n\
- Statics are shared everywhere, and if they refer to \
- mutable data one might violate memory safety since \
- holding multiple mutable references to shared data \
- is not allowed.\n\n\
- If you really want global mutable state, try using \
- static mut or a global UnsafeCell.");
- }
- err.emit();
- } else {
- span_err!(item.tcx.sess, span, E0492,
- "cannot borrow a constant which may contain \
- interior mutability, create a static instead");
+ span_err!(item.tcx.sess, span, E0492,
+ "cannot borrow a constant which may contain \
+ interior mutability, create a static instead");
+ }
+}
+
+#[derive(Debug)]
+pub struct MutBorrow;
+impl NonConstOp for MutBorrow {
+ fn feature_gate(tcx: TyCtxt<'_>) -> Option<bool> {
+ Some(tcx.features().const_mut_refs)
+ }
+
+ fn emit_error(&self, item: &Item<'_, '_>, span: Span) {
+ let mut err = feature_err(
+ &item.tcx.sess.parse_sess,
+ sym::const_mut_refs,
+ span,
+ &format!("references in {}s may only refer \
+ to immutable values", item.const_kind())
+ );
+ err.span_label(span, format!("{}s require immutable values",
+ item.const_kind()));
+ if item.tcx.sess.teach(&err.get_code().unwrap()) {
+ err.note("References in statics and constants may only refer \
+ to immutable values.\n\n\
+ Statics are shared everywhere, and if they refer to \
+ mutable data one might violate memory safety since \
+ holding multiple mutable references to shared data \
+ is not allowed.\n\n\
+ If you really want global mutable state, try using \
+ static mut or a global UnsafeCell.");
}
+ err.emit();
}
}
#[derive(Debug)]
pub struct MutDeref;
-impl NonConstOp for MutDeref {}
+impl NonConstOp for MutDeref {
+ fn feature_gate(tcx: TyCtxt<'_>) -> Option<bool> {
+ Some(tcx.features().const_mut_refs)
+ }
+}
#[derive(Debug)]
pub struct Panic;
diff --git a/src/librustc_mir/transform/check_consts/validation.rs b/src/librustc_mir/transform/check_consts/validation.rs
index f44bac1..6261315 100644
--- a/src/librustc_mir/transform/check_consts/validation.rs
+++ b/src/librustc_mir/transform/check_consts/validation.rs
@@ -40,7 +40,7 @@
let results =
dataflow::Engine::new(item.tcx, &item.body, item.def_id, dead_unwinds, analysis)
.iterate_to_fixpoint();
- let cursor = dataflow::ResultsCursor::new(item.body.body(), results);
+ let cursor = dataflow::ResultsCursor::new(*item.body, results);
let mut in_any_value_of_ty = BitSet::new_empty(item.body.local_decls.len());
for (local, decl) in item.body.local_decls.iter_enumerated() {
@@ -175,13 +175,13 @@
item.def_id,
&item.tcx.get_attrs(item.def_id),
&dead_unwinds,
- old_dataflow::IndirectlyMutableLocals::new(item.tcx, item.body.body(), item.param_env),
+ old_dataflow::IndirectlyMutableLocals::new(item.tcx, *item.body, item.param_env),
|_, local| old_dataflow::DebugFormatted::new(&local),
);
let indirectly_mutable = old_dataflow::DataflowResultsCursor::new(
indirectly_mutable,
- item.body.body(),
+ *item.body,
);
let qualifs = Qualifs {
@@ -359,7 +359,11 @@
};
if !is_allowed {
- self.check_op(ops::MutBorrow(kind));
+ if let BorrowKind::Mut{ .. } = kind {
+ self.check_op(ops::MutBorrow);
+ } else {
+ self.check_op(ops::CellBorrow);
+ }
}
}
@@ -384,7 +388,11 @@
);
if borrowed_place_has_mut_interior {
- self.check_op(ops::MutBorrow(kind));
+ if let BorrowKind::Mut{ .. } = kind {
+ self.check_op(ops::MutBorrow);
+ } else {
+ self.check_op(ops::CellBorrow);
+ }
}
}
@@ -451,7 +459,6 @@
}
}
}
-
fn visit_projection_elem(
&mut self,
place_base: &PlaceBase<'tcx>,
diff --git a/src/librustc_mir/transform/check_unsafety.rs b/src/librustc_mir/transform/check_unsafety.rs
index 2c45dcf..284285c 100644
--- a/src/librustc_mir/transform/check_unsafety.rs
+++ b/src/librustc_mir/transform/check_unsafety.rs
@@ -658,7 +658,7 @@
let mut unsafe_blocks: Vec<_> = unsafe_blocks.into_iter().collect();
unsafe_blocks.sort_by_cached_key(|(hir_id, _)| tcx.hir().hir_to_node_id(*hir_id));
let used_unsafe: FxHashSet<_> = unsafe_blocks.iter()
- .flat_map(|&&(id, used)| if used { Some(id) } else { None })
+ .flat_map(|&&(id, used)| used.then_some(id))
.collect();
for &(block_id, is_used) in unsafe_blocks {
if !is_used {
diff --git a/src/librustc_mir/transform/cleanup_post_borrowck.rs b/src/librustc_mir/transform/cleanup_post_borrowck.rs
index d9dd7c9..34519bc 100644
--- a/src/librustc_mir/transform/cleanup_post_borrowck.rs
+++ b/src/librustc_mir/transform/cleanup_post_borrowck.rs
@@ -16,7 +16,7 @@
//! [`FakeRead`]: rustc::mir::StatementKind::FakeRead
//! [`Nop`]: rustc::mir::StatementKind::Nop
-use rustc::mir::{BodyCache, BorrowKind, Rvalue, Location};
+use rustc::mir::{BodyAndCache, BorrowKind, Rvalue, Location};
use rustc::mir::{Statement, StatementKind};
use rustc::mir::visit::MutVisitor;
use rustc::ty::TyCtxt;
@@ -30,7 +30,7 @@
impl<'tcx> MirPass<'tcx> for CleanupNonCodegenStatements {
fn run_pass(
- &self, tcx: TyCtxt<'tcx>, _source: MirSource<'tcx>, body: &mut BodyCache<'tcx>
+ &self, tcx: TyCtxt<'tcx>, _source: MirSource<'tcx>, body: &mut BodyAndCache<'tcx>
) {
let mut delete = DeleteNonCodegenStatements { tcx };
delete.visit_body(body);
diff --git a/src/librustc_mir/transform/const_prop.rs b/src/librustc_mir/transform/const_prop.rs
index 95de635..aff91ac 100644
--- a/src/librustc_mir/transform/const_prop.rs
+++ b/src/librustc_mir/transform/const_prop.rs
@@ -7,9 +7,9 @@
use rustc::hir::def::DefKind;
use rustc::hir::def_id::DefId;
use rustc::mir::{
- AggregateKind, Constant, Location, Place, PlaceBase, Body, BodyCache, Operand, Local, UnOp,
- Rvalue, StatementKind, Statement, LocalKind, TerminatorKind, Terminator, ClearCrossCrate,
- SourceInfo, BinOp, SourceScope, SourceScopeData, LocalDecl, BasicBlock, ReadOnlyBodyCache,
+ AggregateKind, Constant, Location, Place, PlaceBase, Body, BodyAndCache, Operand, Local, UnOp,
+ Rvalue, StatementKind, Statement, LocalKind, TerminatorKind, Terminator, ClearCrossCrate,
+ SourceInfo, BinOp, SourceScope, SourceScopeData, LocalDecl, BasicBlock, ReadOnlyBodyAndCache,
read_only, RETURN_PLACE
};
use rustc::mir::visit::{
@@ -43,7 +43,7 @@
impl<'tcx> MirPass<'tcx> for ConstProp {
fn run_pass(
- &self, tcx: TyCtxt<'tcx>, source: MirSource<'tcx>, body: &mut BodyCache<'tcx>
+ &self, tcx: TyCtxt<'tcx>, source: MirSource<'tcx>, body: &mut BodyAndCache<'tcx>
) {
// will be evaluated by miri and produce its errors there
if source.promoted.is_some() {
@@ -296,7 +296,7 @@
impl<'mir, 'tcx> ConstPropagator<'mir, 'tcx> {
fn new(
- body: ReadOnlyBodyCache<'_, 'tcx>,
+ body: ReadOnlyBodyAndCache<'_, 'tcx>,
dummy_body: &'mir Body<'tcx>,
tcx: TyCtxt<'tcx>,
source: MirSource<'tcx>,
@@ -636,19 +636,45 @@
ScalarMaybeUndef::Scalar(one),
ScalarMaybeUndef::Scalar(two)
) => {
+ // Found a value represented as a pair. For now only do cont-prop if type of
+ // Rvalue is also a pair with two scalars. The more general case is more
+ // complicated to implement so we'll do it later.
let ty = &value.layout.ty.kind;
+ // Only do it for tuples
if let ty::Tuple(substs) = ty {
- *rval = Rvalue::Aggregate(
- Box::new(AggregateKind::Tuple),
- vec![
- self.operand_from_scalar(
- one, substs[0].expect_ty(), source_info.span
- ),
- self.operand_from_scalar(
- two, substs[1].expect_ty(), source_info.span
- ),
- ],
- );
+ // Only do it if tuple is also a pair with two scalars
+ if substs.len() == 2 {
+ let opt_ty1_ty2 = self.use_ecx(source_info, |this| {
+ let ty1 = substs[0].expect_ty();
+ let ty2 = substs[1].expect_ty();
+ let ty_is_scalar = |ty| {
+ this.ecx
+ .layout_of(ty)
+ .ok()
+ .map(|ty| ty.details.abi.is_scalar())
+ == Some(true)
+ };
+ if ty_is_scalar(ty1) && ty_is_scalar(ty2) {
+ Ok(Some((ty1, ty2)))
+ } else {
+ Ok(None)
+ }
+ });
+
+ if let Some(Some((ty1, ty2))) = opt_ty1_ty2 {
+ *rval = Rvalue::Aggregate(
+ Box::new(AggregateKind::Tuple),
+ vec![
+ self.operand_from_scalar(
+ one, ty1, source_info.span
+ ),
+ self.operand_from_scalar(
+ two, ty2, source_info.span
+ ),
+ ],
+ );
+ }
+ }
}
},
_ => { }
@@ -690,7 +716,7 @@
impl CanConstProp {
/// returns true if `local` can be propagated
- fn check(body: ReadOnlyBodyCache<'_, '_>) -> IndexVec<Local, bool> {
+ fn check(body: ReadOnlyBodyAndCache<'_, '_>) -> IndexVec<Local, bool> {
let mut cpv = CanConstProp {
can_const_prop: IndexVec::from_elem(true, &body.local_decls),
found_assignment: IndexVec::from_elem(false, &body.local_decls),
diff --git a/src/librustc_mir/transform/copy_prop.rs b/src/librustc_mir/transform/copy_prop.rs
index 5e4caf2..272f6e9 100644
--- a/src/librustc_mir/transform/copy_prop.rs
+++ b/src/librustc_mir/transform/copy_prop.rs
@@ -20,7 +20,7 @@
//! future.
use rustc::mir::{
- Constant, Local, LocalKind, Location, Place, Body, BodyCache, Operand, Rvalue,
+ Constant, Local, LocalKind, Location, Place, Body, BodyAndCache, Operand, Rvalue,
StatementKind, read_only
};
use rustc::mir::visit::MutVisitor;
@@ -32,7 +32,7 @@
impl<'tcx> MirPass<'tcx> for CopyPropagation {
fn run_pass(
- &self, tcx: TyCtxt<'tcx>, _source: MirSource<'tcx>, body: &mut BodyCache<'tcx>
+ &self, tcx: TyCtxt<'tcx>, _source: MirSource<'tcx>, body: &mut BodyAndCache<'tcx>
) {
// We only run when the MIR optimization level is > 1.
// This avoids a slow pass, and messing up debug info.
@@ -250,7 +250,7 @@
}
fn perform(self,
- body: &mut BodyCache<'tcx>,
+ body: &mut BodyAndCache<'tcx>,
def_use_analysis: &DefUseAnalysis,
dest_local: Local,
location: Location,
diff --git a/src/librustc_mir/transform/deaggregator.rs b/src/librustc_mir/transform/deaggregator.rs
index 933936e..cd77c9c 100644
--- a/src/librustc_mir/transform/deaggregator.rs
+++ b/src/librustc_mir/transform/deaggregator.rs
@@ -7,7 +7,7 @@
impl<'tcx> MirPass<'tcx> for Deaggregator {
fn run_pass(
- &self, tcx: TyCtxt<'tcx>, _source: MirSource<'tcx>, body: &mut BodyCache<'tcx>
+ &self, tcx: TyCtxt<'tcx>, _source: MirSource<'tcx>, body: &mut BodyAndCache<'tcx>
) {
let (basic_blocks, local_decls) = body.basic_blocks_and_local_decls_mut();
let local_decls = &*local_decls;
diff --git a/src/librustc_mir/transform/dump_mir.rs b/src/librustc_mir/transform/dump_mir.rs
index 13b3bb6..221ced3 100644
--- a/src/librustc_mir/transform/dump_mir.rs
+++ b/src/librustc_mir/transform/dump_mir.rs
@@ -5,7 +5,7 @@
use std::fs::File;
use std::io;
-use rustc::mir::{Body, BodyCache};
+use rustc::mir::{Body, BodyAndCache};
use rustc::session::config::{OutputFilenames, OutputType};
use rustc::ty::TyCtxt;
use crate::transform::{MirPass, MirSource};
@@ -19,7 +19,7 @@
}
fn run_pass(
- &self, _tcx: TyCtxt<'tcx>, _source: MirSource<'tcx>, _body: &mut BodyCache<'tcx>
+ &self, _tcx: TyCtxt<'tcx>, _source: MirSource<'tcx>, _body: &mut BodyAndCache<'tcx>
) {}
}
diff --git a/src/librustc_mir/transform/elaborate_drops.rs b/src/librustc_mir/transform/elaborate_drops.rs
index 42daba9..1cacf1f 100644
--- a/src/librustc_mir/transform/elaborate_drops.rs
+++ b/src/librustc_mir/transform/elaborate_drops.rs
@@ -21,12 +21,12 @@
pub struct ElaborateDrops;
impl<'tcx> MirPass<'tcx> for ElaborateDrops {
- fn run_pass(&self, tcx: TyCtxt<'tcx>, src: MirSource<'tcx>, body: &mut BodyCache<'tcx>) {
+ fn run_pass(&self, tcx: TyCtxt<'tcx>, src: MirSource<'tcx>, body: &mut BodyAndCache<'tcx>) {
debug!("elaborate_drops({:?} @ {:?})", src, body.span);
let def_id = src.def_id();
let param_env = tcx.param_env(src.def_id()).with_reveal_all();
- let move_data = match MoveData::gather_moves(body, tcx) {
+ let move_data = match MoveData::gather_moves(body, tcx, param_env) {
Ok(move_data) => move_data,
Err(_) => bug!("No `move_errors` should be allowed in MIR borrowck"),
};
@@ -234,12 +234,11 @@
fn array_subpath(&self, path: Self::Path, index: u32, size: u32) -> Option<Self::Path> {
dataflow::move_path_children_matching(self.ctxt.move_data(), path, |e| match e {
- ProjectionElem::ConstantIndex { offset, min_length: _, from_end: false } => {
+ ProjectionElem::ConstantIndex { offset, min_length, from_end } => {
+ debug_assert!(size == *min_length, "min_length should be exact for arrays");
+ assert!(!from_end, "from_end should not be used for array element ConstantIndex");
*offset == index
}
- ProjectionElem::ConstantIndex { offset, min_length: _, from_end: true } => {
- size - offset == index
- }
_ => false,
})
}
diff --git a/src/librustc_mir/transform/erase_regions.rs b/src/librustc_mir/transform/erase_regions.rs
index 882e674..1eef3f2 100644
--- a/src/librustc_mir/transform/erase_regions.rs
+++ b/src/librustc_mir/transform/erase_regions.rs
@@ -62,7 +62,7 @@
pub struct EraseRegions;
impl<'tcx> MirPass<'tcx> for EraseRegions {
- fn run_pass(&self, tcx: TyCtxt<'tcx>, _: MirSource<'tcx>, body: &mut BodyCache<'tcx>) {
+ fn run_pass(&self, tcx: TyCtxt<'tcx>, _: MirSource<'tcx>, body: &mut BodyAndCache<'tcx>) {
EraseRegionsVisitor::new(tcx).visit_body(body);
}
}
diff --git a/src/librustc_mir/transform/generator.rs b/src/librustc_mir/transform/generator.rs
index e55737e..3d15d04 100644
--- a/src/librustc_mir/transform/generator.rs
+++ b/src/librustc_mir/transform/generator.rs
@@ -378,7 +378,7 @@
fn make_generator_state_argument_indirect<'tcx>(
tcx: TyCtxt<'tcx>,
def_id: DefId,
- body: &mut BodyCache<'tcx>,
+ body: &mut BodyAndCache<'tcx>,
) {
let gen_ty = body.local_decls.raw[1].ty;
@@ -401,7 +401,7 @@
DerefArgVisitor { tcx }.visit_body(body);
}
-fn make_generator_state_argument_pinned<'tcx>(tcx: TyCtxt<'tcx>, body: &mut BodyCache<'tcx>) {
+fn make_generator_state_argument_pinned<'tcx>(tcx: TyCtxt<'tcx>, body: &mut BodyAndCache<'tcx>) {
let ref_gen_ty = body.local_decls.raw[1].ty;
let pin_did = tcx.lang_items().pin_type().unwrap();
@@ -418,7 +418,7 @@
fn replace_result_variable<'tcx>(
ret_ty: Ty<'tcx>,
- body: &mut BodyCache<'tcx>,
+ body: &mut BodyAndCache<'tcx>,
tcx: TyCtxt<'tcx>,
) -> Local {
let source_info = source_info(body);
@@ -481,7 +481,7 @@
fn locals_live_across_suspend_points(
tcx: TyCtxt<'tcx>,
- body: ReadOnlyBodyCache<'_, 'tcx>,
+ body: ReadOnlyBodyAndCache<'_, 'tcx>,
source: MirSource<'tcx>,
movable: bool,
) -> LivenessInfo {
@@ -751,7 +751,7 @@
upvars: &Vec<Ty<'tcx>>,
interior: Ty<'tcx>,
movable: bool,
- body: &mut BodyCache<'tcx>,
+ body: &mut BodyAndCache<'tcx>,
) -> (
FxHashMap<Local, (Ty<'tcx>, VariantIdx, usize)>,
GeneratorLayout<'tcx>,
@@ -830,7 +830,7 @@
}
fn insert_switch<'tcx>(
- body: &mut BodyCache<'tcx>,
+ body: &mut BodyAndCache<'tcx>,
cases: Vec<(usize, BasicBlock)>,
transform: &TransformVisitor<'tcx>,
default: TerminatorKind<'tcx>,
@@ -862,7 +862,7 @@
}
fn elaborate_generator_drops<'tcx>(
- tcx: TyCtxt<'tcx>, def_id: DefId, body: &mut BodyCache<'tcx>
+ tcx: TyCtxt<'tcx>, def_id: DefId, body: &mut BodyAndCache<'tcx>
) {
use crate::util::elaborate_drops::{elaborate_drop, Unwind};
use crate::util::patch::MirPatch;
@@ -928,9 +928,9 @@
def_id: DefId,
source: MirSource<'tcx>,
gen_ty: Ty<'tcx>,
- body: &mut BodyCache<'tcx>,
+ body: &mut BodyAndCache<'tcx>,
drop_clean: BasicBlock,
-) -> BodyCache<'tcx> {
+) -> BodyAndCache<'tcx> {
let mut body = body.clone();
let source_info = source_info(&body);
@@ -997,7 +997,7 @@
}
fn insert_term_block<'tcx>(
- body: &mut BodyCache<'tcx>, kind: TerminatorKind<'tcx>
+ body: &mut BodyAndCache<'tcx>, kind: TerminatorKind<'tcx>
) -> BasicBlock {
let term_block = BasicBlock::new(body.basic_blocks().len());
let source_info = source_info(body);
@@ -1014,7 +1014,7 @@
fn insert_panic_block<'tcx>(
tcx: TyCtxt<'tcx>,
- body: &mut BodyCache<'tcx>,
+ body: &mut BodyAndCache<'tcx>,
message: AssertMessage<'tcx>,
) -> BasicBlock {
let assert_block = BasicBlock::new(body.basic_blocks().len());
@@ -1048,7 +1048,7 @@
transform: TransformVisitor<'tcx>,
def_id: DefId,
source: MirSource<'tcx>,
- body: &mut BodyCache<'tcx>,
+ body: &mut BodyAndCache<'tcx>,
) {
// Poison the generator when it unwinds
for block in body.basic_blocks_mut() {
@@ -1101,7 +1101,7 @@
}
}
-fn insert_clean_drop(body: &mut BodyCache<'_>) -> BasicBlock {
+fn insert_clean_drop(body: &mut BodyAndCache<'_>) -> BasicBlock {
let return_block = insert_term_block(body, TerminatorKind::Return);
// Create a block to destroy an unresumed generators. This can only destroy upvars.
@@ -1125,7 +1125,7 @@
}
fn create_cases<'tcx, F>(
- body: &mut BodyCache<'tcx>,
+ body: &mut BodyAndCache<'tcx>,
transform: &TransformVisitor<'tcx>,
target: F,
) -> Vec<(usize, BasicBlock)>
@@ -1170,7 +1170,7 @@
impl<'tcx> MirPass<'tcx> for StateTransform {
fn run_pass(
- &self, tcx: TyCtxt<'tcx>, source: MirSource<'tcx>, body: &mut BodyCache<'tcx>
+ &self, tcx: TyCtxt<'tcx>, source: MirSource<'tcx>, body: &mut BodyAndCache<'tcx>
) {
let yield_ty = if let Some(yield_ty) = body.yield_ty {
yield_ty
diff --git a/src/librustc_mir/transform/inline.rs b/src/librustc_mir/transform/inline.rs
index 79cb7fb..9763913 100644
--- a/src/librustc_mir/transform/inline.rs
+++ b/src/librustc_mir/transform/inline.rs
@@ -39,7 +39,7 @@
impl<'tcx> MirPass<'tcx> for Inline {
fn run_pass(
- &self, tcx: TyCtxt<'tcx>, source: MirSource<'tcx>, body: &mut BodyCache<'tcx>
+ &self, tcx: TyCtxt<'tcx>, source: MirSource<'tcx>, body: &mut BodyAndCache<'tcx>
) {
if tcx.sess.opts.debugging_opts.mir_opt_level >= 2 {
Inliner { tcx, source }.run_pass(body);
@@ -53,7 +53,7 @@
}
impl Inliner<'tcx> {
- fn run_pass(&self, caller_body: &mut BodyCache<'tcx>) {
+ fn run_pass(&self, caller_body: &mut BodyAndCache<'tcx>) {
// Keep a queue of callsites to try inlining on. We take
// advantage of the fact that queries detect cycles here to
// allow us to try and fetch the fully optimized MIR of a
@@ -230,6 +230,11 @@
let codegen_fn_attrs = tcx.codegen_fn_attrs(callsite.callee);
+ if codegen_fn_attrs.flags.contains(CodegenFnAttrFlags::TRACK_CALLER) {
+ debug!("`#[track_caller]` present - not inlining");
+ return false;
+ }
+
let hinted = match codegen_fn_attrs.inline {
// Just treat inline(always) as a hint for now,
// there are cases that prevent inlining that we
@@ -380,8 +385,8 @@
fn inline_call(&self,
callsite: CallSite<'tcx>,
- caller_body: &mut BodyCache<'tcx>,
- mut callee_body: BodyCache<'tcx>) -> bool {
+ caller_body: &mut BodyAndCache<'tcx>,
+ mut callee_body: BodyAndCache<'tcx>) -> bool {
let terminator = caller_body[callsite.bb].terminator.take().unwrap();
match terminator.kind {
// FIXME: Handle inlining of diverging calls
@@ -517,7 +522,7 @@
&self,
args: Vec<Operand<'tcx>>,
callsite: &CallSite<'tcx>,
- caller_body: &mut BodyCache<'tcx>,
+ caller_body: &mut BodyAndCache<'tcx>,
) -> Vec<Local> {
let tcx = self.tcx;
@@ -590,7 +595,7 @@
&self,
arg: Operand<'tcx>,
callsite: &CallSite<'tcx>,
- caller_body: &mut BodyCache<'tcx>,
+ caller_body: &mut BodyAndCache<'tcx>,
) -> Local {
// FIXME: Analysis of the usage of the arguments to avoid
// unnecessary temporaries.
diff --git a/src/librustc_mir/transform/instcombine.rs b/src/librustc_mir/transform/instcombine.rs
index bd237b5..eca1b59 100644
--- a/src/librustc_mir/transform/instcombine.rs
+++ b/src/librustc_mir/transform/instcombine.rs
@@ -1,7 +1,7 @@
//! Performs various peephole optimizations.
use rustc::mir::{
- Constant, Location, Place, PlaceBase, PlaceRef, Body, BodyCache, Operand, ProjectionElem,
+ Constant, Location, Place, PlaceBase, PlaceRef, Body, BodyAndCache, Operand, ProjectionElem,
Rvalue, Local, read_only
};
use rustc::mir::visit::{MutVisitor, Visitor};
@@ -14,7 +14,7 @@
pub struct InstCombine;
impl<'tcx> MirPass<'tcx> for InstCombine {
- fn run_pass(&self, tcx: TyCtxt<'tcx>, _: MirSource<'tcx>, body: &mut BodyCache<'tcx>) {
+ fn run_pass(&self, tcx: TyCtxt<'tcx>, _: MirSource<'tcx>, body: &mut BodyAndCache<'tcx>) {
// We only run when optimizing MIR (at any level).
if tcx.sess.opts.debugging_opts.mir_opt_level == 0 {
return
diff --git a/src/librustc_mir/transform/mod.rs b/src/librustc_mir/transform/mod.rs
index df4cb76..2e1a08a 100644
--- a/src/librustc_mir/transform/mod.rs
+++ b/src/librustc_mir/transform/mod.rs
@@ -1,7 +1,7 @@
use crate::{build, shim};
use rustc_index::vec::IndexVec;
use rustc::hir::def_id::{CrateNum, DefId, LOCAL_CRATE};
-use rustc::mir::{BodyCache, MirPhase, Promoted, ConstQualifs};
+use rustc::mir::{BodyAndCache, MirPhase, Promoted, ConstQualifs};
use rustc::ty::{TyCtxt, InstanceDef, TypeFoldable};
use rustc::ty::query::Providers;
use rustc::ty::steal::Steal;
@@ -35,7 +35,6 @@
pub mod const_prop;
pub mod generator;
pub mod inline;
-pub mod uniform_array_move_out;
pub mod uninhabited_enum_branching;
pub(crate) fn provide(providers: &mut Providers<'_>) {
@@ -97,7 +96,7 @@
tcx.arena.alloc(set)
}
-fn mir_built(tcx: TyCtxt<'_>, def_id: DefId) -> &Steal<BodyCache<'_>> {
+fn mir_built(tcx: TyCtxt<'_>, def_id: DefId) -> &Steal<BodyAndCache<'_>> {
let mir = build::mir_build(tcx, def_id);
tcx.alloc_steal_mir(mir)
}
@@ -144,12 +143,12 @@
default_name::<Self>()
}
- fn run_pass(&self, tcx: TyCtxt<'tcx>, source: MirSource<'tcx>, body: &mut BodyCache<'tcx>);
+ fn run_pass(&self, tcx: TyCtxt<'tcx>, source: MirSource<'tcx>, body: &mut BodyAndCache<'tcx>);
}
pub fn run_passes(
tcx: TyCtxt<'tcx>,
- body: &mut BodyCache<'tcx>,
+ body: &mut BodyAndCache<'tcx>,
instance: InstanceDef<'tcx>,
promoted: Option<Promoted>,
mir_phase: MirPhase,
@@ -220,7 +219,7 @@
validator.qualifs_in_return_place().into()
}
-fn mir_const(tcx: TyCtxt<'_>, def_id: DefId) -> &Steal<BodyCache<'_>> {
+fn mir_const(tcx: TyCtxt<'_>, def_id: DefId) -> &Steal<BodyAndCache<'_>> {
// Unsafety check uses the raw mir, so make sure it is run
let _ = tcx.unsafety_check_result(def_id);
@@ -229,7 +228,6 @@
// What we need to do constant evaluation.
&simplify::SimplifyCfg::new("initial"),
&rustc_peek::SanityCheck,
- &uniform_array_move_out::UniformArrayMoveOut,
]);
body.ensure_predecessors();
tcx.alloc_steal_mir(body)
@@ -238,7 +236,7 @@
fn mir_validated(
tcx: TyCtxt<'tcx>,
def_id: DefId,
-) -> (&'tcx Steal<BodyCache<'tcx>>, &'tcx Steal<IndexVec<Promoted, BodyCache<'tcx>>>) {
+) -> (&'tcx Steal<BodyAndCache<'tcx>>, &'tcx Steal<IndexVec<Promoted, BodyAndCache<'tcx>>>) {
// Ensure that we compute the `mir_const_qualif` for constants at
// this point, before we steal the mir-const result.
let _ = tcx.mir_const_qualif(def_id);
@@ -257,7 +255,7 @@
fn run_optimization_passes<'tcx>(
tcx: TyCtxt<'tcx>,
- body: &mut BodyCache<'tcx>,
+ body: &mut BodyAndCache<'tcx>,
def_id: DefId,
promoted: Option<Promoted>,
) {
@@ -294,7 +292,6 @@
// Optimizations begin.
&uninhabited_enum_branching::UninhabitedEnumBranching,
&simplify::SimplifyCfg::new("after-uninhabited-enum-branching"),
- &uniform_array_move_out::RestoreSubsliceArrayMoveOut::new(tcx),
&inline::Inline,
// Lowering generator control-flow and variables
@@ -319,7 +316,7 @@
]);
}
-fn optimized_mir(tcx: TyCtxt<'_>, def_id: DefId) -> &BodyCache<'_> {
+fn optimized_mir(tcx: TyCtxt<'_>, def_id: DefId) -> &BodyAndCache<'_> {
if tcx.is_constructor(def_id) {
// There's no reason to run all of the MIR passes on constructors when
// we can just output the MIR we want directly. This also saves const
@@ -339,7 +336,7 @@
tcx.arena.alloc(body)
}
-fn promoted_mir(tcx: TyCtxt<'_>, def_id: DefId) -> &IndexVec<Promoted, BodyCache<'_>> {
+fn promoted_mir(tcx: TyCtxt<'_>, def_id: DefId) -> &IndexVec<Promoted, BodyAndCache<'_>> {
if tcx.is_constructor(def_id) {
return tcx.intern_promoted(IndexVec::new());
}
diff --git a/src/librustc_mir/transform/no_landing_pads.rs b/src/librustc_mir/transform/no_landing_pads.rs
index 5e1d29d..d4fe72f 100644
--- a/src/librustc_mir/transform/no_landing_pads.rs
+++ b/src/librustc_mir/transform/no_landing_pads.rs
@@ -17,12 +17,12 @@
}
impl<'tcx> MirPass<'tcx> for NoLandingPads<'tcx> {
- fn run_pass(&self, tcx: TyCtxt<'tcx>, _: MirSource<'tcx>, body: &mut BodyCache<'tcx>) {
+ fn run_pass(&self, tcx: TyCtxt<'tcx>, _: MirSource<'tcx>, body: &mut BodyAndCache<'tcx>) {
no_landing_pads(tcx, body)
}
}
-pub fn no_landing_pads<'tcx>(tcx: TyCtxt<'tcx>, body: &mut BodyCache<'tcx>) {
+pub fn no_landing_pads<'tcx>(tcx: TyCtxt<'tcx>, body: &mut BodyAndCache<'tcx>) {
if tcx.sess.no_landing_pads() {
NoLandingPads::new(tcx).visit_body(body);
}
diff --git a/src/librustc_mir/transform/promote_consts.rs b/src/librustc_mir/transform/promote_consts.rs
index c758ccf..4c72319 100644
--- a/src/librustc_mir/transform/promote_consts.rs
+++ b/src/librustc_mir/transform/promote_consts.rs
@@ -41,11 +41,11 @@
/// newly created `StaticKind::Promoted`.
#[derive(Default)]
pub struct PromoteTemps<'tcx> {
- pub promoted_fragments: Cell<IndexVec<Promoted, BodyCache<'tcx>>>,
+ pub promoted_fragments: Cell<IndexVec<Promoted, BodyAndCache<'tcx>>>,
}
impl<'tcx> MirPass<'tcx> for PromoteTemps<'tcx> {
- fn run_pass(&self, tcx: TyCtxt<'tcx>, src: MirSource<'tcx>, body: &mut BodyCache<'tcx>) {
+ fn run_pass(&self, tcx: TyCtxt<'tcx>, src: MirSource<'tcx>, body: &mut BodyAndCache<'tcx>) {
// There's not really any point in promoting errorful MIR.
//
// This does not include MIR that failed const-checking, which we still try to promote.
@@ -742,7 +742,7 @@
// FIXME(eddyb) remove the differences for promotability in `static`, `const`, `const fn`.
pub fn validate_candidates(
tcx: TyCtxt<'tcx>,
- body: ReadOnlyBodyCache<'_, 'tcx>,
+ body: ReadOnlyBodyAndCache<'_, 'tcx>,
def_id: DefId,
temps: &IndexVec<Local, TempState>,
candidates: &[Candidate],
@@ -775,8 +775,8 @@
struct Promoter<'a, 'tcx> {
tcx: TyCtxt<'tcx>,
- source: &'a mut BodyCache<'tcx>,
- promoted: BodyCache<'tcx>,
+ source: &'a mut BodyAndCache<'tcx>,
+ promoted: BodyAndCache<'tcx>,
temps: &'a mut IndexVec<Local, TempState>,
/// If true, all nested temps are also kept in the
@@ -924,7 +924,7 @@
def_id: DefId,
candidate: Candidate,
next_promoted_id: usize,
- ) -> Option<BodyCache<'tcx>> {
+ ) -> Option<BodyAndCache<'tcx>> {
let mut operand = {
let promoted = &mut self.promoted;
let promoted_id = Promoted::new(next_promoted_id);
@@ -1045,11 +1045,11 @@
pub fn promote_candidates<'tcx>(
def_id: DefId,
- body: &mut BodyCache<'tcx>,
+ body: &mut BodyAndCache<'tcx>,
tcx: TyCtxt<'tcx>,
mut temps: IndexVec<Local, TempState>,
candidates: Vec<Candidate>,
-) -> IndexVec<Promoted, BodyCache<'tcx>> {
+) -> IndexVec<Promoted, BodyAndCache<'tcx>> {
// Visit candidates in reverse, in case they're nested.
debug!("promote_candidates({:?})", candidates);
@@ -1081,7 +1081,7 @@
).collect();
let promoter = Promoter {
- promoted: BodyCache::new(Body::new(
+ promoted: BodyAndCache::new(Body::new(
IndexVec::new(),
// FIXME: maybe try to filter this to avoid blowing up
// memory usage?
@@ -1150,7 +1150,7 @@
crate fn should_suggest_const_in_array_repeat_expressions_attribute<'tcx>(
tcx: TyCtxt<'tcx>,
mir_def_id: DefId,
- body: ReadOnlyBodyCache<'_, 'tcx>,
+ body: ReadOnlyBodyAndCache<'_, 'tcx>,
operand: &Operand<'tcx>,
) -> bool {
let mut rpo = traversal::reverse_postorder(&body);
diff --git a/src/librustc_mir/transform/qualify_min_const_fn.rs b/src/librustc_mir/transform/qualify_min_const_fn.rs
index 3030d2e..1c95155 100644
--- a/src/librustc_mir/transform/qualify_min_const_fn.rs
+++ b/src/librustc_mir/transform/qualify_min_const_fn.rs
@@ -79,10 +79,14 @@
fn check_ty(tcx: TyCtxt<'tcx>, ty: Ty<'tcx>, span: Span, fn_def_id: DefId) -> McfResult {
for ty in ty.walk() {
match ty.kind {
- ty::Ref(_, _, hir::Mutability::Mutable) => return Err((
- span,
- "mutable references in const fn are unstable".into(),
- )),
+ ty::Ref(_, _, hir::Mutability::Mutable) => {
+ if !feature_allowed(tcx, fn_def_id, sym::const_mut_refs) {
+ return Err((
+ span,
+ "mutable references in const fn are unstable".into(),
+ ))
+ }
+ }
ty::Opaque(..) => return Err((span, "`impl Trait` in const fn is unstable".into())),
ty::FnPtr(..) => {
if !tcx.const_fn_is_allowed_fn_ptr(fn_def_id) {
@@ -216,7 +220,7 @@
}
| StatementKind::FakeRead(FakeReadCause::ForMatchedPlace, _)
- if !tcx.features().const_if_match
+ if !feature_allowed(tcx, def_id, sym::const_if_match)
=> {
Err((span, "loops and conditional expressions are not stable in const fn".into()))
}
@@ -268,7 +272,7 @@
while let &[ref proj_base @ .., elem] = cursor {
cursor = proj_base;
match elem {
- ProjectionElem::Downcast(..) if !tcx.features().const_if_match
+ ProjectionElem::Downcast(..) if !feature_allowed(tcx, def_id, sym::const_if_match)
=> return Err((span, "`match` or `if let` in `const fn` is unstable".into())),
ProjectionElem::Downcast(_symbol, _variant_index) => {}
@@ -325,7 +329,7 @@
| TerminatorKind::FalseEdges { .. }
| TerminatorKind::SwitchInt { .. }
- if !tcx.features().const_if_match
+ if !feature_allowed(tcx, def_id, sym::const_if_match)
=> Err((
span,
"loops and conditional expressions are not stable in const fn".into(),
@@ -337,7 +341,7 @@
}
// FIXME(ecstaticmorse): We probably want to allow `Unreachable` unconditionally.
- TerminatorKind::Unreachable if tcx.features().const_if_match => Ok(()),
+ TerminatorKind::Unreachable if feature_allowed(tcx, def_id, sym::const_if_match) => Ok(()),
| TerminatorKind::Abort | TerminatorKind::Unreachable => {
Err((span, "const fn with unreachable code is not stable".into()))
diff --git a/src/librustc_mir/transform/remove_noop_landing_pads.rs b/src/librustc_mir/transform/remove_noop_landing_pads.rs
index c636aba..5799d0c 100644
--- a/src/librustc_mir/transform/remove_noop_landing_pads.rs
+++ b/src/librustc_mir/transform/remove_noop_landing_pads.rs
@@ -9,7 +9,7 @@
/// code for these.
pub struct RemoveNoopLandingPads;
-pub fn remove_noop_landing_pads<'tcx>(tcx: TyCtxt<'tcx>, body: &mut BodyCache<'tcx>) {
+pub fn remove_noop_landing_pads<'tcx>(tcx: TyCtxt<'tcx>, body: &mut BodyAndCache<'tcx>) {
if tcx.sess.no_landing_pads() {
return
}
@@ -19,7 +19,7 @@
}
impl<'tcx> MirPass<'tcx> for RemoveNoopLandingPads {
- fn run_pass(&self, tcx: TyCtxt<'tcx>, _src: MirSource<'tcx>, body: &mut BodyCache<'tcx>) {
+ fn run_pass(&self, tcx: TyCtxt<'tcx>, _src: MirSource<'tcx>, body: &mut BodyAndCache<'tcx>) {
remove_noop_landing_pads(tcx, body);
}
}
@@ -84,7 +84,7 @@
}
}
- fn remove_nop_landing_pads(&self, body: &mut BodyCache<'_>) {
+ fn remove_nop_landing_pads(&self, body: &mut BodyAndCache<'_>) {
// make sure there's a single resume block
let resume_block = {
let patch = MirPatch::new(body);
diff --git a/src/librustc_mir/transform/rustc_peek.rs b/src/librustc_mir/transform/rustc_peek.rs
index 794ced1..4345fc6 100644
--- a/src/librustc_mir/transform/rustc_peek.rs
+++ b/src/librustc_mir/transform/rustc_peek.rs
@@ -5,7 +5,7 @@
use rustc::ty::{self, TyCtxt, Ty};
use rustc::hir::def_id::DefId;
-use rustc::mir::{self, Body, BodyCache, Location, Local};
+use rustc::mir::{self, Body, BodyAndCache, Location, Local};
use rustc_index::bit_set::BitSet;
use crate::transform::{MirPass, MirSource};
@@ -26,7 +26,7 @@
pub struct SanityCheck;
impl<'tcx> MirPass<'tcx> for SanityCheck {
- fn run_pass(&self, tcx: TyCtxt<'tcx>, src: MirSource<'tcx>, body: &mut BodyCache<'tcx>) {
+ fn run_pass(&self, tcx: TyCtxt<'tcx>, src: MirSource<'tcx>, body: &mut BodyAndCache<'tcx>) {
let def_id = src.def_id();
if !tcx.has_attr(def_id, sym::rustc_mir) {
debug!("skipping rustc_peek::SanityCheck on {}", tcx.def_path_str(def_id));
@@ -37,7 +37,7 @@
let attributes = tcx.get_attrs(def_id);
let param_env = tcx.param_env(def_id);
- let move_data = MoveData::gather_moves(body, tcx).unwrap();
+ let move_data = MoveData::gather_moves(body, tcx, param_env).unwrap();
let mdpe = MoveDataParamEnv { move_data: move_data, param_env: param_env };
let dead_unwinds = BitSet::new_empty(body.basic_blocks().len());
let flow_inits =
diff --git a/src/librustc_mir/transform/simplify.rs b/src/librustc_mir/transform/simplify.rs
index 900752d..628ac72 100644
--- a/src/librustc_mir/transform/simplify.rs
+++ b/src/librustc_mir/transform/simplify.rs
@@ -29,7 +29,7 @@
use rustc_index::bit_set::BitSet;
use rustc_index::vec::{Idx, IndexVec};
-use rustc::ty::TyCtxt;
+use rustc::ty::{self, TyCtxt};
use rustc::mir::*;
use rustc::mir::visit::{MutVisitor, Visitor, PlaceContext, MutatingUseContext};
use std::borrow::Cow;
@@ -43,7 +43,7 @@
}
}
-pub fn simplify_cfg(body: &mut BodyCache<'_>) {
+pub fn simplify_cfg(body: &mut BodyAndCache<'_>) {
CfgSimplifier::new(body).simplify();
remove_dead_blocks(body);
@@ -57,7 +57,7 @@
}
fn run_pass(
- &self, _tcx: TyCtxt<'tcx>, _src: MirSource<'tcx>, body: &mut BodyCache<'tcx>
+ &self, _tcx: TyCtxt<'tcx>, _src: MirSource<'tcx>, body: &mut BodyAndCache<'tcx>
) {
debug!("SimplifyCfg({:?}) - simplifying {:?}", self.label, body);
simplify_cfg(body);
@@ -70,7 +70,7 @@
}
impl<'a, 'tcx> CfgSimplifier<'a, 'tcx> {
- pub fn new(body: &'a mut BodyCache<'tcx>) -> Self {
+ pub fn new(body: &'a mut BodyAndCache<'tcx>) -> Self {
let mut pred_count = IndexVec::from_elem(0u32, body.basic_blocks());
// we can't use mir.predecessors() here because that counts
@@ -262,7 +262,7 @@
}
}
-pub fn remove_dead_blocks(body: &mut BodyCache<'_>) {
+pub fn remove_dead_blocks(body: &mut BodyAndCache<'_>) {
let mut seen = BitSet::new_empty(body.basic_blocks().len());
for (bb, _) in traversal::preorder(body) {
seen.insert(bb.index());
@@ -296,7 +296,7 @@
impl<'tcx> MirPass<'tcx> for SimplifyLocals {
fn run_pass(
- &self, tcx: TyCtxt<'tcx>, source: MirSource<'tcx>, body: &mut BodyCache<'tcx>
+ &self, tcx: TyCtxt<'tcx>, source: MirSource<'tcx>, body: &mut BodyAndCache<'tcx>
) {
trace!("running SimplifyLocals on {:?}", source);
let locals = {
@@ -367,9 +367,14 @@
if let StatementKind::Assign(
box (p, Rvalue::Use(Operand::Constant(c)))
) = &stmt.kind {
- if !p.is_indirect() {
- trace!("skipping store of const value {:?} to {:?}", c, p);
- return;
+ match c.literal.val {
+ // Keep assignments from unevaluated constants around, since the evaluation
+ // may report errors, even if the use of the constant is dead code.
+ ty::ConstKind::Unevaluated(..) => {}
+ _ => if !p.is_indirect() {
+ trace!("skipping store of const value {:?} to {:?}", c, p);
+ return;
+ },
}
}
}
diff --git a/src/librustc_mir/transform/simplify_branches.rs b/src/librustc_mir/transform/simplify_branches.rs
index c8d0f37..aa3c5b0 100644
--- a/src/librustc_mir/transform/simplify_branches.rs
+++ b/src/librustc_mir/transform/simplify_branches.rs
@@ -19,7 +19,7 @@
Cow::Borrowed(&self.label)
}
- fn run_pass(&self, tcx: TyCtxt<'tcx>, src: MirSource<'tcx>, body: &mut BodyCache<'tcx>) {
+ fn run_pass(&self, tcx: TyCtxt<'tcx>, src: MirSource<'tcx>, body: &mut BodyAndCache<'tcx>) {
let param_env = tcx.param_env(src.def_id());
for block in body.basic_blocks_mut() {
let terminator = block.terminator_mut();
diff --git a/src/librustc_mir/transform/simplify_try.rs b/src/librustc_mir/transform/simplify_try.rs
index 2235de9..752e852 100644
--- a/src/librustc_mir/transform/simplify_try.rs
+++ b/src/librustc_mir/transform/simplify_try.rs
@@ -33,7 +33,7 @@
pub struct SimplifyArmIdentity;
impl<'tcx> MirPass<'tcx> for SimplifyArmIdentity {
- fn run_pass(&self, _: TyCtxt<'tcx>, _: MirSource<'tcx>, body: &mut BodyCache<'tcx>) {
+ fn run_pass(&self, _: TyCtxt<'tcx>, _: MirSource<'tcx>, body: &mut BodyAndCache<'tcx>) {
let (basic_blocks, local_decls) = body.basic_blocks_and_local_decls_mut();
for bb in basic_blocks {
// Need 3 statements:
@@ -151,7 +151,7 @@
pub struct SimplifyBranchSame;
impl<'tcx> MirPass<'tcx> for SimplifyBranchSame {
- fn run_pass(&self, _: TyCtxt<'tcx>, _: MirSource<'tcx>, body: &mut BodyCache<'tcx>) {
+ fn run_pass(&self, _: TyCtxt<'tcx>, _: MirSource<'tcx>, body: &mut BodyAndCache<'tcx>) {
let mut did_remove_blocks = false;
let bbs = body.basic_blocks_mut();
for bb_idx in bbs.indices() {
diff --git a/src/librustc_mir/transform/uniform_array_move_out.rs b/src/librustc_mir/transform/uniform_array_move_out.rs
deleted file mode 100644
index 3fc76ef..0000000
--- a/src/librustc_mir/transform/uniform_array_move_out.rs
+++ /dev/null
@@ -1,381 +0,0 @@
-// This pass converts move out from array by Subslice and
-// ConstIndex{.., from_end: true} to ConstIndex move out(s) from begin
-// of array. It allows detect error by mir borrowck and elaborate
-// drops for array without additional work.
-//
-// Example:
-//
-// let a = [ box 1,box 2, box 3];
-// if b {
-// let [_a.., _] = a;
-// } else {
-// let [.., _b] = a;
-// }
-//
-// mir statement _10 = move _2[:-1]; replaced by:
-// StorageLive(_12);
-// _12 = move _2[0 of 3];
-// StorageLive(_13);
-// _13 = move _2[1 of 3];
-// _10 = [move _12, move _13]
-// StorageDead(_12);
-// StorageDead(_13);
-//
-// and mir statement _11 = move _2[-1 of 1]; replaced by:
-// _11 = move _2[2 of 3];
-//
-// FIXME: integrate this transformation to the mir build
-
-use rustc::ty;
-use rustc::ty::TyCtxt;
-use rustc::mir::*;
-use rustc::mir::visit::{Visitor, PlaceContext, NonUseContext};
-use rustc_index::vec::{IndexVec};
-use crate::transform::{MirPass, MirSource};
-use crate::util::patch::MirPatch;
-
-pub struct UniformArrayMoveOut;
-
-impl<'tcx> MirPass<'tcx> for UniformArrayMoveOut {
- fn run_pass(&self, tcx: TyCtxt<'tcx>, src: MirSource<'tcx>, body: &mut BodyCache<'tcx>) {
- let mut patch = MirPatch::new(body);
- let param_env = tcx.param_env(src.def_id());
- {
- let read_only_cache = read_only!(body);
- let mut visitor
- = UniformArrayMoveOutVisitor{ body, patch: &mut patch, tcx, param_env};
- visitor.visit_body(read_only_cache);
- }
- patch.apply(body);
- }
-}
-
-struct UniformArrayMoveOutVisitor<'a, 'tcx> {
- body: &'a Body<'tcx>,
- patch: &'a mut MirPatch<'tcx>,
- tcx: TyCtxt<'tcx>,
- param_env: ty::ParamEnv<'tcx>,
-}
-
-impl<'a, 'tcx> Visitor<'tcx> for UniformArrayMoveOutVisitor<'a, 'tcx> {
- fn visit_assign(&mut self,
- dst_place: &Place<'tcx>,
- rvalue: &Rvalue<'tcx>,
- location: Location) {
- if let Rvalue::Use(Operand::Move(ref src_place)) = rvalue {
- if let &[ref proj_base @ .., elem] = src_place.projection.as_ref() {
- if let ProjectionElem::ConstantIndex{offset: _,
- min_length: _,
- from_end: false} = elem {
- // no need to transformation
- } else {
- let place_ty =
- Place::ty_from(&src_place.base, proj_base, self.body, self.tcx).ty;
- if let ty::Array(item_ty, const_size) = place_ty.kind {
- if let Some(size) = const_size.try_eval_usize(self.tcx, self.param_env) {
- assert!(size <= u32::max_value() as u64,
- "uniform array move out doesn't supported
- for array bigger then u32");
- self.uniform(
- location,
- dst_place,
- &src_place.base,
- &src_place.projection,
- item_ty,
- size as u32,
- );
- }
- }
-
- }
- }
- }
- self.super_assign(dst_place, rvalue, location)
- }
-}
-
-impl<'a, 'tcx> UniformArrayMoveOutVisitor<'a, 'tcx> {
- fn uniform(&mut self,
- location: Location,
- dst_place: &Place<'tcx>,
- base: &PlaceBase<'tcx>,
- proj: &[PlaceElem<'tcx>],
- item_ty: &'tcx ty::TyS<'tcx>,
- size: u32) {
- if let [proj_base @ .., elem] = proj {
- match elem {
- // uniforms statements like_10 = move _2[:-1];
- ProjectionElem::Subslice{from, to} => {
- self.patch.make_nop(location);
- let temps : Vec<_> = (*from..(size-*to)).map(|i| {
- let temp =
- self.patch.new_temp(item_ty, self.body.source_info(location).span);
- self.patch.add_statement(location, StatementKind::StorageLive(temp));
-
- let mut projection = proj_base.to_vec();
- projection.push(ProjectionElem::ConstantIndex {
- offset: i,
- min_length: size,
- from_end: false,
- });
- self.patch.add_assign(
- location,
- Place::from(temp),
- Rvalue::Use(Operand::Move(Place {
- base: base.clone(),
- projection: self.tcx.intern_place_elems(&projection),
- })),
- );
- temp
- }).collect();
- self.patch.add_assign(
- location,
- dst_place.clone(),
- Rvalue::Aggregate(
- box AggregateKind::Array(item_ty),
- temps.iter().map(
- |x| Operand::Move(Place::from(*x))
- ).collect()
- )
- );
- for temp in temps {
- self.patch.add_statement(location, StatementKind::StorageDead(temp));
- }
- }
- // uniforms statements like _11 = move _2[-1 of 1];
- ProjectionElem::ConstantIndex{offset, min_length: _, from_end: true} => {
- self.patch.make_nop(location);
-
- let mut projection = proj_base.to_vec();
- projection.push(ProjectionElem::ConstantIndex {
- offset: size - offset,
- min_length: size,
- from_end: false,
- });
- self.patch.add_assign(
- location,
- dst_place.clone(),
- Rvalue::Use(Operand::Move(Place {
- base: base.clone(),
- projection: self.tcx.intern_place_elems(&projection),
- })),
- );
- }
- _ => {}
- }
- }
- }
-}
-
-// Restore Subslice move out after analysis
-// Example:
-//
-// next statements:
-// StorageLive(_12);
-// _12 = move _2[0 of 3];
-// StorageLive(_13);
-// _13 = move _2[1 of 3];
-// _10 = [move _12, move _13]
-// StorageDead(_12);
-// StorageDead(_13);
-//
-// replaced by _10 = move _2[:-1];
-
-pub struct RestoreSubsliceArrayMoveOut<'tcx> {
- tcx: TyCtxt<'tcx>
-}
-
-impl<'tcx> MirPass<'tcx> for RestoreSubsliceArrayMoveOut<'tcx> {
- fn run_pass(&self, tcx: TyCtxt<'tcx>, src: MirSource<'tcx>, body: &mut BodyCache<'tcx>) {
- let mut patch = MirPatch::new(body);
- let param_env = tcx.param_env(src.def_id());
- {
- let read_only_cache = read_only!(body);
- let mut visitor = RestoreDataCollector {
- locals_use: IndexVec::from_elem(LocalUse::new(), &body.local_decls),
- candidates: vec![],
- };
- visitor.visit_body(read_only_cache);
-
- for candidate in &visitor.candidates {
- let statement = &body[candidate.block].statements[candidate.statement_index];
- if let StatementKind::Assign(box(ref dst_place, ref rval)) = statement.kind {
- if let Rvalue::Aggregate(box AggregateKind::Array(_), ref items) = *rval {
- let items : Vec<_> = items.iter().map(|item| {
- if let Operand::Move(place) = item {
- if let Some(local) = place.as_local() {
- let local_use = &visitor.locals_use[local];
- let opt_index_and_place =
- Self::try_get_item_source(local_use, body);
- // each local should be used twice:
- // in assign and in aggregate statements
- if local_use.use_count == 2 && opt_index_and_place.is_some() {
- let (index, src_place) = opt_index_and_place.unwrap();
- return Some((local_use, index, src_place));
- }
- }
- }
- None
- }).collect();
-
- let opt_src_place = items.first().and_then(|x| *x).map(|x| x.2);
- let opt_size = opt_src_place.and_then(|src_place| {
- let src_ty = Place::ty_from(
- src_place.base,
- src_place.projection,
- &**body,
- tcx
- ).ty;
- if let ty::Array(_, ref size_o) = src_ty.kind {
- size_o.try_eval_usize(tcx, param_env)
- } else {
- None
- }
- });
- let restore_subslice = RestoreSubsliceArrayMoveOut { tcx };
- restore_subslice
- .check_and_patch(*candidate, &items, opt_size, &mut patch, dst_place);
- }
- }
- }
- }
- patch.apply(body);
- }
-}
-
-impl RestoreSubsliceArrayMoveOut<'tcx> {
- pub fn new(tcx: TyCtxt<'tcx>) -> Self {
- RestoreSubsliceArrayMoveOut { tcx }
- }
-
- // Checks that source has size, all locals are inited from same source place and
- // indices is an integer interval. If all checks pass do the replacent.
- // items are Vec<Option<LocalUse, index in source array, source place for init local>>
- fn check_and_patch(&self,
- candidate: Location,
- items: &[Option<(&LocalUse, u32, PlaceRef<'_, 'tcx>)>],
- opt_size: Option<u64>,
- patch: &mut MirPatch<'tcx>,
- dst_place: &Place<'tcx>) {
- let opt_src_place = items.first().and_then(|x| *x).map(|x| x.2);
-
- if opt_size.is_some() && items.iter().all(
- |l| l.is_some() && l.unwrap().2 == opt_src_place.unwrap()) {
- let src_place = opt_src_place.unwrap();
-
- let indices: Vec<_> = items.iter().map(|x| x.unwrap().1).collect();
- for i in 1..indices.len() {
- if indices[i - 1] + 1 != indices[i] {
- return;
- }
- }
-
- let min = *indices.first().unwrap();
- let max = *indices.last().unwrap();
-
- for item in items {
- let locals_use = item.unwrap().0;
- patch.make_nop(locals_use.alive.unwrap());
- patch.make_nop(locals_use.dead.unwrap());
- patch.make_nop(locals_use.first_use.unwrap());
- }
- patch.make_nop(candidate);
- let size = opt_size.unwrap() as u32;
-
- let mut projection = src_place.projection.to_vec();
- projection.push(ProjectionElem::Subslice { from: min, to: size - max - 1 });
- patch.add_assign(
- candidate,
- dst_place.clone(),
- Rvalue::Use(Operand::Move(Place {
- base: src_place.base.clone(),
- projection: self.tcx.intern_place_elems(&projection),
- })),
- );
- }
- }
-
- fn try_get_item_source<'a>(local_use: &LocalUse,
- body: &'a Body<'tcx>) -> Option<(u32, PlaceRef<'a, 'tcx>)> {
- if let Some(location) = local_use.first_use {
- let block = &body[location.block];
- if block.statements.len() > location.statement_index {
- let statement = &block.statements[location.statement_index];
- if let StatementKind::Assign(
- box(place, Rvalue::Use(Operand::Move(src_place)))
- ) = &statement.kind {
- if let (Some(_), PlaceRef {
- base: _,
- projection: &[.., ProjectionElem::ConstantIndex {
- offset, min_length: _, from_end: false
- }],
- }) = (place.as_local(), src_place.as_ref()) {
- if let StatementKind::Assign(
- box(_, Rvalue::Use(Operand::Move(place)))
- ) = &statement.kind {
- if let PlaceRef {
- base,
- projection: &[ref proj_base @ .., _],
- } = place.as_ref() {
- return Some((offset, PlaceRef {
- base,
- projection: proj_base,
- }))
- }
- }
- }
- }
- }
- }
- None
- }
-}
-
-#[derive(Copy, Clone, Debug)]
-struct LocalUse {
- alive: Option<Location>,
- dead: Option<Location>,
- use_count: u32,
- first_use: Option<Location>,
-}
-
-impl LocalUse {
- pub fn new() -> Self {
- LocalUse{alive: None, dead: None, use_count: 0, first_use: None}
- }
-}
-
-struct RestoreDataCollector {
- locals_use: IndexVec<Local, LocalUse>,
- candidates: Vec<Location>,
-}
-
-impl<'tcx> Visitor<'tcx> for RestoreDataCollector {
- fn visit_assign(&mut self,
- place: &Place<'tcx>,
- rvalue: &Rvalue<'tcx>,
- location: Location) {
- if let Rvalue::Aggregate(box AggregateKind::Array(_), _) = *rvalue {
- self.candidates.push(location);
- }
- self.super_assign(place, rvalue, location)
- }
-
- fn visit_local(&mut self,
- local: &Local,
- context: PlaceContext,
- location: Location) {
- let local_use = &mut self.locals_use[*local];
- match context {
- PlaceContext::NonUse(NonUseContext::StorageLive) => local_use.alive = Some(location),
- PlaceContext::NonUse(NonUseContext::StorageDead) => local_use.dead = Some(location),
- PlaceContext::NonUse(NonUseContext::VarDebugInfo) => {}
- _ => {
- local_use.use_count += 1;
- if local_use.first_use.is_none() {
- local_use.first_use = Some(location);
- }
- }
- }
- }
-}
diff --git a/src/librustc_mir/transform/uninhabited_enum_branching.rs b/src/librustc_mir/transform/uninhabited_enum_branching.rs
index de070d7..0bf0ff2 100644
--- a/src/librustc_mir/transform/uninhabited_enum_branching.rs
+++ b/src/librustc_mir/transform/uninhabited_enum_branching.rs
@@ -2,7 +2,7 @@
use crate::transform::{MirPass, MirSource};
use rustc::mir::{
- BasicBlock, BasicBlockData, Body, BodyCache, Local, Operand, Rvalue, StatementKind,
+ BasicBlock, BasicBlockData, Body, BodyAndCache, Local, Operand, Rvalue, StatementKind,
TerminatorKind,
};
use rustc::ty::layout::{Abi, TyLayout, Variants};
@@ -29,7 +29,7 @@
// Only bother checking blocks which terminate by switching on a local.
if let Some(local) = get_discriminant_local(&terminator.kind) {
let stmt_before_term = (block_data.statements.len() > 0)
- .then_with(|| &block_data.statements[block_data.statements.len() - 1].kind);
+ .then(|| &block_data.statements[block_data.statements.len() - 1].kind);
if let Some(StatementKind::Assign(box (l, Rvalue::Discriminant(place)))) = stmt_before_term
{
@@ -59,14 +59,14 @@
.iter_enumerated()
.filter_map(|(idx, layout)| {
(layout.abi != Abi::Uninhabited)
- .then_with(|| ty.discriminant_for_variant(tcx, idx).unwrap().val)
+ .then(|| ty.discriminant_for_variant(tcx, idx).unwrap().val)
})
.collect(),
}
}
impl<'tcx> MirPass<'tcx> for UninhabitedEnumBranching {
- fn run_pass(&self, tcx: TyCtxt<'tcx>, source: MirSource<'tcx>, body: &mut BodyCache<'tcx>) {
+ fn run_pass(&self, tcx: TyCtxt<'tcx>, source: MirSource<'tcx>, body: &mut BodyAndCache<'tcx>) {
if source.promoted.is_some() {
return;
}
diff --git a/src/librustc_mir/util/collect_writes.rs b/src/librustc_mir/util/collect_writes.rs
index f94bea2..4006787 100644
--- a/src/librustc_mir/util/collect_writes.rs
+++ b/src/librustc_mir/util/collect_writes.rs
@@ -1,5 +1,5 @@
use rustc::mir::{Local, Location};
-use rustc::mir::ReadOnlyBodyCache;
+use rustc::mir::ReadOnlyBodyAndCache;
use rustc::mir::visit::PlaceContext;
use rustc::mir::visit::Visitor;
@@ -9,7 +9,7 @@
fn find_assignments(&self, local: Local) -> Vec<Location>;
}
-impl<'a, 'tcx> FindAssignments for ReadOnlyBodyCache<'a, 'tcx>{
+impl<'a, 'tcx> FindAssignments for ReadOnlyBodyAndCache<'a, 'tcx>{
fn find_assignments(&self, local: Local) -> Vec<Location>{
let mut visitor = FindLocalAssignmentVisitor{ needle: local, locations: vec![]};
visitor.visit_body(*self);
diff --git a/src/librustc_mir/util/def_use.rs b/src/librustc_mir/util/def_use.rs
index 1907e9b..cf98755 100644
--- a/src/librustc_mir/util/def_use.rs
+++ b/src/librustc_mir/util/def_use.rs
@@ -1,6 +1,8 @@
//! Def-use analysis.
-use rustc::mir::{Body, BodyCache, Local, Location, PlaceElem, ReadOnlyBodyCache, VarDebugInfo};
+use rustc::mir::{
+ Body, BodyAndCache, Local, Location, PlaceElem, ReadOnlyBodyAndCache, VarDebugInfo,
+};
use rustc::mir::visit::{PlaceContext, MutVisitor, Visitor};
use rustc::ty::TyCtxt;
use rustc_index::vec::IndexVec;
@@ -30,7 +32,7 @@
}
}
- pub fn analyze(&mut self, body: ReadOnlyBodyCache<'_, '_>) {
+ pub fn analyze(&mut self, body: ReadOnlyBodyAndCache<'_, '_>) {
self.clear();
let mut finder = DefUseFinder {
@@ -55,7 +57,7 @@
fn mutate_defs_and_uses(
&self,
local: Local,
- body: &mut BodyCache<'tcx>,
+ body: &mut BodyAndCache<'tcx>,
new_local: Local,
tcx: TyCtxt<'tcx>,
) {
@@ -73,7 +75,7 @@
// FIXME(pcwalton): this should update the def-use chains.
pub fn replace_all_defs_and_uses_with(&self,
local: Local,
- body: &mut BodyCache<'tcx>,
+ body: &mut BodyAndCache<'tcx>,
new_local: Local,
tcx: TyCtxt<'tcx>) {
self.mutate_defs_and_uses(local, body, new_local, tcx)
diff --git a/src/librustc_mir/util/graphviz.rs b/src/librustc_mir/util/graphviz.rs
index 3a7ec9f..a44d401 100644
--- a/src/librustc_mir/util/graphviz.rs
+++ b/src/librustc_mir/util/graphviz.rs
@@ -202,7 +202,7 @@
}
for var_debug_info in &body.var_debug_info {
- write!(w, r#"debug {} => {};<br align="left"/>"#,
+ write!(w, r#"debug {} => {};<br align="left"/>"#,
var_debug_info.name, escape(&var_debug_info.place))?;
}
diff --git a/src/librustc_mir/util/liveness.rs b/src/librustc_mir/util/liveness.rs
index 3349753..68c2e16 100644
--- a/src/librustc_mir/util/liveness.rs
+++ b/src/librustc_mir/util/liveness.rs
@@ -57,7 +57,7 @@
/// Computes which local variables are live within the given function
/// `mir`, including drops.
pub fn liveness_of_locals(
- body: ReadOnlyBodyCache<'_, '_>,
+ body: ReadOnlyBodyAndCache<'_, '_>,
) -> LivenessResult {
let num_live_vars = body.local_decls.len();
diff --git a/src/librustc_mir/util/patch.rs b/src/librustc_mir/util/patch.rs
index 47bb0b6..575b6d2 100644
--- a/src/librustc_mir/util/patch.rs
+++ b/src/librustc_mir/util/patch.rs
@@ -127,7 +127,7 @@
self.make_nop.push(loc);
}
- pub fn apply(self, body: &mut BodyCache<'tcx>) {
+ pub fn apply(self, body: &mut BodyAndCache<'tcx>) {
debug!("MirPatch: make nops at: {:?}", self.make_nop);
for loc in self.make_nop {
body.make_statement_nop(loc);
diff --git a/src/librustc_parse/Cargo.toml b/src/librustc_parse/Cargo.toml
index 95b3256..fb5cb74 100644
--- a/src/librustc_parse/Cargo.toml
+++ b/src/librustc_parse/Cargo.toml
@@ -12,12 +12,11 @@
[dependencies]
bitflags = "1.0"
log = "0.4"
-syntax_pos = { path = "../libsyntax_pos" }
-syntax = { path = "../libsyntax" }
-errors = { path = "../librustc_errors", package = "rustc_errors" }
rustc_data_structures = { path = "../librustc_data_structures" }
rustc_feature = { path = "../librustc_feature" }
rustc_lexer = { path = "../librustc_lexer" }
-rustc_target = { path = "../librustc_target" }
-smallvec = { version = "1.0", features = ["union", "may_dangle"] }
+rustc_errors = { path = "../librustc_errors" }
rustc_error_codes = { path = "../librustc_error_codes" }
+smallvec = { version = "1.0", features = ["union", "may_dangle"] }
+syntax_pos = { path = "../libsyntax_pos" }
+syntax = { path = "../libsyntax" }
diff --git a/src/librustc_parse/config.rs b/src/librustc_parse/config.rs
index 1bf6e9e..1e9203f 100644
--- a/src/librustc_parse/config.rs
+++ b/src/librustc_parse/config.rs
@@ -8,20 +8,21 @@
//!
//! [#64197]: https://github.com/rust-lang/rust/issues/64197
-use crate::validate_attr;
+use crate::{parse_in, validate_attr};
use rustc_feature::Features;
+use rustc_errors::Applicability;
use syntax::attr::HasAttrs;
use syntax::feature_gate::{feature_err, get_features};
use syntax::attr;
-use syntax::ast;
+use syntax::ast::{self, Attribute, AttrItem, MetaItem};
use syntax::edition::Edition;
use syntax::mut_visit::*;
use syntax::ptr::P;
use syntax::sess::ParseSess;
use syntax::util::map_in_place::MapInPlace;
+use syntax_pos::Span;
use syntax_pos::symbol::sym;
-use errors::Applicability;
use smallvec::SmallVec;
/// A folder that strips out items that do not belong in the current configuration.
@@ -72,10 +73,15 @@
}
}
+const CFG_ATTR_GRAMMAR_HELP: &str = "#[cfg_attr(condition, attribute, other_attribute, ...)]";
+const CFG_ATTR_NOTE_REF: &str = "for more information, visit \
+ <https://doc.rust-lang.org/reference/conditional-compilation.html\
+ #the-cfg_attr-attribute>";
+
impl<'a> StripUnconfigured<'a> {
pub fn configure<T: HasAttrs>(&mut self, mut node: T) -> Option<T> {
self.process_cfg_attrs(&mut node);
- if self.in_cfg(node.attrs()) { Some(node) } else { None }
+ self.in_cfg(node.attrs()).then_some(node)
}
/// Parse and expand all `cfg_attr` attributes into a list of attributes
@@ -97,34 +103,14 @@
/// Gives a compiler warning when the `cfg_attr` contains no attributes and
/// is in the original source file. Gives a compiler error if the syntax of
/// the attribute is incorrect.
- fn process_cfg_attr(&mut self, attr: ast::Attribute) -> Vec<ast::Attribute> {
+ fn process_cfg_attr(&mut self, attr: Attribute) -> Vec<Attribute> {
if !attr.has_name(sym::cfg_attr) {
return vec![attr];
}
- if let ast::MacArgs::Empty = attr.get_normal_item().args {
- self.sess.span_diagnostic
- .struct_span_err(
- attr.span,
- "malformed `cfg_attr` attribute input",
- ).span_suggestion(
- attr.span,
- "missing condition and attribute",
- "#[cfg_attr(condition, attribute, other_attribute, ...)]".to_owned(),
- Applicability::HasPlaceholders,
- ).note("for more information, visit \
- <https://doc.rust-lang.org/reference/conditional-compilation.html\
- #the-cfg_attr-attribute>")
- .emit();
- return vec![];
- }
- let res = crate::parse_in_attr(self.sess, &attr, |p| p.parse_cfg_attr());
- let (cfg_predicate, expanded_attrs) = match res {
- Ok(result) => result,
- Err(mut e) => {
- e.emit();
- return vec![];
- }
+ let (cfg_predicate, expanded_attrs) = match self.parse_cfg_attr(&attr) {
+ None => return vec![],
+ Some(r) => r,
};
// Lint on zero attributes in source.
@@ -135,24 +121,56 @@
// At this point we know the attribute is considered used.
attr::mark_used(&attr);
- if attr::cfg_matches(&cfg_predicate, self.sess, self.features) {
- // We call `process_cfg_attr` recursively in case there's a
- // `cfg_attr` inside of another `cfg_attr`. E.g.
- // `#[cfg_attr(false, cfg_attr(true, some_attr))]`.
- expanded_attrs.into_iter()
- .flat_map(|(item, span)| self.process_cfg_attr(attr::mk_attr_from_item(
- attr.style,
- item,
- span,
- )))
- .collect()
- } else {
- vec![]
+ if !attr::cfg_matches(&cfg_predicate, self.sess, self.features) {
+ return vec![];
}
+
+ // We call `process_cfg_attr` recursively in case there's a
+ // `cfg_attr` inside of another `cfg_attr`. E.g.
+ // `#[cfg_attr(false, cfg_attr(true, some_attr))]`.
+ expanded_attrs
+ .into_iter()
+ .flat_map(|(item, span)| {
+ let attr = attr::mk_attr_from_item(attr.style, item, span);
+ self.process_cfg_attr(attr)
+ })
+ .collect()
+ }
+
+ fn parse_cfg_attr(&self, attr: &Attribute) -> Option<(MetaItem, Vec<(AttrItem, Span)>)> {
+ match attr.get_normal_item().args {
+ ast::MacArgs::Delimited(dspan, delim, ref tts) if !tts.is_empty() => {
+ let msg = "wrong `cfg_attr` delimiters";
+ validate_attr::check_meta_bad_delim(self.sess, dspan, delim, msg);
+ match parse_in(self.sess, tts.clone(), "`cfg_attr` input", |p| p.parse_cfg_attr()) {
+ Ok(r) => return Some(r),
+ Err(mut e) => e
+ .help(&format!("the valid syntax is `{}`", CFG_ATTR_GRAMMAR_HELP))
+ .note(CFG_ATTR_NOTE_REF)
+ .emit(),
+ }
+ }
+ _ => self.error_malformed_cfg_attr_missing(attr.span),
+ }
+ None
+ }
+
+ fn error_malformed_cfg_attr_missing(&self, span: Span) {
+ self.sess
+ .span_diagnostic
+ .struct_span_err(span, "malformed `cfg_attr` attribute input")
+ .span_suggestion(
+ span,
+ "missing condition and attribute",
+ CFG_ATTR_GRAMMAR_HELP.to_string(),
+ Applicability::HasPlaceholders,
+ )
+ .note(CFG_ATTR_NOTE_REF)
+ .emit();
}
/// Determines if a node with the given attributes should be included in this configuration.
- pub fn in_cfg(&self, attrs: &[ast::Attribute]) -> bool {
+ pub fn in_cfg(&self, attrs: &[Attribute]) -> bool {
attrs.iter().all(|attr| {
if !is_cfg(attr) {
return true;
@@ -199,7 +217,7 @@
}
/// Visit attributes on expression and statements (but not attributes on items in blocks).
- fn visit_expr_attrs(&mut self, attrs: &[ast::Attribute]) {
+ fn visit_expr_attrs(&mut self, attrs: &[Attribute]) {
// flag the offending attributes
for attr in attrs.iter() {
self.maybe_emit_expr_attr_err(attr);
@@ -207,7 +225,7 @@
}
/// If attributes are not allowed on expressions, emit an error for `attr`
- pub fn maybe_emit_expr_attr_err(&self, attr: &ast::Attribute) {
+ pub fn maybe_emit_expr_attr_err(&self, attr: &Attribute) {
if !self.features.map(|features| features.stmt_expr_attributes).unwrap_or(true) {
let mut err = feature_err(self.sess,
sym::stmt_expr_attributes,
@@ -350,7 +368,7 @@
}
}
-fn is_cfg(attr: &ast::Attribute) -> bool {
+fn is_cfg(attr: &Attribute) -> bool {
attr.check_name(sym::cfg)
}
@@ -359,8 +377,8 @@
pub fn process_configure_mod(
sess: &ParseSess,
cfg_mods: bool,
- attrs: &[ast::Attribute],
-) -> (bool, Vec<ast::Attribute>) {
+ attrs: &[Attribute],
+) -> (bool, Vec<Attribute>) {
// Don't perform gated feature checking.
let mut strip_unconfigured = StripUnconfigured { sess, features: None };
let mut attrs = attrs.to_owned();
diff --git a/src/librustc_parse/lexer/mod.rs b/src/librustc_parse/lexer/mod.rs
index 5de63cb..ddcfea1 100644
--- a/src/librustc_parse/lexer/mod.rs
+++ b/src/librustc_parse/lexer/mod.rs
@@ -1,16 +1,15 @@
-use syntax::token::{self, Token, TokenKind};
-use syntax::sess::ParseSess;
-use syntax::symbol::{sym, Symbol};
-use syntax::util::comments;
-
-use errors::{FatalError, DiagnosticBuilder};
-use syntax_pos::{BytePos, Pos, Span};
+use rustc_data_structures::sync::Lrc;
+use rustc_errors::{FatalError, DiagnosticBuilder};
use rustc_lexer::Base;
use rustc_lexer::unescape;
+use syntax::token::{self, Token, TokenKind};
+use syntax::sess::ParseSess;
+use syntax::util::comments;
+use syntax_pos::symbol::{sym, Symbol};
+use syntax_pos::{BytePos, Pos, Span};
use std::char;
use std::convert::TryInto;
-use rustc_data_structures::sync::Lrc;
use log::debug;
mod tokentrees;
diff --git a/src/librustc_parse/lexer/tokentrees.rs b/src/librustc_parse/lexer/tokentrees.rs
index 1353591..5791c63 100644
--- a/src/librustc_parse/lexer/tokentrees.rs
+++ b/src/librustc_parse/lexer/tokentrees.rs
@@ -1,13 +1,11 @@
-use rustc_data_structures::fx::FxHashMap;
-use syntax_pos::Span;
-
use super::{StringReader, UnmatchedBrace};
+use rustc_data_structures::fx::FxHashMap;
+use rustc_errors::PResult;
use syntax::print::pprust::token_to_string;
use syntax::token::{self, Token};
use syntax::tokenstream::{DelimSpan, IsJoint::{self, *}, TokenStream, TokenTree, TreeAndJoint};
-
-use errors::PResult;
+use syntax_pos::Span;
impl<'a> StringReader<'a> {
crate fn into_token_trees(self) -> (PResult<'a, TokenStream>, Vec<UnmatchedBrace>) {
diff --git a/src/librustc_parse/lexer/unicode_chars.rs b/src/librustc_parse/lexer/unicode_chars.rs
index 6eb995b..edfebc7 100644
--- a/src/librustc_parse/lexer/unicode_chars.rs
+++ b/src/librustc_parse/lexer/unicode_chars.rs
@@ -2,9 +2,9 @@
// http://www.unicode.org/Public/security/10.0.0/confusables.txt
use super::StringReader;
-use errors::{Applicability, DiagnosticBuilder};
-use syntax_pos::{BytePos, Pos, Span, symbol::kw};
use crate::token;
+use rustc_errors::{Applicability, DiagnosticBuilder};
+use syntax_pos::{BytePos, Pos, Span, symbol::kw};
#[rustfmt::skip] // for line breaks
const UNICODE_ARRAY: &[(char, &str, char)] = &[
diff --git a/src/librustc_parse/lib.rs b/src/librustc_parse/lib.rs
index a22b383..faff386 100644
--- a/src/librustc_parse/lib.rs
+++ b/src/librustc_parse/lib.rs
@@ -1,5 +1,6 @@
//! The main parser interface.
+#![feature(bool_to_option)]
#![feature(crate_visibility_modifier)]
use syntax::ast;
@@ -8,7 +9,7 @@
use syntax::token::{self, Nonterminal};
use syntax::tokenstream::{self, TokenStream, TokenTree};
-use errors::{PResult, FatalError, Level, Diagnostic};
+use rustc_errors::{PResult, FatalError, Level, Diagnostic};
use rustc_data_structures::sync::Lrc;
use syntax_pos::{Span, SourceFile, FileName};
@@ -53,7 +54,7 @@
macro_rules! panictry_buffer {
($handler:expr, $e:expr) => ({
use std::result::Result::{Ok, Err};
- use errors::FatalError;
+ use rustc_errors::FatalError;
match $e {
Ok(e) => e,
Err(errs) => {
@@ -270,21 +271,13 @@
}
/// Runs the given subparser `f` on the tokens of the given `attr`'s item.
-pub fn parse_in_attr<'a, T>(
+pub fn parse_in<'a, T>(
sess: &'a ParseSess,
- attr: &ast::Attribute,
+ tts: TokenStream,
+ name: &'static str,
mut f: impl FnMut(&mut Parser<'a>) -> PResult<'a, T>,
) -> PResult<'a, T> {
- let mut parser = Parser::new(
- sess,
- // FIXME(#66940, Centril | petrochenkov): refactor this function so it doesn't
- // require reconstructing and immediately re-parsing delimiters.
- attr.get_normal_item().args.outer_tokens(),
- None,
- false,
- false,
- Some("attribute"),
- );
+ let mut parser = Parser::new(sess, tts, None, false, false, Some(name));
let result = f(&mut parser)?;
if parser.token != token::Eof {
parser.unexpected()?;
diff --git a/src/librustc_parse/parser/attr.rs b/src/librustc_parse/parser/attr.rs
index c726140..00fd6b8 100644
--- a/src/librustc_parse/parser/attr.rs
+++ b/src/librustc_parse/parser/attr.rs
@@ -1,10 +1,10 @@
use super::{SeqSep, Parser, TokenType, PathStyle};
+use rustc_errors::PResult;
use syntax::attr;
use syntax::ast;
use syntax::util::comments;
use syntax::token::{self, Nonterminal};
use syntax_pos::{Span, Symbol};
-use errors::PResult;
use log::debug;
@@ -220,7 +220,7 @@
Ok(attrs)
}
- pub(super) fn parse_unsuffixed_lit(&mut self) -> PResult<'a, ast::Lit> {
+ crate fn parse_unsuffixed_lit(&mut self) -> PResult<'a, ast::Lit> {
let lit = self.parse_lit()?;
debug!("checking if {:?} is unusuffixed", lit);
@@ -238,25 +238,36 @@
/// Parses `cfg_attr(pred, attr_item_list)` where `attr_item_list` is comma-delimited.
pub fn parse_cfg_attr(&mut self) -> PResult<'a, (ast::MetaItem, Vec<(ast::AttrItem, Span)>)> {
- self.expect(&token::OpenDelim(token::Paren))?;
-
let cfg_predicate = self.parse_meta_item()?;
self.expect(&token::Comma)?;
// Presumably, the majority of the time there will only be one attr.
let mut expanded_attrs = Vec::with_capacity(1);
-
- while !self.check(&token::CloseDelim(token::Paren)) {
- let lo = self.token.span.lo();
+ while self.token.kind != token::Eof {
+ let lo = self.token.span;
let item = self.parse_attr_item()?;
- expanded_attrs.push((item, self.prev_span.with_lo(lo)));
- self.expect_one_of(&[token::Comma], &[token::CloseDelim(token::Paren)])?;
+ expanded_attrs.push((item, lo.to(self.prev_span)));
+ if !self.eat(&token::Comma) {
+ break;
+ }
}
- self.expect(&token::CloseDelim(token::Paren))?;
Ok((cfg_predicate, expanded_attrs))
}
+ /// Matches `COMMASEP(meta_item_inner)`.
+ crate fn parse_meta_seq_top(&mut self) -> PResult<'a, Vec<ast::NestedMetaItem>> {
+ // Presumably, the majority of the time there will only be one attr.
+ let mut nmis = Vec::with_capacity(1);
+ while self.token.kind != token::Eof {
+ nmis.push(self.parse_meta_item_inner()?);
+ if !self.eat(&token::Comma) {
+ break;
+ }
+ }
+ Ok(nmis)
+ }
+
/// Matches the following grammar (per RFC 1559).
///
/// meta_item : PATH ( '=' UNSUFFIXED_LIT | '(' meta_item_inner? ')' )? ;
diff --git a/src/librustc_parse/parser/diagnostics.rs b/src/librustc_parse/parser/diagnostics.rs
index da8bf89..ba125ca 100644
--- a/src/librustc_parse/parser/diagnostics.rs
+++ b/src/librustc_parse/parser/diagnostics.rs
@@ -1,25 +1,22 @@
use super::{BlockMode, PathStyle, SemiColonMode, TokenType, TokenExpectType, SeqSep, Parser};
-use syntax::ast::{
- self, Param, BinOpKind, BindingMode, BlockCheckMode, Expr, ExprKind, Ident, Item, ItemKind,
- Mutability, Pat, PatKind, PathSegment, QSelf, Ty, TyKind,
-};
+use rustc_data_structures::fx::FxHashSet;
+use rustc_errors::{self, PResult, Applicability, DiagnosticBuilder, Handler, pluralize};
+use rustc_error_codes::*;
+use syntax::ast::{self, Param, BinOpKind, BindingMode, BlockCheckMode, Expr, ExprKind, Ident, Item};
+use syntax::ast::{ItemKind, Mutability, Pat, PatKind, PathSegment, QSelf, Ty, TyKind};
use syntax::token::{self, TokenKind, token_can_begin_expr};
use syntax::print::pprust;
use syntax::ptr::P;
-use syntax::symbol::{kw, sym};
use syntax::ThinVec;
use syntax::util::parser::AssocOp;
use syntax::struct_span_err;
-
-use errors::{PResult, Applicability, DiagnosticBuilder, pluralize};
-use rustc_data_structures::fx::FxHashSet;
+use syntax_pos::symbol::{kw, sym};
use syntax_pos::{Span, DUMMY_SP, MultiSpan, SpanSnippetError};
+
use log::{debug, trace};
use std::mem;
-use rustc_error_codes::*;
-
const TURBOFISH: &'static str = "use `::<...>` instead of `<...>` to specify type arguments";
/// Creates a placeholder argument.
@@ -61,10 +58,10 @@
}
impl Error {
- fn span_err<S: Into<MultiSpan>>(
+ fn span_err(
self,
- sp: S,
- handler: &errors::Handler,
+ sp: impl Into<MultiSpan>,
+ handler: &Handler,
) -> DiagnosticBuilder<'_> {
match self {
Error::FileNotFoundForModule {
@@ -212,7 +209,7 @@
self.sess.span_diagnostic.span_bug(sp, m)
}
- pub(super) fn diagnostic(&self) -> &'a errors::Handler {
+ pub(super) fn diagnostic(&self) -> &'a Handler {
&self.sess.span_diagnostic
}
diff --git a/src/librustc_parse/parser/expr.rs b/src/librustc_parse/parser/expr.rs
index 1112274..3cd4988 100644
--- a/src/librustc_parse/parser/expr.rs
+++ b/src/librustc_parse/parser/expr.rs
@@ -4,23 +4,20 @@
use super::diagnostics::Error;
use crate::maybe_recover_from_interpolated_ty_qpath;
-use syntax::ast::{
- self, DUMMY_NODE_ID, Attribute, AttrStyle, Ident, CaptureBy, BlockCheckMode,
- Expr, ExprKind, RangeLimits, Label, Movability, IsAsync, Arm, Ty, TyKind,
- FunctionRetTy, Param, FnDecl, BinOpKind, BinOp, UnOp, Mac, AnonConst, Field, Lit,
-};
+use rustc_data_structures::thin_vec::ThinVec;
+use rustc_errors::{PResult, Applicability};
+use syntax::ast::{self, DUMMY_NODE_ID, Attribute, AttrStyle, Ident, CaptureBy, BlockCheckMode};
+use syntax::ast::{Expr, ExprKind, RangeLimits, Label, Movability, IsAsync, Arm, Ty, TyKind};
+use syntax::ast::{FunctionRetTy, Param, FnDecl, BinOpKind, BinOp, UnOp, Mac, AnonConst, Field, Lit};
use syntax::token::{self, Token, TokenKind};
use syntax::print::pprust;
use syntax::ptr::P;
-use syntax::source_map::{self, Span};
use syntax::util::classify;
use syntax::util::literal::LitError;
use syntax::util::parser::{AssocOp, Fixity, prec_let_scrutinee_needs_par};
-use syntax_pos::symbol::{kw, sym};
-use syntax_pos::Symbol;
-use errors::{PResult, Applicability};
+use syntax_pos::source_map::{self, Span};
+use syntax_pos::symbol::{kw, sym, Symbol};
use std::mem;
-use rustc_data_structures::thin_vec::ThinVec;
/// Possibly accepts an `token::Interpolated` expression (a pre-parsed expression
/// dropped into the token stream, which happens while parsing the result of
diff --git a/src/librustc_parse/parser/generics.rs b/src/librustc_parse/parser/generics.rs
index ba5eafc..32819cc 100644
--- a/src/librustc_parse/parser/generics.rs
+++ b/src/librustc_parse/parser/generics.rs
@@ -1,11 +1,11 @@
use super::Parser;
+use rustc_errors::PResult;
use syntax::ast::{self, WhereClause, GenericParam, GenericParamKind, GenericBounds, Attribute};
use syntax::token;
use syntax::source_map::DUMMY_SP;
use syntax_pos::symbol::{kw, sym};
-use errors::PResult;
impl<'a> Parser<'a> {
/// Parses bounds of a lifetime parameter `BOUND + BOUND + BOUND`, possibly with trailing `+`.
diff --git a/src/librustc_parse/parser/item.rs b/src/librustc_parse/parser/item.rs
index 66a1352..34ef12e 100644
--- a/src/librustc_parse/parser/item.rs
+++ b/src/librustc_parse/parser/item.rs
@@ -3,6 +3,8 @@
use crate::maybe_whole;
+use rustc_errors::{PResult, Applicability, DiagnosticBuilder, StashKey};
+use rustc_error_codes::*;
use syntax::ast::{self, DUMMY_NODE_ID, Ident, Attribute, AttrKind, AttrStyle, AnonConst, Item};
use syntax::ast::{ItemKind, ImplItem, ImplItemKind, TraitItem, TraitItemKind, UseTree, UseTreeKind};
use syntax::ast::{PathSegment, IsAuto, Constness, IsAsync, Unsafety, Defaultness, Extern, StrLit};
@@ -14,16 +16,13 @@
use syntax::ThinVec;
use syntax::token;
use syntax::tokenstream::{DelimSpan, TokenTree, TokenStream};
-use syntax::source_map::{self, respan, Span};
use syntax::struct_span_err;
use syntax_pos::BytePos;
+use syntax_pos::source_map::{self, respan, Span};
use syntax_pos::symbol::{kw, sym, Symbol};
-use rustc_error_codes::*;
-
use log::debug;
use std::mem;
-use errors::{PResult, Applicability, DiagnosticBuilder, StashKey};
pub(super) type ItemInfo = (Ident, ItemKind, Option<Vec<Attribute>>);
@@ -1182,6 +1181,7 @@
attrs,
vis: visibility,
kind: ForeignItemKind::Macro(mac),
+ tokens: None,
}
)
}
@@ -1212,6 +1212,7 @@
id: DUMMY_NODE_ID,
span: lo.to(hi),
vis,
+ tokens: None,
})
}
@@ -1229,7 +1230,8 @@
kind: ForeignItemKind::Ty,
id: DUMMY_NODE_ID,
span: lo.to(hi),
- vis
+ vis,
+ tokens: None,
})
}
@@ -1728,9 +1730,10 @@
/// Checks if current token is one of tokens which cannot be nested like `kw::Enum`. In case
/// it is, we try to parse the item and report error about nested types.
fn recover_nested_adt_item(&mut self, keyword: Symbol) -> PResult<'a, bool> {
- if self.token.is_keyword(kw::Enum) ||
+ if (self.token.is_keyword(kw::Enum) ||
self.token.is_keyword(kw::Struct) ||
- self.token.is_keyword(kw::Union)
+ self.token.is_keyword(kw::Union))
+ && self.look_ahead(1, |t| t.is_ident())
{
let kw_token = self.token.clone();
let kw_str = pprust::token_to_string(&kw_token);
@@ -1826,6 +1829,7 @@
id: DUMMY_NODE_ID,
span,
vis,
+ tokens: None,
})
}
diff --git a/src/librustc_parse/parser/mod.rs b/src/librustc_parse/parser/mod.rs
index 2868972..07e99cf 100644
--- a/src/librustc_parse/parser/mod.rs
+++ b/src/librustc_parse/parser/mod.rs
@@ -14,23 +14,20 @@
use crate::{Directory, DirectoryOwnership};
use crate::lexer::UnmatchedBrace;
-use syntax::ast::{
- self, DUMMY_NODE_ID, AttrStyle, Attribute, CrateSugar, Extern, Ident, StrLit,
- IsAsync, MacArgs, MacDelimiter, Mutability, Visibility, VisibilityKind, Unsafety,
-};
-
+use rustc_errors::{PResult, Applicability, DiagnosticBuilder, FatalError};
+use rustc_data_structures::thin_vec::ThinVec;
+use syntax::ast::{self, DUMMY_NODE_ID, AttrStyle, Attribute, CrateSugar, Extern, Ident, StrLit};
+use syntax::ast::{IsAsync, MacArgs, MacDelimiter, Mutability, Visibility, VisibilityKind, Unsafety};
use syntax::print::pprust;
use syntax::ptr::P;
use syntax::token::{self, Token, TokenKind, DelimToken};
use syntax::tokenstream::{self, DelimSpan, TokenTree, TokenStream, TreeAndJoint};
use syntax::sess::ParseSess;
-use syntax::source_map::respan;
use syntax::struct_span_err;
use syntax::util::comments::{doc_comment_style, strip_doc_comment_decoration};
+use syntax_pos::source_map::respan;
use syntax_pos::symbol::{kw, sym, Symbol};
use syntax_pos::{Span, BytePos, DUMMY_SP, FileName};
-use rustc_data_structures::thin_vec::ThinVec;
-use errors::{PResult, Applicability, DiagnosticBuilder, FatalError};
use log::debug;
use std::borrow::Cow;
diff --git a/src/librustc_parse/parser/module.rs b/src/librustc_parse/parser/module.rs
index 59d7c2b..3777e17 100644
--- a/src/librustc_parse/parser/module.rs
+++ b/src/librustc_parse/parser/module.rs
@@ -4,13 +4,12 @@
use crate::{new_sub_parser_from_file, DirectoryOwnership};
+use rustc_errors::PResult;
use syntax::attr;
use syntax::ast::{self, Ident, Attribute, ItemKind, Mod, Crate};
use syntax::token::{self, TokenKind};
-use syntax::source_map::{SourceMap, Span, DUMMY_SP, FileName};
-
+use syntax_pos::source_map::{SourceMap, Span, DUMMY_SP, FileName};
use syntax_pos::symbol::sym;
-use errors::PResult;
use std::path::{self, Path, PathBuf};
@@ -212,13 +211,13 @@
// `./<id>.rs` and `./<id>/mod.rs`.
let relative_prefix_string;
let relative_prefix = if let Some(ident) = relative {
- relative_prefix_string = format!("{}{}", ident, path::MAIN_SEPARATOR);
+ relative_prefix_string = format!("{}{}", ident.name, path::MAIN_SEPARATOR);
&relative_prefix_string
} else {
""
};
- let mod_name = id.to_string();
+ let mod_name = id.name.to_string();
let default_path_str = format!("{}{}.rs", relative_prefix, mod_name);
let secondary_path_str = format!("{}{}{}mod.rs",
relative_prefix, mod_name, path::MAIN_SEPARATOR);
diff --git a/src/librustc_parse/parser/pat.rs b/src/librustc_parse/parser/pat.rs
index 1127c4b..117b92d 100644
--- a/src/librustc_parse/parser/pat.rs
+++ b/src/librustc_parse/parser/pat.rs
@@ -1,5 +1,6 @@
use super::{Parser, PathStyle};
use crate::{maybe_recover_from_interpolated_ty_qpath, maybe_whole};
+use rustc_errors::{PResult, Applicability, DiagnosticBuilder};
use syntax::ast::{self, Attribute, Pat, PatKind, FieldPat, RangeEnd, RangeSyntax, Mac};
use syntax::ast::{BindingMode, Ident, Mutability, Path, QSelf, Expr, ExprKind};
use syntax::mut_visit::{noop_visit_pat, noop_visit_mac, MutVisitor};
@@ -7,9 +8,8 @@
use syntax::print::pprust;
use syntax::ThinVec;
use syntax::token;
-use syntax::source_map::{respan, Span, Spanned};
+use syntax_pos::source_map::{respan, Span, Spanned};
use syntax_pos::symbol::{kw, sym};
-use errors::{PResult, Applicability, DiagnosticBuilder};
type Expected = Option<&'static str>;
@@ -459,18 +459,28 @@
/// Parse `&pat` / `&mut pat`.
fn parse_pat_deref(&mut self, expected: Expected) -> PResult<'a, PatKind> {
self.expect_and()?;
+ self.recover_lifetime_in_deref_pat();
let mutbl = self.parse_mutability();
-
- if let token::Lifetime(name) = self.token.kind {
- let mut err = self.fatal(&format!("unexpected lifetime `{}` in pattern", name));
- err.span_label(self.token.span, "unexpected lifetime");
- return Err(err);
- }
-
let subpat = self.parse_pat_with_range_pat(false, expected)?;
Ok(PatKind::Ref(subpat, mutbl))
}
+ fn recover_lifetime_in_deref_pat(&mut self) {
+ if let token::Lifetime(name) = self.token.kind {
+ self.bump(); // `'a`
+
+ let span = self.prev_span;
+ self.struct_span_err(span, &format!("unexpected lifetime `{}` in pattern", name))
+ .span_suggestion(
+ span,
+ "remove the lifetime",
+ String::new(),
+ Applicability::MachineApplicable,
+ )
+ .emit();
+ }
+ }
+
/// Parse a tuple or parenthesis pattern.
fn parse_pat_tuple_or_parens(&mut self) -> PResult<'a, PatKind> {
let (fields, trailing_comma) = self.parse_paren_comma_seq(|p| p.parse_pat_with_or_inner())?;
diff --git a/src/librustc_parse/parser/path.rs b/src/librustc_parse/parser/path.rs
index 75bb67d..5334fc4 100644
--- a/src/librustc_parse/parser/path.rs
+++ b/src/librustc_parse/parser/path.rs
@@ -1,16 +1,15 @@
use super::{Parser, TokenType};
use crate::maybe_whole;
+use rustc_errors::{PResult, Applicability, pluralize};
use syntax::ast::{self, QSelf, Path, PathSegment, Ident, ParenthesizedArgs, AngleBracketedArgs};
use syntax::ast::{AnonConst, GenericArg, AssocTyConstraint, AssocTyConstraintKind, BlockCheckMode};
-use syntax::ast::MacArgs;
use syntax::ThinVec;
use syntax::token::{self, Token};
-use syntax::source_map::{Span, BytePos};
+use syntax_pos::source_map::{Span, BytePos};
use syntax_pos::symbol::{kw, sym};
use std::mem;
use log::debug;
-use errors::{PResult, Applicability, pluralize};
/// Specifies how to parse a path.
#[derive(Copy, Clone, PartialEq)]
@@ -109,42 +108,6 @@
Ok(Path { segments, span: lo.to(self.prev_span) })
}
- /// Like `parse_path`, but also supports parsing `Word` meta items into paths for
- /// backwards-compatibility. This is used when parsing derive macro paths in `#[derive]`
- /// attributes.
- fn parse_path_allowing_meta(&mut self, style: PathStyle) -> PResult<'a, Path> {
- let meta_ident = match self.token.kind {
- token::Interpolated(ref nt) => match **nt {
- token::NtMeta(ref item) => match item.args {
- MacArgs::Empty => Some(item.path.clone()),
- _ => None,
- },
- _ => None,
- },
- _ => None,
- };
- if let Some(path) = meta_ident {
- self.bump();
- return Ok(path);
- }
- self.parse_path(style)
- }
-
- /// Parse a list of paths inside `#[derive(path_0, ..., path_n)]`.
- pub fn parse_derive_paths(&mut self) -> PResult<'a, Vec<Path>> {
- self.expect(&token::OpenDelim(token::Paren))?;
- let mut list = Vec::new();
- while !self.eat(&token::CloseDelim(token::Paren)) {
- let path = self.parse_path_allowing_meta(PathStyle::Mod)?;
- list.push(path);
- if !self.eat(&token::Comma) {
- self.expect(&token::CloseDelim(token::Paren))?;
- break
- }
- }
- Ok(list)
- }
-
pub(super) fn parse_path_segments(
&mut self,
segments: &mut Vec<PathSegment>,
diff --git a/src/librustc_parse/parser/stmt.rs b/src/librustc_parse/parser/stmt.rs
index b952e88..943b6ec 100644
--- a/src/librustc_parse/parser/stmt.rs
+++ b/src/librustc_parse/parser/stmt.rs
@@ -6,6 +6,7 @@
use crate::maybe_whole;
use crate::DirectoryOwnership;
+use rustc_errors::{PResult, Applicability};
use syntax::ThinVec;
use syntax::ptr::P;
use syntax::ast;
@@ -13,11 +14,10 @@
use syntax::ast::{Attribute, AttrStyle, VisibilityKind, MacStmtStyle, Mac};
use syntax::util::classify;
use syntax::token;
-use syntax::source_map::{respan, Span};
-use syntax::symbol::{kw, sym};
+use syntax_pos::source_map::{respan, Span};
+use syntax_pos::symbol::{kw, sym};
use std::mem;
-use errors::{PResult, Applicability};
impl<'a> Parser<'a> {
/// Parses a statement. This stops just before trailing semicolons on everything but items.
diff --git a/src/librustc_parse/parser/ty.rs b/src/librustc_parse/parser/ty.rs
index 3214279..84ffef6 100644
--- a/src/librustc_parse/parser/ty.rs
+++ b/src/librustc_parse/parser/ty.rs
@@ -3,19 +3,17 @@
use crate::{maybe_whole, maybe_recover_from_interpolated_ty_qpath};
+use rustc_errors::{PResult, Applicability, pluralize};
+use rustc_error_codes::*;
use syntax::ptr::P;
use syntax::ast::{self, Ty, TyKind, MutTy, BareFnTy, FunctionRetTy, GenericParam, Lifetime, Ident};
use syntax::ast::{TraitBoundModifier, TraitObjectSyntax, GenericBound, GenericBounds, PolyTraitRef};
use syntax::ast::{Mutability, AnonConst, Mac};
use syntax::token::{self, Token};
-use syntax::source_map::Span;
use syntax::struct_span_fatal;
+use syntax_pos::source_map::Span;
use syntax_pos::symbol::kw;
-use errors::{PResult, Applicability, pluralize};
-
-use rustc_error_codes::*;
-
/// Returns `true` if `IDENT t` can start a type -- `IDENT::a::b`, `IDENT<u8, u8>`,
/// `IDENT<<u8 as Trait>::AssocTy>`.
///
diff --git a/src/librustc_parse/validate_attr.rs b/src/librustc_parse/validate_attr.rs
index 8601add..94d3fe7 100644
--- a/src/librustc_parse/validate_attr.rs
+++ b/src/librustc_parse/validate_attr.rs
@@ -1,10 +1,13 @@
//! Meta-syntax validation logic of attributes for post-expansion.
-use errors::{PResult, Applicability};
+use crate::parse_in;
+
+use rustc_errors::{PResult, Applicability};
use rustc_feature::{AttributeTemplate, BUILTIN_ATTRIBUTE_MAP};
-use syntax::ast::{self, Attribute, AttrKind, Ident, MacArgs, MetaItem, MetaItemKind};
+use syntax::ast::{self, Attribute, AttrKind, Ident, MacArgs, MacDelimiter, MetaItem, MetaItemKind};
use syntax::attr::mk_name_value_item_str;
use syntax::early_buffered_lints::ILL_FORMED_ATTRIBUTE_INPUT;
+use syntax::tokenstream::DelimSpan;
use syntax::sess::ParseSess;
use syntax_pos::{Symbol, sym};
@@ -27,9 +30,20 @@
pub fn parse_meta<'a>(sess: &'a ParseSess, attr: &Attribute) -> PResult<'a, MetaItem> {
Ok(match attr.kind {
AttrKind::Normal(ref item) => MetaItem {
- path: item.path.clone(),
- kind: super::parse_in_attr(sess, attr, |p| p.parse_meta_item_kind())?,
span: attr.span,
+ path: item.path.clone(),
+ kind: match &attr.get_normal_item().args {
+ MacArgs::Empty => MetaItemKind::Word,
+ MacArgs::Eq(_, t) => {
+ let v = parse_in(sess, t.clone(), "name value", |p| p.parse_unsuffixed_lit())?;
+ MetaItemKind::NameValue(v)
+ }
+ MacArgs::Delimited(dspan, delim, t) => {
+ check_meta_bad_delim(sess, *dspan, *delim, "wrong meta list delimiters");
+ let nmis = parse_in(sess, t.clone(), "meta list", |p| p.parse_meta_seq_top())?;
+ MetaItemKind::List(nmis)
+ }
+ }
},
AttrKind::DocComment(comment) => {
mk_name_value_item_str(Ident::new(sym::doc, attr.span), comment, attr.span)
@@ -37,6 +51,24 @@
})
}
+crate fn check_meta_bad_delim(sess: &ParseSess, span: DelimSpan, delim: MacDelimiter, msg: &str) {
+ if let ast::MacDelimiter::Parenthesis = delim {
+ return;
+ }
+
+ sess.span_diagnostic
+ .struct_span_err(span.entire(), msg)
+ .multipart_suggestion(
+ "the delimiters should be `(` and `)`",
+ vec![
+ (span.open, "(".to_string()),
+ (span.close, ")".to_string()),
+ ],
+ Applicability::MachineApplicable,
+ )
+ .emit();
+}
+
/// Checks that the given meta-item is compatible with this `AttributeTemplate`.
fn is_attr_template_compatible(template: &AttributeTemplate, meta: &ast::MetaItemKind) -> bool {
match meta {
diff --git a/src/librustc_passes/ast_validation.rs b/src/librustc_passes/ast_validation.rs
index 29cfee8..202b6ae 100644
--- a/src/librustc_passes/ast_validation.rs
+++ b/src/librustc_passes/ast_validation.rs
@@ -158,14 +158,14 @@
err.emit();
}
- fn check_decl_no_pat<F: FnMut(Span, bool)>(decl: &FnDecl, mut report_err: F) {
- for arg in &decl.inputs {
- match arg.pat.kind {
+ fn check_decl_no_pat(decl: &FnDecl, mut report_err: impl FnMut(Span, bool)) {
+ for Param { pat, .. } in &decl.inputs {
+ match pat.kind {
PatKind::Ident(BindingMode::ByValue(Mutability::Immutable), _, None) |
PatKind::Wild => {}
PatKind::Ident(BindingMode::ByValue(Mutability::Mutable), _, None) =>
- report_err(arg.pat.span, true),
- _ => report_err(arg.pat.span, false),
+ report_err(pat.span, true),
+ _ => report_err(pat.span, false),
}
}
}
diff --git a/src/librustc_resolve/build_reduced_graph.rs b/src/librustc_resolve/build_reduced_graph.rs
index 04e233c..e2578d6 100644
--- a/src/librustc_resolve/build_reduced_graph.rs
+++ b/src/librustc_resolve/build_reduced_graph.rs
@@ -12,7 +12,7 @@
use crate::{Module, ModuleData, ModuleKind, NameBinding, NameBindingKind, Segment, ToNameBinding};
use crate::{ModuleOrUniformRoot, ParentScope, PerNS, Resolver, ResolverArenas, ExternPreludeEntry};
use crate::Namespace::{self, TypeNS, ValueNS, MacroNS};
-use crate::{ResolutionError, Determinacy, PathResult, CrateLint};
+use crate::{ResolutionError, VisResolutionError, Determinacy, PathResult, CrateLint};
use rustc::bug;
use rustc::hir::def::{self, *};
@@ -32,8 +32,7 @@
use syntax::ast::{self, Block, ForeignItem, ForeignItemKind, Item, ItemKind, NodeId};
use syntax::ast::{MetaItemKind, StmtKind, TraitItem, TraitItemKind};
use syntax::token::{self, Token};
-use syntax::print::pprust;
-use syntax::{span_err, struct_span_err};
+use syntax::span_err;
use syntax::source_map::{respan, Spanned};
use syntax::symbol::{kw, sym};
use syntax::visit::{self, Visitor};
@@ -192,14 +191,25 @@
impl<'a, 'b> BuildReducedGraphVisitor<'a, 'b> {
fn resolve_visibility(&mut self, vis: &ast::Visibility) -> ty::Visibility {
+ self.resolve_visibility_speculative(vis, false).unwrap_or_else(|err| {
+ self.r.report_vis_error(err);
+ ty::Visibility::Public
+ })
+ }
+
+ fn resolve_visibility_speculative<'ast>(
+ &mut self,
+ vis: &'ast ast::Visibility,
+ speculative: bool,
+ ) -> Result<ty::Visibility, VisResolutionError<'ast>> {
let parent_scope = &self.parent_scope;
match vis.node {
- ast::VisibilityKind::Public => ty::Visibility::Public,
+ ast::VisibilityKind::Public => Ok(ty::Visibility::Public),
ast::VisibilityKind::Crate(..) => {
- ty::Visibility::Restricted(DefId::local(CRATE_DEF_INDEX))
+ Ok(ty::Visibility::Restricted(DefId::local(CRATE_DEF_INDEX)))
}
ast::VisibilityKind::Inherited => {
- ty::Visibility::Restricted(parent_scope.module.normal_ancestor_id)
+ Ok(ty::Visibility::Restricted(parent_scope.module.normal_ancestor_id))
}
ast::VisibilityKind::Restricted { ref path, id, .. } => {
// For visibilities we are not ready to provide correct implementation of "uniform
@@ -209,86 +219,67 @@
let ident = path.segments.get(0).expect("empty path in visibility").ident;
let crate_root = if ident.is_path_segment_keyword() {
None
- } else if ident.span.rust_2018() {
- let msg = "relative paths are not supported in visibilities on 2018 edition";
- self.r.session.struct_span_err(ident.span, msg)
- .span_suggestion(
- path.span,
- "try",
- format!("crate::{}", pprust::path_to_string(&path)),
- Applicability::MaybeIncorrect,
- )
- .emit();
- return ty::Visibility::Public;
- } else {
- let ctxt = ident.span.ctxt();
+ } else if ident.span.rust_2015() {
Some(Segment::from_ident(Ident::new(
- kw::PathRoot, path.span.shrink_to_lo().with_ctxt(ctxt)
+ kw::PathRoot, path.span.shrink_to_lo().with_ctxt(ident.span.ctxt())
)))
+ } else {
+ return Err(VisResolutionError::Relative2018(ident.span, path));
};
let segments = crate_root.into_iter()
.chain(path.segments.iter().map(|seg| seg.into())).collect::<Vec<_>>();
- let expected_found_error = |this: &Self, res: Res| {
- let path_str = Segment::names_to_string(&segments);
- struct_span_err!(this.r.session, path.span, E0577,
- "expected module, found {} `{}`", res.descr(), path_str)
- .span_label(path.span, "not a module").emit();
- };
+ let expected_found_error = |res| Err(VisResolutionError::ExpectedFound(
+ path.span, Segment::names_to_string(&segments), res
+ ));
match self.r.resolve_path(
&segments,
Some(TypeNS),
parent_scope,
- true,
+ !speculative,
path.span,
CrateLint::SimplePath(id),
) {
PathResult::Module(ModuleOrUniformRoot::Module(module)) => {
let res = module.res().expect("visibility resolved to unnamed block");
- self.r.record_partial_res(id, PartialRes::new(res));
+ if !speculative {
+ self.r.record_partial_res(id, PartialRes::new(res));
+ }
if module.is_normal() {
if res == Res::Err {
- ty::Visibility::Public
+ Ok(ty::Visibility::Public)
} else {
let vis = ty::Visibility::Restricted(res.def_id());
if self.r.is_accessible_from(vis, parent_scope.module) {
- vis
+ Ok(vis)
} else {
- struct_span_err!(self.r.session, path.span, E0742,
- "visibilities can only be restricted to ancestor modules")
- .emit();
- ty::Visibility::Public
+ Err(VisResolutionError::AncestorOnly(path.span))
}
}
} else {
- expected_found_error(self, res);
- ty::Visibility::Public
+ expected_found_error(res)
}
}
- PathResult::Module(..) => {
- self.r.session.span_err(path.span, "visibility must resolve to a module");
- ty::Visibility::Public
- }
- PathResult::NonModule(partial_res) => {
- expected_found_error(self, partial_res.base_res());
- ty::Visibility::Public
- }
- PathResult::Failed { span, label, suggestion, .. } => {
- self.r.report_error(
- span, ResolutionError::FailedToResolve { label, suggestion }
- );
- ty::Visibility::Public
- }
- PathResult::Indeterminate => {
- span_err!(self.r.session, path.span, E0578,
- "cannot determine resolution for the visibility");
- ty::Visibility::Public
- }
+ PathResult::Module(..) =>
+ Err(VisResolutionError::ModuleOnly(path.span)),
+ PathResult::NonModule(partial_res) =>
+ expected_found_error(partial_res.base_res()),
+ PathResult::Failed { span, label, suggestion, .. } =>
+ Err(VisResolutionError::FailedToResolve(span, label, suggestion)),
+ PathResult::Indeterminate =>
+ Err(VisResolutionError::Indeterminate(path.span)),
}
}
}
}
+ fn insert_field_names_local(&mut self, def_id: DefId, vdata: &ast::VariantData) {
+ let field_names = vdata.fields().iter().map(|field| {
+ respan(field.span, field.ident.map_or(kw::Invalid, |ident| ident.name))
+ }).collect();
+ self.insert_field_names(def_id, field_names);
+ }
+
fn insert_field_names(&mut self, def_id: DefId, field_names: Vec<Spanned<Name>>) {
if !field_names.is_empty() {
self.r.field_names.insert(def_id, field_names);
@@ -656,8 +647,6 @@
self.r.define(parent, ident, TypeNS, imported_binding);
}
- ItemKind::GlobalAsm(..) => {}
-
ItemKind::Mod(..) if ident.name == kw::Invalid => {} // Crate root
ItemKind::Mod(..) => {
@@ -676,9 +665,6 @@
self.parent_scope.module = module;
}
- // Handled in `rustc_metadata::{native_libs,link_args}`
- ItemKind::ForeignMod(..) => {}
-
// These items live in the value namespace.
ItemKind::Static(..) => {
let res = Res::Def(DefKind::Static, self.r.definitions.local_def_id(item.id));
@@ -726,65 +712,52 @@
}
// These items live in both the type and value namespaces.
- ItemKind::Struct(ref struct_def, _) => {
+ ItemKind::Struct(ref vdata, _) => {
// Define a name in the type namespace.
let def_id = self.r.definitions.local_def_id(item.id);
let res = Res::Def(DefKind::Struct, def_id);
self.r.define(parent, ident, TypeNS, (res, vis, sp, expansion));
- let mut ctor_vis = vis;
-
- let has_non_exhaustive = attr::contains_name(&item.attrs, sym::non_exhaustive);
-
- // If the structure is marked as non_exhaustive then lower the visibility
- // to within the crate.
- if has_non_exhaustive && vis == ty::Visibility::Public {
- ctor_vis = ty::Visibility::Restricted(DefId::local(CRATE_DEF_INDEX));
- }
-
// Record field names for error reporting.
- let field_names = struct_def.fields().iter().map(|field| {
- // NOTE: The field may be an expansion placeholder, but expansion sets correct
- // visibilities for unnamed field placeholders specifically, so the constructor
- // visibility should still be determined correctly.
- let field_vis = self.resolve_visibility(&field.vis);
- if ctor_vis.is_at_least(field_vis, &*self.r) {
- ctor_vis = field_vis;
- }
- respan(field.span, field.ident.map_or(kw::Invalid, |ident| ident.name))
- }).collect();
- let item_def_id = self.r.definitions.local_def_id(item.id);
- self.insert_field_names(item_def_id, field_names);
+ self.insert_field_names_local(def_id, vdata);
// If this is a tuple or unit struct, define a name
// in the value namespace as well.
- if let Some(ctor_node_id) = struct_def.ctor_id() {
+ if let Some(ctor_node_id) = vdata.ctor_id() {
+ let mut ctor_vis = vis;
+ // If the structure is marked as non_exhaustive then lower the visibility
+ // to within the crate.
+ if vis == ty::Visibility::Public &&
+ attr::contains_name(&item.attrs, sym::non_exhaustive) {
+ ctor_vis = ty::Visibility::Restricted(DefId::local(CRATE_DEF_INDEX));
+ }
+ for field in vdata.fields() {
+ // NOTE: The field may be an expansion placeholder, but expansion sets
+ // correct visibilities for unnamed field placeholders specifically, so the
+ // constructor visibility should still be determined correctly.
+ if let Ok(field_vis) =
+ self.resolve_visibility_speculative(&field.vis, true) {
+ if ctor_vis.is_at_least(field_vis, &*self.r) {
+ ctor_vis = field_vis;
+ }
+ }
+ }
let ctor_res = Res::Def(
- DefKind::Ctor(CtorOf::Struct, CtorKind::from_ast(struct_def)),
+ DefKind::Ctor(CtorOf::Struct, CtorKind::from_ast(vdata)),
self.r.definitions.local_def_id(ctor_node_id),
);
self.r.define(parent, ident, ValueNS, (ctor_res, ctor_vis, sp, expansion));
- self.r.struct_constructors.insert(res.def_id(), (ctor_res, ctor_vis));
+ self.r.struct_constructors.insert(def_id, (ctor_res, ctor_vis));
}
}
ItemKind::Union(ref vdata, _) => {
- let res = Res::Def(DefKind::Union, self.r.definitions.local_def_id(item.id));
+ let def_id = self.r.definitions.local_def_id(item.id);
+ let res = Res::Def(DefKind::Union, def_id);
self.r.define(parent, ident, TypeNS, (res, vis, sp, expansion));
// Record field names for error reporting.
- let field_names = vdata.fields().iter().map(|field| {
- self.resolve_visibility(&field.vis);
- respan(field.span, field.ident.map_or(kw::Invalid, |ident| ident.name))
- }).collect();
- let item_def_id = self.r.definitions.local_def_id(item.id);
- self.insert_field_names(item_def_id, field_names);
- }
-
- ItemKind::Impl(.., ref impl_items) => {
- for impl_item in impl_items {
- self.resolve_visibility(&impl_item.vis);
- }
+ self.insert_field_names_local(def_id, vdata);
}
ItemKind::Trait(..) => {
@@ -801,6 +774,9 @@
self.parent_scope.module = module;
}
+ // These items do not add names to modules.
+ ItemKind::Impl(..) | ItemKind::ForeignMod(..) | ItemKind::GlobalAsm(..) => {}
+
ItemKind::MacroDef(..) | ItemKind::Mac(_) => unreachable!(),
}
}
@@ -1134,7 +1110,6 @@
}
impl<'a, 'b> Visitor<'b> for BuildReducedGraphVisitor<'a, 'b> {
- method!(visit_impl_item: ast::ImplItem, ast::ImplItemKind::Macro, walk_impl_item);
method!(visit_expr: ast::Expr, ast::ExprKind::Mac, walk_expr);
method!(visit_pat: ast::Pat, ast::PatKind::Mac, walk_pat);
method!(visit_ty: ast::Ty, ast::TyKind::Mac, walk_ty);
@@ -1218,6 +1193,15 @@
visit::walk_trait_item(self, item);
}
+ fn visit_impl_item(&mut self, item: &'b ast::ImplItem) {
+ if let ast::ImplItemKind::Macro(..) = item.kind {
+ self.visit_invoc(item.id);
+ } else {
+ self.resolve_visibility(&item.vis);
+ visit::walk_impl_item(self, item);
+ }
+ }
+
fn visit_token(&mut self, t: Token) {
if let token::Interpolated(nt) = t.kind {
if let token::NtExpr(ref expr) = *nt {
@@ -1281,6 +1265,7 @@
if sf.is_placeholder {
self.visit_invoc(sf.id);
} else {
+ self.resolve_visibility(&sf.vis);
visit::walk_struct_field(self, sf);
}
}
diff --git a/src/librustc_resolve/diagnostics.rs b/src/librustc_resolve/diagnostics.rs
index 4dcafb6..f92415f 100644
--- a/src/librustc_resolve/diagnostics.rs
+++ b/src/librustc_resolve/diagnostics.rs
@@ -11,6 +11,7 @@
use rustc::util::nodemap::FxHashSet;
use rustc_feature::BUILTIN_ATTRIBUTES;
use syntax::ast::{self, Ident, Path};
+use syntax::print::pprust;
use syntax::source_map::SourceMap;
use syntax::struct_span_err;
use syntax::symbol::{Symbol, kw};
@@ -22,6 +23,7 @@
use crate::path_names_to_string;
use crate::{BindingError, CrateLint, HasGenericParams, LegacyScope, Module, ModuleOrUniformRoot};
use crate::{PathResult, ParentScope, ResolutionError, Resolver, Scope, ScopeSet, Segment};
+use crate::VisResolutionError;
use rustc_error_codes::*;
@@ -357,6 +359,44 @@
}
}
+ crate fn report_vis_error(&self, vis_resolution_error: VisResolutionError<'_>) {
+ match vis_resolution_error {
+ VisResolutionError::Relative2018(span, path) => {
+ let mut err = self.session.struct_span_err(span,
+ "relative paths are not supported in visibilities on 2018 edition");
+ err.span_suggestion(
+ path.span,
+ "try",
+ format!("crate::{}", pprust::path_to_string(&path)),
+ Applicability::MaybeIncorrect,
+ );
+ err
+ }
+ VisResolutionError::AncestorOnly(span) => {
+ struct_span_err!(self.session, span, E0742,
+ "visibilities can only be restricted to ancestor modules")
+ }
+ VisResolutionError::FailedToResolve(span, label, suggestion) => {
+ self.into_struct_error(
+ span, ResolutionError::FailedToResolve { label, suggestion }
+ )
+ }
+ VisResolutionError::ExpectedFound(span, path_str, res) => {
+ let mut err = struct_span_err!(self.session, span, E0577,
+ "expected module, found {} `{}`", res.descr(), path_str);
+ err.span_label(span, "not a module");
+ err
+ }
+ VisResolutionError::Indeterminate(span) => {
+ struct_span_err!(self.session, span, E0578,
+ "cannot determine resolution for the visibility")
+ }
+ VisResolutionError::ModuleOnly(span) => {
+ self.session.struct_span_err(span, "visibility must resolve to a module")
+ }
+ }.emit()
+ }
+
/// Lookup typo candidate in scope for a macro or import.
fn early_lookup_typo_candidate(
&mut self,
@@ -422,11 +462,7 @@
Scope::MacroUsePrelude => {
suggestions.extend(this.macro_use_prelude.iter().filter_map(|(name, binding)| {
let res = binding.res();
- if filter_fn(res) {
- Some(TypoSuggestion::from_res(*name, res))
- } else {
- None
- }
+ filter_fn(res).then_some(TypoSuggestion::from_res(*name, res))
}));
}
Scope::BuiltinAttrs => {
@@ -440,11 +476,7 @@
Scope::ExternPrelude => {
suggestions.extend(this.extern_prelude.iter().filter_map(|(ident, _)| {
let res = Res::Def(DefKind::Mod, DefId::local(CRATE_DEF_INDEX));
- if filter_fn(res) {
- Some(TypoSuggestion::from_res(ident.name, res))
- } else {
- None
- }
+ filter_fn(res).then_some(TypoSuggestion::from_res(ident.name, res))
}));
}
Scope::ToolPrelude => {
@@ -467,11 +499,7 @@
suggestions.extend(
primitive_types.iter().flat_map(|(name, prim_ty)| {
let res = Res::PrimTy(*prim_ty);
- if filter_fn(res) {
- Some(TypoSuggestion::from_res(*name, res))
- } else {
- None
- }
+ filter_fn(res).then_some(TypoSuggestion::from_res(*name, res))
})
)
}
diff --git a/src/librustc_resolve/late.rs b/src/librustc_resolve/late.rs
index 666c482..4f95d6f 100644
--- a/src/librustc_resolve/late.rs
+++ b/src/librustc_resolve/late.rs
@@ -496,11 +496,7 @@
GenericParamKind::Lifetime { .. } => None,
GenericParamKind::Type { ref default, .. } => {
found_default |= default.is_some();
- if found_default {
- Some((Ident::with_dummy_span(param.ident.name), Res::Err))
- } else {
- None
- }
+ found_default.then_some((Ident::with_dummy_span(param.ident.name), Res::Err))
}
}));
diff --git a/src/librustc_resolve/lib.rs b/src/librustc_resolve/lib.rs
index be36e02..d365624 100644
--- a/src/librustc_resolve/lib.rs
+++ b/src/librustc_resolve/lib.rs
@@ -9,6 +9,7 @@
#![doc(html_root_url = "https://doc.rust-lang.org/nightly/")]
+#![feature(bool_to_option)]
#![feature(crate_visibility_modifier)]
#![feature(label_break_value)]
#![feature(nll)]
@@ -217,6 +218,15 @@
SelfInTyParamDefault,
}
+enum VisResolutionError<'a> {
+ Relative2018(Span, &'a ast::Path),
+ AncestorOnly(Span),
+ FailedToResolve(Span, String, Option<Suggestion>),
+ ExpectedFound(Span, String, Res),
+ Indeterminate(Span),
+ ModuleOnly(Span),
+}
+
// A minimal representation of a path segment. We use this in resolve because
// we synthesize 'path segments' which don't have the rest of an AST or HIR
// `PathSegment`.
@@ -1126,8 +1136,10 @@
definitions.create_root_def(crate_name, session.local_crate_disambiguator());
let mut extern_prelude: FxHashMap<Ident, ExternPreludeEntry<'_>> =
- session.opts.externs.iter().map(|kv| (Ident::from_str(kv.0), Default::default()))
- .collect();
+ session.opts.externs.iter()
+ .filter(|(_, entry)| entry.add_prelude)
+ .map(|(name, _)| (Ident::from_str(name), Default::default()))
+ .collect();
if !attr::contains_name(&krate.attrs, sym::no_core) {
extern_prelude.insert(Ident::with_dummy_span(sym::core), Default::default());
diff --git a/src/librustc_session/code_stats.rs b/src/librustc_session/code_stats.rs
index 5baf0c5..764d6d8 100644
--- a/src/librustc_session/code_stats.rs
+++ b/src/librustc_session/code_stats.rs
@@ -132,9 +132,12 @@
let mut min_offset = discr_size;
- // We want to print fields by increasing offset.
+ // We want to print fields by increasing offset. We also want
+ // zero-sized fields before non-zero-sized fields, otherwise
+ // the loop below goes wrong; hence the `f.size` in the sort
+ // key.
let mut fields = fields.clone();
- fields.sort_by_key(|f| f.offset);
+ fields.sort_by_key(|f| (f.offset, f.size));
for field in fields.iter() {
let FieldInfo { ref name, offset, size, align } = *field;
@@ -146,7 +149,7 @@
}
if offset < min_offset {
- // if this happens something is very wrong
+ // If this happens it's probably a union.
println!("print-type-size {}field `.{}`: {} bytes, \
offset: {} bytes, \
alignment: {} bytes",
diff --git a/src/librustc_session/config.rs b/src/librustc_session/config.rs
index 58113bb..7f3bab8 100644
--- a/src/librustc_session/config.rs
+++ b/src/librustc_session/config.rs
@@ -1,3 +1,5 @@
+// ignore-tidy-filelength
+
//! Contains infrastructure for configuring the compiler, including parsing
//! command-line options.
@@ -31,7 +33,7 @@
use std::str::{self, FromStr};
use std::hash::Hasher;
use std::collections::hash_map::DefaultHasher;
-use std::iter::FromIterator;
+use std::iter::{self, FromIterator};
use std::path::{Path, PathBuf};
pub struct Config {
@@ -322,10 +324,35 @@
#[derive(Clone)]
pub struct Externs(BTreeMap<String, ExternEntry>);
-#[derive(Clone, Debug, Default)]
+#[derive(Clone, Debug)]
pub struct ExternEntry {
- pub locations: BTreeSet<Option<String>>,
- pub is_private_dep: bool
+ pub location: ExternLocation,
+ /// Indicates this is a "private" dependency for the
+ /// `exported_private_dependencies` lint.
+ ///
+ /// This can be set with the `priv` option like
+ /// `--extern priv:name=foo.rlib`.
+ pub is_private_dep: bool,
+ /// Add the extern entry to the extern prelude.
+ ///
+ /// This can be disabled with the `noprelude` option like
+ /// `--extern noprelude:name`.
+ pub add_prelude: bool,
+}
+
+#[derive(Clone, Debug)]
+pub enum ExternLocation {
+ /// Indicates to look for the library in the search paths.
+ ///
+ /// Added via `--extern name`.
+ FoundInLibrarySearchDirectories,
+ /// The locations where this extern entry must be found.
+ ///
+ /// The `CrateLoader` is responsible for loading these and figuring out
+ /// which one to use.
+ ///
+ /// Added via `--extern prelude_name=some_file.rlib`
+ ExactPaths(BTreeSet<String>),
}
impl Externs {
@@ -342,6 +369,18 @@
}
}
+impl ExternEntry {
+ fn new(location: ExternLocation) -> ExternEntry {
+ ExternEntry { location, is_private_dep: false, add_prelude: false }
+ }
+
+ pub fn files(&self) -> Option<impl Iterator<Item = &String>> {
+ match &self.location {
+ ExternLocation::ExactPaths(set) => Some(set.iter()),
+ _ => None,
+ }
+ }
+}
macro_rules! hash_option {
($opt_name:ident, $opt_expr:expr, $sub_hashes:expr, [UNTRACKED]) => ({});
@@ -1869,12 +1908,6 @@
"Specify where an external rust library is located",
"NAME[=PATH]",
),
- opt::multi_s(
- "",
- "extern-private",
- "Specify where an extern rust library is located, marking it as a private dependency",
- "NAME=PATH",
- ),
opt::opt_s("", "sysroot", "Override the system root", "PATH"),
opt::multi("Z", "", "Set internal debugging options", "FLAG"),
opt::opt_s(
@@ -2435,43 +2468,105 @@
}
}
-fn parse_externs(
+pub fn parse_externs(
matches: &getopts::Matches,
debugging_opts: &DebuggingOptions,
error_format: ErrorOutputType,
) -> Externs {
- if matches.opt_present("extern-private") && !debugging_opts.unstable_options {
- early_error(
- ErrorOutputType::default(),
- "'--extern-private' is unstable and only \
- available for nightly builds of rustc."
- )
- }
-
- // We start out with a `Vec<(Option<String>, bool)>>`,
- // and later convert it into a `BTreeSet<(Option<String>, bool)>`
- // This allows to modify entries in-place to set their correct
- // 'public' value.
+ let is_unstable_enabled = debugging_opts.unstable_options;
let mut externs: BTreeMap<String, ExternEntry> = BTreeMap::new();
- for (arg, private) in matches.opt_strs("extern").into_iter().map(|v| (v, false))
- .chain(matches.opt_strs("extern-private").into_iter().map(|v| (v, true))) {
-
+ for arg in matches.opt_strs("extern") {
let mut parts = arg.splitn(2, '=');
- let name = parts.next().unwrap_or_else(||
- early_error(error_format, "--extern value must not be empty"));
- let location = parts.next().map(|s| s.to_string());
+ let name = parts
+ .next()
+ .unwrap_or_else(|| early_error(error_format, "--extern value must not be empty"));
+ let path = parts.next().map(|s| s.to_string());
- let entry = externs
- .entry(name.to_owned())
- .or_default();
+ let mut name_parts = name.splitn(2, ':');
+ let first_part = name_parts.next();
+ let second_part = name_parts.next();
+ let (options, name) = match (first_part, second_part) {
+ (Some(opts), Some(name)) => (Some(opts), name),
+ (Some(name), None) => (None, name),
+ (None, None) => early_error(error_format, "--extern name must not be empty"),
+ _ => unreachable!(),
+ };
+ let entry = externs.entry(name.to_owned());
- entry.locations.insert(location.clone());
+ use std::collections::btree_map::Entry;
- // Crates start out being not private,
- // and go to being private if we see an '--extern-private'
- // flag
- entry.is_private_dep |= private;
+ let entry = if let Some(path) = path {
+ // --extern prelude_name=some_file.rlib
+ match entry {
+ Entry::Vacant(vacant) => {
+ let files = BTreeSet::from_iter(iter::once(path));
+ vacant.insert(ExternEntry::new(ExternLocation::ExactPaths(files)))
+ }
+ Entry::Occupied(occupied) => {
+ let ext_ent = occupied.into_mut();
+ match ext_ent {
+ ExternEntry { location: ExternLocation::ExactPaths(files), .. } => {
+ files.insert(path);
+ }
+ ExternEntry {
+ location: location @ ExternLocation::FoundInLibrarySearchDirectories,
+ ..
+ } => {
+ // Exact paths take precedence over search directories.
+ let files = BTreeSet::from_iter(iter::once(path));
+ *location = ExternLocation::ExactPaths(files);
+ }
+ }
+ ext_ent
+ }
+ }
+ } else {
+ // --extern prelude_name
+ match entry {
+ Entry::Vacant(vacant) => {
+ vacant.insert(ExternEntry::new(ExternLocation::FoundInLibrarySearchDirectories))
+ }
+ Entry::Occupied(occupied) => {
+ // Ignore if already specified.
+ occupied.into_mut()
+ }
+ }
+ };
+
+ let mut is_private_dep = false;
+ let mut add_prelude = true;
+ if let Some(opts) = options {
+ if !is_unstable_enabled {
+ early_error(
+ error_format,
+ "the `-Z unstable-options` flag must also be passed to \
+ enable `--extern options",
+ );
+ }
+ for opt in opts.split(',') {
+ match opt {
+ "priv" => is_private_dep = true,
+ "noprelude" => {
+ if let ExternLocation::ExactPaths(_) = &entry.location {
+ add_prelude = false;
+ } else {
+ early_error(
+ error_format,
+ "the `noprelude` --extern option requires a file path",
+ );
+ }
+ }
+ _ => early_error(error_format, &format!("unknown --extern option `{}`", opt)),
+ }
+ }
+ }
+
+ // Crates start out being not private, and go to being private `priv`
+ // is specified.
+ entry.is_private_dep |= is_private_dep;
+ // If any flag is missing `noprelude`, then add to the prelude.
+ entry.add_prelude |= add_prelude;
}
Externs(externs)
}
diff --git a/src/librustc_session/session.rs b/src/librustc_session/session.rs
index 9369c17..150d207 100644
--- a/src/librustc_session/session.rs
+++ b/src/librustc_session/session.rs
@@ -752,11 +752,7 @@
}
pub fn incr_comp_session_dir_opt(&self) -> Option<cell::Ref<'_, PathBuf>> {
- if self.opts.incremental.is_some() {
- Some(self.incr_comp_session_dir())
- } else {
- None
- }
+ self.opts.incremental.as_ref().map(|_| self.incr_comp_session_dir())
}
pub fn print_perf_stats(&self) {
@@ -1079,8 +1075,9 @@
None
}
}
- }
- else { None };
+ } else {
+ None
+ };
let host_triple = TargetTriple::from_triple(config::host_triple());
let host = Target::search(&host_triple).unwrap_or_else(|e|
diff --git a/src/librustc_target/abi/call/aarch64.rs b/src/librustc_target/abi/call/aarch64.rs
index 45fe475..06c001e 100644
--- a/src/librustc_target/abi/call/aarch64.rs
+++ b/src/librustc_target/abi/call/aarch64.rs
@@ -20,14 +20,7 @@
RegKind::Vector => size.bits() == 64 || size.bits() == 128
};
- if valid_unit {
- Some(Uniform {
- unit,
- total: size
- })
- } else {
- None
- }
+ valid_unit.then_some(Uniform { unit, total: size })
})
}
diff --git a/src/librustc_target/abi/call/arm.rs b/src/librustc_target/abi/call/arm.rs
index ff929f3..36971c1 100644
--- a/src/librustc_target/abi/call/arm.rs
+++ b/src/librustc_target/abi/call/arm.rs
@@ -21,14 +21,7 @@
RegKind::Vector => size.bits() == 64 || size.bits() == 128
};
- if valid_unit {
- Some(Uniform {
- unit,
- total: size
- })
- } else {
- None
- }
+ valid_unit.then_some(Uniform { unit, total: size })
})
}
diff --git a/src/librustc_target/abi/call/mod.rs b/src/librustc_target/abi/call/mod.rs
index 6f53577..5119464 100644
--- a/src/librustc_target/abi/call/mod.rs
+++ b/src/librustc_target/abi/call/mod.rs
@@ -416,11 +416,7 @@
// i686-pc-windows-msvc, it results in wrong stack offsets.
// attrs.pointee_align = Some(self.layout.align.abi);
- let extra_attrs = if self.layout.is_unsized() {
- Some(ArgAttributes::new())
- } else {
- None
- };
+ let extra_attrs = self.layout.is_unsized().then_some(ArgAttributes::new());
self.mode = PassMode::Indirect(attrs, extra_attrs);
}
diff --git a/src/librustc_target/abi/call/powerpc64.rs b/src/librustc_target/abi/call/powerpc64.rs
index f967a83..fe45948 100644
--- a/src/librustc_target/abi/call/powerpc64.rs
+++ b/src/librustc_target/abi/call/powerpc64.rs
@@ -32,14 +32,7 @@
RegKind::Vector => arg.layout.size.bits() == 128
};
- if valid_unit {
- Some(Uniform {
- unit,
- total: arg.layout.size
- })
- } else {
- None
- }
+ valid_unit.then_some(Uniform { unit, total: arg.layout.size })
})
}
diff --git a/src/librustc_target/abi/call/sparc64.rs b/src/librustc_target/abi/call/sparc64.rs
index fe2c427..32be7b8 100644
--- a/src/librustc_target/abi/call/sparc64.rs
+++ b/src/librustc_target/abi/call/sparc64.rs
@@ -20,14 +20,7 @@
RegKind::Vector => arg.layout.size.bits() == 128
};
- if valid_unit {
- Some(Uniform {
- unit,
- total: arg.layout.size
- })
- } else {
- None
- }
+ valid_unit.then_some(Uniform { unit, total: arg.layout.size })
})
}
diff --git a/src/librustc_target/abi/mod.rs b/src/librustc_target/abi/mod.rs
index ac78181..b0bc052 100644
--- a/src/librustc_target/abi/mod.rs
+++ b/src/librustc_target/abi/mod.rs
@@ -802,6 +802,14 @@
_ => false,
}
}
+
+ /// Returns `true` is this is a scalar type
+ pub fn is_scalar(&self) -> bool {
+ match *self {
+ Abi::Scalar(_) => true,
+ _ => false,
+ }
+ }
}
rustc_index::newtype_index! {
diff --git a/src/librustc_target/lib.rs b/src/librustc_target/lib.rs
index 5582eaf..6a1498e 100644
--- a/src/librustc_target/lib.rs
+++ b/src/librustc_target/lib.rs
@@ -10,6 +10,7 @@
#![doc(html_root_url = "https://doc.rust-lang.org/nightly/")]
#![feature(box_syntax)]
+#![feature(bool_to_option)]
#![feature(nll)]
#![feature(slice_patterns)]
diff --git a/src/librustc_target/spec/wasm32_base.rs b/src/librustc_target/spec/wasm32_base.rs
index 6f00245..e18a9e6 100644
--- a/src/librustc_target/spec/wasm32_base.rs
+++ b/src/librustc_target/spec/wasm32_base.rs
@@ -140,6 +140,9 @@
has_elf_tls: true,
tls_model: "local-exec".to_string(),
+ // gdb scripts don't work on wasm blobs
+ emit_debug_gdb_scripts: false,
+
.. Default::default()
}
}
diff --git a/src/librustc_typeck/check/coercion.rs b/src/librustc_typeck/check/coercion.rs
index 901a219..726b3ba 100644
--- a/src/librustc_typeck/check/coercion.rs
+++ b/src/librustc_typeck/check/coercion.rs
@@ -1284,9 +1284,25 @@
augment_error(&mut err);
}
+ if let Some(expr) = expression {
+ fcx.emit_coerce_suggestions(&mut err, expr, found, expected);
+ }
+
// Error possibly reported in `check_assign` so avoid emitting error again.
- err.emit_unless(expression.filter(|e| fcx.is_assign_to_bool(e, expected))
- .is_some());
+ let assign_to_bool = expression
+ // #67273: Use initial expected type as opposed to `expected`.
+ // Otherwise we end up using prior coercions in e.g. a `match` expression:
+ // ```
+ // match i {
+ // 0 => true, // Because of this...
+ // 1 => i = 1, // ...`expected == bool` now, but not when checking `i = 1`.
+ // _ => (),
+ // };
+ // ```
+ .filter(|e| fcx.is_assign_to_bool(e, self.expected_ty()))
+ .is_some();
+
+ err.emit_unless(assign_to_bool);
self.final_ty = Some(fcx.tcx.types.err);
}
diff --git a/src/librustc_typeck/check/demand.rs b/src/librustc_typeck/check/demand.rs
index 4331d44..16a55d2 100644
--- a/src/librustc_typeck/check/demand.rs
+++ b/src/librustc_typeck/check/demand.rs
@@ -15,6 +15,22 @@
use super::method::probe;
impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
+
+ pub fn emit_coerce_suggestions(
+ &self,
+ err: &mut DiagnosticBuilder<'_>,
+ expr: &hir::Expr,
+ expr_ty: Ty<'tcx>,
+ expected: Ty<'tcx>
+ ) {
+ self.annotate_expected_due_to_let_ty(err, expr);
+ self.suggest_compatible_variants(err, expr, expected, expr_ty);
+ self.suggest_ref_or_into(err, expr, expected, expr_ty);
+ self.suggest_boxing_when_appropriate(err, expr, expected, expr_ty);
+ self.suggest_missing_await(err, expr, expected, expr_ty);
+ }
+
+
// Requires that the two types unify, and prints an error message if
// they don't.
pub fn demand_suptype(&self, sp: Span, expected: Ty<'tcx>, actual: Ty<'tcx>) {
@@ -65,13 +81,13 @@
}
}
- pub fn demand_eqtype_pat(
+ pub fn demand_eqtype_pat_diag(
&self,
cause_span: Span,
expected: Ty<'tcx>,
actual: Ty<'tcx>,
match_expr_span: Option<Span>,
- ) {
+ ) -> Option<DiagnosticBuilder<'tcx>> {
let cause = if let Some(span) = match_expr_span {
self.cause(
cause_span,
@@ -80,9 +96,19 @@
} else {
self.misc(cause_span)
};
- self.demand_eqtype_with_origin(&cause, expected, actual).map(|mut err| err.emit());
+ self.demand_eqtype_with_origin(&cause, expected, actual)
}
+ pub fn demand_eqtype_pat(
+ &self,
+ cause_span: Span,
+ expected: Ty<'tcx>,
+ actual: Ty<'tcx>,
+ match_expr_span: Option<Span>,
+ ) {
+ self.demand_eqtype_pat_diag(cause_span, expected, actual, match_expr_span)
+ .map(|mut err| err.emit());
+ }
pub fn demand_coerce(&self,
expr: &hir::Expr,
@@ -127,11 +153,7 @@
return (expected, None)
}
- self.annotate_expected_due_to_let_ty(&mut err, expr);
- self.suggest_compatible_variants(&mut err, expr, expected, expr_ty);
- self.suggest_ref_or_into(&mut err, expr, expected, expr_ty);
- self.suggest_boxing_when_appropriate(&mut err, expr, expected, expr_ty);
- self.suggest_missing_await(&mut err, expr, expected, expr_ty);
+ self.emit_coerce_suggestions(&mut err, expr, expr_ty, expected);
(expected, Some(err))
}
diff --git a/src/librustc_typeck/check/expr.rs b/src/librustc_typeck/check/expr.rs
index 4766360..fc7d197 100644
--- a/src/librustc_typeck/check/expr.rs
+++ b/src/librustc_typeck/check/expr.rs
@@ -582,11 +582,21 @@
// If this is a break with a value, we need to type-check
// the expression. Get an expected type from the loop context.
let opt_coerce_to = {
+ // We should release `enclosing_breakables` before the `check_expr_with_hint`
+ // below, so can't move this block of code to the enclosing scope and share
+ // `ctxt` with the second `encloding_breakables` borrow below.
let mut enclosing_breakables = self.enclosing_breakables.borrow_mut();
- enclosing_breakables.find_breakable(target_id)
- .coerce
- .as_ref()
- .map(|coerce| coerce.expected_ty())
+ match enclosing_breakables.opt_find_breakable(target_id) {
+ Some(ctxt) =>
+ ctxt.coerce.as_ref().map(|coerce| coerce.expected_ty()),
+ None => { // Avoid ICE when `break` is inside a closure (#65383).
+ self.tcx.sess.delay_span_bug(
+ expr.span,
+ "break was outside loop, but no error was emitted",
+ );
+ return tcx.types.err;
+ }
+ }
};
// If the loop context is not a `loop { }`, then break with
@@ -861,6 +871,9 @@
let method = match self.lookup_method(rcvr_t, segment, span, expr, rcvr) {
Ok(method) => {
+ // We could add a "consider `foo::<params>`" suggestion here, but I wasn't able to
+ // trigger this codepath causing `structuraly_resolved_type` to emit an error.
+
self.write_method_call(expr.hir_id, method);
Ok(method)
}
diff --git a/src/librustc_typeck/check/intrinsic.rs b/src/librustc_typeck/check/intrinsic.rs
index 9f034e65..cec8311 100644
--- a/src/librustc_typeck/check/intrinsic.rs
+++ b/src/librustc_typeck/check/intrinsic.rs
@@ -1,7 +1,6 @@
//! Type-checking for the rust-intrinsic and platform-intrinsic
//! intrinsics that the compiler exposes.
-use rustc::middle::lang_items::PanicLocationLangItem;
use rustc::traits::{ObligationCause, ObligationCauseCode};
use rustc::ty::{self, TyCtxt, Ty};
use rustc::ty::subst::Subst;
@@ -148,15 +147,7 @@
], tcx.types.usize)
}
"rustc_peek" => (1, vec![param(0)], param(0)),
- "caller_location" => (
- 0,
- vec![],
- tcx.mk_imm_ref(
- tcx.lifetimes.re_static,
- tcx.type_of(tcx.require_lang_item(PanicLocationLangItem, None))
- .subst(tcx, tcx.mk_substs([tcx.lifetimes.re_static.into()].iter())),
- ),
- ),
+ "caller_location" => (0, vec![], tcx.caller_location_ty()),
"panic_if_uninhabited" => (1, Vec::new(), tcx.mk_unit()),
"init" => (1, Vec::new(), param(0)),
"uninit" => (1, Vec::new(), param(0)),
@@ -336,6 +327,7 @@
(1, vec![param(0), param(0)], param(0)),
"fadd_fast" | "fsub_fast" | "fmul_fast" | "fdiv_fast" | "frem_fast" =>
(1, vec![param(0), param(0)], param(0)),
+ "float_to_int_approx_unchecked" => (2, vec![ param(0) ], param(1)),
"assume" => (0, vec![tcx.types.bool], tcx.mk_unit()),
"likely" => (0, vec![tcx.types.bool], tcx.types.bool),
diff --git a/src/librustc_typeck/check/method/probe.rs b/src/librustc_typeck/check/method/probe.rs
index 9717190..9923081 100644
--- a/src/librustc_typeck/check/method/probe.rs
+++ b/src/librustc_typeck/check/method/probe.rs
@@ -1105,11 +1105,7 @@
r.map(|mut pick| {
pick.autoderefs = step.autoderefs;
pick.autoref = Some(mutbl);
- pick.unsize = if step.unsize {
- Some(self_ty)
- } else {
- None
- };
+ pick.unsize = step.unsize.then_some(self_ty);
pick
})
})
diff --git a/src/librustc_typeck/check/mod.rs b/src/librustc_typeck/check/mod.rs
index c7a0190..43e7bbc 100644
--- a/src/librustc_typeck/check/mod.rs
+++ b/src/librustc_typeck/check/mod.rs
@@ -103,6 +103,7 @@
use rustc_target::spec::abi::Abi;
use rustc::infer::opaque_types::OpaqueTypeDecl;
use rustc::infer::type_variable::{TypeVariableOrigin, TypeVariableOriginKind};
+use rustc::infer::error_reporting::TypeAnnotationNeeded::E0282;
use rustc::infer::unify_key::{ConstVariableOrigin, ConstVariableOriginKind};
use rustc::middle::region;
use rustc::mir::interpret::{ConstValue, GlobalId};
@@ -4584,8 +4585,6 @@
pointing_at_return_type = self.suggest_missing_return_type(
err, &fn_decl, expected, found, can_suggest);
}
- self.suggest_ref_or_into(err, expr, expected, found);
- self.suggest_boxing_when_appropriate(err, expr, expected, found);
pointing_at_return_type
}
@@ -4957,7 +4956,9 @@
ty: expected,
}));
let obligation = traits::Obligation::new(self.misc(sp), self.param_env, predicate);
+ debug!("suggest_missing_await: trying obligation {:?}", obligation);
if self.infcx.predicate_may_hold(&obligation) {
+ debug!("suggest_missing_await: obligation held: {:?}", obligation);
if let Ok(code) = self.sess().source_map().span_to_snippet(sp) {
err.span_suggestion(
sp,
@@ -4965,7 +4966,11 @@
format!("{}.await", code),
Applicability::MaybeIncorrect,
);
+ } else {
+ debug!("suggest_missing_await: no snippet for {:?}", sp);
}
+ } else {
+ debug!("suggest_missing_await: obligation did not hold: {:?}", obligation)
}
}
}
@@ -5355,7 +5360,7 @@
ty
} else {
if !self.is_tainted_by_errors() {
- self.need_type_info_err((**self).body_id, sp, ty)
+ self.need_type_info_err((**self).body_id, sp, ty, E0282)
.note("type must be known at this point")
.emit();
}
diff --git a/src/librustc_typeck/check/pat.rs b/src/librustc_typeck/check/pat.rs
index 9dd3bc6..71d1cd8 100644
--- a/src/librustc_typeck/check/pat.rs
+++ b/src/librustc_typeck/check/pat.rs
@@ -703,7 +703,10 @@
let pat_ty = pat_ty.fn_sig(tcx).output();
let pat_ty = pat_ty.no_bound_vars().expect("expected fn type");
- self.demand_eqtype_pat(pat.span, expected, pat_ty, match_arm_pat_span);
+ // Type-check the tuple struct pattern against the expected type.
+ let diag = self.demand_eqtype_pat_diag(pat.span, expected, pat_ty, match_arm_pat_span);
+ let had_err = diag.is_some();
+ diag.map(|mut err| err.emit());
// Type-check subpatterns.
if subpats.len() == variant.fields.len()
@@ -721,7 +724,7 @@
}
} else {
// Pattern has wrong number of fields.
- self.e0023(pat.span, res, qpath, subpats, &variant.fields, expected);
+ self.e0023(pat.span, res, qpath, subpats, &variant.fields, expected, had_err);
on_error();
return tcx.types.err;
}
@@ -734,8 +737,9 @@
res: Res,
qpath: &hir::QPath,
subpats: &'tcx [P<Pat>],
- fields: &[ty::FieldDef],
- expected: Ty<'tcx>
+ fields: &'tcx [ty::FieldDef],
+ expected: Ty<'tcx>,
+ had_err: bool,
) {
let subpats_ending = pluralize!(subpats.len());
let fields_ending = pluralize!(fields.len());
@@ -763,9 +767,12 @@
// More generally, the expected type wants a tuple variant with one field of an
// N-arity-tuple, e.g., `V_i((p_0, .., p_N))`. Meanwhile, the user supplied a pattern
// with the subpatterns directly in the tuple variant pattern, e.g., `V_i(p_0, .., p_N)`.
- let missing_parenthesis = match expected.kind {
- ty::Adt(_, substs) if fields.len() == 1 => {
- let field_ty = fields[0].ty(self.tcx, substs);
+ let missing_parenthesis = match (&expected.kind, fields, had_err) {
+ // #67037: only do this if we could sucessfully type-check the expected type against
+ // the tuple struct pattern. Otherwise the substs could get out of range on e.g.,
+ // `let P() = U;` where `P != U` with `struct P<T>(T);`.
+ (ty::Adt(_, substs), [field], false) => {
+ let field_ty = self.field_ty(pat_span, field, substs);
match field_ty.kind {
ty::Tuple(_) => field_ty.tuple_fields().count() == subpats.len(),
_ => false,
diff --git a/src/librustc_typeck/check/upvar.rs b/src/librustc_typeck/check/upvar.rs
index 3002459..c5a6c07 100644
--- a/src/librustc_typeck/check/upvar.rs
+++ b/src/librustc_typeck/check/upvar.rs
@@ -114,11 +114,7 @@
};
let infer_kind = if let UpvarSubsts::Closure(closure_substs) = substs {
- if self.closure_kind(closure_def_id, closure_substs).is_none() {
- Some(closure_substs)
- } else {
- None
- }
+ self.closure_kind(closure_def_id, closure_substs).is_none().then_some(closure_substs)
} else {
None
};
diff --git a/src/librustc_typeck/check/writeback.rs b/src/librustc_typeck/check/writeback.rs
index 3113e9b..35f25b3 100644
--- a/src/librustc_typeck/check/writeback.rs
+++ b/src/librustc_typeck/check/writeback.rs
@@ -8,6 +8,7 @@
use rustc::hir::def_id::{DefId, DefIndex};
use rustc::hir::intravisit::{self, NestedVisitorMap, Visitor};
use rustc::infer::InferCtxt;
+use rustc::infer::error_reporting::TypeAnnotationNeeded::E0282;
use rustc::ty::adjustment::{Adjust, Adjustment, PointerCast};
use rustc::ty::fold::{TypeFoldable, TypeFolder};
use rustc::ty::{self, Ty, TyCtxt};
@@ -717,7 +718,7 @@
fn report_error(&self, t: Ty<'tcx>) {
if !self.tcx.sess.has_errors() {
self.infcx
- .need_type_info_err(Some(self.body.id()), self.span.to_span(self.tcx), t)
+ .need_type_info_err(Some(self.body.id()), self.span.to_span(self.tcx), t, E0282)
.emit();
}
}
diff --git a/src/librustc_typeck/collect.rs b/src/librustc_typeck/collect.rs
index 6d6e768..b982979 100644
--- a/src/librustc_typeck/collect.rs
+++ b/src/librustc_typeck/collect.rs
@@ -2616,7 +2616,7 @@
tcx.sess,
attr.span,
E0737,
- "Rust ABI is required to use `#[track_caller]`"
+ "`#[track_caller]` requires Rust ABI"
).emit();
}
codegen_fn_attrs.flags |= CodegenFnAttrFlags::TRACK_CALLER;
diff --git a/src/librustc_typeck/lib.rs b/src/librustc_typeck/lib.rs
index c606fea..6a6294b 100644
--- a/src/librustc_typeck/lib.rs
+++ b/src/librustc_typeck/lib.rs
@@ -59,6 +59,7 @@
#![allow(non_camel_case_types)]
+#![feature(bool_to_option)]
#![feature(box_patterns)]
#![feature(box_syntax)]
#![feature(crate_visibility_modifier)]
diff --git a/src/librustdoc/Cargo.toml b/src/librustdoc/Cargo.toml
index e3de7fe..f282291 100644
--- a/src/librustdoc/Cargo.toml
+++ b/src/librustdoc/Cargo.toml
@@ -12,4 +12,6 @@
pulldown-cmark = { version = "0.5.3", default-features = false }
minifier = "0.0.33"
rayon = { version = "0.3.0", package = "rustc-rayon" }
+serde = { version = "1.0", features = ["derive"] }
+serde_json = "1.0"
tempfile = "3"
diff --git a/src/librustdoc/clean/auto_trait.rs b/src/librustdoc/clean/auto_trait.rs
index b7f5ed9..e198b00 100644
--- a/src/librustdoc/clean/auto_trait.rs
+++ b/src/librustdoc/clean/auto_trait.rs
@@ -1,10 +1,24 @@
use rustc::hir;
use rustc::traits::auto_trait::{self, AutoTraitResult};
-use rustc::ty::{self, TypeFoldable};
+use rustc::ty::{self, Region, RegionVid, TypeFoldable};
+use rustc::util::nodemap::FxHashSet;
+
use std::fmt::Debug;
use super::*;
+#[derive(Eq, PartialEq, Hash, Copy, Clone, Debug)]
+enum RegionTarget<'tcx> {
+ Region(Region<'tcx>),
+ RegionVid(RegionVid)
+}
+
+#[derive(Default, Debug, Clone)]
+struct RegionDeps<'tcx> {
+ larger: FxHashSet<RegionTarget<'tcx>>,
+ smaller: FxHashSet<RegionTarget<'tcx>>
+}
+
pub struct AutoTraitFinder<'a, 'tcx> {
pub cx: &'a core::DocContext<'tcx>,
pub f: auto_trait::AutoTraitFinder<'tcx>,
diff --git a/src/librustdoc/clean/cfg.rs b/src/librustdoc/clean/cfg.rs
index 078948c..fb2cce3 100644
--- a/src/librustdoc/clean/cfg.rs
+++ b/src/librustdoc/clean/cfg.rs
@@ -209,6 +209,9 @@
impl ops::BitAndAssign for Cfg {
fn bitand_assign(&mut self, other: Cfg) {
+ if *self == other {
+ return;
+ }
match (self, other) {
(&mut Cfg::False, _) | (_, Cfg::True) => {},
(s, Cfg::False) => *s = Cfg::False,
@@ -238,6 +241,9 @@
impl ops::BitOrAssign for Cfg {
fn bitor_assign(&mut self, other: Cfg) {
+ if *self == other {
+ return;
+ }
match (self, other) {
(&mut Cfg::True, _) | (_, Cfg::False) => {},
(s, Cfg::True) => *s = Cfg::True,
diff --git a/src/librustdoc/clean/mod.rs b/src/librustdoc/clean/mod.rs
index 4d8d004..e5f684c 100644
--- a/src/librustdoc/clean/mod.rs
+++ b/src/librustdoc/clean/mod.rs
@@ -1,16 +1,15 @@
-// ignore-tidy-filelength
-
//! This module contains the "cleaned" pieces of the AST, and the functions
//! that clean them.
pub mod inline;
pub mod cfg;
-mod simplify;
+pub mod utils;
mod auto_trait;
mod blanket_impl;
+mod simplify;
+pub mod types;
use rustc_index::vec::{IndexVec, Idx};
-use rustc_target::spec::abi::Abi;
use rustc_typeck::hir_ty_to_ty;
use rustc::infer::region_constraints::{RegionConstraintData, Constraint};
use rustc::middle::resolve_lifetime as rl;
@@ -19,63 +18,42 @@
use rustc::mir::interpret::GlobalId;
use rustc::hir;
use rustc::hir::def::{CtorKind, DefKind, Res};
-use rustc::hir::def_id::{CrateNum, DefId, CRATE_DEF_INDEX, LOCAL_CRATE};
+use rustc::hir::def_id::{CrateNum, DefId, CRATE_DEF_INDEX};
use rustc::hir::ptr::P;
-use rustc::ty::subst::{InternalSubsts, SubstsRef, GenericArgKind};
-use rustc::ty::{self, DefIdTree, TyCtxt, Region, RegionVid, Ty, AdtKind};
+use rustc::ty::subst::InternalSubsts;
+use rustc::ty::{self, TyCtxt, Ty, AdtKind};
use rustc::ty::fold::TypeFolder;
-use rustc::ty::layout::VariantIdx;
use rustc::util::nodemap::{FxHashMap, FxHashSet};
-use syntax::ast::{self, Attribute, AttrStyle, AttrKind, Ident};
+use syntax::ast::{self, Ident};
use syntax::attr;
-use syntax::util::comments;
-use syntax::source_map::DUMMY_SP;
-use syntax_pos::symbol::{Symbol, kw, sym};
+use syntax_pos::symbol::{kw, sym};
use syntax_pos::hygiene::MacroKind;
-use syntax_pos::{self, Pos, FileName};
+use syntax_pos::{self, Pos};
use std::collections::hash_map::Entry;
-use std::fmt;
-use std::hash::{Hash, Hasher};
+use std::hash::Hash;
use std::default::Default;
-use std::{mem, slice, vec};
-use std::num::NonZeroU32;
-use std::iter::FromIterator;
+use std::{mem, vec};
use std::rc::Rc;
-use std::cell::RefCell;
-use std::sync::Arc;
use std::u32;
use crate::core::{self, DocContext, ImplTraitParam};
use crate::doctree;
-use crate::html::render::{cache, ExternalLocation};
-use crate::html::item_type::ItemType;
+use utils::*;
-use self::cfg::Cfg;
-use self::auto_trait::AutoTraitFinder;
-use self::blanket_impl::BlanketImplFinder;
+pub use utils::{get_auto_trait_and_blanket_impls, krate, register_res};
-pub use self::Type::*;
-pub use self::Mutability::*;
-pub use self::ItemEnum::*;
-pub use self::SelfTy::*;
-pub use self::FunctionRetTy::*;
-pub use self::Visibility::{Public, Inherited};
-
-thread_local!(pub static MAX_DEF_ID: RefCell<FxHashMap<CrateNum, DefId>> = Default::default());
+pub use self::types::*;
+pub use self::types::Type::*;
+pub use self::types::Mutability::*;
+pub use self::types::ItemEnum::*;
+pub use self::types::SelfTy::*;
+pub use self::types::FunctionRetTy::*;
+pub use self::types::Visibility::{Public, Inherited};
const FN_OUTPUT_NAME: &'static str = "Output";
-// extract the stability index for a node from tcx, if possible
-fn get_stability(cx: &DocContext<'_>, def_id: DefId) -> Option<Stability> {
- cx.tcx.lookup_stability(def_id).clean(cx)
-}
-
-fn get_deprecation(cx: &DocContext<'_>, def_id: DefId) -> Option<Deprecation> {
- cx.tcx.lookup_deprecation(def_id).clean(cx)
-}
-
pub trait Clean<T> {
fn clean(&self, cx: &DocContext<'_>) -> T;
}
@@ -122,115 +100,6 @@
}
}
-#[derive(Clone, Debug)]
-pub struct Crate {
- pub name: String,
- pub version: Option<String>,
- pub src: FileName,
- pub module: Option<Item>,
- pub externs: Vec<(CrateNum, ExternalCrate)>,
- pub primitives: Vec<(DefId, PrimitiveType, Attributes)>,
- // These are later on moved into `CACHEKEY`, leaving the map empty.
- // Only here so that they can be filtered through the rustdoc passes.
- pub external_traits: Rc<RefCell<FxHashMap<DefId, Trait>>>,
- pub masked_crates: FxHashSet<CrateNum>,
- pub collapsed: bool,
-}
-
-pub fn krate(mut cx: &mut DocContext<'_>) -> Crate {
- use crate::visit_lib::LibEmbargoVisitor;
-
- let krate = cx.tcx.hir().krate();
- let module = crate::visit_ast::RustdocVisitor::new(&mut cx).visit(krate);
-
- let mut r = cx.renderinfo.get_mut();
- r.deref_trait_did = cx.tcx.lang_items().deref_trait();
- r.deref_mut_trait_did = cx.tcx.lang_items().deref_mut_trait();
- r.owned_box_did = cx.tcx.lang_items().owned_box();
-
- let mut externs = Vec::new();
- for &cnum in cx.tcx.crates().iter() {
- externs.push((cnum, cnum.clean(cx)));
- // Analyze doc-reachability for extern items
- LibEmbargoVisitor::new(&mut cx).visit_lib(cnum);
- }
- externs.sort_by(|&(a, _), &(b, _)| a.cmp(&b));
-
- // Clean the crate, translating the entire libsyntax AST to one that is
- // understood by rustdoc.
- let mut module = module.clean(cx);
- let mut masked_crates = FxHashSet::default();
-
- match module.inner {
- ModuleItem(ref module) => {
- for it in &module.items {
- // `compiler_builtins` should be masked too, but we can't apply
- // `#[doc(masked)]` to the injected `extern crate` because it's unstable.
- if it.is_extern_crate()
- && (it.attrs.has_doc_flag(sym::masked)
- || cx.tcx.is_compiler_builtins(it.def_id.krate))
- {
- masked_crates.insert(it.def_id.krate);
- }
- }
- }
- _ => unreachable!(),
- }
-
- let ExternalCrate { name, src, primitives, keywords, .. } = LOCAL_CRATE.clean(cx);
- {
- let m = match module.inner {
- ModuleItem(ref mut m) => m,
- _ => unreachable!(),
- };
- m.items.extend(primitives.iter().map(|&(def_id, prim, ref attrs)| {
- Item {
- source: Span::empty(),
- name: Some(prim.to_url_str().to_string()),
- attrs: attrs.clone(),
- visibility: Public,
- stability: get_stability(cx, def_id),
- deprecation: get_deprecation(cx, def_id),
- def_id,
- inner: PrimitiveItem(prim),
- }
- }));
- m.items.extend(keywords.into_iter().map(|(def_id, kw, attrs)| {
- Item {
- source: Span::empty(),
- name: Some(kw.clone()),
- attrs,
- visibility: Public,
- stability: get_stability(cx, def_id),
- deprecation: get_deprecation(cx, def_id),
- def_id,
- inner: KeywordItem(kw),
- }
- }));
- }
-
- Crate {
- name,
- version: None,
- src,
- module: Some(module),
- externs,
- primitives,
- external_traits: cx.external_traits.clone(),
- masked_crates,
- collapsed: false,
- }
-}
-
-#[derive(Clone, Debug)]
-pub struct ExternalCrate {
- pub name: String,
- pub src: FileName,
- pub attrs: Attributes,
- pub primitives: Vec<(DefId, PrimitiveType, Attributes)>,
- pub keywords: Vec<(DefId, String, Attributes)>,
-}
-
impl Clean<ExternalCrate> for CrateNum {
fn clean(&self, cx: &DocContext<'_>) -> ExternalCrate {
let root = DefId { krate: *self, index: CRATE_DEF_INDEX };
@@ -351,237 +220,6 @@
}
}
-/// Anything with a source location and set of attributes and, optionally, a
-/// name. That is, anything that can be documented. This doesn't correspond
-/// directly to the AST's concept of an item; it's a strict superset.
-#[derive(Clone)]
-pub struct Item {
- /// Stringified span
- pub source: Span,
- /// Not everything has a name. E.g., impls
- pub name: Option<String>,
- pub attrs: Attributes,
- pub inner: ItemEnum,
- pub visibility: Visibility,
- pub def_id: DefId,
- pub stability: Option<Stability>,
- pub deprecation: Option<Deprecation>,
-}
-
-impl fmt::Debug for Item {
- fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result {
-
- let fake = MAX_DEF_ID.with(|m| m.borrow().get(&self.def_id.krate)
- .map(|id| self.def_id >= *id).unwrap_or(false));
- let def_id: &dyn fmt::Debug = if fake { &"**FAKE**" } else { &self.def_id };
-
- fmt.debug_struct("Item")
- .field("source", &self.source)
- .field("name", &self.name)
- .field("attrs", &self.attrs)
- .field("inner", &self.inner)
- .field("visibility", &self.visibility)
- .field("def_id", def_id)
- .field("stability", &self.stability)
- .field("deprecation", &self.deprecation)
- .finish()
- }
-}
-
-impl Item {
- /// Finds the `doc` attribute as a NameValue and returns the corresponding
- /// value found.
- pub fn doc_value(&self) -> Option<&str> {
- self.attrs.doc_value()
- }
- /// Finds all `doc` attributes as NameValues and returns their corresponding values, joined
- /// with newlines.
- pub fn collapsed_doc_value(&self) -> Option<String> {
- self.attrs.collapsed_doc_value()
- }
-
- pub fn links(&self) -> Vec<(String, String)> {
- self.attrs.links(&self.def_id.krate)
- }
-
- pub fn is_crate(&self) -> bool {
- match self.inner {
- StrippedItem(box ModuleItem(Module { is_crate: true, ..})) |
- ModuleItem(Module { is_crate: true, ..}) => true,
- _ => false,
- }
- }
- pub fn is_mod(&self) -> bool {
- self.type_() == ItemType::Module
- }
- pub fn is_trait(&self) -> bool {
- self.type_() == ItemType::Trait
- }
- pub fn is_struct(&self) -> bool {
- self.type_() == ItemType::Struct
- }
- pub fn is_enum(&self) -> bool {
- self.type_() == ItemType::Enum
- }
- pub fn is_variant(&self) -> bool {
- self.type_() == ItemType::Variant
- }
- pub fn is_associated_type(&self) -> bool {
- self.type_() == ItemType::AssocType
- }
- pub fn is_associated_const(&self) -> bool {
- self.type_() == ItemType::AssocConst
- }
- pub fn is_method(&self) -> bool {
- self.type_() == ItemType::Method
- }
- pub fn is_ty_method(&self) -> bool {
- self.type_() == ItemType::TyMethod
- }
- pub fn is_typedef(&self) -> bool {
- self.type_() == ItemType::Typedef
- }
- pub fn is_primitive(&self) -> bool {
- self.type_() == ItemType::Primitive
- }
- pub fn is_union(&self) -> bool {
- self.type_() == ItemType::Union
- }
- pub fn is_import(&self) -> bool {
- self.type_() == ItemType::Import
- }
- pub fn is_extern_crate(&self) -> bool {
- self.type_() == ItemType::ExternCrate
- }
- pub fn is_keyword(&self) -> bool {
- self.type_() == ItemType::Keyword
- }
-
- pub fn is_stripped(&self) -> bool {
- match self.inner { StrippedItem(..) => true, _ => false }
- }
- pub fn has_stripped_fields(&self) -> Option<bool> {
- match self.inner {
- StructItem(ref _struct) => Some(_struct.fields_stripped),
- UnionItem(ref union) => Some(union.fields_stripped),
- VariantItem(Variant { kind: VariantKind::Struct(ref vstruct)} ) => {
- Some(vstruct.fields_stripped)
- },
- _ => None,
- }
- }
-
- pub fn stability_class(&self) -> Option<String> {
- self.stability.as_ref().and_then(|ref s| {
- let mut classes = Vec::with_capacity(2);
-
- if s.level == stability::Unstable {
- classes.push("unstable");
- }
-
- if s.deprecation.is_some() {
- classes.push("deprecated");
- }
-
- if classes.len() != 0 {
- Some(classes.join(" "))
- } else {
- None
- }
- })
- }
-
- pub fn stable_since(&self) -> Option<&str> {
- self.stability.as_ref().map(|s| &s.since[..])
- }
-
- pub fn is_non_exhaustive(&self) -> bool {
- self.attrs.other_attrs.iter()
- .any(|a| a.check_name(sym::non_exhaustive))
- }
-
- /// Returns a documentation-level item type from the item.
- pub fn type_(&self) -> ItemType {
- ItemType::from(self)
- }
-
- /// Returns the info in the item's `#[deprecated]` or `#[rustc_deprecated]` attributes.
- ///
- /// If the item is not deprecated, returns `None`.
- pub fn deprecation(&self) -> Option<&Deprecation> {
- self.deprecation
- .as_ref()
- .or_else(|| self.stability.as_ref().and_then(|s| s.deprecation.as_ref()))
- }
- pub fn is_default(&self) -> bool {
- match self.inner {
- ItemEnum::MethodItem(ref meth) => {
- if let Some(defaultness) = meth.defaultness {
- defaultness.has_value() && !defaultness.is_final()
- } else {
- false
- }
- }
- _ => false,
- }
- }
-}
-
-#[derive(Clone, Debug)]
-pub enum ItemEnum {
- ExternCrateItem(String, Option<String>),
- ImportItem(Import),
- StructItem(Struct),
- UnionItem(Union),
- EnumItem(Enum),
- FunctionItem(Function),
- ModuleItem(Module),
- TypedefItem(Typedef, bool /* is associated type */),
- OpaqueTyItem(OpaqueTy, bool /* is associated type */),
- StaticItem(Static),
- ConstantItem(Constant),
- TraitItem(Trait),
- TraitAliasItem(TraitAlias),
- ImplItem(Impl),
- /// A method signature only. Used for required methods in traits (ie,
- /// non-default-methods).
- TyMethodItem(TyMethod),
- /// A method with a body.
- MethodItem(Method),
- StructFieldItem(Type),
- VariantItem(Variant),
- /// `fn`s from an extern block
- ForeignFunctionItem(Function),
- /// `static`s from an extern block
- ForeignStaticItem(Static),
- /// `type`s from an extern block
- ForeignTypeItem,
- MacroItem(Macro),
- ProcMacroItem(ProcMacro),
- PrimitiveItem(PrimitiveType),
- AssocConstItem(Type, Option<String>),
- AssocTypeItem(Vec<GenericBound>, Option<Type>),
- /// An item that has been stripped by a rustdoc pass
- StrippedItem(Box<ItemEnum>),
- KeywordItem(String),
-}
-
-impl ItemEnum {
- pub fn is_associated(&self) -> bool {
- match *self {
- ItemEnum::TypedefItem(_, _) |
- ItemEnum::AssocTypeItem(_, _) => true,
- _ => false,
- }
- }
-}
-
-#[derive(Clone, Debug)]
-pub struct Module {
- pub items: Vec<Item>,
- pub is_crate: bool,
-}
-
impl Clean<Item> for doctree::Module<'_> {
fn clean(&self, cx: &DocContext<'_>) -> Item {
let name = if self.name.is_some() {
@@ -645,465 +283,12 @@
}
}
-pub struct ListAttributesIter<'a> {
- attrs: slice::Iter<'a, ast::Attribute>,
- current_list: vec::IntoIter<ast::NestedMetaItem>,
- name: Symbol,
-}
-
-impl<'a> Iterator for ListAttributesIter<'a> {
- type Item = ast::NestedMetaItem;
-
- fn next(&mut self) -> Option<Self::Item> {
- if let Some(nested) = self.current_list.next() {
- return Some(nested);
- }
-
- for attr in &mut self.attrs {
- if let Some(list) = attr.meta_item_list() {
- if attr.check_name(self.name) {
- self.current_list = list.into_iter();
- if let Some(nested) = self.current_list.next() {
- return Some(nested);
- }
- }
- }
- }
-
- None
- }
-
- fn size_hint(&self) -> (usize, Option<usize>) {
- let lower = self.current_list.len();
- (lower, None)
- }
-}
-
-pub trait AttributesExt {
- /// Finds an attribute as List and returns the list of attributes nested inside.
- fn lists(&self, name: Symbol) -> ListAttributesIter<'_>;
-}
-
-impl AttributesExt for [ast::Attribute] {
- fn lists(&self, name: Symbol) -> ListAttributesIter<'_> {
- ListAttributesIter {
- attrs: self.iter(),
- current_list: Vec::new().into_iter(),
- name,
- }
- }
-}
-
-pub trait NestedAttributesExt {
- /// Returns `true` if the attribute list contains a specific `Word`
- fn has_word(self, word: Symbol) -> bool;
-}
-
-impl<I: IntoIterator<Item=ast::NestedMetaItem>> NestedAttributesExt for I {
- fn has_word(self, word: Symbol) -> bool {
- self.into_iter().any(|attr| attr.is_word() && attr.check_name(word))
- }
-}
-
-/// A portion of documentation, extracted from a `#[doc]` attribute.
-///
-/// Each variant contains the line number within the complete doc-comment where the fragment
-/// starts, as well as the Span where the corresponding doc comment or attribute is located.
-///
-/// Included files are kept separate from inline doc comments so that proper line-number
-/// information can be given when a doctest fails. Sugared doc comments and "raw" doc comments are
-/// kept separate because of issue #42760.
-#[derive(Clone, PartialEq, Eq, Debug, Hash)]
-pub enum DocFragment {
- /// A doc fragment created from a `///` or `//!` doc comment.
- SugaredDoc(usize, syntax_pos::Span, String),
- /// A doc fragment created from a "raw" `#[doc=""]` attribute.
- RawDoc(usize, syntax_pos::Span, String),
- /// A doc fragment created from a `#[doc(include="filename")]` attribute. Contains both the
- /// given filename and the file contents.
- Include(usize, syntax_pos::Span, String, String),
-}
-
-impl DocFragment {
- pub fn as_str(&self) -> &str {
- match *self {
- DocFragment::SugaredDoc(_, _, ref s) => &s[..],
- DocFragment::RawDoc(_, _, ref s) => &s[..],
- DocFragment::Include(_, _, _, ref s) => &s[..],
- }
- }
-
- pub fn span(&self) -> syntax_pos::Span {
- match *self {
- DocFragment::SugaredDoc(_, span, _) |
- DocFragment::RawDoc(_, span, _) |
- DocFragment::Include(_, span, _, _) => span,
- }
- }
-}
-
-impl<'a> FromIterator<&'a DocFragment> for String {
- fn from_iter<T>(iter: T) -> Self
- where
- T: IntoIterator<Item = &'a DocFragment>
- {
- iter.into_iter().fold(String::new(), |mut acc, frag| {
- if !acc.is_empty() {
- acc.push('\n');
- }
- match *frag {
- DocFragment::SugaredDoc(_, _, ref docs)
- | DocFragment::RawDoc(_, _, ref docs)
- | DocFragment::Include(_, _, _, ref docs) =>
- acc.push_str(docs),
- }
-
- acc
- })
- }
-}
-
-#[derive(Clone, Debug, Default)]
-pub struct Attributes {
- pub doc_strings: Vec<DocFragment>,
- pub other_attrs: Vec<ast::Attribute>,
- pub cfg: Option<Arc<Cfg>>,
- pub span: Option<syntax_pos::Span>,
- /// map from Rust paths to resolved defs and potential URL fragments
- pub links: Vec<(String, Option<DefId>, Option<String>)>,
- pub inner_docs: bool,
-}
-
-impl Attributes {
- /// Extracts the content from an attribute `#[doc(cfg(content))]`.
- fn extract_cfg(mi: &ast::MetaItem) -> Option<&ast::MetaItem> {
- use syntax::ast::NestedMetaItem::MetaItem;
-
- if let ast::MetaItemKind::List(ref nmis) = mi.kind {
- if nmis.len() == 1 {
- if let MetaItem(ref cfg_mi) = nmis[0] {
- if cfg_mi.check_name(sym::cfg) {
- if let ast::MetaItemKind::List(ref cfg_nmis) = cfg_mi.kind {
- if cfg_nmis.len() == 1 {
- if let MetaItem(ref content_mi) = cfg_nmis[0] {
- return Some(content_mi);
- }
- }
- }
- }
- }
- }
- }
-
- None
- }
-
- /// Reads a `MetaItem` from within an attribute, looks for whether it is a
- /// `#[doc(include="file")]`, and returns the filename and contents of the file as loaded from
- /// its expansion.
- fn extract_include(mi: &ast::MetaItem)
- -> Option<(String, String)>
- {
- mi.meta_item_list().and_then(|list| {
- for meta in list {
- if meta.check_name(sym::include) {
- // the actual compiled `#[doc(include="filename")]` gets expanded to
- // `#[doc(include(file="filename", contents="file contents")]` so we need to
- // look for that instead
- return meta.meta_item_list().and_then(|list| {
- let mut filename: Option<String> = None;
- let mut contents: Option<String> = None;
-
- for it in list {
- if it.check_name(sym::file) {
- if let Some(name) = it.value_str() {
- filename = Some(name.to_string());
- }
- } else if it.check_name(sym::contents) {
- if let Some(docs) = it.value_str() {
- contents = Some(docs.to_string());
- }
- }
- }
-
- if let (Some(filename), Some(contents)) = (filename, contents) {
- Some((filename, contents))
- } else {
- None
- }
- });
- }
- }
-
- None
- })
- }
-
- pub fn has_doc_flag(&self, flag: Symbol) -> bool {
- for attr in &self.other_attrs {
- if !attr.check_name(sym::doc) { continue; }
-
- if let Some(items) = attr.meta_item_list() {
- if items.iter().filter_map(|i| i.meta_item()).any(|it| it.check_name(flag)) {
- return true;
- }
- }
- }
-
- false
- }
-
- pub fn from_ast(diagnostic: &::errors::Handler,
- attrs: &[ast::Attribute]) -> Attributes {
- let mut doc_strings = vec![];
- let mut sp = None;
- let mut cfg = Cfg::True;
- let mut doc_line = 0;
-
- /// If `attr` is a doc comment, strips the leading and (if present)
- /// trailing comments symbols, e.g. `///`, `/**`, and `*/`. Otherwise,
- /// returns `attr` unchanged.
- pub fn with_doc_comment_markers_stripped<T>(
- attr: &Attribute,
- f: impl FnOnce(&Attribute) -> T
- ) -> T {
- match attr.kind {
- AttrKind::Normal(_) => {
- f(attr)
- }
- AttrKind::DocComment(comment) => {
- let comment =
- Symbol::intern(&comments::strip_doc_comment_decoration(&comment.as_str()));
- f(&Attribute {
- kind: AttrKind::DocComment(comment),
- id: attr.id,
- style: attr.style,
- span: attr.span,
- })
- }
- }
- }
-
- let other_attrs = attrs.iter().filter_map(|attr| {
- with_doc_comment_markers_stripped(attr, |attr| {
- if attr.check_name(sym::doc) {
- if let Some(mi) = attr.meta() {
- if let Some(value) = mi.value_str() {
- // Extracted #[doc = "..."]
- let value = value.to_string();
- let line = doc_line;
- doc_line += value.lines().count();
-
- if attr.is_doc_comment() {
- doc_strings.push(DocFragment::SugaredDoc(line, attr.span, value));
- } else {
- doc_strings.push(DocFragment::RawDoc(line, attr.span, value));
- }
-
- if sp.is_none() {
- sp = Some(attr.span);
- }
- return None;
- } else if let Some(cfg_mi) = Attributes::extract_cfg(&mi) {
- // Extracted #[doc(cfg(...))]
- match Cfg::parse(cfg_mi) {
- Ok(new_cfg) => cfg &= new_cfg,
- Err(e) => diagnostic.span_err(e.span, e.msg),
- }
- return None;
- } else if let Some((filename, contents)) = Attributes::extract_include(&mi)
- {
- let line = doc_line;
- doc_line += contents.lines().count();
- doc_strings.push(DocFragment::Include(line,
- attr.span,
- filename,
- contents));
- }
- }
- }
- Some(attr.clone())
- })
- }).collect();
-
- // treat #[target_feature(enable = "feat")] attributes as if they were
- // #[doc(cfg(target_feature = "feat"))] attributes as well
- for attr in attrs.lists(sym::target_feature) {
- if attr.check_name(sym::enable) {
- if let Some(feat) = attr.value_str() {
- let meta = attr::mk_name_value_item_str(
- Ident::with_dummy_span(sym::target_feature), feat, DUMMY_SP
- );
- if let Ok(feat_cfg) = Cfg::parse(&meta) {
- cfg &= feat_cfg;
- }
- }
- }
- }
-
- let inner_docs = attrs.iter()
- .filter(|a| a.check_name(sym::doc))
- .next()
- .map_or(true, |a| a.style == AttrStyle::Inner);
-
- Attributes {
- doc_strings,
- other_attrs,
- cfg: if cfg == Cfg::True { None } else { Some(Arc::new(cfg)) },
- span: sp,
- links: vec![],
- inner_docs,
- }
- }
-
- /// Finds the `doc` attribute as a NameValue and returns the corresponding
- /// value found.
- pub fn doc_value(&self) -> Option<&str> {
- self.doc_strings.first().map(|s| s.as_str())
- }
-
- /// Finds all `doc` attributes as NameValues and returns their corresponding values, joined
- /// with newlines.
- pub fn collapsed_doc_value(&self) -> Option<String> {
- if !self.doc_strings.is_empty() {
- Some(self.doc_strings.iter().collect())
- } else {
- None
- }
- }
-
- /// Gets links as a vector
- ///
- /// Cache must be populated before call
- pub fn links(&self, krate: &CrateNum) -> Vec<(String, String)> {
- use crate::html::format::href;
-
- self.links.iter().filter_map(|&(ref s, did, ref fragment)| {
- match did {
- Some(did) => {
- if let Some((mut href, ..)) = href(did) {
- if let Some(ref fragment) = *fragment {
- href.push_str("#");
- href.push_str(fragment);
- }
- Some((s.clone(), href))
- } else {
- None
- }
- }
- None => {
- if let Some(ref fragment) = *fragment {
- let cache = cache();
- let url = match cache.extern_locations.get(krate) {
- Some(&(_, ref src, ExternalLocation::Local)) =>
- src.to_str().expect("invalid file path"),
- Some(&(_, _, ExternalLocation::Remote(ref s))) => s,
- Some(&(_, _, ExternalLocation::Unknown)) | None =>
- "https://doc.rust-lang.org/nightly",
- };
- // This is a primitive so the url is done "by hand".
- let tail = fragment.find('#').unwrap_or_else(|| fragment.len());
- Some((s.clone(),
- format!("{}{}std/primitive.{}.html{}",
- url,
- if !url.ends_with('/') { "/" } else { "" },
- &fragment[..tail],
- &fragment[tail..])))
- } else {
- panic!("This isn't a primitive?!");
- }
- }
- }
- }).collect()
- }
-}
-
-impl PartialEq for Attributes {
- fn eq(&self, rhs: &Self) -> bool {
- self.doc_strings == rhs.doc_strings &&
- self.cfg == rhs.cfg &&
- self.span == rhs.span &&
- self.links == rhs.links &&
- self.other_attrs.iter().map(|attr| attr.id).eq(rhs.other_attrs.iter().map(|attr| attr.id))
- }
-}
-
-impl Eq for Attributes {}
-
-impl Hash for Attributes {
- fn hash<H: Hasher>(&self, hasher: &mut H) {
- self.doc_strings.hash(hasher);
- self.cfg.hash(hasher);
- self.span.hash(hasher);
- self.links.hash(hasher);
- for attr in &self.other_attrs {
- attr.id.hash(hasher);
- }
- }
-}
-
-impl AttributesExt for Attributes {
- fn lists(&self, name: Symbol) -> ListAttributesIter<'_> {
- self.other_attrs.lists(name)
- }
-}
-
impl Clean<Attributes> for [ast::Attribute] {
fn clean(&self, cx: &DocContext<'_>) -> Attributes {
Attributes::from_ast(cx.sess().diagnostic(), self)
}
}
-#[derive(Clone, PartialEq, Eq, Debug, Hash)]
-pub enum GenericBound {
- TraitBound(PolyTrait, hir::TraitBoundModifier),
- Outlives(Lifetime),
-}
-
-impl GenericBound {
- fn maybe_sized(cx: &DocContext<'_>) -> GenericBound {
- let did = cx.tcx.require_lang_item(lang_items::SizedTraitLangItem, None);
- let empty = cx.tcx.intern_substs(&[]);
- let path = external_path(cx, cx.tcx.item_name(did),
- Some(did), false, vec![], empty);
- inline::record_extern_fqn(cx, did, TypeKind::Trait);
- GenericBound::TraitBound(PolyTrait {
- trait_: ResolvedPath {
- path,
- param_names: None,
- did,
- is_generic: false,
- },
- generic_params: Vec::new(),
- }, hir::TraitBoundModifier::Maybe)
- }
-
- fn is_sized_bound(&self, cx: &DocContext<'_>) -> bool {
- use rustc::hir::TraitBoundModifier as TBM;
- if let GenericBound::TraitBound(PolyTrait { ref trait_, .. }, TBM::None) = *self {
- if trait_.def_id() == cx.tcx.lang_items().sized_trait() {
- return true;
- }
- }
- false
- }
-
- fn get_poly_trait(&self) -> Option<PolyTrait> {
- if let GenericBound::TraitBound(ref p, _) = *self {
- return Some(p.clone())
- }
- None
- }
-
- fn get_trait_type(&self) -> Option<Type> {
- if let GenericBound::TraitBound(PolyTrait { ref trait_, .. }, _) = *self {
- Some(trait_.clone())
- } else {
- None
- }
- }
-}
-
impl Clean<GenericBound> for hir::GenericBound {
fn clean(&self, cx: &DocContext<'_>) -> GenericBound {
match *self {
@@ -1115,66 +300,6 @@
}
}
-fn external_generic_args(
- cx: &DocContext<'_>,
- trait_did: Option<DefId>,
- has_self: bool,
- bindings: Vec<TypeBinding>,
- substs: SubstsRef<'_>,
-) -> GenericArgs {
- let mut skip_self = has_self;
- let mut ty_kind = None;
- let args: Vec<_> = substs.iter().filter_map(|kind| match kind.unpack() {
- GenericArgKind::Lifetime(lt) => {
- lt.clean(cx).and_then(|lt| Some(GenericArg::Lifetime(lt)))
- }
- GenericArgKind::Type(_) if skip_self => {
- skip_self = false;
- None
- }
- GenericArgKind::Type(ty) => {
- ty_kind = Some(&ty.kind);
- Some(GenericArg::Type(ty.clean(cx)))
- }
- GenericArgKind::Const(ct) => Some(GenericArg::Const(ct.clean(cx))),
- }).collect();
-
- match trait_did {
- // Attempt to sugar an external path like Fn<(A, B,), C> to Fn(A, B) -> C
- Some(did) if cx.tcx.lang_items().fn_trait_kind(did).is_some() => {
- assert!(ty_kind.is_some());
- let inputs = match ty_kind {
- Some(ty::Tuple(ref tys)) => tys.iter().map(|t| t.expect_ty().clean(cx)).collect(),
- _ => return GenericArgs::AngleBracketed { args, bindings },
- };
- let output = None;
- // FIXME(#20299) return type comes from a projection now
- // match types[1].kind {
- // ty::Tuple(ref v) if v.is_empty() => None, // -> ()
- // _ => Some(types[1].clean(cx))
- // };
- GenericArgs::Parenthesized { inputs, output }
- },
- _ => {
- GenericArgs::AngleBracketed { args, bindings }
- }
- }
-}
-
-// trait_did should be set to a trait's DefId if called on a TraitRef, in order to sugar
-// from Fn<(A, B,), C> to Fn(A, B) -> C
-fn external_path(cx: &DocContext<'_>, name: Symbol, trait_did: Option<DefId>, has_self: bool,
- bindings: Vec<TypeBinding>, substs: SubstsRef<'_>) -> Path {
- Path {
- global: false,
- res: Res::Err,
- segments: vec![PathSegment {
- name: name.to_string(),
- args: external_generic_args(cx, trait_did, has_self, bindings, substs)
- }],
- }
-}
-
impl<'a, 'tcx> Clean<GenericBound> for (&'a ty::TraitRef<'tcx>, Vec<TypeBinding>) {
fn clean(&self, cx: &DocContext<'_>) -> GenericBound {
let (trait_ref, ref bounds) = *self;
@@ -1237,21 +362,6 @@
}
}
-#[derive(Clone, PartialEq, Eq, Debug, Hash)]
-pub struct Lifetime(String);
-
-impl Lifetime {
- pub fn get_ref<'a>(&'a self) -> &'a str {
- let Lifetime(ref s) = *self;
- let s: &'a str = s;
- s
- }
-
- pub fn statik() -> Lifetime {
- Lifetime("'static".to_string())
- }
-}
-
impl Clean<Lifetime> for hir::Lifetime {
fn clean(&self, cx: &DocContext<'_>) -> Lifetime {
if self.hir_id != hir::DUMMY_HIR_ID {
@@ -1332,23 +442,6 @@
}
}
-#[derive(Clone, Debug)]
-pub enum WherePredicate {
- BoundPredicate { ty: Type, bounds: Vec<GenericBound> },
- RegionPredicate { lifetime: Lifetime, bounds: Vec<GenericBound> },
- EqPredicate { lhs: Type, rhs: Type },
-}
-
-impl WherePredicate {
- pub fn get_bounds(&self) -> Option<&[GenericBound]> {
- match *self {
- WherePredicate::BoundPredicate { ref bounds, .. } => Some(bounds),
- WherePredicate::RegionPredicate { ref bounds, .. } => Some(bounds),
- _ => None,
- }
- }
-}
-
impl Clean<WherePredicate> for hir::WherePredicate {
fn clean(&self, cx: &DocContext<'_>) -> WherePredicate {
match *self {
@@ -1470,73 +563,6 @@
}
}
-#[derive(Clone, PartialEq, Eq, Debug, Hash)]
-pub enum GenericParamDefKind {
- Lifetime,
- Type {
- did: DefId,
- bounds: Vec<GenericBound>,
- default: Option<Type>,
- synthetic: Option<hir::SyntheticTyParamKind>,
- },
- Const {
- did: DefId,
- ty: Type,
- },
-}
-
-impl GenericParamDefKind {
- pub fn is_type(&self) -> bool {
- match *self {
- GenericParamDefKind::Type { .. } => true,
- _ => false,
- }
- }
-
- // FIXME(eddyb) this either returns the default of a type parameter, or the
- // type of a `const` parameter. It seems that the intention is to *visit*
- // any embedded types, but `get_type` seems to be the wrong name for that.
- pub fn get_type(&self) -> Option<Type> {
- match self {
- GenericParamDefKind::Type { default, .. } => default.clone(),
- GenericParamDefKind::Const { ty, .. } => Some(ty.clone()),
- GenericParamDefKind::Lifetime => None,
- }
- }
-}
-
-#[derive(Clone, PartialEq, Eq, Debug, Hash)]
-pub struct GenericParamDef {
- pub name: String,
-
- pub kind: GenericParamDefKind,
-}
-
-impl GenericParamDef {
- pub fn is_synthetic_type_param(&self) -> bool {
- match self.kind {
- GenericParamDefKind::Lifetime |
- GenericParamDefKind::Const { .. } => false,
- GenericParamDefKind::Type { ref synthetic, .. } => synthetic.is_some(),
- }
- }
-
- pub fn is_type(&self) -> bool {
- self.kind.is_type()
- }
-
- pub fn get_type(&self) -> Option<Type> {
- self.kind.get_type()
- }
-
- pub fn get_bounds(&self) -> Option<&[GenericBound]> {
- match self.kind {
- GenericParamDefKind::Type { ref bounds, .. } => Some(bounds),
- _ => None,
- }
- }
-}
-
impl Clean<GenericParamDef> for ty::GenericParamDef {
fn clean(&self, cx: &DocContext<'_>) -> GenericParamDef {
let (name, kind) = match self.kind {
@@ -1614,13 +640,6 @@
}
}
-// maybe use a Generic enum and use Vec<Generic>?
-#[derive(Clone, Debug, Default)]
-pub struct Generics {
- pub params: Vec<GenericParamDef>,
- pub where_predicates: Vec<WherePredicate>,
-}
-
impl Clean<Generics> for hir::Generics {
fn clean(&self, cx: &DocContext<'_>) -> Generics {
// Synthetic type-parameters are inserted after normal ones.
@@ -1863,128 +882,6 @@
}
}
-/// The point of this function is to replace bounds with types.
-///
-/// i.e. `[T, U]` when you have the following bounds: `T: Display, U: Option<T>` will return
-/// `[Display, Option]` (we just returns the list of the types, we don't care about the
-/// wrapped types in here).
-fn get_real_types(
- generics: &Generics,
- arg: &Type,
- cx: &DocContext<'_>,
- recurse: i32,
-) -> FxHashSet<Type> {
- let arg_s = arg.print().to_string();
- let mut res = FxHashSet::default();
- if recurse >= 10 { // FIXME: remove this whole recurse thing when the recursion bug is fixed
- return res;
- }
- if arg.is_full_generic() {
- if let Some(where_pred) = generics.where_predicates.iter().find(|g| {
- match g {
- &WherePredicate::BoundPredicate { ref ty, .. } => ty.def_id() == arg.def_id(),
- _ => false,
- }
- }) {
- let bounds = where_pred.get_bounds().unwrap_or_else(|| &[]);
- for bound in bounds.iter() {
- match *bound {
- GenericBound::TraitBound(ref poly_trait, _) => {
- for x in poly_trait.generic_params.iter() {
- if !x.is_type() {
- continue
- }
- if let Some(ty) = x.get_type() {
- let adds = get_real_types(generics, &ty, cx, recurse + 1);
- if !adds.is_empty() {
- res.extend(adds);
- } else if !ty.is_full_generic() {
- res.insert(ty);
- }
- }
- }
- }
- _ => {}
- }
- }
- }
- if let Some(bound) = generics.params.iter().find(|g| {
- g.is_type() && g.name == arg_s
- }) {
- for bound in bound.get_bounds().unwrap_or_else(|| &[]) {
- if let Some(ty) = bound.get_trait_type() {
- let adds = get_real_types(generics, &ty, cx, recurse + 1);
- if !adds.is_empty() {
- res.extend(adds);
- } else if !ty.is_full_generic() {
- res.insert(ty.clone());
- }
- }
- }
- }
- } else {
- res.insert(arg.clone());
- if let Some(gens) = arg.generics() {
- for gen in gens.iter() {
- if gen.is_full_generic() {
- let adds = get_real_types(generics, gen, cx, recurse + 1);
- if !adds.is_empty() {
- res.extend(adds);
- }
- } else {
- res.insert(gen.clone());
- }
- }
- }
- }
- res
-}
-
-/// Return the full list of types when bounds have been resolved.
-///
-/// i.e. `fn foo<A: Display, B: Option<A>>(x: u32, y: B)` will return
-/// `[u32, Display, Option]`.
-pub fn get_all_types(
- generics: &Generics,
- decl: &FnDecl,
- cx: &DocContext<'_>,
-) -> (Vec<Type>, Vec<Type>) {
- let mut all_types = FxHashSet::default();
- for arg in decl.inputs.values.iter() {
- if arg.type_.is_self_type() {
- continue;
- }
- let args = get_real_types(generics, &arg.type_, cx, 0);
- if !args.is_empty() {
- all_types.extend(args);
- } else {
- all_types.insert(arg.type_.clone());
- }
- }
-
- let ret_types = match decl.output {
- FunctionRetTy::Return(ref return_type) => {
- let mut ret = get_real_types(generics, &return_type, cx, 0);
- if ret.is_empty() {
- ret.insert(return_type.clone());
- }
- ret.into_iter().collect()
- }
- _ => Vec::new(),
- };
- (all_types.into_iter().collect(), ret_types)
-}
-
-#[derive(Clone, Debug)]
-pub struct Method {
- pub generics: Generics,
- pub decl: FnDecl,
- pub header: hir::FnHeader,
- pub defaultness: Option<hir::Defaultness>,
- pub all_types: Vec<Type>,
- pub ret_types: Vec<Type>,
-}
-
impl<'a> Clean<Method> for (&'a hir::FnSig, &'a hir::Generics, hir::BodyId,
Option<hir::Defaultness>) {
fn clean(&self, cx: &DocContext<'_>) -> Method {
@@ -2003,24 +900,6 @@
}
}
-#[derive(Clone, Debug)]
-pub struct TyMethod {
- pub header: hir::FnHeader,
- pub decl: FnDecl,
- pub generics: Generics,
- pub all_types: Vec<Type>,
- pub ret_types: Vec<Type>,
-}
-
-#[derive(Clone, Debug)]
-pub struct Function {
- pub decl: FnDecl,
- pub generics: Generics,
- pub header: hir::FnHeader,
- pub all_types: Vec<Type>,
- pub ret_types: Vec<Type>,
-}
-
impl Clean<Item> for doctree::Function<'_> {
fn clean(&self, cx: &DocContext<'_>) -> Item {
let (generics, decl) = enter_impl_trait(cx, || {
@@ -2053,49 +932,6 @@
}
}
-#[derive(Clone, PartialEq, Eq, Debug, Hash)]
-pub struct FnDecl {
- pub inputs: Arguments,
- pub output: FunctionRetTy,
- pub c_variadic: bool,
- pub attrs: Attributes,
-}
-
-impl FnDecl {
- pub fn self_type(&self) -> Option<SelfTy> {
- self.inputs.values.get(0).and_then(|v| v.to_self())
- }
-
- /// Returns the sugared return type for an async function.
- ///
- /// For example, if the return type is `impl std::future::Future<Output = i32>`, this function
- /// will return `i32`.
- ///
- /// # Panics
- ///
- /// This function will panic if the return type does not match the expected sugaring for async
- /// functions.
- pub fn sugared_async_return_type(&self) -> FunctionRetTy {
- match &self.output {
- FunctionRetTy::Return(Type::ImplTrait(bounds)) => {
- match &bounds[0] {
- GenericBound::TraitBound(PolyTrait { trait_, .. }, ..) => {
- let bindings = trait_.bindings().unwrap();
- FunctionRetTy::Return(bindings[0].ty().clone())
- }
- _ => panic!("unexpected desugaring of async function"),
- }
- }
- _ => panic!("unexpected desugaring of async function"),
- }
- }
-}
-
-#[derive(Clone, PartialEq, Eq, Debug, Hash)]
-pub struct Arguments {
- pub values: Vec<Argument>,
-}
-
impl<'a> Clean<Arguments> for (&'a [hir::Ty], &'a [ast::Ident]) {
fn clean(&self, cx: &DocContext<'_>) -> Arguments {
Arguments {
@@ -2167,42 +1003,6 @@
}
}
-#[derive(Clone, PartialEq, Eq, Debug, Hash)]
-pub struct Argument {
- pub type_: Type,
- pub name: String,
-}
-
-#[derive(Clone, PartialEq, Debug)]
-pub enum SelfTy {
- SelfValue,
- SelfBorrowed(Option<Lifetime>, Mutability),
- SelfExplicit(Type),
-}
-
-impl Argument {
- pub fn to_self(&self) -> Option<SelfTy> {
- if self.name != "self" {
- return None;
- }
- if self.type_.is_self_type() {
- return Some(SelfValue);
- }
- match self.type_ {
- BorrowedRef{ref lifetime, mutability, ref type_} if type_.is_self_type() => {
- Some(SelfBorrowed(lifetime.clone(), mutability))
- }
- _ => Some(SelfExplicit(self.type_.clone()))
- }
- }
-}
-
-#[derive(Clone, PartialEq, Eq, Debug, Hash)]
-pub enum FunctionRetTy {
- Return(Type),
- DefaultReturn,
-}
-
impl Clean<FunctionRetTy> for hir::FunctionRetTy {
fn clean(&self, cx: &DocContext<'_>) -> FunctionRetTy {
match *self {
@@ -2212,26 +1012,6 @@
}
}
-impl GetDefId for FunctionRetTy {
- fn def_id(&self) -> Option<DefId> {
- match *self {
- Return(ref ty) => ty.def_id(),
- DefaultReturn => None,
- }
- }
-}
-
-#[derive(Clone, Debug)]
-pub struct Trait {
- pub auto: bool,
- pub unsafety: hir::Unsafety,
- pub items: Vec<Item>,
- pub generics: Generics,
- pub bounds: Vec<GenericBound>,
- pub is_spotlight: bool,
- pub is_auto: bool,
-}
-
impl Clean<Item> for doctree::Trait<'_> {
fn clean(&self, cx: &DocContext<'_>) -> Item {
let attrs = self.attrs.clean(cx);
@@ -2257,12 +1037,6 @@
}
}
-#[derive(Clone, Debug)]
-pub struct TraitAlias {
- pub generics: Generics,
- pub bounds: Vec<GenericBound>,
-}
-
impl Clean<Item> for doctree::TraitAlias<'_> {
fn clean(&self, cx: &DocContext<'_>) -> Item {
let attrs = self.attrs.clean(cx);
@@ -2541,321 +1315,6 @@
}
}
-/// A trait reference, which may have higher ranked lifetimes.
-#[derive(Clone, PartialEq, Eq, Debug, Hash)]
-pub struct PolyTrait {
- pub trait_: Type,
- pub generic_params: Vec<GenericParamDef>,
-}
-
-/// A representation of a type suitable for hyperlinking purposes. Ideally, one can get the original
-/// type out of the AST/`TyCtxt` given one of these, if more information is needed. Most
-/// importantly, it does not preserve mutability or boxes.
-#[derive(Clone, PartialEq, Eq, Debug, Hash)]
-pub enum Type {
- /// Structs/enums/traits (most that would be an `hir::TyKind::Path`).
- ResolvedPath {
- path: Path,
- param_names: Option<Vec<GenericBound>>,
- did: DefId,
- /// `true` if is a `T::Name` path for associated types.
- is_generic: bool,
- },
- /// For parameterized types, so the consumer of the JSON don't go
- /// looking for types which don't exist anywhere.
- Generic(String),
- /// Primitives are the fixed-size numeric types (plus int/usize/float), char,
- /// arrays, slices, and tuples.
- Primitive(PrimitiveType),
- /// `extern "ABI" fn`
- BareFunction(Box<BareFunctionDecl>),
- Tuple(Vec<Type>),
- Slice(Box<Type>),
- Array(Box<Type>, String),
- Never,
- RawPointer(Mutability, Box<Type>),
- BorrowedRef {
- lifetime: Option<Lifetime>,
- mutability: Mutability,
- type_: Box<Type>,
- },
-
- // `<Type as Trait>::Name`
- QPath {
- name: String,
- self_type: Box<Type>,
- trait_: Box<Type>
- },
-
- // `_`
- Infer,
-
- // `impl TraitA + TraitB + ...`
- ImplTrait(Vec<GenericBound>),
-}
-
-#[derive(Clone, PartialEq, Eq, Hash, Copy, Debug)]
-pub enum PrimitiveType {
- Isize, I8, I16, I32, I64, I128,
- Usize, U8, U16, U32, U64, U128,
- F32, F64,
- Char,
- Bool,
- Str,
- Slice,
- Array,
- Tuple,
- Unit,
- RawPointer,
- Reference,
- Fn,
- Never,
-}
-
-#[derive(Clone, Copy, Debug)]
-pub enum TypeKind {
- Enum,
- Function,
- Module,
- Const,
- Static,
- Struct,
- Union,
- Trait,
- Typedef,
- Foreign,
- Macro,
- Attr,
- Derive,
- TraitAlias,
-}
-
-pub trait GetDefId {
- fn def_id(&self) -> Option<DefId>;
-}
-
-impl<T: GetDefId> GetDefId for Option<T> {
- fn def_id(&self) -> Option<DefId> {
- self.as_ref().and_then(|d| d.def_id())
- }
-}
-
-impl Type {
- pub fn primitive_type(&self) -> Option<PrimitiveType> {
- match *self {
- Primitive(p) | BorrowedRef { type_: box Primitive(p), ..} => Some(p),
- Slice(..) | BorrowedRef { type_: box Slice(..), .. } => Some(PrimitiveType::Slice),
- Array(..) | BorrowedRef { type_: box Array(..), .. } => Some(PrimitiveType::Array),
- Tuple(ref tys) => if tys.is_empty() {
- Some(PrimitiveType::Unit)
- } else {
- Some(PrimitiveType::Tuple)
- },
- RawPointer(..) => Some(PrimitiveType::RawPointer),
- BorrowedRef { type_: box Generic(..), .. } => Some(PrimitiveType::Reference),
- BareFunction(..) => Some(PrimitiveType::Fn),
- Never => Some(PrimitiveType::Never),
- _ => None,
- }
- }
-
- pub fn is_generic(&self) -> bool {
- match *self {
- ResolvedPath { is_generic, .. } => is_generic,
- _ => false,
- }
- }
-
- pub fn is_self_type(&self) -> bool {
- match *self {
- Generic(ref name) => name == "Self",
- _ => false
- }
- }
-
- pub fn generics(&self) -> Option<Vec<Type>> {
- match *self {
- ResolvedPath { ref path, .. } => {
- path.segments.last().and_then(|seg| {
- if let GenericArgs::AngleBracketed { ref args, .. } = seg.args {
- Some(args.iter().filter_map(|arg| match arg {
- GenericArg::Type(ty) => Some(ty.clone()),
- _ => None,
- }).collect())
- } else {
- None
- }
- })
- }
- _ => None,
- }
- }
-
- pub fn bindings(&self) -> Option<&[TypeBinding]> {
- match *self {
- ResolvedPath { ref path, .. } => {
- path.segments.last().and_then(|seg| {
- if let GenericArgs::AngleBracketed { ref bindings, .. } = seg.args {
- Some(&**bindings)
- } else {
- None
- }
- })
- }
- _ => None
- }
- }
-
- pub fn is_full_generic(&self) -> bool {
- match *self {
- Type::Generic(_) => true,
- _ => false,
- }
- }
-
- pub fn projection(&self) -> Option<(&Type, DefId, &str)> {
- let (self_, trait_, name) = match self {
- QPath { ref self_type, ref trait_, ref name } => {
- (self_type, trait_, name)
- }
- _ => return None,
- };
- let trait_did = match **trait_ {
- ResolvedPath { did, .. } => did,
- _ => return None,
- };
- Some((&self_, trait_did, name))
- }
-
-}
-
-impl GetDefId for Type {
- fn def_id(&self) -> Option<DefId> {
- match *self {
- ResolvedPath { did, .. } => Some(did),
- Primitive(p) => crate::html::render::cache().primitive_locations.get(&p).cloned(),
- BorrowedRef { type_: box Generic(..), .. } =>
- Primitive(PrimitiveType::Reference).def_id(),
- BorrowedRef { ref type_, .. } => type_.def_id(),
- Tuple(ref tys) => if tys.is_empty() {
- Primitive(PrimitiveType::Unit).def_id()
- } else {
- Primitive(PrimitiveType::Tuple).def_id()
- },
- BareFunction(..) => Primitive(PrimitiveType::Fn).def_id(),
- Never => Primitive(PrimitiveType::Never).def_id(),
- Slice(..) => Primitive(PrimitiveType::Slice).def_id(),
- Array(..) => Primitive(PrimitiveType::Array).def_id(),
- RawPointer(..) => Primitive(PrimitiveType::RawPointer).def_id(),
- QPath { ref self_type, .. } => self_type.def_id(),
- _ => None,
- }
- }
-}
-
-impl PrimitiveType {
- fn from_str(s: &str) -> Option<PrimitiveType> {
- match s {
- "isize" => Some(PrimitiveType::Isize),
- "i8" => Some(PrimitiveType::I8),
- "i16" => Some(PrimitiveType::I16),
- "i32" => Some(PrimitiveType::I32),
- "i64" => Some(PrimitiveType::I64),
- "i128" => Some(PrimitiveType::I128),
- "usize" => Some(PrimitiveType::Usize),
- "u8" => Some(PrimitiveType::U8),
- "u16" => Some(PrimitiveType::U16),
- "u32" => Some(PrimitiveType::U32),
- "u64" => Some(PrimitiveType::U64),
- "u128" => Some(PrimitiveType::U128),
- "bool" => Some(PrimitiveType::Bool),
- "char" => Some(PrimitiveType::Char),
- "str" => Some(PrimitiveType::Str),
- "f32" => Some(PrimitiveType::F32),
- "f64" => Some(PrimitiveType::F64),
- "array" => Some(PrimitiveType::Array),
- "slice" => Some(PrimitiveType::Slice),
- "tuple" => Some(PrimitiveType::Tuple),
- "unit" => Some(PrimitiveType::Unit),
- "pointer" => Some(PrimitiveType::RawPointer),
- "reference" => Some(PrimitiveType::Reference),
- "fn" => Some(PrimitiveType::Fn),
- "never" => Some(PrimitiveType::Never),
- _ => None,
- }
- }
-
- pub fn as_str(&self) -> &'static str {
- use self::PrimitiveType::*;
- match *self {
- Isize => "isize",
- I8 => "i8",
- I16 => "i16",
- I32 => "i32",
- I64 => "i64",
- I128 => "i128",
- Usize => "usize",
- U8 => "u8",
- U16 => "u16",
- U32 => "u32",
- U64 => "u64",
- U128 => "u128",
- F32 => "f32",
- F64 => "f64",
- Str => "str",
- Bool => "bool",
- Char => "char",
- Array => "array",
- Slice => "slice",
- Tuple => "tuple",
- Unit => "unit",
- RawPointer => "pointer",
- Reference => "reference",
- Fn => "fn",
- Never => "never",
- }
- }
-
- pub fn to_url_str(&self) -> &'static str {
- self.as_str()
- }
-}
-
-impl From<ast::IntTy> for PrimitiveType {
- fn from(int_ty: ast::IntTy) -> PrimitiveType {
- match int_ty {
- ast::IntTy::Isize => PrimitiveType::Isize,
- ast::IntTy::I8 => PrimitiveType::I8,
- ast::IntTy::I16 => PrimitiveType::I16,
- ast::IntTy::I32 => PrimitiveType::I32,
- ast::IntTy::I64 => PrimitiveType::I64,
- ast::IntTy::I128 => PrimitiveType::I128,
- }
- }
-}
-
-impl From<ast::UintTy> for PrimitiveType {
- fn from(uint_ty: ast::UintTy) -> PrimitiveType {
- match uint_ty {
- ast::UintTy::Usize => PrimitiveType::Usize,
- ast::UintTy::U8 => PrimitiveType::U8,
- ast::UintTy::U16 => PrimitiveType::U16,
- ast::UintTy::U32 => PrimitiveType::U32,
- ast::UintTy::U64 => PrimitiveType::U64,
- ast::UintTy::U128 => PrimitiveType::U128,
- }
- }
-}
-
-impl From<ast::FloatTy> for PrimitiveType {
- fn from(float_ty: ast::FloatTy) -> PrimitiveType {
- match float_ty {
- ast::FloatTy::F32 => PrimitiveType::F32,
- ast::FloatTy::F64 => PrimitiveType::F64,
- }
- }
-}
-
impl Clean<Type> for hir::Ty {
fn clean(&self, cx: &DocContext<'_>) -> Type {
use rustc::hir::*;
@@ -3310,14 +1769,6 @@
}
}
-#[derive(Clone, PartialEq, Eq, Debug)]
-pub enum Visibility {
- Public,
- Inherited,
- Crate,
- Restricted(DefId, Path),
-}
-
impl Clean<Visibility> for hir::Visibility {
fn clean(&self, cx: &DocContext<'_>) -> Visibility {
match self.node {
@@ -3339,22 +1790,6 @@
}
}
-#[derive(Clone, Debug)]
-pub struct Struct {
- pub struct_type: doctree::StructType,
- pub generics: Generics,
- pub fields: Vec<Item>,
- pub fields_stripped: bool,
-}
-
-#[derive(Clone, Debug)]
-pub struct Union {
- pub struct_type: doctree::StructType,
- pub generics: Generics,
- pub fields: Vec<Item>,
- pub fields_stripped: bool,
-}
-
impl Clean<Item> for doctree::Struct<'_> {
fn clean(&self, cx: &DocContext<'_>) -> Item {
Item {
@@ -3395,16 +1830,6 @@
}
}
-/// This is a more limited form of the standard Struct, different in that
-/// it lacks the things most items have (name, id, parameterization). Found
-/// only as a variant in an enum.
-#[derive(Clone, Debug)]
-pub struct VariantStruct {
- pub struct_type: doctree::StructType,
- pub fields: Vec<Item>,
- pub fields_stripped: bool,
-}
-
impl Clean<VariantStruct> for ::rustc::hir::VariantData {
fn clean(&self, cx: &DocContext<'_>) -> VariantStruct {
VariantStruct {
@@ -3415,13 +1840,6 @@
}
}
-#[derive(Clone, Debug)]
-pub struct Enum {
- pub variants: IndexVec<VariantIdx, Item>,
- pub generics: Generics,
- pub variants_stripped: bool,
-}
-
impl Clean<Item> for doctree::Enum<'_> {
fn clean(&self, cx: &DocContext<'_>) -> Item {
Item {
@@ -3441,11 +1859,6 @@
}
}
-#[derive(Clone, Debug)]
-pub struct Variant {
- pub kind: VariantKind,
-}
-
impl Clean<Item> for doctree::Variant<'_> {
fn clean(&self, cx: &DocContext<'_>) -> Item {
Item {
@@ -3504,13 +1917,6 @@
}
}
-#[derive(Clone, Debug)]
-pub enum VariantKind {
- CLike,
- Tuple(Vec<Type>),
- Struct(VariantStruct),
-}
-
impl Clean<VariantKind> for hir::VariantData {
fn clean(&self, cx: &DocContext<'_>) -> VariantKind {
match self {
@@ -3522,31 +1928,6 @@
}
}
-#[derive(Clone, Debug)]
-pub struct Span {
- pub filename: FileName,
- pub loline: usize,
- pub locol: usize,
- pub hiline: usize,
- pub hicol: usize,
- pub original: syntax_pos::Span,
-}
-
-impl Span {
- pub fn empty() -> Span {
- Span {
- filename: FileName::Anon(0),
- loline: 0, locol: 0,
- hiline: 0, hicol: 0,
- original: syntax_pos::DUMMY_SP,
- }
- }
-
- pub fn span(&self) -> syntax_pos::Span {
- self.original
- }
-}
-
impl Clean<Span> for syntax_pos::Span {
fn clean(&self, cx: &DocContext<'_>) -> Span {
if self.is_dummy() {
@@ -3568,19 +1949,6 @@
}
}
-#[derive(Clone, PartialEq, Eq, Debug, Hash)]
-pub struct Path {
- pub global: bool,
- pub res: Res,
- pub segments: Vec<PathSegment>,
-}
-
-impl Path {
- pub fn last_name(&self) -> &str {
- self.segments.last().expect("segments were empty").name.as_str()
- }
-}
-
impl Clean<Path> for hir::Path {
fn clean(&self, cx: &DocContext<'_>) -> Path {
Path {
@@ -3591,25 +1959,6 @@
}
}
-#[derive(Clone, PartialEq, Eq, Debug, Hash)]
-pub enum GenericArg {
- Lifetime(Lifetime),
- Type(Type),
- Const(Constant),
-}
-
-#[derive(Clone, PartialEq, Eq, Debug, Hash)]
-pub enum GenericArgs {
- AngleBracketed {
- args: Vec<GenericArg>,
- bindings: Vec<TypeBinding>,
- },
- Parenthesized {
- inputs: Vec<Type>,
- output: Option<Type>,
- }
-}
-
impl Clean<GenericArgs> for hir::GenericArgs {
fn clean(&self, cx: &DocContext<'_>) -> GenericArgs {
if self.parenthesized {
@@ -3638,12 +1987,6 @@
}
}
-#[derive(Clone, PartialEq, Eq, Debug, Hash)]
-pub struct PathSegment {
- pub name: String,
- pub args: GenericArgs,
-}
-
impl Clean<PathSegment> for hir::PathSegment {
fn clean(&self, cx: &DocContext<'_>) -> PathSegment {
PathSegment {
@@ -3653,66 +1996,6 @@
}
}
-fn strip_type(ty: Type) -> Type {
- match ty {
- Type::ResolvedPath { path, param_names, did, is_generic } => {
- Type::ResolvedPath { path: strip_path(&path), param_names, did, is_generic }
- }
- Type::Tuple(inner_tys) => {
- Type::Tuple(inner_tys.iter().map(|t| strip_type(t.clone())).collect())
- }
- Type::Slice(inner_ty) => Type::Slice(Box::new(strip_type(*inner_ty))),
- Type::Array(inner_ty, s) => Type::Array(Box::new(strip_type(*inner_ty)), s),
- Type::RawPointer(m, inner_ty) => Type::RawPointer(m, Box::new(strip_type(*inner_ty))),
- Type::BorrowedRef { lifetime, mutability, type_ } => {
- Type::BorrowedRef { lifetime, mutability, type_: Box::new(strip_type(*type_)) }
- }
- Type::QPath { name, self_type, trait_ } => {
- Type::QPath {
- name,
- self_type: Box::new(strip_type(*self_type)), trait_: Box::new(strip_type(*trait_))
- }
- }
- _ => ty
- }
-}
-
-fn strip_path(path: &Path) -> Path {
- let segments = path.segments.iter().map(|s| {
- PathSegment {
- name: s.name.clone(),
- args: GenericArgs::AngleBracketed {
- args: vec![],
- bindings: vec![],
- }
- }
- }).collect();
-
- Path {
- global: path.global,
- res: path.res.clone(),
- segments,
- }
-}
-
-fn qpath_to_string(p: &hir::QPath) -> String {
- let segments = match *p {
- hir::QPath::Resolved(_, ref path) => &path.segments,
- hir::QPath::TypeRelative(_, ref segment) => return segment.ident.to_string(),
- };
-
- let mut s = String::new();
- for (i, seg) in segments.iter().enumerate() {
- if i > 0 {
- s.push_str("::");
- }
- if seg.ident.name != kw::PathRoot {
- s.push_str(&seg.ident.as_str());
- }
- }
- s
-}
-
impl Clean<String> for Ident {
#[inline]
fn clean(&self, cx: &DocContext<'_>) -> String {
@@ -3727,12 +2010,6 @@
}
}
-#[derive(Clone, Debug)]
-pub struct Typedef {
- pub type_: Type,
- pub generics: Generics,
-}
-
impl Clean<Item> for doctree::Typedef<'_> {
fn clean(&self, cx: &DocContext<'_>) -> Item {
Item {
@@ -3751,12 +2028,6 @@
}
}
-#[derive(Clone, Debug)]
-pub struct OpaqueTy {
- pub bounds: Vec<GenericBound>,
- pub generics: Generics,
-}
-
impl Clean<Item> for doctree::OpaqueTy<'_> {
fn clean(&self, cx: &DocContext<'_>) -> Item {
Item {
@@ -3775,14 +2046,6 @@
}
}
-#[derive(Clone, PartialEq, Eq, Debug, Hash)]
-pub struct BareFunctionDecl {
- pub unsafety: hir::Unsafety,
- pub generic_params: Vec<GenericParamDef>,
- pub decl: FnDecl,
- pub abi: Abi,
-}
-
impl Clean<BareFunctionDecl> for hir::BareFnTy {
fn clean(&self, cx: &DocContext<'_>) -> BareFunctionDecl {
let (generic_params, decl) = enter_impl_trait(cx, || {
@@ -3797,16 +2060,6 @@
}
}
-#[derive(Clone, Debug)]
-pub struct Static {
- pub type_: Type,
- pub mutability: Mutability,
- /// It's useful to have the value of a static documented, but I have no
- /// desire to represent expressions (that'd basically be all of the AST,
- /// which is huge!). So, have a string.
- pub expr: String,
-}
-
impl Clean<Item> for doctree::Static<'_> {
fn clean(&self, cx: &DocContext<'_>) -> Item {
debug!("cleaning static {}: {:?}", self.name.clean(cx), self);
@@ -3827,12 +2080,6 @@
}
}
-#[derive(Clone, PartialEq, Eq, Hash, Debug)]
-pub struct Constant {
- pub type_: Type,
- pub expr: String,
-}
-
impl Clean<Item> for doctree::Constant<'_> {
fn clean(&self, cx: &DocContext<'_>) -> Item {
Item {
@@ -3851,12 +2098,6 @@
}
}
-#[derive(Debug, Clone, PartialEq, Eq, Copy, Hash)]
-pub enum Mutability {
- Mutable,
- Immutable,
-}
-
impl Clean<Mutability> for hir::Mutability {
fn clean(&self, _: &DocContext<'_>) -> Mutability {
match self {
@@ -3866,12 +2107,6 @@
}
}
-#[derive(Clone, PartialEq, Debug)]
-pub enum ImplPolarity {
- Positive,
- Negative,
-}
-
impl Clean<ImplPolarity> for ty::ImplPolarity {
fn clean(&self, _: &DocContext<'_>) -> ImplPolarity {
match self {
@@ -3883,28 +2118,6 @@
}
}
-#[derive(Clone, Debug)]
-pub struct Impl {
- pub unsafety: hir::Unsafety,
- pub generics: Generics,
- pub provided_trait_methods: FxHashSet<String>,
- pub trait_: Option<Type>,
- pub for_: Type,
- pub items: Vec<Item>,
- pub polarity: Option<ImplPolarity>,
- pub synthetic: bool,
- pub blanket_impl: Option<Type>,
-}
-
-pub fn get_auto_trait_and_blanket_impls(
- cx: &DocContext<'tcx>,
- ty: Ty<'tcx>,
- param_env_def_id: DefId,
-) -> impl Iterator<Item = Item> {
- AutoTraitFinder::new(cx).get_auto_trait_impls(ty, param_env_def_id).into_iter()
- .chain(BlanketImplFinder::new(cx).get_blanket_impls(ty, param_env_def_id))
-}
-
impl Clean<Vec<Item>> for doctree::Impl<'_> {
fn clean(&self, cx: &DocContext<'_>) -> Vec<Item> {
let mut ret = Vec::new();
@@ -3949,63 +2162,6 @@
}
}
-fn build_deref_target_impls(cx: &DocContext<'_>,
- items: &[Item],
- ret: &mut Vec<Item>) {
- use self::PrimitiveType::*;
- let tcx = cx.tcx;
-
- for item in items {
- let target = match item.inner {
- TypedefItem(ref t, true) => &t.type_,
- _ => continue,
- };
- let primitive = match *target {
- ResolvedPath { did, .. } if did.is_local() => continue,
- ResolvedPath { did, .. } => {
- ret.extend(inline::build_impls(cx, did, None));
- continue
- }
- _ => match target.primitive_type() {
- Some(prim) => prim,
- None => continue,
- }
- };
- let did = match primitive {
- Isize => tcx.lang_items().isize_impl(),
- I8 => tcx.lang_items().i8_impl(),
- I16 => tcx.lang_items().i16_impl(),
- I32 => tcx.lang_items().i32_impl(),
- I64 => tcx.lang_items().i64_impl(),
- I128 => tcx.lang_items().i128_impl(),
- Usize => tcx.lang_items().usize_impl(),
- U8 => tcx.lang_items().u8_impl(),
- U16 => tcx.lang_items().u16_impl(),
- U32 => tcx.lang_items().u32_impl(),
- U64 => tcx.lang_items().u64_impl(),
- U128 => tcx.lang_items().u128_impl(),
- F32 => tcx.lang_items().f32_impl(),
- F64 => tcx.lang_items().f64_impl(),
- Char => tcx.lang_items().char_impl(),
- Bool => tcx.lang_items().bool_impl(),
- Str => tcx.lang_items().str_impl(),
- Slice => tcx.lang_items().slice_impl(),
- Array => tcx.lang_items().slice_impl(),
- Tuple => None,
- Unit => None,
- RawPointer => tcx.lang_items().const_ptr_impl(),
- Reference => None,
- Fn => None,
- Never => None,
- };
- if let Some(did) = did {
- if !did.is_local() {
- inline::build_impl(cx, did, None, ret);
- }
- }
- }
-}
-
impl Clean<Vec<Item>> for doctree::ExternCrate<'_> {
fn clean(&self, cx: &DocContext<'_>) -> Vec<Item> {
@@ -4115,20 +2271,6 @@
}
}
-#[derive(Clone, Debug)]
-pub enum Import {
- // use source as str;
- Simple(String, ImportSource),
- // use source::*;
- Glob(ImportSource)
-}
-
-#[derive(Clone, Debug)]
-pub struct ImportSource {
- pub path: Path,
- pub did: Option<DefId>,
-}
-
impl Clean<Item> for doctree::ForeignItem<'_> {
fn clean(&self, cx: &DocContext<'_>) -> Item {
let inner = match self.kind {
@@ -4176,176 +2318,6 @@
}
}
-// Utilities
-
-pub trait ToSource {
- fn to_src(&self, cx: &DocContext<'_>) -> String;
-}
-
-impl ToSource for syntax_pos::Span {
- fn to_src(&self, cx: &DocContext<'_>) -> String {
- debug!("converting span {:?} to snippet", self.clean(cx));
- let sn = match cx.sess().source_map().span_to_snippet(*self) {
- Ok(x) => x,
- Err(_) => String::new()
- };
- debug!("got snippet {}", sn);
- sn
- }
-}
-
-fn name_from_pat(p: &hir::Pat) -> String {
- use rustc::hir::*;
- debug!("trying to get a name from pattern: {:?}", p);
-
- match p.kind {
- PatKind::Wild => "_".to_string(),
- PatKind::Binding(_, _, ident, _) => ident.to_string(),
- PatKind::TupleStruct(ref p, ..) | PatKind::Path(ref p) => qpath_to_string(p),
- PatKind::Struct(ref name, ref fields, etc) => {
- format!("{} {{ {}{} }}", qpath_to_string(name),
- fields.iter().map(|fp| format!("{}: {}", fp.ident, name_from_pat(&fp.pat)))
- .collect::<Vec<String>>().join(", "),
- if etc { ", .." } else { "" }
- )
- }
- PatKind::Or(ref pats) => {
- pats.iter().map(|p| name_from_pat(&**p)).collect::<Vec<String>>().join(" | ")
- }
- PatKind::Tuple(ref elts, _) => format!("({})", elts.iter().map(|p| name_from_pat(&**p))
- .collect::<Vec<String>>().join(", ")),
- PatKind::Box(ref p) => name_from_pat(&**p),
- PatKind::Ref(ref p, _) => name_from_pat(&**p),
- PatKind::Lit(..) => {
- warn!("tried to get argument name from PatKind::Lit, \
- which is silly in function arguments");
- "()".to_string()
- },
- PatKind::Range(..) => panic!("tried to get argument name from PatKind::Range, \
- which is not allowed in function arguments"),
- PatKind::Slice(ref begin, ref mid, ref end) => {
- let begin = begin.iter().map(|p| name_from_pat(&**p));
- let mid = mid.as_ref().map(|p| format!("..{}", name_from_pat(&**p))).into_iter();
- let end = end.iter().map(|p| name_from_pat(&**p));
- format!("[{}]", begin.chain(mid).chain(end).collect::<Vec<_>>().join(", "))
- },
- }
-}
-
-fn print_const(cx: &DocContext<'_>, n: &ty::Const<'_>) -> String {
- match n.val {
- ty::ConstKind::Unevaluated(def_id, _) => {
- if let Some(hir_id) = cx.tcx.hir().as_local_hir_id(def_id) {
- print_const_expr(cx, cx.tcx.hir().body_owned_by(hir_id))
- } else {
- inline::print_inlined_const(cx, def_id)
- }
- },
- _ => {
- let mut s = n.to_string();
- // array lengths are obviously usize
- if s.ends_with("usize") {
- let n = s.len() - "usize".len();
- s.truncate(n);
- if s.ends_with(": ") {
- let n = s.len() - ": ".len();
- s.truncate(n);
- }
- }
- s
- },
- }
-}
-
-fn print_const_expr(cx: &DocContext<'_>, body: hir::BodyId) -> String {
- cx.tcx.hir().hir_to_pretty_string(body.hir_id)
-}
-
-/// Given a type Path, resolve it to a Type using the TyCtxt
-fn resolve_type(cx: &DocContext<'_>,
- path: Path,
- id: hir::HirId) -> Type {
- if id == hir::DUMMY_HIR_ID {
- debug!("resolve_type({:?})", path);
- } else {
- debug!("resolve_type({:?},{:?})", path, id);
- }
-
- let is_generic = match path.res {
- Res::PrimTy(p) => match p {
- hir::Str => return Primitive(PrimitiveType::Str),
- hir::Bool => return Primitive(PrimitiveType::Bool),
- hir::Char => return Primitive(PrimitiveType::Char),
- hir::Int(int_ty) => return Primitive(int_ty.into()),
- hir::Uint(uint_ty) => return Primitive(uint_ty.into()),
- hir::Float(float_ty) => return Primitive(float_ty.into()),
- },
- Res::SelfTy(..) if path.segments.len() == 1 => {
- return Generic(kw::SelfUpper.to_string());
- }
- Res::Def(DefKind::TyParam, _) if path.segments.len() == 1 => {
- return Generic(format!("{:#}", path.print()));
- }
- Res::SelfTy(..)
- | Res::Def(DefKind::TyParam, _)
- | Res::Def(DefKind::AssocTy, _) => true,
- _ => false,
- };
- let did = register_res(&*cx, path.res);
- ResolvedPath { path, param_names: None, did, is_generic }
-}
-
-pub fn register_res(cx: &DocContext<'_>, res: Res) -> DefId {
- debug!("register_res({:?})", res);
-
- let (did, kind) = match res {
- Res::Def(DefKind::Fn, i) => (i, TypeKind::Function),
- Res::Def(DefKind::TyAlias, i) => (i, TypeKind::Typedef),
- Res::Def(DefKind::Enum, i) => (i, TypeKind::Enum),
- Res::Def(DefKind::Trait, i) => (i, TypeKind::Trait),
- Res::Def(DefKind::Struct, i) => (i, TypeKind::Struct),
- Res::Def(DefKind::Union, i) => (i, TypeKind::Union),
- Res::Def(DefKind::Mod, i) => (i, TypeKind::Module),
- Res::Def(DefKind::ForeignTy, i) => (i, TypeKind::Foreign),
- Res::Def(DefKind::Const, i) => (i, TypeKind::Const),
- Res::Def(DefKind::Static, i) => (i, TypeKind::Static),
- Res::Def(DefKind::Variant, i) => (cx.tcx.parent(i).expect("cannot get parent def id"),
- TypeKind::Enum),
- Res::Def(DefKind::Macro(mac_kind), i) => match mac_kind {
- MacroKind::Bang => (i, TypeKind::Macro),
- MacroKind::Attr => (i, TypeKind::Attr),
- MacroKind::Derive => (i, TypeKind::Derive),
- },
- Res::Def(DefKind::TraitAlias, i) => (i, TypeKind::TraitAlias),
- Res::SelfTy(Some(def_id), _) => (def_id, TypeKind::Trait),
- Res::SelfTy(_, Some(impl_def_id)) => return impl_def_id,
- _ => return res.def_id()
- };
- if did.is_local() { return did }
- inline::record_extern_fqn(cx, did, kind);
- if let TypeKind::Trait = kind {
- inline::record_extern_trait(cx, did);
- }
- did
-}
-
-fn resolve_use_source(cx: &DocContext<'_>, path: Path) -> ImportSource {
- ImportSource {
- did: if path.res.opt_def_id().is_none() {
- None
- } else {
- Some(register_res(cx, path.res))
- },
- path,
- }
-}
-
-#[derive(Clone, Debug)]
-pub struct Macro {
- pub source: String,
- pub imported_from: Option<String>,
-}
-
impl Clean<Item> for doctree::Macro<'_> {
fn clean(&self, cx: &DocContext<'_>) -> Item {
let name = self.name.clean(cx);
@@ -4369,12 +2341,6 @@
}
}
-#[derive(Clone, Debug)]
-pub struct ProcMacro {
- pub kind: MacroKind,
- pub helpers: Vec<String>,
-}
-
impl Clean<Item> for doctree::ProcMacro<'_> {
fn clean(&self, cx: &DocContext<'_>) -> Item {
Item {
@@ -4393,22 +2359,6 @@
}
}
-#[derive(Clone, Debug)]
-pub struct Stability {
- pub level: stability::StabilityLevel,
- pub feature: Option<String>,
- pub since: String,
- pub deprecation: Option<Deprecation>,
- pub unstable_reason: Option<String>,
- pub issue: Option<NonZeroU32>,
-}
-
-#[derive(Clone, Debug)]
-pub struct Deprecation {
- pub since: Option<String>,
- pub note: Option<String>,
-}
-
impl Clean<Stability> for attr::Stability {
fn clean(&self, _: &DocContext<'_>) -> Stability {
Stability {
@@ -4451,33 +2401,6 @@
}
}
-/// An type binding on an associated type (e.g., `A = Bar` in `Foo<A = Bar>` or
-/// `A: Send + Sync` in `Foo<A: Send + Sync>`).
-#[derive(Clone, PartialEq, Eq, Debug, Hash)]
-pub struct TypeBinding {
- pub name: String,
- pub kind: TypeBindingKind,
-}
-
-#[derive(Clone, PartialEq, Eq, Debug, Hash)]
-pub enum TypeBindingKind {
- Equality {
- ty: Type,
- },
- Constraint {
- bounds: Vec<GenericBound>,
- },
-}
-
-impl TypeBinding {
- pub fn ty(&self) -> &Type {
- match self.kind {
- TypeBindingKind::Equality { ref ty } => ty,
- _ => panic!("expected equality type binding for parenthesized generic args"),
- }
- }
-}
-
impl Clean<TypeBinding> for hir::TypeBinding {
fn clean(&self, cx: &DocContext<'_>) -> TypeBinding {
TypeBinding {
@@ -4502,29 +2425,6 @@
}
}
-pub fn enter_impl_trait<F, R>(cx: &DocContext<'_>, f: F) -> R
-where
- F: FnOnce() -> R,
-{
- let old_bounds = mem::take(&mut *cx.impl_trait_bounds.borrow_mut());
- let r = f();
- assert!(cx.impl_trait_bounds.borrow().is_empty());
- *cx.impl_trait_bounds.borrow_mut() = old_bounds;
- r
-}
-
-#[derive(Eq, PartialEq, Hash, Copy, Clone, Debug)]
-enum RegionTarget<'tcx> {
- Region(Region<'tcx>),
- RegionVid(RegionVid)
-}
-
-#[derive(Default, Debug, Clone)]
-struct RegionDeps<'tcx> {
- larger: FxHashSet<RegionTarget<'tcx>>,
- smaller: FxHashSet<RegionTarget<'tcx>>
-}
-
enum SimpleBound {
TraitBound(Vec<PathSegment>, Vec<SimpleBound>, Vec<GenericParamDef>, hir::TraitBoundModifier),
Outlives(Lifetime),
diff --git a/src/librustdoc/clean/types.rs b/src/librustdoc/clean/types.rs
new file mode 100644
index 0000000..bd3f2a3
--- /dev/null
+++ b/src/librustdoc/clean/types.rs
@@ -0,0 +1,1545 @@
+use std::fmt;
+use std::hash::{Hash, Hasher};
+use std::default::Default;
+use std::{slice, vec};
+use std::num::NonZeroU32;
+use std::iter::FromIterator;
+use std::rc::Rc;
+use std::cell::RefCell;
+use std::sync::Arc;
+
+use rustc::middle::lang_items;
+use rustc::middle::stability;
+use rustc::hir;
+use rustc::hir::def::Res;
+use rustc::hir::def_id::{CrateNum, DefId};
+use rustc::ty::layout::VariantIdx;
+use rustc::util::nodemap::{FxHashMap, FxHashSet};
+use rustc_index::vec::IndexVec;
+use rustc_target::spec::abi::Abi;
+use syntax::ast::{self, Attribute, AttrStyle, AttrKind, Ident};
+use syntax::attr;
+use syntax::util::comments;
+use syntax::source_map::DUMMY_SP;
+use syntax_pos::hygiene::MacroKind;
+use syntax_pos::symbol::{Symbol, sym};
+use syntax_pos::{self, FileName};
+
+use crate::core::DocContext;
+use crate::clean::cfg::Cfg;
+use crate::clean::inline;
+use crate::clean::external_path;
+use crate::clean::types::Type::{QPath, ResolvedPath};
+use crate::doctree;
+use crate::html::item_type::ItemType;
+use crate::html::render::{cache, ExternalLocation};
+
+use self::Type::*;
+use self::ItemEnum::*;
+use self::SelfTy::*;
+use self::FunctionRetTy::*;
+
+thread_local!(pub static MAX_DEF_ID: RefCell<FxHashMap<CrateNum, DefId>> = Default::default());
+
+#[derive(Clone, Debug)]
+pub struct Crate {
+ pub name: String,
+ pub version: Option<String>,
+ pub src: FileName,
+ pub module: Option<Item>,
+ pub externs: Vec<(CrateNum, ExternalCrate)>,
+ pub primitives: Vec<(DefId, PrimitiveType, Attributes)>,
+ // These are later on moved into `CACHEKEY`, leaving the map empty.
+ // Only here so that they can be filtered through the rustdoc passes.
+ pub external_traits: Rc<RefCell<FxHashMap<DefId, Trait>>>,
+ pub masked_crates: FxHashSet<CrateNum>,
+ pub collapsed: bool,
+}
+
+#[derive(Clone, Debug)]
+pub struct ExternalCrate {
+ pub name: String,
+ pub src: FileName,
+ pub attrs: Attributes,
+ pub primitives: Vec<(DefId, PrimitiveType, Attributes)>,
+ pub keywords: Vec<(DefId, String, Attributes)>,
+}
+
+/// Anything with a source location and set of attributes and, optionally, a
+/// name. That is, anything that can be documented. This doesn't correspond
+/// directly to the AST's concept of an item; it's a strict superset.
+#[derive(Clone)]
+pub struct Item {
+ /// Stringified span
+ pub source: Span,
+ /// Not everything has a name. E.g., impls
+ pub name: Option<String>,
+ pub attrs: Attributes,
+ pub inner: ItemEnum,
+ pub visibility: Visibility,
+ pub def_id: DefId,
+ pub stability: Option<Stability>,
+ pub deprecation: Option<Deprecation>,
+}
+
+impl fmt::Debug for Item {
+ fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result {
+ let fake = MAX_DEF_ID.with(|m| m.borrow().get(&self.def_id.krate)
+ .map(|id| self.def_id >= *id).unwrap_or(false));
+ let def_id: &dyn fmt::Debug = if fake { &"**FAKE**" } else { &self.def_id };
+
+ fmt.debug_struct("Item")
+ .field("source", &self.source)
+ .field("name", &self.name)
+ .field("attrs", &self.attrs)
+ .field("inner", &self.inner)
+ .field("visibility", &self.visibility)
+ .field("def_id", def_id)
+ .field("stability", &self.stability)
+ .field("deprecation", &self.deprecation)
+ .finish()
+ }
+}
+
+impl Item {
+ /// Finds the `doc` attribute as a NameValue and returns the corresponding
+ /// value found.
+ pub fn doc_value(&self) -> Option<&str> {
+ self.attrs.doc_value()
+ }
+
+ /// Finds all `doc` attributes as NameValues and returns their corresponding values, joined
+ /// with newlines.
+ pub fn collapsed_doc_value(&self) -> Option<String> {
+ self.attrs.collapsed_doc_value()
+ }
+
+ pub fn links(&self) -> Vec<(String, String)> {
+ self.attrs.links(&self.def_id.krate)
+ }
+
+ pub fn is_crate(&self) -> bool {
+ match self.inner {
+ StrippedItem(box ModuleItem(Module { is_crate: true, ..})) |
+ ModuleItem(Module { is_crate: true, ..}) => true,
+ _ => false,
+ }
+ }
+ pub fn is_mod(&self) -> bool {
+ self.type_() == ItemType::Module
+ }
+ pub fn is_trait(&self) -> bool {
+ self.type_() == ItemType::Trait
+ }
+ pub fn is_struct(&self) -> bool {
+ self.type_() == ItemType::Struct
+ }
+ pub fn is_enum(&self) -> bool {
+ self.type_() == ItemType::Enum
+ }
+ pub fn is_variant(&self) -> bool {
+ self.type_() == ItemType::Variant
+ }
+ pub fn is_associated_type(&self) -> bool {
+ self.type_() == ItemType::AssocType
+ }
+ pub fn is_associated_const(&self) -> bool {
+ self.type_() == ItemType::AssocConst
+ }
+ pub fn is_method(&self) -> bool {
+ self.type_() == ItemType::Method
+ }
+ pub fn is_ty_method(&self) -> bool {
+ self.type_() == ItemType::TyMethod
+ }
+ pub fn is_typedef(&self) -> bool {
+ self.type_() == ItemType::Typedef
+ }
+ pub fn is_primitive(&self) -> bool {
+ self.type_() == ItemType::Primitive
+ }
+ pub fn is_union(&self) -> bool {
+ self.type_() == ItemType::Union
+ }
+ pub fn is_import(&self) -> bool {
+ self.type_() == ItemType::Import
+ }
+ pub fn is_extern_crate(&self) -> bool {
+ self.type_() == ItemType::ExternCrate
+ }
+ pub fn is_keyword(&self) -> bool {
+ self.type_() == ItemType::Keyword
+ }
+ pub fn is_stripped(&self) -> bool {
+ match self.inner { StrippedItem(..) => true, _ => false }
+ }
+ pub fn has_stripped_fields(&self) -> Option<bool> {
+ match self.inner {
+ StructItem(ref _struct) => Some(_struct.fields_stripped),
+ UnionItem(ref union) => Some(union.fields_stripped),
+ VariantItem(Variant { kind: VariantKind::Struct(ref vstruct)} ) => {
+ Some(vstruct.fields_stripped)
+ },
+ _ => None,
+ }
+ }
+
+ pub fn stability_class(&self) -> Option<String> {
+ self.stability.as_ref().and_then(|ref s| {
+ let mut classes = Vec::with_capacity(2);
+
+ if s.level == stability::Unstable {
+ classes.push("unstable");
+ }
+
+ if s.deprecation.is_some() {
+ classes.push("deprecated");
+ }
+
+ if classes.len() != 0 {
+ Some(classes.join(" "))
+ } else {
+ None
+ }
+ })
+ }
+
+ pub fn stable_since(&self) -> Option<&str> {
+ self.stability.as_ref().map(|s| &s.since[..])
+ }
+
+ pub fn is_non_exhaustive(&self) -> bool {
+ self.attrs.other_attrs.iter()
+ .any(|a| a.check_name(sym::non_exhaustive))
+ }
+
+ /// Returns a documentation-level item type from the item.
+ pub fn type_(&self) -> ItemType {
+ ItemType::from(self)
+ }
+
+ /// Returns the info in the item's `#[deprecated]` or `#[rustc_deprecated]` attributes.
+ ///
+ /// If the item is not deprecated, returns `None`.
+ pub fn deprecation(&self) -> Option<&Deprecation> {
+ self.deprecation
+ .as_ref()
+ .or_else(|| self.stability.as_ref().and_then(|s| s.deprecation.as_ref()))
+ }
+ pub fn is_default(&self) -> bool {
+ match self.inner {
+ ItemEnum::MethodItem(ref meth) => {
+ if let Some(defaultness) = meth.defaultness {
+ defaultness.has_value() && !defaultness.is_final()
+ } else {
+ false
+ }
+ }
+ _ => false,
+ }
+ }
+}
+
+#[derive(Clone, Debug)]
+pub enum ItemEnum {
+ ExternCrateItem(String, Option<String>),
+ ImportItem(Import),
+ StructItem(Struct),
+ UnionItem(Union),
+ EnumItem(Enum),
+ FunctionItem(Function),
+ ModuleItem(Module),
+ TypedefItem(Typedef, bool /* is associated type */),
+ OpaqueTyItem(OpaqueTy, bool /* is associated type */),
+ StaticItem(Static),
+ ConstantItem(Constant),
+ TraitItem(Trait),
+ TraitAliasItem(TraitAlias),
+ ImplItem(Impl),
+ /// A method signature only. Used for required methods in traits (ie,
+ /// non-default-methods).
+ TyMethodItem(TyMethod),
+ /// A method with a body.
+ MethodItem(Method),
+ StructFieldItem(Type),
+ VariantItem(Variant),
+ /// `fn`s from an extern block
+ ForeignFunctionItem(Function),
+ /// `static`s from an extern block
+ ForeignStaticItem(Static),
+ /// `type`s from an extern block
+ ForeignTypeItem,
+ MacroItem(Macro),
+ ProcMacroItem(ProcMacro),
+ PrimitiveItem(PrimitiveType),
+ AssocConstItem(Type, Option<String>),
+ AssocTypeItem(Vec<GenericBound>, Option<Type>),
+ /// An item that has been stripped by a rustdoc pass
+ StrippedItem(Box<ItemEnum>),
+ KeywordItem(String),
+}
+
+impl ItemEnum {
+ pub fn is_associated(&self) -> bool {
+ match *self {
+ ItemEnum::TypedefItem(_, _) |
+ ItemEnum::AssocTypeItem(_, _) => true,
+ _ => false,
+ }
+ }
+}
+
+#[derive(Clone, Debug)]
+pub struct Module {
+ pub items: Vec<Item>,
+ pub is_crate: bool,
+}
+
+pub struct ListAttributesIter<'a> {
+ attrs: slice::Iter<'a, ast::Attribute>,
+ current_list: vec::IntoIter<ast::NestedMetaItem>,
+ name: Symbol,
+}
+
+impl<'a> Iterator for ListAttributesIter<'a> {
+ type Item = ast::NestedMetaItem;
+
+ fn next(&mut self) -> Option<Self::Item> {
+ if let Some(nested) = self.current_list.next() {
+ return Some(nested);
+ }
+
+ for attr in &mut self.attrs {
+ if let Some(list) = attr.meta_item_list() {
+ if attr.check_name(self.name) {
+ self.current_list = list.into_iter();
+ if let Some(nested) = self.current_list.next() {
+ return Some(nested);
+ }
+ }
+ }
+ }
+
+ None
+ }
+
+ fn size_hint(&self) -> (usize, Option<usize>) {
+ let lower = self.current_list.len();
+ (lower, None)
+ }
+}
+
+pub trait AttributesExt {
+ /// Finds an attribute as List and returns the list of attributes nested inside.
+ fn lists(&self, name: Symbol) -> ListAttributesIter<'_>;
+}
+
+impl AttributesExt for [ast::Attribute] {
+ fn lists(&self, name: Symbol) -> ListAttributesIter<'_> {
+ ListAttributesIter {
+ attrs: self.iter(),
+ current_list: Vec::new().into_iter(),
+ name,
+ }
+ }
+}
+
+pub trait NestedAttributesExt {
+ /// Returns `true` if the attribute list contains a specific `Word`
+ fn has_word(self, word: Symbol) -> bool;
+}
+
+impl<I: IntoIterator<Item=ast::NestedMetaItem>> NestedAttributesExt for I {
+ fn has_word(self, word: Symbol) -> bool {
+ self.into_iter().any(|attr| attr.is_word() && attr.check_name(word))
+ }
+}
+
+/// A portion of documentation, extracted from a `#[doc]` attribute.
+///
+/// Each variant contains the line number within the complete doc-comment where the fragment
+/// starts, as well as the Span where the corresponding doc comment or attribute is located.
+///
+/// Included files are kept separate from inline doc comments so that proper line-number
+/// information can be given when a doctest fails. Sugared doc comments and "raw" doc comments are
+/// kept separate because of issue #42760.
+#[derive(Clone, PartialEq, Eq, Debug, Hash)]
+pub enum DocFragment {
+ /// A doc fragment created from a `///` or `//!` doc comment.
+ SugaredDoc(usize, syntax_pos::Span, String),
+ /// A doc fragment created from a "raw" `#[doc=""]` attribute.
+ RawDoc(usize, syntax_pos::Span, String),
+ /// A doc fragment created from a `#[doc(include="filename")]` attribute. Contains both the
+ /// given filename and the file contents.
+ Include(usize, syntax_pos::Span, String, String),
+}
+
+impl DocFragment {
+ pub fn as_str(&self) -> &str {
+ match *self {
+ DocFragment::SugaredDoc(_, _, ref s) => &s[..],
+ DocFragment::RawDoc(_, _, ref s) => &s[..],
+ DocFragment::Include(_, _, _, ref s) => &s[..],
+ }
+ }
+
+ pub fn span(&self) -> syntax_pos::Span {
+ match *self {
+ DocFragment::SugaredDoc(_, span, _) |
+ DocFragment::RawDoc(_, span, _) |
+ DocFragment::Include(_, span, _, _) => span,
+ }
+ }
+}
+
+impl<'a> FromIterator<&'a DocFragment> for String {
+ fn from_iter<T>(iter: T) -> Self
+ where
+ T: IntoIterator<Item = &'a DocFragment>
+ {
+ iter.into_iter().fold(String::new(), |mut acc, frag| {
+ if !acc.is_empty() {
+ acc.push('\n');
+ }
+ match *frag {
+ DocFragment::SugaredDoc(_, _, ref docs)
+ | DocFragment::RawDoc(_, _, ref docs)
+ | DocFragment::Include(_, _, _, ref docs) =>
+ acc.push_str(docs),
+ }
+
+ acc
+ })
+ }
+}
+
+#[derive(Clone, Debug, Default)]
+pub struct Attributes {
+ pub doc_strings: Vec<DocFragment>,
+ pub other_attrs: Vec<ast::Attribute>,
+ pub cfg: Option<Arc<Cfg>>,
+ pub span: Option<syntax_pos::Span>,
+ /// map from Rust paths to resolved defs and potential URL fragments
+ pub links: Vec<(String, Option<DefId>, Option<String>)>,
+ pub inner_docs: bool,
+}
+
+impl Attributes {
+ /// Extracts the content from an attribute `#[doc(cfg(content))]`.
+ pub fn extract_cfg(mi: &ast::MetaItem) -> Option<&ast::MetaItem> {
+ use syntax::ast::NestedMetaItem::MetaItem;
+
+ if let ast::MetaItemKind::List(ref nmis) = mi.kind {
+ if nmis.len() == 1 {
+ if let MetaItem(ref cfg_mi) = nmis[0] {
+ if cfg_mi.check_name(sym::cfg) {
+ if let ast::MetaItemKind::List(ref cfg_nmis) = cfg_mi.kind {
+ if cfg_nmis.len() == 1 {
+ if let MetaItem(ref content_mi) = cfg_nmis[0] {
+ return Some(content_mi);
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+
+ None
+ }
+
+ /// Reads a `MetaItem` from within an attribute, looks for whether it is a
+ /// `#[doc(include="file")]`, and returns the filename and contents of the file as loaded from
+ /// its expansion.
+ pub fn extract_include(mi: &ast::MetaItem) -> Option<(String, String)> {
+ mi.meta_item_list().and_then(|list| {
+ for meta in list {
+ if meta.check_name(sym::include) {
+ // the actual compiled `#[doc(include="filename")]` gets expanded to
+ // `#[doc(include(file="filename", contents="file contents")]` so we need to
+ // look for that instead
+ return meta.meta_item_list().and_then(|list| {
+ let mut filename: Option<String> = None;
+ let mut contents: Option<String> = None;
+
+ for it in list {
+ if it.check_name(sym::file) {
+ if let Some(name) = it.value_str() {
+ filename = Some(name.to_string());
+ }
+ } else if it.check_name(sym::contents) {
+ if let Some(docs) = it.value_str() {
+ contents = Some(docs.to_string());
+ }
+ }
+ }
+
+ if let (Some(filename), Some(contents)) = (filename, contents) {
+ Some((filename, contents))
+ } else {
+ None
+ }
+ });
+ }
+ }
+
+ None
+ })
+ }
+
+ pub fn has_doc_flag(&self, flag: Symbol) -> bool {
+ for attr in &self.other_attrs {
+ if !attr.check_name(sym::doc) { continue; }
+
+ if let Some(items) = attr.meta_item_list() {
+ if items.iter().filter_map(|i| i.meta_item()).any(|it| it.check_name(flag)) {
+ return true;
+ }
+ }
+ }
+
+ false
+ }
+
+ pub fn from_ast(diagnostic: &::errors::Handler, attrs: &[ast::Attribute]) -> Attributes {
+ let mut doc_strings = vec![];
+ let mut sp = None;
+ let mut cfg = Cfg::True;
+ let mut doc_line = 0;
+
+ /// If `attr` is a doc comment, strips the leading and (if present)
+ /// trailing comments symbols, e.g. `///`, `/**`, and `*/`. Otherwise,
+ /// returns `attr` unchanged.
+ pub fn with_doc_comment_markers_stripped<T>(
+ attr: &Attribute,
+ f: impl FnOnce(&Attribute) -> T,
+ ) -> T {
+ match attr.kind {
+ AttrKind::Normal(_) => {
+ f(attr)
+ }
+ AttrKind::DocComment(comment) => {
+ let comment =
+ Symbol::intern(&comments::strip_doc_comment_decoration(&comment.as_str()));
+ f(&Attribute {
+ kind: AttrKind::DocComment(comment),
+ id: attr.id,
+ style: attr.style,
+ span: attr.span,
+ })
+ }
+ }
+ }
+
+ let other_attrs = attrs.iter().filter_map(|attr| {
+ with_doc_comment_markers_stripped(attr, |attr| {
+ if attr.check_name(sym::doc) {
+ if let Some(mi) = attr.meta() {
+ if let Some(value) = mi.value_str() {
+ // Extracted #[doc = "..."]
+ let value = value.to_string();
+ let line = doc_line;
+ doc_line += value.lines().count();
+
+ if attr.is_doc_comment() {
+ doc_strings.push(DocFragment::SugaredDoc(line, attr.span, value));
+ } else {
+ doc_strings.push(DocFragment::RawDoc(line, attr.span, value));
+ }
+
+ if sp.is_none() {
+ sp = Some(attr.span);
+ }
+ return None;
+ } else if let Some(cfg_mi) = Attributes::extract_cfg(&mi) {
+ // Extracted #[doc(cfg(...))]
+ match Cfg::parse(cfg_mi) {
+ Ok(new_cfg) => cfg &= new_cfg,
+ Err(e) => diagnostic.span_err(e.span, e.msg),
+ }
+ return None;
+ } else if let Some((filename, contents)) = Attributes::extract_include(&mi)
+ {
+ let line = doc_line;
+ doc_line += contents.lines().count();
+ doc_strings.push(DocFragment::Include(line,
+ attr.span,
+ filename,
+ contents));
+ }
+ }
+ }
+ Some(attr.clone())
+ })
+ }).collect();
+
+ // treat #[target_feature(enable = "feat")] attributes as if they were
+ // #[doc(cfg(target_feature = "feat"))] attributes as well
+ for attr in attrs.lists(sym::target_feature) {
+ if attr.check_name(sym::enable) {
+ if let Some(feat) = attr.value_str() {
+ let meta = attr::mk_name_value_item_str(
+ Ident::with_dummy_span(sym::target_feature), feat, DUMMY_SP
+ );
+ if let Ok(feat_cfg) = Cfg::parse(&meta) {
+ cfg &= feat_cfg;
+ }
+ }
+ }
+ }
+
+ let inner_docs = attrs.iter()
+ .filter(|a| a.check_name(sym::doc))
+ .next()
+ .map_or(true, |a| a.style == AttrStyle::Inner);
+
+ Attributes {
+ doc_strings,
+ other_attrs,
+ cfg: if cfg == Cfg::True { None } else { Some(Arc::new(cfg)) },
+ span: sp,
+ links: vec![],
+ inner_docs,
+ }
+ }
+
+ /// Finds the `doc` attribute as a NameValue and returns the corresponding
+ /// value found.
+ pub fn doc_value(&self) -> Option<&str> {
+ self.doc_strings.first().map(|s| s.as_str())
+ }
+
+ /// Finds all `doc` attributes as NameValues and returns their corresponding values, joined
+ /// with newlines.
+ pub fn collapsed_doc_value(&self) -> Option<String> {
+ if !self.doc_strings.is_empty() {
+ Some(self.doc_strings.iter().collect())
+ } else {
+ None
+ }
+ }
+
+ /// Gets links as a vector
+ ///
+ /// Cache must be populated before call
+ pub fn links(&self, krate: &CrateNum) -> Vec<(String, String)> {
+ use crate::html::format::href;
+
+ self.links.iter().filter_map(|&(ref s, did, ref fragment)| {
+ match did {
+ Some(did) => {
+ if let Some((mut href, ..)) = href(did) {
+ if let Some(ref fragment) = *fragment {
+ href.push_str("#");
+ href.push_str(fragment);
+ }
+ Some((s.clone(), href))
+ } else {
+ None
+ }
+ }
+ None => {
+ if let Some(ref fragment) = *fragment {
+ let cache = cache();
+ let url = match cache.extern_locations.get(krate) {
+ Some(&(_, ref src, ExternalLocation::Local)) =>
+ src.to_str().expect("invalid file path"),
+ Some(&(_, _, ExternalLocation::Remote(ref s))) => s,
+ Some(&(_, _, ExternalLocation::Unknown)) | None =>
+ "https://doc.rust-lang.org/nightly",
+ };
+ // This is a primitive so the url is done "by hand".
+ let tail = fragment.find('#').unwrap_or_else(|| fragment.len());
+ Some((s.clone(),
+ format!("{}{}std/primitive.{}.html{}",
+ url,
+ if !url.ends_with('/') { "/" } else { "" },
+ &fragment[..tail],
+ &fragment[tail..])))
+ } else {
+ panic!("This isn't a primitive?!");
+ }
+ }
+ }
+ }).collect()
+ }
+}
+
+impl PartialEq for Attributes {
+ fn eq(&self, rhs: &Self) -> bool {
+ self.doc_strings == rhs.doc_strings &&
+ self.cfg == rhs.cfg &&
+ self.span == rhs.span &&
+ self.links == rhs.links &&
+ self.other_attrs.iter().map(|attr| attr.id).eq(rhs.other_attrs.iter().map(|attr| attr.id))
+ }
+}
+
+impl Eq for Attributes {}
+
+impl Hash for Attributes {
+ fn hash<H: Hasher>(&self, hasher: &mut H) {
+ self.doc_strings.hash(hasher);
+ self.cfg.hash(hasher);
+ self.span.hash(hasher);
+ self.links.hash(hasher);
+ for attr in &self.other_attrs {
+ attr.id.hash(hasher);
+ }
+ }
+}
+
+impl AttributesExt for Attributes {
+ fn lists(&self, name: Symbol) -> ListAttributesIter<'_> {
+ self.other_attrs.lists(name)
+ }
+}
+
+#[derive(Clone, PartialEq, Eq, Debug, Hash)]
+pub enum GenericBound {
+ TraitBound(PolyTrait, hir::TraitBoundModifier),
+ Outlives(Lifetime),
+}
+
+impl GenericBound {
+ pub fn maybe_sized(cx: &DocContext<'_>) -> GenericBound {
+ let did = cx.tcx.require_lang_item(lang_items::SizedTraitLangItem, None);
+ let empty = cx.tcx.intern_substs(&[]);
+ let path = external_path(cx, cx.tcx.item_name(did),
+ Some(did), false, vec![], empty);
+ inline::record_extern_fqn(cx, did, TypeKind::Trait);
+ GenericBound::TraitBound(PolyTrait {
+ trait_: ResolvedPath {
+ path,
+ param_names: None,
+ did,
+ is_generic: false,
+ },
+ generic_params: Vec::new(),
+ }, hir::TraitBoundModifier::Maybe)
+ }
+
+ pub fn is_sized_bound(&self, cx: &DocContext<'_>) -> bool {
+ use rustc::hir::TraitBoundModifier as TBM;
+ if let GenericBound::TraitBound(PolyTrait { ref trait_, .. }, TBM::None) = *self {
+ if trait_.def_id() == cx.tcx.lang_items().sized_trait() {
+ return true;
+ }
+ }
+ false
+ }
+
+ pub fn get_poly_trait(&self) -> Option<PolyTrait> {
+ if let GenericBound::TraitBound(ref p, _) = *self {
+ return Some(p.clone())
+ }
+ None
+ }
+
+ pub fn get_trait_type(&self) -> Option<Type> {
+ if let GenericBound::TraitBound(PolyTrait { ref trait_, .. }, _) = *self {
+ Some(trait_.clone())
+ } else {
+ None
+ }
+ }
+}
+
+#[derive(Clone, PartialEq, Eq, Debug, Hash)]
+pub struct Lifetime(pub String);
+
+impl Lifetime {
+ pub fn get_ref<'a>(&'a self) -> &'a str {
+ let Lifetime(ref s) = *self;
+ let s: &'a str = s;
+ s
+ }
+
+ pub fn statik() -> Lifetime {
+ Lifetime("'static".to_string())
+ }
+}
+
+#[derive(Clone, Debug)]
+pub enum WherePredicate {
+ BoundPredicate { ty: Type, bounds: Vec<GenericBound> },
+ RegionPredicate { lifetime: Lifetime, bounds: Vec<GenericBound> },
+ EqPredicate { lhs: Type, rhs: Type },
+}
+
+impl WherePredicate {
+ pub fn get_bounds(&self) -> Option<&[GenericBound]> {
+ match *self {
+ WherePredicate::BoundPredicate { ref bounds, .. } => Some(bounds),
+ WherePredicate::RegionPredicate { ref bounds, .. } => Some(bounds),
+ _ => None,
+ }
+ }
+}
+
+#[derive(Clone, PartialEq, Eq, Debug, Hash)]
+pub enum GenericParamDefKind {
+ Lifetime,
+ Type {
+ did: DefId,
+ bounds: Vec<GenericBound>,
+ default: Option<Type>,
+ synthetic: Option<hir::SyntheticTyParamKind>,
+ },
+ Const {
+ did: DefId,
+ ty: Type,
+ },
+}
+
+impl GenericParamDefKind {
+ pub fn is_type(&self) -> bool {
+ match *self {
+ GenericParamDefKind::Type { .. } => true,
+ _ => false,
+ }
+ }
+
+ // FIXME(eddyb) this either returns the default of a type parameter, or the
+ // type of a `const` parameter. It seems that the intention is to *visit*
+ // any embedded types, but `get_type` seems to be the wrong name for that.
+ pub fn get_type(&self) -> Option<Type> {
+ match self {
+ GenericParamDefKind::Type { default, .. } => default.clone(),
+ GenericParamDefKind::Const { ty, .. } => Some(ty.clone()),
+ GenericParamDefKind::Lifetime => None,
+ }
+ }
+}
+
+#[derive(Clone, PartialEq, Eq, Debug, Hash)]
+pub struct GenericParamDef {
+ pub name: String,
+ pub kind: GenericParamDefKind,
+}
+
+impl GenericParamDef {
+ pub fn is_synthetic_type_param(&self) -> bool {
+ match self.kind {
+ GenericParamDefKind::Lifetime |
+ GenericParamDefKind::Const { .. } => false,
+ GenericParamDefKind::Type { ref synthetic, .. } => synthetic.is_some(),
+ }
+ }
+
+ pub fn is_type(&self) -> bool {
+ self.kind.is_type()
+ }
+
+ pub fn get_type(&self) -> Option<Type> {
+ self.kind.get_type()
+ }
+
+ pub fn get_bounds(&self) -> Option<&[GenericBound]> {
+ match self.kind {
+ GenericParamDefKind::Type { ref bounds, .. } => Some(bounds),
+ _ => None,
+ }
+ }
+}
+
+// maybe use a Generic enum and use Vec<Generic>?
+#[derive(Clone, Debug, Default)]
+pub struct Generics {
+ pub params: Vec<GenericParamDef>,
+ pub where_predicates: Vec<WherePredicate>,
+}
+
+#[derive(Clone, Debug)]
+pub struct Method {
+ pub generics: Generics,
+ pub decl: FnDecl,
+ pub header: hir::FnHeader,
+ pub defaultness: Option<hir::Defaultness>,
+ pub all_types: Vec<Type>,
+ pub ret_types: Vec<Type>,
+}
+
+#[derive(Clone, Debug)]
+pub struct TyMethod {
+ pub header: hir::FnHeader,
+ pub decl: FnDecl,
+ pub generics: Generics,
+ pub all_types: Vec<Type>,
+ pub ret_types: Vec<Type>,
+}
+
+#[derive(Clone, Debug)]
+pub struct Function {
+ pub decl: FnDecl,
+ pub generics: Generics,
+ pub header: hir::FnHeader,
+ pub all_types: Vec<Type>,
+ pub ret_types: Vec<Type>,
+}
+
+#[derive(Clone, PartialEq, Eq, Debug, Hash)]
+pub struct FnDecl {
+ pub inputs: Arguments,
+ pub output: FunctionRetTy,
+ pub c_variadic: bool,
+ pub attrs: Attributes,
+}
+
+impl FnDecl {
+ pub fn self_type(&self) -> Option<SelfTy> {
+ self.inputs.values.get(0).and_then(|v| v.to_self())
+ }
+
+ /// Returns the sugared return type for an async function.
+ ///
+ /// For example, if the return type is `impl std::future::Future<Output = i32>`, this function
+ /// will return `i32`.
+ ///
+ /// # Panics
+ ///
+ /// This function will panic if the return type does not match the expected sugaring for async
+ /// functions.
+ pub fn sugared_async_return_type(&self) -> FunctionRetTy {
+ match &self.output {
+ FunctionRetTy::Return(Type::ImplTrait(bounds)) => {
+ match &bounds[0] {
+ GenericBound::TraitBound(PolyTrait { trait_, .. }, ..) => {
+ let bindings = trait_.bindings().unwrap();
+ FunctionRetTy::Return(bindings[0].ty().clone())
+ }
+ _ => panic!("unexpected desugaring of async function"),
+ }
+ }
+ _ => panic!("unexpected desugaring of async function"),
+ }
+ }
+}
+
+#[derive(Clone, PartialEq, Eq, Debug, Hash)]
+pub struct Arguments {
+ pub values: Vec<Argument>,
+}
+
+#[derive(Clone, PartialEq, Eq, Debug, Hash)]
+pub struct Argument {
+ pub type_: Type,
+ pub name: String,
+}
+
+#[derive(Clone, PartialEq, Debug)]
+pub enum SelfTy {
+ SelfValue,
+ SelfBorrowed(Option<Lifetime>, Mutability),
+ SelfExplicit(Type),
+}
+
+impl Argument {
+ pub fn to_self(&self) -> Option<SelfTy> {
+ if self.name != "self" {
+ return None;
+ }
+ if self.type_.is_self_type() {
+ return Some(SelfValue);
+ }
+ match self.type_ {
+ BorrowedRef{ref lifetime, mutability, ref type_} if type_.is_self_type() => {
+ Some(SelfBorrowed(lifetime.clone(), mutability))
+ }
+ _ => Some(SelfExplicit(self.type_.clone()))
+ }
+ }
+}
+
+#[derive(Clone, PartialEq, Eq, Debug, Hash)]
+pub enum FunctionRetTy {
+ Return(Type),
+ DefaultReturn,
+}
+
+impl GetDefId for FunctionRetTy {
+ fn def_id(&self) -> Option<DefId> {
+ match *self {
+ Return(ref ty) => ty.def_id(),
+ DefaultReturn => None,
+ }
+ }
+}
+
+#[derive(Clone, Debug)]
+pub struct Trait {
+ pub auto: bool,
+ pub unsafety: hir::Unsafety,
+ pub items: Vec<Item>,
+ pub generics: Generics,
+ pub bounds: Vec<GenericBound>,
+ pub is_spotlight: bool,
+ pub is_auto: bool,
+}
+
+#[derive(Clone, Debug)]
+pub struct TraitAlias {
+ pub generics: Generics,
+ pub bounds: Vec<GenericBound>,
+}
+
+/// A trait reference, which may have higher ranked lifetimes.
+#[derive(Clone, PartialEq, Eq, Debug, Hash)]
+pub struct PolyTrait {
+ pub trait_: Type,
+ pub generic_params: Vec<GenericParamDef>,
+}
+
+/// A representation of a type suitable for hyperlinking purposes. Ideally, one can get the original
+/// type out of the AST/`TyCtxt` given one of these, if more information is needed. Most
+/// importantly, it does not preserve mutability or boxes.
+#[derive(Clone, PartialEq, Eq, Debug, Hash)]
+pub enum Type {
+ /// Structs/enums/traits (most that would be an `hir::TyKind::Path`).
+ ResolvedPath {
+ path: Path,
+ param_names: Option<Vec<GenericBound>>,
+ did: DefId,
+ /// `true` if is a `T::Name` path for associated types.
+ is_generic: bool,
+ },
+ /// For parameterized types, so the consumer of the JSON don't go
+ /// looking for types which don't exist anywhere.
+ Generic(String),
+ /// Primitives are the fixed-size numeric types (plus int/usize/float), char,
+ /// arrays, slices, and tuples.
+ Primitive(PrimitiveType),
+ /// `extern "ABI" fn`
+ BareFunction(Box<BareFunctionDecl>),
+ Tuple(Vec<Type>),
+ Slice(Box<Type>),
+ Array(Box<Type>, String),
+ Never,
+ RawPointer(Mutability, Box<Type>),
+ BorrowedRef {
+ lifetime: Option<Lifetime>,
+ mutability: Mutability,
+ type_: Box<Type>,
+ },
+
+ // `<Type as Trait>::Name`
+ QPath {
+ name: String,
+ self_type: Box<Type>,
+ trait_: Box<Type>
+ },
+
+ // `_`
+ Infer,
+
+ // `impl TraitA + TraitB + ...`
+ ImplTrait(Vec<GenericBound>),
+}
+
+#[derive(Clone, PartialEq, Eq, Hash, Copy, Debug)]
+pub enum PrimitiveType {
+ Isize, I8, I16, I32, I64, I128,
+ Usize, U8, U16, U32, U64, U128,
+ F32, F64,
+ Char,
+ Bool,
+ Str,
+ Slice,
+ Array,
+ Tuple,
+ Unit,
+ RawPointer,
+ Reference,
+ Fn,
+ Never,
+}
+
+#[derive(Clone, Copy, Debug)]
+pub enum TypeKind {
+ Enum,
+ Function,
+ Module,
+ Const,
+ Static,
+ Struct,
+ Union,
+ Trait,
+ Typedef,
+ Foreign,
+ Macro,
+ Attr,
+ Derive,
+ TraitAlias,
+}
+
+pub trait GetDefId {
+ fn def_id(&self) -> Option<DefId>;
+}
+
+impl<T: GetDefId> GetDefId for Option<T> {
+ fn def_id(&self) -> Option<DefId> {
+ self.as_ref().and_then(|d| d.def_id())
+ }
+}
+
+impl Type {
+ pub fn primitive_type(&self) -> Option<PrimitiveType> {
+ match *self {
+ Primitive(p) | BorrowedRef { type_: box Primitive(p), ..} => Some(p),
+ Slice(..) | BorrowedRef { type_: box Slice(..), .. } => Some(PrimitiveType::Slice),
+ Array(..) | BorrowedRef { type_: box Array(..), .. } => Some(PrimitiveType::Array),
+ Tuple(ref tys) => if tys.is_empty() {
+ Some(PrimitiveType::Unit)
+ } else {
+ Some(PrimitiveType::Tuple)
+ },
+ RawPointer(..) => Some(PrimitiveType::RawPointer),
+ BorrowedRef { type_: box Generic(..), .. } => Some(PrimitiveType::Reference),
+ BareFunction(..) => Some(PrimitiveType::Fn),
+ Never => Some(PrimitiveType::Never),
+ _ => None,
+ }
+ }
+
+ pub fn is_generic(&self) -> bool {
+ match *self {
+ ResolvedPath { is_generic, .. } => is_generic,
+ _ => false,
+ }
+ }
+
+ pub fn is_self_type(&self) -> bool {
+ match *self {
+ Generic(ref name) => name == "Self",
+ _ => false
+ }
+ }
+
+ pub fn generics(&self) -> Option<Vec<Type>> {
+ match *self {
+ ResolvedPath { ref path, .. } => {
+ path.segments.last().and_then(|seg| {
+ if let GenericArgs::AngleBracketed { ref args, .. } = seg.args {
+ Some(args.iter().filter_map(|arg| match arg {
+ GenericArg::Type(ty) => Some(ty.clone()),
+ _ => None,
+ }).collect())
+ } else {
+ None
+ }
+ })
+ }
+ _ => None,
+ }
+ }
+
+ pub fn bindings(&self) -> Option<&[TypeBinding]> {
+ match *self {
+ ResolvedPath { ref path, .. } => {
+ path.segments.last().and_then(|seg| {
+ if let GenericArgs::AngleBracketed { ref bindings, .. } = seg.args {
+ Some(&**bindings)
+ } else {
+ None
+ }
+ })
+ }
+ _ => None
+ }
+ }
+
+ pub fn is_full_generic(&self) -> bool {
+ match *self {
+ Type::Generic(_) => true,
+ _ => false,
+ }
+ }
+
+ pub fn projection(&self) -> Option<(&Type, DefId, &str)> {
+ let (self_, trait_, name) = match self {
+ QPath { ref self_type, ref trait_, ref name } => {
+ (self_type, trait_, name)
+ }
+ _ => return None,
+ };
+ let trait_did = match **trait_ {
+ ResolvedPath { did, .. } => did,
+ _ => return None,
+ };
+ Some((&self_, trait_did, name))
+ }
+
+}
+
+impl GetDefId for Type {
+ fn def_id(&self) -> Option<DefId> {
+ match *self {
+ ResolvedPath { did, .. } => Some(did),
+ Primitive(p) => crate::html::render::cache().primitive_locations.get(&p).cloned(),
+ BorrowedRef { type_: box Generic(..), .. } =>
+ Primitive(PrimitiveType::Reference).def_id(),
+ BorrowedRef { ref type_, .. } => type_.def_id(),
+ Tuple(ref tys) => if tys.is_empty() {
+ Primitive(PrimitiveType::Unit).def_id()
+ } else {
+ Primitive(PrimitiveType::Tuple).def_id()
+ },
+ BareFunction(..) => Primitive(PrimitiveType::Fn).def_id(),
+ Never => Primitive(PrimitiveType::Never).def_id(),
+ Slice(..) => Primitive(PrimitiveType::Slice).def_id(),
+ Array(..) => Primitive(PrimitiveType::Array).def_id(),
+ RawPointer(..) => Primitive(PrimitiveType::RawPointer).def_id(),
+ QPath { ref self_type, .. } => self_type.def_id(),
+ _ => None,
+ }
+ }
+}
+
+impl PrimitiveType {
+ pub fn from_str(s: &str) -> Option<PrimitiveType> {
+ match s {
+ "isize" => Some(PrimitiveType::Isize),
+ "i8" => Some(PrimitiveType::I8),
+ "i16" => Some(PrimitiveType::I16),
+ "i32" => Some(PrimitiveType::I32),
+ "i64" => Some(PrimitiveType::I64),
+ "i128" => Some(PrimitiveType::I128),
+ "usize" => Some(PrimitiveType::Usize),
+ "u8" => Some(PrimitiveType::U8),
+ "u16" => Some(PrimitiveType::U16),
+ "u32" => Some(PrimitiveType::U32),
+ "u64" => Some(PrimitiveType::U64),
+ "u128" => Some(PrimitiveType::U128),
+ "bool" => Some(PrimitiveType::Bool),
+ "char" => Some(PrimitiveType::Char),
+ "str" => Some(PrimitiveType::Str),
+ "f32" => Some(PrimitiveType::F32),
+ "f64" => Some(PrimitiveType::F64),
+ "array" => Some(PrimitiveType::Array),
+ "slice" => Some(PrimitiveType::Slice),
+ "tuple" => Some(PrimitiveType::Tuple),
+ "unit" => Some(PrimitiveType::Unit),
+ "pointer" => Some(PrimitiveType::RawPointer),
+ "reference" => Some(PrimitiveType::Reference),
+ "fn" => Some(PrimitiveType::Fn),
+ "never" => Some(PrimitiveType::Never),
+ _ => None,
+ }
+ }
+
+ pub fn as_str(&self) -> &'static str {
+ use self::PrimitiveType::*;
+ match *self {
+ Isize => "isize",
+ I8 => "i8",
+ I16 => "i16",
+ I32 => "i32",
+ I64 => "i64",
+ I128 => "i128",
+ Usize => "usize",
+ U8 => "u8",
+ U16 => "u16",
+ U32 => "u32",
+ U64 => "u64",
+ U128 => "u128",
+ F32 => "f32",
+ F64 => "f64",
+ Str => "str",
+ Bool => "bool",
+ Char => "char",
+ Array => "array",
+ Slice => "slice",
+ Tuple => "tuple",
+ Unit => "unit",
+ RawPointer => "pointer",
+ Reference => "reference",
+ Fn => "fn",
+ Never => "never",
+ }
+ }
+
+ pub fn to_url_str(&self) -> &'static str {
+ self.as_str()
+ }
+}
+
+impl From<ast::IntTy> for PrimitiveType {
+ fn from(int_ty: ast::IntTy) -> PrimitiveType {
+ match int_ty {
+ ast::IntTy::Isize => PrimitiveType::Isize,
+ ast::IntTy::I8 => PrimitiveType::I8,
+ ast::IntTy::I16 => PrimitiveType::I16,
+ ast::IntTy::I32 => PrimitiveType::I32,
+ ast::IntTy::I64 => PrimitiveType::I64,
+ ast::IntTy::I128 => PrimitiveType::I128,
+ }
+ }
+}
+
+impl From<ast::UintTy> for PrimitiveType {
+ fn from(uint_ty: ast::UintTy) -> PrimitiveType {
+ match uint_ty {
+ ast::UintTy::Usize => PrimitiveType::Usize,
+ ast::UintTy::U8 => PrimitiveType::U8,
+ ast::UintTy::U16 => PrimitiveType::U16,
+ ast::UintTy::U32 => PrimitiveType::U32,
+ ast::UintTy::U64 => PrimitiveType::U64,
+ ast::UintTy::U128 => PrimitiveType::U128,
+ }
+ }
+}
+
+impl From<ast::FloatTy> for PrimitiveType {
+ fn from(float_ty: ast::FloatTy) -> PrimitiveType {
+ match float_ty {
+ ast::FloatTy::F32 => PrimitiveType::F32,
+ ast::FloatTy::F64 => PrimitiveType::F64,
+ }
+ }
+}
+
+#[derive(Clone, PartialEq, Eq, Debug)]
+pub enum Visibility {
+ Public,
+ Inherited,
+ Crate,
+ Restricted(DefId, Path),
+}
+
+#[derive(Clone, Debug)]
+pub struct Struct {
+ pub struct_type: doctree::StructType,
+ pub generics: Generics,
+ pub fields: Vec<Item>,
+ pub fields_stripped: bool,
+}
+
+#[derive(Clone, Debug)]
+pub struct Union {
+ pub struct_type: doctree::StructType,
+ pub generics: Generics,
+ pub fields: Vec<Item>,
+ pub fields_stripped: bool,
+}
+
+/// This is a more limited form of the standard Struct, different in that
+/// it lacks the things most items have (name, id, parameterization). Found
+/// only as a variant in an enum.
+#[derive(Clone, Debug)]
+pub struct VariantStruct {
+ pub struct_type: doctree::StructType,
+ pub fields: Vec<Item>,
+ pub fields_stripped: bool,
+}
+
+#[derive(Clone, Debug)]
+pub struct Enum {
+ pub variants: IndexVec<VariantIdx, Item>,
+ pub generics: Generics,
+ pub variants_stripped: bool,
+}
+
+#[derive(Clone, Debug)]
+pub struct Variant {
+ pub kind: VariantKind,
+}
+
+#[derive(Clone, Debug)]
+pub enum VariantKind {
+ CLike,
+ Tuple(Vec<Type>),
+ Struct(VariantStruct),
+}
+
+#[derive(Clone, Debug)]
+pub struct Span {
+ pub filename: FileName,
+ pub loline: usize,
+ pub locol: usize,
+ pub hiline: usize,
+ pub hicol: usize,
+ pub original: syntax_pos::Span,
+}
+
+impl Span {
+ pub fn empty() -> Span {
+ Span {
+ filename: FileName::Anon(0),
+ loline: 0, locol: 0,
+ hiline: 0, hicol: 0,
+ original: syntax_pos::DUMMY_SP,
+ }
+ }
+
+ pub fn span(&self) -> syntax_pos::Span {
+ self.original
+ }
+}
+
+#[derive(Clone, PartialEq, Eq, Debug, Hash)]
+pub struct Path {
+ pub global: bool,
+ pub res: Res,
+ pub segments: Vec<PathSegment>,
+}
+
+impl Path {
+ pub fn last_name(&self) -> &str {
+ self.segments.last().expect("segments were empty").name.as_str()
+ }
+}
+
+#[derive(Clone, PartialEq, Eq, Debug, Hash)]
+pub enum GenericArg {
+ Lifetime(Lifetime),
+ Type(Type),
+ Const(Constant),
+}
+
+#[derive(Clone, PartialEq, Eq, Debug, Hash)]
+pub enum GenericArgs {
+ AngleBracketed {
+ args: Vec<GenericArg>,
+ bindings: Vec<TypeBinding>,
+ },
+ Parenthesized {
+ inputs: Vec<Type>,
+ output: Option<Type>,
+ }
+}
+
+#[derive(Clone, PartialEq, Eq, Debug, Hash)]
+pub struct PathSegment {
+ pub name: String,
+ pub args: GenericArgs,
+}
+
+#[derive(Clone, Debug)]
+pub struct Typedef {
+ pub type_: Type,
+ pub generics: Generics,
+}
+
+#[derive(Clone, Debug)]
+pub struct OpaqueTy {
+ pub bounds: Vec<GenericBound>,
+ pub generics: Generics,
+}
+
+#[derive(Clone, PartialEq, Eq, Debug, Hash)]
+pub struct BareFunctionDecl {
+ pub unsafety: hir::Unsafety,
+ pub generic_params: Vec<GenericParamDef>,
+ pub decl: FnDecl,
+ pub abi: Abi,
+}
+
+#[derive(Clone, Debug)]
+pub struct Static {
+ pub type_: Type,
+ pub mutability: Mutability,
+ /// It's useful to have the value of a static documented, but I have no
+ /// desire to represent expressions (that'd basically be all of the AST,
+ /// which is huge!). So, have a string.
+ pub expr: String,
+}
+
+#[derive(Clone, PartialEq, Eq, Hash, Debug)]
+pub struct Constant {
+ pub type_: Type,
+ pub expr: String,
+}
+
+#[derive(Debug, Clone, PartialEq, Eq, Copy, Hash)]
+pub enum Mutability {
+ Mutable,
+ Immutable,
+}
+
+#[derive(Clone, PartialEq, Debug)]
+pub enum ImplPolarity {
+ Positive,
+ Negative,
+}
+
+#[derive(Clone, Debug)]
+pub struct Impl {
+ pub unsafety: hir::Unsafety,
+ pub generics: Generics,
+ pub provided_trait_methods: FxHashSet<String>,
+ pub trait_: Option<Type>,
+ pub for_: Type,
+ pub items: Vec<Item>,
+ pub polarity: Option<ImplPolarity>,
+ pub synthetic: bool,
+ pub blanket_impl: Option<Type>,
+}
+
+#[derive(Clone, Debug)]
+pub enum Import {
+ // use source as str;
+ Simple(String, ImportSource),
+ // use source::*;
+ Glob(ImportSource)
+}
+
+#[derive(Clone, Debug)]
+pub struct ImportSource {
+ pub path: Path,
+ pub did: Option<DefId>,
+}
+
+#[derive(Clone, Debug)]
+pub struct Macro {
+ pub source: String,
+ pub imported_from: Option<String>,
+}
+
+#[derive(Clone, Debug)]
+pub struct ProcMacro {
+ pub kind: MacroKind,
+ pub helpers: Vec<String>,
+}
+
+#[derive(Clone, Debug)]
+pub struct Stability {
+ pub level: stability::StabilityLevel,
+ pub feature: Option<String>,
+ pub since: String,
+ pub deprecation: Option<Deprecation>,
+ pub unstable_reason: Option<String>,
+ pub issue: Option<NonZeroU32>,
+}
+
+#[derive(Clone, Debug)]
+pub struct Deprecation {
+ pub since: Option<String>,
+ pub note: Option<String>,
+}
+
+/// An type binding on an associated type (e.g., `A = Bar` in `Foo<A = Bar>` or
+/// `A: Send + Sync` in `Foo<A: Send + Sync>`).
+#[derive(Clone, PartialEq, Eq, Debug, Hash)]
+pub struct TypeBinding {
+ pub name: String,
+ pub kind: TypeBindingKind,
+}
+
+#[derive(Clone, PartialEq, Eq, Debug, Hash)]
+pub enum TypeBindingKind {
+ Equality {
+ ty: Type,
+ },
+ Constraint {
+ bounds: Vec<GenericBound>,
+ },
+}
+
+impl TypeBinding {
+ pub fn ty(&self) -> &Type {
+ match self.kind {
+ TypeBindingKind::Equality { ref ty } => ty,
+ _ => panic!("expected equality type binding for parenthesized generic args"),
+ }
+ }
+}
diff --git a/src/librustdoc/clean/utils.rs b/src/librustdoc/clean/utils.rs
new file mode 100644
index 0000000..e46300a
--- /dev/null
+++ b/src/librustdoc/clean/utils.rs
@@ -0,0 +1,585 @@
+use crate::core::DocContext;
+use crate::clean::{
+ Clean, Crate, Deprecation, ExternalCrate, FnDecl, FunctionRetTy, Generic, GenericArg,
+ GenericArgs, Generics, GenericBound, GetDefId, ImportSource, Item, ItemEnum, MacroKind, Path,
+ PathSegment, Primitive, PrimitiveType, ResolvedPath, Span, Stability, Type, TypeBinding,
+ TypeKind, Visibility, WherePredicate, inline,
+};
+use crate::clean::blanket_impl::BlanketImplFinder;
+use crate::clean::auto_trait::AutoTraitFinder;
+
+use rustc::hir;
+use rustc::hir::def::{DefKind, Res};
+use rustc::hir::def_id::{DefId, LOCAL_CRATE};
+use rustc::ty::{self, DefIdTree, Ty};
+use rustc::ty::subst::{SubstsRef, GenericArgKind};
+use rustc::util::nodemap::FxHashSet;
+use syntax_pos;
+use syntax_pos::symbol::{Symbol, kw, sym};
+
+use std::mem;
+
+pub fn krate(mut cx: &mut DocContext<'_>) -> Crate {
+ use crate::visit_lib::LibEmbargoVisitor;
+
+ let krate = cx.tcx.hir().krate();
+ let module = crate::visit_ast::RustdocVisitor::new(&mut cx).visit(krate);
+
+ let mut r = cx.renderinfo.get_mut();
+ r.deref_trait_did = cx.tcx.lang_items().deref_trait();
+ r.deref_mut_trait_did = cx.tcx.lang_items().deref_mut_trait();
+ r.owned_box_did = cx.tcx.lang_items().owned_box();
+
+ let mut externs = Vec::new();
+ for &cnum in cx.tcx.crates().iter() {
+ externs.push((cnum, cnum.clean(cx)));
+ // Analyze doc-reachability for extern items
+ LibEmbargoVisitor::new(&mut cx).visit_lib(cnum);
+ }
+ externs.sort_by(|&(a, _), &(b, _)| a.cmp(&b));
+
+ // Clean the crate, translating the entire libsyntax AST to one that is
+ // understood by rustdoc.
+ let mut module = module.clean(cx);
+ let mut masked_crates = FxHashSet::default();
+
+ match module.inner {
+ ItemEnum::ModuleItem(ref module) => {
+ for it in &module.items {
+ // `compiler_builtins` should be masked too, but we can't apply
+ // `#[doc(masked)]` to the injected `extern crate` because it's unstable.
+ if it.is_extern_crate()
+ && (it.attrs.has_doc_flag(sym::masked)
+ || cx.tcx.is_compiler_builtins(it.def_id.krate))
+ {
+ masked_crates.insert(it.def_id.krate);
+ }
+ }
+ }
+ _ => unreachable!(),
+ }
+
+ let ExternalCrate { name, src, primitives, keywords, .. } = LOCAL_CRATE.clean(cx);
+ {
+ let m = match module.inner {
+ ItemEnum::ModuleItem(ref mut m) => m,
+ _ => unreachable!(),
+ };
+ m.items.extend(primitives.iter().map(|&(def_id, prim, ref attrs)| {
+ Item {
+ source: Span::empty(),
+ name: Some(prim.to_url_str().to_string()),
+ attrs: attrs.clone(),
+ visibility: Visibility::Public,
+ stability: get_stability(cx, def_id),
+ deprecation: get_deprecation(cx, def_id),
+ def_id,
+ inner: ItemEnum::PrimitiveItem(prim),
+ }
+ }));
+ m.items.extend(keywords.into_iter().map(|(def_id, kw, attrs)| {
+ Item {
+ source: Span::empty(),
+ name: Some(kw.clone()),
+ attrs,
+ visibility: Visibility::Public,
+ stability: get_stability(cx, def_id),
+ deprecation: get_deprecation(cx, def_id),
+ def_id,
+ inner: ItemEnum::KeywordItem(kw),
+ }
+ }));
+ }
+
+ Crate {
+ name,
+ version: None,
+ src,
+ module: Some(module),
+ externs,
+ primitives,
+ external_traits: cx.external_traits.clone(),
+ masked_crates,
+ collapsed: false,
+ }
+}
+
+// extract the stability index for a node from tcx, if possible
+pub fn get_stability(cx: &DocContext<'_>, def_id: DefId) -> Option<Stability> {
+ cx.tcx.lookup_stability(def_id).clean(cx)
+}
+
+pub fn get_deprecation(cx: &DocContext<'_>, def_id: DefId) -> Option<Deprecation> {
+ cx.tcx.lookup_deprecation(def_id).clean(cx)
+}
+
+pub fn external_generic_args(
+ cx: &DocContext<'_>,
+ trait_did: Option<DefId>,
+ has_self: bool,
+ bindings: Vec<TypeBinding>,
+ substs: SubstsRef<'_>,
+) -> GenericArgs {
+ let mut skip_self = has_self;
+ let mut ty_kind = None;
+ let args: Vec<_> = substs.iter().filter_map(|kind| match kind.unpack() {
+ GenericArgKind::Lifetime(lt) => {
+ lt.clean(cx).and_then(|lt| Some(GenericArg::Lifetime(lt)))
+ }
+ GenericArgKind::Type(_) if skip_self => {
+ skip_self = false;
+ None
+ }
+ GenericArgKind::Type(ty) => {
+ ty_kind = Some(&ty.kind);
+ Some(GenericArg::Type(ty.clean(cx)))
+ }
+ GenericArgKind::Const(ct) => Some(GenericArg::Const(ct.clean(cx))),
+ }).collect();
+
+ match trait_did {
+ // Attempt to sugar an external path like Fn<(A, B,), C> to Fn(A, B) -> C
+ Some(did) if cx.tcx.lang_items().fn_trait_kind(did).is_some() => {
+ assert!(ty_kind.is_some());
+ let inputs = match ty_kind {
+ Some(ty::Tuple(ref tys)) => tys.iter().map(|t| t.expect_ty().clean(cx)).collect(),
+ _ => return GenericArgs::AngleBracketed { args, bindings },
+ };
+ let output = None;
+ // FIXME(#20299) return type comes from a projection now
+ // match types[1].kind {
+ // ty::Tuple(ref v) if v.is_empty() => None, // -> ()
+ // _ => Some(types[1].clean(cx))
+ // };
+ GenericArgs::Parenthesized { inputs, output }
+ },
+ _ => {
+ GenericArgs::AngleBracketed { args, bindings }
+ }
+ }
+}
+
+// trait_did should be set to a trait's DefId if called on a TraitRef, in order to sugar
+// from Fn<(A, B,), C> to Fn(A, B) -> C
+pub fn external_path(cx: &DocContext<'_>, name: Symbol, trait_did: Option<DefId>, has_self: bool,
+ bindings: Vec<TypeBinding>, substs: SubstsRef<'_>) -> Path {
+ Path {
+ global: false,
+ res: Res::Err,
+ segments: vec![PathSegment {
+ name: name.to_string(),
+ args: external_generic_args(cx, trait_did, has_self, bindings, substs)
+ }],
+ }
+}
+
+/// The point of this function is to replace bounds with types.
+///
+/// i.e. `[T, U]` when you have the following bounds: `T: Display, U: Option<T>` will return
+/// `[Display, Option]` (we just returns the list of the types, we don't care about the
+/// wrapped types in here).
+pub fn get_real_types(
+ generics: &Generics,
+ arg: &Type,
+ cx: &DocContext<'_>,
+ recurse: i32,
+) -> FxHashSet<Type> {
+ let arg_s = arg.print().to_string();
+ let mut res = FxHashSet::default();
+ if recurse >= 10 { // FIXME: remove this whole recurse thing when the recursion bug is fixed
+ return res;
+ }
+ if arg.is_full_generic() {
+ if let Some(where_pred) = generics.where_predicates.iter().find(|g| {
+ match g {
+ &WherePredicate::BoundPredicate { ref ty, .. } => ty.def_id() == arg.def_id(),
+ _ => false,
+ }
+ }) {
+ let bounds = where_pred.get_bounds().unwrap_or_else(|| &[]);
+ for bound in bounds.iter() {
+ match *bound {
+ GenericBound::TraitBound(ref poly_trait, _) => {
+ for x in poly_trait.generic_params.iter() {
+ if !x.is_type() {
+ continue
+ }
+ if let Some(ty) = x.get_type() {
+ let adds = get_real_types(generics, &ty, cx, recurse + 1);
+ if !adds.is_empty() {
+ res.extend(adds);
+ } else if !ty.is_full_generic() {
+ res.insert(ty);
+ }
+ }
+ }
+ }
+ _ => {}
+ }
+ }
+ }
+ if let Some(bound) = generics.params.iter().find(|g| {
+ g.is_type() && g.name == arg_s
+ }) {
+ for bound in bound.get_bounds().unwrap_or_else(|| &[]) {
+ if let Some(ty) = bound.get_trait_type() {
+ let adds = get_real_types(generics, &ty, cx, recurse + 1);
+ if !adds.is_empty() {
+ res.extend(adds);
+ } else if !ty.is_full_generic() {
+ res.insert(ty.clone());
+ }
+ }
+ }
+ }
+ } else {
+ res.insert(arg.clone());
+ if let Some(gens) = arg.generics() {
+ for gen in gens.iter() {
+ if gen.is_full_generic() {
+ let adds = get_real_types(generics, gen, cx, recurse + 1);
+ if !adds.is_empty() {
+ res.extend(adds);
+ }
+ } else {
+ res.insert(gen.clone());
+ }
+ }
+ }
+ }
+ res
+}
+
+/// Return the full list of types when bounds have been resolved.
+///
+/// i.e. `fn foo<A: Display, B: Option<A>>(x: u32, y: B)` will return
+/// `[u32, Display, Option]`.
+pub fn get_all_types(
+ generics: &Generics,
+ decl: &FnDecl,
+ cx: &DocContext<'_>,
+) -> (Vec<Type>, Vec<Type>) {
+ let mut all_types = FxHashSet::default();
+ for arg in decl.inputs.values.iter() {
+ if arg.type_.is_self_type() {
+ continue;
+ }
+ let args = get_real_types(generics, &arg.type_, cx, 0);
+ if !args.is_empty() {
+ all_types.extend(args);
+ } else {
+ all_types.insert(arg.type_.clone());
+ }
+ }
+
+ let ret_types = match decl.output {
+ FunctionRetTy::Return(ref return_type) => {
+ let mut ret = get_real_types(generics, &return_type, cx, 0);
+ if ret.is_empty() {
+ ret.insert(return_type.clone());
+ }
+ ret.into_iter().collect()
+ }
+ _ => Vec::new(),
+ };
+ (all_types.into_iter().collect(), ret_types)
+}
+
+pub fn strip_type(ty: Type) -> Type {
+ match ty {
+ Type::ResolvedPath { path, param_names, did, is_generic } => {
+ Type::ResolvedPath { path: strip_path(&path), param_names, did, is_generic }
+ }
+ Type::Tuple(inner_tys) => {
+ Type::Tuple(inner_tys.iter().map(|t| strip_type(t.clone())).collect())
+ }
+ Type::Slice(inner_ty) => Type::Slice(Box::new(strip_type(*inner_ty))),
+ Type::Array(inner_ty, s) => Type::Array(Box::new(strip_type(*inner_ty)), s),
+ Type::RawPointer(m, inner_ty) => Type::RawPointer(m, Box::new(strip_type(*inner_ty))),
+ Type::BorrowedRef { lifetime, mutability, type_ } => {
+ Type::BorrowedRef { lifetime, mutability, type_: Box::new(strip_type(*type_)) }
+ }
+ Type::QPath { name, self_type, trait_ } => {
+ Type::QPath {
+ name,
+ self_type: Box::new(strip_type(*self_type)), trait_: Box::new(strip_type(*trait_))
+ }
+ }
+ _ => ty
+ }
+}
+
+pub fn strip_path(path: &Path) -> Path {
+ let segments = path.segments.iter().map(|s| {
+ PathSegment {
+ name: s.name.clone(),
+ args: GenericArgs::AngleBracketed {
+ args: vec![],
+ bindings: vec![],
+ }
+ }
+ }).collect();
+
+ Path {
+ global: path.global,
+ res: path.res.clone(),
+ segments,
+ }
+}
+
+pub fn qpath_to_string(p: &hir::QPath) -> String {
+ let segments = match *p {
+ hir::QPath::Resolved(_, ref path) => &path.segments,
+ hir::QPath::TypeRelative(_, ref segment) => return segment.ident.to_string(),
+ };
+
+ let mut s = String::new();
+ for (i, seg) in segments.iter().enumerate() {
+ if i > 0 {
+ s.push_str("::");
+ }
+ if seg.ident.name != kw::PathRoot {
+ s.push_str(&seg.ident.as_str());
+ }
+ }
+ s
+}
+
+pub fn build_deref_target_impls(cx: &DocContext<'_>,
+ items: &[Item],
+ ret: &mut Vec<Item>) {
+ use self::PrimitiveType::*;
+ let tcx = cx.tcx;
+
+ for item in items {
+ let target = match item.inner {
+ ItemEnum::TypedefItem(ref t, true) => &t.type_,
+ _ => continue,
+ };
+ let primitive = match *target {
+ ResolvedPath { did, .. } if did.is_local() => continue,
+ ResolvedPath { did, .. } => {
+ ret.extend(inline::build_impls(cx, did, None));
+ continue
+ }
+ _ => match target.primitive_type() {
+ Some(prim) => prim,
+ None => continue,
+ }
+ };
+ let did = match primitive {
+ Isize => tcx.lang_items().isize_impl(),
+ I8 => tcx.lang_items().i8_impl(),
+ I16 => tcx.lang_items().i16_impl(),
+ I32 => tcx.lang_items().i32_impl(),
+ I64 => tcx.lang_items().i64_impl(),
+ I128 => tcx.lang_items().i128_impl(),
+ Usize => tcx.lang_items().usize_impl(),
+ U8 => tcx.lang_items().u8_impl(),
+ U16 => tcx.lang_items().u16_impl(),
+ U32 => tcx.lang_items().u32_impl(),
+ U64 => tcx.lang_items().u64_impl(),
+ U128 => tcx.lang_items().u128_impl(),
+ F32 => tcx.lang_items().f32_impl(),
+ F64 => tcx.lang_items().f64_impl(),
+ Char => tcx.lang_items().char_impl(),
+ Bool => tcx.lang_items().bool_impl(),
+ Str => tcx.lang_items().str_impl(),
+ Slice => tcx.lang_items().slice_impl(),
+ Array => tcx.lang_items().slice_impl(),
+ Tuple => None,
+ Unit => None,
+ RawPointer => tcx.lang_items().const_ptr_impl(),
+ Reference => None,
+ Fn => None,
+ Never => None,
+ };
+ if let Some(did) = did {
+ if !did.is_local() {
+ inline::build_impl(cx, did, None, ret);
+ }
+ }
+ }
+}
+
+pub trait ToSource {
+ fn to_src(&self, cx: &DocContext<'_>) -> String;
+}
+
+impl ToSource for syntax_pos::Span {
+ fn to_src(&self, cx: &DocContext<'_>) -> String {
+ debug!("converting span {:?} to snippet", self.clean(cx));
+ let sn = match cx.sess().source_map().span_to_snippet(*self) {
+ Ok(x) => x,
+ Err(_) => String::new()
+ };
+ debug!("got snippet {}", sn);
+ sn
+ }
+}
+
+pub fn name_from_pat(p: &hir::Pat) -> String {
+ use rustc::hir::*;
+ debug!("trying to get a name from pattern: {:?}", p);
+
+ match p.kind {
+ PatKind::Wild => "_".to_string(),
+ PatKind::Binding(_, _, ident, _) => ident.to_string(),
+ PatKind::TupleStruct(ref p, ..) | PatKind::Path(ref p) => qpath_to_string(p),
+ PatKind::Struct(ref name, ref fields, etc) => {
+ format!("{} {{ {}{} }}", qpath_to_string(name),
+ fields.iter().map(|fp| format!("{}: {}", fp.ident, name_from_pat(&fp.pat)))
+ .collect::<Vec<String>>().join(", "),
+ if etc { ", .." } else { "" }
+ )
+ }
+ PatKind::Or(ref pats) => {
+ pats.iter().map(|p| name_from_pat(&**p)).collect::<Vec<String>>().join(" | ")
+ }
+ PatKind::Tuple(ref elts, _) => format!("({})", elts.iter().map(|p| name_from_pat(&**p))
+ .collect::<Vec<String>>().join(", ")),
+ PatKind::Box(ref p) => name_from_pat(&**p),
+ PatKind::Ref(ref p, _) => name_from_pat(&**p),
+ PatKind::Lit(..) => {
+ warn!("tried to get argument name from PatKind::Lit, \
+ which is silly in function arguments");
+ "()".to_string()
+ },
+ PatKind::Range(..) => panic!("tried to get argument name from PatKind::Range, \
+ which is not allowed in function arguments"),
+ PatKind::Slice(ref begin, ref mid, ref end) => {
+ let begin = begin.iter().map(|p| name_from_pat(&**p));
+ let mid = mid.as_ref().map(|p| format!("..{}", name_from_pat(&**p))).into_iter();
+ let end = end.iter().map(|p| name_from_pat(&**p));
+ format!("[{}]", begin.chain(mid).chain(end).collect::<Vec<_>>().join(", "))
+ },
+ }
+}
+
+pub fn print_const(cx: &DocContext<'_>, n: &ty::Const<'_>) -> String {
+ match n.val {
+ ty::ConstKind::Unevaluated(def_id, _) => {
+ if let Some(hir_id) = cx.tcx.hir().as_local_hir_id(def_id) {
+ print_const_expr(cx, cx.tcx.hir().body_owned_by(hir_id))
+ } else {
+ inline::print_inlined_const(cx, def_id)
+ }
+ },
+ _ => {
+ let mut s = n.to_string();
+ // array lengths are obviously usize
+ if s.ends_with("usize") {
+ let n = s.len() - "usize".len();
+ s.truncate(n);
+ if s.ends_with(": ") {
+ let n = s.len() - ": ".len();
+ s.truncate(n);
+ }
+ }
+ s
+ },
+ }
+}
+
+pub fn print_const_expr(cx: &DocContext<'_>, body: hir::BodyId) -> String {
+ cx.tcx.hir().hir_to_pretty_string(body.hir_id)
+}
+
+/// Given a type Path, resolve it to a Type using the TyCtxt
+pub fn resolve_type(cx: &DocContext<'_>,
+ path: Path,
+ id: hir::HirId) -> Type {
+ if id == hir::DUMMY_HIR_ID {
+ debug!("resolve_type({:?})", path);
+ } else {
+ debug!("resolve_type({:?},{:?})", path, id);
+ }
+
+ let is_generic = match path.res {
+ Res::PrimTy(p) => match p {
+ hir::Str => return Primitive(PrimitiveType::Str),
+ hir::Bool => return Primitive(PrimitiveType::Bool),
+ hir::Char => return Primitive(PrimitiveType::Char),
+ hir::Int(int_ty) => return Primitive(int_ty.into()),
+ hir::Uint(uint_ty) => return Primitive(uint_ty.into()),
+ hir::Float(float_ty) => return Primitive(float_ty.into()),
+ },
+ Res::SelfTy(..) if path.segments.len() == 1 => {
+ return Generic(kw::SelfUpper.to_string());
+ }
+ Res::Def(DefKind::TyParam, _) if path.segments.len() == 1 => {
+ return Generic(format!("{:#}", path.print()));
+ }
+ Res::SelfTy(..)
+ | Res::Def(DefKind::TyParam, _)
+ | Res::Def(DefKind::AssocTy, _) => true,
+ _ => false,
+ };
+ let did = register_res(&*cx, path.res);
+ ResolvedPath { path, param_names: None, did, is_generic }
+}
+
+pub fn get_auto_trait_and_blanket_impls(
+ cx: &DocContext<'tcx>,
+ ty: Ty<'tcx>,
+ param_env_def_id: DefId,
+) -> impl Iterator<Item = Item> {
+ AutoTraitFinder::new(cx).get_auto_trait_impls(ty, param_env_def_id).into_iter()
+ .chain(BlanketImplFinder::new(cx).get_blanket_impls(ty, param_env_def_id))
+}
+
+pub fn register_res(cx: &DocContext<'_>, res: Res) -> DefId {
+ debug!("register_res({:?})", res);
+
+ let (did, kind) = match res {
+ Res::Def(DefKind::Fn, i) => (i, TypeKind::Function),
+ Res::Def(DefKind::TyAlias, i) => (i, TypeKind::Typedef),
+ Res::Def(DefKind::Enum, i) => (i, TypeKind::Enum),
+ Res::Def(DefKind::Trait, i) => (i, TypeKind::Trait),
+ Res::Def(DefKind::Struct, i) => (i, TypeKind::Struct),
+ Res::Def(DefKind::Union, i) => (i, TypeKind::Union),
+ Res::Def(DefKind::Mod, i) => (i, TypeKind::Module),
+ Res::Def(DefKind::ForeignTy, i) => (i, TypeKind::Foreign),
+ Res::Def(DefKind::Const, i) => (i, TypeKind::Const),
+ Res::Def(DefKind::Static, i) => (i, TypeKind::Static),
+ Res::Def(DefKind::Variant, i) => (cx.tcx.parent(i).expect("cannot get parent def id"),
+ TypeKind::Enum),
+ Res::Def(DefKind::Macro(mac_kind), i) => match mac_kind {
+ MacroKind::Bang => (i, TypeKind::Macro),
+ MacroKind::Attr => (i, TypeKind::Attr),
+ MacroKind::Derive => (i, TypeKind::Derive),
+ },
+ Res::Def(DefKind::TraitAlias, i) => (i, TypeKind::TraitAlias),
+ Res::SelfTy(Some(def_id), _) => (def_id, TypeKind::Trait),
+ Res::SelfTy(_, Some(impl_def_id)) => return impl_def_id,
+ _ => return res.def_id()
+ };
+ if did.is_local() { return did }
+ inline::record_extern_fqn(cx, did, kind);
+ if let TypeKind::Trait = kind {
+ inline::record_extern_trait(cx, did);
+ }
+ did
+}
+
+pub fn resolve_use_source(cx: &DocContext<'_>, path: Path) -> ImportSource {
+ ImportSource {
+ did: if path.res.opt_def_id().is_none() {
+ None
+ } else {
+ Some(register_res(cx, path.res))
+ },
+ path,
+ }
+}
+
+pub fn enter_impl_trait<F, R>(cx: &DocContext<'_>, f: F) -> R
+where
+ F: FnOnce() -> R,
+{
+ let old_bounds = mem::take(&mut *cx.impl_trait_bounds.borrow_mut());
+ let r = f();
+ assert!(cx.impl_trait_bounds.borrow().is_empty());
+ *cx.impl_trait_bounds.borrow_mut() = old_bounds;
+ r
+}
diff --git a/src/librustdoc/config.rs b/src/librustdoc/config.rs
index cdb1a1f..0db3d28 100644
--- a/src/librustdoc/config.rs
+++ b/src/librustdoc/config.rs
@@ -7,10 +7,10 @@
use getopts;
use rustc::lint::Level;
use rustc::session;
-use rustc::session::config::{CrateType, parse_crate_types_from_list};
+use rustc::session::config::{CrateType, parse_crate_types_from_list, parse_externs};
use rustc::session::config::{CodegenOptions, DebuggingOptions, ErrorOutputType, Externs};
use rustc::session::config::{nightly_options, build_codegen_options, build_debugging_options,
- get_cmd_lint_options, host_triple, ExternEntry};
+ get_cmd_lint_options, host_triple};
use rustc::session::search_paths::SearchPath;
use rustc_driver;
use rustc_target::spec::TargetTriple;
@@ -320,13 +320,7 @@
let libs = matches.opt_strs("L").iter()
.map(|s| SearchPath::from_cli_opt(s, error_format))
.collect();
- let externs = match parse_externs(&matches) {
- Ok(ex) => ex,
- Err(err) => {
- diag.struct_err(&err).emit();
- return Err(1);
- }
- };
+ let externs = parse_externs(&matches, &debugging_options, error_format);
let extern_html_root_urls = match parse_extern_html_roots(&matches) {
Ok(ex) => ex,
Err(err) => {
@@ -617,24 +611,3 @@
Ok(externs)
}
-
-/// Extracts `--extern CRATE=PATH` arguments from `matches` and
-/// returns a map mapping crate names to their paths or else an
-/// error message.
-/// Also handles `--extern-private` which for the purposes of rustdoc
-/// we can treat as `--extern`
-// FIXME(eddyb) This shouldn't be duplicated with `rustc::session`.
-fn parse_externs(matches: &getopts::Matches) -> Result<Externs, String> {
- let mut externs: BTreeMap<_, ExternEntry> = BTreeMap::new();
- for arg in matches.opt_strs("extern").iter().chain(matches.opt_strs("extern-private").iter()) {
- let mut parts = arg.splitn(2, '=');
- let name = parts.next().ok_or("--extern value must not be empty".to_string())?;
- let location = parts.next().map(|s| s.to_string());
- let name = name.to_string();
- // For Rustdoc purposes, we can treat all externs as public
- externs.entry(name)
- .or_default()
- .locations.insert(location.clone());
- }
- Ok(Externs::new(externs))
-}
diff --git a/src/librustdoc/core.rs b/src/librustdoc/core.rs
index b77b1c7..a524801 100644
--- a/src/librustdoc/core.rs
+++ b/src/librustdoc/core.rs
@@ -248,7 +248,9 @@
..
} = options;
- let extern_names: Vec<String> = externs.iter().map(|(s,_)| s).cloned().collect();
+ let extern_names: Vec<String> = externs.iter()
+ .filter(|(_, entry)| entry.add_prelude)
+ .map(|(name, _)| name).cloned().collect();
// Add the doc cfg into the doc build.
cfgs.push("doc".to_string());
diff --git a/src/librustdoc/html/format.rs b/src/librustdoc/html/format.rs
index 4cde868..fd620d4 100644
--- a/src/librustdoc/html/format.rs
+++ b/src/librustdoc/html/format.rs
@@ -63,6 +63,13 @@
}
}
+ crate fn new() -> Buffer {
+ Buffer {
+ for_html: false,
+ buffer: String::new(),
+ }
+ }
+
crate fn is_empty(&self) -> bool {
self.buffer.is_empty()
}
@@ -106,6 +113,10 @@
write!(self, "{:#}", t);
}
}
+
+ crate fn is_for_html(&self) -> bool {
+ self.for_html
+ }
}
/// Wrapper struct for properly emitting a function or method declaration.
diff --git a/src/librustdoc/html/item_type.rs b/src/librustdoc/html/item_type.rs
index f5e4592..85f1323 100644
--- a/src/librustdoc/html/item_type.rs
+++ b/src/librustdoc/html/item_type.rs
@@ -1,7 +1,11 @@
//! Item types.
use std::fmt;
+
+use serde::{Serialize, Serializer};
+
use syntax_pos::hygiene::MacroKind;
+
use crate::clean;
/// Item type. Corresponds to `clean::ItemEnum` variants.
@@ -45,6 +49,14 @@
TraitAlias = 25,
}
+impl Serialize for ItemType {
+ fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
+ where
+ S: Serializer,
+ {
+ (*self as u8).serialize(serializer)
+ }
+}
impl<'a> From<&'a clean::Item> for ItemType {
fn from(item: &'a clean::Item) -> ItemType {
diff --git a/src/librustdoc/html/render.rs b/src/librustdoc/html/render.rs
index b5c1a77..e764b7e 100644
--- a/src/librustdoc/html/render.rs
+++ b/src/librustdoc/html/render.rs
@@ -31,7 +31,8 @@
use std::collections::{BTreeMap, VecDeque};
use std::default::Default;
use std::error;
-use std::fmt::{self, Formatter, Write as FmtWrite};
+
+use std::fmt::{self, Formatter, Write};
use std::ffi::OsStr;
use std::fs::{self, File};
use std::io::prelude::*;
@@ -42,7 +43,8 @@
use std::rc::Rc;
use errors;
-use serialize::json::{ToJson, Json, as_json};
+use serde::{Serialize, Serializer};
+use serde::ser::SerializeSeq;
use syntax::ast;
use syntax::edition::Edition;
use syntax::print::pprust;
@@ -303,19 +305,22 @@
search_type: Option<IndexItemFunctionType>,
}
-impl ToJson for IndexItem {
- fn to_json(&self) -> Json {
+impl Serialize for IndexItem {
+ fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
+ where
+ S: Serializer,
+ {
assert_eq!(self.parent.is_some(), self.parent_idx.is_some());
- let mut data = Vec::with_capacity(6);
- data.push((self.ty as usize).to_json());
- data.push(self.name.to_json());
- data.push(self.path.to_json());
- data.push(self.desc.to_json());
- data.push(self.parent_idx.to_json());
- data.push(self.search_type.to_json());
-
- Json::Array(data)
+ (
+ self.ty,
+ &self.name,
+ &self.path,
+ &self.desc,
+ self.parent_idx,
+ &self.search_type,
+ )
+ .serialize(serializer)
}
}
@@ -326,18 +331,20 @@
generics: Option<Vec<String>>,
}
-impl ToJson for Type {
- fn to_json(&self) -> Json {
- match self.name {
- Some(ref name) => {
- let mut data = Vec::with_capacity(2);
- data.push(name.to_json());
- if let Some(ref generics) = self.generics {
- data.push(generics.to_json());
- }
- Json::Array(data)
+impl Serialize for Type {
+ fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
+ where
+ S: Serializer,
+ {
+ if let Some(name) = &self.name {
+ let mut seq = serializer.serialize_seq(None)?;
+ seq.serialize_element(&name)?;
+ if let Some(generics) = &self.generics {
+ seq.serialize_element(&generics)?;
}
- None => Json::Null,
+ seq.end()
+ } else {
+ serializer.serialize_none()
}
}
}
@@ -349,26 +356,29 @@
output: Option<Vec<Type>>,
}
-impl ToJson for IndexItemFunctionType {
- fn to_json(&self) -> Json {
+impl Serialize for IndexItemFunctionType {
+ fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
+ where
+ S: Serializer,
+ {
// If we couldn't figure out a type, just write `null`.
let mut iter = self.inputs.iter();
if match self.output {
Some(ref output) => iter.chain(output.iter()).any(|ref i| i.name.is_none()),
None => iter.any(|ref i| i.name.is_none()),
} {
- Json::Null
+ serializer.serialize_none()
} else {
- let mut data = Vec::with_capacity(2);
- data.push(self.inputs.to_json());
- if let Some(ref output) = self.output {
+ let mut seq = serializer.serialize_seq(None)?;
+ seq.serialize_element(&self.inputs)?;
+ if let Some(output) = &self.output {
if output.len() > 1 {
- data.push(output.to_json());
+ seq.serialize_element(&output)?;
} else {
- data.push(output[0].to_json());
+ seq.serialize_element(&output[0])?;
}
}
- Json::Array(data)
+ seq.end()
}
}
}
@@ -596,7 +606,7 @@
// To avoid theme switch latencies as much as possible, we put everything theme related
// at the beginning of the html files into another js file.
let theme_js = format!(
-r#"var themes = document.getElementById("theme-choices");
+ r#"var themes = document.getElementById("theme-choices");
var themePicker = document.getElementById("theme-picker");
function showThemeButtonState() {{
@@ -642,12 +652,11 @@
}};
but.onblur = handleThemeButtonsBlur;
themes.appendChild(but);
-}});"#,
- as_json(&themes));
- write(cx.dst.join(&format!("theme{}.js", cx.shared.resource_suffix)),
- theme_js.as_bytes()
- )?;
+}});"#, serde_json::to_string(&themes).unwrap());
+ write_minify(&cx.shared.fs, cx.path("theme.js"),
+ &theme_js,
+ options.enable_minification)?;
write_minify(&cx.shared.fs, cx.path("main.js"),
static_files::MAIN_JS,
options.enable_minification)?;
@@ -715,19 +724,13 @@
path: &Path,
krate: &str,
key: &str,
- for_search_index: bool,
- ) -> io::Result<(Vec<String>, Vec<String>, Vec<String>)> {
+ ) -> io::Result<(Vec<String>, Vec<String>)> {
let mut ret = Vec::new();
let mut krates = Vec::new();
- let mut variables = Vec::new();
if path.exists() {
for line in BufReader::new(File::open(path)?).lines() {
let line = line?;
- if for_search_index && line.starts_with("var R") {
- variables.push(line.clone());
- continue;
- }
if !line.starts_with(key) {
continue;
}
@@ -741,7 +744,7 @@
.unwrap_or_else(|| String::new()));
}
}
- Ok((ret, krates, variables))
+ Ok((ret, krates))
}
fn show_item(item: &IndexItem, krate: &str) -> String {
@@ -756,7 +759,7 @@
let dst = cx.dst.join(&format!("aliases{}.js", cx.shared.resource_suffix));
{
- let (mut all_aliases, _, _) = try_err!(collect(&dst, &krate.name, "ALIASES", false), &dst);
+ let (mut all_aliases, _) = try_err!(collect(&dst, &krate.name, "ALIASES"), &dst);
let mut output = String::with_capacity(100);
for (alias, items) in &cx.cache.aliases {
if items.is_empty() {
@@ -853,9 +856,7 @@
}
let dst = cx.dst.join(&format!("source-files{}.js", cx.shared.resource_suffix));
- let (mut all_sources, _krates, _) = try_err!(collect(&dst, &krate.name, "sourcesIndex",
- false),
- &dst);
+ let (mut all_sources, _krates) = try_err!(collect(&dst, &krate.name, "sourcesIndex"), &dst);
all_sources.push(format!("sourcesIndex[\"{}\"] = {};",
&krate.name,
hierarchy.to_json_string()));
@@ -867,23 +868,18 @@
// Update the search index
let dst = cx.dst.join(&format!("search-index{}.js", cx.shared.resource_suffix));
- let (mut all_indexes, mut krates, variables) = try_err!(collect(&dst,
- &krate.name,
- "searchIndex",
- true), &dst);
+ let (mut all_indexes, mut krates) = try_err!(collect(&dst, &krate.name, "searchIndex"), &dst);
all_indexes.push(search_index);
// Sort the indexes by crate so the file will be generated identically even
// with rustdoc running in parallel.
all_indexes.sort();
{
- let mut v = String::from("var N=null,E=\"\",T=\"t\",U=\"u\",searchIndex={};\n");
- v.push_str(&minify_replacer(
- &format!("{}\n{}", variables.join(""), all_indexes.join("\n")),
- options.enable_minification));
+ let mut v = String::from("var searchIndex={};\n");
+ v.push_str(&all_indexes.join("\n"));
// "addSearchOptions" has to be called first so the crate filtering can be set before the
// search might start (if it's set into the URL for example).
- v.push_str("addSearchOptions(searchIndex);initSearch(searchIndex);");
+ v.push_str("\naddSearchOptions(searchIndex);initSearch(searchIndex);");
cx.shared.fs.write(&dst, &v)?;
}
if options.enable_index_page {
@@ -946,32 +942,48 @@
}
};
- let mut have_impls = false;
- let mut implementors = format!(r#"implementors["{}"] = ["#, krate.name);
- for imp in imps {
- // If the trait and implementation are in the same crate, then
- // there's no need to emit information about it (there's inlining
- // going on). If they're in different crates then the crate defining
- // the trait will be interested in our implementation.
- if imp.impl_item.def_id.krate == did.krate { continue }
- // If the implementation is from another crate then that crate
- // should add it.
- if !imp.impl_item.def_id.is_local() { continue }
- have_impls = true;
- write!(implementors, "{{text:{},synthetic:{},types:{}}},",
- as_json(&imp.inner_impl().print().to_string()),
- imp.inner_impl().synthetic,
- as_json(&collect_paths_for_type(imp.inner_impl().for_.clone()))).unwrap();
+ #[derive(Serialize)]
+ struct Implementor {
+ text: String,
+ synthetic: bool,
+ types: Vec<String>,
}
- implementors.push_str("];");
+
+ let implementors = imps
+ .iter()
+ .filter_map(|imp| {
+ // If the trait and implementation are in the same crate, then
+ // there's no need to emit information about it (there's inlining
+ // going on). If they're in different crates then the crate defining
+ // the trait will be interested in our implementation.
+ //
+ // If the implementation is from another crate then that crate
+ // should add it.
+ if imp.impl_item.def_id.krate == did.krate || !imp.impl_item.def_id.is_local() {
+ None
+ } else {
+ Some(Implementor {
+ text: imp.inner_impl().print().to_string(),
+ synthetic: imp.inner_impl().synthetic,
+ types: collect_paths_for_type(imp.inner_impl().for_.clone()),
+ })
+ }
+ })
+ .collect::<Vec<_>>();
// Only create a js file if we have impls to add to it. If the trait is
// documented locally though we always create the file to avoid dead
// links.
- if !have_impls && !cx.cache.paths.contains_key(&did) {
+ if implementors.is_empty() && !cx.cache.paths.contains_key(&did) {
continue;
}
+ let implementors = format!(
+ r#"implementors["{}"] = {};"#,
+ krate.name,
+ serde_json::to_string(&implementors).unwrap()
+ );
+
let mut mydst = dst.clone();
for part in &remote_path[..remote_path.len() - 1] {
mydst.push(part);
@@ -981,9 +993,8 @@
remote_item_type,
remote_path[remote_path.len() - 1]));
- let (mut all_implementors, _, _) = try_err!(collect(&mydst, &krate.name, "implementors",
- false),
- &mydst);
+ let (mut all_implementors, _) = try_err!(collect(&mydst, &krate.name, "implementors"),
+ &mydst);
all_implementors.push(implementors);
// Sort the implementors by crate so the file will be generated
// identically even with rustdoc running in parallel.
@@ -1020,68 +1031,6 @@
}
}
-fn minify_replacer(
- contents: &str,
- enable_minification: bool,
-) -> String {
- use minifier::js::{simple_minify, Keyword, ReservedChar, Token, Tokens};
-
- if enable_minification {
- let tokens: Tokens<'_> = simple_minify(contents)
- .into_iter()
- .filter(|(f, next)| {
- // We keep backlines.
- minifier::js::clean_token_except(f, next, &|c: &Token<'_>| {
- c.get_char() != Some(ReservedChar::Backline)
- })
- })
- .map(|(f, _)| {
- minifier::js::replace_token_with(f, &|t: &Token<'_>| {
- match *t {
- Token::Keyword(Keyword::Null) => Some(Token::Other("N")),
- Token::String(s) => {
- let s = &s[1..s.len() -1]; // The quotes are included
- if s.is_empty() {
- Some(Token::Other("E"))
- } else if s == "t" {
- Some(Token::Other("T"))
- } else if s == "u" {
- Some(Token::Other("U"))
- } else {
- None
- }
- }
- _ => None,
- }
- })
- })
- .collect::<Vec<_>>()
- .into();
- let o = tokens.apply(|f| {
- // We add a backline after the newly created variables.
- minifier::js::aggregate_strings_into_array_with_separation_filter(
- f,
- "R",
- Token::Char(ReservedChar::Backline),
- // This closure prevents crates' names from being aggregated.
- //
- // The point here is to check if the string is preceded by '[' and
- // "searchIndex". If so, it means this is a crate name and that it
- // shouldn't be aggregated.
- |tokens, pos| {
- pos < 2 ||
- !tokens[pos - 1].eq_char(ReservedChar::OpenBracket) ||
- tokens[pos - 2].get_other() != Some("searchIndex")
- }
- )
- })
- .to_string();
- format!("{}\n", o)
- } else {
- format!("{}\n", contents)
- }
-}
-
#[derive(Debug, Eq, PartialEq, Hash)]
struct ItemEntry {
url: String,
@@ -1533,7 +1482,7 @@
if !self.render_redirect_pages {
let items = self.build_sidebar_items(&m);
let js_dst = self.dst.join("sidebar-items.js");
- let v = format!("initSidebarItems({});", as_json(&items));
+ let v = format!("initSidebarItems({});", serde_json::to_string(&items).unwrap());
scx.fs.write(&js_dst, &v)?;
}
@@ -2359,12 +2308,23 @@
fn render_impls(cx: &Context, w: &mut Buffer,
traits: &[&&Impl],
containing_item: &clean::Item) {
- for i in traits {
- let did = i.trait_did().unwrap();
- let assoc_link = AssocItemLink::GotoSource(did, &i.inner_impl().provided_trait_methods);
- render_impl(w, cx, i, assoc_link,
- RenderMode::Normal, containing_item.stable_since(), true, None, false, true);
- }
+ let mut impls = traits.iter()
+ .map(|i| {
+ let did = i.trait_did().unwrap();
+ let assoc_link = AssocItemLink::GotoSource(did, &i.inner_impl().provided_trait_methods);
+ let mut buffer = if w.is_for_html() {
+ Buffer::html()
+ } else {
+ Buffer::new()
+ };
+ render_impl(&mut buffer, cx, i, assoc_link,
+ RenderMode::Normal, containing_item.stable_since(),
+ true, None, false, true);
+ buffer.into_inner()
+ })
+ .collect::<Vec<_>>();
+ impls.sort();
+ w.write_str(&impls.join(""));
}
fn bounds(t_bounds: &[clean::GenericBound], trait_alias: bool) -> String {
@@ -2624,8 +2584,11 @@
write_loading_content(w, "</div>");
}
}
- write!(w, r#"<script type="text/javascript">window.inlined_types=new Set({});</script>"#,
- as_json(&synthetic_types));
+ write!(
+ w,
+ r#"<script type="text/javascript">window.inlined_types=new Set({});</script>"#,
+ serde_json::to_string(&synthetic_types).unwrap(),
+ );
write!(w, r#"<script type="text/javascript" async
src="{root_path}/implementors/{path}/{ty}.{name}.js">
diff --git a/src/librustdoc/html/render/cache.rs b/src/librustdoc/html/render/cache.rs
index 65dd119..d80facf 100644
--- a/src/librustdoc/html/render/cache.rs
+++ b/src/librustdoc/html/render/cache.rs
@@ -8,7 +8,8 @@
use std::collections::BTreeMap;
use syntax::source_map::FileName;
use syntax::symbol::sym;
-use serialize::json::{ToJson, Json, as_json};
+
+use serde::Serialize;
use super::{ItemType, IndexItem, IndexItemFunctionType, Impl, shorten, plain_summary_line};
use super::{Type, RenderInfo};
@@ -544,7 +545,7 @@
fn build_index(krate: &clean::Crate, cache: &mut Cache) -> String {
let mut nodeid_to_pathid = FxHashMap::default();
let mut crate_items = Vec::with_capacity(cache.search_index.len());
- let mut crate_paths = Vec::<Json>::new();
+ let mut crate_paths = vec![];
let Cache { ref mut search_index,
ref orphan_impl_items,
@@ -581,7 +582,7 @@
lastpathid += 1;
let &(ref fqp, short) = paths.get(&nodeid).unwrap();
- crate_paths.push(((short as usize), fqp.last().unwrap().clone()).to_json());
+ crate_paths.push((short, fqp.last().unwrap().clone()));
pathid
}
});
@@ -592,22 +593,33 @@
} else {
lastpath = item.path.clone();
}
- crate_items.push(item.to_json());
+ crate_items.push(&*item);
}
let crate_doc = krate.module.as_ref().map(|module| {
shorten(plain_summary_line(module.doc_value()))
}).unwrap_or(String::new());
- let mut crate_data = BTreeMap::new();
- crate_data.insert("doc".to_owned(), Json::String(crate_doc));
- crate_data.insert("i".to_owned(), Json::Array(crate_items));
- crate_data.insert("p".to_owned(), Json::Array(crate_paths));
+ #[derive(Serialize)]
+ struct CrateData<'a> {
+ doc: String,
+ #[serde(rename = "i")]
+ items: Vec<&'a IndexItem>,
+ #[serde(rename = "p")]
+ paths: Vec<(ItemType, String)>,
+ }
// Collect the index into a string
- format!("searchIndex[{}] = {};",
- as_json(&krate.name),
- Json::Object(crate_data))
+ format!(
+ r#"searchIndex["{}"] = {};"#,
+ krate.name,
+ serde_json::to_string(&CrateData {
+ doc: crate_doc,
+ items: crate_items,
+ paths: crate_paths,
+ })
+ .unwrap()
+ )
}
fn get_index_search_type(item: &clean::Item) -> Option<IndexItemFunctionType> {
diff --git a/src/librustdoc/html/static/main.js b/src/librustdoc/html/static/main.js
index cc0f470..49a9cb0 100644
--- a/src/librustdoc/html/static/main.js
+++ b/src/librustdoc/html/static/main.js
@@ -1221,7 +1221,7 @@
// then an exact path match
path.indexOf(keys[i]) > -1 ||
// next if there is a parent, check for exact parent match
- (parent !== undefined &&
+ (parent !== undefined && parent.name !== undefined &&
parent.name.toLowerCase().indexOf(keys[i]) > -1) ||
// lastly check to see if the name was a levenshtein match
levenshtein(name, keys[i]) <= MAX_LEV_DISTANCE)) {
diff --git a/src/librustdoc/lib.rs b/src/librustdoc/lib.rs
index be3644e..a7ef428 100644
--- a/src/librustdoc/lib.rs
+++ b/src/librustdoc/lib.rs
@@ -35,7 +35,6 @@
extern crate rustc_target;
extern crate rustc_typeck;
extern crate rustc_lexer;
-extern crate serialize;
extern crate syntax;
extern crate syntax_expand;
extern crate syntax_pos;
@@ -145,10 +144,6 @@
stable("extern", |o| {
o.optmulti("", "extern", "pass an --extern to rustc", "NAME[=PATH]")
}),
- unstable("extern-private", |o| {
- o.optmulti("", "extern-private",
- "pass an --extern to rustc (compatibility only)", "NAME=PATH")
- }),
unstable("extern-html-root-url", |o| {
o.optmulti("", "extern-html-root-url",
"base URL to use for dependencies", "NAME=URL")
diff --git a/src/libstd/build.rs b/src/libstd/build.rs
index 1f839f1..8db7bc1 100644
--- a/src/libstd/build.rs
+++ b/src/libstd/build.rs
@@ -54,7 +54,5 @@
}
println!("cargo:rustc-link-lib=c");
println!("cargo:rustc-link-lib=compiler_rt");
- } else if target.contains("hermit") {
- println!("cargo:rustc-link-lib=hermit");
}
}
diff --git a/src/libstd/collections/mod.rs b/src/libstd/collections/mod.rs
index 522b8b2..e8b9e9c 100644
--- a/src/libstd/collections/mod.rs
+++ b/src/libstd/collections/mod.rs
@@ -433,7 +433,7 @@
#[stable(feature = "rust1", since = "1.0.0")]
pub mod hash_map {
- //! A hash map implemented with linear probing and Robin Hood bucket stealing.
+ //! A hash map implemented with quadratic probing and SIMD lookup.
#[stable(feature = "rust1", since = "1.0.0")]
pub use super::hash::map::*;
}
diff --git a/src/libstd/ffi/os_str.rs b/src/libstd/ffi/os_str.rs
index 6cf062d..b9cede7 100644
--- a/src/libstd/ffi/os_str.rs
+++ b/src/libstd/ffi/os_str.rs
@@ -495,11 +495,13 @@
///
/// let os_str = OsStr::new("foo");
/// ```
+ #[inline]
#[stable(feature = "rust1", since = "1.0.0")]
pub fn new<S: AsRef<OsStr> + ?Sized>(s: &S) -> &OsStr {
s.as_ref()
}
+ #[inline]
fn from_inner(inner: &Slice) -> &OsStr {
unsafe { &*(inner as *const Slice as *const OsStr) }
}
@@ -658,6 +660,7 @@
///
/// Note: it is *crucial* that this API is private, to avoid
/// revealing the internal, platform-specific encodings.
+ #[inline]
fn bytes(&self) -> &[u8] {
unsafe { &*(&self.inner as *const _ as *const [u8]) }
}
@@ -797,6 +800,7 @@
#[stable(feature = "rust1", since = "1.0.0")]
impl PartialEq for OsStr {
+ #[inline]
fn eq(&self, other: &OsStr) -> bool {
self.bytes().eq(other.bytes())
}
@@ -804,6 +808,7 @@
#[stable(feature = "rust1", since = "1.0.0")]
impl PartialEq<str> for OsStr {
+ #[inline]
fn eq(&self, other: &str) -> bool {
*self == *OsStr::new(other)
}
@@ -811,6 +816,7 @@
#[stable(feature = "rust1", since = "1.0.0")]
impl PartialEq<OsStr> for str {
+ #[inline]
fn eq(&self, other: &OsStr) -> bool {
*other == *OsStr::new(self)
}
@@ -944,6 +950,7 @@
#[stable(feature = "rust1", since = "1.0.0")]
impl AsRef<OsStr> for str {
+ #[inline]
fn as_ref(&self) -> &OsStr {
OsStr::from_inner(Slice::from_str(self))
}
@@ -951,6 +958,7 @@
#[stable(feature = "rust1", since = "1.0.0")]
impl AsRef<OsStr> for String {
+ #[inline]
fn as_ref(&self) -> &OsStr {
(&**self).as_ref()
}
diff --git a/src/libstd/fs.rs b/src/libstd/fs.rs
index e5cf022..a109e38 100644
--- a/src/libstd/fs.rs
+++ b/src/libstd/fs.rs
@@ -2339,8 +2339,10 @@
let filename = &tmpdir.join("file_that_does_not_exist.txt");
let result = File::open(filename);
- #[cfg(unix)]
+ #[cfg(all(unix, not(target_os = "vxworks")))]
error!(result, "No such file or directory");
+ #[cfg(target_os = "vxworks")]
+ error!(result, "no such file or directory");
#[cfg(windows)]
error!(result, 2); // ERROR_FILE_NOT_FOUND
}
@@ -2352,8 +2354,10 @@
let result = fs::remove_file(filename);
- #[cfg(unix)]
+ #[cfg(all(unix, not(target_os = "vxworks")))]
error!(result, "No such file or directory");
+ #[cfg(target_os = "vxworks")]
+ error!(result, "no such file or directory");
#[cfg(windows)]
error!(result, 2); // ERROR_FILE_NOT_FOUND
}
@@ -2553,7 +2557,10 @@
check!(fs::set_permissions(filename, fs::Permissions::from_mode(0o1777)));
let metadata1 = check!(fs::metadata(filename));
+ #[cfg(all(unix, not(target_os = "vxworks")))]
assert_eq!(mask & metadata1.permissions().mode(), 0o1777);
+ #[cfg(target_os = "vxworks")]
+ assert_eq!(mask & metadata1.permissions().mode(), 0o0777);
}
#[test]
diff --git a/src/libstd/future.rs b/src/libstd/future.rs
index 6de3f1d..ac1ef3e 100644
--- a/src/libstd/future.rs
+++ b/src/libstd/future.rs
@@ -26,7 +26,6 @@
#[doc(hidden)]
#[unstable(feature = "gen_future", issue = "50547")]
#[derive(Copy, Clone, Debug, Eq, PartialEq, Ord, PartialOrd, Hash)]
-#[cfg_attr(not(test), rustc_diagnostic_item = "gen_future")]
struct GenFuture<T: Generator<Yield = ()>>(T);
// We rely on the fact that async/await futures are immovable in order to create
diff --git a/src/libstd/io/mod.rs b/src/libstd/io/mod.rs
index 20c1c5c..a1a33ba 100644
--- a/src/libstd/io/mod.rs
+++ b/src/libstd/io/mod.rs
@@ -987,7 +987,6 @@
/// #![feature(io_slice_advance)]
///
/// use std::io::IoSliceMut;
- /// use std::mem;
/// use std::ops::Deref;
///
/// let mut buf1 = [1; 8];
@@ -1000,7 +999,7 @@
/// ][..];
///
/// // Mark 10 bytes as read.
- /// bufs = IoSliceMut::advance(mem::replace(&mut bufs, &mut []), 10);
+ /// bufs = IoSliceMut::advance(bufs, 10);
/// assert_eq!(bufs[0].deref(), [2; 14].as_ref());
/// assert_eq!(bufs[1].deref(), [3; 8].as_ref());
/// ```
@@ -1090,20 +1089,19 @@
/// #![feature(io_slice_advance)]
///
/// use std::io::IoSlice;
- /// use std::mem;
/// use std::ops::Deref;
///
- /// let mut buf1 = [1; 8];
- /// let mut buf2 = [2; 16];
- /// let mut buf3 = [3; 8];
+ /// let buf1 = [1; 8];
+ /// let buf2 = [2; 16];
+ /// let buf3 = [3; 8];
/// let mut bufs = &mut [
- /// IoSlice::new(&mut buf1),
- /// IoSlice::new(&mut buf2),
- /// IoSlice::new(&mut buf3),
+ /// IoSlice::new(&buf1),
+ /// IoSlice::new(&buf2),
+ /// IoSlice::new(&buf3),
/// ][..];
///
/// // Mark 10 bytes as written.
- /// bufs = IoSlice::advance(mem::replace(&mut bufs, &mut []), 10);
+ /// bufs = IoSlice::advance(bufs, 10);
/// assert_eq!(bufs[0].deref(), [2; 14].as_ref());
/// assert_eq!(bufs[1].deref(), [3; 8].as_ref());
#[unstable(feature = "io_slice_advance", issue = "62726")]
@@ -2415,7 +2413,6 @@
use crate::cmp;
use crate::io::prelude::*;
use crate::io::{self, IoSlice, IoSliceMut};
- use crate::mem;
use crate::ops::Deref;
#[test]
@@ -2731,26 +2728,26 @@
][..];
// Only in a single buffer..
- bufs = IoSliceMut::advance(mem::replace(&mut bufs, &mut []), 1);
+ bufs = IoSliceMut::advance(bufs, 1);
assert_eq!(bufs[0].deref(), [1; 7].as_ref());
assert_eq!(bufs[1].deref(), [2; 16].as_ref());
assert_eq!(bufs[2].deref(), [3; 8].as_ref());
// Removing a buffer, leaving others as is.
- bufs = IoSliceMut::advance(mem::replace(&mut bufs, &mut []), 7);
+ bufs = IoSliceMut::advance(bufs, 7);
assert_eq!(bufs[0].deref(), [2; 16].as_ref());
assert_eq!(bufs[1].deref(), [3; 8].as_ref());
// Removing a buffer and removing from the next buffer.
- bufs = IoSliceMut::advance(mem::replace(&mut bufs, &mut []), 18);
+ bufs = IoSliceMut::advance(bufs, 18);
assert_eq!(bufs[0].deref(), [3; 6].as_ref());
}
#[test]
fn io_slice_mut_advance_empty_slice() {
- let mut empty_bufs = &mut [][..];
+ let empty_bufs = &mut [][..];
// Shouldn't panic.
- IoSliceMut::advance(&mut empty_bufs, 1);
+ IoSliceMut::advance(empty_bufs, 1);
}
#[test]
@@ -2759,48 +2756,48 @@
let mut bufs = &mut [IoSliceMut::new(&mut buf1)][..];
// Going beyond the total length should be ok.
- bufs = IoSliceMut::advance(mem::replace(&mut bufs, &mut []), 9);
+ bufs = IoSliceMut::advance(bufs, 9);
assert!(bufs.is_empty());
}
#[test]
fn io_slice_advance() {
- let mut buf1 = [1; 8];
- let mut buf2 = [2; 16];
- let mut buf3 = [3; 8];
+ let buf1 = [1; 8];
+ let buf2 = [2; 16];
+ let buf3 = [3; 8];
let mut bufs =
- &mut [IoSlice::new(&mut buf1), IoSlice::new(&mut buf2), IoSlice::new(&mut buf3)][..];
+ &mut [IoSlice::new(&buf1), IoSlice::new(&buf2), IoSlice::new(&buf3)][..];
// Only in a single buffer..
- bufs = IoSlice::advance(mem::replace(&mut bufs, &mut []), 1);
+ bufs = IoSlice::advance(bufs, 1);
assert_eq!(bufs[0].deref(), [1; 7].as_ref());
assert_eq!(bufs[1].deref(), [2; 16].as_ref());
assert_eq!(bufs[2].deref(), [3; 8].as_ref());
// Removing a buffer, leaving others as is.
- bufs = IoSlice::advance(mem::replace(&mut bufs, &mut []), 7);
+ bufs = IoSlice::advance(bufs, 7);
assert_eq!(bufs[0].deref(), [2; 16].as_ref());
assert_eq!(bufs[1].deref(), [3; 8].as_ref());
// Removing a buffer and removing from the next buffer.
- bufs = IoSlice::advance(mem::replace(&mut bufs, &mut []), 18);
+ bufs = IoSlice::advance(bufs, 18);
assert_eq!(bufs[0].deref(), [3; 6].as_ref());
}
#[test]
fn io_slice_advance_empty_slice() {
- let mut empty_bufs = &mut [][..];
+ let empty_bufs = &mut [][..];
// Shouldn't panic.
- IoSlice::advance(&mut empty_bufs, 1);
+ IoSlice::advance(empty_bufs, 1);
}
#[test]
fn io_slice_advance_beyond_total_length() {
- let mut buf1 = [1; 8];
- let mut bufs = &mut [IoSlice::new(&mut buf1)][..];
+ let buf1 = [1; 8];
+ let mut bufs = &mut [IoSlice::new(&buf1)][..];
// Going beyond the total length should be ok.
- bufs = IoSlice::advance(mem::replace(&mut bufs, &mut []), 9);
+ bufs = IoSlice::advance(bufs, 9);
assert!(bufs.is_empty());
}
}
diff --git a/src/libstd/keyword_docs.rs b/src/libstd/keyword_docs.rs
index 5b7bef9..de7ced3 100644
--- a/src/libstd/keyword_docs.rs
+++ b/src/libstd/keyword_docs.rs
@@ -57,7 +57,7 @@
/// 'outer: for i in 1..=5 {
/// println!("outer iteration (i): {}", i);
///
-/// 'inner: for j in 1..=200 {
+/// '_inner: for j in 1..=200 {
/// println!(" inner iteration (j): {}", j);
/// if j >= 3 {
/// // breaks from inner loop, let's outer loop continue.
@@ -178,7 +178,7 @@
///```rust
/// // Print Odd numbers under 30 with unit <= 5
/// 'tens: for ten in 0..3 {
-/// 'units: for unit in 0..=9 {
+/// '_units: for unit in 0..=9 {
/// if unit % 2 == 0 {
/// continue;
/// }
diff --git a/src/libstd/net/parser.rs b/src/libstd/net/parser.rs
index 8106d1c..686fa8c 100644
--- a/src/libstd/net/parser.rs
+++ b/src/libstd/net/parser.rs
@@ -44,19 +44,6 @@
self.read_atomically(move |p| cb(p).filter(|_| p.is_eof()))
}
- // Return result of first successful parser
- fn read_or<T>(
- &mut self,
- parsers: &mut [Box<dyn FnMut(&mut Parser<'_>) -> Option<T> + 'static>],
- ) -> Option<T> {
- for pf in parsers {
- if let Some(r) = self.read_atomically(|p: &mut Parser<'_>| pf(p)) {
- return Some(r);
- }
- }
- None
- }
-
// Apply 3 parsers sequentially
fn read_seq_3<A, B, C, PA, PB, PC>(&mut self, pa: PA, pb: PB, pc: PC) -> Option<(A, B, C)>
where
@@ -235,9 +222,8 @@
}
fn read_ip_addr(&mut self) -> Option<IpAddr> {
- let ipv4_addr = |p: &mut Parser<'_>| p.read_ipv4_addr().map(IpAddr::V4);
- let ipv6_addr = |p: &mut Parser<'_>| p.read_ipv6_addr().map(IpAddr::V6);
- self.read_or(&mut [Box::new(ipv4_addr), Box::new(ipv6_addr)])
+ self.read_ipv4_addr().map(IpAddr::V4)
+ .or_else(|| self.read_ipv6_addr().map(IpAddr::V6))
}
fn read_socket_addr_v4(&mut self) -> Option<SocketAddrV4> {
@@ -268,9 +254,8 @@
}
fn read_socket_addr(&mut self) -> Option<SocketAddr> {
- let v4 = |p: &mut Parser<'_>| p.read_socket_addr_v4().map(SocketAddr::V4);
- let v6 = |p: &mut Parser<'_>| p.read_socket_addr_v6().map(SocketAddr::V6);
- self.read_or(&mut [Box::new(v4), Box::new(v6)])
+ self.read_socket_addr_v4().map(SocketAddr::V4)
+ .or_else(|| self.read_socket_addr_v6().map(SocketAddr::V6))
}
}
diff --git a/src/libstd/sync/mutex.rs b/src/libstd/sync/mutex.rs
index 87c2318..e90da69 100644
--- a/src/libstd/sync/mutex.rs
+++ b/src/libstd/sync/mutex.rs
@@ -143,10 +143,8 @@
#[must_use = "if unused the Mutex will immediately unlock"]
#[stable(feature = "rust1", since = "1.0.0")]
pub struct MutexGuard<'a, T: ?Sized + 'a> {
- // funny underscores due to how Deref/DerefMut currently work (they
- // disregard field privacy).
- __lock: &'a Mutex<T>,
- __poison: poison::Guard,
+ lock: &'a Mutex<T>,
+ poison: poison::Guard,
}
#[stable(feature = "rust1", since = "1.0.0")]
@@ -417,8 +415,8 @@
unsafe fn new(lock: &'mutex Mutex<T>) -> LockResult<MutexGuard<'mutex, T>> {
poison::map_result(lock.poison.borrow(), |guard| {
MutexGuard {
- __lock: lock,
- __poison: guard,
+ lock: lock,
+ poison: guard,
}
})
}
@@ -429,14 +427,14 @@
type Target = T;
fn deref(&self) -> &T {
- unsafe { &*self.__lock.data.get() }
+ unsafe { &*self.lock.data.get() }
}
}
#[stable(feature = "rust1", since = "1.0.0")]
impl<T: ?Sized> DerefMut for MutexGuard<'_, T> {
fn deref_mut(&mut self) -> &mut T {
- unsafe { &mut *self.__lock.data.get() }
+ unsafe { &mut *self.lock.data.get() }
}
}
@@ -445,8 +443,8 @@
#[inline]
fn drop(&mut self) {
unsafe {
- self.__lock.poison.done(&self.__poison);
- self.__lock.inner.raw_unlock();
+ self.lock.poison.done(&self.poison);
+ self.lock.inner.raw_unlock();
}
}
}
@@ -466,11 +464,11 @@
}
pub fn guard_lock<'a, T: ?Sized>(guard: &MutexGuard<'a, T>) -> &'a sys::Mutex {
- &guard.__lock.inner
+ &guard.lock.inner
}
pub fn guard_poison<'a, T: ?Sized>(guard: &MutexGuard<'a, T>) -> &'a poison::Flag {
- &guard.__lock.poison
+ &guard.lock.poison
}
#[cfg(all(test, not(target_os = "emscripten")))]
diff --git a/src/libstd/sync/rwlock.rs b/src/libstd/sync/rwlock.rs
index b1b56f3..c217291 100644
--- a/src/libstd/sync/rwlock.rs
+++ b/src/libstd/sync/rwlock.rs
@@ -87,7 +87,7 @@
#[must_use = "if unused the RwLock will immediately unlock"]
#[stable(feature = "rust1", since = "1.0.0")]
pub struct RwLockReadGuard<'a, T: ?Sized + 'a> {
- __lock: &'a RwLock<T>,
+ lock: &'a RwLock<T>,
}
#[stable(feature = "rust1", since = "1.0.0")]
@@ -108,8 +108,8 @@
#[must_use = "if unused the RwLock will immediately unlock"]
#[stable(feature = "rust1", since = "1.0.0")]
pub struct RwLockWriteGuard<'a, T: ?Sized + 'a> {
- __lock: &'a RwLock<T>,
- __poison: poison::Guard,
+ lock: &'a RwLock<T>,
+ poison: poison::Guard,
}
#[stable(feature = "rust1", since = "1.0.0")]
@@ -465,7 +465,7 @@
-> LockResult<RwLockReadGuard<'rwlock, T>> {
poison::map_result(lock.poison.borrow(), |_| {
RwLockReadGuard {
- __lock: lock,
+ lock: lock,
}
})
}
@@ -476,8 +476,8 @@
-> LockResult<RwLockWriteGuard<'rwlock, T>> {
poison::map_result(lock.poison.borrow(), |guard| {
RwLockWriteGuard {
- __lock: lock,
- __poison: guard,
+ lock: lock,
+ poison: guard,
}
})
}
@@ -487,7 +487,7 @@
impl<T: fmt::Debug> fmt::Debug for RwLockReadGuard<'_, T> {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
f.debug_struct("RwLockReadGuard")
- .field("lock", &self.__lock)
+ .field("lock", &self.lock)
.finish()
}
}
@@ -503,7 +503,7 @@
impl<T: fmt::Debug> fmt::Debug for RwLockWriteGuard<'_, T> {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
f.debug_struct("RwLockWriteGuard")
- .field("lock", &self.__lock)
+ .field("lock", &self.lock)
.finish()
}
}
@@ -520,7 +520,7 @@
type Target = T;
fn deref(&self) -> &T {
- unsafe { &*self.__lock.data.get() }
+ unsafe { &*self.lock.data.get() }
}
}
@@ -529,29 +529,29 @@
type Target = T;
fn deref(&self) -> &T {
- unsafe { &*self.__lock.data.get() }
+ unsafe { &*self.lock.data.get() }
}
}
#[stable(feature = "rust1", since = "1.0.0")]
impl<T: ?Sized> DerefMut for RwLockWriteGuard<'_, T> {
fn deref_mut(&mut self) -> &mut T {
- unsafe { &mut *self.__lock.data.get() }
+ unsafe { &mut *self.lock.data.get() }
}
}
#[stable(feature = "rust1", since = "1.0.0")]
impl<T: ?Sized> Drop for RwLockReadGuard<'_, T> {
fn drop(&mut self) {
- unsafe { self.__lock.inner.read_unlock(); }
+ unsafe { self.lock.inner.read_unlock(); }
}
}
#[stable(feature = "rust1", since = "1.0.0")]
impl<T: ?Sized> Drop for RwLockWriteGuard<'_, T> {
fn drop(&mut self) {
- self.__lock.poison.done(&self.__poison);
- unsafe { self.__lock.inner.write_unlock(); }
+ self.lock.poison.done(&self.poison);
+ unsafe { self.lock.inner.write_unlock(); }
}
}
diff --git a/src/libstd/sys/unix/fast_thread_local.rs b/src/libstd/sys/unix/fast_thread_local.rs
index dfb9307..0861432 100644
--- a/src/libstd/sys/unix/fast_thread_local.rs
+++ b/src/libstd/sys/unix/fast_thread_local.rs
@@ -8,8 +8,6 @@
// Note, however, that we run on lots older linuxes, as well as cross
// compiling from a newer linux to an older linux, so we also have a
// fallback implementation to use as well.
-//
-// Due to rust-lang/rust#18804, make sure this is not generic!
#[cfg(any(
target_os = "linux",
target_os = "fuchsia",
diff --git a/src/libstd/sys/vxworks/ext/mod.rs b/src/libstd/sys/vxworks/ext/mod.rs
index 251a198..8fa9bd9 100644
--- a/src/libstd/sys/vxworks/ext/mod.rs
+++ b/src/libstd/sys/vxworks/ext/mod.rs
@@ -18,4 +18,7 @@
#[doc(no_inline)]
#[stable(feature = "rust1", since = "1.0.0")]
pub use super::io::{AsRawFd, FromRawFd, IntoRawFd, RawFd};
+ #[doc(no_inline)]
+ #[stable(feature = "rust1", since = "1.0.0")]
+ pub use super::process::ExitStatusExt;
}
diff --git a/src/libstd/sys/vxworks/os.rs b/src/libstd/sys/vxworks/os.rs
index baa6c42..71e1d16 100644
--- a/src/libstd/sys/vxworks/os.rs
+++ b/src/libstd/sys/vxworks/os.rs
@@ -11,14 +11,12 @@
use crate::ptr;
use crate::slice;
use crate::str;
-use crate::sys_common::mutex::Mutex;
+use crate::sys_common::mutex::{Mutex, MutexGuard};
use crate::sys::cvt;
/*use sys::fd; this one is probably important */
use crate::vec;
const TMPBUF_SZ: usize = 128;
-static ENV_LOCK: Mutex = Mutex::new();
-
// This is a terrible fix
use crate::sys::os_str::Buf;
@@ -200,11 +198,18 @@
&mut environ
}
+pub unsafe fn env_lock() -> MutexGuard<'static> {
+ // We never call `ENV_LOCK.init()`, so it is UB to attempt to
+ // acquire this mutex reentrantly!
+ static ENV_LOCK: Mutex = Mutex::new();
+ ENV_LOCK.lock()
+}
+
/// Returns a vector of (variable, value) byte-vector pairs for all the
/// environment variables of the current process.
pub fn env() -> Env {
unsafe {
- let _guard = ENV_LOCK.lock();
+ let _guard = env_lock();
let mut environ = *environ();
if environ == ptr::null() {
panic!("os::env() failure getting env string from OS: {}",
@@ -244,7 +249,7 @@
// always None as well
let k = CString::new(k.as_bytes())?;
unsafe {
- let _guard = ENV_LOCK.lock();
+ let _guard = env_lock();
let s = libc::getenv(k.as_ptr()) as *const libc::c_char;
let ret = if s.is_null() {
None
@@ -260,7 +265,7 @@
let v = CString::new(v.as_bytes())?;
unsafe {
- let _guard = ENV_LOCK.lock();
+ let _guard = env_lock();
cvt(libc::setenv(k.as_ptr(), v.as_ptr(), 1)).map(|_| ())
}
}
@@ -269,7 +274,7 @@
let nbuf = CString::new(n.as_bytes())?;
unsafe {
- let _guard = ENV_LOCK.lock();
+ let _guard = env_lock();
cvt(libc::unsetenv(nbuf.as_ptr())).map(|_| ())
}
}
diff --git a/src/libstd/sys/vxworks/process/process_vxworks.rs b/src/libstd/sys/vxworks/process/process_vxworks.rs
index 7446471..79bfd770 100644
--- a/src/libstd/sys/vxworks/process/process_vxworks.rs
+++ b/src/libstd/sys/vxworks/process/process_vxworks.rs
@@ -15,6 +15,7 @@
-> io::Result<(Process, StdioPipes)> {
use crate::sys::{cvt_r};
const CLOEXEC_MSG_FOOTER: &'static [u8] = b"NOEX";
+ let envp = self.capture_env();
if self.saw_nul() {
return Err(io::Error::new(ErrorKind::InvalidInput,
@@ -52,12 +53,19 @@
t!(cvt(libc::chdir(cwd.as_ptr())));
}
+ let c_envp = envp.as_ref().map(|c| c.as_ptr())
+ .unwrap_or_else(|| *sys::os::environ() as *const _);
+ let stack_size = thread::min_stack();
+
+ // ensure that access to the environment is synchronized
+ let _lock = sys::os::env_lock();
+
let ret = libc::rtpSpawn(
self.get_argv()[0], // executing program
self.get_argv().as_ptr() as *mut *const c_char, // argv
- *sys::os::environ() as *mut *const c_char,
+ c_envp as *mut *const c_char,
100 as c_int, // initial priority
- thread::min_stack(), // initial stack size.
+ stack_size, // initial stack size.
0, // options
0 // task options
);
diff --git a/src/libstd/sys/wasi/args.rs b/src/libstd/sys/wasi/args.rs
index 3db36f5..02aa68d 100644
--- a/src/libstd/sys/wasi/args.rs
+++ b/src/libstd/sys/wasi/args.rs
@@ -26,6 +26,7 @@
let mut argv = Vec::with_capacity(argc);
let mut buf = Vec::with_capacity(buf_size);
wasi::args_get(argv.as_mut_ptr(), buf.as_mut_ptr()).ok()?;
+ argv.set_len(argc);
let mut ret = Vec::with_capacity(argc);
for ptr in argv {
let s = CStr::from_ptr(ptr.cast());
diff --git a/src/libstd/sys/windows/net.rs b/src/libstd/sys/windows/net.rs
index 32f4011..2f2f285 100644
--- a/src/libstd/sys/windows/net.rs
+++ b/src/libstd/sys/windows/net.rs
@@ -100,7 +100,7 @@
c::WSA_FLAG_OVERLAPPED | c::WSA_FLAG_NO_HANDLE_INHERIT) {
c::INVALID_SOCKET => {
match c::WSAGetLastError() {
- c::WSAEPROTOTYPE => {
+ c::WSAEPROTOTYPE | c::WSAEINVAL => {
match c::WSASocketW(fam, ty, 0, ptr::null_mut(), 0,
c::WSA_FLAG_OVERLAPPED) {
c::INVALID_SOCKET => Err(last_error()),
@@ -199,7 +199,7 @@
c::WSA_FLAG_OVERLAPPED | c::WSA_FLAG_NO_HANDLE_INHERIT) {
c::INVALID_SOCKET => {
match c::WSAGetLastError() {
- c::WSAEPROTOTYPE => {
+ c::WSAEPROTOTYPE | c::WSAEINVAL => {
match c::WSASocketW(info.iAddressFamily,
info.iSocketType,
info.iProtocol,
diff --git a/src/libstd/sys/windows/os_str.rs b/src/libstd/sys/windows/os_str.rs
index e451e0c..ef260f9 100644
--- a/src/libstd/sys/windows/os_str.rs
+++ b/src/libstd/sys/windows/os_str.rs
@@ -128,6 +128,7 @@
}
impl Slice {
+ #[inline]
pub fn from_str(s: &str) -> &Slice {
unsafe { mem::transmute(Wtf8::from_str(s)) }
}
diff --git a/src/libstd/sys_common/os_str_bytes.rs b/src/libstd/sys_common/os_str_bytes.rs
index a2608ad..eb8a881 100644
--- a/src/libstd/sys_common/os_str_bytes.rs
+++ b/src/libstd/sys_common/os_str_bytes.rs
@@ -139,10 +139,12 @@
}
impl Slice {
+ #[inline]
fn from_u8_slice(s: &[u8]) -> &Slice {
unsafe { mem::transmute(s) }
}
+ #[inline]
pub fn from_str(s: &str) -> &Slice {
Slice::from_u8_slice(s.as_bytes())
}
diff --git a/src/libsyntax/ast.rs b/src/libsyntax/ast.rs
index 75ddf10..92ba071 100644
--- a/src/libsyntax/ast.rs
+++ b/src/libsyntax/ast.rs
@@ -2488,14 +2488,14 @@
///
/// The name might be a dummy name in case of anonymous items.
#[derive(Clone, RustcEncodable, RustcDecodable, Debug)]
-pub struct Item {
+pub struct Item<K = ItemKind> {
pub attrs: Vec<Attribute>,
pub id: NodeId,
pub span: Span,
pub vis: Visibility,
pub ident: Ident,
- pub kind: ItemKind,
+ pub kind: K,
/// Original tokens this item was parsed from. This isn't necessarily
/// available for all items, although over time more and more items should
@@ -2650,16 +2650,7 @@
}
}
-#[derive(Clone, RustcEncodable, RustcDecodable, Debug)]
-pub struct ForeignItem {
- pub attrs: Vec<Attribute>,
- pub id: NodeId,
- pub span: Span,
- pub vis: Visibility,
- pub ident: Ident,
-
- pub kind: ForeignItemKind,
-}
+pub type ForeignItem = Item<ForeignItemKind>;
/// An item within an `extern` block.
#[derive(Clone, RustcEncodable, RustcDecodable, Debug)]
diff --git a/src/libsyntax/lib.rs b/src/libsyntax/lib.rs
index a947426..3617380 100644
--- a/src/libsyntax/lib.rs
+++ b/src/libsyntax/lib.rs
@@ -7,6 +7,7 @@
#![doc(html_root_url = "https://doc.rust-lang.org/nightly/",
test(attr(deny(warnings))))]
+#![feature(bool_to_option)]
#![feature(box_syntax)]
#![feature(const_fn)]
#![feature(const_transmute)]
diff --git a/src/libsyntax/mut_visit.rs b/src/libsyntax/mut_visit.rs
index 8889e5d..f8795d8 100644
--- a/src/libsyntax/mut_visit.rs
+++ b/src/libsyntax/mut_visit.rs
@@ -1053,7 +1053,7 @@
pub fn noop_flat_map_foreign_item<T: MutVisitor>(mut item: ForeignItem, visitor: &mut T)
-> SmallVec<[ForeignItem; 1]>
{
- let ForeignItem { ident, attrs, kind, id, span, vis } = &mut item;
+ let ForeignItem { ident, attrs, id, kind, vis, span, tokens: _ } = &mut item;
visitor.visit_ident(ident);
visit_attrs(attrs, visitor);
match kind {
diff --git a/src/libsyntax/print/pprust.rs b/src/libsyntax/print/pprust.rs
index 4821bbd..f0c5fb3 100644
--- a/src/libsyntax/print/pprust.rs
+++ b/src/libsyntax/print/pprust.rs
@@ -317,7 +317,7 @@
}
fn token_to_string_ext(token: &Token, convert_dollar_crate: bool) -> String {
- let convert_dollar_crate = if convert_dollar_crate { Some(token.span) } else { None };
+ let convert_dollar_crate = convert_dollar_crate.then_some(token.span);
token_kind_to_string_ext(&token.kind, convert_dollar_crate)
}
@@ -1518,6 +1518,7 @@
crate fn print_variant(&mut self, v: &ast::Variant) {
self.head("");
+ self.print_visibility(&v.vis);
let generics = ast::Generics::default();
self.print_struct(&v.data, &generics, v.ident, v.span, false);
match v.disr_expr {
diff --git a/src/libsyntax/util/lev_distance.rs b/src/libsyntax/util/lev_distance.rs
index 4127a8c..efb3c23 100644
--- a/src/libsyntax/util/lev_distance.rs
+++ b/src/libsyntax/util/lev_distance.rs
@@ -77,6 +77,6 @@
if let Some(candidate) = case_insensitive_match {
Some(candidate) // exact case insensitive match has a higher priority
} else {
- if let Some((candidate, _)) = levenstein_match { Some(candidate) } else { None }
+ levenstein_match.map(|(candidate, _)| candidate)
}
}
diff --git a/src/libsyntax_expand/mbe/macro_parser.rs b/src/libsyntax_expand/mbe/macro_parser.rs
index bf7960f..1e2f3f9 100644
--- a/src/libsyntax_expand/mbe/macro_parser.rs
+++ b/src/libsyntax_expand/mbe/macro_parser.rs
@@ -83,7 +83,7 @@
use syntax::sess::ParseSess;
use syntax::symbol::{kw, sym, Symbol};
use syntax::token::{self, DocComment, Nonterminal, Token};
-use syntax::tokenstream::{DelimSpan, TokenStream};
+use syntax::tokenstream::TokenStream;
use errors::{PResult, FatalError};
use smallvec::{smallvec, SmallVec};
@@ -164,11 +164,6 @@
/// The position of the "dot" in this matcher
idx: usize,
- /// The first span of source that the beginning of this matcher corresponds to. In other
- /// words, the token in the source whose span is `sp_open` is matched against the first token of
- /// the matcher.
- sp_open: Span,
-
/// For each named metavar in the matcher, we keep track of token trees matched against the
/// metavar by the black box parser. In particular, there may be more than one match per
/// metavar if we are in a repetition (each repetition matches each of the variables).
@@ -307,8 +302,8 @@
}
/// Generates the top-level matcher position in which the "dot" is before the first token of the
-/// matcher `ms` and we are going to start matching at the span `open` in the source.
-fn initial_matcher_pos<'root, 'tt>(ms: &'tt [TokenTree], open: Span) -> MatcherPos<'root, 'tt> {
+/// matcher `ms`.
+fn initial_matcher_pos<'root, 'tt>(ms: &'tt [TokenTree]) -> MatcherPos<'root, 'tt> {
let match_idx_hi = count_names(ms);
let matches = create_matches(match_idx_hi);
MatcherPos {
@@ -316,8 +311,6 @@
top_elts: TtSeq(ms), // "elts" is an abbr. for "elements"
// The "dot" is before the first token of the matcher
idx: 0,
- // We start matching at the span `open` in the source code
- sp_open: open,
// Initialize `matches` to a bunch of empty `Vec`s -- one for each metavar in `top_elts`.
// `match_lo` for `top_elts` is 0 and `match_hi` is `matches.len()`. `match_cur` is 0 since
@@ -355,7 +348,7 @@
/// token tree it was derived from.
#[derive(Debug, Clone)]
crate enum NamedMatch {
- MatchedSeq(Lrc<NamedMatchVec>, DelimSpan),
+ MatchedSeq(Lrc<NamedMatchVec>),
MatchedNonterminal(Lrc<Nonterminal>),
}
@@ -497,8 +490,7 @@
// Add matches from this repetition to the `matches` of `up`
for idx in item.match_lo..item.match_hi {
let sub = item.matches[idx].clone();
- let span = DelimSpan::from_pair(item.sp_open, token.span);
- new_pos.push_match(idx, MatchedSeq(sub, span));
+ new_pos.push_match(idx, MatchedSeq(sub));
}
// Move the "dot" past the repetition in `up`
@@ -552,7 +544,7 @@
new_item.match_cur += seq.num_captures;
new_item.idx += 1;
for idx in item.match_cur..item.match_cur + seq.num_captures {
- new_item.push_match(idx, MatchedSeq(Lrc::new(smallvec![]), sp));
+ new_item.push_match(idx, MatchedSeq(Lrc::new(smallvec![])));
}
cur_items.push(new_item);
}
@@ -568,7 +560,6 @@
match_cur: item.match_cur,
match_hi: item.match_cur + seq.num_captures,
up: Some(item),
- sp_open: sp.open,
top_elts: Tt(TokenTree::Sequence(sp, seq)),
})));
}
@@ -663,7 +654,7 @@
//
// This MatcherPos instance is allocated on the stack. All others -- and
// there are frequently *no* others! -- are allocated on the heap.
- let mut initial = initial_matcher_pos(ms, parser.token.span);
+ let mut initial = initial_matcher_pos(ms);
let mut cur_items = smallvec![MatcherPosHandle::Ref(&mut initial)];
let mut next_items = Vec::new();
diff --git a/src/libsyntax_expand/mbe/macro_rules.rs b/src/libsyntax_expand/mbe/macro_rules.rs
index e3c3655..2dd1587 100644
--- a/src/libsyntax_expand/mbe/macro_rules.rs
+++ b/src/libsyntax_expand/mbe/macro_rules.rs
@@ -379,7 +379,7 @@
// Extract the arguments:
let lhses = match argument_map[&lhs_nm] {
- MatchedSeq(ref s, _) => s
+ MatchedSeq(ref s) => s
.iter()
.map(|m| {
if let MatchedNonterminal(ref nt) = *m {
@@ -402,7 +402,7 @@
};
let rhses = match argument_map[&rhs_nm] {
- MatchedSeq(ref s, _) => s
+ MatchedSeq(ref s) => s
.iter()
.map(|m| {
if let MatchedNonterminal(ref nt) = *m {
diff --git a/src/libsyntax_expand/mbe/transcribe.rs b/src/libsyntax_expand/mbe/transcribe.rs
index a115766..0605f7f 100644
--- a/src/libsyntax_expand/mbe/transcribe.rs
+++ b/src/libsyntax_expand/mbe/transcribe.rs
@@ -299,7 +299,7 @@
for &(idx, _) in repeats {
match matched {
MatchedNonterminal(_) => break,
- MatchedSeq(ref ads, _) => matched = ads.get(idx).unwrap(),
+ MatchedSeq(ref ads) => matched = ads.get(idx).unwrap(),
}
}
@@ -382,7 +382,7 @@
match lookup_cur_matched(name, interpolations, repeats) {
Some(matched) => match matched {
MatchedNonterminal(_) => LockstepIterSize::Unconstrained,
- MatchedSeq(ref ads, _) => LockstepIterSize::Constraint(ads.len(), name),
+ MatchedSeq(ref ads) => LockstepIterSize::Constraint(ads.len(), name),
},
_ => LockstepIterSize::Unconstrained,
}
diff --git a/src/libsyntax_expand/placeholders.rs b/src/libsyntax_expand/placeholders.rs
index 74ade1d..faea04e 100644
--- a/src/libsyntax_expand/placeholders.rs
+++ b/src/libsyntax_expand/placeholders.rs
@@ -65,6 +65,7 @@
AstFragment::ForeignItems(smallvec![ast::ForeignItem {
id, span, ident, vis, attrs,
kind: ast::ForeignItemKind::Macro(mac_placeholder()),
+ tokens: None,
}]),
AstFragmentKind::Pat => AstFragment::Pat(P(ast::Pat {
id, span, kind: ast::PatKind::Mac(mac_placeholder()),
diff --git a/src/libsyntax_expand/proc_macro.rs b/src/libsyntax_expand/proc_macro.rs
index 8e56e2b..520488c 100644
--- a/src/libsyntax_expand/proc_macro.rs
+++ b/src/libsyntax_expand/proc_macro.rs
@@ -1,7 +1,7 @@
use crate::base::{self, *};
use crate::proc_macro_server;
-use syntax::ast::{self, ItemKind, MacArgs};
+use syntax::ast::{self, ItemKind, MetaItemKind, NestedMetaItem};
use syntax::errors::{Applicability, FatalError};
use syntax::symbol::sym;
use syntax::token;
@@ -171,34 +171,71 @@
if !attr.has_name(sym::derive) {
return true;
}
- if !attr.is_meta_item_list() {
- cx.struct_span_err(attr.span, "malformed `derive` attribute input")
- .span_suggestion(
- attr.span,
- "missing traits to be derived",
- "#[derive(Trait1, Trait2, ...)]".to_owned(),
- Applicability::HasPlaceholders,
- ).emit();
- return false;
- }
- let parse_derive_paths = |attr: &ast::Attribute| {
- if let MacArgs::Empty = attr.get_normal_item().args {
- return Ok(Vec::new());
+ // 1) First let's ensure that it's a meta item.
+ let nmis = match attr.meta_item_list() {
+ None => {
+ cx.struct_span_err(attr.span, "malformed `derive` attribute input")
+ .span_suggestion(
+ attr.span,
+ "missing traits to be derived",
+ "#[derive(Trait1, Trait2, ...)]".to_owned(),
+ Applicability::HasPlaceholders,
+ )
+ .emit();
+ return false;
}
- rustc_parse::parse_in_attr(cx.parse_sess, attr, |p| p.parse_derive_paths())
+ Some(x) => x,
};
- match parse_derive_paths(attr) {
- Ok(traits) => {
- result.extend(traits);
- true
- }
- Err(mut e) => {
- e.emit();
- false
- }
- }
+ let mut error_reported_filter_map = false;
+ let mut error_reported_map = false;
+ let traits = nmis
+ .into_iter()
+ // 2) Moreover, let's ensure we have a path and not `#[derive("foo")]`.
+ .filter_map(|nmi| match nmi {
+ NestedMetaItem::Literal(lit) => {
+ error_reported_filter_map = true;
+ cx.struct_span_err(lit.span, "expected path to a trait, found literal")
+ .help("for example, write `#[derive(Debug)]` for `Debug`")
+ .emit();
+ None
+ }
+ NestedMetaItem::MetaItem(mi) => Some(mi),
+ })
+ // 3) Finally, we only accept `#[derive($path_0, $path_1, ..)]`
+ // but not e.g. `#[derive($path_0 = "value", $path_1(abc))]`.
+ // In this case we can still at least determine that the user
+ // wanted this trait to be derived, so let's keep it.
+ .map(|mi| {
+ let mut traits_dont_accept = |title, action| {
+ error_reported_map = true;
+ let sp = mi.span.with_lo(mi.path.span.hi());
+ cx.struct_span_err(sp, title)
+ .span_suggestion(
+ sp,
+ action,
+ String::new(),
+ Applicability::MachineApplicable,
+ )
+ .emit();
+ };
+ match &mi.kind {
+ MetaItemKind::List(..) => traits_dont_accept(
+ "traits in `#[derive(...)]` don't accept arguments",
+ "remove the arguments",
+ ),
+ MetaItemKind::NameValue(..) => traits_dont_accept(
+ "traits in `#[derive(...)]` don't accept values",
+ "remove the value",
+ ),
+ MetaItemKind::Word => {}
+ }
+ mi.path
+ });
+
+ result.extend(traits);
+ !error_reported_filter_map && !error_reported_map
});
result
}
diff --git a/src/libsyntax_ext/format_foreign.rs b/src/libsyntax_ext/format_foreign.rs
index 3d4f827..0d1d292 100644
--- a/src/libsyntax_ext/format_foreign.rs
+++ b/src/libsyntax_ext/format_foreign.rs
@@ -95,12 +95,12 @@
};
// Has a special form in Rust for numbers.
- let fill = if c_zero { Some("0") } else { None };
+ let fill = c_zero.then_some("0");
- let align = if c_left { Some("<") } else { None };
+ let align = c_left.then_some("<");
// Rust doesn't have an equivalent to the `' '` flag.
- let sign = if c_plus { Some("+") } else { None };
+ let sign = c_plus.then_some("+");
// Not *quite* the same, depending on the type...
let alt = c_alt;
diff --git a/src/libsyntax_ext/lib.rs b/src/libsyntax_ext/lib.rs
index b9287d2..55c7f3f 100644
--- a/src/libsyntax_ext/lib.rs
+++ b/src/libsyntax_ext/lib.rs
@@ -3,6 +3,7 @@
#![doc(html_root_url = "https://doc.rust-lang.org/nightly/")]
+#![feature(bool_to_option)]
#![feature(crate_visibility_modifier)]
#![feature(decl_macro)]
#![feature(nll)]
diff --git a/src/libsyntax_pos/symbol.rs b/src/libsyntax_pos/symbol.rs
index 2af6671..92de56b 100644
--- a/src/libsyntax_pos/symbol.rs
+++ b/src/libsyntax_pos/symbol.rs
@@ -213,6 +213,7 @@
const_indexing,
const_in_array_repeat_expressions,
const_let,
+ const_mut_refs,
const_panic,
const_raw_ptr_deref,
const_raw_ptr_to_usize_cast,
@@ -659,6 +660,7 @@
_Self,
self_in_typedefs,
self_struct_ctor,
+ send_trait,
should_panic,
simd,
simd_extract,
@@ -696,6 +698,7 @@
sty,
sub_with_overflow,
suggestion,
+ sync_trait,
target_feature,
target_has_atomic,
target_has_atomic_load_store,
@@ -869,12 +872,18 @@
impl fmt::Debug for Ident {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
+ if self.is_raw_guess() {
+ write!(f, "r#")?;
+ }
write!(f, "{}{:?}", self.name, self.span.ctxt())
}
}
impl fmt::Display for Ident {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
+ if self.is_raw_guess() {
+ write!(f, "r#")?;
+ }
fmt::Display::fmt(&self.name, f)
}
}
diff --git a/src/libtest/lib.rs b/src/libtest/lib.rs
index 7647978..0097558 100644
--- a/src/libtest/lib.rs
+++ b/src/libtest/lib.rs
@@ -24,6 +24,7 @@
#![cfg_attr(any(unix, target_os = "cloudabi"), feature(libc))]
#![feature(rustc_private)]
#![feature(nll)]
+#![feature(bool_to_option)]
#![feature(set_stdio)]
#![feature(panic_unwind)]
#![feature(staged_api)]
@@ -562,11 +563,7 @@
None
};
- let start = if report_time {
- Some(Instant::now())
- } else {
- None
- };
+ let start = report_time.then(Instant::now);
let result = catch_unwind(AssertUnwindSafe(testfn));
let exec_time = start.map(|start| {
let duration = start.elapsed();
@@ -597,11 +594,7 @@
let args = env::args().collect::<Vec<_>>();
let current_exe = &args[0];
- let start = if report_time {
- Some(Instant::now())
- } else {
- None
- };
+ let start = report_time.then(Instant::now);
let output = match Command::new(current_exe)
.env(SECONDARY_TEST_INVOKER_VAR, desc.name.as_slice())
.output() {
diff --git a/src/llvm-project b/src/llvm-project
index de1a7db..2cb4100 160000
--- a/src/llvm-project
+++ b/src/llvm-project
@@ -1 +1 @@
-Subproject commit de1a7dbf6c6b34f56e65732d45970ff27a8e84bf
+Subproject commit 2cb41005ed5c4747b10d2bf01d8779d3bb4ae32d
diff --git a/src/rustc/Cargo.toml b/src/rustc/Cargo.toml
index 997d139..86a93d7 100644
--- a/src/rustc/Cargo.toml
+++ b/src/rustc/Cargo.toml
@@ -23,3 +23,4 @@
[features]
jemalloc = ['jemalloc-sys']
+llvm = ['rustc_driver/llvm']
diff --git a/src/rustllvm/PassWrapper.cpp b/src/rustllvm/PassWrapper.cpp
index 1cb123e..6698e5d 100644
--- a/src/rustllvm/PassWrapper.cpp
+++ b/src/rustllvm/PassWrapper.cpp
@@ -658,46 +658,11 @@
}
};
-class RustPrintModulePass : public ModulePass {
- raw_ostream* OS;
- DemangleFn Demangle;
-public:
- static char ID;
- RustPrintModulePass() : ModulePass(ID), OS(nullptr), Demangle(nullptr) {}
- RustPrintModulePass(raw_ostream &OS, DemangleFn Demangle)
- : ModulePass(ID), OS(&OS), Demangle(Demangle) {}
-
- bool runOnModule(Module &M) override {
- RustAssemblyAnnotationWriter AW(Demangle);
-
- M.print(*OS, &AW, false);
-
- return false;
- }
-
- void getAnalysisUsage(AnalysisUsage &AU) const override {
- AU.setPreservesAll();
- }
-
- static StringRef name() { return "RustPrintModulePass"; }
-};
-
} // namespace
-namespace llvm {
- void initializeRustPrintModulePassPass(PassRegistry&);
-}
-
-char RustPrintModulePass::ID = 0;
-INITIALIZE_PASS(RustPrintModulePass, "print-rust-module",
- "Print rust module to stderr", false, false)
-
extern "C" LLVMRustResult
-LLVMRustPrintModule(LLVMPassManagerRef PMR, LLVMModuleRef M,
- const char *Path, DemangleFn Demangle) {
- llvm::legacy::PassManager *PM = unwrap<llvm::legacy::PassManager>(PMR);
+LLVMRustPrintModule(LLVMModuleRef M, const char *Path, DemangleFn Demangle) {
std::string ErrorInfo;
-
std::error_code EC;
raw_fd_ostream OS(Path, EC, sys::fs::F_None);
if (EC)
@@ -707,11 +672,9 @@
return LLVMRustResult::Failure;
}
+ RustAssemblyAnnotationWriter AAW(Demangle);
formatted_raw_ostream FOS(OS);
-
- PM->add(new RustPrintModulePass(FOS, Demangle));
-
- PM->run(*unwrap(M));
+ unwrap(M)->print(FOS, &AAW);
return LLVMRustResult::Success;
}
diff --git a/src/rustllvm/RustWrapper.cpp b/src/rustllvm/RustWrapper.cpp
index a83ba9a..720928e 100644
--- a/src/rustllvm/RustWrapper.cpp
+++ b/src/rustllvm/RustWrapper.cpp
@@ -129,8 +129,9 @@
}
extern "C" LLVMValueRef
-LLVMRustGetOrInsertGlobal(LLVMModuleRef M, const char *Name, LLVMTypeRef Ty) {
- return wrap(unwrap(M)->getOrInsertGlobal(Name, unwrap(Ty)));
+LLVMRustGetOrInsertGlobal(LLVMModuleRef M, const char *Name, size_t NameLen, LLVMTypeRef Ty) {
+ StringRef NameRef(Name, NameLen);
+ return wrap(unwrap(M)->getOrInsertGlobal(NameRef, unwrap(Ty)));
}
extern "C" LLVMValueRef
@@ -1287,11 +1288,12 @@
}
extern "C" void LLVMRustSetComdat(LLVMModuleRef M, LLVMValueRef V,
- const char *Name) {
+ const char *Name, size_t NameLen) {
Triple TargetTriple(unwrap(M)->getTargetTriple());
GlobalObject *GV = unwrap<GlobalObject>(V);
if (!TargetTriple.isOSBinFormatMachO()) {
- GV->setComdat(unwrap(M)->getOrInsertComdat(Name));
+ StringRef NameRef(Name, NameLen);
+ GV->setComdat(unwrap(M)->getOrInsertComdat(NameRef));
}
}
diff --git a/src/test/codegen/bool-cmp.rs b/src/test/codegen/bool-cmp.rs
new file mode 100644
index 0000000..8769a4c
--- /dev/null
+++ b/src/test/codegen/bool-cmp.rs
@@ -0,0 +1,17 @@
+// This is a test for optimal Ord trait implementation for bool.
+// See <https://github.com/rust-lang/rust/issues/66780> for more info.
+
+// compile-flags: -C opt-level=3
+
+#![crate_type = "lib"]
+
+use std::cmp::Ordering;
+
+// CHECK-LABEL: @cmp_bool
+#[no_mangle]
+pub fn cmp_bool(a: bool, b: bool) -> Ordering {
+// CHECK: zext i1
+// CHECK: zext i1
+// CHECK: sub nsw
+ a.cmp(&b)
+}
diff --git a/src/test/codegen/gdb_debug_script_load.rs b/src/test/codegen/gdb_debug_script_load.rs
index 2e8dc7b..178269f 100644
--- a/src/test/codegen/gdb_debug_script_load.rs
+++ b/src/test/codegen/gdb_debug_script_load.rs
@@ -1,6 +1,8 @@
// ignore-tidy-linelength
// ignore-windows
// ignore-macos
+// ignore-wasm
+// ignore-emscripten
// compile-flags: -g -C no-prepopulate-passes
diff --git a/src/test/codegen/set-discriminant-invalid.rs b/src/test/codegen/set-discriminant-invalid.rs
new file mode 100644
index 0000000..d9614f0
--- /dev/null
+++ b/src/test/codegen/set-discriminant-invalid.rs
@@ -0,0 +1,43 @@
+// compile-flags: -C opt-level=0
+#![crate_type = "lib"]
+
+pub enum ApiError {}
+#[allow(dead_code)]
+pub struct TokioError {
+ b: bool,
+}
+pub enum Error {
+ Api {
+ source: ApiError,
+ },
+ Ethereum,
+ Tokio {
+ source: TokioError,
+ },
+}
+struct Api;
+impl IntoError<Error> for Api
+{
+ type Source = ApiError;
+ // CHECK-LABEL: @into_error
+ // CHECK: llvm.trap()
+ // Also check the next two instructions to make sure we do not match against `trap`
+ // elsewhere in the code.
+ // CHECK-NEXT: load
+ // CHECK-NEXT: ret
+ #[no_mangle]
+ fn into_error(self, error: Self::Source) -> Error {
+ Error::Api {
+ source: (|v| v)(error),
+ }
+ }
+}
+
+pub trait IntoError<E>
+{
+ /// The underlying error
+ type Source;
+
+ /// Combine the information to produce the error
+ fn into_error(self, source: Self::Source) -> E;
+}
diff --git a/src/test/compile-fail/consts/const-err3.rs b/src/test/compile-fail/consts/const-err3.rs
index add4eef..fc10824 100644
--- a/src/test/compile-fail/consts/const-err3.rs
+++ b/src/test/compile-fail/consts/const-err3.rs
@@ -14,7 +14,6 @@
//~^ ERROR const_err
let _e = [5u8][1];
//~^ ERROR const_err
- //~| ERROR this expression will panic at runtime
black_box(b);
black_box(c);
black_box(d);
diff --git a/src/test/compile-fail/consts/const-fn-error.rs b/src/test/compile-fail/consts/const-fn-error.rs
index 1a4fc72..5d26059 100644
--- a/src/test/compile-fail/consts/const-fn-error.rs
+++ b/src/test/compile-fail/consts/const-fn-error.rs
@@ -6,7 +6,7 @@
let mut sum = 0;
for i in 0..x {
//~^ ERROR E0015
- //~| ERROR E0017
+ //~| ERROR E0658
//~| ERROR E0080
//~| ERROR E0744
//~| ERROR E0019
diff --git a/src/test/incremental/issue-61323.rs b/src/test/incremental/issue-61323.rs
new file mode 100644
index 0000000..448ce36
--- /dev/null
+++ b/src/test/incremental/issue-61323.rs
@@ -0,0 +1,15 @@
+// revisions: rpass cfail
+
+enum A {
+ //[cfail]~^ ERROR 3:1: 3:7: recursive type `A` has infinite size [E0072]
+ B(C),
+}
+
+#[cfg(rpass)]
+struct C(Box<A>);
+
+#[cfg(cfail)]
+struct C(A);
+//[cfail]~^ ERROR 12:1: 12:13: recursive type `C` has infinite size [E0072]
+
+fn main() {}
diff --git a/src/test/mir-opt/const_prop/issue-66971.rs b/src/test/mir-opt/const_prop/issue-66971.rs
new file mode 100644
index 0000000..30c7530
--- /dev/null
+++ b/src/test/mir-opt/const_prop/issue-66971.rs
@@ -0,0 +1,38 @@
+// compile-flags: -Z mir-opt-level=2
+
+// Due to a bug in propagating scalar pairs the assertion below used to fail. In the expected
+// outputs below, after ConstProp this is how _2 would look like with the bug:
+//
+// _2 = (const Scalar(0x00) : (), const 0u8);
+//
+// Which has the wrong type.
+
+fn encode(this: ((), u8, u8)) {
+ assert!(this.2 == 0);
+}
+
+fn main() {
+ encode(((), 0, 0));
+}
+
+// END RUST SOURCE
+// START rustc.main.ConstProp.before.mir
+// bb0: {
+// ...
+// _3 = ();
+// _2 = (move _3, const 0u8, const 0u8);
+// ...
+// _1 = const encode(move _2) -> bb1;
+// ...
+// }
+// END rustc.main.ConstProp.before.mir
+// START rustc.main.ConstProp.after.mir
+// bb0: {
+// ...
+// _3 = const Scalar(<ZST>) : ();
+// _2 = (move _3, const 0u8, const 0u8);
+// ...
+// _1 = const encode(move _2) -> bb1;
+// ...
+// }
+// END rustc.main.ConstProp.after.mir
diff --git a/src/test/mir-opt/const_prop/issue-67019.rs b/src/test/mir-opt/const_prop/issue-67019.rs
new file mode 100644
index 0000000..c6d753a
--- /dev/null
+++ b/src/test/mir-opt/const_prop/issue-67019.rs
@@ -0,0 +1,34 @@
+// compile-flags: -Z mir-opt-level=2
+
+// This used to ICE in const-prop
+
+fn test(this: ((u8, u8),)) {
+ assert!((this.0).0 == 1);
+}
+
+fn main() {
+ test(((1, 2),));
+}
+
+// Important bit is parameter passing so we only check that below
+// END RUST SOURCE
+// START rustc.main.ConstProp.before.mir
+// bb0: {
+// ...
+// _3 = (const 1u8, const 2u8);
+// _2 = (move _3,);
+// ...
+// _1 = const test(move _2) -> bb1;
+// ...
+// }
+// END rustc.main.ConstProp.before.mir
+// START rustc.main.ConstProp.after.mir
+// bb0: {
+// ...
+// _3 = (const 1u8, const 2u8);
+// _2 = (move _3,);
+// ...
+// _1 = const test(move _2) -> bb1;
+// ...
+// }
+// END rustc.main.ConstProp.after.mir
diff --git a/src/test/mir-opt/const_prop/return_place.rs b/src/test/mir-opt/const_prop/return_place.rs
index cc9951b..ea7c1e7 100644
--- a/src/test/mir-opt/const_prop/return_place.rs
+++ b/src/test/mir-opt/const_prop/return_place.rs
@@ -21,9 +21,6 @@
// _0 = move (_1.0: u32);
// return;
// }
-// bb2 (cleanup): {
-// resume;
-// }
// }
// END rustc.add.ConstProp.before.mir
// START rustc.add.ConstProp.after.mir
@@ -38,9 +35,6 @@
// _0 = const 4u32;
// return;
// }
-// bb2 (cleanup): {
-// resume;
-// }
// }
// END rustc.add.ConstProp.after.mir
// START rustc.add.PreCodegen.before.mir
diff --git a/src/test/mir-opt/retain-never-const.rs b/src/test/mir-opt/retain-never-const.rs
new file mode 100644
index 0000000..5d59b2f
--- /dev/null
+++ b/src/test/mir-opt/retain-never-const.rs
@@ -0,0 +1,28 @@
+// Regression test for #66975 - ensure that we don't keep unevaluated
+// `!`-typed constants until codegen.
+
+// Force generation of optimized mir for functions that do not reach codegen.
+// compile-flags: --emit mir,link
+
+#![feature(const_panic)]
+
+struct PrintName<T>(T);
+
+impl<T> PrintName<T> {
+ const VOID: ! = panic!();
+}
+
+fn no_codegen<T>() {
+ let _ = PrintName::<T>::VOID;
+}
+
+fn main() {}
+
+// END RUST SOURCE
+// START rustc.no_codegen.PreCodegen.after.mir
+// bb0: {
+// StorageLive(_1);
+// _1 = const PrintName::<T>::VOID;
+// unreachable;
+// }
+// END rustc.no_codegen.PreCodegen.after.mir
diff --git a/src/test/mir-opt/uniform_array_move_out.rs b/src/test/mir-opt/uniform_array_move_out.rs
index c249154..f2e1864 100644
--- a/src/test/mir-opt/uniform_array_move_out.rs
+++ b/src/test/mir-opt/uniform_array_move_out.rs
@@ -18,58 +18,12 @@
// END RUST SOURCE
-// START rustc.move_out_from_end.UniformArrayMoveOut.before.mir
-// StorageLive(_6);
-// _6 = move _1[-1 of 1];
-// _0 = ();
-// END rustc.move_out_from_end.UniformArrayMoveOut.before.mir
-
-// START rustc.move_out_from_end.UniformArrayMoveOut.after.mir
-// StorageLive(_6);
+// START rustc.move_out_from_end.mir_map.0.mir
// _6 = move _1[1 of 2];
-// nop;
// _0 = ();
-// END rustc.move_out_from_end.UniformArrayMoveOut.after.mir
+// END rustc.move_out_from_end.mir_map.0.mir
-// START rustc.move_out_by_subslice.UniformArrayMoveOut.before.mir
-// StorageLive(_6);
-// _6 = move _1[0:];
-// END rustc.move_out_by_subslice.UniformArrayMoveOut.before.mir
-
-// START rustc.move_out_by_subslice.UniformArrayMoveOut.after.mir
-// StorageLive(_6);
-// StorageLive(_7);
-// _7 = move _1[0 of 2];
-// StorageLive(_8);
-// _8 = move _1[1 of 2];
-// _6 = [move _7, move _8];
-// StorageDead(_7);
-// StorageDead(_8);
-// nop;
+// START rustc.move_out_by_subslice.mir_map.0.mir
+// _6 = move _1[0..2];
// _0 = ();
-// END rustc.move_out_by_subslice.UniformArrayMoveOut.after.mir
-
-// START rustc.move_out_by_subslice.RestoreSubsliceArrayMoveOut.before.mir
-// StorageLive(_6);
-// StorageLive(_7);
-// _7 = move _1[0 of 2];
-// StorageLive(_8);
-// _8 = move _1[1 of 2];
-// _6 = [move _7, move _8];
-// StorageDead(_7);
-// StorageDead(_8);
-// _0 = ();
-// END rustc.move_out_by_subslice.RestoreSubsliceArrayMoveOut.before.mir
-
-// START rustc.move_out_by_subslice.RestoreSubsliceArrayMoveOut.after.mir
-// StorageLive(_6);
-// nop;
-// nop;
-// nop;
-// nop;
-// _6 = move _1[0:];
-// nop;
-// nop;
-// nop;
-// _0 = ();
-// END rustc.move_out_by_subslice.RestoreSubsliceArrayMoveOut.after.mir
+// END rustc.move_out_by_subslice.mir_map.0.mir
diff --git a/src/test/pretty/enum-variant-vis.rs b/src/test/pretty/enum-variant-vis.rs
new file mode 100644
index 0000000..a3e8178
--- /dev/null
+++ b/src/test/pretty/enum-variant-vis.rs
@@ -0,0 +1,8 @@
+// pp-exact
+
+// Check that the visibility is printed on an enum variant.
+
+fn main() { }
+
+#[cfg(FALSE)]
+enum Foo { pub V, }
diff --git a/src/test/rustdoc-ui/issue-61732.rs b/src/test/rustdoc-ui/issue-61732.rs
new file mode 100644
index 0000000..d4835c0
--- /dev/null
+++ b/src/test/rustdoc-ui/issue-61732.rs
@@ -0,0 +1,4 @@
+// This previously triggered an ICE.
+
+pub(in crate::r#mod) fn main() {}
+//~^ ERROR expected module, found unresolved item
diff --git a/src/test/rustdoc-ui/issue-61732.stderr b/src/test/rustdoc-ui/issue-61732.stderr
new file mode 100644
index 0000000..6c8ba48
--- /dev/null
+++ b/src/test/rustdoc-ui/issue-61732.stderr
@@ -0,0 +1,11 @@
+error[E0577]: expected module, found unresolved item `crate::r#mod`
+ --> $DIR/issue-61732.rs:3:8
+ |
+LL | pub(in crate::r#mod) fn main() {}
+ | ^^^^^^^^^^^^ not a module
+
+error: Compilation failed, aborting rustdoc
+
+error: aborting due to 2 previous errors
+
+For more information about this error, try `rustc --explain E0577`.
diff --git a/src/test/rustdoc/duplicate-cfg.rs b/src/test/rustdoc/duplicate-cfg.rs
new file mode 100644
index 0000000..505d6ee
--- /dev/null
+++ b/src/test/rustdoc/duplicate-cfg.rs
@@ -0,0 +1,15 @@
+#![crate_name = "foo"]
+#![feature(doc_cfg)]
+
+// @has 'foo/index.html'
+// @!has '-' '//*[@class="stab portability"]' 'feature="sync" and'
+// @has '-' '//*[@class="stab portability"]' 'feature="sync"'
+#[doc(cfg(feature = "sync"))]
+#[doc(cfg(feature = "sync"))]
+pub struct Foo;
+
+#[doc(cfg(feature = "sync"))]
+pub mod bar {
+ #[doc(cfg(feature = "sync"))]
+ pub struct Bar;
+}
diff --git a/src/test/rustdoc/issue-66159.rs b/src/test/rustdoc/issue-66159.rs
index a69ba61..003d079a 100644
--- a/src/test/rustdoc/issue-66159.rs
+++ b/src/test/rustdoc/issue-66159.rs
@@ -1,6 +1,5 @@
-// aux-build:issue-66159-1.rs
+// aux-crate:priv:issue_66159_1=issue-66159-1.rs
// compile-flags:-Z unstable-options
-// extern-private:issue_66159_1
// The issue was an ICE which meant that we never actually generated the docs
// so if we have generated the docs, we're okay.
diff --git a/src/test/ui/anonymous-higher-ranked-lifetime.stderr b/src/test/ui/anonymous-higher-ranked-lifetime.stderr
index 9be44c7..c6d9a61 100644
--- a/src/test/ui/anonymous-higher-ranked-lifetime.stderr
+++ b/src/test/ui/anonymous-higher-ranked-lifetime.stderr
@@ -121,3 +121,4 @@
error: aborting due to 11 previous errors
+For more information about this error, try `rustc --explain E0631`.
diff --git a/src/test/ui/associated-const/issue-63496.rs b/src/test/ui/associated-const/issue-63496.rs
index 311c48b..f9f663a 100644
--- a/src/test/ui/associated-const/issue-63496.rs
+++ b/src/test/ui/associated-const/issue-63496.rs
@@ -2,8 +2,8 @@
const C: usize;
fn f() -> ([u8; A::C], [u8; A::C]);
- //~^ ERROR: type annotations needed: cannot resolve
- //~| ERROR: type annotations needed: cannot resolve
+ //~^ ERROR: type annotations needed
+ //~| ERROR: type annotations needed
}
fn main() {}
diff --git a/src/test/ui/associated-const/issue-63496.stderr b/src/test/ui/associated-const/issue-63496.stderr
index 70bb12d..23916a3 100644
--- a/src/test/ui/associated-const/issue-63496.stderr
+++ b/src/test/ui/associated-const/issue-63496.stderr
@@ -1,20 +1,24 @@
-error[E0283]: type annotations needed: cannot resolve `_: A`
+error[E0283]: type annotations needed
--> $DIR/issue-63496.rs:4:21
|
LL | const C: usize;
| --------------- required by `A::C`
LL |
LL | fn f() -> ([u8; A::C], [u8; A::C]);
- | ^^^^
+ | ^^^^ cannot infer type
+ |
+ = note: cannot resolve `_: A`
-error[E0283]: type annotations needed: cannot resolve `_: A`
+error[E0283]: type annotations needed
--> $DIR/issue-63496.rs:4:33
|
LL | const C: usize;
| --------------- required by `A::C`
LL |
LL | fn f() -> ([u8; A::C], [u8; A::C]);
- | ^^^^
+ | ^^^^ cannot infer type
+ |
+ = note: cannot resolve `_: A`
error: aborting due to 2 previous errors
diff --git a/src/test/ui/associated-item/issue-48027.stderr b/src/test/ui/associated-item/issue-48027.stderr
index 562146a..9c825d5 100644
--- a/src/test/ui/associated-item/issue-48027.stderr
+++ b/src/test/ui/associated-item/issue-48027.stderr
@@ -7,13 +7,15 @@
LL | impl dyn Bar {}
| ^^^^^^^ the trait `Bar` cannot be made into an object
-error[E0283]: type annotations needed: cannot resolve `_: Bar`
+error[E0283]: type annotations needed
--> $DIR/issue-48027.rs:3:32
|
LL | const X: usize;
| --------------- required by `Bar::X`
LL | fn return_n(&self) -> [u8; Bar::X];
- | ^^^^^^
+ | ^^^^^^ cannot infer type
+ |
+ = note: cannot resolve `_: Bar`
error: aborting due to 2 previous errors
diff --git a/src/test/ui/associated-types/associated-types-overridden-binding.stderr b/src/test/ui/associated-types/associated-types-overridden-binding.stderr
index 5ef1b23..069da95 100644
--- a/src/test/ui/associated-types/associated-types-overridden-binding.stderr
+++ b/src/test/ui/associated-types/associated-types-overridden-binding.stderr
@@ -1,18 +1,23 @@
-error[E0284]: type annotations needed: cannot resolve `<Self as std::iter::Iterator>::Item == i32`
+error[E0284]: type annotations needed
--> $DIR/associated-types-overridden-binding.rs:4:1
|
LL | trait Foo: Iterator<Item = i32> {}
| ------------------------------- required by `Foo`
LL | trait Bar: Foo<Item = u32> {}
- | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ cannot infer type for type parameter `Self`
+ |
+ = note: cannot resolve `<Self as std::iter::Iterator>::Item == i32`
-error[E0282]: type annotations needed
+error[E0284]: type annotations needed
--> $DIR/associated-types-overridden-binding.rs:7:1
|
+LL | trait I32Iterator = Iterator<Item = i32>;
+ | ----------------------------------------- required by `I32Iterator`
LL | trait U32Iterator = I32Iterator<Item = u32>;
- | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ cannot infer type
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ cannot infer type for type parameter `Self`
+ |
+ = note: cannot resolve `<Self as std::iter::Iterator>::Item == i32`
error: aborting due to 2 previous errors
-Some errors have detailed explanations: E0282, E0284.
-For more information about an error, try `rustc --explain E0282`.
+For more information about this error, try `rustc --explain E0284`.
diff --git a/src/test/ui/associated-types/associated-types-unconstrained.stderr b/src/test/ui/associated-types/associated-types-unconstrained.stderr
index 4e9e54d..14ce483 100644
--- a/src/test/ui/associated-types/associated-types-unconstrained.stderr
+++ b/src/test/ui/associated-types/associated-types-unconstrained.stderr
@@ -1,8 +1,10 @@
-error[E0284]: type annotations needed: cannot resolve `<_ as Foo>::A == _`
+error[E0284]: type annotations needed
--> $DIR/associated-types-unconstrained.rs:14:20
|
LL | let x: isize = Foo::bar();
- | ^^^^^^^^
+ | ^^^^^^^^ cannot infer type
+ |
+ = note: cannot resolve `<_ as Foo>::A == _`
error: aborting due to previous error
diff --git a/src/test/ui/associated-types/cache/project-fn-ret-invariant.transmute.stderr b/src/test/ui/associated-types/cache/project-fn-ret-invariant.transmute.stderr
index 627609c..3e39c8a 100644
--- a/src/test/ui/associated-types/cache/project-fn-ret-invariant.transmute.stderr
+++ b/src/test/ui/associated-types/cache/project-fn-ret-invariant.transmute.stderr
@@ -9,13 +9,21 @@
|
LL | fn baz<'a,'b>(x: Type<'a>) -> Type<'static> {
| ^^
- = note: ...so that the expression is assignable:
- expected Type<'_>
- found Type<'a>
+note: ...so that the expression is assignable
+ --> $DIR/project-fn-ret-invariant.rs:48:13
+ |
+LL | bar(foo, x)
+ | ^
+ = note: expected `Type<'_>`
+ found `Type<'a>`
= note: but, the lifetime must be valid for the static lifetime...
- = note: ...so that the expression is assignable:
- expected Type<'static>
- found Type<'_>
+note: ...so that the expression is assignable
+ --> $DIR/project-fn-ret-invariant.rs:48:4
+ |
+LL | bar(foo, x)
+ | ^^^^^^^^^^^
+ = note: expected `Type<'static>`
+ found `Type<'_>`
error: aborting due to previous error
diff --git a/src/test/ui/async-await/async-fn-nonsend.rs b/src/test/ui/async-await/async-fn-nonsend.rs
index 1f1bf42..645c903 100644
--- a/src/test/ui/async-await/async-fn-nonsend.rs
+++ b/src/test/ui/async-await/async-fn-nonsend.rs
@@ -48,10 +48,10 @@
pub fn pass_assert() {
assert_send(local_dropped_before_await());
- //~^ ERROR `std::rc::Rc<()>` cannot be sent between threads safely
+ //~^ ERROR future cannot be sent between threads safely
assert_send(non_send_temporary_in_match());
- //~^ ERROR `std::rc::Rc<()>` cannot be sent between threads safely
+ //~^ ERROR future cannot be sent between threads safely
assert_send(non_sync_with_method_call());
- //~^ ERROR `dyn std::fmt::Write` cannot be sent between threads safely
- //~^^ ERROR `*mut (dyn std::ops::Fn() + 'static)` cannot be shared between threads safely
+ //~^ ERROR future cannot be sent between threads safely
+ //~^^ ERROR future cannot be sent between threads safely
}
diff --git a/src/test/ui/async-await/async-fn-nonsend.stderr b/src/test/ui/async-await/async-fn-nonsend.stderr
index 6e89deb..5c870ca 100644
--- a/src/test/ui/async-await/async-fn-nonsend.stderr
+++ b/src/test/ui/async-await/async-fn-nonsend.stderr
@@ -1,79 +1,88 @@
-error[E0277]: `std::rc::Rc<()>` cannot be sent between threads safely
+error: future cannot be sent between threads safely
--> $DIR/async-fn-nonsend.rs:50:5
|
LL | fn assert_send(_: impl Send) {}
| ----------- ---- required by this bound in `assert_send`
...
LL | assert_send(local_dropped_before_await());
- | ^^^^^^^^^^^ `std::rc::Rc<()>` cannot be sent between threads safely
+ | ^^^^^^^^^^^ future returned by `local_dropped_before_await` is not `Send`
|
= help: within `impl std::future::Future`, the trait `std::marker::Send` is not implemented for `std::rc::Rc<()>`
- = note: required because it appears within the type `impl std::fmt::Debug`
- = note: required because it appears within the type `{impl std::fmt::Debug, impl std::future::Future, impl std::future::Future, ()}`
- = note: required because it appears within the type `[static generator@$DIR/async-fn-nonsend.rs:21:39: 26:2 {impl std::fmt::Debug, impl std::future::Future, impl std::future::Future, ()}]`
- = note: required because it appears within the type `std::future::GenFuture<[static generator@$DIR/async-fn-nonsend.rs:21:39: 26:2 {impl std::fmt::Debug, impl std::future::Future, impl std::future::Future, ()}]>`
- = note: required because it appears within the type `impl std::future::Future`
- = note: required because it appears within the type `impl std::future::Future`
+note: future is not `Send` as this value is used across an await
+ --> $DIR/async-fn-nonsend.rs:25:5
+ |
+LL | let x = non_send();
+ | - has type `impl std::fmt::Debug`
+LL | drop(x);
+LL | fut().await;
+ | ^^^^^^^^^^^ await occurs here, with `x` maybe used later
+LL | }
+ | - `x` is later dropped here
-error[E0277]: `std::rc::Rc<()>` cannot be sent between threads safely
+error: future cannot be sent between threads safely
--> $DIR/async-fn-nonsend.rs:52:5
|
LL | fn assert_send(_: impl Send) {}
| ----------- ---- required by this bound in `assert_send`
...
LL | assert_send(non_send_temporary_in_match());
- | ^^^^^^^^^^^ `std::rc::Rc<()>` cannot be sent between threads safely
+ | ^^^^^^^^^^^ future returned by `non_send_temporary_in_match` is not `Send`
|
= help: within `impl std::future::Future`, the trait `std::marker::Send` is not implemented for `std::rc::Rc<()>`
- = note: required because it appears within the type `impl std::fmt::Debug`
- = note: required because it appears within the type `{impl std::fmt::Debug, std::option::Option<impl std::fmt::Debug>, impl std::future::Future, impl std::future::Future, ()}`
- = note: required because it appears within the type `[static generator@$DIR/async-fn-nonsend.rs:28:40: 37:2 {impl std::fmt::Debug, std::option::Option<impl std::fmt::Debug>, impl std::future::Future, impl std::future::Future, ()}]`
- = note: required because it appears within the type `std::future::GenFuture<[static generator@$DIR/async-fn-nonsend.rs:28:40: 37:2 {impl std::fmt::Debug, std::option::Option<impl std::fmt::Debug>, impl std::future::Future, impl std::future::Future, ()}]>`
- = note: required because it appears within the type `impl std::future::Future`
- = note: required because it appears within the type `impl std::future::Future`
+note: future is not `Send` as this value is used across an await
+ --> $DIR/async-fn-nonsend.rs:34:20
+ |
+LL | match Some(non_send()) {
+ | ---------- has type `impl std::fmt::Debug`
+LL | Some(_) => fut().await,
+ | ^^^^^^^^^^^ await occurs here, with `non_send()` maybe used later
+...
+LL | }
+ | - `non_send()` is later dropped here
-error[E0277]: `dyn std::fmt::Write` cannot be sent between threads safely
+error: future cannot be sent between threads safely
--> $DIR/async-fn-nonsend.rs:54:5
|
LL | fn assert_send(_: impl Send) {}
| ----------- ---- required by this bound in `assert_send`
...
LL | assert_send(non_sync_with_method_call());
- | ^^^^^^^^^^^ `dyn std::fmt::Write` cannot be sent between threads safely
+ | ^^^^^^^^^^^ future returned by `non_sync_with_method_call` is not `Send`
|
= help: the trait `std::marker::Send` is not implemented for `dyn std::fmt::Write`
- = note: required because of the requirements on the impl of `std::marker::Send` for `&mut dyn std::fmt::Write`
- = note: required because it appears within the type `std::fmt::Formatter<'_>`
- = note: required because of the requirements on the impl of `std::marker::Send` for `&mut std::fmt::Formatter<'_>`
- = note: required because it appears within the type `for<'r, 's> {&'r mut std::fmt::Formatter<'s>, bool, bool, impl std::future::Future, impl std::future::Future, ()}`
- = note: required because it appears within the type `[static generator@$DIR/async-fn-nonsend.rs:39:38: 45:2 for<'r, 's> {&'r mut std::fmt::Formatter<'s>, bool, bool, impl std::future::Future, impl std::future::Future, ()}]`
- = note: required because it appears within the type `std::future::GenFuture<[static generator@$DIR/async-fn-nonsend.rs:39:38: 45:2 for<'r, 's> {&'r mut std::fmt::Formatter<'s>, bool, bool, impl std::future::Future, impl std::future::Future, ()}]>`
- = note: required because it appears within the type `impl std::future::Future`
- = note: required because it appears within the type `impl std::future::Future`
+note: future is not `Send` as this value is used across an await
+ --> $DIR/async-fn-nonsend.rs:43:9
+ |
+LL | let f: &mut std::fmt::Formatter = panic!();
+ | - has type `&mut std::fmt::Formatter<'_>`
+LL | if non_sync().fmt(f).unwrap() == () {
+LL | fut().await;
+ | ^^^^^^^^^^^ await occurs here, with `f` maybe used later
+LL | }
+LL | }
+ | - `f` is later dropped here
-error[E0277]: `*mut (dyn std::ops::Fn() + 'static)` cannot be shared between threads safely
+error: future cannot be sent between threads safely
--> $DIR/async-fn-nonsend.rs:54:5
|
LL | fn assert_send(_: impl Send) {}
| ----------- ---- required by this bound in `assert_send`
...
LL | assert_send(non_sync_with_method_call());
- | ^^^^^^^^^^^ `*mut (dyn std::ops::Fn() + 'static)` cannot be shared between threads safely
+ | ^^^^^^^^^^^ future returned by `non_sync_with_method_call` is not `Send`
|
= help: within `std::fmt::ArgumentV1<'_>`, the trait `std::marker::Sync` is not implemented for `*mut (dyn std::ops::Fn() + 'static)`
- = note: required because it appears within the type `std::marker::PhantomData<*mut (dyn std::ops::Fn() + 'static)>`
- = note: required because it appears within the type `core::fmt::Void`
- = note: required because it appears within the type `&core::fmt::Void`
- = note: required because it appears within the type `std::fmt::ArgumentV1<'_>`
- = note: required because of the requirements on the impl of `std::marker::Send` for `std::slice::Iter<'_, std::fmt::ArgumentV1<'_>>`
- = note: required because it appears within the type `std::fmt::Formatter<'_>`
- = note: required because of the requirements on the impl of `std::marker::Send` for `&mut std::fmt::Formatter<'_>`
- = note: required because it appears within the type `for<'r, 's> {&'r mut std::fmt::Formatter<'s>, bool, bool, impl std::future::Future, impl std::future::Future, ()}`
- = note: required because it appears within the type `[static generator@$DIR/async-fn-nonsend.rs:39:38: 45:2 for<'r, 's> {&'r mut std::fmt::Formatter<'s>, bool, bool, impl std::future::Future, impl std::future::Future, ()}]`
- = note: required because it appears within the type `std::future::GenFuture<[static generator@$DIR/async-fn-nonsend.rs:39:38: 45:2 for<'r, 's> {&'r mut std::fmt::Formatter<'s>, bool, bool, impl std::future::Future, impl std::future::Future, ()}]>`
- = note: required because it appears within the type `impl std::future::Future`
- = note: required because it appears within the type `impl std::future::Future`
+note: future is not `Send` as this value is used across an await
+ --> $DIR/async-fn-nonsend.rs:43:9
+ |
+LL | let f: &mut std::fmt::Formatter = panic!();
+ | - has type `&mut std::fmt::Formatter<'_>`
+LL | if non_sync().fmt(f).unwrap() == () {
+LL | fut().await;
+ | ^^^^^^^^^^^ await occurs here, with `f` maybe used later
+LL | }
+LL | }
+ | - `f` is later dropped here
error: aborting due to 4 previous errors
-For more information about this error, try `rustc --explain E0277`.
diff --git a/src/test/ui/async-await/issue-64130-1-sync.rs b/src/test/ui/async-await/issue-64130-1-sync.rs
new file mode 100644
index 0000000..cc5ca89
--- /dev/null
+++ b/src/test/ui/async-await/issue-64130-1-sync.rs
@@ -0,0 +1,23 @@
+#![feature(optin_builtin_traits)]
+// edition:2018
+
+// This tests the the specialized async-await-specific error when futures don't implement an
+// auto trait (which is specifically Sync) due to some type that was captured.
+
+struct Foo;
+
+impl !Sync for Foo {}
+
+fn is_sync<T: Sync>(t: T) { }
+
+async fn bar() {
+ let x = Foo;
+ baz().await;
+}
+
+async fn baz() { }
+
+fn main() {
+ is_sync(bar());
+ //~^ ERROR future cannot be shared between threads safely
+}
diff --git a/src/test/ui/async-await/issue-64130-1-sync.stderr b/src/test/ui/async-await/issue-64130-1-sync.stderr
new file mode 100644
index 0000000..8beb31f
--- /dev/null
+++ b/src/test/ui/async-await/issue-64130-1-sync.stderr
@@ -0,0 +1,22 @@
+error: future cannot be shared between threads safely
+ --> $DIR/issue-64130-1-sync.rs:21:5
+ |
+LL | fn is_sync<T: Sync>(t: T) { }
+ | ------- ---- required by this bound in `is_sync`
+...
+LL | is_sync(bar());
+ | ^^^^^^^ future returned by `bar` is not `Sync`
+ |
+ = help: within `impl std::future::Future`, the trait `std::marker::Sync` is not implemented for `Foo`
+note: future is not `Sync` as this value is used across an await
+ --> $DIR/issue-64130-1-sync.rs:15:5
+ |
+LL | let x = Foo;
+ | - has type `Foo`
+LL | baz().await;
+ | ^^^^^^^^^^^ await occurs here, with `x` maybe used later
+LL | }
+ | - `x` is later dropped here
+
+error: aborting due to previous error
+
diff --git a/src/test/ui/async-await/issue-64130-2-send.rs b/src/test/ui/async-await/issue-64130-2-send.rs
new file mode 100644
index 0000000..1efe2ab
--- /dev/null
+++ b/src/test/ui/async-await/issue-64130-2-send.rs
@@ -0,0 +1,23 @@
+#![feature(optin_builtin_traits)]
+// edition:2018
+
+// This tests the the specialized async-await-specific error when futures don't implement an
+// auto trait (which is specifically Send) due to some type that was captured.
+
+struct Foo;
+
+impl !Send for Foo {}
+
+fn is_send<T: Send>(t: T) { }
+
+async fn bar() {
+ let x = Foo;
+ baz().await;
+}
+
+async fn baz() { }
+
+fn main() {
+ is_send(bar());
+ //~^ ERROR future cannot be sent between threads safely
+}
diff --git a/src/test/ui/async-await/issue-64130-2-send.stderr b/src/test/ui/async-await/issue-64130-2-send.stderr
new file mode 100644
index 0000000..823b88e
--- /dev/null
+++ b/src/test/ui/async-await/issue-64130-2-send.stderr
@@ -0,0 +1,22 @@
+error: future cannot be sent between threads safely
+ --> $DIR/issue-64130-2-send.rs:21:5
+ |
+LL | fn is_send<T: Send>(t: T) { }
+ | ------- ---- required by this bound in `is_send`
+...
+LL | is_send(bar());
+ | ^^^^^^^ future returned by `bar` is not `Send`
+ |
+ = help: within `impl std::future::Future`, the trait `std::marker::Send` is not implemented for `Foo`
+note: future is not `Send` as this value is used across an await
+ --> $DIR/issue-64130-2-send.rs:15:5
+ |
+LL | let x = Foo;
+ | - has type `Foo`
+LL | baz().await;
+ | ^^^^^^^^^^^ await occurs here, with `x` maybe used later
+LL | }
+ | - `x` is later dropped here
+
+error: aborting due to previous error
+
diff --git a/src/test/ui/async-await/issue-64130-3-other.rs b/src/test/ui/async-await/issue-64130-3-other.rs
new file mode 100644
index 0000000..901544e
--- /dev/null
+++ b/src/test/ui/async-await/issue-64130-3-other.rs
@@ -0,0 +1,25 @@
+#![feature(optin_builtin_traits)]
+// edition:2018
+
+// This tests the the unspecialized async-await-specific error when futures don't implement an
+// auto trait (which is not Send or Sync) due to some type that was captured.
+
+auto trait Qux { }
+
+struct Foo;
+
+impl !Qux for Foo {}
+
+fn is_qux<T: Qux>(t: T) { }
+
+async fn bar() {
+ let x = Foo;
+ baz().await;
+}
+
+async fn baz() { }
+
+fn main() {
+ is_qux(bar());
+ //~^ ERROR the trait bound `Foo: Qux` is not satisfied in `impl std::future::Future`
+}
diff --git a/src/test/ui/async-await/issue-64130-3-other.stderr b/src/test/ui/async-await/issue-64130-3-other.stderr
new file mode 100644
index 0000000..155c5cc
--- /dev/null
+++ b/src/test/ui/async-await/issue-64130-3-other.stderr
@@ -0,0 +1,24 @@
+error[E0277]: the trait bound `Foo: Qux` is not satisfied in `impl std::future::Future`
+ --> $DIR/issue-64130-3-other.rs:23:5
+ |
+LL | fn is_qux<T: Qux>(t: T) { }
+ | ------ --- required by this bound in `is_qux`
+...
+LL | is_qux(bar());
+ | ^^^^^^ within `impl std::future::Future`, the trait `Qux` is not implemented for `Foo`
+ |
+ = help: the following implementations were found:
+ <Foo as Qux>
+note: future does not implement `Qux` as this value is used across an await
+ --> $DIR/issue-64130-3-other.rs:17:5
+ |
+LL | let x = Foo;
+ | - has type `Foo`
+LL | baz().await;
+ | ^^^^^^^^^^^ await occurs here, with `x` maybe used later
+LL | }
+ | - `x` is later dropped here
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0277`.
diff --git a/src/test/ui/async-await/issue-64130-4-async-move.rs b/src/test/ui/async-await/issue-64130-4-async-move.rs
new file mode 100644
index 0000000..2538f34
--- /dev/null
+++ b/src/test/ui/async-await/issue-64130-4-async-move.rs
@@ -0,0 +1,28 @@
+// edition:2018
+use std::any::Any;
+use std::future::Future;
+
+struct Client(Box<dyn Any + Send>);
+
+impl Client {
+ fn status(&self) -> u16 {
+ 200
+ }
+}
+
+async fn get() { }
+
+pub fn foo() -> impl Future + Send {
+ //~^ ERROR future cannot be sent between threads safely
+ let client = Client(Box::new(true));
+ async move {
+ match client.status() {
+ 200 => {
+ let _x = get().await;
+ },
+ _ => (),
+ }
+ }
+}
+
+fn main() {}
diff --git a/src/test/ui/async-await/issue-64130-4-async-move.stderr b/src/test/ui/async-await/issue-64130-4-async-move.stderr
new file mode 100644
index 0000000..ddbb469
--- /dev/null
+++ b/src/test/ui/async-await/issue-64130-4-async-move.stderr
@@ -0,0 +1,22 @@
+error: future cannot be sent between threads safely
+ --> $DIR/issue-64130-4-async-move.rs:15:17
+ |
+LL | pub fn foo() -> impl Future + Send {
+ | ^^^^^^^^^^^^^^^^^^ future returned by `foo` is not `Send`
+ |
+ = help: the trait `std::marker::Sync` is not implemented for `(dyn std::any::Any + std::marker::Send + 'static)`
+note: future is not `Send` as this value is used across an await
+ --> $DIR/issue-64130-4-async-move.rs:21:26
+ |
+LL | match client.status() {
+ | ------ has type `&Client`
+LL | 200 => {
+LL | let _x = get().await;
+ | ^^^^^^^^^^^ await occurs here, with `client` maybe used later
+...
+LL | }
+ | - `client` is later dropped here
+ = note: the return type of a function must have a statically known size
+
+error: aborting due to previous error
+
diff --git a/src/test/ui/async-await/issue-64130-non-send-future-diags.rs b/src/test/ui/async-await/issue-64130-non-send-future-diags.rs
index 1936d1a..656ade6 100644
--- a/src/test/ui/async-await/issue-64130-non-send-future-diags.rs
+++ b/src/test/ui/async-await/issue-64130-non-send-future-diags.rs
@@ -1,10 +1,10 @@
// edition:2018
+// This tests the basic example case for the async-await-specific error.
+
use std::sync::Mutex;
-fn is_send<T: Send>(t: T) {
-
-}
+fn is_send<T: Send>(t: T) { }
async fn foo() {
bar(&Mutex::new(22)).await;
@@ -15,11 +15,9 @@
baz().await;
}
-async fn baz() {
-
-}
+async fn baz() { }
fn main() {
is_send(foo());
- //~^ ERROR `std::sync::MutexGuard<'_, u32>` cannot be sent between threads safely [E0277]
+ //~^ ERROR future cannot be sent between threads safely
}
diff --git a/src/test/ui/async-await/issue-64130-non-send-future-diags.stderr b/src/test/ui/async-await/issue-64130-non-send-future-diags.stderr
index 9e9fc52..662407f 100644
--- a/src/test/ui/async-await/issue-64130-non-send-future-diags.stderr
+++ b/src/test/ui/async-await/issue-64130-non-send-future-diags.stderr
@@ -1,14 +1,14 @@
-error[E0277]: `std::sync::MutexGuard<'_, u32>` cannot be sent between threads safely
- --> $DIR/issue-64130-non-send-future-diags.rs:23:5
+error: future cannot be sent between threads safely
+ --> $DIR/issue-64130-non-send-future-diags.rs:21:5
|
-LL | fn is_send<T: Send>(t: T) {
+LL | fn is_send<T: Send>(t: T) { }
| ------- ---- required by this bound in `is_send`
...
LL | is_send(foo());
- | ^^^^^^^ `std::sync::MutexGuard<'_, u32>` cannot be sent between threads safely
+ | ^^^^^^^ future returned by `foo` is not `Send`
|
= help: within `impl std::future::Future`, the trait `std::marker::Send` is not implemented for `std::sync::MutexGuard<'_, u32>`
-note: future does not implement `std::marker::Send` as this value is used across an await
+note: future is not `Send` as this value is used across an await
--> $DIR/issue-64130-non-send-future-diags.rs:15:5
|
LL | let g = x.lock().unwrap();
@@ -20,4 +20,3 @@
error: aborting due to previous error
-For more information about this error, try `rustc --explain E0277`.
diff --git a/src/test/ui/async-await/issues/issue-66958-non-copy-infered-type-arg.rs b/src/test/ui/async-await/issues/issue-66958-non-copy-infered-type-arg.rs
new file mode 100644
index 0000000..c8c2702
--- /dev/null
+++ b/src/test/ui/async-await/issues/issue-66958-non-copy-infered-type-arg.rs
@@ -0,0 +1,15 @@
+// edition:2018
+
+struct Ia<S>(S);
+
+impl<S> Ia<S> {
+ fn partial(_: S) {}
+ fn full(self) {}
+
+ async fn crash(self) {
+ Self::partial(self.0);
+ Self::full(self); //~ ERROR use of moved value: `self`
+ }
+}
+
+fn main() {}
diff --git a/src/test/ui/async-await/issues/issue-66958-non-copy-infered-type-arg.stderr b/src/test/ui/async-await/issues/issue-66958-non-copy-infered-type-arg.stderr
new file mode 100644
index 0000000..9177b83
--- /dev/null
+++ b/src/test/ui/async-await/issues/issue-66958-non-copy-infered-type-arg.stderr
@@ -0,0 +1,13 @@
+error[E0382]: use of moved value: `self`
+ --> $DIR/issue-66958-non-copy-infered-type-arg.rs:11:20
+ |
+LL | Self::partial(self.0);
+ | ------ value moved here
+LL | Self::full(self);
+ | ^^^^ value used here after partial move
+ |
+ = note: move occurs because `self.0` has type `S`, which does not implement the `Copy` trait
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0382`.
diff --git a/src/test/ui/async-await/suggest-missing-await.fixed b/src/test/ui/async-await/suggest-missing-await.fixed
index 7c02a90..1ec59d9 100644
--- a/src/test/ui/async-await/suggest-missing-await.fixed
+++ b/src/test/ui/async-await/suggest-missing-await.fixed
@@ -16,4 +16,15 @@
//~| SUGGESTION x.await
}
+async fn dummy() {}
+
+#[allow(unused)]
+async fn suggest_await_in_async_fn_return() {
+ dummy().await;
+ //~^ ERROR mismatched types [E0308]
+ //~| HELP try adding a semicolon
+ //~| HELP consider using `.await` here
+ //~| SUGGESTION dummy().await
+}
+
fn main() {}
diff --git a/src/test/ui/async-await/suggest-missing-await.rs b/src/test/ui/async-await/suggest-missing-await.rs
index 91abd44..70cc1f1 100644
--- a/src/test/ui/async-await/suggest-missing-await.rs
+++ b/src/test/ui/async-await/suggest-missing-await.rs
@@ -16,4 +16,15 @@
//~| SUGGESTION x.await
}
+async fn dummy() {}
+
+#[allow(unused)]
+async fn suggest_await_in_async_fn_return() {
+ dummy()
+ //~^ ERROR mismatched types [E0308]
+ //~| HELP try adding a semicolon
+ //~| HELP consider using `.await` here
+ //~| SUGGESTION dummy().await
+}
+
fn main() {}
diff --git a/src/test/ui/async-await/suggest-missing-await.stderr b/src/test/ui/async-await/suggest-missing-await.stderr
index 7a635a3..7ab0244 100644
--- a/src/test/ui/async-await/suggest-missing-await.stderr
+++ b/src/test/ui/async-await/suggest-missing-await.stderr
@@ -10,6 +10,23 @@
= note: expected type `u32`
found opaque type `impl std::future::Future`
-error: aborting due to previous error
+error[E0308]: mismatched types
+ --> $DIR/suggest-missing-await.rs:23:5
+ |
+LL | dummy()
+ | ^^^^^^^ expected `()`, found opaque type
+ |
+ = note: expected unit type `()`
+ found opaque type `impl std::future::Future`
+help: try adding a semicolon
+ |
+LL | dummy();
+ | ^
+help: consider using `.await` here
+ |
+LL | dummy().await
+ |
+
+error: aborting due to 2 previous errors
For more information about this error, try `rustc --explain E0308`.
diff --git a/src/test/ui/async-await/unresolved_type_param.rs b/src/test/ui/async-await/unresolved_type_param.rs
index 2876f9f..79c043b 100644
--- a/src/test/ui/async-await/unresolved_type_param.rs
+++ b/src/test/ui/async-await/unresolved_type_param.rs
@@ -8,7 +8,7 @@
async fn foo() {
bar().await;
//~^ ERROR type inside `async fn` body must be known in this context
- //~| NOTE cannot infer type for `T`
+ //~| NOTE cannot infer type for type parameter `T`
//~| NOTE the type is part of the `async fn` body because of this `await`
//~| NOTE in this expansion of desugaring of `await`
}
diff --git a/src/test/ui/async-await/unresolved_type_param.stderr b/src/test/ui/async-await/unresolved_type_param.stderr
index c7866fc..b9b4f51 100644
--- a/src/test/ui/async-await/unresolved_type_param.stderr
+++ b/src/test/ui/async-await/unresolved_type_param.stderr
@@ -2,7 +2,7 @@
--> $DIR/unresolved_type_param.rs:9:5
|
LL | bar().await;
- | ^^^ cannot infer type for `T`
+ | ^^^ cannot infer type for type parameter `T`
|
note: the type is part of the `async fn` body because of this `await`
--> $DIR/unresolved_type_param.rs:9:5
diff --git a/src/test/ui/attributes/field-attributes-vis-unresolved.rs b/src/test/ui/attributes/field-attributes-vis-unresolved.rs
new file mode 100644
index 0000000..d1bd2a1
--- /dev/null
+++ b/src/test/ui/attributes/field-attributes-vis-unresolved.rs
@@ -0,0 +1,25 @@
+// Non-builtin attributes do not mess with field visibility resolution (issue #67006).
+
+mod internal {
+ struct S {
+ #[rustfmt::skip]
+ pub(in crate::internal) field: u8 // OK
+ }
+
+ struct Z(
+ #[rustfmt::skip]
+ pub(in crate::internal) u8 // OK
+ );
+}
+
+struct S {
+ #[rustfmt::skip]
+ pub(in nonexistent) field: u8 //~ ERROR failed to resolve
+}
+
+struct Z(
+ #[rustfmt::skip]
+ pub(in nonexistent) u8 //~ ERROR failed to resolve
+);
+
+fn main() {}
diff --git a/src/test/ui/attributes/field-attributes-vis-unresolved.stderr b/src/test/ui/attributes/field-attributes-vis-unresolved.stderr
new file mode 100644
index 0000000..41c3cea
--- /dev/null
+++ b/src/test/ui/attributes/field-attributes-vis-unresolved.stderr
@@ -0,0 +1,15 @@
+error[E0433]: failed to resolve: maybe a missing crate `nonexistent`?
+ --> $DIR/field-attributes-vis-unresolved.rs:17:12
+ |
+LL | pub(in nonexistent) field: u8
+ | ^^^^^^^^^^^ maybe a missing crate `nonexistent`?
+
+error[E0433]: failed to resolve: maybe a missing crate `nonexistent`?
+ --> $DIR/field-attributes-vis-unresolved.rs:22:12
+ |
+LL | pub(in nonexistent) u8
+ | ^^^^^^^^^^^ maybe a missing crate `nonexistent`?
+
+error: aborting due to 2 previous errors
+
+For more information about this error, try `rustc --explain E0433`.
diff --git a/src/test/ui/borrowck/borrowck-move-out-from-array-no-overlap.rs b/src/test/ui/borrowck/borrowck-move-out-from-array-no-overlap.rs
new file mode 100644
index 0000000..8f274cf
--- /dev/null
+++ b/src/test/ui/borrowck/borrowck-move-out-from-array-no-overlap.rs
@@ -0,0 +1,69 @@
+// check-pass
+
+#![feature(slice_patterns)]
+
+fn array() -> [(String, String); 3] {
+ Default::default()
+}
+
+// Const Index + Const Index
+
+fn move_out_from_begin_and_one_from_end() {
+ let a = array();
+ let [_, _, _x] = a;
+ let [.., _y, _] = a;
+}
+
+fn move_out_from_begin_field_and_end_field() {
+ let a = array();
+ let [_, _, (_x, _)] = a;
+ let [.., (_, _y)] = a;
+}
+
+// Const Index + Slice
+
+fn move_out_by_const_index_and_subslice() {
+ let a = array();
+ let [_x, _, _] = a;
+ let [_, _y @ ..] = a;
+}
+
+fn move_out_by_const_index_end_and_subslice() {
+ let a = array();
+ let [.., _x] = a;
+ let [_y @ .., _] = a;
+}
+
+fn move_out_by_const_index_field_and_subslice() {
+ let a = array();
+ let [(_x, _), _, _] = a;
+ let [_, _y @ ..] = a;
+}
+
+fn move_out_by_const_index_end_field_and_subslice() {
+ let a = array();
+ let [.., (_x, _)] = a;
+ let [_y @ .., _] = a;
+}
+
+fn move_out_by_const_subslice_and_index_field() {
+ let a = array();
+ let [_, _y @ ..] = a;
+ let [(_x, _), _, _] = a;
+}
+
+fn move_out_by_const_subslice_and_end_index_field() {
+ let a = array();
+ let [_y @ .., _] = a;
+ let [.., (_x, _)] = a;
+}
+
+// Slice + Slice
+
+fn move_out_by_subslice_and_subslice() {
+ let a = array();
+ let [x @ .., _, _] = a;
+ let [_, _y @ ..] = a;
+}
+
+fn main() {}
diff --git a/src/test/ui/borrowck/borrowck-move-out-from-array-use-no-overlap.rs b/src/test/ui/borrowck/borrowck-move-out-from-array-use-no-overlap.rs
new file mode 100644
index 0000000..57ce241
--- /dev/null
+++ b/src/test/ui/borrowck/borrowck-move-out-from-array-use-no-overlap.rs
@@ -0,0 +1,69 @@
+// check-pass
+
+#![feature(slice_patterns)]
+
+fn array() -> [(String, String); 3] {
+ Default::default()
+}
+
+// Const Index + Const Index
+
+fn move_out_from_begin_and_one_from_end() {
+ let a = array();
+ let [_, _, _x] = a;
+ let [.., ref _y, _] = a;
+}
+
+fn move_out_from_begin_field_and_end_field() {
+ let a = array();
+ let [_, _, (_x, _)] = a;
+ let [.., (_, ref _y)] = a;
+}
+
+// Const Index + Slice
+
+fn move_out_by_const_index_and_subslice() {
+ let a = array();
+ let [_x, _, _] = a;
+ let [_, ref _y @ ..] = a;
+}
+
+fn move_out_by_const_index_end_and_subslice() {
+ let a = array();
+ let [.., _x] = a;
+ let [ref _y @ .., _] = a;
+}
+
+fn move_out_by_const_index_field_and_subslice() {
+ let a = array();
+ let [(_x, _), _, _] = a;
+ let [_, ref _y @ ..] = a;
+}
+
+fn move_out_by_const_index_end_field_and_subslice() {
+ let a = array();
+ let [.., (_x, _)] = a;
+ let [ref _y @ .., _] = a;
+}
+
+fn move_out_by_const_subslice_and_index_field() {
+ let a = array();
+ let [_, _y @ ..] = a;
+ let [(ref _x, _), _, _] = a;
+}
+
+fn move_out_by_const_subslice_and_end_index_field() {
+ let a = array();
+ let [_y @ .., _] = a;
+ let [.., (ref _x, _)] = a;
+}
+
+// Slice + Slice
+
+fn move_out_by_subslice_and_subslice() {
+ let a = array();
+ let [x @ .., _, _] = a;
+ let [_, ref _y @ ..] = a;
+}
+
+fn main() {}
diff --git a/src/test/ui/borrowck/borrowck-move-out-from-array-use.rs b/src/test/ui/borrowck/borrowck-move-out-from-array-use.rs
new file mode 100644
index 0000000..778beef
--- /dev/null
+++ b/src/test/ui/borrowck/borrowck-move-out-from-array-use.rs
@@ -0,0 +1,99 @@
+#![feature(slice_patterns)]
+
+fn array() -> [(String, String); 3] {
+ Default::default()
+}
+
+// Const Index + Const Index
+
+fn move_out_from_begin_and_end() {
+ let a = array();
+ let [_, _, _x] = a;
+ let [.., ref _y] = a; //~ ERROR [E0382]
+}
+
+fn move_out_from_begin_field_and_end() {
+ let a = array();
+ let [_, _, (_x, _)] = a;
+ let [.., ref _y] = a; //~ ERROR [E0382]
+}
+
+fn move_out_from_begin_field_and_end_field() {
+ let a = array();
+ let [_, _, (_x, _)] = a;
+ let [.., (ref _y, _)] = a; //~ ERROR [E0382]
+}
+
+// Const Index + Slice
+
+fn move_out_by_const_index_and_subslice() {
+ let a = array();
+ let [_x, _, _] = a;
+ let [ref _y @ .., _, _] = a; //~ ERROR [E0382]
+}
+
+fn move_out_by_const_index_end_and_subslice() {
+ let a = array();
+ let [.., _x] = a;
+ let [_, _, ref _y @ ..] = a; //~ ERROR [E0382]
+}
+
+fn move_out_by_const_index_field_and_subslice() {
+ let a = array();
+ let [(_x, _), _, _] = a;
+ let [ref _y @ .., _, _] = a; //~ ERROR [E0382]
+}
+
+fn move_out_by_const_index_end_field_and_subslice() {
+ let a = array();
+ let [.., (_x, _)] = a;
+ let [_, _, ref _y @ ..] = a; //~ ERROR [E0382]
+}
+
+fn move_out_by_subslice_and_const_index_field() {
+ let a = array();
+ let [_y @ .., _, _] = a;
+ let [(ref _x, _), _, _] = a; //~ ERROR [E0382]
+}
+
+fn move_out_by_subslice_and_const_index_end_field() {
+ let a = array();
+ let [_, _, _y @ ..] = a;
+ let [.., (ref _x, _)] = a; //~ ERROR [E0382]
+}
+
+// Slice + Slice
+
+fn move_out_by_subslice_and_subslice() {
+ let a = array();
+ let [x @ .., _] = a;
+ let [_, ref _y @ ..] = a; //~ ERROR [E0382]
+}
+
+// Move + Assign
+
+fn move_out_and_assign_end() {
+ let mut a = array();
+ let [_, _, _x] = a;
+ a[2] = Default::default(); //~ ERROR [E0382]
+}
+
+fn move_out_and_assign_end_field() {
+ let mut a = array();
+ let [_, _, (_x, _)] = a;
+ a[2].1 = Default::default(); //~ ERROR [E0382]
+}
+
+fn move_out_slice_and_assign_end() {
+ let mut a = array();
+ let [_, _, _x @ ..] = a;
+ a[0] = Default::default(); //~ ERROR [E0382]
+}
+
+fn move_out_slice_and_assign_end_field() {
+ let mut a = array();
+ let [_, _, _x @ ..] = a;
+ a[0].1 = Default::default(); //~ ERROR [E0382]
+}
+
+fn main() {}
diff --git a/src/test/ui/borrowck/borrowck-move-out-from-array-use.stderr b/src/test/ui/borrowck/borrowck-move-out-from-array-use.stderr
new file mode 100644
index 0000000..2a7b891
--- /dev/null
+++ b/src/test/ui/borrowck/borrowck-move-out-from-array-use.stderr
@@ -0,0 +1,143 @@
+error[E0382]: borrow of moved value: `a[..]`
+ --> $DIR/borrowck-move-out-from-array-use.rs:12:14
+ |
+LL | let [_, _, _x] = a;
+ | -- value moved here
+LL | let [.., ref _y] = a;
+ | ^^^^^^ value borrowed here after move
+ |
+ = note: move occurs because `a[..]` has type `(std::string::String, std::string::String)`, which does not implement the `Copy` trait
+
+error[E0382]: borrow of moved value: `a[..]`
+ --> $DIR/borrowck-move-out-from-array-use.rs:18:14
+ |
+LL | let [_, _, (_x, _)] = a;
+ | -- value moved here
+LL | let [.., ref _y] = a;
+ | ^^^^^^ value borrowed here after partial move
+ |
+ = note: move occurs because `a[..].0` has type `std::string::String`, which does not implement the `Copy` trait
+
+error[E0382]: borrow of moved value: `a[..].0`
+ --> $DIR/borrowck-move-out-from-array-use.rs:24:15
+ |
+LL | let [_, _, (_x, _)] = a;
+ | -- value moved here
+LL | let [.., (ref _y, _)] = a;
+ | ^^^^^^ value borrowed here after move
+ |
+ = note: move occurs because `a[..].0` has type `std::string::String`, which does not implement the `Copy` trait
+
+error[E0382]: borrow of moved value: `a`
+ --> $DIR/borrowck-move-out-from-array-use.rs:32:10
+ |
+LL | let [_x, _, _] = a;
+ | -- value moved here
+LL | let [ref _y @ .., _, _] = a;
+ | ^^^^^^^^^^^ value borrowed here after partial move
+ |
+ = note: move occurs because `a[..]` has type `(std::string::String, std::string::String)`, which does not implement the `Copy` trait
+
+error[E0382]: borrow of moved value: `a`
+ --> $DIR/borrowck-move-out-from-array-use.rs:38:16
+ |
+LL | let [.., _x] = a;
+ | -- value moved here
+LL | let [_, _, ref _y @ ..] = a;
+ | ^^^^^^^^^^^ value borrowed here after partial move
+ |
+ = note: move occurs because `a[..]` has type `(std::string::String, std::string::String)`, which does not implement the `Copy` trait
+
+error[E0382]: borrow of moved value: `a`
+ --> $DIR/borrowck-move-out-from-array-use.rs:44:10
+ |
+LL | let [(_x, _), _, _] = a;
+ | -- value moved here
+LL | let [ref _y @ .., _, _] = a;
+ | ^^^^^^^^^^^ value borrowed here after partial move
+ |
+ = note: move occurs because `a[..].0` has type `std::string::String`, which does not implement the `Copy` trait
+
+error[E0382]: borrow of moved value: `a`
+ --> $DIR/borrowck-move-out-from-array-use.rs:50:16
+ |
+LL | let [.., (_x, _)] = a;
+ | -- value moved here
+LL | let [_, _, ref _y @ ..] = a;
+ | ^^^^^^^^^^^ value borrowed here after partial move
+ |
+ = note: move occurs because `a[..].0` has type `std::string::String`, which does not implement the `Copy` trait
+
+error[E0382]: borrow of moved value: `a[..]`
+ --> $DIR/borrowck-move-out-from-array-use.rs:56:11
+ |
+LL | let [_y @ .., _, _] = a;
+ | ------- value moved here
+LL | let [(ref _x, _), _, _] = a;
+ | ^^^^^^ value borrowed here after move
+ |
+ = note: move occurs because `a[..]` has type `(std::string::String, std::string::String)`, which does not implement the `Copy` trait
+
+error[E0382]: borrow of moved value: `a[..]`
+ --> $DIR/borrowck-move-out-from-array-use.rs:62:15
+ |
+LL | let [_, _, _y @ ..] = a;
+ | ------- value moved here
+LL | let [.., (ref _x, _)] = a;
+ | ^^^^^^ value borrowed here after move
+ |
+ = note: move occurs because `a[..]` has type `(std::string::String, std::string::String)`, which does not implement the `Copy` trait
+
+error[E0382]: borrow of moved value: `a`
+ --> $DIR/borrowck-move-out-from-array-use.rs:70:13
+ |
+LL | let [x @ .., _] = a;
+ | ------ value moved here
+LL | let [_, ref _y @ ..] = a;
+ | ^^^^^^^^^^^ value borrowed here after partial move
+ |
+ = note: move occurs because `a[..]` has type `(std::string::String, std::string::String)`, which does not implement the `Copy` trait
+
+error[E0382]: use of moved value: `a`
+ --> $DIR/borrowck-move-out-from-array-use.rs:78:5
+ |
+LL | let [_, _, _x] = a;
+ | -- value moved here
+LL | a[2] = Default::default();
+ | ^^^^ value used here after partial move
+ |
+ = note: move occurs because `a[..]` has type `(std::string::String, std::string::String)`, which does not implement the `Copy` trait
+
+error[E0382]: use of moved value: `a`
+ --> $DIR/borrowck-move-out-from-array-use.rs:84:5
+ |
+LL | let [_, _, (_x, _)] = a;
+ | -- value moved here
+LL | a[2].1 = Default::default();
+ | ^^^^ value used here after partial move
+ |
+ = note: move occurs because `a[..].0` has type `std::string::String`, which does not implement the `Copy` trait
+
+error[E0382]: use of moved value: `a`
+ --> $DIR/borrowck-move-out-from-array-use.rs:90:5
+ |
+LL | let [_, _, _x @ ..] = a;
+ | ------- value moved here
+LL | a[0] = Default::default();
+ | ^^^^ value used here after partial move
+ |
+ = note: move occurs because `a[..]` has type `(std::string::String, std::string::String)`, which does not implement the `Copy` trait
+
+error[E0382]: use of moved value: `a`
+ --> $DIR/borrowck-move-out-from-array-use.rs:96:5
+ |
+LL | let [_, _, _x @ ..] = a;
+ | ------- value moved here
+LL | a[0].1 = Default::default();
+ | ^^^^ value used here after partial move
+ |
+ = note: move occurs because `a[..]` has type `(std::string::String, std::string::String)`, which does not implement the `Copy` trait
+
+error: aborting due to 14 previous errors
+
+For more information about this error, try `rustc --explain E0382`.
diff --git a/src/test/ui/borrowck/borrowck-move-out-from-array.rs b/src/test/ui/borrowck/borrowck-move-out-from-array.rs
index ee6abf4..f9d3f6f 100644
--- a/src/test/ui/borrowck/borrowck-move-out-from-array.rs
+++ b/src/test/ui/borrowck/borrowck-move-out-from-array.rs
@@ -1,16 +1,73 @@
-#![feature(box_syntax)]
#![feature(slice_patterns)]
+fn array() -> [(String, String); 3] {
+ Default::default()
+}
+
+// Const Index + Const Index
+
fn move_out_from_begin_and_end() {
- let a = [box 1, box 2];
- let [_, _x] = a;
+ let a = array();
+ let [_, _, _x] = a;
let [.., _y] = a; //~ ERROR [E0382]
}
+fn move_out_from_begin_field_and_end() {
+ let a = array();
+ let [_, _, (_x, _)] = a;
+ let [.., _y] = a; //~ ERROR [E0382]
+}
+
+fn move_out_from_begin_field_and_end_field() {
+ let a = array();
+ let [_, _, (_x, _)] = a;
+ let [.., (_y, _)] = a; //~ ERROR [E0382]
+}
+
+// Const Index + Slice
+
fn move_out_by_const_index_and_subslice() {
- let a = [box 1, box 2];
- let [_x, _] = a;
- let [_y @ ..] = a; //~ ERROR [E0382]
+ let a = array();
+ let [_x, _, _] = a;
+ let [_y @ .., _, _] = a; //~ ERROR [E0382]
+}
+
+fn move_out_by_const_index_end_and_subslice() {
+ let a = array();
+ let [.., _x] = a;
+ let [_, _, _y @ ..] = a; //~ ERROR [E0382]
+}
+
+fn move_out_by_const_index_field_and_subslice() {
+ let a = array();
+ let [(_x, _), _, _] = a;
+ let [_y @ .., _, _] = a; //~ ERROR [E0382]
+}
+
+fn move_out_by_const_index_end_field_and_subslice() {
+ let a = array();
+ let [.., (_x, _)] = a;
+ let [_, _, _y @ ..] = a; //~ ERROR [E0382]
+}
+
+fn move_out_by_subslice_and_const_index_field() {
+ let a = array();
+ let [_y @ .., _, _] = a;
+ let [(_x, _), _, _] = a; //~ ERROR [E0382]
+}
+
+fn move_out_by_subslice_and_const_index_end_field() {
+ let a = array();
+ let [_, _, _y @ ..] = a;
+ let [.., (_x, _)] = a; //~ ERROR [E0382]
+}
+
+// Slice + Slice
+
+fn move_out_by_subslice_and_subslice() {
+ let a = array();
+ let [x @ .., _] = a;
+ let [_, _y @ ..] = a; //~ ERROR [E0382]
}
fn main() {}
diff --git a/src/test/ui/borrowck/borrowck-move-out-from-array.stderr b/src/test/ui/borrowck/borrowck-move-out-from-array.stderr
index b34c03e..08134a2 100644
--- a/src/test/ui/borrowck/borrowck-move-out-from-array.stderr
+++ b/src/test/ui/borrowck/borrowck-move-out-from-array.stderr
@@ -1,23 +1,103 @@
error[E0382]: use of moved value: `a[..]`
- --> $DIR/borrowck-move-out-from-array.rs:7:14
+ --> $DIR/borrowck-move-out-from-array.rs:12:14
|
-LL | let [_, _x] = a;
- | -- value moved here
+LL | let [_, _, _x] = a;
+ | -- value moved here
LL | let [.., _y] = a;
| ^^ value used here after move
|
- = note: move occurs because `a[..]` has type `std::boxed::Box<i32>`, which does not implement the `Copy` trait
+ = note: move occurs because `a[..]` has type `(std::string::String, std::string::String)`, which does not implement the `Copy` trait
error[E0382]: use of moved value: `a[..]`
- --> $DIR/borrowck-move-out-from-array.rs:13:10
+ --> $DIR/borrowck-move-out-from-array.rs:18:14
|
-LL | let [_x, _] = a;
- | -- value moved here
-LL | let [_y @ ..] = a;
- | ^^^^^^^ value used here after move
+LL | let [_, _, (_x, _)] = a;
+ | -- value moved here
+LL | let [.., _y] = a;
+ | ^^ value used here after partial move
|
- = note: move occurs because `a[..]` has type `std::boxed::Box<i32>`, which does not implement the `Copy` trait
+ = note: move occurs because `a[..].0` has type `std::string::String`, which does not implement the `Copy` trait
-error: aborting due to 2 previous errors
+error[E0382]: use of moved value: `a[..].0`
+ --> $DIR/borrowck-move-out-from-array.rs:24:15
+ |
+LL | let [_, _, (_x, _)] = a;
+ | -- value moved here
+LL | let [.., (_y, _)] = a;
+ | ^^ value used here after move
+ |
+ = note: move occurs because `a[..].0` has type `std::string::String`, which does not implement the `Copy` trait
+
+error[E0382]: use of moved value: `a`
+ --> $DIR/borrowck-move-out-from-array.rs:32:10
+ |
+LL | let [_x, _, _] = a;
+ | -- value moved here
+LL | let [_y @ .., _, _] = a;
+ | ^^^^^^^ value used here after partial move
+ |
+ = note: move occurs because `a[..]` has type `(std::string::String, std::string::String)`, which does not implement the `Copy` trait
+
+error[E0382]: use of moved value: `a`
+ --> $DIR/borrowck-move-out-from-array.rs:38:16
+ |
+LL | let [.., _x] = a;
+ | -- value moved here
+LL | let [_, _, _y @ ..] = a;
+ | ^^^^^^^ value used here after partial move
+ |
+ = note: move occurs because `a[..]` has type `(std::string::String, std::string::String)`, which does not implement the `Copy` trait
+
+error[E0382]: use of moved value: `a`
+ --> $DIR/borrowck-move-out-from-array.rs:44:10
+ |
+LL | let [(_x, _), _, _] = a;
+ | -- value moved here
+LL | let [_y @ .., _, _] = a;
+ | ^^^^^^^ value used here after partial move
+ |
+ = note: move occurs because `a[..].0` has type `std::string::String`, which does not implement the `Copy` trait
+
+error[E0382]: use of moved value: `a`
+ --> $DIR/borrowck-move-out-from-array.rs:50:16
+ |
+LL | let [.., (_x, _)] = a;
+ | -- value moved here
+LL | let [_, _, _y @ ..] = a;
+ | ^^^^^^^ value used here after partial move
+ |
+ = note: move occurs because `a[..].0` has type `std::string::String`, which does not implement the `Copy` trait
+
+error[E0382]: use of moved value: `a[..].0`
+ --> $DIR/borrowck-move-out-from-array.rs:56:11
+ |
+LL | let [_y @ .., _, _] = a;
+ | ------- value moved here
+LL | let [(_x, _), _, _] = a;
+ | ^^ value used here after move
+ |
+ = note: move occurs because `a[..]` has type `(std::string::String, std::string::String)`, which does not implement the `Copy` trait
+
+error[E0382]: use of moved value: `a[..].0`
+ --> $DIR/borrowck-move-out-from-array.rs:62:15
+ |
+LL | let [_, _, _y @ ..] = a;
+ | ------- value moved here
+LL | let [.., (_x, _)] = a;
+ | ^^ value used here after move
+ |
+ = note: move occurs because `a[..]` has type `(std::string::String, std::string::String)`, which does not implement the `Copy` trait
+
+error[E0382]: use of moved value: `a`
+ --> $DIR/borrowck-move-out-from-array.rs:70:13
+ |
+LL | let [x @ .., _] = a;
+ | ------ value moved here
+LL | let [_, _y @ ..] = a;
+ | ^^^^^^^ value used here after partial move
+ |
+ = note: move occurs because `a[..]` has type `(std::string::String, std::string::String)`, which does not implement the `Copy` trait
+
+error: aborting due to 10 previous errors
For more information about this error, try `rustc --explain E0382`.
diff --git a/src/test/ui/borrowck/borrowck-slice-pattern-element-loan-array-no-overlap.rs b/src/test/ui/borrowck/borrowck-slice-pattern-element-loan-array-no-overlap.rs
new file mode 100644
index 0000000..7d91a21
--- /dev/null
+++ b/src/test/ui/borrowck/borrowck-slice-pattern-element-loan-array-no-overlap.rs
@@ -0,0 +1,66 @@
+// check-pass
+
+#![feature(slice_patterns)]
+
+fn nop(_s: &[& i32]) {}
+fn nop_subslice(_s: &[i32]) {}
+
+fn const_index_ok(s: &mut [i32; 4]) {
+ let [ref first, ref second, _, ref fourth, ..] = *s;
+ let [_, _, ref mut third, ..] = *s;
+ nop(&[first, second, third, fourth]);
+}
+
+fn const_index_from_end_ok(s: &mut [i32; 4]) {
+ let [.., ref fourth, ref third, _, ref first] = *s;
+ let [.., ref mut second, _] = *s;
+ nop(&[first, second, third, fourth]);
+}
+
+fn const_index_mixed(s: &mut [i32; 6]) {
+ let [.., _, ref from_end4, ref from_end3, _, ref from_end1] = *s;
+
+ let [ref mut from_begin0, ..] = *s;
+ nop(&[from_begin0, from_end1, from_end3, from_end4]);
+ let [_, ref mut from_begin1, ..] = *s;
+ nop(&[from_begin1, from_end1, from_end3, from_end4]);
+
+ let [ref from_begin0, ref from_begin1, _, ref from_begin3, _, ..] = *s;
+
+ let [.., ref mut from_end1] = *s;
+ nop(&[from_begin0, from_begin1, from_begin3, from_end1]);
+ let [.., ref mut from_end2, _] = *s;
+ nop(&[from_begin0, from_begin1, from_begin3, from_end2]);
+ let [.., ref mut from_end4, _, _, _] = *s;
+ nop(&[from_begin0, from_begin1, from_begin3, from_end4]);
+}
+
+fn const_index_and_subslice_ok(s: &mut [i32; 4]) {
+ let [ref first, ref second, ..] = *s;
+ let [_, _, ref mut tail @ ..] = *s;
+ nop(&[first, second]);
+ nop_subslice(tail);
+}
+
+fn const_index_and_subslice_from_end_ok(s: &mut [i32; 4]) {
+ let [.., ref second, ref first] = *s;
+ let [ref mut tail @ .., _, _] = *s;
+ nop(&[first, second]);
+ nop_subslice(tail);
+}
+
+fn subslices(s: &mut [i32; 4]) {
+ let [_, _, ref s1 @ ..] = *s;
+ let [ref mut s2 @ .., _, _] = *s;
+ nop_subslice(s1);
+ nop_subslice(s2);
+}
+
+fn main() {
+ let mut v = [1,2,3,4];
+ const_index_ok(&mut v);
+ const_index_from_end_ok(&mut v);
+ const_index_and_subslice_ok(&mut v);
+ const_index_and_subslice_from_end_ok(&mut v);
+ subslices(&mut v);
+}
diff --git a/src/test/ui/borrowck/borrowck-slice-pattern-element-loan-array.rs b/src/test/ui/borrowck/borrowck-slice-pattern-element-loan-array.rs
new file mode 100644
index 0000000..f03a2ab
--- /dev/null
+++ b/src/test/ui/borrowck/borrowck-slice-pattern-element-loan-array.rs
@@ -0,0 +1,60 @@
+#![feature(slice_patterns)]
+
+fn nop(_s: &[& i32]) {}
+fn nop_subslice(_s: &[i32]) {}
+
+fn const_index_err(s: &mut [i32; 4]) {
+ let [ref first, ref second, ..] = *s;
+ let [_, ref mut second2, ref mut third, ..] = *s; //~ERROR
+ nop(&[first, second, second2, third]);
+}
+
+fn const_index_from_end_err(s: &mut [i32; 4]) {
+ let [.., ref fourth, ref third, _, ref first] = *s;
+ let [.., ref mut third2, _, _] = *s; //~ERROR
+ nop(&[first, third, third2, fourth]);
+}
+
+fn const_index_mixed(s: &mut [i32; 6]) {
+ let [.., _, ref from_end4, ref from_end3, _, ref from_end1] = *s;
+
+ let [_, _, ref mut from_begin2, ..] = *s; //~ERROR
+ nop(&[from_begin2, from_end1, from_end3, from_end4]);
+ let [_, _, _, ref mut from_begin3, ..] = *s; //~ERROR
+ nop(&[from_begin3, from_end1, from_end3, from_end4]);
+
+ let [ref from_begin0, ref from_begin1, _, ref from_begin3, _, ..] = *s;
+
+ let [.., ref mut from_end3, _, _] = *s; //~ERROR
+ nop(&[from_begin0, from_begin1, from_begin3, from_end3]);
+}
+
+fn const_index_and_subslice_err(s: &mut [i32; 4]) {
+ let [ref first, ref second, ..] = *s;
+ let [_, ref mut tail @ ..] = *s; //~ERROR
+ nop(&[first, second]);
+ nop_subslice(tail);
+}
+
+fn const_index_and_subslice_from_end_err(s: &mut [i32; 4]) {
+ let [.., ref second, ref first] = *s;
+ let [ref mut tail @ .., _] = *s; //~ERROR
+ nop(&[first, second]);
+ nop_subslice(tail);
+}
+
+fn subslices_overlap(s: &mut [i32; 4]) {
+ let [_, ref s1 @ ..] = *s;
+ let [ref mut s2 @ .., _, _] = *s; //~ERROR
+ nop_subslice(s1);
+ nop_subslice(s2);
+}
+
+fn main() {
+ let mut v = [1,2,3,4];
+ const_index_err(&mut v);
+ const_index_from_end_err(&mut v);
+ const_index_and_subslice_err(&mut v);
+ const_index_and_subslice_from_end_err(&mut v);
+ subslices_overlap(&mut v);
+}
diff --git a/src/test/ui/borrowck/borrowck-slice-pattern-element-loan-array.stderr b/src/test/ui/borrowck/borrowck-slice-pattern-element-loan-array.stderr
new file mode 100644
index 0000000..e50e7eb
--- /dev/null
+++ b/src/test/ui/borrowck/borrowck-slice-pattern-element-loan-array.stderr
@@ -0,0 +1,86 @@
+error[E0502]: cannot borrow `s[..]` as mutable because it is also borrowed as immutable
+ --> $DIR/borrowck-slice-pattern-element-loan-array.rs:8:13
+ |
+LL | let [ref first, ref second, ..] = *s;
+ | ---------- immutable borrow occurs here
+LL | let [_, ref mut second2, ref mut third, ..] = *s;
+ | ^^^^^^^^^^^^^^^^ mutable borrow occurs here
+LL | nop(&[first, second, second2, third]);
+ | ------ immutable borrow later used here
+
+error[E0502]: cannot borrow `s[..]` as mutable because it is also borrowed as immutable
+ --> $DIR/borrowck-slice-pattern-element-loan-array.rs:14:14
+ |
+LL | let [.., ref fourth, ref third, _, ref first] = *s;
+ | --------- immutable borrow occurs here
+LL | let [.., ref mut third2, _, _] = *s;
+ | ^^^^^^^^^^^^^^ mutable borrow occurs here
+LL | nop(&[first, third, third2, fourth]);
+ | ----- immutable borrow later used here
+
+error[E0502]: cannot borrow `s[..]` as mutable because it is also borrowed as immutable
+ --> $DIR/borrowck-slice-pattern-element-loan-array.rs:21:16
+ |
+LL | let [.., _, ref from_end4, ref from_end3, _, ref from_end1] = *s;
+ | ------------- immutable borrow occurs here
+LL |
+LL | let [_, _, ref mut from_begin2, ..] = *s;
+ | ^^^^^^^^^^^^^^^^^^^ mutable borrow occurs here
+LL | nop(&[from_begin2, from_end1, from_end3, from_end4]);
+ | --------- immutable borrow later used here
+
+error[E0502]: cannot borrow `s[..]` as mutable because it is also borrowed as immutable
+ --> $DIR/borrowck-slice-pattern-element-loan-array.rs:23:19
+ |
+LL | let [.., _, ref from_end4, ref from_end3, _, ref from_end1] = *s;
+ | ------------- immutable borrow occurs here
+...
+LL | let [_, _, _, ref mut from_begin3, ..] = *s;
+ | ^^^^^^^^^^^^^^^^^^^ mutable borrow occurs here
+LL | nop(&[from_begin3, from_end1, from_end3, from_end4]);
+ | --------- immutable borrow later used here
+
+error[E0502]: cannot borrow `s[..]` as mutable because it is also borrowed as immutable
+ --> $DIR/borrowck-slice-pattern-element-loan-array.rs:28:14
+ |
+LL | let [ref from_begin0, ref from_begin1, _, ref from_begin3, _, ..] = *s;
+ | --------------- immutable borrow occurs here
+LL |
+LL | let [.., ref mut from_end3, _, _] = *s;
+ | ^^^^^^^^^^^^^^^^^ mutable borrow occurs here
+LL | nop(&[from_begin0, from_begin1, from_begin3, from_end3]);
+ | ----------- immutable borrow later used here
+
+error[E0502]: cannot borrow `s[..]` as mutable because it is also borrowed as immutable
+ --> $DIR/borrowck-slice-pattern-element-loan-array.rs:34:13
+ |
+LL | let [ref first, ref second, ..] = *s;
+ | ---------- immutable borrow occurs here
+LL | let [_, ref mut tail @ ..] = *s;
+ | ^^^^^^^^^^^^^^^^^ mutable borrow occurs here
+LL | nop(&[first, second]);
+ | ------ immutable borrow later used here
+
+error[E0502]: cannot borrow `s[..]` as mutable because it is also borrowed as immutable
+ --> $DIR/borrowck-slice-pattern-element-loan-array.rs:41:10
+ |
+LL | let [.., ref second, ref first] = *s;
+ | ---------- immutable borrow occurs here
+LL | let [ref mut tail @ .., _] = *s;
+ | ^^^^^^^^^^^^^^^^^ mutable borrow occurs here
+LL | nop(&[first, second]);
+ | ------ immutable borrow later used here
+
+error[E0502]: cannot borrow `s[..]` as mutable because it is also borrowed as immutable
+ --> $DIR/borrowck-slice-pattern-element-loan-array.rs:48:10
+ |
+LL | let [_, ref s1 @ ..] = *s;
+ | ----------- immutable borrow occurs here
+LL | let [ref mut s2 @ .., _, _] = *s;
+ | ^^^^^^^^^^^^^^^ mutable borrow occurs here
+LL | nop_subslice(s1);
+ | -- immutable borrow later used here
+
+error: aborting due to 8 previous errors
+
+For more information about this error, try `rustc --explain E0502`.
diff --git a/src/test/ui/borrowck/borrowck-slice-pattern-element-loan-slice-no-overlap.rs b/src/test/ui/borrowck/borrowck-slice-pattern-element-loan-slice-no-overlap.rs
new file mode 100644
index 0000000..e69071f
--- /dev/null
+++ b/src/test/ui/borrowck/borrowck-slice-pattern-element-loan-slice-no-overlap.rs
@@ -0,0 +1,61 @@
+// check-pass
+
+#![feature(slice_patterns)]
+
+fn nop(_s: &[& i32]) {}
+fn nop_subslice(_s: &[i32]) {}
+
+fn const_index_ok(s: &mut [i32]) {
+ if let [ref first, ref second, _, ref fourth, ..] = *s {
+ if let [_, _, ref mut third, ..] = *s {
+ nop(&[first, second, third, fourth]);
+ }
+ }
+}
+
+fn const_index_from_end_ok(s: &mut [i32]) {
+ if let [.., ref fourth, ref third, _, ref first] = *s {
+ if let [.., ref mut second, _] = *s {
+ nop(&[first, second, third, fourth]);
+ }
+ }
+}
+
+fn const_index_mixed(s: &mut [i32]) {
+ if let [.., _, ref from_end4, ref from_end3, _, ref from_end1] = *s {
+ if let [ref mut from_begin0, ..] = *s {
+ nop(&[from_begin0, from_end1, from_end3, from_end4]);
+ }
+ }
+ if let [ref from_begin0, ref from_begin1, _, ref from_begin3, _, ..] = *s {
+ if let [.., ref mut from_end1] = *s {
+ nop(&[from_begin0, from_begin1, from_begin3, from_end1]);
+ }
+ }
+}
+
+fn const_index_and_subslice_ok(s: &mut [i32]) {
+ if let [ref first, ref second, ..] = *s {
+ if let [_, _, ref mut tail @ ..] = *s {
+ nop(&[first, second]);
+ nop_subslice(tail);
+ }
+ }
+}
+
+fn const_index_and_subslice_from_end_ok(s: &mut [i32]) {
+ if let [.., ref second, ref first] = *s {
+ if let [ref mut tail @ .., _, _] = *s {
+ nop(&[first, second]);
+ nop_subslice(tail);
+ }
+ }
+}
+
+fn main() {
+ let mut v = [1,2,3,4];
+ const_index_ok(&mut v);
+ const_index_from_end_ok(&mut v);
+ const_index_and_subslice_ok(&mut v);
+ const_index_and_subslice_from_end_ok(&mut v);
+}
diff --git a/src/test/ui/borrowck/borrowck-slice-pattern-element-loan.rs b/src/test/ui/borrowck/borrowck-slice-pattern-element-loan-slice.rs
similarity index 65%
rename from src/test/ui/borrowck/borrowck-slice-pattern-element-loan.rs
rename to src/test/ui/borrowck/borrowck-slice-pattern-element-loan-slice.rs
index a6b54f9..2ef9874 100644
--- a/src/test/ui/borrowck/borrowck-slice-pattern-element-loan.rs
+++ b/src/test/ui/borrowck/borrowck-slice-pattern-element-loan-slice.rs
@@ -1,18 +1,8 @@
-//compile-flags: -Z borrowck=mir
-
#![feature(slice_patterns)]
fn nop(_s: &[& i32]) {}
fn nop_subslice(_s: &[i32]) {}
-fn const_index_ok(s: &mut [i32]) {
- if let [ref first, ref second, _, ref fourth, ..] = *s {
- if let [_, _, ref mut third, ..] = *s {
- nop(&[first, second, third, fourth]);
- }
- }
-}
-
fn const_index_err(s: &mut [i32]) {
if let [ref first, ref second, ..] = *s {
if let [_, ref mut second2, ref mut third, ..] = *s { //~ERROR
@@ -21,14 +11,6 @@
}
}
-fn const_index_from_end_ok(s: &mut [i32]) {
- if let [.., ref fourth, ref third, _, ref first] = *s {
- if let [.., ref mut second, _] = *s {
- nop(&[first, second, third, fourth]);
- }
- }
-}
-
fn const_index_from_end_err(s: &mut [i32]) {
if let [.., ref fourth, ref third, _, ref first] = *s {
if let [.., ref mut third2, _, _] = *s { //~ERROR
@@ -39,9 +21,6 @@
fn const_index_mixed(s: &mut [i32]) {
if let [.., _, ref from_end4, ref from_end3, _, ref from_end1] = *s {
- if let [ref mut from_begin0, ..] = *s {
- nop(&[from_begin0, from_end1, from_end3, from_end4]);
- }
if let [_, ref mut from_begin1, ..] = *s { //~ERROR
nop(&[from_begin1, from_end1, from_end3, from_end4]);
}
@@ -53,9 +32,6 @@
}
}
if let [ref from_begin0, ref from_begin1, _, ref from_begin3, _, ..] = *s {
- if let [.., ref mut from_end1] = *s {
- nop(&[from_begin0, from_begin1, from_begin3, from_end1]);
- }
if let [.., ref mut from_end2, _] = *s { //~ERROR
nop(&[from_begin0, from_begin1, from_begin3, from_end2]);
}
@@ -68,15 +44,6 @@
}
}
-fn const_index_and_subslice_ok(s: &mut [i32]) {
- if let [ref first, ref second, ..] = *s {
- if let [_, _, ref mut tail @ ..] = *s {
- nop(&[first, second]);
- nop_subslice(tail);
- }
- }
-}
-
fn const_index_and_subslice_err(s: &mut [i32]) {
if let [ref first, ref second, ..] = *s {
if let [_, ref mut tail @ ..] = *s { //~ERROR
@@ -86,15 +53,6 @@
}
}
-fn const_index_and_subslice_from_end_ok(s: &mut [i32]) {
- if let [.., ref second, ref first] = *s {
- if let [ref mut tail @ .., _, _] = *s {
- nop(&[first, second]);
- nop_subslice(tail);
- }
- }
-}
-
fn const_index_and_subslice_from_end_err(s: &mut [i32]) {
if let [.., ref second, ref first] = *s {
if let [ref mut tail @ .., _] = *s { //~ERROR
@@ -115,13 +73,9 @@
fn main() {
let mut v = [1,2,3,4];
- const_index_ok(&mut v);
const_index_err(&mut v);
- const_index_from_end_ok(&mut v);
const_index_from_end_err(&mut v);
- const_index_and_subslice_ok(&mut v);
const_index_and_subslice_err(&mut v);
- const_index_and_subslice_from_end_ok(&mut v);
const_index_and_subslice_from_end_err(&mut v);
subslices(&mut v);
}
diff --git a/src/test/ui/borrowck/borrowck-slice-pattern-element-loan.stderr b/src/test/ui/borrowck/borrowck-slice-pattern-element-loan-slice.stderr
similarity index 89%
rename from src/test/ui/borrowck/borrowck-slice-pattern-element-loan.stderr
rename to src/test/ui/borrowck/borrowck-slice-pattern-element-loan-slice.stderr
index 2c019f4..b6f5ac6 100644
--- a/src/test/ui/borrowck/borrowck-slice-pattern-element-loan.stderr
+++ b/src/test/ui/borrowck/borrowck-slice-pattern-element-loan-slice.stderr
@@ -1,5 +1,5 @@
error[E0502]: cannot borrow `s[..]` as mutable because it is also borrowed as immutable
- --> $DIR/borrowck-slice-pattern-element-loan.rs:18:20
+ --> $DIR/borrowck-slice-pattern-element-loan-slice.rs:8:20
|
LL | if let [ref first, ref second, ..] = *s {
| ---------- immutable borrow occurs here
@@ -9,7 +9,7 @@
| ------ immutable borrow later used here
error[E0502]: cannot borrow `s[..]` as mutable because it is also borrowed as immutable
- --> $DIR/borrowck-slice-pattern-element-loan.rs:34:21
+ --> $DIR/borrowck-slice-pattern-element-loan-slice.rs:16:21
|
LL | if let [.., ref fourth, ref third, _, ref first] = *s {
| --------- immutable borrow occurs here
@@ -19,18 +19,17 @@
| ----- immutable borrow later used here
error[E0502]: cannot borrow `s[..]` as mutable because it is also borrowed as immutable
- --> $DIR/borrowck-slice-pattern-element-loan.rs:45:20
+ --> $DIR/borrowck-slice-pattern-element-loan-slice.rs:24:20
|
LL | if let [.., _, ref from_end4, ref from_end3, _, ref from_end1] = *s {
| ------------- immutable borrow occurs here
-...
LL | if let [_, ref mut from_begin1, ..] = *s {
| ^^^^^^^^^^^^^^^^^^^ mutable borrow occurs here
LL | nop(&[from_begin1, from_end1, from_end3, from_end4]);
| --------- immutable borrow later used here
error[E0502]: cannot borrow `s[..]` as mutable because it is also borrowed as immutable
- --> $DIR/borrowck-slice-pattern-element-loan.rs:48:23
+ --> $DIR/borrowck-slice-pattern-element-loan-slice.rs:27:23
|
LL | if let [.., _, ref from_end4, ref from_end3, _, ref from_end1] = *s {
| ------------- immutable borrow occurs here
@@ -41,7 +40,7 @@
| --------- immutable borrow later used here
error[E0502]: cannot borrow `s[..]` as mutable because it is also borrowed as immutable
- --> $DIR/borrowck-slice-pattern-element-loan.rs:51:26
+ --> $DIR/borrowck-slice-pattern-element-loan-slice.rs:30:26
|
LL | if let [.., _, ref from_end4, ref from_end3, _, ref from_end1] = *s {
| ------------- immutable borrow occurs here
@@ -52,18 +51,17 @@
| --------- immutable borrow later used here
error[E0502]: cannot borrow `s[..]` as mutable because it is also borrowed as immutable
- --> $DIR/borrowck-slice-pattern-element-loan.rs:59:21
+ --> $DIR/borrowck-slice-pattern-element-loan-slice.rs:35:21
|
LL | if let [ref from_begin0, ref from_begin1, _, ref from_begin3, _, ..] = *s {
| --------------- immutable borrow occurs here
-...
LL | if let [.., ref mut from_end2, _] = *s {
| ^^^^^^^^^^^^^^^^^ mutable borrow occurs here
LL | nop(&[from_begin0, from_begin1, from_begin3, from_end2]);
| ----------- immutable borrow later used here
error[E0502]: cannot borrow `s[..]` as mutable because it is also borrowed as immutable
- --> $DIR/borrowck-slice-pattern-element-loan.rs:62:21
+ --> $DIR/borrowck-slice-pattern-element-loan-slice.rs:38:21
|
LL | if let [ref from_begin0, ref from_begin1, _, ref from_begin3, _, ..] = *s {
| --------------- immutable borrow occurs here
@@ -74,7 +72,7 @@
| ----------- immutable borrow later used here
error[E0502]: cannot borrow `s[..]` as mutable because it is also borrowed as immutable
- --> $DIR/borrowck-slice-pattern-element-loan.rs:65:21
+ --> $DIR/borrowck-slice-pattern-element-loan-slice.rs:41:21
|
LL | if let [ref from_begin0, ref from_begin1, _, ref from_begin3, _, ..] = *s {
| --------------- immutable borrow occurs here
@@ -85,7 +83,7 @@
| ----------- immutable borrow later used here
error[E0502]: cannot borrow `s[..]` as mutable because it is also borrowed as immutable
- --> $DIR/borrowck-slice-pattern-element-loan.rs:82:20
+ --> $DIR/borrowck-slice-pattern-element-loan-slice.rs:49:20
|
LL | if let [ref first, ref second, ..] = *s {
| ---------- immutable borrow occurs here
@@ -95,7 +93,7 @@
| ------ immutable borrow later used here
error[E0502]: cannot borrow `s[..]` as mutable because it is also borrowed as immutable
- --> $DIR/borrowck-slice-pattern-element-loan.rs:100:17
+ --> $DIR/borrowck-slice-pattern-element-loan-slice.rs:58:17
|
LL | if let [.., ref second, ref first] = *s {
| ---------- immutable borrow occurs here
@@ -105,7 +103,7 @@
| ------ immutable borrow later used here
error[E0502]: cannot borrow `s[..]` as mutable because it is also borrowed as immutable
- --> $DIR/borrowck-slice-pattern-element-loan.rs:109:17
+ --> $DIR/borrowck-slice-pattern-element-loan-slice.rs:67:17
|
LL | if let [_, _, _, ref s1 @ ..] = *s {
| ----------- immutable borrow occurs here
diff --git a/src/test/ui/c-variadic/variadic-ffi-4.stderr b/src/test/ui/c-variadic/variadic-ffi-4.stderr
index c80ed5e..cd4cd8b 100644
--- a/src/test/ui/c-variadic/variadic-ffi-4.stderr
+++ b/src/test/ui/c-variadic/variadic-ffi-4.stderr
@@ -49,9 +49,13 @@
|
LL | let _ = ap.with_copy(|ap| { ap });
| ^^^^^^^^^^^
- = note: ...so that the expression is assignable:
- expected core::ffi::VaList<'_, '_>
- found core::ffi::VaList<'_, '_>
+note: ...so that the expression is assignable
+ --> $DIR/variadic-ffi-4.rs:16:33
+ |
+LL | let _ = ap.with_copy(|ap| { ap });
+ | ^^
+ = note: expected `core::ffi::VaList<'_, '_>`
+ found `core::ffi::VaList<'_, '_>`
note: but, the lifetime must be valid for the method call at 16:13...
--> $DIR/variadic-ffi-4.rs:16:13
|
diff --git a/src/test/ui/check-static-immutable-mut-slices.stderr b/src/test/ui/check-static-immutable-mut-slices.stderr
index 4f4bf16..39da824 100644
--- a/src/test/ui/check-static-immutable-mut-slices.stderr
+++ b/src/test/ui/check-static-immutable-mut-slices.stderr
@@ -1,9 +1,12 @@
-error[E0017]: references in statics may only refer to immutable values
+error[E0658]: references in statics may only refer to immutable values
--> $DIR/check-static-immutable-mut-slices.rs:3:37
|
LL | static TEST: &'static mut [isize] = &mut [];
| ^^^^^^^ statics require immutable values
+ |
+ = note: for more information, see https://github.com/rust-lang/rust/issues/57349
+ = help: add `#![feature(const_mut_refs)]` to the crate attributes to enable
error: aborting due to previous error
-For more information about this error, try `rustc --explain E0017`.
+For more information about this error, try `rustc --explain E0658`.
diff --git a/src/test/ui/closure-expected-type/expect-fn-supply-fn.nll.stderr b/src/test/ui/closure-expected-type/expect-fn-supply-fn.nll.stderr
index a6b52b2..7141c04 100644
--- a/src/test/ui/closure-expected-type/expect-fn-supply-fn.nll.stderr
+++ b/src/test/ui/closure-expected-type/expect-fn-supply-fn.nll.stderr
@@ -39,3 +39,4 @@
error: aborting due to 3 previous errors
+For more information about this error, try `rustc --explain E0631`.
diff --git a/src/test/ui/closure-expected-type/expect-fn-supply-fn.stderr b/src/test/ui/closure-expected-type/expect-fn-supply-fn.stderr
index a154442..0033395 100644
--- a/src/test/ui/closure-expected-type/expect-fn-supply-fn.stderr
+++ b/src/test/ui/closure-expected-type/expect-fn-supply-fn.stderr
@@ -77,4 +77,5 @@
error: aborting due to 5 previous errors
-For more information about this error, try `rustc --explain E0308`.
+Some errors have detailed explanations: E0308, E0631.
+For more information about an error, try `rustc --explain E0308`.
diff --git a/src/test/ui/closure-expected-type/expect-infer-var-appearing-twice.stderr b/src/test/ui/closure-expected-type/expect-infer-var-appearing-twice.stderr
index 9fbe95a..1c6564e 100644
--- a/src/test/ui/closure-expected-type/expect-infer-var-appearing-twice.stderr
+++ b/src/test/ui/closure-expected-type/expect-infer-var-appearing-twice.stderr
@@ -13,3 +13,4 @@
error: aborting due to previous error
+For more information about this error, try `rustc --explain E0631`.
diff --git a/src/test/ui/closures/closure-expected-type/expect-region-supply-region.polonius.stderr b/src/test/ui/closures/closure-expected-type/expect-region-supply-region.polonius.stderr
new file mode 100644
index 0000000..2a7461f
--- /dev/null
+++ b/src/test/ui/closures/closure-expected-type/expect-region-supply-region.polonius.stderr
@@ -0,0 +1,56 @@
+error[E0521]: borrowed data escapes outside of closure
+ --> $DIR/expect-region-supply-region.rs:18:9
+ |
+LL | let mut f: Option<&u32> = None;
+ | ----- `f` is declared here, outside of the closure body
+LL | closure_expecting_bound(|x| {
+ | - `x` is a reference that is only valid in the closure body
+LL | f = Some(x);
+ | ^^^^^^^^^^^ `x` escapes the closure body here
+
+error[E0521]: borrowed data escapes outside of closure
+ --> $DIR/expect-region-supply-region.rs:28:9
+ |
+LL | let mut f: Option<&u32> = None;
+ | ----- `f` is declared here, outside of the closure body
+LL | closure_expecting_bound(|x: &u32| {
+ | - `x` is a reference that is only valid in the closure body
+LL | f = Some(x);
+ | ^^^^^^^^^^^ `x` escapes the closure body here
+
+error: lifetime may not live long enough
+ --> $DIR/expect-region-supply-region.rs:37:30
+ |
+LL | fn expect_bound_supply_named<'x>() {
+ | -- lifetime `'x` defined here
+...
+LL | closure_expecting_bound(|x: &'x u32| {
+ | ^ - let's call the lifetime of this reference `'1`
+ | |
+ | requires that `'1` must outlive `'x`
+
+error[E0521]: borrowed data escapes outside of closure
+ --> $DIR/expect-region-supply-region.rs:42:9
+ |
+LL | let mut f: Option<&u32> = None;
+ | ----- `f` is declared here, outside of the closure body
+...
+LL | closure_expecting_bound(|x: &'x u32| {
+ | - `x` is a reference that is only valid in the closure body
+...
+LL | f = Some(x);
+ | ^^^^^^^^^^^ `x` escapes the closure body here
+
+error: lifetime may not live long enough
+ --> $DIR/expect-region-supply-region.rs:37:30
+ |
+LL | fn expect_bound_supply_named<'x>() {
+ | -- lifetime `'x` defined here
+...
+LL | closure_expecting_bound(|x: &'x u32| {
+ | ^ requires that `'x` must outlive `'static`
+ |
+ = help: consider replacing `'x` with `'static`
+
+error: aborting due to 5 previous errors
+
diff --git a/src/test/ui/closures/issue-41366.stderr b/src/test/ui/closures/issue-41366.stderr
index 91d26ef..2f2871e 100644
--- a/src/test/ui/closures/issue-41366.stderr
+++ b/src/test/ui/closures/issue-41366.stderr
@@ -19,4 +19,5 @@
error: aborting due to 2 previous errors
-For more information about this error, try `rustc --explain E0271`.
+Some errors have detailed explanations: E0271, E0631.
+For more information about an error, try `rustc --explain E0271`.
diff --git a/src/test/ui/closures/issue-67123.rs b/src/test/ui/closures/issue-67123.rs
new file mode 100644
index 0000000..014c530
--- /dev/null
+++ b/src/test/ui/closures/issue-67123.rs
@@ -0,0 +1,5 @@
+fn foo<T>(t: T) {
+ || { t; t; }; //~ ERROR: use of moved value
+}
+
+fn main() {}
diff --git a/src/test/ui/closures/issue-67123.stderr b/src/test/ui/closures/issue-67123.stderr
new file mode 100644
index 0000000..b2e875b
--- /dev/null
+++ b/src/test/ui/closures/issue-67123.stderr
@@ -0,0 +1,15 @@
+error[E0382]: use of moved value: `t`
+ --> $DIR/issue-67123.rs:2:13
+ |
+LL | fn foo<T>(t: T) {
+ | - help: consider restricting this bound: `T: Copy`
+LL | || { t; t; };
+ | - ^ value used here after move
+ | |
+ | value moved here
+ |
+ = note: move occurs because `t` has type `T`, which does not implement the `Copy` trait
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0382`.
diff --git a/src/test/ui/conditional-compilation/cfg-attr-parse.rs b/src/test/ui/conditional-compilation/cfg-attr-parse.rs
index 93aef72..8ca31c1 100644
--- a/src/test/ui/conditional-compilation/cfg-attr-parse.rs
+++ b/src/test/ui/conditional-compilation/cfg-attr-parse.rs
@@ -1,11 +1,11 @@
// Parse `cfg_attr` with varying numbers of attributes and trailing commas
// Completely empty `cfg_attr` input
-#[cfg_attr()] //~ error: expected identifier, found `)`
+#[cfg_attr()] //~ error: malformed `cfg_attr` attribute input
struct NoConfigurationPredicate;
// Zero attributes, zero trailing comma (comma manatory here)
-#[cfg_attr(all())] //~ error: expected `,`, found `)`
+#[cfg_attr(all())] //~ error: expected `,`, found end of `cfg_attr`
struct A0C0;
// Zero attributes, one trailing comma
@@ -40,4 +40,16 @@
#[cfg_attr(all(), must_use, deprecated,,)] //~ ERROR expected identifier
struct A2C2;
+// Wrong delimiter `[`
+#[cfg_attr[all(),,]]
+//~^ ERROR wrong `cfg_attr` delimiters
+//~| ERROR expected identifier, found `,`
+struct BracketZero;
+
+// Wrong delimiter `{`
+#[cfg_attr{all(),,}]
+//~^ ERROR wrong `cfg_attr` delimiters
+//~| ERROR expected identifier, found `,`
+struct BraceZero;
+
fn main() {}
diff --git a/src/test/ui/conditional-compilation/cfg-attr-parse.stderr b/src/test/ui/conditional-compilation/cfg-attr-parse.stderr
index 3dfbd6d..3a590d3 100644
--- a/src/test/ui/conditional-compilation/cfg-attr-parse.stderr
+++ b/src/test/ui/conditional-compilation/cfg-attr-parse.stderr
@@ -1,32 +1,86 @@
-error: expected identifier, found `)`
- --> $DIR/cfg-attr-parse.rs:4:12
+error: malformed `cfg_attr` attribute input
+ --> $DIR/cfg-attr-parse.rs:4:1
|
LL | #[cfg_attr()]
- | ^ expected identifier
+ | ^^^^^^^^^^^^^ help: missing condition and attribute: `#[cfg_attr(condition, attribute, other_attribute, ...)]`
+ |
+ = note: for more information, visit <https://doc.rust-lang.org/reference/conditional-compilation.html#the-cfg_attr-attribute>
-error: expected `,`, found `)`
+error: expected `,`, found end of `cfg_attr` input
--> $DIR/cfg-attr-parse.rs:8:17
|
LL | #[cfg_attr(all())]
| ^ expected `,`
+ |
+ = help: the valid syntax is `#[cfg_attr(condition, attribute, other_attribute, ...)]`
+ = note: for more information, visit <https://doc.rust-lang.org/reference/conditional-compilation.html#the-cfg_attr-attribute>
error: expected identifier, found `,`
--> $DIR/cfg-attr-parse.rs:16:18
|
LL | #[cfg_attr(all(),,)]
| ^ expected identifier
+ |
+ = help: the valid syntax is `#[cfg_attr(condition, attribute, other_attribute, ...)]`
+ = note: for more information, visit <https://doc.rust-lang.org/reference/conditional-compilation.html#the-cfg_attr-attribute>
error: expected identifier, found `,`
--> $DIR/cfg-attr-parse.rs:28:28
|
LL | #[cfg_attr(all(), must_use,,)]
| ^ expected identifier
+ |
+ = help: the valid syntax is `#[cfg_attr(condition, attribute, other_attribute, ...)]`
+ = note: for more information, visit <https://doc.rust-lang.org/reference/conditional-compilation.html#the-cfg_attr-attribute>
error: expected identifier, found `,`
--> $DIR/cfg-attr-parse.rs:40:40
|
LL | #[cfg_attr(all(), must_use, deprecated,,)]
| ^ expected identifier
+ |
+ = help: the valid syntax is `#[cfg_attr(condition, attribute, other_attribute, ...)]`
+ = note: for more information, visit <https://doc.rust-lang.org/reference/conditional-compilation.html#the-cfg_attr-attribute>
-error: aborting due to 5 previous errors
+error: wrong `cfg_attr` delimiters
+ --> $DIR/cfg-attr-parse.rs:44:11
+ |
+LL | #[cfg_attr[all(),,]]
+ | ^^^^^^^^^
+ |
+help: the delimiters should be `(` and `)`
+ |
+LL | #[cfg_attr(all(),,)]
+ | ^ ^
+
+error: expected identifier, found `,`
+ --> $DIR/cfg-attr-parse.rs:44:18
+ |
+LL | #[cfg_attr[all(),,]]
+ | ^ expected identifier
+ |
+ = help: the valid syntax is `#[cfg_attr(condition, attribute, other_attribute, ...)]`
+ = note: for more information, visit <https://doc.rust-lang.org/reference/conditional-compilation.html#the-cfg_attr-attribute>
+
+error: wrong `cfg_attr` delimiters
+ --> $DIR/cfg-attr-parse.rs:50:11
+ |
+LL | #[cfg_attr{all(),,}]
+ | ^^^^^^^^^
+ |
+help: the delimiters should be `(` and `)`
+ |
+LL | #[cfg_attr(all(),,)]
+ | ^ ^
+
+error: expected identifier, found `,`
+ --> $DIR/cfg-attr-parse.rs:50:18
+ |
+LL | #[cfg_attr{all(),,}]
+ | ^ expected identifier
+ |
+ = help: the valid syntax is `#[cfg_attr(condition, attribute, other_attribute, ...)]`
+ = note: for more information, visit <https://doc.rust-lang.org/reference/conditional-compilation.html#the-cfg_attr-attribute>
+
+error: aborting due to 9 previous errors
diff --git a/src/test/ui/const-generics/cannot-infer-const-args.stderr b/src/test/ui/const-generics/cannot-infer-const-args.stderr
index 32adc63..8379cbd 100644
--- a/src/test/ui/const-generics/cannot-infer-const-args.stderr
+++ b/src/test/ui/const-generics/cannot-infer-const-args.stderr
@@ -10,7 +10,7 @@
--> $DIR/cannot-infer-const-args.rs:9:5
|
LL | foo();
- | ^^^ cannot infer type for `fn() -> usize {foo::<_: usize>}`
+ | ^^^ cannot infer type for fn item `fn() -> usize {foo::<_: usize>}`
error: aborting due to previous error
diff --git a/src/test/ui/const-generics/fn-const-param-infer.stderr b/src/test/ui/const-generics/fn-const-param-infer.stderr
index 2d9b6ed..9ccad7b 100644
--- a/src/test/ui/const-generics/fn-const-param-infer.stderr
+++ b/src/test/ui/const-generics/fn-const-param-infer.stderr
@@ -30,7 +30,7 @@
--> $DIR/fn-const-param-infer.rs:22:23
|
LL | let _ = Checked::<generic>;
- | ^^^^^^^ cannot infer type for `T`
+ | ^^^^^^^ cannot infer type for type parameter `T`
error[E0308]: mismatched types
--> $DIR/fn-const-param-infer.rs:25:40
diff --git a/src/test/ui/consts/array-literal-index-oob.stderr b/src/test/ui/consts/array-literal-index-oob.stderr
index 0ddc2a0..f4d4e6f 100644
--- a/src/test/ui/consts/array-literal-index-oob.stderr
+++ b/src/test/ui/consts/array-literal-index-oob.stderr
@@ -12,7 +12,7 @@
LL | &{[1, 2, 3][4]};
| --^^^^^^^^^^^^-
| |
- | index out of bounds: the len is 3 but the index is 4
+ | indexing out of bounds: the len is 3 but the index is 4
error: aborting due to 2 previous errors
diff --git a/src/test/ui/consts/assoc_const_generic_impl.rs b/src/test/ui/consts/assoc_const_generic_impl.rs
new file mode 100644
index 0000000..62702a8
--- /dev/null
+++ b/src/test/ui/consts/assoc_const_generic_impl.rs
@@ -0,0 +1,19 @@
+#![warn(const_err)]
+
+trait ZeroSized: Sized {
+ const I_AM_ZERO_SIZED: ();
+ fn requires_zero_size(self);
+}
+
+impl<T: Sized> ZeroSized for T {
+ const I_AM_ZERO_SIZED: () = [()][std::mem::size_of::<Self>()]; //~ WARN any use of this value
+ fn requires_zero_size(self) {
+ let () = Self::I_AM_ZERO_SIZED; //~ ERROR erroneous constant encountered
+ println!("requires_zero_size called");
+ }
+}
+
+fn main() {
+ ().requires_zero_size();
+ 42_u32.requires_zero_size();
+}
diff --git a/src/test/ui/consts/assoc_const_generic_impl.stderr b/src/test/ui/consts/assoc_const_generic_impl.stderr
new file mode 100644
index 0000000..a114d5c
--- /dev/null
+++ b/src/test/ui/consts/assoc_const_generic_impl.stderr
@@ -0,0 +1,22 @@
+warning: any use of this value will cause an error
+ --> $DIR/assoc_const_generic_impl.rs:9:34
+ |
+LL | const I_AM_ZERO_SIZED: () = [()][std::mem::size_of::<Self>()];
+ | -----------------------------^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^-
+ | |
+ | index out of bounds: the len is 1 but the index is 4
+ |
+note: lint level defined here
+ --> $DIR/assoc_const_generic_impl.rs:1:9
+ |
+LL | #![warn(const_err)]
+ | ^^^^^^^^^
+
+error: erroneous constant encountered
+ --> $DIR/assoc_const_generic_impl.rs:11:18
+ |
+LL | let () = Self::I_AM_ZERO_SIZED;
+ | ^^^^^^^^^^^^^^^^^^^^^
+
+error: aborting due to previous error
+
diff --git a/src/test/ui/consts/const-err2.rs b/src/test/ui/consts/const-err2.rs
index e5ee90f..ecbcc2a 100644
--- a/src/test/ui/consts/const-err2.rs
+++ b/src/test/ui/consts/const-err2.rs
@@ -23,7 +23,6 @@
//~^ ERROR const_err
let _e = [5u8][1];
//~^ ERROR index out of bounds
- //~| ERROR this expression will panic at runtime
black_box(a);
black_box(b);
black_box(c);
diff --git a/src/test/ui/consts/const-err2.stderr b/src/test/ui/consts/const-err2.stderr
index 0a09a72..1d84d44 100644
--- a/src/test/ui/consts/const-err2.stderr
+++ b/src/test/ui/consts/const-err2.stderr
@@ -34,11 +34,5 @@
LL | let _e = [5u8][1];
| ^^^^^^^^
-error: this expression will panic at runtime
- --> $DIR/const-err2.rs:24:14
- |
-LL | let _e = [5u8][1];
- | ^^^^^^^^ index out of bounds: the len is 1 but the index is 1
-
-error: aborting due to 6 previous errors
+error: aborting due to 5 previous errors
diff --git a/src/test/ui/consts/const-err3.rs b/src/test/ui/consts/const-err3.rs
index 89373f9..a9cf04c 100644
--- a/src/test/ui/consts/const-err3.rs
+++ b/src/test/ui/consts/const-err3.rs
@@ -23,7 +23,6 @@
//~^ ERROR const_err
let _e = [5u8][1];
//~^ ERROR const_err
- //~| ERROR this expression will panic at runtime
black_box(a);
black_box(b);
black_box(c);
diff --git a/src/test/ui/consts/const-err3.stderr b/src/test/ui/consts/const-err3.stderr
index 42de247..0602707 100644
--- a/src/test/ui/consts/const-err3.stderr
+++ b/src/test/ui/consts/const-err3.stderr
@@ -34,11 +34,5 @@
LL | let _e = [5u8][1];
| ^^^^^^^^
-error: this expression will panic at runtime
- --> $DIR/const-err3.rs:24:14
- |
-LL | let _e = [5u8][1];
- | ^^^^^^^^ index out of bounds: the len is 1 but the index is 1
-
-error: aborting due to 6 previous errors
+error: aborting due to 5 previous errors
diff --git a/src/test/ui/consts/const-eval/const_caller_location.rs b/src/test/ui/consts/const-eval/const_caller_location.rs
deleted file mode 100644
index c63822f..0000000
--- a/src/test/ui/consts/const-eval/const_caller_location.rs
+++ /dev/null
@@ -1,23 +0,0 @@
-// run-pass
-
-#![feature(const_fn, core_intrinsics)]
-
-use std::{intrinsics::caller_location, panic::Location};
-
-const LOCATION: &Location = caller_location();
-const NESTED: &Location = {
- const fn nested_location() -> &'static Location<'static> {
- caller_location()
- };
- nested_location()
-};
-
-fn main() {
- assert_eq!(LOCATION.file(), file!());
- assert_eq!(LOCATION.line(), 7);
- assert_eq!(LOCATION.column(), 29);
-
- assert_eq!(NESTED.file(), file!());
- assert_eq!(NESTED.line(), 10);
- assert_eq!(NESTED.column(), 9);
-}
diff --git a/src/test/ui/consts/const-eval/index-out-of-bounds-never-type.rs b/src/test/ui/consts/const-eval/index-out-of-bounds-never-type.rs
new file mode 100644
index 0000000..516ca4f
--- /dev/null
+++ b/src/test/ui/consts/const-eval/index-out-of-bounds-never-type.rs
@@ -0,0 +1,18 @@
+// Regression test for #66975
+#![warn(const_err)]
+
+struct PrintName<T>(T);
+
+impl<T> PrintName<T> {
+ const VOID: ! = { let x = 0 * std::mem::size_of::<T>(); [][x] };
+ //~^ WARN any use of this value will cause an error
+}
+
+fn f<T>() {
+ let _ = PrintName::<T>::VOID;
+ //~^ ERROR erroneous constant encountered
+}
+
+pub fn main() {
+ f::<()>();
+}
diff --git a/src/test/ui/consts/const-eval/index-out-of-bounds-never-type.stderr b/src/test/ui/consts/const-eval/index-out-of-bounds-never-type.stderr
new file mode 100644
index 0000000..e2bd8d0
--- /dev/null
+++ b/src/test/ui/consts/const-eval/index-out-of-bounds-never-type.stderr
@@ -0,0 +1,22 @@
+warning: any use of this value will cause an error
+ --> $DIR/index-out-of-bounds-never-type.rs:7:61
+ |
+LL | const VOID: ! = { let x = 0 * std::mem::size_of::<T>(); [][x] };
+ | --------------------------------------------------------^^^^^---
+ | |
+ | index out of bounds: the len is 0 but the index is 0
+ |
+note: lint level defined here
+ --> $DIR/index-out-of-bounds-never-type.rs:2:9
+ |
+LL | #![warn(const_err)]
+ | ^^^^^^^^^
+
+error: erroneous constant encountered
+ --> $DIR/index-out-of-bounds-never-type.rs:12:13
+ |
+LL | let _ = PrintName::<T>::VOID;
+ | ^^^^^^^^^^^^^^^^^^^^
+
+error: aborting due to previous error
+
diff --git a/src/test/ui/consts/const-eval/issue-65394.stderr b/src/test/ui/consts/const-eval/issue-65394.stderr
index acf5cba..54b3507 100644
--- a/src/test/ui/consts/const-eval/issue-65394.stderr
+++ b/src/test/ui/consts/const-eval/issue-65394.stderr
@@ -1,8 +1,11 @@
-error[E0017]: references in constants may only refer to immutable values
+error[E0658]: references in constants may only refer to immutable values
--> $DIR/issue-65394.rs:8:13
|
LL | let r = &mut x;
| ^^^^^^ constants require immutable values
+ |
+ = note: for more information, see https://github.com/rust-lang/rust/issues/57349
+ = help: add `#![feature(const_mut_refs)]` to the crate attributes to enable
error[E0493]: destructors cannot be evaluated at compile-time
--> $DIR/issue-65394.rs:7:9
@@ -12,5 +15,5 @@
error: aborting due to 2 previous errors
-Some errors have detailed explanations: E0017, E0493.
-For more information about an error, try `rustc --explain E0017`.
+Some errors have detailed explanations: E0493, E0658.
+For more information about an error, try `rustc --explain E0493`.
diff --git a/src/test/ui/consts/const-eval/panic-assoc-never-type.rs b/src/test/ui/consts/const-eval/panic-assoc-never-type.rs
new file mode 100644
index 0000000..b39d9af
--- /dev/null
+++ b/src/test/ui/consts/const-eval/panic-assoc-never-type.rs
@@ -0,0 +1,15 @@
+// Regression test for #66975
+#![warn(const_err)]
+#![feature(const_panic)]
+
+struct PrintName;
+
+impl PrintName {
+ const VOID: ! = panic!();
+ //~^ WARN any use of this value will cause an error
+}
+
+fn main() {
+ let _ = PrintName::VOID;
+ //~^ ERROR erroneous constant used
+}
diff --git a/src/test/ui/consts/const-eval/panic-assoc-never-type.stderr b/src/test/ui/consts/const-eval/panic-assoc-never-type.stderr
new file mode 100644
index 0000000..c07c8c6
--- /dev/null
+++ b/src/test/ui/consts/const-eval/panic-assoc-never-type.stderr
@@ -0,0 +1,24 @@
+warning: any use of this value will cause an error
+ --> $DIR/panic-assoc-never-type.rs:8:21
+ |
+LL | const VOID: ! = panic!();
+ | ----------------^^^^^^^^-
+ | |
+ | the evaluated program panicked at 'explicit panic', $DIR/panic-assoc-never-type.rs:8:21
+ |
+note: lint level defined here
+ --> $DIR/panic-assoc-never-type.rs:2:9
+ |
+LL | #![warn(const_err)]
+ | ^^^^^^^^^
+ = note: this warning originates in a macro outside of the current crate (in Nightly builds, run with -Z external-macro-backtrace for more info)
+
+error[E0080]: erroneous constant used
+ --> $DIR/panic-assoc-never-type.rs:13:13
+ |
+LL | let _ = PrintName::VOID;
+ | ^^^^^^^^^^^^^^^ referenced constant has errors
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0080`.
diff --git a/src/test/ui/consts/const-eval/panic-never-type.rs b/src/test/ui/consts/const-eval/panic-never-type.rs
new file mode 100644
index 0000000..42eabbf
--- /dev/null
+++ b/src/test/ui/consts/const-eval/panic-never-type.rs
@@ -0,0 +1,11 @@
+// Regression test for #66975
+#![warn(const_err)]
+#![feature(const_panic)]
+
+const VOID: ! = panic!();
+//~^ WARN any use of this value will cause an error
+
+fn main() {
+ let _ = VOID;
+ //~^ ERROR erroneous constant used
+}
diff --git a/src/test/ui/consts/const-eval/panic-never-type.stderr b/src/test/ui/consts/const-eval/panic-never-type.stderr
new file mode 100644
index 0000000..4fb11a6
--- /dev/null
+++ b/src/test/ui/consts/const-eval/panic-never-type.stderr
@@ -0,0 +1,24 @@
+warning: any use of this value will cause an error
+ --> $DIR/panic-never-type.rs:5:17
+ |
+LL | const VOID: ! = panic!();
+ | ----------------^^^^^^^^-
+ | |
+ | the evaluated program panicked at 'explicit panic', $DIR/panic-never-type.rs:5:17
+ |
+note: lint level defined here
+ --> $DIR/panic-never-type.rs:2:9
+ |
+LL | #![warn(const_err)]
+ | ^^^^^^^^^
+ = note: this warning originates in a macro outside of the current crate (in Nightly builds, run with -Z external-macro-backtrace for more info)
+
+error[E0080]: erroneous constant used
+ --> $DIR/panic-never-type.rs:9:13
+ |
+LL | let _ = VOID;
+ | ^^^^ referenced constant has errors
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0080`.
diff --git a/src/test/ui/consts/const-eval/promoted_errors.rs b/src/test/ui/consts/const-eval/promoted_errors.rs
index 4594139..dfa6863 100644
--- a/src/test/ui/consts/const-eval/promoted_errors.rs
+++ b/src/test/ui/consts/const-eval/promoted_errors.rs
@@ -8,14 +8,12 @@
//~^ ERROR const_err
println!("{}", 1/(1-1));
//~^ ERROR attempt to divide by zero [const_err]
- //~| ERROR reaching this expression at runtime will panic or abort [const_err]
+ //~| ERROR const_err
let _x = 1/(1-1);
//~^ ERROR const_err
- //~| ERROR const_err
println!("{}", 1/(false as u32));
//~^ ERROR attempt to divide by zero [const_err]
- //~| ERROR reaching this expression at runtime will panic or abort [const_err]
+ //~| ERROR const_err
let _x = 1/(false as u32);
//~^ ERROR const_err
- //~| ERROR const_err
}
diff --git a/src/test/ui/consts/const-eval/promoted_errors.stderr b/src/test/ui/consts/const-eval/promoted_errors.stderr
index 40d5c73..848a880 100644
--- a/src/test/ui/consts/const-eval/promoted_errors.stderr
+++ b/src/test/ui/consts/const-eval/promoted_errors.stderr
@@ -20,7 +20,7 @@
--> $DIR/promoted_errors.rs:9:20
|
LL | println!("{}", 1/(1-1));
- | ^^^^^^^ attempt to divide by zero
+ | ^^^^^^^ dividing by zero
error: attempt to divide by zero
--> $DIR/promoted_errors.rs:12:14
@@ -28,35 +28,23 @@
LL | let _x = 1/(1-1);
| ^^^^^^^
-error: this expression will panic at runtime
- --> $DIR/promoted_errors.rs:12:14
- |
-LL | let _x = 1/(1-1);
- | ^^^^^^^ attempt to divide by zero
-
error: attempt to divide by zero
- --> $DIR/promoted_errors.rs:15:20
+ --> $DIR/promoted_errors.rs:14:20
|
LL | println!("{}", 1/(false as u32));
| ^^^^^^^^^^^^^^^^
error: reaching this expression at runtime will panic or abort
- --> $DIR/promoted_errors.rs:15:20
+ --> $DIR/promoted_errors.rs:14:20
|
LL | println!("{}", 1/(false as u32));
- | ^^^^^^^^^^^^^^^^ attempt to divide by zero
+ | ^^^^^^^^^^^^^^^^ dividing by zero
error: attempt to divide by zero
- --> $DIR/promoted_errors.rs:18:14
+ --> $DIR/promoted_errors.rs:17:14
|
LL | let _x = 1/(false as u32);
| ^^^^^^^^^^^^^^^^
-error: this expression will panic at runtime
- --> $DIR/promoted_errors.rs:18:14
- |
-LL | let _x = 1/(false as u32);
- | ^^^^^^^^^^^^^^^^ attempt to divide by zero
-
-error: aborting due to 9 previous errors
+error: aborting due to 7 previous errors
diff --git a/src/test/ui/consts/const-eval/promoted_errors2.rs b/src/test/ui/consts/const-eval/promoted_errors2.rs
index 7adb394..58b1794 100644
--- a/src/test/ui/consts/const-eval/promoted_errors2.rs
+++ b/src/test/ui/consts/const-eval/promoted_errors2.rs
@@ -9,14 +9,12 @@
//~^ ERROR attempt to subtract with overflow
println!("{}", 1/(1-1));
//~^ ERROR attempt to divide by zero [const_err]
- //~| ERROR reaching this expression at runtime will panic or abort [const_err]
+ //~| ERROR const_err
let _x = 1/(1-1);
//~^ ERROR const_err
- //~| ERROR const_err
println!("{}", 1/(false as u32));
//~^ ERROR attempt to divide by zero [const_err]
- //~| ERROR reaching this expression at runtime will panic or abort [const_err]
+ //~| ERROR const_err
let _x = 1/(false as u32);
//~^ ERROR const_err
- //~| ERROR const_err
}
diff --git a/src/test/ui/consts/const-eval/promoted_errors2.stderr b/src/test/ui/consts/const-eval/promoted_errors2.stderr
index 2819e6e..6f4b1c0 100644
--- a/src/test/ui/consts/const-eval/promoted_errors2.stderr
+++ b/src/test/ui/consts/const-eval/promoted_errors2.stderr
@@ -26,7 +26,7 @@
--> $DIR/promoted_errors2.rs:10:20
|
LL | println!("{}", 1/(1-1));
- | ^^^^^^^ attempt to divide by zero
+ | ^^^^^^^ dividing by zero
error: attempt to divide by zero
--> $DIR/promoted_errors2.rs:13:14
@@ -34,35 +34,23 @@
LL | let _x = 1/(1-1);
| ^^^^^^^
-error: this expression will panic at runtime
- --> $DIR/promoted_errors2.rs:13:14
- |
-LL | let _x = 1/(1-1);
- | ^^^^^^^ attempt to divide by zero
-
error: attempt to divide by zero
- --> $DIR/promoted_errors2.rs:16:20
+ --> $DIR/promoted_errors2.rs:15:20
|
LL | println!("{}", 1/(false as u32));
| ^^^^^^^^^^^^^^^^
error: reaching this expression at runtime will panic or abort
- --> $DIR/promoted_errors2.rs:16:20
+ --> $DIR/promoted_errors2.rs:15:20
|
LL | println!("{}", 1/(false as u32));
- | ^^^^^^^^^^^^^^^^ attempt to divide by zero
+ | ^^^^^^^^^^^^^^^^ dividing by zero
error: attempt to divide by zero
- --> $DIR/promoted_errors2.rs:19:14
+ --> $DIR/promoted_errors2.rs:18:14
|
LL | let _x = 1/(false as u32);
| ^^^^^^^^^^^^^^^^
-error: this expression will panic at runtime
- --> $DIR/promoted_errors2.rs:19:14
- |
-LL | let _x = 1/(false as u32);
- | ^^^^^^^^^^^^^^^^ attempt to divide by zero
-
-error: aborting due to 10 previous errors
+error: aborting due to 8 previous errors
diff --git a/src/test/ui/consts/const-multi-ref.stderr b/src/test/ui/consts/const-multi-ref.stderr
index ed3837e..0809c77 100644
--- a/src/test/ui/consts/const-multi-ref.stderr
+++ b/src/test/ui/consts/const-multi-ref.stderr
@@ -1,8 +1,11 @@
-error[E0017]: references in constants may only refer to immutable values
+error[E0658]: references in constants may only refer to immutable values
--> $DIR/const-multi-ref.rs:6:13
|
LL | let p = &mut a;
| ^^^^^^ constants require immutable values
+ |
+ = note: for more information, see https://github.com/rust-lang/rust/issues/57349
+ = help: add `#![feature(const_mut_refs)]` to the crate attributes to enable
error[E0492]: cannot borrow a constant which may contain interior mutability, create a static instead
--> $DIR/const-multi-ref.rs:16:13
@@ -12,5 +15,5 @@
error: aborting due to 2 previous errors
-Some errors have detailed explanations: E0017, E0492.
-For more information about an error, try `rustc --explain E0017`.
+Some errors have detailed explanations: E0492, E0658.
+For more information about an error, try `rustc --explain E0492`.
diff --git a/src/test/ui/consts/const-mut-refs/const_mut_refs.rs b/src/test/ui/consts/const-mut-refs/const_mut_refs.rs
new file mode 100644
index 0000000..33abfec
--- /dev/null
+++ b/src/test/ui/consts/const-mut-refs/const_mut_refs.rs
@@ -0,0 +1,37 @@
+// run-pass
+
+#![feature(const_mut_refs)]
+#![feature(const_fn)]
+
+struct Foo {
+ x: usize
+}
+
+const fn foo() -> Foo {
+ Foo { x: 0 }
+}
+
+impl Foo {
+ const fn bar(&mut self) -> usize {
+ self.x = 1;
+ self.x
+ }
+
+}
+
+const fn baz(foo: &mut Foo) -> usize {
+ let x = &mut foo.x;
+ *x = 2;
+ *x
+}
+
+const fn bazz(foo: &mut Foo) -> usize {
+ foo.x = 3;
+ foo.x
+}
+
+fn main() {
+ let _: [(); foo().bar()] = [(); 1];
+ let _: [(); baz(&mut foo())] = [(); 2];
+ let _: [(); bazz(&mut foo())] = [(); 3];
+}
diff --git a/src/test/ui/consts/const-mut-refs/feature-gate-const_mut_refs.rs b/src/test/ui/consts/const-mut-refs/feature-gate-const_mut_refs.rs
new file mode 100644
index 0000000..2207599
--- /dev/null
+++ b/src/test/ui/consts/const-mut-refs/feature-gate-const_mut_refs.rs
@@ -0,0 +1,7 @@
+fn main() {
+ foo(&mut 5);
+}
+
+const fn foo(x: &mut i32) -> i32 { //~ ERROR mutable references in const fn are unstable
+ *x + 1
+}
diff --git a/src/test/ui/consts/const-mut-refs/feature-gate-const_mut_refs.stderr b/src/test/ui/consts/const-mut-refs/feature-gate-const_mut_refs.stderr
new file mode 100644
index 0000000..4fae119
--- /dev/null
+++ b/src/test/ui/consts/const-mut-refs/feature-gate-const_mut_refs.stderr
@@ -0,0 +1,12 @@
+error[E0723]: mutable references in const fn are unstable
+ --> $DIR/feature-gate-const_mut_refs.rs:5:14
+ |
+LL | const fn foo(x: &mut i32) -> i32 {
+ | ^
+ |
+ = note: for more information, see issue https://github.com/rust-lang/rust/issues/57563
+ = help: add `#![feature(const_fn)]` to the crate attributes to enable
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0723`.
diff --git a/src/test/ui/consts/const-prop-ice.rs b/src/test/ui/consts/const-prop-ice.rs
index 48c4b7d..13309f9 100644
--- a/src/test/ui/consts/const-prop-ice.rs
+++ b/src/test/ui/consts/const-prop-ice.rs
@@ -1,4 +1,3 @@
fn main() {
[0; 3][3u64 as usize]; //~ ERROR the len is 3 but the index is 3
- //~| ERROR this expression will panic at runtime
}
diff --git a/src/test/ui/consts/const-prop-ice.stderr b/src/test/ui/consts/const-prop-ice.stderr
index 8ecc6f4..4b38801 100644
--- a/src/test/ui/consts/const-prop-ice.stderr
+++ b/src/test/ui/consts/const-prop-ice.stderr
@@ -6,11 +6,5 @@
|
= note: `#[deny(const_err)]` on by default
-error: this expression will panic at runtime
- --> $DIR/const-prop-ice.rs:2:5
- |
-LL | [0; 3][3u64 as usize];
- | ^^^^^^^^^^^^^^^^^^^^^ index out of bounds: the len is 3 but the index is 3
-
-error: aborting due to 2 previous errors
+error: aborting due to previous error
diff --git a/src/test/ui/consts/const_let_assign3.stderr b/src/test/ui/consts/const_let_assign3.stderr
index 53b960b..7852874 100644
--- a/src/test/ui/consts/const_let_assign3.stderr
+++ b/src/test/ui/consts/const_let_assign3.stderr
@@ -4,17 +4,23 @@
LL | self.state = x;
| ^^^^^^^^^^^^^^
-error[E0017]: references in constants may only refer to immutable values
+error[E0658]: references in constants may only refer to immutable values
--> $DIR/const_let_assign3.rs:16:5
|
LL | s.foo(3);
| ^ constants require immutable values
+ |
+ = note: for more information, see https://github.com/rust-lang/rust/issues/57349
+ = help: add `#![feature(const_mut_refs)]` to the crate attributes to enable
-error[E0017]: references in constants may only refer to immutable values
+error[E0658]: references in constants may only refer to immutable values
--> $DIR/const_let_assign3.rs:22:13
|
LL | let y = &mut x;
| ^^^^^^ constants require immutable values
+ |
+ = note: for more information, see https://github.com/rust-lang/rust/issues/57349
+ = help: add `#![feature(const_mut_refs)]` to the crate attributes to enable
error[E0019]: constant contains unimplemented expression type
--> $DIR/const_let_assign3.rs:24:5
@@ -24,5 +30,5 @@
error: aborting due to 4 previous errors
-Some errors have detailed explanations: E0017, E0019.
-For more information about an error, try `rustc --explain E0017`.
+Some errors have detailed explanations: E0019, E0658.
+For more information about an error, try `rustc --explain E0019`.
diff --git a/src/test/ui/consts/control-flow/basics.rs b/src/test/ui/consts/control-flow/basics.rs
index 8bd1929..b9ff040 100644
--- a/src/test/ui/consts/control-flow/basics.rs
+++ b/src/test/ui/consts/control-flow/basics.rs
@@ -4,6 +4,7 @@
#![feature(const_panic)]
#![feature(const_if_match)]
+#![feature(const_fn)]
const X: u32 = 4;
const Y: u32 = 5;
diff --git a/src/test/ui/consts/control-flow/exhaustive-c-like-enum-match.rs b/src/test/ui/consts/control-flow/exhaustive-c-like-enum-match.rs
index 6bbbdd9..7887fd1 100644
--- a/src/test/ui/consts/control-flow/exhaustive-c-like-enum-match.rs
+++ b/src/test/ui/consts/control-flow/exhaustive-c-like-enum-match.rs
@@ -3,6 +3,7 @@
// check-pass
#![feature(const_if_match)]
+#![feature(const_fn)]
enum E {
A,
diff --git a/src/test/ui/consts/control-flow/feature-gate-const-if-match.if_match.stderr b/src/test/ui/consts/control-flow/feature-gate-const-if-match.if_match.stderr
index 21e3f2a..9509672 100644
--- a/src/test/ui/consts/control-flow/feature-gate-const-if-match.if_match.stderr
+++ b/src/test/ui/consts/control-flow/feature-gate-const-if-match.if_match.stderr
@@ -1,5 +1,5 @@
error: fatal error triggered by #[rustc_error]
- --> $DIR/feature-gate-const-if-match.rs:108:1
+ --> $DIR/feature-gate-const-if-match.rs:109:1
|
LL | / fn main() {
LL | | let _ = [0; {
diff --git a/src/test/ui/consts/control-flow/feature-gate-const-if-match.rs b/src/test/ui/consts/control-flow/feature-gate-const-if-match.rs
index 00576d5..e4b6525 100644
--- a/src/test/ui/consts/control-flow/feature-gate-const-if-match.rs
+++ b/src/test/ui/consts/control-flow/feature-gate-const-if-match.rs
@@ -6,6 +6,7 @@
#![feature(rustc_attrs)]
#![cfg_attr(if_match, feature(const_if_match))]
+#![feature(const_fn)]
const _: i32 = if true { //[stock]~ ERROR `if` is not allowed in a `const`
5
diff --git a/src/test/ui/consts/control-flow/feature-gate-const-if-match.stock.stderr b/src/test/ui/consts/control-flow/feature-gate-const-if-match.stock.stderr
index d3c6a51..e846ee4 100644
--- a/src/test/ui/consts/control-flow/feature-gate-const-if-match.stock.stderr
+++ b/src/test/ui/consts/control-flow/feature-gate-const-if-match.stock.stderr
@@ -1,5 +1,5 @@
error[E0658]: `if` is not allowed in a `const`
- --> $DIR/feature-gate-const-if-match.rs:10:16
+ --> $DIR/feature-gate-const-if-match.rs:11:16
|
LL | const _: i32 = if true {
| ________________^
@@ -13,7 +13,7 @@
= help: add `#![feature(const_if_match)]` to the crate attributes to enable
error[E0658]: `if` is not allowed in a `const`
- --> $DIR/feature-gate-const-if-match.rs:16:16
+ --> $DIR/feature-gate-const-if-match.rs:17:16
|
LL | const _: i32 = if let Some(true) = Some(false) {
| ________________^
@@ -27,7 +27,7 @@
= help: add `#![feature(const_if_match)]` to the crate attributes to enable
error[E0658]: `match` is not allowed in a `const`
- --> $DIR/feature-gate-const-if-match.rs:22:16
+ --> $DIR/feature-gate-const-if-match.rs:23:16
|
LL | const _: i32 = match 1 {
| ________________^
@@ -41,7 +41,7 @@
= help: add `#![feature(const_if_match)]` to the crate attributes to enable
error[E0658]: `if` is not allowed in a `static`
- --> $DIR/feature-gate-const-if-match.rs:29:13
+ --> $DIR/feature-gate-const-if-match.rs:30:13
|
LL | let x = if true { 0 } else { 1 };
| ^^^^^^^^^^^^^^^^^^^^^^^^
@@ -50,7 +50,7 @@
= help: add `#![feature(const_if_match)]` to the crate attributes to enable
error[E0658]: `match` is not allowed in a `static`
- --> $DIR/feature-gate-const-if-match.rs:31:13
+ --> $DIR/feature-gate-const-if-match.rs:32:13
|
LL | let x = match x { 0 => 1, _ => 0 };
| ^^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -59,7 +59,7 @@
= help: add `#![feature(const_if_match)]` to the crate attributes to enable
error[E0658]: `if` is not allowed in a `static`
- --> $DIR/feature-gate-const-if-match.rs:33:5
+ --> $DIR/feature-gate-const-if-match.rs:34:5
|
LL | if let Some(x) = Some(x) { x } else { 1 }
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -68,7 +68,7 @@
= help: add `#![feature(const_if_match)]` to the crate attributes to enable
error[E0658]: `if` is not allowed in a `static mut`
- --> $DIR/feature-gate-const-if-match.rs:38:13
+ --> $DIR/feature-gate-const-if-match.rs:39:13
|
LL | let x = if true { 0 } else { 1 };
| ^^^^^^^^^^^^^^^^^^^^^^^^
@@ -77,7 +77,7 @@
= help: add `#![feature(const_if_match)]` to the crate attributes to enable
error[E0658]: `match` is not allowed in a `static mut`
- --> $DIR/feature-gate-const-if-match.rs:40:13
+ --> $DIR/feature-gate-const-if-match.rs:41:13
|
LL | let x = match x { 0 => 1, _ => 0 };
| ^^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -86,7 +86,7 @@
= help: add `#![feature(const_if_match)]` to the crate attributes to enable
error[E0658]: `if` is not allowed in a `static mut`
- --> $DIR/feature-gate-const-if-match.rs:42:5
+ --> $DIR/feature-gate-const-if-match.rs:43:5
|
LL | if let Some(x) = Some(x) { x } else { 1 }
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -95,7 +95,7 @@
= help: add `#![feature(const_if_match)]` to the crate attributes to enable
error[E0658]: `if` is not allowed in a `const fn`
- --> $DIR/feature-gate-const-if-match.rs:47:5
+ --> $DIR/feature-gate-const-if-match.rs:48:5
|
LL | if true { 5 } else { 6 }
| ^^^^^^^^^^^^^^^^^^^^^^^^
@@ -104,7 +104,7 @@
= help: add `#![feature(const_if_match)]` to the crate attributes to enable
error[E0658]: `if` is not allowed in a `const fn`
- --> $DIR/feature-gate-const-if-match.rs:51:5
+ --> $DIR/feature-gate-const-if-match.rs:52:5
|
LL | / if let Some(true) = a {
LL | | 0
@@ -117,7 +117,7 @@
= help: add `#![feature(const_if_match)]` to the crate attributes to enable
error[E0658]: `match` is not allowed in a `const fn`
- --> $DIR/feature-gate-const-if-match.rs:59:5
+ --> $DIR/feature-gate-const-if-match.rs:60:5
|
LL | / match i {
LL | | i if i > 10 => i,
@@ -130,7 +130,7 @@
= help: add `#![feature(const_if_match)]` to the crate attributes to enable
error[E0658]: `if` is not allowed in a `const fn`
- --> $DIR/feature-gate-const-if-match.rs:90:17
+ --> $DIR/feature-gate-const-if-match.rs:91:17
|
LL | let x = if y { 0 } else { 1 };
| ^^^^^^^^^^^^^^^^^^^^^
@@ -139,7 +139,7 @@
= help: add `#![feature(const_if_match)]` to the crate attributes to enable
error[E0658]: `match` is not allowed in a `const fn`
- --> $DIR/feature-gate-const-if-match.rs:92:17
+ --> $DIR/feature-gate-const-if-match.rs:93:17
|
LL | let x = match x { 0 => 1, _ => 0 };
| ^^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -148,7 +148,7 @@
= help: add `#![feature(const_if_match)]` to the crate attributes to enable
error[E0658]: `if` is not allowed in a `const fn`
- --> $DIR/feature-gate-const-if-match.rs:94:9
+ --> $DIR/feature-gate-const-if-match.rs:95:9
|
LL | if let Some(x) = Some(x) { x } else { 1 }
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -157,7 +157,7 @@
= help: add `#![feature(const_if_match)]` to the crate attributes to enable
error[E0658]: `if` is not allowed in a `const`
- --> $DIR/feature-gate-const-if-match.rs:110:17
+ --> $DIR/feature-gate-const-if-match.rs:111:17
|
LL | let x = if false { 0 } else { 1 };
| ^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -166,7 +166,7 @@
= help: add `#![feature(const_if_match)]` to the crate attributes to enable
error[E0658]: `match` is not allowed in a `const`
- --> $DIR/feature-gate-const-if-match.rs:112:17
+ --> $DIR/feature-gate-const-if-match.rs:113:17
|
LL | let x = match x { 0 => 1, _ => 0 };
| ^^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -175,7 +175,7 @@
= help: add `#![feature(const_if_match)]` to the crate attributes to enable
error[E0658]: `if` is not allowed in a `const`
- --> $DIR/feature-gate-const-if-match.rs:114:9
+ --> $DIR/feature-gate-const-if-match.rs:115:9
|
LL | if let Some(x) = Some(x) { x } else { 1 }
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -184,7 +184,7 @@
= help: add `#![feature(const_if_match)]` to the crate attributes to enable
error[E0658]: `if` is not allowed in a `const`
- --> $DIR/feature-gate-const-if-match.rs:67:21
+ --> $DIR/feature-gate-const-if-match.rs:68:21
|
LL | const IF: i32 = if true { 5 } else { 6 };
| ^^^^^^^^^^^^^^^^^^^^^^^^
@@ -193,7 +193,7 @@
= help: add `#![feature(const_if_match)]` to the crate attributes to enable
error[E0658]: `if` is not allowed in a `const`
- --> $DIR/feature-gate-const-if-match.rs:70:25
+ --> $DIR/feature-gate-const-if-match.rs:71:25
|
LL | const IF_LET: i32 = if let Some(true) = None { 5 } else { 6 };
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -202,7 +202,7 @@
= help: add `#![feature(const_if_match)]` to the crate attributes to enable
error[E0658]: `match` is not allowed in a `const`
- --> $DIR/feature-gate-const-if-match.rs:73:24
+ --> $DIR/feature-gate-const-if-match.rs:74:24
|
LL | const MATCH: i32 = match 0 { 1 => 2, _ => 0 };
| ^^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -211,7 +211,7 @@
= help: add `#![feature(const_if_match)]` to the crate attributes to enable
error[E0658]: `if` is not allowed in a `const`
- --> $DIR/feature-gate-const-if-match.rs:78:21
+ --> $DIR/feature-gate-const-if-match.rs:79:21
|
LL | const IF: i32 = if true { 5 } else { 6 };
| ^^^^^^^^^^^^^^^^^^^^^^^^
@@ -220,7 +220,7 @@
= help: add `#![feature(const_if_match)]` to the crate attributes to enable
error[E0658]: `if` is not allowed in a `const`
- --> $DIR/feature-gate-const-if-match.rs:81:25
+ --> $DIR/feature-gate-const-if-match.rs:82:25
|
LL | const IF_LET: i32 = if let Some(true) = None { 5 } else { 6 };
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -229,7 +229,7 @@
= help: add `#![feature(const_if_match)]` to the crate attributes to enable
error[E0658]: `match` is not allowed in a `const`
- --> $DIR/feature-gate-const-if-match.rs:84:24
+ --> $DIR/feature-gate-const-if-match.rs:85:24
|
LL | const MATCH: i32 = match 0 { 1 => 2, _ => 0 };
| ^^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -238,7 +238,7 @@
= help: add `#![feature(const_if_match)]` to the crate attributes to enable
error[E0019]: constant contains unimplemented expression type
- --> $DIR/feature-gate-const-if-match.rs:114:21
+ --> $DIR/feature-gate-const-if-match.rs:115:21
|
LL | if let Some(x) = Some(x) { x } else { 1 }
| ^
diff --git a/src/test/ui/consts/control-flow/short-circuit-let.rs b/src/test/ui/consts/control-flow/short-circuit-let.rs
index 8cee2a5..4b20a21 100644
--- a/src/test/ui/consts/control-flow/short-circuit-let.rs
+++ b/src/test/ui/consts/control-flow/short-circuit-let.rs
@@ -4,6 +4,7 @@
#![feature(const_if_match)]
#![feature(const_panic)]
+#![feature(const_fn)]
const X: i32 = {
let mut x = 0;
diff --git a/src/test/ui/consts/control-flow/single_variant_match_ice.rs b/src/test/ui/consts/control-flow/single_variant_match_ice.rs
index 823605f..bb0fce6 100644
--- a/src/test/ui/consts/control-flow/single_variant_match_ice.rs
+++ b/src/test/ui/consts/control-flow/single_variant_match_ice.rs
@@ -1,6 +1,6 @@
// check-pass
-#![feature(const_if_match)]
+#![feature(const_if_match, const_fn)]
enum Foo {
Prob,
diff --git a/src/test/ui/consts/issue-64662.stderr b/src/test/ui/consts/issue-64662.stderr
index b81daae..b3c673e 100644
--- a/src/test/ui/consts/issue-64662.stderr
+++ b/src/test/ui/consts/issue-64662.stderr
@@ -2,13 +2,13 @@
--> $DIR/issue-64662.rs:2:9
|
LL | A = foo(),
- | ^^^ cannot infer type for `T`
+ | ^^^ cannot infer type for type parameter `T`
error[E0282]: type annotations needed
--> $DIR/issue-64662.rs:3:9
|
LL | B = foo(),
- | ^^^ cannot infer type for `T`
+ | ^^^ cannot infer type for type parameter `T`
error: aborting due to 2 previous errors
diff --git a/src/test/ui/consts/miri_unleashed/mutable_const.rs b/src/test/ui/consts/miri_unleashed/mutable_const.rs
index 44b4084..972f595 100644
--- a/src/test/ui/consts/miri_unleashed/mutable_const.rs
+++ b/src/test/ui/consts/miri_unleashed/mutable_const.rs
@@ -1,6 +1,7 @@
// compile-flags: -Zunleash-the-miri-inside-of-you
#![feature(const_raw_ptr_deref)]
+#![feature(const_mut_refs)]
#![deny(const_err)]
use std::cell::UnsafeCell;
@@ -12,9 +13,7 @@
const MUTATING_BEHIND_RAW: () = {
// Test that `MUTABLE_BEHIND_RAW` is actually immutable, by doing this at const time.
unsafe {
- *MUTABLE_BEHIND_RAW = 99 //~ WARN skipping const checks
- //~^ ERROR any use of this value will cause an error
- //~^^ tried to modify constant memory
+ *MUTABLE_BEHIND_RAW = 99 //~ ERROR any use of this value will cause an error
}
};
diff --git a/src/test/ui/consts/miri_unleashed/mutable_const.stderr b/src/test/ui/consts/miri_unleashed/mutable_const.stderr
index 757f0ff..9daca76 100644
--- a/src/test/ui/consts/miri_unleashed/mutable_const.stderr
+++ b/src/test/ui/consts/miri_unleashed/mutable_const.stderr
@@ -1,30 +1,23 @@
warning: skipping const checks
- --> $DIR/mutable_const.rs:9:38
+ --> $DIR/mutable_const.rs:10:38
|
LL | const MUTABLE_BEHIND_RAW: *mut i32 = &UnsafeCell::new(42) as *const _ as *mut _;
| ^^^^^^^^^^^^^^^^^^^^
-warning: skipping const checks
- --> $DIR/mutable_const.rs:15:9
- |
-LL | *MUTABLE_BEHIND_RAW = 99
- | ^^^^^^^^^^^^^^^^^^^^^^^^
-
error: any use of this value will cause an error
- --> $DIR/mutable_const.rs:15:9
+ --> $DIR/mutable_const.rs:16:9
|
LL | / const MUTATING_BEHIND_RAW: () = {
LL | | // Test that `MUTABLE_BEHIND_RAW` is actually immutable, by doing this at const time.
LL | | unsafe {
LL | | *MUTABLE_BEHIND_RAW = 99
| | ^^^^^^^^^^^^^^^^^^^^^^^^ tried to modify constant memory
-... |
LL | | }
LL | | };
| |__-
|
note: lint level defined here
- --> $DIR/mutable_const.rs:4:9
+ --> $DIR/mutable_const.rs:5:9
|
LL | #![deny(const_err)]
| ^^^^^^^^^
diff --git a/src/test/ui/consts/miri_unleashed/mutable_references.rs b/src/test/ui/consts/miri_unleashed/mutable_references.rs
index 59dafcb..fe3c4ee 100644
--- a/src/test/ui/consts/miri_unleashed/mutable_references.rs
+++ b/src/test/ui/consts/miri_unleashed/mutable_references.rs
@@ -1,20 +1,22 @@
// compile-flags: -Zunleash-the-miri-inside-of-you
+#![feature(const_mut_refs)]
#![allow(const_err)]
use std::cell::UnsafeCell;
// a test demonstrating what things we could allow with a smarter const qualification
+// this is fine because is not possible to mutate through an immutable reference.
static FOO: &&mut u32 = &&mut 42;
-//~^ WARN: skipping const checks
+// this is fine because accessing an immutable static `BAR` is equivalent to accessing `*&BAR`
+// which puts the mutable reference behind an immutable one.
static BAR: &mut () = &mut ();
-//~^ WARN: skipping const checks
struct Foo<T>(T);
+// this is fine for the same reason as `BAR`.
static BOO: &mut Foo<()> = &mut Foo(());
-//~^ WARN: skipping const checks
struct Meh {
x: &'static UnsafeCell<i32>,
@@ -27,8 +29,8 @@
//~^ WARN: skipping const checks
};
+// this is fine for the same reason as `BAR`.
static OH_YES: &mut i32 = &mut 42;
-//~^ WARN: skipping const checks
fn main() {
unsafe {
diff --git a/src/test/ui/consts/miri_unleashed/mutable_references.stderr b/src/test/ui/consts/miri_unleashed/mutable_references.stderr
index b9c0af3..3e1300c 100644
--- a/src/test/ui/consts/miri_unleashed/mutable_references.stderr
+++ b/src/test/ui/consts/miri_unleashed/mutable_references.stderr
@@ -1,35 +1,11 @@
warning: skipping const checks
- --> $DIR/mutable_references.rs:8:26
- |
-LL | static FOO: &&mut u32 = &&mut 42;
- | ^^^^^^^
-
-warning: skipping const checks
- --> $DIR/mutable_references.rs:11:23
- |
-LL | static BAR: &mut () = &mut ();
- | ^^^^^^^
-
-warning: skipping const checks
- --> $DIR/mutable_references.rs:16:28
- |
-LL | static BOO: &mut Foo<()> = &mut Foo(());
- | ^^^^^^^^^^^^
-
-warning: skipping const checks
- --> $DIR/mutable_references.rs:26:8
+ --> $DIR/mutable_references.rs:28:8
|
LL | x: &UnsafeCell::new(42),
| ^^^^^^^^^^^^^^^^^^^^
-warning: skipping const checks
- --> $DIR/mutable_references.rs:30:27
- |
-LL | static OH_YES: &mut i32 = &mut 42;
- | ^^^^^^^
-
error[E0594]: cannot assign to `*OH_YES`, as `OH_YES` is an immutable static item
- --> $DIR/mutable_references.rs:37:5
+ --> $DIR/mutable_references.rs:39:5
|
LL | *OH_YES = 99;
| ^^^^^^^^^^^^ cannot assign
diff --git a/src/test/ui/consts/miri_unleashed/read_from_static.rs b/src/test/ui/consts/miri_unleashed/read_from_static.rs
new file mode 100644
index 0000000..821c501
--- /dev/null
+++ b/src/test/ui/consts/miri_unleashed/read_from_static.rs
@@ -0,0 +1,11 @@
+// run-pass
+// compile-flags: -Zunleash-the-miri-inside-of-you
+#![feature(const_mut_refs)]
+#![allow(const_err)]
+
+static OH_YES: &mut i32 = &mut 42;
+
+fn main() {
+ // Make sure `OH_YES` can be read.
+ assert_eq!(*OH_YES, 42);
+}
diff --git a/src/test/ui/consts/projection_qualif.mut_refs.stderr b/src/test/ui/consts/projection_qualif.mut_refs.stderr
new file mode 100644
index 0000000..2353877
--- /dev/null
+++ b/src/test/ui/consts/projection_qualif.mut_refs.stderr
@@ -0,0 +1,12 @@
+error[E0658]: dereferencing raw pointers in constants is unstable
+ --> $DIR/projection_qualif.rs:11:18
+ |
+LL | unsafe { *b = 5; }
+ | ^^^^^^
+ |
+ = note: for more information, see https://github.com/rust-lang/rust/issues/51911
+ = help: add `#![feature(const_raw_ptr_deref)]` to the crate attributes to enable
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0658`.
diff --git a/src/test/ui/consts/projection_qualif.rs b/src/test/ui/consts/projection_qualif.rs
index dedb7db..cfe8e7f 100644
--- a/src/test/ui/consts/projection_qualif.rs
+++ b/src/test/ui/consts/projection_qualif.rs
@@ -1,11 +1,15 @@
+// revisions: stock mut_refs
+
+#![cfg_attr(mut_refs, feature(const_mut_refs))]
+
use std::cell::Cell;
const FOO: &u32 = {
let mut a = 42;
{
- let b: *mut u32 = &mut a; //~ ERROR may only refer to immutable values
+ let b: *mut u32 = &mut a; //[stock]~ ERROR may only refer to immutable values
unsafe { *b = 5; } //~ ERROR dereferencing raw pointers in constants
- //~^ contains unimplemented expression
+ //[stock]~^ contains unimplemented expression
}
&{a}
};
diff --git a/src/test/ui/consts/projection_qualif.stderr b/src/test/ui/consts/projection_qualif.stderr
deleted file mode 100644
index 0efb6bf..0000000
--- a/src/test/ui/consts/projection_qualif.stderr
+++ /dev/null
@@ -1,25 +0,0 @@
-error[E0017]: references in constants may only refer to immutable values
- --> $DIR/projection_qualif.rs:6:27
- |
-LL | let b: *mut u32 = &mut a;
- | ^^^^^^ constants require immutable values
-
-error[E0658]: dereferencing raw pointers in constants is unstable
- --> $DIR/projection_qualif.rs:7:18
- |
-LL | unsafe { *b = 5; }
- | ^^^^^^
- |
- = note: for more information, see https://github.com/rust-lang/rust/issues/51911
- = help: add `#![feature(const_raw_ptr_deref)]` to the crate attributes to enable
-
-error[E0019]: constant contains unimplemented expression type
- --> $DIR/projection_qualif.rs:7:18
- |
-LL | unsafe { *b = 5; }
- | ^^^^^^
-
-error: aborting due to 3 previous errors
-
-Some errors have detailed explanations: E0017, E0019, E0658.
-For more information about an error, try `rustc --explain E0017`.
diff --git a/src/test/ui/consts/projection_qualif.stock.stderr b/src/test/ui/consts/projection_qualif.stock.stderr
new file mode 100644
index 0000000..472d260
--- /dev/null
+++ b/src/test/ui/consts/projection_qualif.stock.stderr
@@ -0,0 +1,28 @@
+error[E0658]: references in constants may only refer to immutable values
+ --> $DIR/projection_qualif.rs:10:27
+ |
+LL | let b: *mut u32 = &mut a;
+ | ^^^^^^ constants require immutable values
+ |
+ = note: for more information, see https://github.com/rust-lang/rust/issues/57349
+ = help: add `#![feature(const_mut_refs)]` to the crate attributes to enable
+
+error[E0658]: dereferencing raw pointers in constants is unstable
+ --> $DIR/projection_qualif.rs:11:18
+ |
+LL | unsafe { *b = 5; }
+ | ^^^^^^
+ |
+ = note: for more information, see https://github.com/rust-lang/rust/issues/51911
+ = help: add `#![feature(const_raw_ptr_deref)]` to the crate attributes to enable
+
+error[E0019]: constant contains unimplemented expression type
+ --> $DIR/projection_qualif.rs:11:18
+ |
+LL | unsafe { *b = 5; }
+ | ^^^^^^
+
+error: aborting due to 3 previous errors
+
+Some errors have detailed explanations: E0019, E0658.
+For more information about an error, try `rustc --explain E0019`.
diff --git a/src/test/ui/consts/static_mut_containing_mut_ref2.mut_refs.stderr b/src/test/ui/consts/static_mut_containing_mut_ref2.mut_refs.stderr
new file mode 100644
index 0000000..b43fbc8
--- /dev/null
+++ b/src/test/ui/consts/static_mut_containing_mut_ref2.mut_refs.stderr
@@ -0,0 +1,9 @@
+error[E0080]: could not evaluate static initializer
+ --> $DIR/static_mut_containing_mut_ref2.rs:7:45
+ |
+LL | pub static mut STDERR_BUFFER: () = unsafe { *(&mut STDERR_BUFFER_SPACE) = 42; };
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ tried to modify a static's initial value from another static's initializer
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0080`.
diff --git a/src/test/ui/consts/static_mut_containing_mut_ref2.rs b/src/test/ui/consts/static_mut_containing_mut_ref2.rs
index ef378fa..74162fb 100644
--- a/src/test/ui/consts/static_mut_containing_mut_ref2.rs
+++ b/src/test/ui/consts/static_mut_containing_mut_ref2.rs
@@ -1,7 +1,12 @@
+// revisions: stock mut_refs
+
+#![cfg_attr(mut_refs, feature(const_mut_refs))]
+
static mut STDERR_BUFFER_SPACE: u8 = 0;
pub static mut STDERR_BUFFER: () = unsafe { *(&mut STDERR_BUFFER_SPACE) = 42; };
-//~^ ERROR references in statics may only refer to immutable values
-//~| ERROR static contains unimplemented expression type
+//[mut_refs]~^ ERROR could not evaluate static initializer
+//[stock]~^^ ERROR references in statics may only refer to immutable values
+//[stock]~| ERROR static contains unimplemented expression type
fn main() {}
diff --git a/src/test/ui/consts/static_mut_containing_mut_ref2.stderr b/src/test/ui/consts/static_mut_containing_mut_ref2.stderr
deleted file mode 100644
index ca691b0..0000000
--- a/src/test/ui/consts/static_mut_containing_mut_ref2.stderr
+++ /dev/null
@@ -1,16 +0,0 @@
-error[E0017]: references in statics may only refer to immutable values
- --> $DIR/static_mut_containing_mut_ref2.rs:3:46
- |
-LL | pub static mut STDERR_BUFFER: () = unsafe { *(&mut STDERR_BUFFER_SPACE) = 42; };
- | ^^^^^^^^^^^^^^^^^^^^^^^^^^ statics require immutable values
-
-error[E0019]: static contains unimplemented expression type
- --> $DIR/static_mut_containing_mut_ref2.rs:3:45
- |
-LL | pub static mut STDERR_BUFFER: () = unsafe { *(&mut STDERR_BUFFER_SPACE) = 42; };
- | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
-
-error: aborting due to 2 previous errors
-
-Some errors have detailed explanations: E0017, E0019.
-For more information about an error, try `rustc --explain E0017`.
diff --git a/src/test/ui/consts/static_mut_containing_mut_ref2.stock.stderr b/src/test/ui/consts/static_mut_containing_mut_ref2.stock.stderr
new file mode 100644
index 0000000..430cef9
--- /dev/null
+++ b/src/test/ui/consts/static_mut_containing_mut_ref2.stock.stderr
@@ -0,0 +1,19 @@
+error[E0658]: references in statics may only refer to immutable values
+ --> $DIR/static_mut_containing_mut_ref2.rs:7:46
+ |
+LL | pub static mut STDERR_BUFFER: () = unsafe { *(&mut STDERR_BUFFER_SPACE) = 42; };
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^ statics require immutable values
+ |
+ = note: for more information, see https://github.com/rust-lang/rust/issues/57349
+ = help: add `#![feature(const_mut_refs)]` to the crate attributes to enable
+
+error[E0019]: static contains unimplemented expression type
+ --> $DIR/static_mut_containing_mut_ref2.rs:7:45
+ |
+LL | pub static mut STDERR_BUFFER: () = unsafe { *(&mut STDERR_BUFFER_SPACE) = 42; };
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+error: aborting due to 2 previous errors
+
+Some errors have detailed explanations: E0019, E0658.
+For more information about an error, try `rustc --explain E0019`.
diff --git a/src/test/ui/consts/unstable-const-fn-in-libcore.rs b/src/test/ui/consts/unstable-const-fn-in-libcore.rs
new file mode 100644
index 0000000..cad1516
--- /dev/null
+++ b/src/test/ui/consts/unstable-const-fn-in-libcore.rs
@@ -0,0 +1,29 @@
+// This is a non-regression test for const-qualification of unstable items in libcore
+// as explained in issue #67053.
+// const-qualification could miss some `const fn`s if they were unstable and the feature
+// gate was not enabled in libcore.
+
+#![stable(feature = "core", since = "1.6.0")]
+#![feature(const_if_match)]
+#![feature(rustc_const_unstable)]
+#![feature(staged_api)]
+
+enum Opt<T> {
+ Some(T),
+ None,
+}
+
+impl<T> Opt<T> {
+ #[rustc_const_unstable(feature = "foo")]
+ #[stable(feature = "rust1", since = "1.0.0")]
+ const fn unwrap_or_else<F: FnOnce() -> T>(self, f: F) -> T {
+ //~^ ERROR destructors cannot be evaluated at compile-time
+ //~| ERROR destructors cannot be evaluated at compile-time
+ match self {
+ Opt::Some(t) => t,
+ Opt::None => f(), //~ ERROR E0015
+ }
+ }
+}
+
+fn main() {}
diff --git a/src/test/ui/consts/unstable-const-fn-in-libcore.stderr b/src/test/ui/consts/unstable-const-fn-in-libcore.stderr
new file mode 100644
index 0000000..a8455ce
--- /dev/null
+++ b/src/test/ui/consts/unstable-const-fn-in-libcore.stderr
@@ -0,0 +1,22 @@
+error[E0015]: calls in constant functions are limited to constant functions, tuple structs and tuple variants
+ --> $DIR/unstable-const-fn-in-libcore.rs:24:26
+ |
+LL | Opt::None => f(),
+ | ^^^
+
+error[E0493]: destructors cannot be evaluated at compile-time
+ --> $DIR/unstable-const-fn-in-libcore.rs:19:53
+ |
+LL | const fn unwrap_or_else<F: FnOnce() -> T>(self, f: F) -> T {
+ | ^ constant functions cannot evaluate destructors
+
+error[E0493]: destructors cannot be evaluated at compile-time
+ --> $DIR/unstable-const-fn-in-libcore.rs:19:47
+ |
+LL | const fn unwrap_or_else<F: FnOnce() -> T>(self, f: F) -> T {
+ | ^^^^ constant functions cannot evaluate destructors
+
+error: aborting due to 3 previous errors
+
+Some errors have detailed explanations: E0015, E0493.
+For more information about an error, try `rustc --explain E0015`.
diff --git a/src/test/ui/drop/dynamic-drop.rs b/src/test/ui/drop/dynamic-drop.rs
index 29dcbfe..0f0ec0b 100644
--- a/src/test/ui/drop/dynamic-drop.rs
+++ b/src/test/ui/drop/dynamic-drop.rs
@@ -269,6 +269,28 @@
let[_, _y @ ..] = ar;
}
+fn index_field_mixed_ends(a: &Allocator) {
+ let ar = [(a.alloc(), a.alloc()), (a.alloc(), a.alloc())];
+ let[(_x, _), ..] = ar;
+ let[(_, _y), _] = ar;
+ let[_, (_, _w)] = ar;
+ let[.., (_z, _)] = ar;
+}
+
+fn subslice_mixed_min_lengths(a: &Allocator, c: i32) {
+ let ar = [(a.alloc(), a.alloc()), (a.alloc(), a.alloc())];
+ match c {
+ 0 => { let[_x, ..] = ar; }
+ 1 => { let[_x, _, ..] = ar; }
+ 2 => { let[_x, _] = ar; }
+ 3 => { let[(_x, _), _, ..] = ar; }
+ 4 => { let[.., (_x, _)] = ar; }
+ 5 => { let[.., (_x, _), _] = ar; }
+ 6 => { let [_y @ ..] = ar; }
+ _ => { let [_y @ .., _] = ar; }
+ }
+}
+
fn panic_after_return(a: &Allocator) -> Ptr<'_> {
// Panic in the drop of `p` or `q` can leak
let exceptions = vec![8, 9];
@@ -422,6 +444,16 @@
run_test(|a| slice_pattern_reassign(a));
run_test(|a| subslice_pattern_reassign(a));
+ run_test(|a| index_field_mixed_ends(a));
+ run_test(|a| subslice_mixed_min_lengths(a, 0));
+ run_test(|a| subslice_mixed_min_lengths(a, 1));
+ run_test(|a| subslice_mixed_min_lengths(a, 2));
+ run_test(|a| subslice_mixed_min_lengths(a, 3));
+ run_test(|a| subslice_mixed_min_lengths(a, 4));
+ run_test(|a| subslice_mixed_min_lengths(a, 5));
+ run_test(|a| subslice_mixed_min_lengths(a, 6));
+ run_test(|a| subslice_mixed_min_lengths(a, 7));
+
run_test(|a| {
panic_after_return(a);
});
diff --git a/src/test/ui/enum/union-in-enum.rs b/src/test/ui/enum/union-in-enum.rs
new file mode 100644
index 0000000..048913e
--- /dev/null
+++ b/src/test/ui/enum/union-in-enum.rs
@@ -0,0 +1,13 @@
+// This test checks that the union keyword
+// is accepted as the name of an enum variant
+// when not followed by an identifier
+// This special case exists because `union` is a contextual keyword.
+
+#![allow(warnings)]
+
+// check-pass
+
+enum A { union }
+enum B { union {} }
+enum C { union() }
+fn main(){}
diff --git a/src/test/ui/error-codes/E0004-2.stderr b/src/test/ui/error-codes/E0004-2.stderr
index db0a2b5..f5b41cd 100644
--- a/src/test/ui/error-codes/E0004-2.stderr
+++ b/src/test/ui/error-codes/E0004-2.stderr
@@ -1,8 +1,8 @@
-error[E0004]: non-exhaustive patterns: multiple patterns of type `std::option::Option<i32>` are not handled
+error[E0004]: non-exhaustive patterns: `None` and `Some(_)` not covered
--> $DIR/E0004-2.rs:4:11
|
LL | match x { }
- | ^
+ | ^ patterns `None` and `Some(_)` not covered
|
= help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms
diff --git a/src/test/ui/error-codes/E0017.rs b/src/test/ui/error-codes/E0017.rs
index 3bc518c..64be411 100644
--- a/src/test/ui/error-codes/E0017.rs
+++ b/src/test/ui/error-codes/E0017.rs
@@ -2,10 +2,10 @@
const C: i32 = 2;
static mut M: i32 = 3;
-const CR: &'static mut i32 = &mut C; //~ ERROR E0017
-static STATIC_REF: &'static mut i32 = &mut X; //~ ERROR E0017
+const CR: &'static mut i32 = &mut C; //~ ERROR E0658
+static STATIC_REF: &'static mut i32 = &mut X; //~ ERROR E0658
//~| ERROR E0019
//~| ERROR cannot borrow
-static CONST_REF: &'static mut i32 = &mut C; //~ ERROR E0017
-static STATIC_MUT_REF: &'static mut i32 = unsafe { &mut M }; //~ ERROR E0017
+static CONST_REF: &'static mut i32 = &mut C; //~ ERROR E0658
+static STATIC_MUT_REF: &'static mut i32 = unsafe { &mut M }; //~ ERROR E0658
fn main() {}
diff --git a/src/test/ui/error-codes/E0017.stderr b/src/test/ui/error-codes/E0017.stderr
index 8c8660a..9a87195 100644
--- a/src/test/ui/error-codes/E0017.stderr
+++ b/src/test/ui/error-codes/E0017.stderr
@@ -1,8 +1,11 @@
-error[E0017]: references in constants may only refer to immutable values
+error[E0658]: references in constants may only refer to immutable values
--> $DIR/E0017.rs:5:30
|
LL | const CR: &'static mut i32 = &mut C;
| ^^^^^^ constants require immutable values
+ |
+ = note: for more information, see https://github.com/rust-lang/rust/issues/57349
+ = help: add `#![feature(const_mut_refs)]` to the crate attributes to enable
error[E0019]: static contains unimplemented expression type
--> $DIR/E0017.rs:6:39
@@ -10,11 +13,14 @@
LL | static STATIC_REF: &'static mut i32 = &mut X;
| ^^^^^^
-error[E0017]: references in statics may only refer to immutable values
+error[E0658]: references in statics may only refer to immutable values
--> $DIR/E0017.rs:6:39
|
LL | static STATIC_REF: &'static mut i32 = &mut X;
| ^^^^^^ statics require immutable values
+ |
+ = note: for more information, see https://github.com/rust-lang/rust/issues/57349
+ = help: add `#![feature(const_mut_refs)]` to the crate attributes to enable
error[E0596]: cannot borrow immutable static item `X` as mutable
--> $DIR/E0017.rs:6:39
@@ -22,19 +28,25 @@
LL | static STATIC_REF: &'static mut i32 = &mut X;
| ^^^^^^ cannot borrow as mutable
-error[E0017]: references in statics may only refer to immutable values
+error[E0658]: references in statics may only refer to immutable values
--> $DIR/E0017.rs:9:38
|
LL | static CONST_REF: &'static mut i32 = &mut C;
| ^^^^^^ statics require immutable values
+ |
+ = note: for more information, see https://github.com/rust-lang/rust/issues/57349
+ = help: add `#![feature(const_mut_refs)]` to the crate attributes to enable
-error[E0017]: references in statics may only refer to immutable values
+error[E0658]: references in statics may only refer to immutable values
--> $DIR/E0017.rs:10:52
|
LL | static STATIC_MUT_REF: &'static mut i32 = unsafe { &mut M };
| ^^^^^^ statics require immutable values
+ |
+ = note: for more information, see https://github.com/rust-lang/rust/issues/57349
+ = help: add `#![feature(const_mut_refs)]` to the crate attributes to enable
error: aborting due to 6 previous errors
-Some errors have detailed explanations: E0017, E0019, E0596.
-For more information about an error, try `rustc --explain E0017`.
+Some errors have detailed explanations: E0019, E0596, E0658.
+For more information about an error, try `rustc --explain E0019`.
diff --git a/src/test/ui/error-codes/E0283.stderr b/src/test/ui/error-codes/E0283.stderr
index aba649d..ae5b7c3 100644
--- a/src/test/ui/error-codes/E0283.stderr
+++ b/src/test/ui/error-codes/E0283.stderr
@@ -1,11 +1,13 @@
-error[E0283]: type annotations needed: cannot resolve `_: Generator`
+error[E0283]: type annotations needed
--> $DIR/E0283.rs:18:21
|
LL | fn create() -> u32;
| ------------------- required by `Generator::create`
...
LL | let cont: u32 = Generator::create();
- | ^^^^^^^^^^^^^^^^^
+ | ^^^^^^^^^^^^^^^^^ cannot infer type
+ |
+ = note: cannot resolve `_: Generator`
error: aborting due to previous error
diff --git a/src/test/ui/error-codes/E0388.rs b/src/test/ui/error-codes/E0388.rs
new file mode 100644
index 0000000..5954e34
--- /dev/null
+++ b/src/test/ui/error-codes/E0388.rs
@@ -0,0 +1,10 @@
+static X: i32 = 1;
+const C: i32 = 2;
+
+const CR: &'static mut i32 = &mut C; //~ ERROR E0658
+static STATIC_REF: &'static mut i32 = &mut X; //~ ERROR E0658
+ //~| ERROR cannot borrow
+ //~| ERROR E0019
+static CONST_REF: &'static mut i32 = &mut C; //~ ERROR E0658
+
+fn main() {}
diff --git a/src/test/ui/error-codes/E0388.stderr b/src/test/ui/error-codes/E0388.stderr
new file mode 100644
index 0000000..986307d
--- /dev/null
+++ b/src/test/ui/error-codes/E0388.stderr
@@ -0,0 +1,43 @@
+error[E0658]: references in constants may only refer to immutable values
+ --> $DIR/E0388.rs:4:30
+ |
+LL | const CR: &'static mut i32 = &mut C;
+ | ^^^^^^ constants require immutable values
+ |
+ = note: for more information, see https://github.com/rust-lang/rust/issues/57349
+ = help: add `#![feature(const_mut_refs)]` to the crate attributes to enable
+
+error[E0019]: static contains unimplemented expression type
+ --> $DIR/E0388.rs:5:39
+ |
+LL | static STATIC_REF: &'static mut i32 = &mut X;
+ | ^^^^^^
+
+error[E0658]: references in statics may only refer to immutable values
+ --> $DIR/E0388.rs:5:39
+ |
+LL | static STATIC_REF: &'static mut i32 = &mut X;
+ | ^^^^^^ statics require immutable values
+ |
+ = note: for more information, see https://github.com/rust-lang/rust/issues/57349
+ = help: add `#![feature(const_mut_refs)]` to the crate attributes to enable
+
+error[E0596]: cannot borrow immutable static item `X` as mutable
+ --> $DIR/E0388.rs:5:39
+ |
+LL | static STATIC_REF: &'static mut i32 = &mut X;
+ | ^^^^^^ cannot borrow as mutable
+
+error[E0658]: references in statics may only refer to immutable values
+ --> $DIR/E0388.rs:8:38
+ |
+LL | static CONST_REF: &'static mut i32 = &mut C;
+ | ^^^^^^ statics require immutable values
+ |
+ = note: for more information, see https://github.com/rust-lang/rust/issues/57349
+ = help: add `#![feature(const_mut_refs)]` to the crate attributes to enable
+
+error: aborting due to 5 previous errors
+
+Some errors have detailed explanations: E0019, E0596, E0658.
+For more information about an error, try `rustc --explain E0019`.
diff --git a/src/test/ui/error-codes/E0401.stderr b/src/test/ui/error-codes/E0401.stderr
index 485b76a..0adf982 100644
--- a/src/test/ui/error-codes/E0401.stderr
+++ b/src/test/ui/error-codes/E0401.stderr
@@ -36,7 +36,7 @@
--> $DIR/E0401.rs:11:5
|
LL | bfnr(x);
- | ^^^^ cannot infer type for `U`
+ | ^^^^ cannot infer type for type parameter `U`
error: aborting due to 4 previous errors
diff --git a/src/test/ui/extern-flag/auxiliary/somedep.rs b/src/test/ui/extern-flag/auxiliary/somedep.rs
new file mode 100644
index 0000000..dd2f373
--- /dev/null
+++ b/src/test/ui/extern-flag/auxiliary/somedep.rs
@@ -0,0 +1,3 @@
+pub fn somefun() {}
+
+pub struct S;
diff --git a/src/test/ui/extern-flag/multiple-opts.rs b/src/test/ui/extern-flag/multiple-opts.rs
new file mode 100644
index 0000000..3dc2f1d
--- /dev/null
+++ b/src/test/ui/extern-flag/multiple-opts.rs
@@ -0,0 +1,20 @@
+// aux-crate:priv,noprelude:somedep=somedep.rs
+// compile-flags: -Zunstable-options
+// edition:2018
+
+// Test for multiple options to --extern. Can't test for errors from both
+// options at the same time, so this only checks that noprelude is honored.
+
+#![warn(exported_private_dependencies)]
+
+// Module to avoid adding to prelude.
+pub mod m {
+ extern crate somedep;
+ pub struct PublicType {
+ pub field: somedep::S,
+ }
+}
+
+fn main() {
+ somedep::somefun(); //~ ERROR failed to resolve
+}
diff --git a/src/test/ui/extern-flag/multiple-opts.stderr b/src/test/ui/extern-flag/multiple-opts.stderr
new file mode 100644
index 0000000..3bf73d1
--- /dev/null
+++ b/src/test/ui/extern-flag/multiple-opts.stderr
@@ -0,0 +1,9 @@
+error[E0433]: failed to resolve: use of undeclared type or module `somedep`
+ --> $DIR/multiple-opts.rs:19:5
+ |
+LL | somedep::somefun();
+ | ^^^^^^^ use of undeclared type or module `somedep`
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0433`.
diff --git a/src/test/ui/extern-flag/noprelude-and-prelude.rs b/src/test/ui/extern-flag/noprelude-and-prelude.rs
new file mode 100644
index 0000000..e6a150b
--- /dev/null
+++ b/src/test/ui/extern-flag/noprelude-and-prelude.rs
@@ -0,0 +1,10 @@
+// check-pass
+// aux-crate:noprelude:somedep=somedep.rs
+// compile-flags: -Zunstable-options --extern somedep
+// edition:2018
+
+// Having a flag with `noprelude` and one without, will add to the prelude.
+
+fn main() {
+ somedep::somefun();
+}
diff --git a/src/test/ui/extern-flag/noprelude-resolves.rs b/src/test/ui/extern-flag/noprelude-resolves.rs
new file mode 100644
index 0000000..f69f552
--- /dev/null
+++ b/src/test/ui/extern-flag/noprelude-resolves.rs
@@ -0,0 +1,11 @@
+// check-pass
+// aux-crate:noprelude:somedep=somedep.rs
+// compile-flags: -Zunstable-options
+// edition:2018
+
+// `extern crate` can be used to add to prelude.
+extern crate somedep;
+
+fn main() {
+ somedep::somefun();
+}
diff --git a/src/test/ui/extern-flag/noprelude.rs b/src/test/ui/extern-flag/noprelude.rs
new file mode 100644
index 0000000..cdbf340
--- /dev/null
+++ b/src/test/ui/extern-flag/noprelude.rs
@@ -0,0 +1,7 @@
+// aux-crate:noprelude:somedep=somedep.rs
+// compile-flags: -Zunstable-options
+// edition:2018
+
+fn main() {
+ somedep::somefun(); //~ ERROR failed to resolve
+}
diff --git a/src/test/ui/extern-flag/noprelude.stderr b/src/test/ui/extern-flag/noprelude.stderr
new file mode 100644
index 0000000..beb9200
--- /dev/null
+++ b/src/test/ui/extern-flag/noprelude.stderr
@@ -0,0 +1,9 @@
+error[E0433]: failed to resolve: use of undeclared type or module `somedep`
+ --> $DIR/noprelude.rs:6:5
+ |
+LL | somedep::somefun();
+ | ^^^^^^^ use of undeclared type or module `somedep`
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0433`.
diff --git a/src/test/ui/extern-flag/public-and-private.rs b/src/test/ui/extern-flag/public-and-private.rs
new file mode 100644
index 0000000..a3a81cb
--- /dev/null
+++ b/src/test/ui/extern-flag/public-and-private.rs
@@ -0,0 +1,13 @@
+// aux-crate:priv:somedep=somedep.rs
+// compile-flags: -Zunstable-options --extern somedep
+// edition:2018
+
+#![deny(exported_private_dependencies)]
+
+// Having a flag with `priv` and one without, will remain private (it is sticky).
+
+pub struct PublicType {
+ pub field: somedep::S, //~ ERROR from private dependency
+}
+
+fn main() {}
diff --git a/src/test/ui/extern-flag/public-and-private.stderr b/src/test/ui/extern-flag/public-and-private.stderr
new file mode 100644
index 0000000..72f1bb2
--- /dev/null
+++ b/src/test/ui/extern-flag/public-and-private.stderr
@@ -0,0 +1,14 @@
+error: type `somedep::S` from private dependency 'somedep' in public interface
+ --> $DIR/public-and-private.rs:10:5
+ |
+LL | pub field: somedep::S,
+ | ^^^^^^^^^^^^^^^^^^^^^
+ |
+note: lint level defined here
+ --> $DIR/public-and-private.rs:5:9
+ |
+LL | #![deny(exported_private_dependencies)]
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+error: aborting due to previous error
+
diff --git a/src/test/ui/for-loop-while/label_break_value.rs b/src/test/ui/for-loop-while/label_break_value.rs
index eb5be77..18930ac 100644
--- a/src/test/ui/for-loop-while/label_break_value.rs
+++ b/src/test/ui/for-loop-while/label_break_value.rs
@@ -77,7 +77,7 @@
}
// Labeled breaking an outer loop still works
'd: loop {
- 'e: {
+ {
if v == r {
break 'b;
}
diff --git a/src/test/ui/for-loop-while/loop-label-shadowing.rs b/src/test/ui/for-loop-while/loop-label-shadowing.rs
index acb53e2..9bedde6 100644
--- a/src/test/ui/for-loop-while/loop-label-shadowing.rs
+++ b/src/test/ui/for-loop-while/loop-label-shadowing.rs
@@ -5,6 +5,7 @@
fn main() {
let mut foo = Vec::new();
+ #[allow(unused_labels)]
'foo: for i in &[1, 2, 3] {
foo.push(*i);
}
diff --git a/src/test/ui/fully-qualified-type/fully-qualified-type-name4.stderr b/src/test/ui/fully-qualified-type/fully-qualified-type-name4.stderr
index b388f38..ca61fb0 100644
--- a/src/test/ui/fully-qualified-type/fully-qualified-type-name4.stderr
+++ b/src/test/ui/fully-qualified-type/fully-qualified-type-name4.stderr
@@ -4,7 +4,10 @@
LL | fn bar(x: usize) -> Option<usize> {
| ------------- expected `std::option::Option<usize>` because of return type
LL | return x;
- | ^ expected enum `std::option::Option`, found `usize`
+ | ^
+ | |
+ | expected enum `std::option::Option`, found `usize`
+ | help: try using a variant of the expected enum: `Some(x)`
|
= note: expected enum `std::option::Option<usize>`
found type `usize`
diff --git a/src/test/ui/generator/not-send-sync.rs b/src/test/ui/generator/not-send-sync.rs
index ae0a288..0db01c6 100644
--- a/src/test/ui/generator/not-send-sync.rs
+++ b/src/test/ui/generator/not-send-sync.rs
@@ -7,7 +7,7 @@
fn assert_send<T: Send>(_: T) {}
assert_sync(|| {
- //~^ ERROR: E0277
+ //~^ ERROR: future cannot be shared between threads safely
let a = Cell::new(2);
yield;
});
diff --git a/src/test/ui/generator/not-send-sync.stderr b/src/test/ui/generator/not-send-sync.stderr
index 620db24..0ac1d18 100644
--- a/src/test/ui/generator/not-send-sync.stderr
+++ b/src/test/ui/generator/not-send-sync.stderr
@@ -11,18 +11,25 @@
= note: required because of the requirements on the impl of `std::marker::Send` for `&std::cell::Cell<i32>`
= note: required because it appears within the type `[generator@$DIR/not-send-sync.rs:16:17: 20:6 a:&std::cell::Cell<i32> _]`
-error[E0277]: `std::cell::Cell<i32>` cannot be shared between threads safely
+error: future cannot be shared between threads safely
--> $DIR/not-send-sync.rs:9:5
|
LL | fn assert_sync<T: Sync>(_: T) {}
| ----------- ---- required by this bound in `main::assert_sync`
...
LL | assert_sync(|| {
- | ^^^^^^^^^^^ `std::cell::Cell<i32>` cannot be shared between threads safely
+ | ^^^^^^^^^^^ future returned by `main` is not `Sync`
|
= help: within `[generator@$DIR/not-send-sync.rs:9:17: 13:6 {std::cell::Cell<i32>, ()}]`, the trait `std::marker::Sync` is not implemented for `std::cell::Cell<i32>`
- = note: required because it appears within the type `{std::cell::Cell<i32>, ()}`
- = note: required because it appears within the type `[generator@$DIR/not-send-sync.rs:9:17: 13:6 {std::cell::Cell<i32>, ()}]`
+note: future is not `Sync` as this value is used across an yield
+ --> $DIR/not-send-sync.rs:12:9
+ |
+LL | let a = Cell::new(2);
+ | - has type `std::cell::Cell<i32>`
+LL | yield;
+ | ^^^^^ yield occurs here, with `a` maybe used later
+LL | });
+ | - `a` is later dropped here
error: aborting due to 2 previous errors
diff --git a/src/test/ui/hrtb/hrtb-perfect-forwarding.polonius.stderr b/src/test/ui/hrtb/hrtb-perfect-forwarding.polonius.stderr
new file mode 100644
index 0000000..558d643
--- /dev/null
+++ b/src/test/ui/hrtb/hrtb-perfect-forwarding.polonius.stderr
@@ -0,0 +1,68 @@
+warning: function cannot return without recursing
+ --> $DIR/hrtb-perfect-forwarding.rs:22:1
+ |
+LL | / fn no_hrtb<'b,T>(mut t: T)
+LL | | where T : Bar<&'b isize>
+LL | | {
+LL | | // OK -- `T : Bar<&'b isize>`, and thus the impl above ensures that
+LL | | // `&mut T : Bar<&'b isize>`.
+LL | | no_hrtb(&mut t);
+ | | --------------- recursive call site
+LL | | }
+ | |_^ cannot return without recursing
+ |
+ = note: `#[warn(unconditional_recursion)]` on by default
+ = help: a `loop` may express intention better if this is on purpose
+
+warning: function cannot return without recursing
+ --> $DIR/hrtb-perfect-forwarding.rs:30:1
+ |
+LL | / fn bar_hrtb<T>(mut t: T)
+LL | | where T : for<'b> Bar<&'b isize>
+LL | | {
+LL | | // OK -- `T : for<'b> Bar<&'b isize>`, and thus the impl above
+... |
+LL | | bar_hrtb(&mut t);
+ | | ---------------- recursive call site
+LL | | }
+ | |_^ cannot return without recursing
+ |
+ = help: a `loop` may express intention better if this is on purpose
+
+warning: function cannot return without recursing
+ --> $DIR/hrtb-perfect-forwarding.rs:39:1
+ |
+LL | / fn foo_hrtb_bar_not<'b,T>(mut t: T)
+LL | | where T : for<'a> Foo<&'a isize> + Bar<&'b isize>
+LL | | {
+LL | | // Not OK -- The forwarding impl for `Foo` requires that `Bar` also
+... |
+LL | | foo_hrtb_bar_not(&mut t);
+ | | ------------------------ recursive call site
+LL | | }
+ | |_^ cannot return without recursing
+ |
+ = help: a `loop` may express intention better if this is on purpose
+
+error: higher-ranked subtype error
+ --> $DIR/hrtb-perfect-forwarding.rs:46:5
+ |
+LL | foo_hrtb_bar_not(&mut t);
+ | ^^^^^^^^^^^^^^^^^^^^^^^^
+
+warning: function cannot return without recursing
+ --> $DIR/hrtb-perfect-forwarding.rs:49:1
+ |
+LL | / fn foo_hrtb_bar_hrtb<T>(mut t: T)
+LL | | where T : for<'a> Foo<&'a isize> + for<'b> Bar<&'b isize>
+LL | | {
+LL | | // OK -- now we have `T : for<'b> Bar&'b isize>`.
+LL | | foo_hrtb_bar_hrtb(&mut t);
+ | | ------------------------- recursive call site
+LL | | }
+ | |_^ cannot return without recursing
+ |
+ = help: a `loop` may express intention better if this is on purpose
+
+error: aborting due to previous error
+
diff --git a/src/test/ui/hygiene/hygienic-labels-in-let.rs b/src/test/ui/hygiene/hygienic-labels-in-let.rs
index 5d22cf8..491855d 100644
--- a/src/test/ui/hygiene/hygienic-labels-in-let.rs
+++ b/src/test/ui/hygiene/hygienic-labels-in-let.rs
@@ -1,5 +1,6 @@
// run-pass
#![allow(unreachable_code)]
+#![allow(unused_labels)]
// Test that labels injected by macros do not break hygiene. This
// checks cases where the macros invocations are under the rhs of a
diff --git a/src/test/ui/hygiene/hygienic-labels-in-let.stderr b/src/test/ui/hygiene/hygienic-labels-in-let.stderr
index d88470f..4acb34f 100644
--- a/src/test/ui/hygiene/hygienic-labels-in-let.stderr
+++ b/src/test/ui/hygiene/hygienic-labels-in-let.stderr
@@ -1,5 +1,5 @@
warning: label name `'x` shadows a label name that is already in scope
- --> $DIR/hygienic-labels-in-let.rs:15:9
+ --> $DIR/hygienic-labels-in-let.rs:16:9
|
LL | 'x: loop { $e }
| ^^ lifetime 'x already in scope
@@ -11,7 +11,7 @@
| ------------------ in this macro invocation
warning: label name `'x` shadows a label name that is already in scope
- --> $DIR/hygienic-labels-in-let.rs:63:9
+ --> $DIR/hygienic-labels-in-let.rs:64:9
|
LL | 'x: loop {
| -- first declared here
@@ -20,7 +20,7 @@
| ^^ lifetime 'x already in scope
warning: label name `'x` shadows a label name that is already in scope
- --> $DIR/hygienic-labels-in-let.rs:63:9
+ --> $DIR/hygienic-labels-in-let.rs:64:9
|
LL | 'x: loop { $e }
| -- first declared here
@@ -29,7 +29,7 @@
| ^^ lifetime 'x already in scope
warning: label name `'x` shadows a label name that is already in scope
- --> $DIR/hygienic-labels-in-let.rs:15:9
+ --> $DIR/hygienic-labels-in-let.rs:16:9
|
LL | 'x: loop { $e }
| ^^ lifetime 'x already in scope
@@ -41,7 +41,7 @@
| ------------------ in this macro invocation
warning: label name `'x` shadows a label name that is already in scope
- --> $DIR/hygienic-labels-in-let.rs:15:9
+ --> $DIR/hygienic-labels-in-let.rs:16:9
|
LL | 'x: loop { $e }
| ^^
@@ -53,7 +53,7 @@
| ------------------ in this macro invocation
warning: label name `'x` shadows a label name that is already in scope
- --> $DIR/hygienic-labels-in-let.rs:15:9
+ --> $DIR/hygienic-labels-in-let.rs:16:9
|
LL | 'x: loop { $e }
| ^^ lifetime 'x already in scope
@@ -65,7 +65,7 @@
| ------------------ in this macro invocation
warning: label name `'x` shadows a label name that is already in scope
- --> $DIR/hygienic-labels-in-let.rs:75:9
+ --> $DIR/hygienic-labels-in-let.rs:76:9
|
LL | 'x: loop {
| -- first declared here
@@ -74,7 +74,7 @@
| ^^ lifetime 'x already in scope
warning: label name `'x` shadows a label name that is already in scope
- --> $DIR/hygienic-labels-in-let.rs:75:9
+ --> $DIR/hygienic-labels-in-let.rs:76:9
|
LL | 'x: loop { $e }
| -- first declared here
@@ -83,7 +83,7 @@
| ^^ lifetime 'x already in scope
warning: label name `'x` shadows a label name that is already in scope
- --> $DIR/hygienic-labels-in-let.rs:75:9
+ --> $DIR/hygienic-labels-in-let.rs:76:9
|
LL | 'x: for _ in 0..1 {
| -- first declared here
@@ -92,7 +92,7 @@
| ^^ lifetime 'x already in scope
warning: label name `'x` shadows a label name that is already in scope
- --> $DIR/hygienic-labels-in-let.rs:75:9
+ --> $DIR/hygienic-labels-in-let.rs:76:9
|
LL | 'x: loop { $e }
| -- first declared here
@@ -101,7 +101,7 @@
| ^^ lifetime 'x already in scope
warning: label name `'x` shadows a label name that is already in scope
- --> $DIR/hygienic-labels-in-let.rs:26:9
+ --> $DIR/hygienic-labels-in-let.rs:27:9
|
LL | 'x: while 1 + 1 == 2 { $e }
| ^^ lifetime 'x already in scope
@@ -113,7 +113,7 @@
| ---------------------- in this macro invocation
warning: label name `'x` shadows a label name that is already in scope
- --> $DIR/hygienic-labels-in-let.rs:26:9
+ --> $DIR/hygienic-labels-in-let.rs:27:9
|
LL | 'x: loop { $e }
| -- first declared here
@@ -125,7 +125,7 @@
| ---------------------- in this macro invocation
warning: label name `'x` shadows a label name that is already in scope
- --> $DIR/hygienic-labels-in-let.rs:26:9
+ --> $DIR/hygienic-labels-in-let.rs:27:9
|
LL | 'x: while 1 + 1 == 2 { $e }
| ^^ lifetime 'x already in scope
@@ -137,7 +137,7 @@
| ---------------------- in this macro invocation
warning: label name `'x` shadows a label name that is already in scope
- --> $DIR/hygienic-labels-in-let.rs:26:9
+ --> $DIR/hygienic-labels-in-let.rs:27:9
|
LL | 'x: loop { $e }
| -- first declared here
@@ -149,7 +149,7 @@
| ---------------------- in this macro invocation
warning: label name `'x` shadows a label name that is already in scope
- --> $DIR/hygienic-labels-in-let.rs:26:9
+ --> $DIR/hygienic-labels-in-let.rs:27:9
|
LL | 'x: while 1 + 1 == 2 { $e }
| ^^ lifetime 'x already in scope
@@ -161,7 +161,7 @@
| ---------------------- in this macro invocation
warning: label name `'x` shadows a label name that is already in scope
- --> $DIR/hygienic-labels-in-let.rs:89:9
+ --> $DIR/hygienic-labels-in-let.rs:90:9
|
LL | 'x: loop {
| -- first declared here
@@ -170,7 +170,7 @@
| ^^ lifetime 'x already in scope
warning: label name `'x` shadows a label name that is already in scope
- --> $DIR/hygienic-labels-in-let.rs:89:9
+ --> $DIR/hygienic-labels-in-let.rs:90:9
|
LL | 'x: loop { $e }
| -- first declared here
@@ -179,7 +179,7 @@
| ^^ lifetime 'x already in scope
warning: label name `'x` shadows a label name that is already in scope
- --> $DIR/hygienic-labels-in-let.rs:89:9
+ --> $DIR/hygienic-labels-in-let.rs:90:9
|
LL | 'x: for _ in 0..1 {
| -- first declared here
@@ -188,7 +188,7 @@
| ^^ lifetime 'x already in scope
warning: label name `'x` shadows a label name that is already in scope
- --> $DIR/hygienic-labels-in-let.rs:89:9
+ --> $DIR/hygienic-labels-in-let.rs:90:9
|
LL | 'x: loop { $e }
| -- first declared here
@@ -197,7 +197,7 @@
| ^^ lifetime 'x already in scope
warning: label name `'x` shadows a label name that is already in scope
- --> $DIR/hygienic-labels-in-let.rs:89:9
+ --> $DIR/hygienic-labels-in-let.rs:90:9
|
LL | 'x: for _ in 0..1 {
| -- first declared here
@@ -206,7 +206,7 @@
| ^^ lifetime 'x already in scope
warning: label name `'x` shadows a label name that is already in scope
- --> $DIR/hygienic-labels-in-let.rs:89:9
+ --> $DIR/hygienic-labels-in-let.rs:90:9
|
LL | 'x: while 1 + 1 == 2 { $e }
| -- first declared here
@@ -215,7 +215,7 @@
| ^^ lifetime 'x already in scope
warning: label name `'x` shadows a label name that is already in scope
- --> $DIR/hygienic-labels-in-let.rs:38:9
+ --> $DIR/hygienic-labels-in-let.rs:39:9
|
LL | 'x: for _ in 0..1 { $e }
| ^^ lifetime 'x already in scope
@@ -227,7 +227,7 @@
| ----------------------- in this macro invocation
warning: label name `'x` shadows a label name that is already in scope
- --> $DIR/hygienic-labels-in-let.rs:38:9
+ --> $DIR/hygienic-labels-in-let.rs:39:9
|
LL | 'x: loop { $e }
| -- first declared here
@@ -239,7 +239,7 @@
| ----------------------- in this macro invocation
warning: label name `'x` shadows a label name that is already in scope
- --> $DIR/hygienic-labels-in-let.rs:38:9
+ --> $DIR/hygienic-labels-in-let.rs:39:9
|
LL | 'x: for _ in 0..1 { $e }
| ^^ lifetime 'x already in scope
@@ -251,7 +251,7 @@
| ----------------------- in this macro invocation
warning: label name `'x` shadows a label name that is already in scope
- --> $DIR/hygienic-labels-in-let.rs:38:9
+ --> $DIR/hygienic-labels-in-let.rs:39:9
|
LL | 'x: loop { $e }
| -- first declared here
@@ -263,7 +263,7 @@
| ----------------------- in this macro invocation
warning: label name `'x` shadows a label name that is already in scope
- --> $DIR/hygienic-labels-in-let.rs:38:9
+ --> $DIR/hygienic-labels-in-let.rs:39:9
|
LL | 'x: for _ in 0..1 { $e }
| ^^ lifetime 'x already in scope
@@ -275,7 +275,7 @@
| ----------------------- in this macro invocation
warning: label name `'x` shadows a label name that is already in scope
- --> $DIR/hygienic-labels-in-let.rs:38:9
+ --> $DIR/hygienic-labels-in-let.rs:39:9
|
LL | 'x: while 1 + 1 == 2 { $e }
| -- first declared here
@@ -287,7 +287,7 @@
| ----------------------- in this macro invocation
warning: label name `'x` shadows a label name that is already in scope
- --> $DIR/hygienic-labels-in-let.rs:38:9
+ --> $DIR/hygienic-labels-in-let.rs:39:9
|
LL | 'x: for _ in 0..1 { $e }
| ^^ lifetime 'x already in scope
diff --git a/src/test/ui/hygiene/hygienic-labels.rs b/src/test/ui/hygiene/hygienic-labels.rs
index 8eafb4c..c9f494b 100644
--- a/src/test/ui/hygiene/hygienic-labels.rs
+++ b/src/test/ui/hygiene/hygienic-labels.rs
@@ -1,5 +1,6 @@
// run-pass
#![allow(unreachable_code)]
+#![allow(unused_labels)]
// Test that labels injected by macros do not break hygiene.
// Issue #24278: The label/lifetime shadowing checker from #24162
diff --git a/src/test/ui/hygiene/hygienic-labels.stderr b/src/test/ui/hygiene/hygienic-labels.stderr
index 285e903..0833825 100644
--- a/src/test/ui/hygiene/hygienic-labels.stderr
+++ b/src/test/ui/hygiene/hygienic-labels.stderr
@@ -1,5 +1,5 @@
warning: label name `'x` shadows a label name that is already in scope
- --> $DIR/hygienic-labels.rs:12:9
+ --> $DIR/hygienic-labels.rs:13:9
|
LL | 'x: loop { $e }
| ^^ lifetime 'x already in scope
@@ -11,7 +11,7 @@
| ------------------ in this macro invocation
warning: label name `'x` shadows a label name that is already in scope
- --> $DIR/hygienic-labels.rs:53:5
+ --> $DIR/hygienic-labels.rs:54:5
|
LL | 'x: for _ in 0..1 {
| -- first declared here
@@ -20,7 +20,7 @@
| ^^ lifetime 'x already in scope
warning: label name `'x` shadows a label name that is already in scope
- --> $DIR/hygienic-labels.rs:53:5
+ --> $DIR/hygienic-labels.rs:54:5
|
LL | 'x: loop { $e }
| -- first declared here
@@ -29,7 +29,7 @@
| ^^ lifetime 'x already in scope
warning: label name `'x` shadows a label name that is already in scope
- --> $DIR/hygienic-labels.rs:12:9
+ --> $DIR/hygienic-labels.rs:13:9
|
LL | 'x: loop { $e }
| ^^ lifetime 'x already in scope
@@ -41,7 +41,7 @@
| ------------------ in this macro invocation
warning: label name `'x` shadows a label name that is already in scope
- --> $DIR/hygienic-labels.rs:12:9
+ --> $DIR/hygienic-labels.rs:13:9
|
LL | 'x: loop { $e }
| ^^
@@ -53,7 +53,7 @@
| ------------------ in this macro invocation
warning: label name `'x` shadows a label name that is already in scope
- --> $DIR/hygienic-labels.rs:12:9
+ --> $DIR/hygienic-labels.rs:13:9
|
LL | 'x: loop { $e }
| ^^ lifetime 'x already in scope
@@ -65,7 +65,7 @@
| ------------------ in this macro invocation
warning: label name `'x` shadows a label name that is already in scope
- --> $DIR/hygienic-labels.rs:62:5
+ --> $DIR/hygienic-labels.rs:63:5
|
LL | 'x: for _ in 0..1 {
| -- first declared here
@@ -74,7 +74,7 @@
| ^^ lifetime 'x already in scope
warning: label name `'x` shadows a label name that is already in scope
- --> $DIR/hygienic-labels.rs:62:5
+ --> $DIR/hygienic-labels.rs:63:5
|
LL | 'x: loop { $e }
| -- first declared here
@@ -83,7 +83,7 @@
| ^^ lifetime 'x already in scope
warning: label name `'x` shadows a label name that is already in scope
- --> $DIR/hygienic-labels.rs:62:5
+ --> $DIR/hygienic-labels.rs:63:5
|
LL | 'x: loop {
| -- first declared here
@@ -92,7 +92,7 @@
| ^^ lifetime 'x already in scope
warning: label name `'x` shadows a label name that is already in scope
- --> $DIR/hygienic-labels.rs:62:5
+ --> $DIR/hygienic-labels.rs:63:5
|
LL | 'x: loop { $e }
| -- first declared here
@@ -101,7 +101,7 @@
| ^^ lifetime 'x already in scope
warning: label name `'x` shadows a label name that is already in scope
- --> $DIR/hygienic-labels.rs:37:9
+ --> $DIR/hygienic-labels.rs:38:9
|
LL | 'x: while 1 + 1 == 2 { $e }
| ^^ lifetime 'x already in scope
@@ -113,7 +113,7 @@
| ------------------- in this macro invocation
warning: label name `'x` shadows a label name that is already in scope
- --> $DIR/hygienic-labels.rs:37:9
+ --> $DIR/hygienic-labels.rs:38:9
|
LL | 'x: loop { $e }
| -- first declared here
@@ -125,7 +125,7 @@
| ------------------- in this macro invocation
warning: label name `'x` shadows a label name that is already in scope
- --> $DIR/hygienic-labels.rs:37:9
+ --> $DIR/hygienic-labels.rs:38:9
|
LL | 'x: while 1 + 1 == 2 { $e }
| ^^ lifetime 'x already in scope
@@ -137,7 +137,7 @@
| ------------------- in this macro invocation
warning: label name `'x` shadows a label name that is already in scope
- --> $DIR/hygienic-labels.rs:37:9
+ --> $DIR/hygienic-labels.rs:38:9
|
LL | 'x: loop { $e }
| -- first declared here
@@ -149,7 +149,7 @@
| ------------------- in this macro invocation
warning: label name `'x` shadows a label name that is already in scope
- --> $DIR/hygienic-labels.rs:37:9
+ --> $DIR/hygienic-labels.rs:38:9
|
LL | 'x: while 1 + 1 == 2 { $e }
| ^^ lifetime 'x already in scope
@@ -161,7 +161,7 @@
| ------------------- in this macro invocation
warning: label name `'x` shadows a label name that is already in scope
- --> $DIR/hygienic-labels.rs:72:5
+ --> $DIR/hygienic-labels.rs:73:5
|
LL | 'x: for _ in 0..1 {
| -- first declared here
@@ -170,7 +170,7 @@
| ^^ lifetime 'x already in scope
warning: label name `'x` shadows a label name that is already in scope
- --> $DIR/hygienic-labels.rs:72:5
+ --> $DIR/hygienic-labels.rs:73:5
|
LL | 'x: loop { $e }
| -- first declared here
@@ -179,7 +179,7 @@
| ^^ lifetime 'x already in scope
warning: label name `'x` shadows a label name that is already in scope
- --> $DIR/hygienic-labels.rs:72:5
+ --> $DIR/hygienic-labels.rs:73:5
|
LL | 'x: loop {
| -- first declared here
@@ -188,7 +188,7 @@
| ^^ lifetime 'x already in scope
warning: label name `'x` shadows a label name that is already in scope
- --> $DIR/hygienic-labels.rs:72:5
+ --> $DIR/hygienic-labels.rs:73:5
|
LL | 'x: loop { $e }
| -- first declared here
@@ -197,7 +197,7 @@
| ^^ lifetime 'x already in scope
warning: label name `'x` shadows a label name that is already in scope
- --> $DIR/hygienic-labels.rs:72:5
+ --> $DIR/hygienic-labels.rs:73:5
|
LL | 'x: while 1 + 1 == 2 {
| -- first declared here
@@ -206,7 +206,7 @@
| ^^ lifetime 'x already in scope
warning: label name `'x` shadows a label name that is already in scope
- --> $DIR/hygienic-labels.rs:72:5
+ --> $DIR/hygienic-labels.rs:73:5
|
LL | 'x: while 1 + 1 == 2 { $e }
| -- first declared here
@@ -215,7 +215,7 @@
| ^^ lifetime 'x already in scope
warning: label name `'x` shadows a label name that is already in scope
- --> $DIR/hygienic-labels.rs:23:9
+ --> $DIR/hygienic-labels.rs:24:9
|
LL | 'x: for _ in 0..1 { $e }
| ^^ lifetime 'x already in scope
@@ -227,7 +227,7 @@
| ----------------------- in this macro invocation
warning: label name `'x` shadows a label name that is already in scope
- --> $DIR/hygienic-labels.rs:23:9
+ --> $DIR/hygienic-labels.rs:24:9
|
LL | 'x: loop { $e }
| -- first declared here
@@ -239,7 +239,7 @@
| ----------------------- in this macro invocation
warning: label name `'x` shadows a label name that is already in scope
- --> $DIR/hygienic-labels.rs:23:9
+ --> $DIR/hygienic-labels.rs:24:9
|
LL | 'x: for _ in 0..1 { $e }
| ^^ lifetime 'x already in scope
@@ -251,7 +251,7 @@
| ----------------------- in this macro invocation
warning: label name `'x` shadows a label name that is already in scope
- --> $DIR/hygienic-labels.rs:23:9
+ --> $DIR/hygienic-labels.rs:24:9
|
LL | 'x: loop { $e }
| -- first declared here
@@ -263,7 +263,7 @@
| ----------------------- in this macro invocation
warning: label name `'x` shadows a label name that is already in scope
- --> $DIR/hygienic-labels.rs:23:9
+ --> $DIR/hygienic-labels.rs:24:9
|
LL | 'x: for _ in 0..1 { $e }
| ^^ lifetime 'x already in scope
@@ -275,7 +275,7 @@
| ----------------------- in this macro invocation
warning: label name `'x` shadows a label name that is already in scope
- --> $DIR/hygienic-labels.rs:23:9
+ --> $DIR/hygienic-labels.rs:24:9
|
LL | 'x: for _ in 0..1 { $e }
| ^^ lifetime 'x already in scope
@@ -287,7 +287,7 @@
| ----------------------- in this macro invocation
warning: label name `'x` shadows a label name that is already in scope
- --> $DIR/hygienic-labels.rs:23:9
+ --> $DIR/hygienic-labels.rs:24:9
|
LL | 'x: for _ in 0..1 { $e }
| ^^ lifetime 'x already in scope
diff --git a/src/test/ui/impl-header-lifetime-elision/dyn-trait.stderr b/src/test/ui/impl-header-lifetime-elision/dyn-trait.stderr
index 5e80c67..3300293 100644
--- a/src/test/ui/impl-header-lifetime-elision/dyn-trait.stderr
+++ b/src/test/ui/impl-header-lifetime-elision/dyn-trait.stderr
@@ -9,13 +9,21 @@
|
LL | fn with_dyn_debug_static<'a>(x: Box<dyn Debug + 'a>) {
| ^^
- = note: ...so that the expression is assignable:
- expected std::boxed::Box<dyn std::fmt::Debug>
- found std::boxed::Box<(dyn std::fmt::Debug + 'a)>
+note: ...so that the expression is assignable
+ --> $DIR/dyn-trait.rs:20:16
+ |
+LL | static_val(x);
+ | ^
+ = note: expected `std::boxed::Box<dyn std::fmt::Debug>`
+ found `std::boxed::Box<(dyn std::fmt::Debug + 'a)>`
= note: but, the lifetime must be valid for the static lifetime...
- = note: ...so that the types are compatible:
- expected StaticTrait
- found StaticTrait
+note: ...so that the types are compatible
+ --> $DIR/dyn-trait.rs:20:5
+ |
+LL | static_val(x);
+ | ^^^^^^^^^^
+ = note: expected `StaticTrait`
+ found `StaticTrait`
error: aborting due to previous error
diff --git a/src/test/ui/impl-trait/multiple-lifetimes/error-handling.polonius.stderr b/src/test/ui/impl-trait/multiple-lifetimes/error-handling.polonius.stderr
new file mode 100644
index 0000000..72e8fa3
--- /dev/null
+++ b/src/test/ui/impl-trait/multiple-lifetimes/error-handling.polonius.stderr
@@ -0,0 +1,12 @@
+error: lifetime may not live long enough
+ --> $DIR/error-handling.rs:13:56
+ |
+LL | fn foo<'a, 'b, 'c>(x: &'static i32, mut y: &'a i32) -> E<'b, 'c> {
+ | -- -- lifetime `'b` defined here ^^^^^^^^^ opaque type requires that `'a` must outlive `'b`
+ | |
+ | lifetime `'a` defined here
+ |
+ = help: consider adding the following bound: `'a: 'b`
+
+error: aborting due to previous error
+
diff --git a/src/test/ui/issues/issue-12028.stderr b/src/test/ui/issues/issue-12028.stderr
index ff92d01..5f2dd72 100644
--- a/src/test/ui/issues/issue-12028.stderr
+++ b/src/test/ui/issues/issue-12028.stderr
@@ -1,8 +1,10 @@
-error[E0284]: type annotations needed: cannot resolve `<_ as StreamHasher>::S == <H as StreamHasher>::S`
+error[E0284]: type annotations needed
--> $DIR/issue-12028.rs:27:14
|
LL | self.input_stream(&mut stream);
- | ^^^^^^^^^^^^
+ | ^^^^^^^^^^^^ cannot infer type for type parameter `H`
+ |
+ = note: cannot resolve `<_ as StreamHasher>::S == <H as StreamHasher>::S`
error: aborting due to previous error
diff --git a/src/test/ui/issues/issue-16683.stderr b/src/test/ui/issues/issue-16683.stderr
index b663e21..99700f2 100644
--- a/src/test/ui/issues/issue-16683.stderr
+++ b/src/test/ui/issues/issue-16683.stderr
@@ -21,9 +21,13 @@
|
LL | trait T<'a> {
| ^^
- = note: ...so that the types are compatible:
- expected &'a Self
- found &Self
+note: ...so that the types are compatible
+ --> $DIR/issue-16683.rs:4:14
+ |
+LL | self.a();
+ | ^
+ = note: expected `&'a Self`
+ found `&Self`
error: aborting due to previous error
diff --git a/src/test/ui/issues/issue-16966.stderr b/src/test/ui/issues/issue-16966.stderr
index 13e77fe..0d565af 100644
--- a/src/test/ui/issues/issue-16966.stderr
+++ b/src/test/ui/issues/issue-16966.stderr
@@ -2,7 +2,7 @@
--> $DIR/issue-16966.rs:2:5
|
LL | panic!(std::default::Default::default());
- | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ cannot infer type for `M`
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ cannot infer type for type parameter `M`
|
= note: this error originates in a macro outside of the current crate (in Nightly builds, run with -Z external-macro-backtrace for more info)
diff --git a/src/test/ui/issues/issue-17551.stderr b/src/test/ui/issues/issue-17551.stderr
index ce16f0f..5468268 100644
--- a/src/test/ui/issues/issue-17551.stderr
+++ b/src/test/ui/issues/issue-17551.stderr
@@ -2,7 +2,7 @@
--> $DIR/issue-17551.rs:6:15
|
LL | let foo = B(marker::PhantomData);
- | --- ^ cannot infer type for `T`
+ | --- ^ cannot infer type for type parameter `T`
| |
| consider giving `foo` the explicit type `B<T>`, where the type parameter `T` is specified
diff --git a/src/test/ui/issues/issue-17718-const-bad-values.stderr b/src/test/ui/issues/issue-17718-const-bad-values.stderr
index 8d875d3..7e4a62a 100644
--- a/src/test/ui/issues/issue-17718-const-bad-values.stderr
+++ b/src/test/ui/issues/issue-17718-const-bad-values.stderr
@@ -1,8 +1,11 @@
-error[E0017]: references in constants may only refer to immutable values
+error[E0658]: references in constants may only refer to immutable values
--> $DIR/issue-17718-const-bad-values.rs:1:34
|
LL | const C1: &'static mut [usize] = &mut [];
| ^^^^^^^ constants require immutable values
+ |
+ = note: for more information, see https://github.com/rust-lang/rust/issues/57349
+ = help: add `#![feature(const_mut_refs)]` to the crate attributes to enable
error[E0013]: constants cannot refer to statics, use a constant instead
--> $DIR/issue-17718-const-bad-values.rs:5:46
@@ -10,13 +13,16 @@
LL | const C2: &'static mut usize = unsafe { &mut S };
| ^
-error[E0017]: references in constants may only refer to immutable values
+error[E0658]: references in constants may only refer to immutable values
--> $DIR/issue-17718-const-bad-values.rs:5:41
|
LL | const C2: &'static mut usize = unsafe { &mut S };
| ^^^^^^ constants require immutable values
+ |
+ = note: for more information, see https://github.com/rust-lang/rust/issues/57349
+ = help: add `#![feature(const_mut_refs)]` to the crate attributes to enable
error: aborting due to 3 previous errors
-Some errors have detailed explanations: E0013, E0017.
+Some errors have detailed explanations: E0013, E0658.
For more information about an error, try `rustc --explain E0013`.
diff --git a/src/test/ui/issues/issue-17758.stderr b/src/test/ui/issues/issue-17758.stderr
index adcbb62..adfc3f508 100644
--- a/src/test/ui/issues/issue-17758.stderr
+++ b/src/test/ui/issues/issue-17758.stderr
@@ -22,9 +22,13 @@
|
LL | trait Foo<'a> {
| ^^
- = note: ...so that the types are compatible:
- expected &'a Self
- found &Self
+note: ...so that the types are compatible
+ --> $DIR/issue-17758.rs:7:14
+ |
+LL | self.foo();
+ | ^^^
+ = note: expected `&'a Self`
+ found `&Self`
error: aborting due to previous error
diff --git a/src/test/ui/issues/issue-20831-debruijn.stderr b/src/test/ui/issues/issue-20831-debruijn.stderr
index 13c9c09..c7fd134 100644
--- a/src/test/ui/issues/issue-20831-debruijn.stderr
+++ b/src/test/ui/issues/issue-20831-debruijn.stderr
@@ -88,9 +88,19 @@
|
LL | impl<'a> Publisher<'a> for MyStruct<'a> {
| ^^
- = note: ...so that the types are compatible:
- expected Publisher<'_>
- found Publisher<'_>
+note: ...so that the types are compatible
+ --> $DIR/issue-20831-debruijn.rs:28:5
+ |
+LL | / fn subscribe(&mut self, t : Box<dyn Subscriber<Input=<Self as Publisher>::Output> + 'a>) {
+LL | | // Not obvious, but there is an implicit lifetime here -------^
+LL | |
+LL | |
+... |
+LL | | self.sub = t;
+LL | | }
+ | |_____^
+ = note: expected `Publisher<'_>`
+ found `Publisher<'_>`
error: aborting due to 3 previous errors
diff --git a/src/test/ui/issues/issue-21974.stderr b/src/test/ui/issues/issue-21974.stderr
index 7ceb2bd..b1536bd 100644
--- a/src/test/ui/issues/issue-21974.stderr
+++ b/src/test/ui/issues/issue-21974.stderr
@@ -1,4 +1,4 @@
-error[E0283]: type annotations needed: cannot resolve `&'a T: Foo`
+error[E0283]: type annotations needed
--> $DIR/issue-21974.rs:10:1
|
LL | trait Foo {
@@ -11,7 +11,9 @@
LL | | x.foo();
LL | | y.foo();
LL | | }
- | |_^
+ | |_^ cannot infer type for reference `&'a T`
+ |
+ = note: cannot resolve `&'a T: Foo`
error: aborting due to previous error
diff --git a/src/test/ui/issues/issue-2216.rs b/src/test/ui/issues/issue-2216.rs
index fa712ed..ad54107 100644
--- a/src/test/ui/issues/issue-2216.rs
+++ b/src/test/ui/issues/issue-2216.rs
@@ -5,7 +5,7 @@
'foo: loop {
'bar: loop {
- 'quux: loop {
+ loop {
if 1 == 2 {
break 'foo;
}
diff --git a/src/test/ui/issues/issue-24424.rs b/src/test/ui/issues/issue-24424.rs
index 9b74cd1..22bf513 100644
--- a/src/test/ui/issues/issue-24424.rs
+++ b/src/test/ui/issues/issue-24424.rs
@@ -2,6 +2,6 @@
trait Trait0<'l0> {}
impl <'l0, 'l1, T0> Trait1<'l0, T0> for bool where T0 : Trait0<'l0>, T0 : Trait0<'l1> {}
-//~^ ERROR type annotations needed: cannot resolve `T0: Trait0<'l0>`
+//~^ ERROR type annotations needed
fn main() {}
diff --git a/src/test/ui/issues/issue-24424.stderr b/src/test/ui/issues/issue-24424.stderr
index 8c539f7..8f08503 100644
--- a/src/test/ui/issues/issue-24424.stderr
+++ b/src/test/ui/issues/issue-24424.stderr
@@ -1,11 +1,13 @@
-error[E0283]: type annotations needed: cannot resolve `T0: Trait0<'l0>`
+error[E0283]: type annotations needed
--> $DIR/issue-24424.rs:4:1
|
LL | trait Trait0<'l0> {}
| ----------------- required by `Trait0`
LL |
LL | impl <'l0, 'l1, T0> Trait1<'l0, T0> for bool where T0 : Trait0<'l0>, T0 : Trait0<'l1> {}
- | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ cannot infer type for type parameter `T0`
+ |
+ = note: cannot resolve `T0: Trait0<'l0>`
error: aborting due to previous error
diff --git a/src/test/ui/issues/issue-25368.stderr b/src/test/ui/issues/issue-25368.stderr
index 0b890b5..de020d4 100644
--- a/src/test/ui/issues/issue-25368.stderr
+++ b/src/test/ui/issues/issue-25368.stderr
@@ -5,7 +5,7 @@
| -------- consider giving this pattern the explicit type `(std::sync::mpsc::Sender<Foo<T>>, std::sync::mpsc::Receiver<Foo<T>>)`, where the type parameter `T` is specified
...
LL | tx.send(Foo{ foo: PhantomData });
- | ^^^ cannot infer type for `T`
+ | ^^^ cannot infer type for type parameter `T`
error: aborting due to previous error
diff --git a/src/test/ui/issues/issue-29147.rs b/src/test/ui/issues/issue-29147.rs
index 7ec96b9..271bc52 100644
--- a/src/test/ui/issues/issue-29147.rs
+++ b/src/test/ui/issues/issue-29147.rs
@@ -18,5 +18,5 @@
impl Foo for S5<u64> { fn xxx(&self) {} }
fn main() {
- let _ = <S5<_>>::xxx; //~ ERROR cannot resolve `S5<_>: Foo`
+ let _ = <S5<_>>::xxx; //~ ERROR type annotations needed
}
diff --git a/src/test/ui/issues/issue-29147.stderr b/src/test/ui/issues/issue-29147.stderr
index c9dd92f..1efedb4 100644
--- a/src/test/ui/issues/issue-29147.stderr
+++ b/src/test/ui/issues/issue-29147.stderr
@@ -1,11 +1,13 @@
-error[E0283]: type annotations needed: cannot resolve `S5<_>: Foo`
+error[E0283]: type annotations needed
--> $DIR/issue-29147.rs:21:13
|
LL | trait Foo { fn xxx(&self); }
| -------------- required by `Foo::xxx`
...
LL | let _ = <S5<_>>::xxx;
- | ^^^^^^^^^^^^
+ | ^^^^^^^^^^^^ cannot infer type for struct `S5<_>`
+ |
+ = note: cannot resolve `S5<_>: Foo`
error: aborting due to previous error
diff --git a/src/test/ui/issues/issue-3601.stderr b/src/test/ui/issues/issue-3601.stderr
index fa0fa334..445eb41 100644
--- a/src/test/ui/issues/issue-3601.stderr
+++ b/src/test/ui/issues/issue-3601.stderr
@@ -1,8 +1,8 @@
-error[E0004]: non-exhaustive patterns: `_` not covered
+error[E0004]: non-exhaustive patterns: `Box(_)` not covered
--> $DIR/issue-3601.rs:30:44
|
LL | box NodeKind::Element(ed) => match ed.kind {
- | ^^^^^^^ pattern `_` not covered
+ | ^^^^^^^ pattern `Box(_)` not covered
|
= help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms
diff --git a/src/test/ui/issues/issue-43623.stderr b/src/test/ui/issues/issue-43623.stderr
index 2c57b85..d90eb53 100644
--- a/src/test/ui/issues/issue-43623.stderr
+++ b/src/test/ui/issues/issue-43623.stderr
@@ -25,4 +25,5 @@
error: aborting due to 2 previous errors
-For more information about this error, try `rustc --explain E0271`.
+Some errors have detailed explanations: E0271, E0631.
+For more information about an error, try `rustc --explain E0271`.
diff --git a/src/test/ui/issues/issue-46604.rs b/src/test/ui/issues/issue-46604.rs
index 4f1ad38..e1967eb 100644
--- a/src/test/ui/issues/issue-46604.rs
+++ b/src/test/ui/issues/issue-46604.rs
@@ -1,4 +1,4 @@
-static buf: &mut [u8] = &mut [1u8,2,3,4,5,7]; //~ ERROR E0017
+static buf: &mut [u8] = &mut [1u8,2,3,4,5,7]; //~ ERROR E0658
fn write<T: AsRef<[u8]>>(buffer: T) { }
fn main() {
diff --git a/src/test/ui/issues/issue-46604.stderr b/src/test/ui/issues/issue-46604.stderr
index c72f580..32c7ecb 100644
--- a/src/test/ui/issues/issue-46604.stderr
+++ b/src/test/ui/issues/issue-46604.stderr
@@ -1,8 +1,11 @@
-error[E0017]: references in statics may only refer to immutable values
+error[E0658]: references in statics may only refer to immutable values
--> $DIR/issue-46604.rs:1:25
|
LL | static buf: &mut [u8] = &mut [1u8,2,3,4,5,7];
| ^^^^^^^^^^^^^^^^^^^^ statics require immutable values
+ |
+ = note: for more information, see https://github.com/rust-lang/rust/issues/57349
+ = help: add `#![feature(const_mut_refs)]` to the crate attributes to enable
error[E0594]: cannot assign to `buf[_]`, as `buf` is an immutable static item
--> $DIR/issue-46604.rs:6:5
@@ -12,5 +15,5 @@
error: aborting due to 2 previous errors
-Some errors have detailed explanations: E0017, E0594.
-For more information about an error, try `rustc --explain E0017`.
+Some errors have detailed explanations: E0594, E0658.
+For more information about an error, try `rustc --explain E0594`.
diff --git a/src/test/ui/issues/issue-5062.stderr b/src/test/ui/issues/issue-5062.stderr
index 0f5c6d8..a20118d 100644
--- a/src/test/ui/issues/issue-5062.stderr
+++ b/src/test/ui/issues/issue-5062.stderr
@@ -2,7 +2,7 @@
--> $DIR/issue-5062.rs:1:29
|
LL | fn main() { format!("{:?}", None); }
- | ^^^^ cannot infer type for `T`
+ | ^^^^ cannot infer type for type parameter `T`
error: aborting due to previous error
diff --git a/src/test/ui/issues/issue-51632-try-desugar-incompatible-types.stderr b/src/test/ui/issues/issue-51632-try-desugar-incompatible-types.stderr
index aef6dc5..9ca983d 100644
--- a/src/test/ui/issues/issue-51632-try-desugar-incompatible-types.stderr
+++ b/src/test/ui/issues/issue-51632-try-desugar-incompatible-types.stderr
@@ -2,13 +2,18 @@
--> $DIR/issue-51632-try-desugar-incompatible-types.rs:8:5
|
LL | missing_discourses()?
- | ^^^^^^^^^^^^^^^^^^^^-
- | | |
- | | help: try removing this `?`
- | expected enum `std::result::Result`, found `isize`
+ | ^^^^^^^^^^^^^^^^^^^^^ expected enum `std::result::Result`, found `isize`
|
= note: expected enum `std::result::Result<isize, ()>`
found type `isize`
+help: try removing this `?`
+ |
+LL | missing_discourses()
+ | --
+help: try using a variant of the expected enum
+ |
+LL | Ok(missing_discourses()?)
+ |
error: aborting due to previous error
diff --git a/src/test/ui/issues/issue-52213.stderr b/src/test/ui/issues/issue-52213.stderr
index b79a5dd..a8960f7 100644
--- a/src/test/ui/issues/issue-52213.stderr
+++ b/src/test/ui/issues/issue-52213.stderr
@@ -9,9 +9,13 @@
|
LL | fn transmute_lifetime<'a, 'b, T>(t: &'a (T,)) -> &'b T {
| ^^
- = note: ...so that the types are compatible:
- expected (&&(T,),)
- found (&&'a (T,),)
+note: ...so that the types are compatible
+ --> $DIR/issue-52213.rs:2:11
+ |
+LL | match (&t,) {
+ | ^^^^^
+ = note: expected `(&&(T,),)`
+ found `(&&'a (T,),)`
note: but, the lifetime must be valid for the lifetime `'b` as defined on the function body at 1:27...
--> $DIR/issue-52213.rs:1:27
|
diff --git a/src/test/ui/issues/issue-54348.rs b/src/test/ui/issues/issue-54348.rs
index e7221e2..68d8380 100644
--- a/src/test/ui/issues/issue-54348.rs
+++ b/src/test/ui/issues/issue-54348.rs
@@ -1,7 +1,5 @@
fn main() {
[1][0u64 as usize];
[1][1.5 as usize]; //~ ERROR index out of bounds
- //~| ERROR this expression will panic at runtime
[1][1u64 as usize]; //~ ERROR index out of bounds
- //~| ERROR this expression will panic at runtime
}
diff --git a/src/test/ui/issues/issue-54348.stderr b/src/test/ui/issues/issue-54348.stderr
index 79320ef..fa77bd6 100644
--- a/src/test/ui/issues/issue-54348.stderr
+++ b/src/test/ui/issues/issue-54348.stderr
@@ -6,23 +6,11 @@
|
= note: `#[deny(const_err)]` on by default
-error: this expression will panic at runtime
- --> $DIR/issue-54348.rs:3:5
- |
-LL | [1][1.5 as usize];
- | ^^^^^^^^^^^^^^^^^ index out of bounds: the len is 1 but the index is 1
-
error: index out of bounds: the len is 1 but the index is 1
- --> $DIR/issue-54348.rs:5:5
+ --> $DIR/issue-54348.rs:4:5
|
LL | [1][1u64 as usize];
| ^^^^^^^^^^^^^^^^^^
-error: this expression will panic at runtime
- --> $DIR/issue-54348.rs:5:5
- |
-LL | [1][1u64 as usize];
- | ^^^^^^^^^^^^^^^^^^ index out of bounds: the len is 1 but the index is 1
-
-error: aborting due to 4 previous errors
+error: aborting due to 2 previous errors
diff --git a/src/test/ui/issues/issue-54954.stderr b/src/test/ui/issues/issue-54954.stderr
index 56ccdaf..d99a5772 100644
--- a/src/test/ui/issues/issue-54954.stderr
+++ b/src/test/ui/issues/issue-54954.stderr
@@ -4,14 +4,16 @@
LL | const fn const_val<T: Sized>() -> usize {
| ^^^^^ trait fns cannot be const
-error[E0283]: type annotations needed: cannot resolve `_: Tt`
+error[E0283]: type annotations needed
--> $DIR/issue-54954.rs:3:24
|
LL | const ARR_LEN: usize = Tt::const_val::<[i8; 123]>();
- | ^^^^^^^^^^^^^^^^^^^^^^^^^^
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^ cannot infer type
...
LL | const fn const_val<T: Sized>() -> usize {
| --------- - required by this bound in `Tt::const_val`
+ |
+ = note: cannot resolve `_: Tt`
error[E0080]: evaluation of constant value failed
--> $DIR/issue-54954.rs:13:15
diff --git a/src/test/ui/issues/issue-55796.stderr b/src/test/ui/issues/issue-55796.stderr
index 7b910f5..b8cafdc 100644
--- a/src/test/ui/issues/issue-55796.stderr
+++ b/src/test/ui/issues/issue-55796.stderr
@@ -15,9 +15,13 @@
LL | Box::new(self.out_edges(u).map(|e| e.target()))
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
= note: but, the lifetime must be valid for the static lifetime...
- = note: ...so that the expression is assignable:
- expected std::boxed::Box<(dyn std::iter::Iterator<Item = <Self as Graph<'a>>::Node> + 'static)>
- found std::boxed::Box<dyn std::iter::Iterator<Item = <Self as Graph<'a>>::Node>>
+note: ...so that the expression is assignable
+ --> $DIR/issue-55796.rs:16:9
+ |
+LL | Box::new(self.out_edges(u).map(|e| e.target()))
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+ = note: expected `std::boxed::Box<(dyn std::iter::Iterator<Item = <Self as Graph<'a>>::Node> + 'static)>`
+ found `std::boxed::Box<dyn std::iter::Iterator<Item = <Self as Graph<'a>>::Node>>`
error[E0495]: cannot infer an appropriate lifetime due to conflicting requirements
--> $DIR/issue-55796.rs:21:9
@@ -36,9 +40,13 @@
LL | Box::new(self.in_edges(u).map(|e| e.target()))
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
= note: but, the lifetime must be valid for the static lifetime...
- = note: ...so that the expression is assignable:
- expected std::boxed::Box<(dyn std::iter::Iterator<Item = <Self as Graph<'a>>::Node> + 'static)>
- found std::boxed::Box<dyn std::iter::Iterator<Item = <Self as Graph<'a>>::Node>>
+note: ...so that the expression is assignable
+ --> $DIR/issue-55796.rs:21:9
+ |
+LL | Box::new(self.in_edges(u).map(|e| e.target()))
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+ = note: expected `std::boxed::Box<(dyn std::iter::Iterator<Item = <Self as Graph<'a>>::Node> + 'static)>`
+ found `std::boxed::Box<dyn std::iter::Iterator<Item = <Self as Graph<'a>>::Node>>`
error: aborting due to 2 previous errors
diff --git a/src/test/ui/issues/issue-58022.rs b/src/test/ui/issues/issue-58022.rs
index 3052790..e4b9b3b 100644
--- a/src/test/ui/issues/issue-58022.rs
+++ b/src/test/ui/issues/issue-58022.rs
@@ -2,7 +2,7 @@
const SIZE: usize;
fn new(slice: &[u8; Foo::SIZE]) -> Self;
- //~^ ERROR: type annotations needed: cannot resolve `_: Foo`
+ //~^ ERROR: type annotations needed
}
pub struct Bar<T: ?Sized>(T);
diff --git a/src/test/ui/issues/issue-58022.stderr b/src/test/ui/issues/issue-58022.stderr
index a3e4cb6..ef0d66d 100644
--- a/src/test/ui/issues/issue-58022.stderr
+++ b/src/test/ui/issues/issue-58022.stderr
@@ -4,14 +4,16 @@
LL | Foo(Box::new(*slice))
| ^^^ not a function, tuple struct or tuple variant
-error[E0283]: type annotations needed: cannot resolve `_: Foo`
+error[E0283]: type annotations needed
--> $DIR/issue-58022.rs:4:25
|
LL | const SIZE: usize;
| ------------------ required by `Foo::SIZE`
LL |
LL | fn new(slice: &[u8; Foo::SIZE]) -> Self;
- | ^^^^^^^^^
+ | ^^^^^^^^^ cannot infer type
+ |
+ = note: cannot resolve `_: Foo`
error: aborting due to 2 previous errors
diff --git a/src/test/ui/issues/issue-59756.rs b/src/test/ui/issues/issue-59756.rs
index cccae39..d6df059 100644
--- a/src/test/ui/issues/issue-59756.rs
+++ b/src/test/ui/issues/issue-59756.rs
@@ -1,4 +1,8 @@
// run-rustfix
+// ignore-test
+//
+// FIXME: Re-enable this test once we support choosing
+// between multiple mutually exclusive suggestions for the same span
#![allow(warnings)]
diff --git a/src/test/ui/issues/issue-59756.stderr b/src/test/ui/issues/issue-59756.stderr
index 150916c..9066e57 100644
--- a/src/test/ui/issues/issue-59756.stderr
+++ b/src/test/ui/issues/issue-59756.stderr
@@ -2,13 +2,18 @@
--> $DIR/issue-59756.rs:13:5
|
LL | foo()?
- | ^^^^^-
- | | |
- | | help: try removing this `?`
- | expected enum `std::result::Result`, found struct `A`
+ | ^^^^^^ expected enum `std::result::Result`, found struct `A`
|
= note: expected enum `std::result::Result<A, B>`
found struct `A`
+help: try removing this `?`
+ |
+LL | foo()
+ | --
+help: try using a variant of the expected enum
+ |
+LL | Ok(foo()?)
+ |
error: aborting due to previous error
diff --git a/src/test/ui/issues/issue-60283.stderr b/src/test/ui/issues/issue-60283.stderr
index 69c1d85..d13dcd5 100644
--- a/src/test/ui/issues/issue-60283.stderr
+++ b/src/test/ui/issues/issue-60283.stderr
@@ -27,4 +27,5 @@
error: aborting due to 2 previous errors
-For more information about this error, try `rustc --explain E0271`.
+Some errors have detailed explanations: E0271, E0631.
+For more information about an error, try `rustc --explain E0271`.
diff --git a/src/test/ui/issues/issue-6458-2.stderr b/src/test/ui/issues/issue-6458-2.stderr
index b5da2bf..d538a69 100644
--- a/src/test/ui/issues/issue-6458-2.stderr
+++ b/src/test/ui/issues/issue-6458-2.stderr
@@ -2,7 +2,7 @@
--> $DIR/issue-6458-2.rs:3:21
|
LL | format!("{:?}", None);
- | ^^^^ cannot infer type for `T`
+ | ^^^^ cannot infer type for type parameter `T`
error: aborting due to previous error
diff --git a/src/test/ui/issues/issue-6458-3.stderr b/src/test/ui/issues/issue-6458-3.stderr
index 784497c..6b3f469 100644
--- a/src/test/ui/issues/issue-6458-3.stderr
+++ b/src/test/ui/issues/issue-6458-3.stderr
@@ -2,7 +2,7 @@
--> $DIR/issue-6458-3.rs:4:5
|
LL | mem::transmute(0);
- | ^^^^^^^^^^^^^^ cannot infer type for `U`
+ | ^^^^^^^^^^^^^^ cannot infer type for type parameter `U`
error: aborting due to previous error
diff --git a/src/test/ui/issues/issue-6458.stderr b/src/test/ui/issues/issue-6458.stderr
index d59d872..de31565 100644
--- a/src/test/ui/issues/issue-6458.stderr
+++ b/src/test/ui/issues/issue-6458.stderr
@@ -2,7 +2,7 @@
--> $DIR/issue-6458.rs:9:4
|
LL | foo(TypeWithState(marker::PhantomData));
- | ^^^ cannot infer type for `State`
+ | ^^^ cannot infer type for type parameter `State`
error: aborting due to previous error
diff --git a/src/test/ui/issues/issue-65611.stderr b/src/test/ui/issues/issue-65611.stderr
index cb441c1..20e2ba1 100644
--- a/src/test/ui/issues/issue-65611.stderr
+++ b/src/test/ui/issues/issue-65611.stderr
@@ -2,7 +2,10 @@
--> $DIR/issue-65611.rs:59:20
|
LL | let x = buffer.last().unwrap().0.clone();
- | ^^^^ cannot infer type for `T`
+ | -------^^^^--
+ | | |
+ | | cannot infer type for type parameter `T`
+ | this method call resolves to `std::option::Option<&T>`
|
= note: type must be known at this point
diff --git a/src/test/ui/issues/issue-65634-raw-ident-suggestion.rs b/src/test/ui/issues/issue-65634-raw-ident-suggestion.rs
new file mode 100644
index 0000000..b928510
--- /dev/null
+++ b/src/test/ui/issues/issue-65634-raw-ident-suggestion.rs
@@ -0,0 +1,22 @@
+#![allow(non_camel_case_types)]
+
+trait r#async {
+ fn r#struct(&self) {
+ println!("async");
+ }
+}
+
+trait r#await {
+ fn r#struct(&self) {
+ println!("await");
+ }
+}
+
+struct r#fn {}
+
+impl r#async for r#fn {}
+impl r#await for r#fn {}
+
+fn main() {
+ r#fn {}.r#struct(); //~ ERROR multiple applicable items in scope
+}
diff --git a/src/test/ui/issues/issue-65634-raw-ident-suggestion.stderr b/src/test/ui/issues/issue-65634-raw-ident-suggestion.stderr
new file mode 100644
index 0000000..c7bb653
--- /dev/null
+++ b/src/test/ui/issues/issue-65634-raw-ident-suggestion.stderr
@@ -0,0 +1,22 @@
+error[E0034]: multiple applicable items in scope
+ --> $DIR/issue-65634-raw-ident-suggestion.rs:21:13
+ |
+LL | r#fn {}.r#struct();
+ | ^^^^^^^^ multiple `r#struct` found
+ |
+note: candidate #1 is defined in an impl of the trait `async` for the type `r#fn`
+ --> $DIR/issue-65634-raw-ident-suggestion.rs:4:5
+ |
+LL | fn r#struct(&self) {
+ | ^^^^^^^^^^^^^^^^^^
+ = help: to disambiguate the method call, write `async::r#struct(r#fn {})` instead
+note: candidate #2 is defined in an impl of the trait `await` for the type `r#fn`
+ --> $DIR/issue-65634-raw-ident-suggestion.rs:10:5
+ |
+LL | fn r#struct(&self) {
+ | ^^^^^^^^^^^^^^^^^^
+ = help: to disambiguate the method call, write `await::r#struct(r#fn {})` instead
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0034`.
diff --git a/src/test/ui/issues/issue-66702-break-outside-loop-val.rs b/src/test/ui/issues/issue-66702-break-outside-loop-val.rs
new file mode 100644
index 0000000..bd3c00d
--- /dev/null
+++ b/src/test/ui/issues/issue-66702-break-outside-loop-val.rs
@@ -0,0 +1,7 @@
+// Breaks with values inside closures used to ICE (#66863)
+
+fn main() {
+ 'some_label: loop {
+ || break 'some_label (); //~ ERROR: `break` inside of a closure
+ }
+}
diff --git a/src/test/ui/issues/issue-66702-break-outside-loop-val.stderr b/src/test/ui/issues/issue-66702-break-outside-loop-val.stderr
new file mode 100644
index 0000000..83bde97
--- /dev/null
+++ b/src/test/ui/issues/issue-66702-break-outside-loop-val.stderr
@@ -0,0 +1,11 @@
+error[E0267]: `break` inside of a closure
+ --> $DIR/issue-66702-break-outside-loop-val.rs:5:12
+ |
+LL | || break 'some_label ();
+ | -- ^^^^^^^^^^^^^^^^^^^^ cannot `break` inside of a closure
+ | |
+ | enclosing closure
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0267`.
diff --git a/src/test/ui/issues/issue-67037-pat-tup-scrut-ty-diff-less-fields.rs b/src/test/ui/issues/issue-67037-pat-tup-scrut-ty-diff-less-fields.rs
new file mode 100644
index 0000000..44bd645
--- /dev/null
+++ b/src/test/ui/issues/issue-67037-pat-tup-scrut-ty-diff-less-fields.rs
@@ -0,0 +1,21 @@
+// Regression test for #67037.
+//
+// In type checking patterns, E0023 occurs when the tuple pattern and the expected
+// tuple pattern have different number of fields. For example, as below, `P()`,
+// the tuple struct pattern, has 0 fields, but requires 1 field.
+//
+// In emitting E0023, we try to see if this is a case of e.g., `Some(a, b, c)` but where
+// the scrutinee was of type `Some((a, b, c))`, and suggest that parenthesis be added.
+//
+// However, we did not account for the expected type being different than the tuple pattern type.
+// This caused an issue when the tuple pattern type (`P<T>`) was generic.
+// Specifically, we tried deriving the 0th field's type using the `substs` of the expected type.
+// When attempting to substitute `T`, there was no such substitution, so "out of range" occured.
+
+struct U {} // 0 type parameters offered
+struct P<T>(T); // 1 type parameter wanted
+
+fn main() {
+ let P() = U {}; //~ ERROR mismatched types
+ //~^ ERROR this pattern has 0 fields, but the corresponding tuple struct has 1 field
+}
diff --git a/src/test/ui/issues/issue-67037-pat-tup-scrut-ty-diff-less-fields.stderr b/src/test/ui/issues/issue-67037-pat-tup-scrut-ty-diff-less-fields.stderr
new file mode 100644
index 0000000..521dd02
--- /dev/null
+++ b/src/test/ui/issues/issue-67037-pat-tup-scrut-ty-diff-less-fields.stderr
@@ -0,0 +1,22 @@
+error[E0308]: mismatched types
+ --> $DIR/issue-67037-pat-tup-scrut-ty-diff-less-fields.rs:19:9
+ |
+LL | let P() = U {};
+ | ^^^ expected struct `U`, found struct `P`
+ |
+ = note: expected struct `U`
+ found struct `P<_>`
+
+error[E0023]: this pattern has 0 fields, but the corresponding tuple struct has 1 field
+ --> $DIR/issue-67037-pat-tup-scrut-ty-diff-less-fields.rs:19:9
+ |
+LL | struct P<T>(T); // 1 type parameter wanted
+ | --------------- tuple struct defined here
+...
+LL | let P() = U {};
+ | ^^^ expected 1 field, found 0
+
+error: aborting due to 2 previous errors
+
+Some errors have detailed explanations: E0023, E0308.
+For more information about an error, try `rustc --explain E0023`.
diff --git a/src/test/ui/issues/issue-67039-unsound-pin-partialeq.rs b/src/test/ui/issues/issue-67039-unsound-pin-partialeq.rs
new file mode 100644
index 0000000..a496e58
--- /dev/null
+++ b/src/test/ui/issues/issue-67039-unsound-pin-partialeq.rs
@@ -0,0 +1,27 @@
+// Pin's PartialEq implementation allowed to access the pointer allowing for
+// unsoundness by using Rc::get_mut to move value within Rc.
+// See https://internals.rust-lang.org/t/unsoundness-in-pin/11311/73 for more details.
+
+use std::ops::Deref;
+use std::pin::Pin;
+use std::rc::Rc;
+
+struct Apple;
+
+impl Deref for Apple {
+ type Target = Apple;
+ fn deref(&self) -> &Apple {
+ &Apple
+ }
+}
+
+impl PartialEq<Rc<Apple>> for Apple {
+ fn eq(&self, _rc: &Rc<Apple>) -> bool {
+ unreachable!()
+ }
+}
+
+fn main() {
+ let _ = Pin::new(Apple) == Rc::pin(Apple);
+ //~^ ERROR type mismatch resolving
+}
diff --git a/src/test/ui/issues/issue-67039-unsound-pin-partialeq.stderr b/src/test/ui/issues/issue-67039-unsound-pin-partialeq.stderr
new file mode 100644
index 0000000..3330d60
--- /dev/null
+++ b/src/test/ui/issues/issue-67039-unsound-pin-partialeq.stderr
@@ -0,0 +1,13 @@
+error[E0271]: type mismatch resolving `<std::rc::Rc<Apple> as std::ops::Deref>::Target == std::rc::Rc<Apple>`
+ --> $DIR/issue-67039-unsound-pin-partialeq.rs:25:29
+ |
+LL | let _ = Pin::new(Apple) == Rc::pin(Apple);
+ | ^^ expected struct `Apple`, found struct `std::rc::Rc`
+ |
+ = note: expected type `Apple`
+ found struct `std::rc::Rc<Apple>`
+ = note: required because of the requirements on the impl of `std::cmp::PartialEq<std::pin::Pin<std::rc::Rc<Apple>>>` for `std::pin::Pin<Apple>`
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0271`.
diff --git a/src/test/ui/issues/issue-8460-const.rs b/src/test/ui/issues/issue-8460-const.rs
index 4637814..71e2b58 100644
--- a/src/test/ui/issues/issue-8460-const.rs
+++ b/src/test/ui/issues/issue-8460-const.rs
@@ -23,19 +23,14 @@
//~| ERROR this expression will panic at runtime
assert!(thread::spawn(move|| { 1isize / 0; }).join().is_err());
//~^ ERROR attempt to divide by zero
- //~| ERROR this expression will panic at runtime
assert!(thread::spawn(move|| { 1i8 / 0; }).join().is_err());
//~^ ERROR attempt to divide by zero
- //~| ERROR this expression will panic at runtime
assert!(thread::spawn(move|| { 1i16 / 0; }).join().is_err());
//~^ ERROR attempt to divide by zero
- //~| ERROR this expression will panic at runtime
assert!(thread::spawn(move|| { 1i32 / 0; }).join().is_err());
//~^ ERROR attempt to divide by zero
- //~| ERROR this expression will panic at runtime
assert!(thread::spawn(move|| { 1i64 / 0; }).join().is_err());
//~^ ERROR attempt to divide by zero
- //~| ERROR this expression will panic at runtime
assert!(thread::spawn(move|| { isize::MIN % -1; }).join().is_err());
//~^ ERROR attempt to calculate the remainder with overflow
//~| ERROR this expression will panic at runtime
@@ -53,17 +48,12 @@
//~| ERROR this expression will panic at runtime
assert!(thread::spawn(move|| { 1isize % 0; }).join().is_err());
//~^ ERROR attempt to calculate the remainder with a divisor of zero
- //~| ERROR this expression will panic at runtime
assert!(thread::spawn(move|| { 1i8 % 0; }).join().is_err());
//~^ ERROR attempt to calculate the remainder with a divisor of zero
- //~| ERROR this expression will panic at runtime
assert!(thread::spawn(move|| { 1i16 % 0; }).join().is_err());
//~^ ERROR attempt to calculate the remainder with a divisor of zero
- //~| ERROR this expression will panic at runtime
assert!(thread::spawn(move|| { 1i32 % 0; }).join().is_err());
//~^ ERROR attempt to calculate the remainder with a divisor of zero
- //~| ERROR this expression will panic at runtime
assert!(thread::spawn(move|| { 1i64 % 0; }).join().is_err());
//~^ ERROR attempt to calculate the remainder with a divisor of zero
- //~| ERROR this expression will panic at runtime
}
diff --git a/src/test/ui/issues/issue-8460-const.stderr b/src/test/ui/issues/issue-8460-const.stderr
index 7e5a22e..c6750e6 100644
--- a/src/test/ui/issues/issue-8460-const.stderr
+++ b/src/test/ui/issues/issue-8460-const.stderr
@@ -70,179 +70,119 @@
LL | assert!(thread::spawn(move|| { 1isize / 0; }).join().is_err());
| ^^^^^^^^^^
-error: this expression will panic at runtime
- --> $DIR/issue-8460-const.rs:24:36
- |
-LL | assert!(thread::spawn(move|| { 1isize / 0; }).join().is_err());
- | ^^^^^^^^^^ attempt to divide by zero
-
error: attempt to divide by zero
- --> $DIR/issue-8460-const.rs:27:36
+ --> $DIR/issue-8460-const.rs:26:36
|
LL | assert!(thread::spawn(move|| { 1i8 / 0; }).join().is_err());
| ^^^^^^^
-error: this expression will panic at runtime
- --> $DIR/issue-8460-const.rs:27:36
- |
-LL | assert!(thread::spawn(move|| { 1i8 / 0; }).join().is_err());
- | ^^^^^^^ attempt to divide by zero
-
error: attempt to divide by zero
- --> $DIR/issue-8460-const.rs:30:36
+ --> $DIR/issue-8460-const.rs:28:36
|
LL | assert!(thread::spawn(move|| { 1i16 / 0; }).join().is_err());
| ^^^^^^^^
-error: this expression will panic at runtime
+error: attempt to divide by zero
--> $DIR/issue-8460-const.rs:30:36
|
-LL | assert!(thread::spawn(move|| { 1i16 / 0; }).join().is_err());
- | ^^^^^^^^ attempt to divide by zero
-
-error: attempt to divide by zero
- --> $DIR/issue-8460-const.rs:33:36
- |
LL | assert!(thread::spawn(move|| { 1i32 / 0; }).join().is_err());
| ^^^^^^^^
-error: this expression will panic at runtime
- --> $DIR/issue-8460-const.rs:33:36
- |
-LL | assert!(thread::spawn(move|| { 1i32 / 0; }).join().is_err());
- | ^^^^^^^^ attempt to divide by zero
-
error: attempt to divide by zero
- --> $DIR/issue-8460-const.rs:36:36
+ --> $DIR/issue-8460-const.rs:32:36
|
LL | assert!(thread::spawn(move|| { 1i64 / 0; }).join().is_err());
| ^^^^^^^^
-error: this expression will panic at runtime
- --> $DIR/issue-8460-const.rs:36:36
- |
-LL | assert!(thread::spawn(move|| { 1i64 / 0; }).join().is_err());
- | ^^^^^^^^ attempt to divide by zero
-
error: attempt to calculate the remainder with overflow
- --> $DIR/issue-8460-const.rs:39:36
+ --> $DIR/issue-8460-const.rs:34:36
|
LL | assert!(thread::spawn(move|| { isize::MIN % -1; }).join().is_err());
| ^^^^^^^^^^^^^^^
error: this expression will panic at runtime
- --> $DIR/issue-8460-const.rs:39:36
+ --> $DIR/issue-8460-const.rs:34:36
|
LL | assert!(thread::spawn(move|| { isize::MIN % -1; }).join().is_err());
| ^^^^^^^^^^^^^^^ attempt to calculate the remainder with overflow
error: attempt to calculate the remainder with overflow
- --> $DIR/issue-8460-const.rs:42:36
+ --> $DIR/issue-8460-const.rs:37:36
|
LL | assert!(thread::spawn(move|| { i8::MIN % -1; }).join().is_err());
| ^^^^^^^^^^^^
error: this expression will panic at runtime
- --> $DIR/issue-8460-const.rs:42:36
+ --> $DIR/issue-8460-const.rs:37:36
|
LL | assert!(thread::spawn(move|| { i8::MIN % -1; }).join().is_err());
| ^^^^^^^^^^^^ attempt to calculate the remainder with overflow
error: attempt to calculate the remainder with overflow
- --> $DIR/issue-8460-const.rs:45:36
+ --> $DIR/issue-8460-const.rs:40:36
|
LL | assert!(thread::spawn(move|| { i16::MIN % -1; }).join().is_err());
| ^^^^^^^^^^^^^
error: this expression will panic at runtime
- --> $DIR/issue-8460-const.rs:45:36
+ --> $DIR/issue-8460-const.rs:40:36
|
LL | assert!(thread::spawn(move|| { i16::MIN % -1; }).join().is_err());
| ^^^^^^^^^^^^^ attempt to calculate the remainder with overflow
error: attempt to calculate the remainder with overflow
- --> $DIR/issue-8460-const.rs:48:36
+ --> $DIR/issue-8460-const.rs:43:36
|
LL | assert!(thread::spawn(move|| { i32::MIN % -1; }).join().is_err());
| ^^^^^^^^^^^^^
error: this expression will panic at runtime
- --> $DIR/issue-8460-const.rs:48:36
+ --> $DIR/issue-8460-const.rs:43:36
|
LL | assert!(thread::spawn(move|| { i32::MIN % -1; }).join().is_err());
| ^^^^^^^^^^^^^ attempt to calculate the remainder with overflow
error: attempt to calculate the remainder with overflow
- --> $DIR/issue-8460-const.rs:51:36
+ --> $DIR/issue-8460-const.rs:46:36
|
LL | assert!(thread::spawn(move|| { i64::MIN % -1; }).join().is_err());
| ^^^^^^^^^^^^^
error: this expression will panic at runtime
- --> $DIR/issue-8460-const.rs:51:36
+ --> $DIR/issue-8460-const.rs:46:36
|
LL | assert!(thread::spawn(move|| { i64::MIN % -1; }).join().is_err());
| ^^^^^^^^^^^^^ attempt to calculate the remainder with overflow
error: attempt to calculate the remainder with a divisor of zero
- --> $DIR/issue-8460-const.rs:54:36
+ --> $DIR/issue-8460-const.rs:49:36
|
LL | assert!(thread::spawn(move|| { 1isize % 0; }).join().is_err());
| ^^^^^^^^^^
-error: this expression will panic at runtime
- --> $DIR/issue-8460-const.rs:54:36
- |
-LL | assert!(thread::spawn(move|| { 1isize % 0; }).join().is_err());
- | ^^^^^^^^^^ attempt to calculate the remainder with a divisor of zero
-
error: attempt to calculate the remainder with a divisor of zero
- --> $DIR/issue-8460-const.rs:57:36
+ --> $DIR/issue-8460-const.rs:51:36
|
LL | assert!(thread::spawn(move|| { 1i8 % 0; }).join().is_err());
| ^^^^^^^
-error: this expression will panic at runtime
+error: attempt to calculate the remainder with a divisor of zero
+ --> $DIR/issue-8460-const.rs:53:36
+ |
+LL | assert!(thread::spawn(move|| { 1i16 % 0; }).join().is_err());
+ | ^^^^^^^^
+
+error: attempt to calculate the remainder with a divisor of zero
+ --> $DIR/issue-8460-const.rs:55:36
+ |
+LL | assert!(thread::spawn(move|| { 1i32 % 0; }).join().is_err());
+ | ^^^^^^^^
+
+error: attempt to calculate the remainder with a divisor of zero
--> $DIR/issue-8460-const.rs:57:36
|
-LL | assert!(thread::spawn(move|| { 1i8 % 0; }).join().is_err());
- | ^^^^^^^ attempt to calculate the remainder with a divisor of zero
-
-error: attempt to calculate the remainder with a divisor of zero
- --> $DIR/issue-8460-const.rs:60:36
- |
-LL | assert!(thread::spawn(move|| { 1i16 % 0; }).join().is_err());
- | ^^^^^^^^
-
-error: this expression will panic at runtime
- --> $DIR/issue-8460-const.rs:60:36
- |
-LL | assert!(thread::spawn(move|| { 1i16 % 0; }).join().is_err());
- | ^^^^^^^^ attempt to calculate the remainder with a divisor of zero
-
-error: attempt to calculate the remainder with a divisor of zero
- --> $DIR/issue-8460-const.rs:63:36
- |
-LL | assert!(thread::spawn(move|| { 1i32 % 0; }).join().is_err());
- | ^^^^^^^^
-
-error: this expression will panic at runtime
- --> $DIR/issue-8460-const.rs:63:36
- |
-LL | assert!(thread::spawn(move|| { 1i32 % 0; }).join().is_err());
- | ^^^^^^^^ attempt to calculate the remainder with a divisor of zero
-
-error: attempt to calculate the remainder with a divisor of zero
- --> $DIR/issue-8460-const.rs:66:36
- |
LL | assert!(thread::spawn(move|| { 1i64 % 0; }).join().is_err());
| ^^^^^^^^
-error: this expression will panic at runtime
- --> $DIR/issue-8460-const.rs:66:36
- |
-LL | assert!(thread::spawn(move|| { 1i64 % 0; }).join().is_err());
- | ^^^^^^^^ attempt to calculate the remainder with a divisor of zero
-
-error: aborting due to 40 previous errors
+error: aborting due to 30 previous errors
diff --git a/src/test/ui/issues/issue-8460-const2.rs b/src/test/ui/issues/issue-8460-const2.rs
index c3f53e3..723a179 100644
--- a/src/test/ui/issues/issue-8460-const2.rs
+++ b/src/test/ui/issues/issue-8460-const2.rs
@@ -18,19 +18,14 @@
//~^ ERROR attempt to divide with overflow
assert!(thread::spawn(move|| { 1isize / 0; }).join().is_err());
//~^ ERROR attempt to divide by zero
- //~| ERROR this expression will panic at runtime
assert!(thread::spawn(move|| { 1i8 / 0; }).join().is_err());
//~^ ERROR attempt to divide by zero
- //~| ERROR this expression will panic at runtime
assert!(thread::spawn(move|| { 1i16 / 0; }).join().is_err());
//~^ ERROR attempt to divide by zero
- //~| ERROR this expression will panic at runtime
assert!(thread::spawn(move|| { 1i32 / 0; }).join().is_err());
//~^ ERROR attempt to divide by zero
- //~| ERROR this expression will panic at runtime
assert!(thread::spawn(move|| { 1i64 / 0; }).join().is_err());
//~^ ERROR attempt to divide by zero
- //~| ERROR this expression will panic at runtime
assert!(thread::spawn(move|| { isize::MIN % -1; }).join().is_err());
//~^ ERROR attempt to calculate the remainder with overflow
assert!(thread::spawn(move|| { i8::MIN % -1; }).join().is_err());
@@ -43,17 +38,12 @@
//~^ ERROR attempt to calculate the remainder with overflow
assert!(thread::spawn(move|| { 1isize % 0; }).join().is_err());
//~^ ERROR attempt to calculate the remainder with a divisor of zero
- //~| ERROR this expression will panic at runtime
assert!(thread::spawn(move|| { 1i8 % 0; }).join().is_err());
//~^ ERROR attempt to calculate the remainder with a divisor of zero
- //~| ERROR this expression will panic at runtime
assert!(thread::spawn(move|| { 1i16 % 0; }).join().is_err());
//~^ ERROR attempt to calculate the remainder with a divisor of zero
- //~| ERROR this expression will panic at runtime
assert!(thread::spawn(move|| { 1i32 % 0; }).join().is_err());
//~^ ERROR attempt to calculate the remainder with a divisor of zero
- //~| ERROR this expression will panic at runtime
assert!(thread::spawn(move|| { 1i64 % 0; }).join().is_err());
//~^ ERROR attempt to calculate the remainder with a divisor of zero
- //~| ERROR this expression will panic at runtime
}
diff --git a/src/test/ui/issues/issue-8460-const2.stderr b/src/test/ui/issues/issue-8460-const2.stderr
index b688ec1..87b9b2d 100644
--- a/src/test/ui/issues/issue-8460-const2.stderr
+++ b/src/test/ui/issues/issue-8460-const2.stderr
@@ -40,149 +40,89 @@
LL | assert!(thread::spawn(move|| { 1isize / 0; }).join().is_err());
| ^^^^^^^^^^
-error: this expression will panic at runtime
- --> $DIR/issue-8460-const2.rs:19:36
- |
-LL | assert!(thread::spawn(move|| { 1isize / 0; }).join().is_err());
- | ^^^^^^^^^^ attempt to divide by zero
-
error: attempt to divide by zero
- --> $DIR/issue-8460-const2.rs:22:36
+ --> $DIR/issue-8460-const2.rs:21:36
|
LL | assert!(thread::spawn(move|| { 1i8 / 0; }).join().is_err());
| ^^^^^^^
-error: this expression will panic at runtime
- --> $DIR/issue-8460-const2.rs:22:36
- |
-LL | assert!(thread::spawn(move|| { 1i8 / 0; }).join().is_err());
- | ^^^^^^^ attempt to divide by zero
-
error: attempt to divide by zero
- --> $DIR/issue-8460-const2.rs:25:36
+ --> $DIR/issue-8460-const2.rs:23:36
|
LL | assert!(thread::spawn(move|| { 1i16 / 0; }).join().is_err());
| ^^^^^^^^
-error: this expression will panic at runtime
+error: attempt to divide by zero
--> $DIR/issue-8460-const2.rs:25:36
|
-LL | assert!(thread::spawn(move|| { 1i16 / 0; }).join().is_err());
- | ^^^^^^^^ attempt to divide by zero
-
-error: attempt to divide by zero
- --> $DIR/issue-8460-const2.rs:28:36
- |
LL | assert!(thread::spawn(move|| { 1i32 / 0; }).join().is_err());
| ^^^^^^^^
-error: this expression will panic at runtime
- --> $DIR/issue-8460-const2.rs:28:36
- |
-LL | assert!(thread::spawn(move|| { 1i32 / 0; }).join().is_err());
- | ^^^^^^^^ attempt to divide by zero
-
error: attempt to divide by zero
- --> $DIR/issue-8460-const2.rs:31:36
+ --> $DIR/issue-8460-const2.rs:27:36
|
LL | assert!(thread::spawn(move|| { 1i64 / 0; }).join().is_err());
| ^^^^^^^^
-error: this expression will panic at runtime
- --> $DIR/issue-8460-const2.rs:31:36
- |
-LL | assert!(thread::spawn(move|| { 1i64 / 0; }).join().is_err());
- | ^^^^^^^^ attempt to divide by zero
-
error: attempt to calculate the remainder with overflow
- --> $DIR/issue-8460-const2.rs:34:36
+ --> $DIR/issue-8460-const2.rs:29:36
|
LL | assert!(thread::spawn(move|| { isize::MIN % -1; }).join().is_err());
| ^^^^^^^^^^^^^^^
error: attempt to calculate the remainder with overflow
- --> $DIR/issue-8460-const2.rs:36:36
+ --> $DIR/issue-8460-const2.rs:31:36
|
LL | assert!(thread::spawn(move|| { i8::MIN % -1; }).join().is_err());
| ^^^^^^^^^^^^
error: attempt to calculate the remainder with overflow
- --> $DIR/issue-8460-const2.rs:38:36
+ --> $DIR/issue-8460-const2.rs:33:36
|
LL | assert!(thread::spawn(move|| { i16::MIN % -1; }).join().is_err());
| ^^^^^^^^^^^^^
error: attempt to calculate the remainder with overflow
- --> $DIR/issue-8460-const2.rs:40:36
+ --> $DIR/issue-8460-const2.rs:35:36
|
LL | assert!(thread::spawn(move|| { i32::MIN % -1; }).join().is_err());
| ^^^^^^^^^^^^^
error: attempt to calculate the remainder with overflow
- --> $DIR/issue-8460-const2.rs:42:36
+ --> $DIR/issue-8460-const2.rs:37:36
|
LL | assert!(thread::spawn(move|| { i64::MIN % -1; }).join().is_err());
| ^^^^^^^^^^^^^
error: attempt to calculate the remainder with a divisor of zero
- --> $DIR/issue-8460-const2.rs:44:36
+ --> $DIR/issue-8460-const2.rs:39:36
|
LL | assert!(thread::spawn(move|| { 1isize % 0; }).join().is_err());
| ^^^^^^^^^^
-error: this expression will panic at runtime
- --> $DIR/issue-8460-const2.rs:44:36
- |
-LL | assert!(thread::spawn(move|| { 1isize % 0; }).join().is_err());
- | ^^^^^^^^^^ attempt to calculate the remainder with a divisor of zero
-
error: attempt to calculate the remainder with a divisor of zero
- --> $DIR/issue-8460-const2.rs:47:36
+ --> $DIR/issue-8460-const2.rs:41:36
|
LL | assert!(thread::spawn(move|| { 1i8 % 0; }).join().is_err());
| ^^^^^^^
-error: this expression will panic at runtime
+error: attempt to calculate the remainder with a divisor of zero
+ --> $DIR/issue-8460-const2.rs:43:36
+ |
+LL | assert!(thread::spawn(move|| { 1i16 % 0; }).join().is_err());
+ | ^^^^^^^^
+
+error: attempt to calculate the remainder with a divisor of zero
+ --> $DIR/issue-8460-const2.rs:45:36
+ |
+LL | assert!(thread::spawn(move|| { 1i32 % 0; }).join().is_err());
+ | ^^^^^^^^
+
+error: attempt to calculate the remainder with a divisor of zero
--> $DIR/issue-8460-const2.rs:47:36
|
-LL | assert!(thread::spawn(move|| { 1i8 % 0; }).join().is_err());
- | ^^^^^^^ attempt to calculate the remainder with a divisor of zero
-
-error: attempt to calculate the remainder with a divisor of zero
- --> $DIR/issue-8460-const2.rs:50:36
- |
-LL | assert!(thread::spawn(move|| { 1i16 % 0; }).join().is_err());
- | ^^^^^^^^
-
-error: this expression will panic at runtime
- --> $DIR/issue-8460-const2.rs:50:36
- |
-LL | assert!(thread::spawn(move|| { 1i16 % 0; }).join().is_err());
- | ^^^^^^^^ attempt to calculate the remainder with a divisor of zero
-
-error: attempt to calculate the remainder with a divisor of zero
- --> $DIR/issue-8460-const2.rs:53:36
- |
-LL | assert!(thread::spawn(move|| { 1i32 % 0; }).join().is_err());
- | ^^^^^^^^
-
-error: this expression will panic at runtime
- --> $DIR/issue-8460-const2.rs:53:36
- |
-LL | assert!(thread::spawn(move|| { 1i32 % 0; }).join().is_err());
- | ^^^^^^^^ attempt to calculate the remainder with a divisor of zero
-
-error: attempt to calculate the remainder with a divisor of zero
- --> $DIR/issue-8460-const2.rs:56:36
- |
LL | assert!(thread::spawn(move|| { 1i64 % 0; }).join().is_err());
| ^^^^^^^^
-error: this expression will panic at runtime
- --> $DIR/issue-8460-const2.rs:56:36
- |
-LL | assert!(thread::spawn(move|| { 1i64 % 0; }).join().is_err());
- | ^^^^^^^^ attempt to calculate the remainder with a divisor of zero
-
-error: aborting due to 30 previous errors
+error: aborting due to 20 previous errors
diff --git a/src/test/ui/lint/issue-47775-nested-macro-unnecessary-parens-arg.rs b/src/test/ui/lint/issue-47775-nested-macro-unnecessary-parens-arg.rs
index ab9baa7..0a951cf 100644
--- a/src/test/ui/lint/issue-47775-nested-macro-unnecessary-parens-arg.rs
+++ b/src/test/ui/lint/issue-47775-nested-macro-unnecessary-parens-arg.rs
@@ -17,10 +17,7 @@
macro_rules! and_the_heavens_reject_not {
() => {
- // ↓ But let's test that we still lint for unused parens around
- // function args inside of simple, one-deep macros.
#[allow(dead_code)] fn the_night_for_the_morrow() -> Option<isize> { Some((2)) }
- //~^ WARN unnecessary parentheses around function argument
}
}
diff --git a/src/test/ui/lint/issue-47775-nested-macro-unnecessary-parens-arg.stderr b/src/test/ui/lint/issue-47775-nested-macro-unnecessary-parens-arg.stderr
deleted file mode 100644
index 57cdcd7..0000000
--- a/src/test/ui/lint/issue-47775-nested-macro-unnecessary-parens-arg.stderr
+++ /dev/null
@@ -1,15 +0,0 @@
-warning: unnecessary parentheses around function argument
- --> $DIR/issue-47775-nested-macro-unnecessary-parens-arg.rs:22:83
- |
-LL | #[allow(dead_code)] fn the_night_for_the_morrow() -> Option<isize> { Some((2)) }
- | ^^^ help: remove these parentheses
-...
-LL | and_the_heavens_reject_not!();
- | ------------------------------ in this macro invocation
- |
-note: lint level defined here
- --> $DIR/issue-47775-nested-macro-unnecessary-parens-arg.rs:3:9
- |
-LL | #![warn(unused_parens)]
- | ^^^^^^^^^^^^^
-
diff --git a/src/test/ui/lint/lint-unnecessary-parens.rs b/src/test/ui/lint/lint-unnecessary-parens.rs
index 9f42b85..12ffb6d 100644
--- a/src/test/ui/lint/lint-unnecessary-parens.rs
+++ b/src/test/ui/lint/lint-unnecessary-parens.rs
@@ -25,6 +25,12 @@
panic!()
}
+macro_rules! baz {
+ ($($foo:expr),+) => {
+ ($($foo),*)
+ }
+}
+
fn main() {
foo();
bar((true)); //~ ERROR unnecessary parentheses around function argument
@@ -55,4 +61,7 @@
let mut _a = (0); //~ ERROR unnecessary parentheses around assigned value
_a = (0); //~ ERROR unnecessary parentheses around assigned value
_a += (1); //~ ERROR unnecessary parentheses around assigned value
+
+ let _a = baz!(3, 4);
+ let _b = baz!(3);
}
diff --git a/src/test/ui/lint/lint-unnecessary-parens.stderr b/src/test/ui/lint/lint-unnecessary-parens.stderr
index adc1069..541ae7a 100644
--- a/src/test/ui/lint/lint-unnecessary-parens.stderr
+++ b/src/test/ui/lint/lint-unnecessary-parens.stderr
@@ -23,25 +23,25 @@
| ^^^^^ help: remove these parentheses
error: unnecessary parentheses around function argument
- --> $DIR/lint-unnecessary-parens.rs:30:9
+ --> $DIR/lint-unnecessary-parens.rs:36:9
|
LL | bar((true));
| ^^^^^^ help: remove these parentheses
error: unnecessary parentheses around `if` condition
- --> $DIR/lint-unnecessary-parens.rs:32:8
+ --> $DIR/lint-unnecessary-parens.rs:38:8
|
LL | if (true) {}
| ^^^^^^ help: remove these parentheses
error: unnecessary parentheses around `while` condition
- --> $DIR/lint-unnecessary-parens.rs:33:11
+ --> $DIR/lint-unnecessary-parens.rs:39:11
|
LL | while (true) {}
| ^^^^^^ help: remove these parentheses
warning: denote infinite loops with `loop { ... }`
- --> $DIR/lint-unnecessary-parens.rs:33:5
+ --> $DIR/lint-unnecessary-parens.rs:39:5
|
LL | while (true) {}
| ^^^^^^^^^^^^ help: use `loop`
@@ -49,43 +49,43 @@
= note: `#[warn(while_true)]` on by default
error: unnecessary parentheses around `match` head expression
- --> $DIR/lint-unnecessary-parens.rs:35:11
+ --> $DIR/lint-unnecessary-parens.rs:41:11
|
LL | match (true) {
| ^^^^^^ help: remove these parentheses
error: unnecessary parentheses around `let` head expression
- --> $DIR/lint-unnecessary-parens.rs:38:16
+ --> $DIR/lint-unnecessary-parens.rs:44:16
|
LL | if let 1 = (1) {}
| ^^^ help: remove these parentheses
error: unnecessary parentheses around `let` head expression
- --> $DIR/lint-unnecessary-parens.rs:39:19
+ --> $DIR/lint-unnecessary-parens.rs:45:19
|
LL | while let 1 = (2) {}
| ^^^ help: remove these parentheses
error: unnecessary parentheses around method argument
- --> $DIR/lint-unnecessary-parens.rs:53:24
+ --> $DIR/lint-unnecessary-parens.rs:59:24
|
LL | X { y: false }.foo((true));
| ^^^^^^ help: remove these parentheses
error: unnecessary parentheses around assigned value
- --> $DIR/lint-unnecessary-parens.rs:55:18
+ --> $DIR/lint-unnecessary-parens.rs:61:18
|
LL | let mut _a = (0);
| ^^^ help: remove these parentheses
error: unnecessary parentheses around assigned value
- --> $DIR/lint-unnecessary-parens.rs:56:10
+ --> $DIR/lint-unnecessary-parens.rs:62:10
|
LL | _a = (0);
| ^^^ help: remove these parentheses
error: unnecessary parentheses around assigned value
- --> $DIR/lint-unnecessary-parens.rs:57:11
+ --> $DIR/lint-unnecessary-parens.rs:63:11
|
LL | _a += (1);
| ^^^ help: remove these parentheses
diff --git a/src/test/ui/macros/macro-lifetime-used-with-labels.rs b/src/test/ui/macros/macro-lifetime-used-with-labels.rs
index 86a3e9f..2e9da6f 100644
--- a/src/test/ui/macros/macro-lifetime-used-with-labels.rs
+++ b/src/test/ui/macros/macro-lifetime-used-with-labels.rs
@@ -1,6 +1,6 @@
// run-pass
#![allow(stable_features)]
-
+#![allow(unused_labels)]
#![allow(unreachable_code)]
macro_rules! x {
diff --git a/src/test/ui/malformed/malformed-derive-entry.rs b/src/test/ui/malformed/malformed-derive-entry.rs
index a6d8863..77fa2f5 100644
--- a/src/test/ui/malformed/malformed-derive-entry.rs
+++ b/src/test/ui/malformed/malformed-derive-entry.rs
@@ -1,7 +1,11 @@
-#[derive(Copy(Bad))] //~ ERROR expected one of `)`, `,`, or `::`, found `(`
+#[derive(Copy(Bad))]
+//~^ ERROR traits in `#[derive(...)]` don't accept arguments
+//~| ERROR the trait bound
struct Test1;
-#[derive(Copy="bad")] //~ ERROR expected one of `)`, `,`, or `::`, found `=`
+#[derive(Copy="bad")]
+//~^ ERROR traits in `#[derive(...)]` don't accept values
+//~| ERROR the trait bound
struct Test2;
#[derive] //~ ERROR malformed `derive` attribute input
diff --git a/src/test/ui/malformed/malformed-derive-entry.stderr b/src/test/ui/malformed/malformed-derive-entry.stderr
index 8d750b6..1f1ee39 100644
--- a/src/test/ui/malformed/malformed-derive-entry.stderr
+++ b/src/test/ui/malformed/malformed-derive-entry.stderr
@@ -1,20 +1,33 @@
-error: expected one of `)`, `,`, or `::`, found `(`
+error: traits in `#[derive(...)]` don't accept arguments
--> $DIR/malformed-derive-entry.rs:1:14
|
LL | #[derive(Copy(Bad))]
- | ^ expected one of `)`, `,`, or `::`
+ | ^^^^^ help: remove the arguments
-error: expected one of `)`, `,`, or `::`, found `=`
- --> $DIR/malformed-derive-entry.rs:4:14
+error: traits in `#[derive(...)]` don't accept values
+ --> $DIR/malformed-derive-entry.rs:6:14
|
LL | #[derive(Copy="bad")]
- | ^ expected one of `)`, `,`, or `::`
+ | ^^^^^^ help: remove the value
error: malformed `derive` attribute input
- --> $DIR/malformed-derive-entry.rs:7:1
+ --> $DIR/malformed-derive-entry.rs:11:1
|
LL | #[derive]
| ^^^^^^^^^ help: missing traits to be derived: `#[derive(Trait1, Trait2, ...)]`
-error: aborting due to 3 previous errors
+error[E0277]: the trait bound `Test1: std::clone::Clone` is not satisfied
+ --> $DIR/malformed-derive-entry.rs:1:10
+ |
+LL | #[derive(Copy(Bad))]
+ | ^^^^ the trait `std::clone::Clone` is not implemented for `Test1`
+error[E0277]: the trait bound `Test2: std::clone::Clone` is not satisfied
+ --> $DIR/malformed-derive-entry.rs:6:10
+ |
+LL | #[derive(Copy="bad")]
+ | ^^^^ the trait `std::clone::Clone` is not implemented for `Test2`
+
+error: aborting due to 5 previous errors
+
+For more information about this error, try `rustc --explain E0277`.
diff --git a/src/test/ui/malformed/malformed-meta-delim.rs b/src/test/ui/malformed/malformed-meta-delim.rs
new file mode 100644
index 0000000..5b1614b
--- /dev/null
+++ b/src/test/ui/malformed/malformed-meta-delim.rs
@@ -0,0 +1,11 @@
+fn main() {}
+
+#[allow { foo_lint } ]
+//~^ ERROR wrong meta list delimiters
+//~| HELP the delimiters should be `(` and `)`
+fn delim_brace() {}
+
+#[allow [ foo_lint ] ]
+//~^ ERROR wrong meta list delimiters
+//~| HELP the delimiters should be `(` and `)`
+fn delim_bracket() {}
diff --git a/src/test/ui/malformed/malformed-meta-delim.stderr b/src/test/ui/malformed/malformed-meta-delim.stderr
new file mode 100644
index 0000000..407193d
--- /dev/null
+++ b/src/test/ui/malformed/malformed-meta-delim.stderr
@@ -0,0 +1,24 @@
+error: wrong meta list delimiters
+ --> $DIR/malformed-meta-delim.rs:3:9
+ |
+LL | #[allow { foo_lint } ]
+ | ^^^^^^^^^^^^
+ |
+help: the delimiters should be `(` and `)`
+ |
+LL | #[allow ( foo_lint ) ]
+ | ^ ^
+
+error: wrong meta list delimiters
+ --> $DIR/malformed-meta-delim.rs:8:9
+ |
+LL | #[allow [ foo_lint ] ]
+ | ^^^^^^^^^^^^
+ |
+help: the delimiters should be `(` and `)`
+ |
+LL | #[allow ( foo_lint ) ]
+ | ^ ^
+
+error: aborting due to 2 previous errors
+
diff --git a/src/test/ui/malformed/malformed-special-attrs.rs b/src/test/ui/malformed/malformed-special-attrs.rs
index e67fbdd..05b7ebe 100644
--- a/src/test/ui/malformed/malformed-special-attrs.rs
+++ b/src/test/ui/malformed/malformed-special-attrs.rs
@@ -1,7 +1,7 @@
#[cfg_attr] //~ ERROR malformed `cfg_attr` attribute
struct S1;
-#[cfg_attr = ""] //~ ERROR expected `(`, found `=`
+#[cfg_attr = ""] //~ ERROR malformed `cfg_attr` attribute
struct S2;
#[derive] //~ ERROR malformed `derive` attribute
diff --git a/src/test/ui/malformed/malformed-special-attrs.stderr b/src/test/ui/malformed/malformed-special-attrs.stderr
index 319c05e..6f535e0 100644
--- a/src/test/ui/malformed/malformed-special-attrs.stderr
+++ b/src/test/ui/malformed/malformed-special-attrs.stderr
@@ -6,11 +6,13 @@
|
= note: for more information, visit <https://doc.rust-lang.org/reference/conditional-compilation.html#the-cfg_attr-attribute>
-error: expected `(`, found `=`
- --> $DIR/malformed-special-attrs.rs:4:12
+error: malformed `cfg_attr` attribute input
+ --> $DIR/malformed-special-attrs.rs:4:1
|
LL | #[cfg_attr = ""]
- | ^ expected `(`
+ | ^^^^^^^^^^^^^^^^ help: missing condition and attribute: `#[cfg_attr(condition, attribute, other_attribute, ...)]`
+ |
+ = note: for more information, visit <https://doc.rust-lang.org/reference/conditional-compilation.html#the-cfg_attr-attribute>
error: malformed `derive` attribute input
--> $DIR/malformed-special-attrs.rs:7:1
diff --git a/src/test/ui/methods/method-ambig-one-trait-unknown-int-type.stderr b/src/test/ui/methods/method-ambig-one-trait-unknown-int-type.stderr
index fcd9764..f3f3c47 100644
--- a/src/test/ui/methods/method-ambig-one-trait-unknown-int-type.stderr
+++ b/src/test/ui/methods/method-ambig-one-trait-unknown-int-type.stderr
@@ -2,7 +2,7 @@
--> $DIR/method-ambig-one-trait-unknown-int-type.rs:24:17
|
LL | let mut x = Vec::new();
- | ----- ^^^^^^^^ cannot infer type for `T`
+ | ----- ^^^^^^^^ cannot infer type for type parameter `T`
| |
| consider giving `x` the explicit type `std::vec::Vec<T>`, where the type parameter `T` is specified
diff --git a/src/test/ui/mir/issue66339.rs b/src/test/ui/mir/issue66339.rs
new file mode 100644
index 0000000..98e178c
--- /dev/null
+++ b/src/test/ui/mir/issue66339.rs
@@ -0,0 +1,13 @@
+// compile-flags: -Z mir-opt-level=2
+// build-pass
+
+// This used to ICE in const-prop
+
+fn foo() {
+ let bar = |_| { };
+ let _ = bar("a");
+}
+
+fn main() {
+ foo();
+}
diff --git a/src/test/ui/mismatched_types/E0631.stderr b/src/test/ui/mismatched_types/E0631.stderr
index 88c1efd..06f5c05 100644
--- a/src/test/ui/mismatched_types/E0631.stderr
+++ b/src/test/ui/mismatched_types/E0631.stderr
@@ -46,3 +46,4 @@
error: aborting due to 4 previous errors
+For more information about this error, try `rustc --explain E0631`.
diff --git a/src/test/ui/mismatched_types/abridged.stderr b/src/test/ui/mismatched_types/abridged.stderr
index c208187..c731306 100644
--- a/src/test/ui/mismatched_types/abridged.stderr
+++ b/src/test/ui/mismatched_types/abridged.stderr
@@ -26,7 +26,10 @@
LL | fn b() -> Option<Foo> {
| ----------- expected `std::option::Option<Foo>` because of return type
LL | Foo { bar: 1 }
- | ^^^^^^^^^^^^^^ expected enum `std::option::Option`, found struct `Foo`
+ | ^^^^^^^^^^^^^^
+ | |
+ | expected enum `std::option::Option`, found struct `Foo`
+ | help: try using a variant of the expected enum: `Some(Foo { bar: 1 })`
|
= note: expected enum `std::option::Option<Foo>`
found struct `Foo`
@@ -37,7 +40,10 @@
LL | fn c() -> Result<Foo, Bar> {
| ---------------- expected `std::result::Result<Foo, Bar>` because of return type
LL | Foo { bar: 1 }
- | ^^^^^^^^^^^^^^ expected enum `std::result::Result`, found struct `Foo`
+ | ^^^^^^^^^^^^^^
+ | |
+ | expected enum `std::result::Result`, found struct `Foo`
+ | help: try using a variant of the expected enum: `Ok(Foo { bar: 1 })`
|
= note: expected enum `std::result::Result<Foo, Bar>`
found struct `Foo`
diff --git a/src/test/ui/mismatched_types/closure-arg-type-mismatch.stderr b/src/test/ui/mismatched_types/closure-arg-type-mismatch.stderr
index 85cad61..ed50282 100644
--- a/src/test/ui/mismatched_types/closure-arg-type-mismatch.stderr
+++ b/src/test/ui/mismatched_types/closure-arg-type-mismatch.stderr
@@ -45,4 +45,5 @@
error: aborting due to 5 previous errors
-For more information about this error, try `rustc --explain E0271`.
+Some errors have detailed explanations: E0271, E0631.
+For more information about an error, try `rustc --explain E0271`.
diff --git a/src/test/ui/mismatched_types/closure-mismatch.stderr b/src/test/ui/mismatched_types/closure-mismatch.stderr
index fd2b9f3..f3874c0 100644
--- a/src/test/ui/mismatched_types/closure-mismatch.stderr
+++ b/src/test/ui/mismatched_types/closure-mismatch.stderr
@@ -24,4 +24,5 @@
error: aborting due to 2 previous errors
-For more information about this error, try `rustc --explain E0271`.
+Some errors have detailed explanations: E0271, E0631.
+For more information about an error, try `rustc --explain E0271`.
diff --git a/src/test/ui/mismatched_types/fn-variance-1.stderr b/src/test/ui/mismatched_types/fn-variance-1.stderr
index 1a82dd5..88c9266 100644
--- a/src/test/ui/mismatched_types/fn-variance-1.stderr
+++ b/src/test/ui/mismatched_types/fn-variance-1.stderr
@@ -24,3 +24,4 @@
error: aborting due to 2 previous errors
+For more information about this error, try `rustc --explain E0631`.
diff --git a/src/test/ui/mismatched_types/issue-36053-2.stderr b/src/test/ui/mismatched_types/issue-36053-2.stderr
index 72f3220..da018aa 100644
--- a/src/test/ui/mismatched_types/issue-36053-2.stderr
+++ b/src/test/ui/mismatched_types/issue-36053-2.stderr
@@ -18,4 +18,5 @@
error: aborting due to 2 previous errors
-For more information about this error, try `rustc --explain E0599`.
+Some errors have detailed explanations: E0599, E0631.
+For more information about an error, try `rustc --explain E0599`.
diff --git a/src/test/ui/mismatched_types/unboxed-closures-vtable-mismatch.stderr b/src/test/ui/mismatched_types/unboxed-closures-vtable-mismatch.stderr
index 2daf478..3c999f2 100644
--- a/src/test/ui/mismatched_types/unboxed-closures-vtable-mismatch.stderr
+++ b/src/test/ui/mismatched_types/unboxed-closures-vtable-mismatch.stderr
@@ -12,3 +12,4 @@
error: aborting due to previous error
+For more information about this error, try `rustc --explain E0631`.
diff --git a/src/test/ui/missing/missing-items/missing-type-parameter.stderr b/src/test/ui/missing/missing-items/missing-type-parameter.stderr
index dbb467d..be97f23 100644
--- a/src/test/ui/missing/missing-items/missing-type-parameter.stderr
+++ b/src/test/ui/missing/missing-items/missing-type-parameter.stderr
@@ -2,7 +2,7 @@
--> $DIR/missing-type-parameter.rs:4:5
|
LL | foo();
- | ^^^ cannot infer type for `X`
+ | ^^^ cannot infer type for type parameter `X`
error: aborting due to previous error
diff --git a/src/test/ui/nll/closure-requirements/escape-argument-callee.stderr b/src/test/ui/nll/closure-requirements/escape-argument-callee.stderr
index abeffee..3d79ff0 100644
--- a/src/test/ui/nll/closure-requirements/escape-argument-callee.stderr
+++ b/src/test/ui/nll/closure-requirements/escape-argument-callee.stderr
@@ -4,7 +4,7 @@
LL | let mut closure = expect_sig(|p, y| *p = y);
| ^^^^^^^^^^^^^
|
- = note: defining type: DefId(0:4 ~ escape_argument_callee[317d]::test[0]::{{closure}}[0]) with closure substs [
+ = note: defining type: test::{{closure}}#0 with closure substs [
i16,
for<'r, 's, 't0> extern "rust-call" fn((&ReLateBound(DebruijnIndex(0), BrNamed('r)) mut &ReLateBound(DebruijnIndex(0), BrNamed('s)) i32, &ReLateBound(DebruijnIndex(0), BrNamed('t0)) i32)),
]
@@ -30,7 +30,7 @@
LL | | }
| |_^
|
- = note: defining type: DefId(0:3 ~ escape_argument_callee[317d]::test[0]) with substs []
+ = note: defining type: test
error: aborting due to previous error
diff --git a/src/test/ui/nll/closure-requirements/escape-argument.stderr b/src/test/ui/nll/closure-requirements/escape-argument.stderr
index f750d15..37f04af 100644
--- a/src/test/ui/nll/closure-requirements/escape-argument.stderr
+++ b/src/test/ui/nll/closure-requirements/escape-argument.stderr
@@ -4,7 +4,7 @@
LL | let mut closure = expect_sig(|p, y| *p = y);
| ^^^^^^^^^^^^^
|
- = note: defining type: DefId(0:4 ~ escape_argument[317d]::test[0]::{{closure}}[0]) with closure substs [
+ = note: defining type: test::{{closure}}#0 with closure substs [
i16,
for<'r, 's> extern "rust-call" fn((&ReLateBound(DebruijnIndex(0), BrNamed('r)) mut &ReLateBound(DebruijnIndex(0), BrNamed('s)) i32, &ReLateBound(DebruijnIndex(0), BrNamed('s)) i32)),
]
@@ -21,7 +21,7 @@
LL | | }
| |_^
|
- = note: defining type: DefId(0:3 ~ escape_argument[317d]::test[0]) with substs []
+ = note: defining type: test
error[E0597]: `y` does not live long enough
--> $DIR/escape-argument.rs:27:25
diff --git a/src/test/ui/nll/closure-requirements/escape-upvar-nested.stderr b/src/test/ui/nll/closure-requirements/escape-upvar-nested.stderr
index 7c4d48c..810c028 100644
--- a/src/test/ui/nll/closure-requirements/escape-upvar-nested.stderr
+++ b/src/test/ui/nll/closure-requirements/escape-upvar-nested.stderr
@@ -4,7 +4,7 @@
LL | let mut closure1 = || p = &y;
| ^^^^^^^^^
|
- = note: defining type: DefId(0:5 ~ escape_upvar_nested[317d]::test[0]::{{closure}}[0]::{{closure}}[0]) with closure substs [
+ = note: defining type: test::{{closure}}#0::{{closure}}#0 with closure substs [
i16,
extern "rust-call" fn(()),
&'_#1r i32,
@@ -23,7 +23,7 @@
LL | | };
| |_________^
|
- = note: defining type: DefId(0:4 ~ escape_upvar_nested[317d]::test[0]::{{closure}}[0]) with closure substs [
+ = note: defining type: test::{{closure}}#0 with closure substs [
i16,
extern "rust-call" fn(()),
&'_#1r i32,
@@ -44,7 +44,7 @@
LL | | }
| |_^
|
- = note: defining type: DefId(0:3 ~ escape_upvar_nested[317d]::test[0]) with substs []
+ = note: defining type: test
error[E0597]: `y` does not live long enough
--> $DIR/escape-upvar-nested.rs:21:40
diff --git a/src/test/ui/nll/closure-requirements/escape-upvar-ref.stderr b/src/test/ui/nll/closure-requirements/escape-upvar-ref.stderr
index 4446486..bf04276 100644
--- a/src/test/ui/nll/closure-requirements/escape-upvar-ref.stderr
+++ b/src/test/ui/nll/closure-requirements/escape-upvar-ref.stderr
@@ -4,7 +4,7 @@
LL | let mut closure = || p = &y;
| ^^^^^^^^^
|
- = note: defining type: DefId(0:4 ~ escape_upvar_ref[317d]::test[0]::{{closure}}[0]) with closure substs [
+ = note: defining type: test::{{closure}}#0 with closure substs [
i16,
extern "rust-call" fn(()),
&'_#1r i32,
@@ -25,7 +25,7 @@
LL | | }
| |_^
|
- = note: defining type: DefId(0:3 ~ escape_upvar_ref[317d]::test[0]) with substs []
+ = note: defining type: test
error[E0597]: `y` does not live long enough
--> $DIR/escape-upvar-ref.rs:23:35
diff --git a/src/test/ui/nll/closure-requirements/propagate-approximated-fail-no-postdom.stderr b/src/test/ui/nll/closure-requirements/propagate-approximated-fail-no-postdom.stderr
index 92f30d4..4e3aa35 100644
--- a/src/test/ui/nll/closure-requirements/propagate-approximated-fail-no-postdom.stderr
+++ b/src/test/ui/nll/closure-requirements/propagate-approximated-fail-no-postdom.stderr
@@ -8,7 +8,7 @@
LL | | },
| |_________^
|
- = note: defining type: DefId(0:18 ~ propagate_approximated_fail_no_postdom[317d]::supply[0]::{{closure}}[0]) with closure substs [
+ = note: defining type: supply::{{closure}}#0 with closure substs [
i16,
for<'r, 's> extern "rust-call" fn((std::cell::Cell<&'_#1r &ReLateBound(DebruijnIndex(0), BrNamed('r)) u32>, std::cell::Cell<&'_#2r &ReLateBound(DebruijnIndex(0), BrNamed('r)) u32>, std::cell::Cell<&ReLateBound(DebruijnIndex(0), BrNamed('s)) &'_#3r u32>, std::cell::Cell<&ReLateBound(DebruijnIndex(0), BrNamed('r)) u32>, std::cell::Cell<&ReLateBound(DebruijnIndex(0), BrNamed('s)) u32>)),
]
@@ -39,7 +39,7 @@
LL | | }
| |_^
|
- = note: defining type: DefId(0:14 ~ propagate_approximated_fail_no_postdom[317d]::supply[0]) with substs []
+ = note: defining type: supply
error: aborting due to previous error
diff --git a/src/test/ui/nll/closure-requirements/propagate-approximated-ref.stderr b/src/test/ui/nll/closure-requirements/propagate-approximated-ref.stderr
index 00bb66a..cd61b8b 100644
--- a/src/test/ui/nll/closure-requirements/propagate-approximated-ref.stderr
+++ b/src/test/ui/nll/closure-requirements/propagate-approximated-ref.stderr
@@ -9,7 +9,7 @@
LL | | });
| |_____^
|
- = note: defining type: DefId(0:16 ~ propagate_approximated_ref[317d]::supply[0]::{{closure}}[0]) with closure substs [
+ = note: defining type: supply::{{closure}}#0 with closure substs [
i16,
for<'r, 's, 't0, 't1, 't2, 't3> extern "rust-call" fn((&ReLateBound(DebruijnIndex(0), BrNamed('r)) std::cell::Cell<&'_#1r &ReLateBound(DebruijnIndex(0), BrNamed('s)) u32>, &ReLateBound(DebruijnIndex(0), BrNamed('t0)) std::cell::Cell<&ReLateBound(DebruijnIndex(0), BrNamed('t1)) &'_#2r u32>, &ReLateBound(DebruijnIndex(0), BrNamed('t2)) std::cell::Cell<&ReLateBound(DebruijnIndex(0), BrNamed('s)) u32>, &ReLateBound(DebruijnIndex(0), BrNamed('t3)) std::cell::Cell<&ReLateBound(DebruijnIndex(0), BrNamed('t1)) u32>)),
]
@@ -30,7 +30,7 @@
LL | | }
| |_^
|
- = note: defining type: DefId(0:13 ~ propagate_approximated_ref[317d]::supply[0]) with substs []
+ = note: defining type: supply
error: lifetime may not live long enough
--> $DIR/propagate-approximated-ref.rs:45:9
diff --git a/src/test/ui/nll/closure-requirements/propagate-approximated-shorter-to-static-comparing-against-free.stderr b/src/test/ui/nll/closure-requirements/propagate-approximated-shorter-to-static-comparing-against-free.stderr
index 2b05503..259140c 100644
--- a/src/test/ui/nll/closure-requirements/propagate-approximated-shorter-to-static-comparing-against-free.stderr
+++ b/src/test/ui/nll/closure-requirements/propagate-approximated-shorter-to-static-comparing-against-free.stderr
@@ -8,7 +8,7 @@
LL | | })
| |_____^
|
- = note: defining type: DefId(0:9 ~ propagate_approximated_shorter_to_static_comparing_against_free[317d]::case1[0]::{{closure}}[0]) with closure substs [
+ = note: defining type: case1::{{closure}}#0 with closure substs [
i32,
for<'r> extern "rust-call" fn((std::cell::Cell<&'_#1r u32>, std::cell::Cell<&ReLateBound(DebruijnIndex(0), BrNamed('r)) u32>)),
]
@@ -35,7 +35,7 @@
LL | | }
| |_^
|
- = note: defining type: DefId(0:8 ~ propagate_approximated_shorter_to_static_comparing_against_free[317d]::case1[0]) with substs []
+ = note: defining type: case1
note: External requirements
--> $DIR/propagate-approximated-shorter-to-static-comparing-against-free.rs:35:15
@@ -46,7 +46,7 @@
LL | | })
| |_____^
|
- = note: defining type: DefId(0:11 ~ propagate_approximated_shorter_to_static_comparing_against_free[317d]::case2[0]::{{closure}}[0]) with closure substs [
+ = note: defining type: case2::{{closure}}#0 with closure substs [
i32,
for<'r> extern "rust-call" fn((std::cell::Cell<&'_#1r u32>, std::cell::Cell<&ReLateBound(DebruijnIndex(0), BrNamed('r)) u32>)),
]
@@ -65,7 +65,7 @@
LL | | }
| |_^
|
- = note: defining type: DefId(0:10 ~ propagate_approximated_shorter_to_static_comparing_against_free[317d]::case2[0]) with substs []
+ = note: defining type: case2
error[E0597]: `a` does not live long enough
--> $DIR/propagate-approximated-shorter-to-static-comparing-against-free.rs:30:26
diff --git a/src/test/ui/nll/closure-requirements/propagate-approximated-shorter-to-static-no-bound.stderr b/src/test/ui/nll/closure-requirements/propagate-approximated-shorter-to-static-no-bound.stderr
index ee0f0b7..b3dd682 100644
--- a/src/test/ui/nll/closure-requirements/propagate-approximated-shorter-to-static-no-bound.stderr
+++ b/src/test/ui/nll/closure-requirements/propagate-approximated-shorter-to-static-no-bound.stderr
@@ -10,7 +10,7 @@
LL | | });
| |_____^
|
- = note: defining type: DefId(0:16 ~ propagate_approximated_shorter_to_static_no_bound[317d]::supply[0]::{{closure}}[0]) with closure substs [
+ = note: defining type: supply::{{closure}}#0 with closure substs [
i16,
for<'r, 's, 't0, 't1, 't2> extern "rust-call" fn((&ReLateBound(DebruijnIndex(0), BrNamed('r)) std::cell::Cell<&'_#1r &ReLateBound(DebruijnIndex(0), BrNamed('s)) u32>, &ReLateBound(DebruijnIndex(0), BrNamed('t0)) std::cell::Cell<&ReLateBound(DebruijnIndex(0), BrNamed('s)) u32>, &ReLateBound(DebruijnIndex(0), BrNamed('t1)) std::cell::Cell<&ReLateBound(DebruijnIndex(0), BrNamed('t2)) u32>)),
]
@@ -31,7 +31,7 @@
LL | | }
| |_^
|
- = note: defining type: DefId(0:13 ~ propagate_approximated_shorter_to_static_no_bound[317d]::supply[0]) with substs []
+ = note: defining type: supply
error[E0521]: borrowed data escapes outside of function
--> $DIR/propagate-approximated-shorter-to-static-no-bound.rs:32:5
diff --git a/src/test/ui/nll/closure-requirements/propagate-approximated-shorter-to-static-wrong-bound.stderr b/src/test/ui/nll/closure-requirements/propagate-approximated-shorter-to-static-wrong-bound.stderr
index 611a129..ab12d08 100644
--- a/src/test/ui/nll/closure-requirements/propagate-approximated-shorter-to-static-wrong-bound.stderr
+++ b/src/test/ui/nll/closure-requirements/propagate-approximated-shorter-to-static-wrong-bound.stderr
@@ -10,7 +10,7 @@
LL | | });
| |_____^
|
- = note: defining type: DefId(0:16 ~ propagate_approximated_shorter_to_static_wrong_bound[317d]::supply[0]::{{closure}}[0]) with closure substs [
+ = note: defining type: supply::{{closure}}#0 with closure substs [
i16,
for<'r, 's, 't0, 't1, 't2, 't3> extern "rust-call" fn((&ReLateBound(DebruijnIndex(0), BrNamed('r)) std::cell::Cell<&'_#1r &ReLateBound(DebruijnIndex(0), BrNamed('s)) u32>, &ReLateBound(DebruijnIndex(0), BrNamed('t0)) std::cell::Cell<&'_#2r &ReLateBound(DebruijnIndex(0), BrNamed('t1)) u32>, &ReLateBound(DebruijnIndex(0), BrNamed('t2)) std::cell::Cell<&ReLateBound(DebruijnIndex(0), BrNamed('s)) u32>, &ReLateBound(DebruijnIndex(0), BrNamed('t3)) std::cell::Cell<&ReLateBound(DebruijnIndex(0), BrNamed('t1)) u32>)),
]
@@ -31,7 +31,7 @@
LL | | }
| |_^
|
- = note: defining type: DefId(0:13 ~ propagate_approximated_shorter_to_static_wrong_bound[317d]::supply[0]) with substs []
+ = note: defining type: supply
error[E0521]: borrowed data escapes outside of function
--> $DIR/propagate-approximated-shorter-to-static-wrong-bound.rs:35:5
diff --git a/src/test/ui/nll/closure-requirements/propagate-approximated-val.stderr b/src/test/ui/nll/closure-requirements/propagate-approximated-val.stderr
index 9328d05..b2209e9 100644
--- a/src/test/ui/nll/closure-requirements/propagate-approximated-val.stderr
+++ b/src/test/ui/nll/closure-requirements/propagate-approximated-val.stderr
@@ -9,7 +9,7 @@
LL | | });
| |_____^
|
- = note: defining type: DefId(0:16 ~ propagate_approximated_val[317d]::test[0]::{{closure}}[0]) with closure substs [
+ = note: defining type: test::{{closure}}#0 with closure substs [
i16,
for<'r, 's> extern "rust-call" fn((std::cell::Cell<&'_#1r &ReLateBound(DebruijnIndex(0), BrNamed('r)) u32>, std::cell::Cell<&ReLateBound(DebruijnIndex(0), BrNamed('s)) &'_#2r u32>, std::cell::Cell<&ReLateBound(DebruijnIndex(0), BrNamed('r)) u32>, std::cell::Cell<&ReLateBound(DebruijnIndex(0), BrNamed('s)) u32>)),
]
@@ -30,7 +30,7 @@
LL | | }
| |_^
|
- = note: defining type: DefId(0:13 ~ propagate_approximated_val[317d]::test[0]) with substs []
+ = note: defining type: test
error: lifetime may not live long enough
--> $DIR/propagate-approximated-val.rs:38:9
diff --git a/src/test/ui/nll/closure-requirements/propagate-despite-same-free-region.stderr b/src/test/ui/nll/closure-requirements/propagate-despite-same-free-region.stderr
index afac526..55ee515 100644
--- a/src/test/ui/nll/closure-requirements/propagate-despite-same-free-region.stderr
+++ b/src/test/ui/nll/closure-requirements/propagate-despite-same-free-region.stderr
@@ -8,7 +8,7 @@
LL | | },
| |_________^
|
- = note: defining type: DefId(0:14 ~ propagate_despite_same_free_region[317d]::supply[0]::{{closure}}[0]) with closure substs [
+ = note: defining type: supply::{{closure}}#0 with closure substs [
i16,
for<'r, 's> extern "rust-call" fn((std::cell::Cell<&'_#1r &ReLateBound(DebruijnIndex(0), BrNamed('r)) u32>, std::cell::Cell<&ReLateBound(DebruijnIndex(0), BrNamed('s)) &'_#2r u32>, std::cell::Cell<&ReLateBound(DebruijnIndex(0), BrNamed('r)) u32>, std::cell::Cell<&ReLateBound(DebruijnIndex(0), BrNamed('s)) u32>)),
]
@@ -28,5 +28,5 @@
LL | | }
| |_^
|
- = note: defining type: DefId(0:12 ~ propagate_despite_same_free_region[317d]::supply[0]) with substs []
+ = note: defining type: supply
diff --git a/src/test/ui/nll/closure-requirements/propagate-fail-to-approximate-longer-no-bounds.stderr b/src/test/ui/nll/closure-requirements/propagate-fail-to-approximate-longer-no-bounds.stderr
index 9699e8f..1c29af8 100644
--- a/src/test/ui/nll/closure-requirements/propagate-fail-to-approximate-longer-no-bounds.stderr
+++ b/src/test/ui/nll/closure-requirements/propagate-fail-to-approximate-longer-no-bounds.stderr
@@ -9,7 +9,7 @@
LL | | });
| |_____^
|
- = note: defining type: DefId(0:16 ~ propagate_fail_to_approximate_longer_no_bounds[317d]::supply[0]::{{closure}}[0]) with closure substs [
+ = note: defining type: supply::{{closure}}#0 with closure substs [
i16,
for<'r, 's, 't0, 't1, 't2> extern "rust-call" fn((&ReLateBound(DebruijnIndex(0), BrNamed('r)) std::cell::Cell<&ReLateBound(DebruijnIndex(0), BrNamed('s)) &'_#1r u32>, &ReLateBound(DebruijnIndex(0), BrNamed('t0)) std::cell::Cell<&ReLateBound(DebruijnIndex(0), BrNamed('t1)) u32>, &ReLateBound(DebruijnIndex(0), BrNamed('t2)) std::cell::Cell<&ReLateBound(DebruijnIndex(0), BrNamed('s)) u32>)),
]
@@ -39,7 +39,7 @@
LL | | }
| |_^
|
- = note: defining type: DefId(0:13 ~ propagate_fail_to_approximate_longer_no_bounds[317d]::supply[0]) with substs []
+ = note: defining type: supply
error: aborting due to previous error
diff --git a/src/test/ui/nll/closure-requirements/propagate-fail-to-approximate-longer-wrong-bounds.stderr b/src/test/ui/nll/closure-requirements/propagate-fail-to-approximate-longer-wrong-bounds.stderr
index 2a18079..afa0e9f 100644
--- a/src/test/ui/nll/closure-requirements/propagate-fail-to-approximate-longer-wrong-bounds.stderr
+++ b/src/test/ui/nll/closure-requirements/propagate-fail-to-approximate-longer-wrong-bounds.stderr
@@ -9,7 +9,7 @@
LL | | });
| |_____^
|
- = note: defining type: DefId(0:16 ~ propagate_fail_to_approximate_longer_wrong_bounds[317d]::supply[0]::{{closure}}[0]) with closure substs [
+ = note: defining type: supply::{{closure}}#0 with closure substs [
i16,
for<'r, 's, 't0, 't1, 't2, 't3> extern "rust-call" fn((&ReLateBound(DebruijnIndex(0), BrNamed('r)) std::cell::Cell<&ReLateBound(DebruijnIndex(0), BrNamed('s)) &'_#1r u32>, &ReLateBound(DebruijnIndex(0), BrNamed('t0)) std::cell::Cell<&ReLateBound(DebruijnIndex(0), BrNamed('t1)) &'_#2r u32>, &ReLateBound(DebruijnIndex(0), BrNamed('t2)) std::cell::Cell<&ReLateBound(DebruijnIndex(0), BrNamed('s)) u32>, &ReLateBound(DebruijnIndex(0), BrNamed('t3)) std::cell::Cell<&ReLateBound(DebruijnIndex(0), BrNamed('t1)) u32>)),
]
@@ -39,7 +39,7 @@
LL | | }
| |_^
|
- = note: defining type: DefId(0:13 ~ propagate_fail_to_approximate_longer_wrong_bounds[317d]::supply[0]) with substs []
+ = note: defining type: supply
error: aborting due to previous error
diff --git a/src/test/ui/nll/closure-requirements/propagate-from-trait-match.stderr b/src/test/ui/nll/closure-requirements/propagate-from-trait-match.stderr
index 0d62265..0dbb530 100644
--- a/src/test/ui/nll/closure-requirements/propagate-from-trait-match.stderr
+++ b/src/test/ui/nll/closure-requirements/propagate-from-trait-match.stderr
@@ -11,9 +11,7 @@
LL | | });
| |_____^
|
- = note: defining type: DefId(0:14 ~ propagate_from_trait_match[317d]::supply[0]::{{closure}}[0]) with closure substs [
- '_#1r,
- T,
+ = note: defining type: supply::<'_#1r, T>::{{closure}}#0 with closure substs [
i32,
extern "rust-call" fn((T,)),
]
@@ -32,10 +30,7 @@
LL | | }
| |_^
|
- = note: defining type: DefId(0:11 ~ propagate_from_trait_match[317d]::supply[0]) with substs [
- '_#1r,
- T,
- ]
+ = note: defining type: supply::<'_#1r, T>
error[E0309]: the parameter type `T` may not live long enough
--> $DIR/propagate-from-trait-match.rs:32:36
diff --git a/src/test/ui/nll/closure-requirements/return-wrong-bound-region.stderr b/src/test/ui/nll/closure-requirements/return-wrong-bound-region.stderr
index 8ce0b77..ca794d9 100644
--- a/src/test/ui/nll/closure-requirements/return-wrong-bound-region.stderr
+++ b/src/test/ui/nll/closure-requirements/return-wrong-bound-region.stderr
@@ -4,7 +4,7 @@
LL | expect_sig(|a, b| b); // ought to return `a`
| ^^^^^^^^
|
- = note: defining type: DefId(0:4 ~ return_wrong_bound_region[317d]::test[0]::{{closure}}[0]) with closure substs [
+ = note: defining type: test::{{closure}}#0 with closure substs [
i16,
for<'r, 's> extern "rust-call" fn((&ReLateBound(DebruijnIndex(0), BrNamed('r)) i32, &ReLateBound(DebruijnIndex(0), BrNamed('s)) i32)) -> &ReLateBound(DebruijnIndex(0), BrNamed('r)) i32,
]
@@ -27,7 +27,7 @@
LL | | }
| |_^
|
- = note: defining type: DefId(0:3 ~ return_wrong_bound_region[317d]::test[0]) with substs []
+ = note: defining type: test
error: aborting due to previous error
diff --git a/src/test/ui/nll/issue-55394.stderr b/src/test/ui/nll/issue-55394.stderr
index 714a63b..69a6ab0 100644
--- a/src/test/ui/nll/issue-55394.stderr
+++ b/src/test/ui/nll/issue-55394.stderr
@@ -21,9 +21,13 @@
|
LL | impl Foo<'_> {
| ^^
- = note: ...so that the expression is assignable:
- expected Foo<'_>
- found Foo<'_>
+note: ...so that the expression is assignable
+ --> $DIR/issue-55394.rs:9:9
+ |
+LL | Foo { bar }
+ | ^^^^^^^^^^^
+ = note: expected `Foo<'_>`
+ found `Foo<'_>`
error: aborting due to previous error
diff --git a/src/test/ui/nll/normalization-bounds-error.stderr b/src/test/ui/nll/normalization-bounds-error.stderr
index 3a152fb..58f2067 100644
--- a/src/test/ui/nll/normalization-bounds-error.stderr
+++ b/src/test/ui/nll/normalization-bounds-error.stderr
@@ -14,9 +14,13 @@
|
LL | fn visit_seq<'d, 'a: 'd>() -> <&'a () as Visitor<'d>>::Value {}
| ^^
- = note: ...so that the types are compatible:
- expected Visitor<'d>
- found Visitor<'_>
+note: ...so that the types are compatible
+ --> $DIR/normalization-bounds-error.rs:12:1
+ |
+LL | fn visit_seq<'d, 'a: 'd>() -> <&'a () as Visitor<'d>>::Value {}
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+ = note: expected `Visitor<'d>`
+ found `Visitor<'_>`
error: aborting due to previous error
diff --git a/src/test/ui/nll/outlives-suggestion-simple.polonius.stderr b/src/test/ui/nll/outlives-suggestion-simple.polonius.stderr
new file mode 100644
index 0000000..8157446
--- /dev/null
+++ b/src/test/ui/nll/outlives-suggestion-simple.polonius.stderr
@@ -0,0 +1,121 @@
+error: lifetime may not live long enough
+ --> $DIR/outlives-suggestion-simple.rs:6:5
+ |
+LL | fn foo1<'a, 'b>(x: &'a usize) -> &'b usize {
+ | -- -- lifetime `'b` defined here
+ | |
+ | lifetime `'a` defined here
+LL | x
+ | ^ returning this value requires that `'a` must outlive `'b`
+ |
+ = help: consider adding the following bound: `'a: 'b`
+
+error: lifetime may not live long enough
+ --> $DIR/outlives-suggestion-simple.rs:10:5
+ |
+LL | fn foo2<'a>(x: &'a usize) -> &'static usize {
+ | -- lifetime `'a` defined here
+LL | x
+ | ^ returning this value requires that `'a` must outlive `'static`
+ |
+ = help: consider replacing `'a` with `'static`
+
+error: lifetime may not live long enough
+ --> $DIR/outlives-suggestion-simple.rs:14:5
+ |
+LL | fn foo3<'a, 'b>(x: &'a usize, y: &'b usize) -> (&'b usize, &'a usize) {
+ | -- -- lifetime `'b` defined here
+ | |
+ | lifetime `'a` defined here
+LL | (x, y)
+ | ^^^^^^ function was supposed to return data with lifetime `'b` but it is returning data with lifetime `'a`
+ |
+ = help: consider adding the following bound: `'a: 'b`
+
+error: lifetime may not live long enough
+ --> $DIR/outlives-suggestion-simple.rs:14:5
+ |
+LL | fn foo3<'a, 'b>(x: &'a usize, y: &'b usize) -> (&'b usize, &'a usize) {
+ | -- -- lifetime `'b` defined here
+ | |
+ | lifetime `'a` defined here
+LL | (x, y)
+ | ^^^^^^ function was supposed to return data with lifetime `'a` but it is returning data with lifetime `'b`
+ |
+ = help: consider adding the following bound: `'b: 'a`
+
+help: `'a` and `'b` must be the same: replace one with the other
+
+error: lifetime may not live long enough
+ --> $DIR/outlives-suggestion-simple.rs:22:5
+ |
+LL | fn foo4<'a, 'b, 'c>(x: &'a usize) -> (&'b usize, &'c usize) {
+ | -- -- lifetime `'b` defined here
+ | |
+ | lifetime `'a` defined here
+...
+LL | (x, x)
+ | ^^^^^^ returning this value requires that `'a` must outlive `'b`
+ |
+ = help: consider adding the following bound: `'a: 'b`
+
+error: lifetime may not live long enough
+ --> $DIR/outlives-suggestion-simple.rs:22:5
+ |
+LL | fn foo4<'a, 'b, 'c>(x: &'a usize) -> (&'b usize, &'c usize) {
+ | -- -- lifetime `'c` defined here
+ | |
+ | lifetime `'a` defined here
+...
+LL | (x, x)
+ | ^^^^^^ returning this value requires that `'a` must outlive `'c`
+ |
+ = help: consider adding the following bound: `'a: 'c`
+
+error: lifetime may not live long enough
+ --> $DIR/outlives-suggestion-simple.rs:31:9
+ |
+LL | pub fn foo<'a>(x: &'a usize) -> Self {
+ | -- lifetime `'a` defined here
+LL | Foo { x }
+ | ^^^^^^^^^ returning this value requires that `'a` must outlive `'static`
+ |
+ = help: consider replacing `'a` with `'static`
+
+error: lifetime may not live long enough
+ --> $DIR/outlives-suggestion-simple.rs:41:9
+ |
+LL | impl<'a> Bar<'a> {
+ | -- lifetime `'a` defined here
+LL | pub fn get<'b>(&self) -> &'b usize {
+ | -- lifetime `'b` defined here
+LL | self.x
+ | ^^^^^^ returning this value requires that `'a` must outlive `'b`
+ |
+ = help: consider adding the following bound: `'a: 'b`
+
+error: lifetime may not live long enough
+ --> $DIR/outlives-suggestion-simple.rs:52:9
+ |
+LL | impl<'a> Baz<'a> {
+ | -- lifetime `'a` defined here
+LL | fn get<'b>(&'b self) -> &'a i32 {
+ | -- lifetime `'b` defined here
+LL | self.x
+ | ^^^^^^ returning this value requires that `'b` must outlive `'a`
+ |
+ = help: consider adding the following bound: `'b: 'a`
+
+error[E0521]: borrowed data escapes outside of function
+ --> $DIR/outlives-suggestion-simple.rs:73:9
+ |
+LL | fn get_bar(&self) -> Bar2 {
+ | -----
+ | |
+ | `self` is declared here, outside of the function body
+ | `self` is a reference that is only valid in the function body
+LL | Bar2::new(&self)
+ | ^^^^^^^^^^^^^^^^ `self` escapes the function body here
+
+error: aborting due to 10 previous errors
+
diff --git a/src/test/ui/nll/polonius/subset-relations.rs b/src/test/ui/nll/polonius/subset-relations.rs
new file mode 100644
index 0000000..3f6f67e
--- /dev/null
+++ b/src/test/ui/nll/polonius/subset-relations.rs
@@ -0,0 +1,30 @@
+// Checks that Polonius can compute cases of universal regions errors:
+// "illegal subset relation errors", cases where analysis finds that
+// two free regions outlive each other, without any evidence that this
+// relation holds.
+
+// ignore-compare-mode-nll
+// compile-flags: -Z borrowck=mir -Zpolonius
+
+// returning `y` requires that `'b: 'a`, but it's not known to be true
+fn missing_subset<'a, 'b>(x: &'a u32, y: &'b u32) -> &'a u32 {
+ y //~ ERROR
+}
+
+// `'b: 'a` is explicitly declared
+fn valid_subset<'a, 'b: 'a>(x: &'a u32, y: &'b u32) -> &'a u32 {
+ y
+}
+
+// because of `x`, it is implied that `'b: 'a` holds
+fn implied_bounds_subset<'a, 'b>(x: &'a &'b mut u32) -> &'a u32 {
+ x
+}
+
+// `'b: 'a` is declared, and `'a: 'c` is known via implied bounds:
+// `'b: 'c` is therefore known to hold transitively
+fn transitively_valid_subset<'a, 'b: 'a, 'c>(x: &'c &'a u32, y: &'b u32) -> &'c u32 {
+ y
+}
+
+fn main() {}
diff --git a/src/test/ui/nll/polonius/subset-relations.stderr b/src/test/ui/nll/polonius/subset-relations.stderr
new file mode 100644
index 0000000..6364510
--- /dev/null
+++ b/src/test/ui/nll/polonius/subset-relations.stderr
@@ -0,0 +1,14 @@
+error: lifetime may not live long enough
+ --> $DIR/subset-relations.rs:11:5
+ |
+LL | fn missing_subset<'a, 'b>(x: &'a u32, y: &'b u32) -> &'a u32 {
+ | -- -- lifetime `'b` defined here
+ | |
+ | lifetime `'a` defined here
+LL | y
+ | ^ function was supposed to return data with lifetime `'a` but it is returning data with lifetime `'b`
+ |
+ = help: consider adding the following bound: `'b: 'a`
+
+error: aborting due to previous error
+
diff --git a/src/test/ui/nll/ty-outlives/projection-no-regions-closure.stderr b/src/test/ui/nll/ty-outlives/projection-no-regions-closure.stderr
index dd61023..c825227 100644
--- a/src/test/ui/nll/ty-outlives/projection-no-regions-closure.stderr
+++ b/src/test/ui/nll/ty-outlives/projection-no-regions-closure.stderr
@@ -4,9 +4,7 @@
LL | with_signature(x, |mut y| Box::new(y.next()))
| ^^^^^^^^^^^^^^^^^^^^^^^^^^
|
- = note: defining type: DefId(0:13 ~ projection_no_regions_closure[317d]::no_region[0]::{{closure}}[0]) with closure substs [
- '_#1r,
- T,
+ = note: defining type: no_region::<'_#1r, T>::{{closure}}#0 with closure substs [
i32,
extern "rust-call" fn((std::boxed::Box<T>,)) -> std::boxed::Box<(dyn Anything + '_#2r)>,
]
@@ -25,10 +23,7 @@
LL | | }
| |_^
|
- = note: defining type: DefId(0:10 ~ projection_no_regions_closure[317d]::no_region[0]) with substs [
- '_#1r,
- T,
- ]
+ = note: defining type: no_region::<'_#1r, T>
error[E0309]: the associated type `<T as std::iter::Iterator>::Item` may not live long enough
--> $DIR/projection-no-regions-closure.rs:25:23
@@ -44,9 +39,7 @@
LL | with_signature(x, |mut y| Box::new(y.next()))
| ^^^^^^^^^^^^^^^^^^^^^^^^^^
|
- = note: defining type: DefId(0:17 ~ projection_no_regions_closure[317d]::correct_region[0]::{{closure}}[0]) with closure substs [
- '_#1r,
- T,
+ = note: defining type: correct_region::<'_#1r, T>::{{closure}}#0 with closure substs [
i32,
extern "rust-call" fn((std::boxed::Box<T>,)) -> std::boxed::Box<(dyn Anything + '_#2r)>,
]
@@ -64,10 +57,7 @@
LL | | }
| |_^
|
- = note: defining type: DefId(0:14 ~ projection_no_regions_closure[317d]::correct_region[0]) with substs [
- '_#1r,
- T,
- ]
+ = note: defining type: correct_region::<'_#1r, T>
note: External requirements
--> $DIR/projection-no-regions-closure.rs:42:23
@@ -75,10 +65,7 @@
LL | with_signature(x, |mut y| Box::new(y.next()))
| ^^^^^^^^^^^^^^^^^^^^^^^^^^
|
- = note: defining type: DefId(0:22 ~ projection_no_regions_closure[317d]::wrong_region[0]::{{closure}}[0]) with closure substs [
- '_#1r,
- '_#2r,
- T,
+ = note: defining type: wrong_region::<'_#1r, '_#2r, T>::{{closure}}#0 with closure substs [
i32,
extern "rust-call" fn((std::boxed::Box<T>,)) -> std::boxed::Box<(dyn Anything + '_#3r)>,
]
@@ -97,11 +84,7 @@
LL | | }
| |_^
|
- = note: defining type: DefId(0:18 ~ projection_no_regions_closure[317d]::wrong_region[0]) with substs [
- '_#1r,
- '_#2r,
- T,
- ]
+ = note: defining type: wrong_region::<'_#1r, '_#2r, T>
error[E0309]: the associated type `<T as std::iter::Iterator>::Item` may not live long enough
--> $DIR/projection-no-regions-closure.rs:42:23
@@ -117,10 +100,7 @@
LL | with_signature(x, |mut y| Box::new(y.next()))
| ^^^^^^^^^^^^^^^^^^^^^^^^^^
|
- = note: defining type: DefId(0:27 ~ projection_no_regions_closure[317d]::outlives_region[0]::{{closure}}[0]) with closure substs [
- '_#1r,
- '_#2r,
- T,
+ = note: defining type: outlives_region::<'_#1r, '_#2r, T>::{{closure}}#0 with closure substs [
i32,
extern "rust-call" fn((std::boxed::Box<T>,)) -> std::boxed::Box<(dyn Anything + '_#3r)>,
]
@@ -139,11 +119,7 @@
LL | | }
| |_^
|
- = note: defining type: DefId(0:23 ~ projection_no_regions_closure[317d]::outlives_region[0]) with substs [
- '_#1r,
- '_#2r,
- T,
- ]
+ = note: defining type: outlives_region::<'_#1r, '_#2r, T>
error: aborting due to 2 previous errors
diff --git a/src/test/ui/nll/ty-outlives/projection-one-region-closure.stderr b/src/test/ui/nll/ty-outlives/projection-one-region-closure.stderr
index d9cbc71..7226c52 100644
--- a/src/test/ui/nll/ty-outlives/projection-one-region-closure.stderr
+++ b/src/test/ui/nll/ty-outlives/projection-one-region-closure.stderr
@@ -4,9 +4,7 @@
LL | with_signature(cell, t, |cell, t| require(cell, t));
| ^^^^^^^^^^^^^^^^^^^^^^^^^^
|
- = note: defining type: DefId(0:19 ~ projection_one_region_closure[317d]::no_relationships_late[0]::{{closure}}[0]) with closure substs [
- '_#1r,
- T,
+ = note: defining type: no_relationships_late::<'_#1r, T>::{{closure}}#0 with closure substs [
i32,
extern "rust-call" fn((std::cell::Cell<&'_#2r ()>, T)),
]
@@ -27,10 +25,7 @@
LL | | }
| |_^
|
- = note: defining type: DefId(0:15 ~ projection_one_region_closure[317d]::no_relationships_late[0]) with substs [
- '_#1r,
- T,
- ]
+ = note: defining type: no_relationships_late::<'_#1r, T>
error[E0309]: the parameter type `T` may not live long enough
--> $DIR/projection-one-region-closure.rs:45:29
@@ -59,10 +54,7 @@
LL | with_signature(cell, t, |cell, t| require(cell, t));
| ^^^^^^^^^^^^^^^^^^^^^^^^^^
|
- = note: defining type: DefId(0:24 ~ projection_one_region_closure[317d]::no_relationships_early[0]::{{closure}}[0]) with closure substs [
- '_#1r,
- '_#2r,
- T,
+ = note: defining type: no_relationships_early::<'_#1r, '_#2r, T>::{{closure}}#0 with closure substs [
i32,
extern "rust-call" fn((std::cell::Cell<&'_#3r ()>, T)),
]
@@ -82,11 +74,7 @@
LL | | }
| |_^
|
- = note: defining type: DefId(0:20 ~ projection_one_region_closure[317d]::no_relationships_early[0]) with substs [
- '_#1r,
- '_#2r,
- T,
- ]
+ = note: defining type: no_relationships_early::<'_#1r, '_#2r, T>
error[E0309]: the parameter type `T` may not live long enough
--> $DIR/projection-one-region-closure.rs:56:29
@@ -115,10 +103,7 @@
LL | with_signature(cell, t, |cell, t| require(cell, t));
| ^^^^^^^^^^^^^^^^^^^^^^^^^^
|
- = note: defining type: DefId(0:29 ~ projection_one_region_closure[317d]::projection_outlives[0]::{{closure}}[0]) with closure substs [
- '_#1r,
- '_#2r,
- T,
+ = note: defining type: projection_outlives::<'_#1r, '_#2r, T>::{{closure}}#0 with closure substs [
i32,
extern "rust-call" fn((std::cell::Cell<&'_#3r ()>, T)),
]
@@ -137,11 +122,7 @@
LL | | }
| |_^
|
- = note: defining type: DefId(0:25 ~ projection_one_region_closure[317d]::projection_outlives[0]) with substs [
- '_#1r,
- '_#2r,
- T,
- ]
+ = note: defining type: projection_outlives::<'_#1r, '_#2r, T>
note: External requirements
--> $DIR/projection-one-region-closure.rs:80:29
@@ -149,10 +130,7 @@
LL | with_signature(cell, t, |cell, t| require(cell, t));
| ^^^^^^^^^^^^^^^^^^^^^^^^^^
|
- = note: defining type: DefId(0:34 ~ projection_one_region_closure[317d]::elements_outlive[0]::{{closure}}[0]) with closure substs [
- '_#1r,
- '_#2r,
- T,
+ = note: defining type: elements_outlive::<'_#1r, '_#2r, T>::{{closure}}#0 with closure substs [
i32,
extern "rust-call" fn((std::cell::Cell<&'_#3r ()>, T)),
]
@@ -172,11 +150,7 @@
LL | | }
| |_^
|
- = note: defining type: DefId(0:30 ~ projection_one_region_closure[317d]::elements_outlive[0]) with substs [
- '_#1r,
- '_#2r,
- T,
- ]
+ = note: defining type: elements_outlive::<'_#1r, '_#2r, T>
error: aborting due to 4 previous errors
diff --git a/src/test/ui/nll/ty-outlives/projection-one-region-trait-bound-closure.stderr b/src/test/ui/nll/ty-outlives/projection-one-region-trait-bound-closure.stderr
index 0be25de..655995c 100644
--- a/src/test/ui/nll/ty-outlives/projection-one-region-trait-bound-closure.stderr
+++ b/src/test/ui/nll/ty-outlives/projection-one-region-trait-bound-closure.stderr
@@ -4,9 +4,7 @@
LL | with_signature(cell, t, |cell, t| require(cell, t));
| ^^^^^^^^^^^^^^^^^^^^^^^^^^
|
- = note: defining type: DefId(0:19 ~ projection_one_region_trait_bound_closure[317d]::no_relationships_late[0]::{{closure}}[0]) with closure substs [
- '_#1r,
- T,
+ = note: defining type: no_relationships_late::<'_#1r, T>::{{closure}}#0 with closure substs [
i32,
extern "rust-call" fn((std::cell::Cell<&'_#2r ()>, T)),
]
@@ -26,10 +24,7 @@
LL | | }
| |_^
|
- = note: defining type: DefId(0:15 ~ projection_one_region_trait_bound_closure[317d]::no_relationships_late[0]) with substs [
- '_#1r,
- T,
- ]
+ = note: defining type: no_relationships_late::<'_#1r, T>
error: lifetime may not live long enough
--> $DIR/projection-one-region-trait-bound-closure.rs:37:39
@@ -50,10 +45,7 @@
LL | with_signature(cell, t, |cell, t| require(cell, t));
| ^^^^^^^^^^^^^^^^^^^^^^^^^^
|
- = note: defining type: DefId(0:24 ~ projection_one_region_trait_bound_closure[317d]::no_relationships_early[0]::{{closure}}[0]) with closure substs [
- '_#1r,
- '_#2r,
- T,
+ = note: defining type: no_relationships_early::<'_#1r, '_#2r, T>::{{closure}}#0 with closure substs [
i32,
extern "rust-call" fn((std::cell::Cell<&'_#3r ()>, T)),
]
@@ -72,11 +64,7 @@
LL | | }
| |_^
|
- = note: defining type: DefId(0:20 ~ projection_one_region_trait_bound_closure[317d]::no_relationships_early[0]) with substs [
- '_#1r,
- '_#2r,
- T,
- ]
+ = note: defining type: no_relationships_early::<'_#1r, '_#2r, T>
error: lifetime may not live long enough
--> $DIR/projection-one-region-trait-bound-closure.rs:47:39
@@ -97,10 +85,7 @@
LL | with_signature(cell, t, |cell, t| require(cell, t));
| ^^^^^^^^^^^^^^^^^^^^^^^^^^
|
- = note: defining type: DefId(0:29 ~ projection_one_region_trait_bound_closure[317d]::projection_outlives[0]::{{closure}}[0]) with closure substs [
- '_#1r,
- '_#2r,
- T,
+ = note: defining type: projection_outlives::<'_#1r, '_#2r, T>::{{closure}}#0 with closure substs [
i32,
extern "rust-call" fn((std::cell::Cell<&'_#3r ()>, T)),
]
@@ -119,11 +104,7 @@
LL | | }
| |_^
|
- = note: defining type: DefId(0:25 ~ projection_one_region_trait_bound_closure[317d]::projection_outlives[0]) with substs [
- '_#1r,
- '_#2r,
- T,
- ]
+ = note: defining type: projection_outlives::<'_#1r, '_#2r, T>
note: External requirements
--> $DIR/projection-one-region-trait-bound-closure.rs:69:29
@@ -131,10 +112,7 @@
LL | with_signature(cell, t, |cell, t| require(cell, t));
| ^^^^^^^^^^^^^^^^^^^^^^^^^^
|
- = note: defining type: DefId(0:34 ~ projection_one_region_trait_bound_closure[317d]::elements_outlive[0]::{{closure}}[0]) with closure substs [
- '_#1r,
- '_#2r,
- T,
+ = note: defining type: elements_outlive::<'_#1r, '_#2r, T>::{{closure}}#0 with closure substs [
i32,
extern "rust-call" fn((std::cell::Cell<&'_#3r ()>, T)),
]
@@ -153,11 +131,7 @@
LL | | }
| |_^
|
- = note: defining type: DefId(0:30 ~ projection_one_region_trait_bound_closure[317d]::elements_outlive[0]) with substs [
- '_#1r,
- '_#2r,
- T,
- ]
+ = note: defining type: elements_outlive::<'_#1r, '_#2r, T>
note: External requirements
--> $DIR/projection-one-region-trait-bound-closure.rs:81:29
@@ -165,9 +139,7 @@
LL | with_signature(cell, t, |cell, t| require(cell, t));
| ^^^^^^^^^^^^^^^^^^^^^^^^^^
|
- = note: defining type: DefId(0:38 ~ projection_one_region_trait_bound_closure[317d]::one_region[0]::{{closure}}[0]) with closure substs [
- '_#1r,
- T,
+ = note: defining type: one_region::<'_#1r, T>::{{closure}}#0 with closure substs [
i32,
extern "rust-call" fn((std::cell::Cell<&'_#2r ()>, T)),
]
@@ -186,10 +158,7 @@
LL | | }
| |_^
|
- = note: defining type: DefId(0:35 ~ projection_one_region_trait_bound_closure[317d]::one_region[0]) with substs [
- '_#1r,
- T,
- ]
+ = note: defining type: one_region::<'_#1r, T>
error: aborting due to 2 previous errors
diff --git a/src/test/ui/nll/ty-outlives/projection-one-region-trait-bound-static-closure.stderr b/src/test/ui/nll/ty-outlives/projection-one-region-trait-bound-static-closure.stderr
index 9cc2e50..2fb07b9 100644
--- a/src/test/ui/nll/ty-outlives/projection-one-region-trait-bound-static-closure.stderr
+++ b/src/test/ui/nll/ty-outlives/projection-one-region-trait-bound-static-closure.stderr
@@ -4,9 +4,7 @@
LL | with_signature(cell, t, |cell, t| require(cell, t));
| ^^^^^^^^^^^^^^^^^^^^^^^^^^
|
- = note: defining type: DefId(0:19 ~ projection_one_region_trait_bound_static_closure[317d]::no_relationships_late[0]::{{closure}}[0]) with closure substs [
- '_#1r,
- T,
+ = note: defining type: no_relationships_late::<'_#1r, T>::{{closure}}#0 with closure substs [
i32,
extern "rust-call" fn((std::cell::Cell<&'_#2r ()>, T)),
]
@@ -23,10 +21,7 @@
LL | | }
| |_^
|
- = note: defining type: DefId(0:15 ~ projection_one_region_trait_bound_static_closure[317d]::no_relationships_late[0]) with substs [
- '_#1r,
- T,
- ]
+ = note: defining type: no_relationships_late::<'_#1r, T>
note: No external requirements
--> $DIR/projection-one-region-trait-bound-static-closure.rs:45:29
@@ -34,10 +29,7 @@
LL | with_signature(cell, t, |cell, t| require(cell, t));
| ^^^^^^^^^^^^^^^^^^^^^^^^^^
|
- = note: defining type: DefId(0:24 ~ projection_one_region_trait_bound_static_closure[317d]::no_relationships_early[0]::{{closure}}[0]) with closure substs [
- '_#1r,
- '_#2r,
- T,
+ = note: defining type: no_relationships_early::<'_#1r, '_#2r, T>::{{closure}}#0 with closure substs [
i32,
extern "rust-call" fn((std::cell::Cell<&'_#3r ()>, T)),
]
@@ -54,11 +46,7 @@
LL | | }
| |_^
|
- = note: defining type: DefId(0:20 ~ projection_one_region_trait_bound_static_closure[317d]::no_relationships_early[0]) with substs [
- '_#1r,
- '_#2r,
- T,
- ]
+ = note: defining type: no_relationships_early::<'_#1r, '_#2r, T>
note: No external requirements
--> $DIR/projection-one-region-trait-bound-static-closure.rs:64:29
@@ -66,10 +54,7 @@
LL | with_signature(cell, t, |cell, t| require(cell, t));
| ^^^^^^^^^^^^^^^^^^^^^^^^^^
|
- = note: defining type: DefId(0:29 ~ projection_one_region_trait_bound_static_closure[317d]::projection_outlives[0]::{{closure}}[0]) with closure substs [
- '_#1r,
- '_#2r,
- T,
+ = note: defining type: projection_outlives::<'_#1r, '_#2r, T>::{{closure}}#0 with closure substs [
i32,
extern "rust-call" fn((std::cell::Cell<&'_#3r ()>, T)),
]
@@ -86,11 +71,7 @@
LL | | }
| |_^
|
- = note: defining type: DefId(0:25 ~ projection_one_region_trait_bound_static_closure[317d]::projection_outlives[0]) with substs [
- '_#1r,
- '_#2r,
- T,
- ]
+ = note: defining type: projection_outlives::<'_#1r, '_#2r, T>
note: No external requirements
--> $DIR/projection-one-region-trait-bound-static-closure.rs:73:29
@@ -98,10 +79,7 @@
LL | with_signature(cell, t, |cell, t| require(cell, t));
| ^^^^^^^^^^^^^^^^^^^^^^^^^^
|
- = note: defining type: DefId(0:34 ~ projection_one_region_trait_bound_static_closure[317d]::elements_outlive[0]::{{closure}}[0]) with closure substs [
- '_#1r,
- '_#2r,
- T,
+ = note: defining type: elements_outlive::<'_#1r, '_#2r, T>::{{closure}}#0 with closure substs [
i32,
extern "rust-call" fn((std::cell::Cell<&'_#3r ()>, T)),
]
@@ -118,11 +96,7 @@
LL | | }
| |_^
|
- = note: defining type: DefId(0:30 ~ projection_one_region_trait_bound_static_closure[317d]::elements_outlive[0]) with substs [
- '_#1r,
- '_#2r,
- T,
- ]
+ = note: defining type: elements_outlive::<'_#1r, '_#2r, T>
note: No external requirements
--> $DIR/projection-one-region-trait-bound-static-closure.rs:85:29
@@ -130,9 +104,7 @@
LL | with_signature(cell, t, |cell, t| require(cell, t));
| ^^^^^^^^^^^^^^^^^^^^^^^^^^
|
- = note: defining type: DefId(0:38 ~ projection_one_region_trait_bound_static_closure[317d]::one_region[0]::{{closure}}[0]) with closure substs [
- '_#1r,
- T,
+ = note: defining type: one_region::<'_#1r, T>::{{closure}}#0 with closure substs [
i32,
extern "rust-call" fn((std::cell::Cell<&'_#2r ()>, T)),
]
@@ -149,8 +121,5 @@
LL | | }
| |_^
|
- = note: defining type: DefId(0:35 ~ projection_one_region_trait_bound_static_closure[317d]::one_region[0]) with substs [
- '_#1r,
- T,
- ]
+ = note: defining type: one_region::<'_#1r, T>
diff --git a/src/test/ui/nll/ty-outlives/projection-two-region-trait-bound-closure.stderr b/src/test/ui/nll/ty-outlives/projection-two-region-trait-bound-closure.stderr
index ed53ce9..501a55e3 100644
--- a/src/test/ui/nll/ty-outlives/projection-two-region-trait-bound-closure.stderr
+++ b/src/test/ui/nll/ty-outlives/projection-two-region-trait-bound-closure.stderr
@@ -4,10 +4,7 @@
LL | with_signature(cell, t, |cell, t| require(cell, t));
| ^^^^^^^^^^^^^^^^^^^^^^^^^^
|
- = note: defining type: DefId(0:22 ~ projection_two_region_trait_bound_closure[317d]::no_relationships_late[0]::{{closure}}[0]) with closure substs [
- '_#1r,
- '_#2r,
- T,
+ = note: defining type: no_relationships_late::<'_#1r, '_#2r, T>::{{closure}}#0 with closure substs [
i32,
extern "rust-call" fn((std::cell::Cell<&'_#3r ()>, T)),
]
@@ -27,11 +24,7 @@
LL | | }
| |_^
|
- = note: defining type: DefId(0:17 ~ projection_two_region_trait_bound_closure[317d]::no_relationships_late[0]) with substs [
- '_#1r,
- '_#2r,
- T,
- ]
+ = note: defining type: no_relationships_late::<'_#1r, '_#2r, T>
error[E0309]: the associated type `<T as Anything<'_#5r, '_#6r>>::AssocType` may not live long enough
--> $DIR/projection-two-region-trait-bound-closure.rs:38:29
@@ -47,11 +40,7 @@
LL | with_signature(cell, t, |cell, t| require(cell, t));
| ^^^^^^^^^^^^^^^^^^^^^^^^^^
|
- = note: defining type: DefId(0:28 ~ projection_two_region_trait_bound_closure[317d]::no_relationships_early[0]::{{closure}}[0]) with closure substs [
- '_#1r,
- '_#2r,
- '_#3r,
- T,
+ = note: defining type: no_relationships_early::<'_#1r, '_#2r, '_#3r, T>::{{closure}}#0 with closure substs [
i32,
extern "rust-call" fn((std::cell::Cell<&'_#4r ()>, T)),
]
@@ -70,12 +59,7 @@
LL | | }
| |_^
|
- = note: defining type: DefId(0:23 ~ projection_two_region_trait_bound_closure[317d]::no_relationships_early[0]) with substs [
- '_#1r,
- '_#2r,
- '_#3r,
- T,
- ]
+ = note: defining type: no_relationships_early::<'_#1r, '_#2r, '_#3r, T>
error[E0309]: the associated type `<T as Anything<'_#6r, '_#7r>>::AssocType` may not live long enough
--> $DIR/projection-two-region-trait-bound-closure.rs:48:29
@@ -91,11 +75,7 @@
LL | with_signature(cell, t, |cell, t| require(cell, t));
| ^^^^^^^^^^^^^^^^^^^^^^^^^^
|
- = note: defining type: DefId(0:34 ~ projection_two_region_trait_bound_closure[317d]::projection_outlives[0]::{{closure}}[0]) with closure substs [
- '_#1r,
- '_#2r,
- '_#3r,
- T,
+ = note: defining type: projection_outlives::<'_#1r, '_#2r, '_#3r, T>::{{closure}}#0 with closure substs [
i32,
extern "rust-call" fn((std::cell::Cell<&'_#4r ()>, T)),
]
@@ -114,12 +94,7 @@
LL | | }
| |_^
|
- = note: defining type: DefId(0:29 ~ projection_two_region_trait_bound_closure[317d]::projection_outlives[0]) with substs [
- '_#1r,
- '_#2r,
- '_#3r,
- T,
- ]
+ = note: defining type: projection_outlives::<'_#1r, '_#2r, '_#3r, T>
note: External requirements
--> $DIR/projection-two-region-trait-bound-closure.rs:70:29
@@ -127,11 +102,7 @@
LL | with_signature(cell, t, |cell, t| require(cell, t));
| ^^^^^^^^^^^^^^^^^^^^^^^^^^
|
- = note: defining type: DefId(0:40 ~ projection_two_region_trait_bound_closure[317d]::elements_outlive1[0]::{{closure}}[0]) with closure substs [
- '_#1r,
- '_#2r,
- '_#3r,
- T,
+ = note: defining type: elements_outlive1::<'_#1r, '_#2r, '_#3r, T>::{{closure}}#0 with closure substs [
i32,
extern "rust-call" fn((std::cell::Cell<&'_#4r ()>, T)),
]
@@ -150,12 +121,7 @@
LL | | }
| |_^
|
- = note: defining type: DefId(0:35 ~ projection_two_region_trait_bound_closure[317d]::elements_outlive1[0]) with substs [
- '_#1r,
- '_#2r,
- '_#3r,
- T,
- ]
+ = note: defining type: elements_outlive1::<'_#1r, '_#2r, '_#3r, T>
note: External requirements
--> $DIR/projection-two-region-trait-bound-closure.rs:79:29
@@ -163,11 +129,7 @@
LL | with_signature(cell, t, |cell, t| require(cell, t));
| ^^^^^^^^^^^^^^^^^^^^^^^^^^
|
- = note: defining type: DefId(0:46 ~ projection_two_region_trait_bound_closure[317d]::elements_outlive2[0]::{{closure}}[0]) with closure substs [
- '_#1r,
- '_#2r,
- '_#3r,
- T,
+ = note: defining type: elements_outlive2::<'_#1r, '_#2r, '_#3r, T>::{{closure}}#0 with closure substs [
i32,
extern "rust-call" fn((std::cell::Cell<&'_#4r ()>, T)),
]
@@ -186,12 +148,7 @@
LL | | }
| |_^
|
- = note: defining type: DefId(0:41 ~ projection_two_region_trait_bound_closure[317d]::elements_outlive2[0]) with substs [
- '_#1r,
- '_#2r,
- '_#3r,
- T,
- ]
+ = note: defining type: elements_outlive2::<'_#1r, '_#2r, '_#3r, T>
note: External requirements
--> $DIR/projection-two-region-trait-bound-closure.rs:87:29
@@ -199,9 +156,7 @@
LL | with_signature(cell, t, |cell, t| require(cell, t));
| ^^^^^^^^^^^^^^^^^^^^^^^^^^
|
- = note: defining type: DefId(0:51 ~ projection_two_region_trait_bound_closure[317d]::two_regions[0]::{{closure}}[0]) with closure substs [
- '_#1r,
- T,
+ = note: defining type: two_regions::<'_#1r, T>::{{closure}}#0 with closure substs [
i32,
extern "rust-call" fn((std::cell::Cell<&'_#2r ()>, T)),
]
@@ -221,10 +176,7 @@
LL | | }
| |_^
|
- = note: defining type: DefId(0:47 ~ projection_two_region_trait_bound_closure[317d]::two_regions[0]) with substs [
- '_#1r,
- T,
- ]
+ = note: defining type: two_regions::<'_#1r, T>
error: lifetime may not live long enough
--> $DIR/projection-two-region-trait-bound-closure.rs:87:29
@@ -245,10 +197,7 @@
LL | with_signature(cell, t, |cell, t| require(cell, t));
| ^^^^^^^^^^^^^^^^^^^^^^^^^^
|
- = note: defining type: DefId(0:56 ~ projection_two_region_trait_bound_closure[317d]::two_regions_outlive[0]::{{closure}}[0]) with closure substs [
- '_#1r,
- '_#2r,
- T,
+ = note: defining type: two_regions_outlive::<'_#1r, '_#2r, T>::{{closure}}#0 with closure substs [
i32,
extern "rust-call" fn((std::cell::Cell<&'_#3r ()>, T)),
]
@@ -267,11 +216,7 @@
LL | | }
| |_^
|
- = note: defining type: DefId(0:52 ~ projection_two_region_trait_bound_closure[317d]::two_regions_outlive[0]) with substs [
- '_#1r,
- '_#2r,
- T,
- ]
+ = note: defining type: two_regions_outlive::<'_#1r, '_#2r, T>
note: External requirements
--> $DIR/projection-two-region-trait-bound-closure.rs:109:29
@@ -279,9 +224,7 @@
LL | with_signature(cell, t, |cell, t| require(cell, t));
| ^^^^^^^^^^^^^^^^^^^^^^^^^^
|
- = note: defining type: DefId(0:60 ~ projection_two_region_trait_bound_closure[317d]::one_region[0]::{{closure}}[0]) with closure substs [
- '_#1r,
- T,
+ = note: defining type: one_region::<'_#1r, T>::{{closure}}#0 with closure substs [
i32,
extern "rust-call" fn((std::cell::Cell<&'_#2r ()>, T)),
]
@@ -300,10 +243,7 @@
LL | | }
| |_^
|
- = note: defining type: DefId(0:57 ~ projection_two_region_trait_bound_closure[317d]::one_region[0]) with substs [
- '_#1r,
- T,
- ]
+ = note: defining type: one_region::<'_#1r, T>
error: aborting due to 3 previous errors
diff --git a/src/test/ui/nll/ty-outlives/ty-param-closure-approximate-lower-bound.stderr b/src/test/ui/nll/ty-outlives/ty-param-closure-approximate-lower-bound.stderr
index e2a9bd7..db0bca1 100644
--- a/src/test/ui/nll/ty-outlives/ty-param-closure-approximate-lower-bound.stderr
+++ b/src/test/ui/nll/ty-outlives/ty-param-closure-approximate-lower-bound.stderr
@@ -4,8 +4,7 @@
LL | twice(cell, value, |a, b| invoke(a, b));
| ^^^^^^^^^^^^^^^^^^^
|
- = note: defining type: DefId(0:11 ~ ty_param_closure_approximate_lower_bound[317d]::generic[0]::{{closure}}[0]) with closure substs [
- T,
+ = note: defining type: generic::<T>::{{closure}}#0 with closure substs [
i16,
for<'r, 's> extern "rust-call" fn((std::option::Option<std::cell::Cell<&'_#1r &ReLateBound(DebruijnIndex(0), BrNamed('r)) ()>>, &ReLateBound(DebruijnIndex(0), BrNamed('s)) T)),
]
@@ -21,9 +20,7 @@
LL | | }
| |_^
|
- = note: defining type: DefId(0:9 ~ ty_param_closure_approximate_lower_bound[317d]::generic[0]) with substs [
- T,
- ]
+ = note: defining type: generic::<T>
note: External requirements
--> $DIR/ty-param-closure-approximate-lower-bound.rs:29:24
@@ -31,8 +28,7 @@
LL | twice(cell, value, |a, b| invoke(a, b));
| ^^^^^^^^^^^^^^^^^^^
|
- = note: defining type: DefId(0:15 ~ ty_param_closure_approximate_lower_bound[317d]::generic_fail[0]::{{closure}}[0]) with closure substs [
- T,
+ = note: defining type: generic_fail::<T>::{{closure}}#0 with closure substs [
i16,
for<'r, 's> extern "rust-call" fn((std::option::Option<std::cell::Cell<&'_#1r &ReLateBound(DebruijnIndex(0), BrNamed('r)) ()>>, &ReLateBound(DebruijnIndex(0), BrNamed('s)) T)),
]
@@ -49,9 +45,7 @@
LL | | }
| |_^
|
- = note: defining type: DefId(0:12 ~ ty_param_closure_approximate_lower_bound[317d]::generic_fail[0]) with substs [
- T,
- ]
+ = note: defining type: generic_fail::<T>
error[E0309]: the parameter type `T` may not live long enough
--> $DIR/ty-param-closure-approximate-lower-bound.rs:29:24
diff --git a/src/test/ui/nll/ty-outlives/ty-param-closure-outlives-from-return-type.stderr b/src/test/ui/nll/ty-outlives/ty-param-closure-outlives-from-return-type.stderr
index 7c8dc94..0021d73 100644
--- a/src/test/ui/nll/ty-outlives/ty-param-closure-outlives-from-return-type.stderr
+++ b/src/test/ui/nll/ty-outlives/ty-param-closure-outlives-from-return-type.stderr
@@ -4,9 +4,7 @@
LL | with_signature(x, |y| y)
| ^^^^^
|
- = note: defining type: DefId(0:11 ~ ty_param_closure_outlives_from_return_type[317d]::no_region[0]::{{closure}}[0]) with closure substs [
- '_#1r,
- T,
+ = note: defining type: no_region::<'_#1r, T>::{{closure}}#0 with closure substs [
i32,
extern "rust-call" fn((std::boxed::Box<T>,)) -> std::boxed::Box<(dyn std::fmt::Debug + '_#2r)>,
]
@@ -25,10 +23,7 @@
LL | | }
| |_^
|
- = note: defining type: DefId(0:8 ~ ty_param_closure_outlives_from_return_type[317d]::no_region[0]) with substs [
- '_#1r,
- T,
- ]
+ = note: defining type: no_region::<'_#1r, T>
error[E0309]: the parameter type `T` may not live long enough
--> $DIR/ty-param-closure-outlives-from-return-type.rs:26:23
diff --git a/src/test/ui/nll/ty-outlives/ty-param-closure-outlives-from-where-clause.stderr b/src/test/ui/nll/ty-outlives/ty-param-closure-outlives-from-where-clause.stderr
index ffd936b..46fef8e 100644
--- a/src/test/ui/nll/ty-outlives/ty-param-closure-outlives-from-where-clause.stderr
+++ b/src/test/ui/nll/ty-outlives/ty-param-closure-outlives-from-where-clause.stderr
@@ -11,8 +11,7 @@
LL | | })
| |_____^
|
- = note: defining type: DefId(0:14 ~ ty_param_closure_outlives_from_where_clause[317d]::no_region[0]::{{closure}}[0]) with closure substs [
- T,
+ = note: defining type: no_region::<T>::{{closure}}#0 with closure substs [
i32,
extern "rust-call" fn((std::cell::Cell<&'_#1r ()>, T)),
]
@@ -32,9 +31,7 @@
LL | | }
| |_^
|
- = note: defining type: DefId(0:11 ~ ty_param_closure_outlives_from_where_clause[317d]::no_region[0]) with substs [
- T,
- ]
+ = note: defining type: no_region::<T>
error[E0309]: the parameter type `T` may not live long enough
--> $DIR/ty-param-closure-outlives-from-where-clause.rs:27:26
@@ -64,9 +61,7 @@
LL | | })
| |_____^
|
- = note: defining type: DefId(0:18 ~ ty_param_closure_outlives_from_where_clause[317d]::correct_region[0]::{{closure}}[0]) with closure substs [
- '_#1r,
- T,
+ = note: defining type: correct_region::<'_#1r, T>::{{closure}}#0 with closure substs [
i32,
extern "rust-call" fn((std::cell::Cell<&'_#2r ()>, T)),
]
@@ -85,10 +80,7 @@
LL | | }
| |_^
|
- = note: defining type: DefId(0:15 ~ ty_param_closure_outlives_from_where_clause[317d]::correct_region[0]) with substs [
- '_#1r,
- T,
- ]
+ = note: defining type: correct_region::<'_#1r, T>
note: External requirements
--> $DIR/ty-param-closure-outlives-from-where-clause.rs:64:26
@@ -101,9 +93,7 @@
LL | | })
| |_____^
|
- = note: defining type: DefId(0:23 ~ ty_param_closure_outlives_from_where_clause[317d]::wrong_region[0]::{{closure}}[0]) with closure substs [
- '_#1r,
- T,
+ = note: defining type: wrong_region::<'_#1r, T>::{{closure}}#0 with closure substs [
i32,
extern "rust-call" fn((std::cell::Cell<&'_#2r ()>, T)),
]
@@ -123,10 +113,7 @@
LL | | }
| |_^
|
- = note: defining type: DefId(0:19 ~ ty_param_closure_outlives_from_where_clause[317d]::wrong_region[0]) with substs [
- '_#1r,
- T,
- ]
+ = note: defining type: wrong_region::<'_#1r, T>
error[E0309]: the parameter type `T` may not live long enough
--> $DIR/ty-param-closure-outlives-from-where-clause.rs:64:26
@@ -151,10 +138,7 @@
LL | | })
| |_____^
|
- = note: defining type: DefId(0:28 ~ ty_param_closure_outlives_from_where_clause[317d]::outlives_region[0]::{{closure}}[0]) with closure substs [
- '_#1r,
- '_#2r,
- T,
+ = note: defining type: outlives_region::<'_#1r, '_#2r, T>::{{closure}}#0 with closure substs [
i32,
extern "rust-call" fn((std::cell::Cell<&'_#3r ()>, T)),
]
@@ -173,11 +157,7 @@
LL | | }
| |_^
|
- = note: defining type: DefId(0:24 ~ ty_param_closure_outlives_from_where_clause[317d]::outlives_region[0]) with substs [
- '_#1r,
- '_#2r,
- T,
- ]
+ = note: defining type: outlives_region::<'_#1r, '_#2r, T>
error: aborting due to 2 previous errors
diff --git a/src/test/ui/nll/type-alias-free-regions.stderr b/src/test/ui/nll/type-alias-free-regions.stderr
index 6986389..5191dec 100644
--- a/src/test/ui/nll/type-alias-free-regions.stderr
+++ b/src/test/ui/nll/type-alias-free-regions.stderr
@@ -11,17 +11,25 @@
LL | | C { f: b }
LL | | }
| |_____^
- = note: ...so that the expression is assignable:
- expected std::boxed::Box<std::boxed::Box<&isize>>
- found std::boxed::Box<std::boxed::Box<&isize>>
+note: ...so that the expression is assignable
+ --> $DIR/type-alias-free-regions.rs:17:16
+ |
+LL | C { f: b }
+ | ^
+ = note: expected `std::boxed::Box<std::boxed::Box<&isize>>`
+ found `std::boxed::Box<std::boxed::Box<&isize>>`
note: but, the lifetime must be valid for the lifetime `'a` as defined on the impl at 15:6...
--> $DIR/type-alias-free-regions.rs:15:6
|
LL | impl<'a> FromBox<'a> for C<'a> {
| ^^
- = note: ...so that the expression is assignable:
- expected C<'a>
- found C<'_>
+note: ...so that the expression is assignable
+ --> $DIR/type-alias-free-regions.rs:17:9
+ |
+LL | C { f: b }
+ | ^^^^^^^^^^
+ = note: expected `C<'a>`
+ found `C<'_>`
error[E0495]: cannot infer an appropriate lifetime due to conflicting requirements
--> $DIR/type-alias-free-regions.rs:27:16
@@ -36,17 +44,25 @@
LL | | C { f: Box::new(b.0) }
LL | | }
| |_____^
- = note: ...so that the expression is assignable:
- expected std::boxed::Box<&isize>
- found std::boxed::Box<&isize>
+note: ...so that the expression is assignable
+ --> $DIR/type-alias-free-regions.rs:27:25
+ |
+LL | C { f: Box::new(b.0) }
+ | ^^^
+ = note: expected `std::boxed::Box<&isize>`
+ found `std::boxed::Box<&isize>`
note: but, the lifetime must be valid for the lifetime `'a` as defined on the impl at 25:6...
--> $DIR/type-alias-free-regions.rs:25:6
|
LL | impl<'a> FromTuple<'a> for C<'a> {
| ^^
- = note: ...so that the expression is assignable:
- expected C<'a>
- found C<'_>
+note: ...so that the expression is assignable
+ --> $DIR/type-alias-free-regions.rs:27:9
+ |
+LL | C { f: Box::new(b.0) }
+ | ^^^^^^^^^^^^^^^^^^^^^^
+ = note: expected `C<'a>`
+ found `C<'_>`
error: aborting due to 2 previous errors
diff --git a/src/test/ui/nll/user-annotations/closure-substs.polonius.stderr b/src/test/ui/nll/user-annotations/closure-substs.polonius.stderr
new file mode 100644
index 0000000..d5bcdf6
--- /dev/null
+++ b/src/test/ui/nll/user-annotations/closure-substs.polonius.stderr
@@ -0,0 +1,60 @@
+error: lifetime may not live long enough
+ --> $DIR/closure-substs.rs:8:16
+ |
+LL | fn foo<'a>() {
+ | -- lifetime `'a` defined here
+...
+LL | return x;
+ | ^ returning this value requires that `'a` must outlive `'static`
+ |
+ = help: consider replacing `'a` with `'static`
+
+error: lifetime may not live long enough
+ --> $DIR/closure-substs.rs:15:16
+ |
+LL | |x: &i32| -> &'static i32 {
+ | - let's call the lifetime of this reference `'1`
+LL | return x;
+ | ^ returning this value requires that `'1` must outlive `'static`
+
+error: lifetime may not live long enough
+ --> $DIR/closure-substs.rs:15:16
+ |
+LL | |x: &i32| -> &'static i32 {
+ | - ------------ return type of closure is &'2 i32
+ | |
+ | let's call the lifetime of this reference `'1`
+LL | return x;
+ | ^ returning this value requires that `'1` must outlive `'2`
+
+error: lifetime may not live long enough
+ --> $DIR/closure-substs.rs:22:9
+ |
+LL | fn bar<'a>() {
+ | -- lifetime `'a` defined here
+...
+LL | b(x);
+ | ^^^^ argument requires that `'a` must outlive `'static`
+ |
+ = help: consider replacing `'a` with `'static`
+
+error[E0521]: borrowed data escapes outside of closure
+ --> $DIR/closure-substs.rs:29:9
+ |
+LL | |x: &i32, b: fn(&'static i32)| {
+ | - `x` is a reference that is only valid in the closure body
+LL | b(x);
+ | ^^^^ `x` escapes the closure body here
+
+error[E0521]: borrowed data escapes outside of closure
+ --> $DIR/closure-substs.rs:29:9
+ |
+LL | |x: &i32, b: fn(&'static i32)| {
+ | - - `b` is declared here, outside of the closure body
+ | |
+ | `x` is a reference that is only valid in the closure body
+LL | b(x);
+ | ^^^^ `x` escapes the closure body here
+
+error: aborting due to 6 previous errors
+
diff --git a/src/test/ui/nll/user-annotations/constant-in-expr-inherent-1.stderr b/src/test/ui/nll/user-annotations/constant-in-expr-inherent-1.stderr
index 4ebd991..37be450 100644
--- a/src/test/ui/nll/user-annotations/constant-in-expr-inherent-1.stderr
+++ b/src/test/ui/nll/user-annotations/constant-in-expr-inherent-1.stderr
@@ -9,9 +9,13 @@
|
LL | fn foo<'a>(_: &'a u32) -> &'static u32 {
| ^^
- = note: ...so that the types are compatible:
- expected Foo<'_>
- found Foo<'a>
+note: ...so that the types are compatible
+ --> $DIR/constant-in-expr-inherent-1.rs:8:5
+ |
+LL | <Foo<'a>>::C
+ | ^^^^^^^^^^^^
+ = note: expected `Foo<'_>`
+ found `Foo<'a>`
= note: but, the lifetime must be valid for the static lifetime...
note: ...so that reference does not outlive borrowed content
--> $DIR/constant-in-expr-inherent-1.rs:8:5
diff --git a/src/test/ui/nll/user-annotations/constant-in-expr-trait-item-3.stderr b/src/test/ui/nll/user-annotations/constant-in-expr-trait-item-3.stderr
index d61659e..4ee3284 100644
--- a/src/test/ui/nll/user-annotations/constant-in-expr-trait-item-3.stderr
+++ b/src/test/ui/nll/user-annotations/constant-in-expr-trait-item-3.stderr
@@ -9,9 +9,13 @@
|
LL | fn foo<'a, T: Foo<'a>>() -> &'static u32 {
| ^^
- = note: ...so that the types are compatible:
- expected Foo<'_>
- found Foo<'a>
+note: ...so that the types are compatible
+ --> $DIR/constant-in-expr-trait-item-3.rs:10:5
+ |
+LL | T::C
+ | ^^^^
+ = note: expected `Foo<'_>`
+ found `Foo<'a>`
= note: but, the lifetime must be valid for the static lifetime...
note: ...so that reference does not outlive borrowed content
--> $DIR/constant-in-expr-trait-item-3.rs:10:5
diff --git a/src/test/ui/object-lifetime/object-lifetime-default-elision.stderr b/src/test/ui/object-lifetime/object-lifetime-default-elision.stderr
index d66322c..1952ee8 100644
--- a/src/test/ui/object-lifetime/object-lifetime-default-elision.stderr
+++ b/src/test/ui/object-lifetime/object-lifetime-default-elision.stderr
@@ -19,9 +19,13 @@
|
LL | fn load3<'a,'b>(ss: &'a dyn SomeTrait) -> &'b dyn SomeTrait {
| ^^
- = note: ...so that the expression is assignable:
- expected &'b (dyn SomeTrait + 'b)
- found &dyn SomeTrait
+note: ...so that the expression is assignable
+ --> $DIR/object-lifetime-default-elision.rs:71:5
+ |
+LL | ss
+ | ^^
+ = note: expected `&'b (dyn SomeTrait + 'b)`
+ found `&dyn SomeTrait`
error[E0495]: cannot infer an appropriate lifetime due to conflicting requirements
--> $DIR/object-lifetime-default-elision.rs:71:5
@@ -44,9 +48,13 @@
|
LL | fn load3<'a,'b>(ss: &'a dyn SomeTrait) -> &'b dyn SomeTrait {
| ^^
- = note: ...so that the expression is assignable:
- expected &'b (dyn SomeTrait + 'b)
- found &dyn SomeTrait
+note: ...so that the expression is assignable
+ --> $DIR/object-lifetime-default-elision.rs:71:5
+ |
+LL | ss
+ | ^^
+ = note: expected `&'b (dyn SomeTrait + 'b)`
+ found `&dyn SomeTrait`
error: aborting due to 2 previous errors
diff --git a/src/test/ui/on-unimplemented/expected-comma-found-token.rs b/src/test/ui/on-unimplemented/expected-comma-found-token.rs
index 77c0ea1..8fb34f2 100644
--- a/src/test/ui/on-unimplemented/expected-comma-found-token.rs
+++ b/src/test/ui/on-unimplemented/expected-comma-found-token.rs
@@ -6,7 +6,7 @@
#[rustc_on_unimplemented(
message="the message"
- label="the label" //~ ERROR expected one of `)` or `,`, found `label`
+ label="the label" //~ ERROR expected `,`, found `label`
)]
trait T {}
diff --git a/src/test/ui/on-unimplemented/expected-comma-found-token.stderr b/src/test/ui/on-unimplemented/expected-comma-found-token.stderr
index 2e1d484..048b72e 100644
--- a/src/test/ui/on-unimplemented/expected-comma-found-token.stderr
+++ b/src/test/ui/on-unimplemented/expected-comma-found-token.stderr
@@ -1,11 +1,8 @@
-error: expected one of `)` or `,`, found `label`
+error: expected `,`, found `label`
--> $DIR/expected-comma-found-token.rs:9:5
|
LL | message="the message"
- | -
- | |
- | expected one of `)` or `,`
- | help: missing `,`
+ | - expected `,`
LL | label="the label"
| ^^^^^ unexpected token
diff --git a/src/test/ui/parser/lifetime-in-pattern-recover.rs b/src/test/ui/parser/lifetime-in-pattern-recover.rs
new file mode 100644
index 0000000..7fb14b8
--- /dev/null
+++ b/src/test/ui/parser/lifetime-in-pattern-recover.rs
@@ -0,0 +1,6 @@
+fn main() {
+ let &'a x = &0; //~ ERROR unexpected lifetime `'a` in pattern
+ let &'a mut y = &mut 0; //~ ERROR unexpected lifetime `'a` in pattern
+
+ let _recovery_witness: () = 0; //~ ERROR mismatched types
+}
diff --git a/src/test/ui/parser/lifetime-in-pattern-recover.stderr b/src/test/ui/parser/lifetime-in-pattern-recover.stderr
new file mode 100644
index 0000000..4bf7f57
--- /dev/null
+++ b/src/test/ui/parser/lifetime-in-pattern-recover.stderr
@@ -0,0 +1,23 @@
+error: unexpected lifetime `'a` in pattern
+ --> $DIR/lifetime-in-pattern-recover.rs:2:10
+ |
+LL | let &'a x = &0;
+ | ^^ help: remove the lifetime
+
+error: unexpected lifetime `'a` in pattern
+ --> $DIR/lifetime-in-pattern-recover.rs:3:10
+ |
+LL | let &'a mut y = &mut 0;
+ | ^^ help: remove the lifetime
+
+error[E0308]: mismatched types
+ --> $DIR/lifetime-in-pattern-recover.rs:5:33
+ |
+LL | let _recovery_witness: () = 0;
+ | -- ^ expected `()`, found integer
+ | |
+ | expected due to this
+
+error: aborting due to 3 previous errors
+
+For more information about this error, try `rustc --explain E0308`.
diff --git a/src/test/ui/parser/lifetime-in-pattern.rs b/src/test/ui/parser/lifetime-in-pattern.rs
index afee685..d3c638d 100644
--- a/src/test/ui/parser/lifetime-in-pattern.rs
+++ b/src/test/ui/parser/lifetime-in-pattern.rs
@@ -1,5 +1,6 @@
fn test(&'a str) {
//~^ ERROR unexpected lifetime `'a` in pattern
+ //~| ERROR expected one of `:`, `@`, or `|`, found `)`
}
fn main() {
diff --git a/src/test/ui/parser/lifetime-in-pattern.stderr b/src/test/ui/parser/lifetime-in-pattern.stderr
index e525c7b..71fd3cd 100644
--- a/src/test/ui/parser/lifetime-in-pattern.stderr
+++ b/src/test/ui/parser/lifetime-in-pattern.stderr
@@ -2,7 +2,13 @@
--> $DIR/lifetime-in-pattern.rs:1:10
|
LL | fn test(&'a str) {
- | ^^ unexpected lifetime
+ | ^^ help: remove the lifetime
-error: aborting due to previous error
+error: expected one of `:`, `@`, or `|`, found `)`
+ --> $DIR/lifetime-in-pattern.rs:1:16
+ |
+LL | fn test(&'a str) {
+ | ^ expected one of `:`, `@`, or `|`
+
+error: aborting due to 2 previous errors
diff --git a/src/test/ui/parser/raw/raw-literal-keywords.rs b/src/test/ui/parser/raw/raw-literal-keywords.rs
index bf9cbcd..a986980 100644
--- a/src/test/ui/parser/raw/raw-literal-keywords.rs
+++ b/src/test/ui/parser/raw/raw-literal-keywords.rs
@@ -11,11 +11,11 @@
}
fn test_if_2() {
- let _ = r#if; //~ ERROR cannot find value `if` in this scope
+ let _ = r#if; //~ ERROR cannot find value `r#if` in this scope
}
fn test_struct_2() {
- let _ = r#struct; //~ ERROR cannot find value `struct` in this scope
+ let _ = r#struct; //~ ERROR cannot find value `r#struct` in this scope
}
fn test_union_2() {
diff --git a/src/test/ui/parser/raw/raw-literal-keywords.stderr b/src/test/ui/parser/raw/raw-literal-keywords.stderr
index fd8eda3..f7b6c89 100644
--- a/src/test/ui/parser/raw/raw-literal-keywords.stderr
+++ b/src/test/ui/parser/raw/raw-literal-keywords.stderr
@@ -16,13 +16,13 @@
LL | r#union Test;
| ^^^^ expected one of 8 possible tokens
-error[E0425]: cannot find value `if` in this scope
+error[E0425]: cannot find value `r#if` in this scope
--> $DIR/raw-literal-keywords.rs:14:13
|
LL | let _ = r#if;
| ^^^^ not found in this scope
-error[E0425]: cannot find value `struct` in this scope
+error[E0425]: cannot find value `r#struct` in this scope
--> $DIR/raw-literal-keywords.rs:18:13
|
LL | let _ = r#struct;
diff --git a/src/test/ui/pattern/usefulness/always-inhabited-union-ref.stderr b/src/test/ui/pattern/usefulness/always-inhabited-union-ref.stderr
index 792ab6f..1b1096c 100644
--- a/src/test/ui/pattern/usefulness/always-inhabited-union-ref.stderr
+++ b/src/test/ui/pattern/usefulness/always-inhabited-union-ref.stderr
@@ -9,8 +9,13 @@
error[E0004]: non-exhaustive patterns: type `Foo` is non-empty
--> $DIR/always-inhabited-union-ref.rs:27:11
|
-LL | match uninhab_union() {
- | ^^^^^^^^^^^^^^^
+LL | / pub union Foo {
+LL | | foo: !,
+LL | | }
+ | |_- `Foo` defined here
+...
+LL | match uninhab_union() {
+ | ^^^^^^^^^^^^^^^
|
= help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms
diff --git a/src/test/ui/pattern/usefulness/match-empty-exhaustive_patterns.rs b/src/test/ui/pattern/usefulness/match-empty-exhaustive_patterns.rs
new file mode 100644
index 0000000..57b6b91
--- /dev/null
+++ b/src/test/ui/pattern/usefulness/match-empty-exhaustive_patterns.rs
@@ -0,0 +1,93 @@
+#![feature(never_type)]
+#![feature(exhaustive_patterns)]
+#![deny(unreachable_patterns)]
+enum Foo {}
+
+struct NonEmptyStruct(bool); //~ `NonEmptyStruct` defined here
+union NonEmptyUnion1 { //~ `NonEmptyUnion1` defined here
+ foo: (),
+}
+union NonEmptyUnion2 { //~ `NonEmptyUnion2` defined here
+ foo: (),
+ bar: (),
+}
+enum NonEmptyEnum1 { //~ `NonEmptyEnum1` defined here
+ Foo(bool),
+ //~^ not covered
+ //~| not covered
+}
+enum NonEmptyEnum2 { //~ `NonEmptyEnum2` defined here
+ Foo(bool),
+ //~^ not covered
+ //~| not covered
+ Bar,
+ //~^ not covered
+ //~| not covered
+}
+enum NonEmptyEnum5 { //~ `NonEmptyEnum5` defined here
+ V1, V2, V3, V4, V5,
+}
+
+macro_rules! match_empty {
+ ($e:expr) => {
+ match $e {}
+ };
+}
+macro_rules! match_false {
+ ($e:expr) => {
+ match $e {
+ _ if false => {}
+ }
+ };
+}
+
+fn foo(x: Foo) {
+ match_empty!(x); // ok
+ match x {
+ _ => {}, //~ ERROR unreachable pattern
+ }
+ match x {
+ _ if false => {}, //~ ERROR unreachable pattern
+ }
+}
+
+fn main() {
+ match None::<!> {
+ None => {}
+ Some(_) => {} //~ ERROR unreachable pattern
+ }
+ match None::<Foo> {
+ None => {}
+ Some(_) => {} //~ ERROR unreachable pattern
+ }
+
+ match_empty!(0u8);
+ //~^ ERROR type `u8` is non-empty
+ match_empty!(NonEmptyStruct(true));
+ //~^ ERROR type `NonEmptyStruct` is non-empty
+ match_empty!((NonEmptyUnion1 { foo: () }));
+ //~^ ERROR type `NonEmptyUnion1` is non-empty
+ match_empty!((NonEmptyUnion2 { foo: () }));
+ //~^ ERROR type `NonEmptyUnion2` is non-empty
+ match_empty!(NonEmptyEnum1::Foo(true));
+ //~^ ERROR `Foo(_)` not covered
+ match_empty!(NonEmptyEnum2::Foo(true));
+ //~^ ERROR `Foo(_)` and `Bar` not covered
+ match_empty!(NonEmptyEnum5::V1);
+ //~^ ERROR `V1`, `V2`, `V3` and 2 more not covered
+
+ match_false!(0u8);
+ //~^ ERROR `_` not covered
+ match_false!(NonEmptyStruct(true));
+ //~^ ERROR `NonEmptyStruct(_)` not covered
+ match_false!((NonEmptyUnion1 { foo: () }));
+ //~^ ERROR `NonEmptyUnion1 { .. }` not covered
+ match_false!((NonEmptyUnion2 { foo: () }));
+ //~^ ERROR `NonEmptyUnion2 { .. }` not covered
+ match_false!(NonEmptyEnum1::Foo(true));
+ //~^ ERROR `Foo(_)` not covered
+ match_false!(NonEmptyEnum2::Foo(true));
+ //~^ ERROR `Foo(_)` and `Bar` not covered
+ match_false!(NonEmptyEnum5::V1);
+ //~^ ERROR `V1`, `V2`, `V3` and 2 more not covered
+}
diff --git a/src/test/ui/pattern/usefulness/match-empty-exhaustive_patterns.stderr b/src/test/ui/pattern/usefulness/match-empty-exhaustive_patterns.stderr
new file mode 100644
index 0000000..f242ecf
--- /dev/null
+++ b/src/test/ui/pattern/usefulness/match-empty-exhaustive_patterns.stderr
@@ -0,0 +1,223 @@
+error: unreachable pattern
+ --> $DIR/match-empty-exhaustive_patterns.rs:47:9
+ |
+LL | _ => {},
+ | ^
+ |
+note: lint level defined here
+ --> $DIR/match-empty-exhaustive_patterns.rs:3:9
+ |
+LL | #![deny(unreachable_patterns)]
+ | ^^^^^^^^^^^^^^^^^^^^
+
+error: unreachable pattern
+ --> $DIR/match-empty-exhaustive_patterns.rs:50:9
+ |
+LL | _ if false => {},
+ | ^
+
+error: unreachable pattern
+ --> $DIR/match-empty-exhaustive_patterns.rs:57:9
+ |
+LL | Some(_) => {}
+ | ^^^^^^^
+
+error: unreachable pattern
+ --> $DIR/match-empty-exhaustive_patterns.rs:61:9
+ |
+LL | Some(_) => {}
+ | ^^^^^^^
+
+error[E0004]: non-exhaustive patterns: type `u8` is non-empty
+ --> $DIR/match-empty-exhaustive_patterns.rs:64:18
+ |
+LL | match_empty!(0u8);
+ | ^^^
+ |
+ = help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms
+
+error[E0004]: non-exhaustive patterns: type `NonEmptyStruct` is non-empty
+ --> $DIR/match-empty-exhaustive_patterns.rs:66:18
+ |
+LL | struct NonEmptyStruct(bool);
+ | ---------------------------- `NonEmptyStruct` defined here
+...
+LL | match_empty!(NonEmptyStruct(true));
+ | ^^^^^^^^^^^^^^^^^^^^
+ |
+ = help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms
+
+error[E0004]: non-exhaustive patterns: type `NonEmptyUnion1` is non-empty
+ --> $DIR/match-empty-exhaustive_patterns.rs:68:18
+ |
+LL | / union NonEmptyUnion1 {
+LL | | foo: (),
+LL | | }
+ | |_- `NonEmptyUnion1` defined here
+...
+LL | match_empty!((NonEmptyUnion1 { foo: () }));
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+ |
+ = help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms
+
+error[E0004]: non-exhaustive patterns: type `NonEmptyUnion2` is non-empty
+ --> $DIR/match-empty-exhaustive_patterns.rs:70:18
+ |
+LL | / union NonEmptyUnion2 {
+LL | | foo: (),
+LL | | bar: (),
+LL | | }
+ | |_- `NonEmptyUnion2` defined here
+...
+LL | match_empty!((NonEmptyUnion2 { foo: () }));
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+ |
+ = help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms
+
+error[E0004]: non-exhaustive patterns: `Foo(_)` not covered
+ --> $DIR/match-empty-exhaustive_patterns.rs:72:18
+ |
+LL | / enum NonEmptyEnum1 {
+LL | | Foo(bool),
+ | | --- not covered
+LL | |
+LL | |
+LL | | }
+ | |_- `NonEmptyEnum1` defined here
+...
+LL | match_empty!(NonEmptyEnum1::Foo(true));
+ | ^^^^^^^^^^^^^^^^^^^^^^^^ pattern `Foo(_)` not covered
+ |
+ = help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms
+
+error[E0004]: non-exhaustive patterns: `Foo(_)` and `Bar` not covered
+ --> $DIR/match-empty-exhaustive_patterns.rs:74:18
+ |
+LL | / enum NonEmptyEnum2 {
+LL | | Foo(bool),
+ | | --- not covered
+LL | |
+LL | |
+LL | | Bar,
+ | | --- not covered
+LL | |
+LL | |
+LL | | }
+ | |_- `NonEmptyEnum2` defined here
+...
+LL | match_empty!(NonEmptyEnum2::Foo(true));
+ | ^^^^^^^^^^^^^^^^^^^^^^^^ patterns `Foo(_)` and `Bar` not covered
+ |
+ = help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms
+
+error[E0004]: non-exhaustive patterns: `V1`, `V2`, `V3` and 2 more not covered
+ --> $DIR/match-empty-exhaustive_patterns.rs:76:18
+ |
+LL | / enum NonEmptyEnum5 {
+LL | | V1, V2, V3, V4, V5,
+LL | | }
+ | |_- `NonEmptyEnum5` defined here
+...
+LL | match_empty!(NonEmptyEnum5::V1);
+ | ^^^^^^^^^^^^^^^^^ patterns `V1`, `V2`, `V3` and 2 more not covered
+ |
+ = help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms
+
+error[E0004]: non-exhaustive patterns: `_` not covered
+ --> $DIR/match-empty-exhaustive_patterns.rs:79:18
+ |
+LL | match_false!(0u8);
+ | ^^^ pattern `_` not covered
+ |
+ = help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms
+
+error[E0004]: non-exhaustive patterns: `NonEmptyStruct(_)` not covered
+ --> $DIR/match-empty-exhaustive_patterns.rs:81:18
+ |
+LL | struct NonEmptyStruct(bool);
+ | ---------------------------- `NonEmptyStruct` defined here
+...
+LL | match_false!(NonEmptyStruct(true));
+ | ^^^^^^^^^^^^^^^^^^^^ pattern `NonEmptyStruct(_)` not covered
+ |
+ = help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms
+
+error[E0004]: non-exhaustive patterns: `NonEmptyUnion1 { .. }` not covered
+ --> $DIR/match-empty-exhaustive_patterns.rs:83:18
+ |
+LL | / union NonEmptyUnion1 {
+LL | | foo: (),
+LL | | }
+ | |_- `NonEmptyUnion1` defined here
+...
+LL | match_false!((NonEmptyUnion1 { foo: () }));
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ pattern `NonEmptyUnion1 { .. }` not covered
+ |
+ = help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms
+
+error[E0004]: non-exhaustive patterns: `NonEmptyUnion2 { .. }` not covered
+ --> $DIR/match-empty-exhaustive_patterns.rs:85:18
+ |
+LL | / union NonEmptyUnion2 {
+LL | | foo: (),
+LL | | bar: (),
+LL | | }
+ | |_- `NonEmptyUnion2` defined here
+...
+LL | match_false!((NonEmptyUnion2 { foo: () }));
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ pattern `NonEmptyUnion2 { .. }` not covered
+ |
+ = help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms
+
+error[E0004]: non-exhaustive patterns: `Foo(_)` not covered
+ --> $DIR/match-empty-exhaustive_patterns.rs:87:18
+ |
+LL | / enum NonEmptyEnum1 {
+LL | | Foo(bool),
+ | | --- not covered
+LL | |
+LL | |
+LL | | }
+ | |_- `NonEmptyEnum1` defined here
+...
+LL | match_false!(NonEmptyEnum1::Foo(true));
+ | ^^^^^^^^^^^^^^^^^^^^^^^^ pattern `Foo(_)` not covered
+ |
+ = help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms
+
+error[E0004]: non-exhaustive patterns: `Foo(_)` and `Bar` not covered
+ --> $DIR/match-empty-exhaustive_patterns.rs:89:18
+ |
+LL | / enum NonEmptyEnum2 {
+LL | | Foo(bool),
+ | | --- not covered
+LL | |
+LL | |
+LL | | Bar,
+ | | --- not covered
+LL | |
+LL | |
+LL | | }
+ | |_- `NonEmptyEnum2` defined here
+...
+LL | match_false!(NonEmptyEnum2::Foo(true));
+ | ^^^^^^^^^^^^^^^^^^^^^^^^ patterns `Foo(_)` and `Bar` not covered
+ |
+ = help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms
+
+error[E0004]: non-exhaustive patterns: `V1`, `V2`, `V3` and 2 more not covered
+ --> $DIR/match-empty-exhaustive_patterns.rs:91:18
+ |
+LL | / enum NonEmptyEnum5 {
+LL | | V1, V2, V3, V4, V5,
+LL | | }
+ | |_- `NonEmptyEnum5` defined here
+...
+LL | match_false!(NonEmptyEnum5::V1);
+ | ^^^^^^^^^^^^^^^^^ patterns `V1`, `V2`, `V3` and 2 more not covered
+ |
+ = help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms
+
+error: aborting due to 18 previous errors
+
+For more information about this error, try `rustc --explain E0004`.
diff --git a/src/test/ui/pattern/usefulness/match-empty.rs b/src/test/ui/pattern/usefulness/match-empty.rs
new file mode 100644
index 0000000..f757712
--- /dev/null
+++ b/src/test/ui/pattern/usefulness/match-empty.rs
@@ -0,0 +1,92 @@
+#![feature(never_type)]
+#![deny(unreachable_patterns)]
+enum Foo {}
+
+struct NonEmptyStruct(bool); //~ `NonEmptyStruct` defined here
+union NonEmptyUnion1 { //~ `NonEmptyUnion1` defined here
+ foo: (),
+}
+union NonEmptyUnion2 { //~ `NonEmptyUnion2` defined here
+ foo: (),
+ bar: (),
+}
+enum NonEmptyEnum1 { //~ `NonEmptyEnum1` defined here
+ Foo(bool),
+ //~^ not covered
+ //~| not covered
+}
+enum NonEmptyEnum2 { //~ `NonEmptyEnum2` defined here
+ Foo(bool),
+ //~^ not covered
+ //~| not covered
+ Bar,
+ //~^ not covered
+ //~| not covered
+}
+enum NonEmptyEnum5 { //~ `NonEmptyEnum5` defined here
+ V1, V2, V3, V4, V5,
+}
+
+macro_rules! match_empty {
+ ($e:expr) => {
+ match $e {}
+ };
+}
+macro_rules! match_false {
+ ($e:expr) => {
+ match $e {
+ _ if false => {}
+ }
+ };
+}
+
+fn foo(x: Foo) {
+ match_empty!(x); // ok
+ match_false!(x); // Not detected as unreachable nor exhaustive.
+ //~^ ERROR non-exhaustive patterns: `_` not covered
+ match x {
+ _ => {}, // Not detected as unreachable, see #55123.
+ }
+}
+
+fn main() {
+ // `exhaustive_patterns` is not on, so uninhabited branches are not detected as unreachable.
+ match None::<!> {
+ None => {}
+ Some(_) => {}
+ }
+ match None::<Foo> {
+ None => {}
+ Some(_) => {}
+ }
+
+ match_empty!(0u8);
+ //~^ ERROR type `u8` is non-empty
+ match_empty!(NonEmptyStruct(true));
+ //~^ ERROR type `NonEmptyStruct` is non-empty
+ match_empty!((NonEmptyUnion1 { foo: () }));
+ //~^ ERROR type `NonEmptyUnion1` is non-empty
+ match_empty!((NonEmptyUnion2 { foo: () }));
+ //~^ ERROR type `NonEmptyUnion2` is non-empty
+ match_empty!(NonEmptyEnum1::Foo(true));
+ //~^ ERROR `Foo(_)` not covered
+ match_empty!(NonEmptyEnum2::Foo(true));
+ //~^ ERROR `Foo(_)` and `Bar` not covered
+ match_empty!(NonEmptyEnum5::V1);
+ //~^ ERROR `V1`, `V2`, `V3` and 2 more not covered
+
+ match_false!(0u8);
+ //~^ ERROR `_` not covered
+ match_false!(NonEmptyStruct(true));
+ //~^ ERROR `NonEmptyStruct(_)` not covered
+ match_false!((NonEmptyUnion1 { foo: () }));
+ //~^ ERROR `NonEmptyUnion1 { .. }` not covered
+ match_false!((NonEmptyUnion2 { foo: () }));
+ //~^ ERROR `NonEmptyUnion2 { .. }` not covered
+ match_false!(NonEmptyEnum1::Foo(true));
+ //~^ ERROR `Foo(_)` not covered
+ match_false!(NonEmptyEnum2::Foo(true));
+ //~^ ERROR `Foo(_)` and `Bar` not covered
+ match_false!(NonEmptyEnum5::V1);
+ //~^ ERROR `V1`, `V2`, `V3` and 2 more not covered
+}
diff --git a/src/test/ui/pattern/usefulness/match-empty.stderr b/src/test/ui/pattern/usefulness/match-empty.stderr
new file mode 100644
index 0000000..72e3fc0
--- /dev/null
+++ b/src/test/ui/pattern/usefulness/match-empty.stderr
@@ -0,0 +1,204 @@
+error[E0004]: non-exhaustive patterns: `_` not covered
+ --> $DIR/match-empty.rs:45:18
+ |
+LL | enum Foo {}
+ | ----------- `Foo` defined here
+...
+LL | match_false!(x); // Not detected as unreachable nor exhaustive.
+ | ^ pattern `_` not covered
+ |
+ = help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms
+
+error[E0004]: non-exhaustive patterns: type `u8` is non-empty
+ --> $DIR/match-empty.rs:63:18
+ |
+LL | match_empty!(0u8);
+ | ^^^
+ |
+ = help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms
+
+error[E0004]: non-exhaustive patterns: type `NonEmptyStruct` is non-empty
+ --> $DIR/match-empty.rs:65:18
+ |
+LL | struct NonEmptyStruct(bool);
+ | ---------------------------- `NonEmptyStruct` defined here
+...
+LL | match_empty!(NonEmptyStruct(true));
+ | ^^^^^^^^^^^^^^^^^^^^
+ |
+ = help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms
+
+error[E0004]: non-exhaustive patterns: type `NonEmptyUnion1` is non-empty
+ --> $DIR/match-empty.rs:67:18
+ |
+LL | / union NonEmptyUnion1 {
+LL | | foo: (),
+LL | | }
+ | |_- `NonEmptyUnion1` defined here
+...
+LL | match_empty!((NonEmptyUnion1 { foo: () }));
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+ |
+ = help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms
+
+error[E0004]: non-exhaustive patterns: type `NonEmptyUnion2` is non-empty
+ --> $DIR/match-empty.rs:69:18
+ |
+LL | / union NonEmptyUnion2 {
+LL | | foo: (),
+LL | | bar: (),
+LL | | }
+ | |_- `NonEmptyUnion2` defined here
+...
+LL | match_empty!((NonEmptyUnion2 { foo: () }));
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+ |
+ = help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms
+
+error[E0004]: non-exhaustive patterns: `Foo(_)` not covered
+ --> $DIR/match-empty.rs:71:18
+ |
+LL | / enum NonEmptyEnum1 {
+LL | | Foo(bool),
+ | | --- not covered
+LL | |
+LL | |
+LL | | }
+ | |_- `NonEmptyEnum1` defined here
+...
+LL | match_empty!(NonEmptyEnum1::Foo(true));
+ | ^^^^^^^^^^^^^^^^^^^^^^^^ pattern `Foo(_)` not covered
+ |
+ = help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms
+
+error[E0004]: non-exhaustive patterns: `Foo(_)` and `Bar` not covered
+ --> $DIR/match-empty.rs:73:18
+ |
+LL | / enum NonEmptyEnum2 {
+LL | | Foo(bool),
+ | | --- not covered
+LL | |
+LL | |
+LL | | Bar,
+ | | --- not covered
+LL | |
+LL | |
+LL | | }
+ | |_- `NonEmptyEnum2` defined here
+...
+LL | match_empty!(NonEmptyEnum2::Foo(true));
+ | ^^^^^^^^^^^^^^^^^^^^^^^^ patterns `Foo(_)` and `Bar` not covered
+ |
+ = help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms
+
+error[E0004]: non-exhaustive patterns: `V1`, `V2`, `V3` and 2 more not covered
+ --> $DIR/match-empty.rs:75:18
+ |
+LL | / enum NonEmptyEnum5 {
+LL | | V1, V2, V3, V4, V5,
+LL | | }
+ | |_- `NonEmptyEnum5` defined here
+...
+LL | match_empty!(NonEmptyEnum5::V1);
+ | ^^^^^^^^^^^^^^^^^ patterns `V1`, `V2`, `V3` and 2 more not covered
+ |
+ = help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms
+
+error[E0004]: non-exhaustive patterns: `_` not covered
+ --> $DIR/match-empty.rs:78:18
+ |
+LL | match_false!(0u8);
+ | ^^^ pattern `_` not covered
+ |
+ = help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms
+
+error[E0004]: non-exhaustive patterns: `NonEmptyStruct(_)` not covered
+ --> $DIR/match-empty.rs:80:18
+ |
+LL | struct NonEmptyStruct(bool);
+ | ---------------------------- `NonEmptyStruct` defined here
+...
+LL | match_false!(NonEmptyStruct(true));
+ | ^^^^^^^^^^^^^^^^^^^^ pattern `NonEmptyStruct(_)` not covered
+ |
+ = help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms
+
+error[E0004]: non-exhaustive patterns: `NonEmptyUnion1 { .. }` not covered
+ --> $DIR/match-empty.rs:82:18
+ |
+LL | / union NonEmptyUnion1 {
+LL | | foo: (),
+LL | | }
+ | |_- `NonEmptyUnion1` defined here
+...
+LL | match_false!((NonEmptyUnion1 { foo: () }));
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ pattern `NonEmptyUnion1 { .. }` not covered
+ |
+ = help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms
+
+error[E0004]: non-exhaustive patterns: `NonEmptyUnion2 { .. }` not covered
+ --> $DIR/match-empty.rs:84:18
+ |
+LL | / union NonEmptyUnion2 {
+LL | | foo: (),
+LL | | bar: (),
+LL | | }
+ | |_- `NonEmptyUnion2` defined here
+...
+LL | match_false!((NonEmptyUnion2 { foo: () }));
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ pattern `NonEmptyUnion2 { .. }` not covered
+ |
+ = help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms
+
+error[E0004]: non-exhaustive patterns: `Foo(_)` not covered
+ --> $DIR/match-empty.rs:86:18
+ |
+LL | / enum NonEmptyEnum1 {
+LL | | Foo(bool),
+ | | --- not covered
+LL | |
+LL | |
+LL | | }
+ | |_- `NonEmptyEnum1` defined here
+...
+LL | match_false!(NonEmptyEnum1::Foo(true));
+ | ^^^^^^^^^^^^^^^^^^^^^^^^ pattern `Foo(_)` not covered
+ |
+ = help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms
+
+error[E0004]: non-exhaustive patterns: `Foo(_)` and `Bar` not covered
+ --> $DIR/match-empty.rs:88:18
+ |
+LL | / enum NonEmptyEnum2 {
+LL | | Foo(bool),
+ | | --- not covered
+LL | |
+LL | |
+LL | | Bar,
+ | | --- not covered
+LL | |
+LL | |
+LL | | }
+ | |_- `NonEmptyEnum2` defined here
+...
+LL | match_false!(NonEmptyEnum2::Foo(true));
+ | ^^^^^^^^^^^^^^^^^^^^^^^^ patterns `Foo(_)` and `Bar` not covered
+ |
+ = help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms
+
+error[E0004]: non-exhaustive patterns: `V1`, `V2`, `V3` and 2 more not covered
+ --> $DIR/match-empty.rs:90:18
+ |
+LL | / enum NonEmptyEnum5 {
+LL | | V1, V2, V3, V4, V5,
+LL | | }
+ | |_- `NonEmptyEnum5` defined here
+...
+LL | match_false!(NonEmptyEnum5::V1);
+ | ^^^^^^^^^^^^^^^^^ patterns `V1`, `V2`, `V3` and 2 more not covered
+ |
+ = help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms
+
+error: aborting due to 15 previous errors
+
+For more information about this error, try `rustc --explain E0004`.
diff --git a/src/test/ui/print_type_sizes/zero-sized-fields.rs b/src/test/ui/print_type_sizes/zero-sized-fields.rs
new file mode 100644
index 0000000..2ad488e
--- /dev/null
+++ b/src/test/ui/print_type_sizes/zero-sized-fields.rs
@@ -0,0 +1,46 @@
+// compile-flags: -Z print-type-sizes
+// build-pass (FIXME(62277): could be check-pass?)
+
+// At one point, zero-sized fields such as those in this file were causing
+// incorrect output from `-Z print-type-sizes`.
+
+#![feature(start)]
+
+struct S1 {
+ x: u32,
+ y: u32,
+ tag: (),
+}
+
+struct Void();
+struct Empty {}
+
+struct S5<TagW, TagZ> {
+ tagw: TagW,
+ w: u32,
+ unit: (),
+ x: u32,
+ void: Void,
+ y: u32,
+ empty: Empty,
+ z: u32,
+ tagz: TagZ,
+}
+
+#[start]
+fn start(_: isize, _: *const *const u8) -> isize {
+ let _s1: S1 = S1 { x: 0, y: 0, tag: () };
+
+ let _s5: S5<(), Empty> = S5 {
+ tagw: (),
+ w: 1,
+ unit: (),
+ x: 2,
+ void: Void(),
+ y: 3,
+ empty: Empty {},
+ z: 4,
+ tagz: Empty {},
+ };
+ 0
+}
diff --git a/src/test/ui/print_type_sizes/zero-sized-fields.stdout b/src/test/ui/print_type_sizes/zero-sized-fields.stdout
new file mode 100644
index 0000000..72f59c4
--- /dev/null
+++ b/src/test/ui/print_type_sizes/zero-sized-fields.stdout
@@ -0,0 +1,16 @@
+print-type-size type: `S5<(), Empty>`: 16 bytes, alignment: 4 bytes
+print-type-size field `.tagw`: 0 bytes
+print-type-size field `.unit`: 0 bytes
+print-type-size field `.void`: 0 bytes
+print-type-size field `.empty`: 0 bytes
+print-type-size field `.tagz`: 0 bytes
+print-type-size field `.w`: 4 bytes
+print-type-size field `.x`: 4 bytes
+print-type-size field `.y`: 4 bytes
+print-type-size field `.z`: 4 bytes
+print-type-size type: `S1`: 8 bytes, alignment: 4 bytes
+print-type-size field `.tag`: 0 bytes
+print-type-size field `.x`: 4 bytes
+print-type-size field `.y`: 4 bytes
+print-type-size type: `Empty`: 0 bytes, alignment: 1 bytes
+print-type-size type: `Void`: 0 bytes, alignment: 1 bytes
diff --git a/src/test/ui/privacy/pub-priv-dep/pub-priv1.rs b/src/test/ui/privacy/pub-priv-dep/pub-priv1.rs
index 7846153..feab72b 100644
--- a/src/test/ui/privacy/pub-priv-dep/pub-priv1.rs
+++ b/src/test/ui/privacy/pub-priv-dep/pub-priv1.rs
@@ -1,11 +1,10 @@
- // aux-build:priv_dep.rs
+ // aux-crate:priv:priv_dep=priv_dep.rs
// aux-build:pub_dep.rs
- // extern-private:priv_dep
#![deny(exported_private_dependencies)]
// This crate is a private dependency
extern crate priv_dep;
-// This crate is a public dependenct
+// This crate is a public dependency
extern crate pub_dep;
use priv_dep::{OtherType, OtherTrait};
diff --git a/src/test/ui/privacy/pub-priv-dep/pub-priv1.stderr b/src/test/ui/privacy/pub-priv-dep/pub-priv1.stderr
index b31efdb..f21b11f 100644
--- a/src/test/ui/privacy/pub-priv-dep/pub-priv1.stderr
+++ b/src/test/ui/privacy/pub-priv-dep/pub-priv1.stderr
@@ -1,23 +1,23 @@
error: type `priv_dep::OtherType` from private dependency 'priv_dep' in public interface
- --> $DIR/pub-priv1.rs:21:5
+ --> $DIR/pub-priv1.rs:20:5
|
LL | pub field: OtherType,
| ^^^^^^^^^^^^^^^^^^^^
|
note: lint level defined here
- --> $DIR/pub-priv1.rs:4:9
+ --> $DIR/pub-priv1.rs:3:9
|
LL | #![deny(exported_private_dependencies)]
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
error: type `priv_dep::OtherType` from private dependency 'priv_dep' in public interface
- --> $DIR/pub-priv1.rs:28:5
+ --> $DIR/pub-priv1.rs:27:5
|
LL | pub fn pub_fn(param: OtherType) {}
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
error: trait `priv_dep::OtherTrait` from private dependency 'priv_dep' in public interface
- --> $DIR/pub-priv1.rs:34:1
+ --> $DIR/pub-priv1.rs:33:1
|
LL | / pub trait MyPubTrait {
LL | | type Foo: OtherTrait;
diff --git a/src/test/ui/proc-macro/span-preservation.stderr b/src/test/ui/proc-macro/span-preservation.stderr
index cd6f0ea..a77e920 100644
--- a/src/test/ui/proc-macro/span-preservation.stderr
+++ b/src/test/ui/proc-macro/span-preservation.stderr
@@ -14,6 +14,11 @@
LL | match x {
LL | Some(x) => { return x },
| ^ expected `usize`, found `isize`
+ |
+help: you can convert an `isize` to `usize` and panic if the converted value wouldn't fit
+ |
+LL | Some(x) => { return x.try_into().unwrap() },
+ | ^^^^^^^^^^^^^^^^^^^^^
error[E0308]: mismatched types
--> $DIR/span-preservation.rs:33:22
diff --git a/src/test/ui/question-mark-type-infer.rs b/src/test/ui/question-mark-type-infer.rs
index 95ee01a..2ef8618 100644
--- a/src/test/ui/question-mark-type-infer.rs
+++ b/src/test/ui/question-mark-type-infer.rs
@@ -9,7 +9,7 @@
fn g() -> Result<Vec<i32>, ()> {
let l = [1, 2, 3, 4];
- l.iter().map(f).collect()? //~ ERROR type annotations needed: cannot resolve
+ l.iter().map(f).collect()? //~ ERROR type annotations needed
}
fn main() {
diff --git a/src/test/ui/question-mark-type-infer.stderr b/src/test/ui/question-mark-type-infer.stderr
index 53a170e..7911701 100644
--- a/src/test/ui/question-mark-type-infer.stderr
+++ b/src/test/ui/question-mark-type-infer.stderr
@@ -1,8 +1,13 @@
-error[E0284]: type annotations needed: cannot resolve `<_ as std::ops::Try>::Ok == _`
- --> $DIR/question-mark-type-infer.rs:12:5
+error[E0284]: type annotations needed
+ --> $DIR/question-mark-type-infer.rs:12:21
|
LL | l.iter().map(f).collect()?
- | ^^^^^^^^^^^^^^^^^^^^^^^^^^
+ | ^^^^^^^
+ | |
+ | cannot infer type
+ | help: consider specifying the type argument in the method call: `collect::<B>`
+ |
+ = note: cannot resolve `<_ as std::ops::Try>::Ok == _`
error: aborting due to previous error
diff --git a/src/test/ui/regions/region-object-lifetime-in-coercion.stderr b/src/test/ui/regions/region-object-lifetime-in-coercion.stderr
index 14934d6..e889651 100644
--- a/src/test/ui/regions/region-object-lifetime-in-coercion.stderr
+++ b/src/test/ui/regions/region-object-lifetime-in-coercion.stderr
@@ -34,17 +34,25 @@
|
LL | fn d<'a,'b>(v: &'a [u8]) -> Box<dyn Foo+'b> {
| ^^
- = note: ...so that the expression is assignable:
- expected &[u8]
- found &'a [u8]
+note: ...so that the expression is assignable
+ --> $DIR/region-object-lifetime-in-coercion.rs:26:14
+ |
+LL | Box::new(v)
+ | ^
+ = note: expected `&[u8]`
+ found `&'a [u8]`
note: but, the lifetime must be valid for the lifetime `'b` as defined on the function body at 25:9...
--> $DIR/region-object-lifetime-in-coercion.rs:25:9
|
LL | fn d<'a,'b>(v: &'a [u8]) -> Box<dyn Foo+'b> {
| ^^
- = note: ...so that the expression is assignable:
- expected std::boxed::Box<(dyn Foo + 'b)>
- found std::boxed::Box<dyn Foo>
+note: ...so that the expression is assignable
+ --> $DIR/region-object-lifetime-in-coercion.rs:26:5
+ |
+LL | Box::new(v)
+ | ^^^^^^^^^^^
+ = note: expected `std::boxed::Box<(dyn Foo + 'b)>`
+ found `std::boxed::Box<dyn Foo>`
error: aborting due to 4 previous errors
diff --git a/src/test/ui/regions/regions-assoc-type-region-bound-in-trait-not-met.stderr b/src/test/ui/regions/regions-assoc-type-region-bound-in-trait-not-met.stderr
index a636c9e..865e967 100644
--- a/src/test/ui/regions/regions-assoc-type-region-bound-in-trait-not-met.stderr
+++ b/src/test/ui/regions/regions-assoc-type-region-bound-in-trait-not-met.stderr
@@ -9,9 +9,13 @@
|
LL | impl<'a> Foo<'static> for &'a i32 {
| ^^
- = note: ...so that the types are compatible:
- expected Foo<'static>
- found Foo<'static>
+note: ...so that the types are compatible
+ --> $DIR/regions-assoc-type-region-bound-in-trait-not-met.rs:14:10
+ |
+LL | impl<'a> Foo<'static> for &'a i32 {
+ | ^^^^^^^^^^^^
+ = note: expected `Foo<'static>`
+ found `Foo<'static>`
= note: but, the lifetime must be valid for the static lifetime...
note: ...so that the type `&i32` will meet its required lifetime bounds
--> $DIR/regions-assoc-type-region-bound-in-trait-not-met.rs:14:10
@@ -30,9 +34,13 @@
|
LL | impl<'a,'b> Foo<'b> for &'a i64 {
| ^^
- = note: ...so that the types are compatible:
- expected Foo<'b>
- found Foo<'_>
+note: ...so that the types are compatible
+ --> $DIR/regions-assoc-type-region-bound-in-trait-not-met.rs:19:13
+ |
+LL | impl<'a,'b> Foo<'b> for &'a i64 {
+ | ^^^^^^^
+ = note: expected `Foo<'b>`
+ found `Foo<'_>`
note: but, the lifetime must be valid for the lifetime `'b` as defined on the impl at 19:9...
--> $DIR/regions-assoc-type-region-bound-in-trait-not-met.rs:19:9
|
diff --git a/src/test/ui/regions/regions-assoc-type-static-bound-in-trait-not-met.stderr b/src/test/ui/regions/regions-assoc-type-static-bound-in-trait-not-met.stderr
index 81256e3..6a34871 100644
--- a/src/test/ui/regions/regions-assoc-type-static-bound-in-trait-not-met.stderr
+++ b/src/test/ui/regions/regions-assoc-type-static-bound-in-trait-not-met.stderr
@@ -9,9 +9,13 @@
|
LL | impl<'a> Foo for &'a i32 {
| ^^
- = note: ...so that the types are compatible:
- expected Foo
- found Foo
+note: ...so that the types are compatible
+ --> $DIR/regions-assoc-type-static-bound-in-trait-not-met.rs:9:10
+ |
+LL | impl<'a> Foo for &'a i32 {
+ | ^^^
+ = note: expected `Foo`
+ found `Foo`
= note: but, the lifetime must be valid for the static lifetime...
note: ...so that the type `&i32` will meet its required lifetime bounds
--> $DIR/regions-assoc-type-static-bound-in-trait-not-met.rs:9:10
diff --git a/src/test/ui/regions/regions-close-object-into-object-2.stderr b/src/test/ui/regions/regions-close-object-into-object-2.stderr
index 8e473da..28873ab 100644
--- a/src/test/ui/regions/regions-close-object-into-object-2.stderr
+++ b/src/test/ui/regions/regions-close-object-into-object-2.stderr
@@ -15,9 +15,13 @@
LL | box B(&*v) as Box<dyn X>
| ^^^
= note: but, the lifetime must be valid for the static lifetime...
- = note: ...so that the expression is assignable:
- expected std::boxed::Box<(dyn X + 'static)>
- found std::boxed::Box<dyn X>
+note: ...so that the expression is assignable
+ --> $DIR/regions-close-object-into-object-2.rs:10:5
+ |
+LL | box B(&*v) as Box<dyn X>
+ | ^^^^^^^^^^^^^^^^^^^^^^^^
+ = note: expected `std::boxed::Box<(dyn X + 'static)>`
+ found `std::boxed::Box<dyn X>`
error: aborting due to previous error
diff --git a/src/test/ui/regions/regions-close-object-into-object-4.stderr b/src/test/ui/regions/regions-close-object-into-object-4.stderr
index c80d13e..449a5b5 100644
--- a/src/test/ui/regions/regions-close-object-into-object-4.stderr
+++ b/src/test/ui/regions/regions-close-object-into-object-4.stderr
@@ -15,9 +15,13 @@
LL | box B(&*v) as Box<dyn X>
| ^^^
= note: but, the lifetime must be valid for the static lifetime...
- = note: ...so that the expression is assignable:
- expected std::boxed::Box<(dyn X + 'static)>
- found std::boxed::Box<dyn X>
+note: ...so that the expression is assignable
+ --> $DIR/regions-close-object-into-object-4.rs:10:5
+ |
+LL | box B(&*v) as Box<dyn X>
+ | ^^^^^^^^^^^^^^^^^^^^^^^^
+ = note: expected `std::boxed::Box<(dyn X + 'static)>`
+ found `std::boxed::Box<dyn X>`
error: aborting due to previous error
diff --git a/src/test/ui/regions/regions-close-over-type-parameter-multiple.stderr b/src/test/ui/regions/regions-close-over-type-parameter-multiple.stderr
index ef21316..b2a7afa 100644
--- a/src/test/ui/regions/regions-close-over-type-parameter-multiple.stderr
+++ b/src/test/ui/regions/regions-close-over-type-parameter-multiple.stderr
@@ -19,9 +19,13 @@
|
LL | fn make_object_bad<'a,'b,'c,A:SomeTrait+'a+'b>(v: A) -> Box<dyn SomeTrait + 'c> {
| ^^
- = note: ...so that the expression is assignable:
- expected std::boxed::Box<(dyn SomeTrait + 'c)>
- found std::boxed::Box<dyn SomeTrait>
+note: ...so that the expression is assignable
+ --> $DIR/regions-close-over-type-parameter-multiple.rs:20:5
+ |
+LL | box v as Box<dyn SomeTrait + 'a>
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+ = note: expected `std::boxed::Box<(dyn SomeTrait + 'c)>`
+ found `std::boxed::Box<dyn SomeTrait>`
error: aborting due to previous error
diff --git a/src/test/ui/regions/regions-creating-enums4.stderr b/src/test/ui/regions/regions-creating-enums4.stderr
index 12b8978..58f74e4 100644
--- a/src/test/ui/regions/regions-creating-enums4.stderr
+++ b/src/test/ui/regions/regions-creating-enums4.stderr
@@ -9,17 +9,25 @@
|
LL | fn mk_add_bad2<'a,'b>(x: &'a Ast<'a>, y: &'a Ast<'a>, z: &Ast) -> Ast<'b> {
| ^^
- = note: ...so that the expression is assignable:
- expected &Ast<'_>
- found &Ast<'a>
+note: ...so that the expression is assignable
+ --> $DIR/regions-creating-enums4.rs:7:14
+ |
+LL | Ast::Add(x, y)
+ | ^
+ = note: expected `&Ast<'_>`
+ found `&Ast<'a>`
note: but, the lifetime must be valid for the lifetime `'b` as defined on the function body at 6:19...
--> $DIR/regions-creating-enums4.rs:6:19
|
LL | fn mk_add_bad2<'a,'b>(x: &'a Ast<'a>, y: &'a Ast<'a>, z: &Ast) -> Ast<'b> {
| ^^
- = note: ...so that the expression is assignable:
- expected Ast<'b>
- found Ast<'_>
+note: ...so that the expression is assignable
+ --> $DIR/regions-creating-enums4.rs:7:5
+ |
+LL | Ast::Add(x, y)
+ | ^^^^^^^^^^^^^^
+ = note: expected `Ast<'b>`
+ found `Ast<'_>`
error: aborting due to previous error
diff --git a/src/test/ui/regions/regions-escape-method.stderr b/src/test/ui/regions/regions-escape-method.stderr
index b93dd0d..ffc2a259 100644
--- a/src/test/ui/regions/regions-escape-method.stderr
+++ b/src/test/ui/regions/regions-escape-method.stderr
@@ -9,9 +9,13 @@
|
LL | s.f(|p| p)
| ^^^^^
- = note: ...so that the expression is assignable:
- expected &i32
- found &i32
+note: ...so that the expression is assignable
+ --> $DIR/regions-escape-method.rs:15:13
+ |
+LL | s.f(|p| p)
+ | ^
+ = note: expected `&i32`
+ found `&i32`
note: but, the lifetime must be valid for the method call at 15:5...
--> $DIR/regions-escape-method.rs:15:5
|
diff --git a/src/test/ui/regions/regions-escape-via-trait-or-not.stderr b/src/test/ui/regions/regions-escape-via-trait-or-not.stderr
index a6b165e..9082346 100644
--- a/src/test/ui/regions/regions-escape-via-trait-or-not.stderr
+++ b/src/test/ui/regions/regions-escape-via-trait-or-not.stderr
@@ -9,9 +9,13 @@
|
LL | with(|o| o)
| ^^^^^
- = note: ...so that the expression is assignable:
- expected &isize
- found &isize
+note: ...so that the expression is assignable
+ --> $DIR/regions-escape-via-trait-or-not.rs:18:14
+ |
+LL | with(|o| o)
+ | ^
+ = note: expected `&isize`
+ found `&isize`
note: but, the lifetime must be valid for the expression at 18:5...
--> $DIR/regions-escape-via-trait-or-not.rs:18:5
|
diff --git a/src/test/ui/regions/regions-nested-fns.stderr b/src/test/ui/regions/regions-nested-fns.stderr
index f4eb5c8..8fce160 100644
--- a/src/test/ui/regions/regions-nested-fns.stderr
+++ b/src/test/ui/regions/regions-nested-fns.stderr
@@ -29,9 +29,18 @@
LL | | return z;
LL | | }));
| |_____^
- = note: ...so that the types are compatible:
- expected &isize
- found &isize
+note: ...so that the types are compatible
+ --> $DIR/regions-nested-fns.rs:13:76
+ |
+LL | ignore::< Box<dyn for<'z> FnMut(&'z isize) -> &'z isize>>(Box::new(|z| {
+ | ____________________________________________________________________________^
+LL | | if false { return x; }
+LL | | if false { return ay; }
+LL | | return z;
+LL | | }));
+ | |_____^
+ = note: expected `&isize`
+ found `&isize`
error[E0312]: lifetime of reference outlives lifetime of borrowed content...
--> $DIR/regions-nested-fns.rs:14:27
diff --git a/src/test/ui/regions/regions-normalize-in-where-clause-list.stderr b/src/test/ui/regions/regions-normalize-in-where-clause-list.stderr
index d29fd80..8a600d2 100644
--- a/src/test/ui/regions/regions-normalize-in-where-clause-list.stderr
+++ b/src/test/ui/regions/regions-normalize-in-where-clause-list.stderr
@@ -17,9 +17,16 @@
|
LL | fn bar<'a, 'b>()
| ^^
- = note: ...so that the types are compatible:
- expected Project<'a, 'b>
- found Project<'_, '_>
+note: ...so that the types are compatible
+ --> $DIR/regions-normalize-in-where-clause-list.rs:22:1
+ |
+LL | / fn bar<'a, 'b>()
+LL | | where <() as Project<'a, 'b>>::Item : Eq
+LL | | {
+LL | | }
+ | |_^
+ = note: expected `Project<'a, 'b>`
+ found `Project<'_, '_>`
error: aborting due to previous error
diff --git a/src/test/ui/regions/regions-ret-borrowed-1.stderr b/src/test/ui/regions/regions-ret-borrowed-1.stderr
index 4907667..2895a0c 100644
--- a/src/test/ui/regions/regions-ret-borrowed-1.stderr
+++ b/src/test/ui/regions/regions-ret-borrowed-1.stderr
@@ -9,9 +9,13 @@
|
LL | with(|o| o)
| ^^^^^
- = note: ...so that the expression is assignable:
- expected &isize
- found &isize
+note: ...so that the expression is assignable
+ --> $DIR/regions-ret-borrowed-1.rs:10:14
+ |
+LL | with(|o| o)
+ | ^
+ = note: expected `&isize`
+ found `&isize`
note: but, the lifetime must be valid for the lifetime `'a` as defined on the function body at 9:14...
--> $DIR/regions-ret-borrowed-1.rs:9:14
|
diff --git a/src/test/ui/regions/regions-ret-borrowed.stderr b/src/test/ui/regions/regions-ret-borrowed.stderr
index eb1ade2..b74f10f 100644
--- a/src/test/ui/regions/regions-ret-borrowed.stderr
+++ b/src/test/ui/regions/regions-ret-borrowed.stderr
@@ -9,9 +9,13 @@
|
LL | with(|o| o)
| ^^^^^
- = note: ...so that the expression is assignable:
- expected &isize
- found &isize
+note: ...so that the expression is assignable
+ --> $DIR/regions-ret-borrowed.rs:13:14
+ |
+LL | with(|o| o)
+ | ^
+ = note: expected `&isize`
+ found `&isize`
note: but, the lifetime must be valid for the lifetime `'a` as defined on the function body at 12:14...
--> $DIR/regions-ret-borrowed.rs:12:14
|
diff --git a/src/test/ui/regions/regions-trait-object-subtyping.stderr b/src/test/ui/regions/regions-trait-object-subtyping.stderr
index ef69f25..58b79d2 100644
--- a/src/test/ui/regions/regions-trait-object-subtyping.stderr
+++ b/src/test/ui/regions/regions-trait-object-subtyping.stderr
@@ -36,9 +36,13 @@
|
LL | fn foo3<'a,'b>(x: &'a mut dyn Dummy) -> &'b mut dyn Dummy {
| ^^
- = note: ...so that the expression is assignable:
- expected &'b mut (dyn Dummy + 'b)
- found &mut (dyn Dummy + 'b)
+note: ...so that the expression is assignable
+ --> $DIR/regions-trait-object-subtyping.rs:15:5
+ |
+LL | x
+ | ^
+ = note: expected `&'b mut (dyn Dummy + 'b)`
+ found `&mut (dyn Dummy + 'b)`
error[E0308]: mismatched types
--> $DIR/regions-trait-object-subtyping.rs:22:5
diff --git a/src/test/ui/reject-specialized-drops-8142.stderr b/src/test/ui/reject-specialized-drops-8142.stderr
index e55f023..527babb 100644
--- a/src/test/ui/reject-specialized-drops-8142.stderr
+++ b/src/test/ui/reject-specialized-drops-8142.stderr
@@ -105,9 +105,13 @@
|
LL | struct W<'l1, 'l2> { x: &'l1 i8, y: &'l2 u8 }
| ^^^
- = note: ...so that the types are compatible:
- expected W<'l1, 'l2>
- found W<'_, '_>
+note: ...so that the types are compatible
+ --> $DIR/reject-specialized-drops-8142.rs:54:1
+ |
+LL | impl<'lw> Drop for W<'lw,'lw> { fn drop(&mut self) { } } // REJECT
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+ = note: expected `W<'l1, 'l2>`
+ found `W<'_, '_>`
error: aborting due to 8 previous errors
diff --git a/src/test/ui/resolve/impl-items-vis-unresolved.rs b/src/test/ui/resolve/impl-items-vis-unresolved.rs
new file mode 100644
index 0000000..9b4fe49
--- /dev/null
+++ b/src/test/ui/resolve/impl-items-vis-unresolved.rs
@@ -0,0 +1,25 @@
+// Visibilities on impl items expanded from macros are resolved (issue #64705).
+
+macro_rules! perftools_inline {
+ ($($item:tt)*) => (
+ $($item)*
+ );
+}
+
+mod state {
+ pub struct RawFloatState;
+ impl RawFloatState {
+ perftools_inline! {
+ pub(super) fn new() {} // OK
+ }
+ }
+}
+
+pub struct RawFloatState;
+impl RawFloatState {
+ perftools_inline! {
+ pub(super) fn new() {} //~ ERROR failed to resolve: there are too many initial `super`s
+ }
+}
+
+fn main() {}
diff --git a/src/test/ui/resolve/impl-items-vis-unresolved.stderr b/src/test/ui/resolve/impl-items-vis-unresolved.stderr
new file mode 100644
index 0000000..8e285e5
--- /dev/null
+++ b/src/test/ui/resolve/impl-items-vis-unresolved.stderr
@@ -0,0 +1,9 @@
+error[E0433]: failed to resolve: there are too many initial `super`s.
+ --> $DIR/impl-items-vis-unresolved.rs:21:13
+ |
+LL | pub(super) fn new() {}
+ | ^^^^^ there are too many initial `super`s.
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0433`.
diff --git a/src/test/ui/rfc-2008-non-exhaustive/auxiliary/enums.rs b/src/test/ui/rfc-2008-non-exhaustive/auxiliary/enums.rs
index bbc25d4..8516baf 100644
--- a/src/test/ui/rfc-2008-non-exhaustive/auxiliary/enums.rs
+++ b/src/test/ui/rfc-2008-non-exhaustive/auxiliary/enums.rs
@@ -6,3 +6,6 @@
Tuple(u32),
Struct { field: u32 }
}
+
+#[non_exhaustive]
+pub enum EmptyNonExhaustiveEnum {}
diff --git a/src/test/ui/rfc-2008-non-exhaustive/enum.rs b/src/test/ui/rfc-2008-non-exhaustive/enum.rs
index 7423a97..802f20b 100644
--- a/src/test/ui/rfc-2008-non-exhaustive/enum.rs
+++ b/src/test/ui/rfc-2008-non-exhaustive/enum.rs
@@ -1,7 +1,14 @@
// aux-build:enums.rs
extern crate enums;
-use enums::NonExhaustiveEnum;
+use enums::{EmptyNonExhaustiveEnum, NonExhaustiveEnum};
+
+fn empty(x: EmptyNonExhaustiveEnum) {
+ match x {} //~ ERROR type `enums::EmptyNonExhaustiveEnum` is non-empty
+ match x {
+ _ => {}, // ok
+ }
+}
fn main() {
let enum_unit = NonExhaustiveEnum::Unit;
@@ -13,6 +20,9 @@
NonExhaustiveEnum::Struct { .. } => "third"
};
+ match enum_unit {};
+ //~^ ERROR non-exhaustive patterns: `_` not covered [E0004]
+
// Everything below this is expected to compile successfully.
let enum_unit = NonExhaustiveEnum::Unit;
diff --git a/src/test/ui/rfc-2008-non-exhaustive/enum.stderr b/src/test/ui/rfc-2008-non-exhaustive/enum.stderr
index b5c1a4e..a2bdcba 100644
--- a/src/test/ui/rfc-2008-non-exhaustive/enum.stderr
+++ b/src/test/ui/rfc-2008-non-exhaustive/enum.stderr
@@ -1,11 +1,27 @@
+error[E0004]: non-exhaustive patterns: type `enums::EmptyNonExhaustiveEnum` is non-empty
+ --> $DIR/enum.rs:7:11
+ |
+LL | match x {}
+ | ^
+ |
+ = help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms
+
error[E0004]: non-exhaustive patterns: `_` not covered
- --> $DIR/enum.rs:9:11
+ --> $DIR/enum.rs:16:11
|
LL | match enum_unit {
| ^^^^^^^^^ pattern `_` not covered
|
= help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms
-error: aborting due to previous error
+error[E0004]: non-exhaustive patterns: `_` not covered
+ --> $DIR/enum.rs:23:11
+ |
+LL | match enum_unit {};
+ | ^^^^^^^^^ pattern `_` not covered
+ |
+ = help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms
+
+error: aborting due to 3 previous errors
For more information about this error, try `rustc --explain E0004`.
diff --git a/src/test/ui/rfc-2008-non-exhaustive/enum_same_crate_empty_match.rs b/src/test/ui/rfc-2008-non-exhaustive/enum_same_crate_empty_match.rs
new file mode 100644
index 0000000..afd6d99
--- /dev/null
+++ b/src/test/ui/rfc-2008-non-exhaustive/enum_same_crate_empty_match.rs
@@ -0,0 +1,37 @@
+#![deny(unreachable_patterns)]
+
+#[non_exhaustive]
+pub enum NonExhaustiveEnum {
+ Unit,
+ //~^ not covered
+ Tuple(u32),
+ //~^ not covered
+ Struct { field: u32 }
+ //~^ not covered
+}
+
+pub enum NormalEnum {
+ Unit,
+ //~^ not covered
+ Tuple(u32),
+ //~^ not covered
+ Struct { field: u32 }
+ //~^ not covered
+}
+
+#[non_exhaustive]
+pub enum EmptyNonExhaustiveEnum {}
+
+fn empty_non_exhaustive(x: EmptyNonExhaustiveEnum) {
+ match x {}
+ match x {
+ _ => {} // not detected as unreachable
+ }
+}
+
+fn main() {
+ match NonExhaustiveEnum::Unit {}
+ //~^ ERROR `Unit`, `Tuple(_)` and `Struct { .. }` not covered [E0004]
+ match NormalEnum::Unit {}
+ //~^ ERROR `Unit`, `Tuple(_)` and `Struct { .. }` not covered [E0004]
+}
diff --git a/src/test/ui/rfc-2008-non-exhaustive/enum_same_crate_empty_match.stderr b/src/test/ui/rfc-2008-non-exhaustive/enum_same_crate_empty_match.stderr
new file mode 100644
index 0000000..a99a690
--- /dev/null
+++ b/src/test/ui/rfc-2008-non-exhaustive/enum_same_crate_empty_match.stderr
@@ -0,0 +1,45 @@
+error[E0004]: non-exhaustive patterns: `Unit`, `Tuple(_)` and `Struct { .. }` not covered
+ --> $DIR/enum_same_crate_empty_match.rs:33:11
+ |
+LL | / pub enum NonExhaustiveEnum {
+LL | | Unit,
+ | | ---- not covered
+LL | |
+LL | | Tuple(u32),
+ | | ----- not covered
+LL | |
+LL | | Struct { field: u32 }
+ | | ------ not covered
+LL | |
+LL | | }
+ | |_- `NonExhaustiveEnum` defined here
+...
+LL | match NonExhaustiveEnum::Unit {}
+ | ^^^^^^^^^^^^^^^^^^^^^^^ patterns `Unit`, `Tuple(_)` and `Struct { .. }` not covered
+ |
+ = help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms
+
+error[E0004]: non-exhaustive patterns: `Unit`, `Tuple(_)` and `Struct { .. }` not covered
+ --> $DIR/enum_same_crate_empty_match.rs:35:11
+ |
+LL | / pub enum NormalEnum {
+LL | | Unit,
+ | | ---- not covered
+LL | |
+LL | | Tuple(u32),
+ | | ----- not covered
+LL | |
+LL | | Struct { field: u32 }
+ | | ------ not covered
+LL | |
+LL | | }
+ | |_- `NormalEnum` defined here
+...
+LL | match NormalEnum::Unit {}
+ | ^^^^^^^^^^^^^^^^ patterns `Unit`, `Tuple(_)` and `Struct { .. }` not covered
+ |
+ = help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms
+
+error: aborting due to 2 previous errors
+
+For more information about this error, try `rustc --explain E0004`.
diff --git a/src/test/ui/rfc-2008-non-exhaustive/uninhabited/indirect_match.stderr b/src/test/ui/rfc-2008-non-exhaustive/uninhabited/indirect_match.stderr
index b903e9b..0d669a9a 100644
--- a/src/test/ui/rfc-2008-non-exhaustive/uninhabited/indirect_match.stderr
+++ b/src/test/ui/rfc-2008-non-exhaustive/uninhabited/indirect_match.stderr
@@ -1,4 +1,4 @@
-error[E0004]: non-exhaustive patterns: pattern `IndirectUninhabitedEnum` of type `uninhabited::IndirectUninhabitedEnum` is not handled
+error[E0004]: non-exhaustive patterns: type `uninhabited::IndirectUninhabitedEnum` is non-empty
--> $DIR/indirect_match.rs:18:11
|
LL | match x {}
@@ -6,7 +6,7 @@
|
= help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms
-error[E0004]: non-exhaustive patterns: pattern `IndirectUninhabitedStruct` of type `uninhabited::IndirectUninhabitedStruct` is not handled
+error[E0004]: non-exhaustive patterns: type `uninhabited::IndirectUninhabitedStruct` is non-empty
--> $DIR/indirect_match.rs:22:11
|
LL | match x {}
@@ -14,7 +14,7 @@
|
= help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms
-error[E0004]: non-exhaustive patterns: pattern `IndirectUninhabitedTupleStruct` of type `uninhabited::IndirectUninhabitedTupleStruct` is not handled
+error[E0004]: non-exhaustive patterns: type `uninhabited::IndirectUninhabitedTupleStruct` is non-empty
--> $DIR/indirect_match.rs:26:11
|
LL | match x {}
@@ -22,7 +22,7 @@
|
= help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms
-error[E0004]: non-exhaustive patterns: pattern `IndirectUninhabitedVariants` of type `uninhabited::IndirectUninhabitedVariants` is not handled
+error[E0004]: non-exhaustive patterns: type `uninhabited::IndirectUninhabitedVariants` is non-empty
--> $DIR/indirect_match.rs:32:11
|
LL | match x {}
diff --git a/src/test/ui/rfc-2008-non-exhaustive/uninhabited/indirect_match_same_crate.stderr b/src/test/ui/rfc-2008-non-exhaustive/uninhabited/indirect_match_same_crate.stderr
index f94616d..41a37cf 100644
--- a/src/test/ui/rfc-2008-non-exhaustive/uninhabited/indirect_match_same_crate.stderr
+++ b/src/test/ui/rfc-2008-non-exhaustive/uninhabited/indirect_match_same_crate.stderr
@@ -1,53 +1,41 @@
-error[E0004]: non-exhaustive patterns: pattern `IndirectUninhabitedEnum` of type `IndirectUninhabitedEnum` is not handled
+error[E0004]: non-exhaustive patterns: type `IndirectUninhabitedEnum` is non-empty
--> $DIR/indirect_match_same_crate.rs:32:11
|
LL | pub struct IndirectUninhabitedEnum(UninhabitedEnum);
- | ----------------------------------------------------
- | | |
- | | variant not covered
- | `IndirectUninhabitedEnum` defined here
+ | ---------------------------------------------------- `IndirectUninhabitedEnum` defined here
...
LL | match x {}
| ^
|
= help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms
-error[E0004]: non-exhaustive patterns: pattern `IndirectUninhabitedStruct` of type `IndirectUninhabitedStruct` is not handled
+error[E0004]: non-exhaustive patterns: type `IndirectUninhabitedStruct` is non-empty
--> $DIR/indirect_match_same_crate.rs:36:11
|
LL | pub struct IndirectUninhabitedStruct(UninhabitedStruct);
- | --------------------------------------------------------
- | | |
- | | variant not covered
- | `IndirectUninhabitedStruct` defined here
+ | -------------------------------------------------------- `IndirectUninhabitedStruct` defined here
...
LL | match x {}
| ^
|
= help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms
-error[E0004]: non-exhaustive patterns: pattern `IndirectUninhabitedTupleStruct` of type `IndirectUninhabitedTupleStruct` is not handled
+error[E0004]: non-exhaustive patterns: type `IndirectUninhabitedTupleStruct` is non-empty
--> $DIR/indirect_match_same_crate.rs:40:11
|
LL | pub struct IndirectUninhabitedTupleStruct(UninhabitedTupleStruct);
- | ------------------------------------------------------------------
- | | |
- | | variant not covered
- | `IndirectUninhabitedTupleStruct` defined here
+ | ------------------------------------------------------------------ `IndirectUninhabitedTupleStruct` defined here
...
LL | match x {}
| ^
|
= help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms
-error[E0004]: non-exhaustive patterns: pattern `IndirectUninhabitedVariants` of type `IndirectUninhabitedVariants` is not handled
+error[E0004]: non-exhaustive patterns: type `IndirectUninhabitedVariants` is non-empty
--> $DIR/indirect_match_same_crate.rs:46:11
|
LL | pub struct IndirectUninhabitedVariants(UninhabitedVariants);
- | ------------------------------------------------------------
- | | |
- | | variant not covered
- | `IndirectUninhabitedVariants` defined here
+ | ------------------------------------------------------------ `IndirectUninhabitedVariants` defined here
...
LL | match x {}
| ^
diff --git a/src/test/ui/rfc-2008-non-exhaustive/uninhabited/match.stderr b/src/test/ui/rfc-2008-non-exhaustive/uninhabited/match.stderr
index de3fa90..10a456a 100644
--- a/src/test/ui/rfc-2008-non-exhaustive/uninhabited/match.stderr
+++ b/src/test/ui/rfc-2008-non-exhaustive/uninhabited/match.stderr
@@ -6,7 +6,7 @@
|
= help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms
-error[E0004]: non-exhaustive patterns: pattern `UninhabitedStruct` of type `uninhabited::UninhabitedStruct` is not handled
+error[E0004]: non-exhaustive patterns: type `uninhabited::UninhabitedStruct` is non-empty
--> $DIR/match.rs:22:11
|
LL | match x {}
@@ -14,7 +14,7 @@
|
= help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms
-error[E0004]: non-exhaustive patterns: pattern `UninhabitedTupleStruct` of type `uninhabited::UninhabitedTupleStruct` is not handled
+error[E0004]: non-exhaustive patterns: type `uninhabited::UninhabitedTupleStruct` is non-empty
--> $DIR/match.rs:26:11
|
LL | match x {}
@@ -22,11 +22,11 @@
|
= help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms
-error[E0004]: non-exhaustive patterns: multiple patterns of type `uninhabited::UninhabitedVariants` are not handled
+error[E0004]: non-exhaustive patterns: `Tuple(_)` and `Struct { .. }` not covered
--> $DIR/match.rs:30:11
|
LL | match x {}
- | ^
+ | ^ patterns `Tuple(_)` and `Struct { .. }` not covered
|
= help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms
diff --git a/src/test/ui/rfc-2008-non-exhaustive/uninhabited/match_same_crate.stderr b/src/test/ui/rfc-2008-non-exhaustive/uninhabited/match_same_crate.stderr
index 3dd1a91..148af8c 100644
--- a/src/test/ui/rfc-2008-non-exhaustive/uninhabited/match_same_crate.stderr
+++ b/src/test/ui/rfc-2008-non-exhaustive/uninhabited/match_same_crate.stderr
@@ -1,10 +1,7 @@
-error[E0004]: non-exhaustive patterns: pattern `UninhabitedStruct` of type `UninhabitedStruct` is not handled
+error[E0004]: non-exhaustive patterns: type `UninhabitedStruct` is non-empty
--> $DIR/match_same_crate.rs:28:11
|
-LL | pub struct UninhabitedStruct {
- | - ----------------- variant not covered
- | _|
- | |
+LL | / pub struct UninhabitedStruct {
LL | | _priv: !,
LL | | }
| |_- `UninhabitedStruct` defined here
@@ -14,33 +11,30 @@
|
= help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms
-error[E0004]: non-exhaustive patterns: pattern `UninhabitedTupleStruct` of type `UninhabitedTupleStruct` is not handled
+error[E0004]: non-exhaustive patterns: type `UninhabitedTupleStruct` is non-empty
--> $DIR/match_same_crate.rs:32:11
|
LL | pub struct UninhabitedTupleStruct(!);
- | -------------------------------------
- | | |
- | | variant not covered
- | `UninhabitedTupleStruct` defined here
+ | ------------------------------------- `UninhabitedTupleStruct` defined here
...
LL | match x {}
| ^
|
= help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms
-error[E0004]: non-exhaustive patterns: multiple patterns of type `UninhabitedVariants` are not handled
+error[E0004]: non-exhaustive patterns: `Tuple(_)` and `Struct { .. }` not covered
--> $DIR/match_same_crate.rs:36:11
|
LL | / pub enum UninhabitedVariants {
LL | | #[non_exhaustive] Tuple(!),
- | | ----- variant not covered
+ | | ----- not covered
LL | | #[non_exhaustive] Struct { x: ! }
- | | ------ variant not covered
+ | | ------ not covered
LL | | }
| |_- `UninhabitedVariants` defined here
...
LL | match x {}
- | ^
+ | ^ patterns `Tuple(_)` and `Struct { .. }` not covered
|
= help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms
diff --git a/src/test/ui/rfc-2008-non-exhaustive/uninhabited/match_with_exhaustive_patterns.stderr b/src/test/ui/rfc-2008-non-exhaustive/uninhabited/match_with_exhaustive_patterns.stderr
index 3b56c68..2fc09c8 100644
--- a/src/test/ui/rfc-2008-non-exhaustive/uninhabited/match_with_exhaustive_patterns.stderr
+++ b/src/test/ui/rfc-2008-non-exhaustive/uninhabited/match_with_exhaustive_patterns.stderr
@@ -22,11 +22,11 @@
|
= help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms
-error[E0004]: non-exhaustive patterns: type `uninhabited::UninhabitedVariants` is non-empty
+error[E0004]: non-exhaustive patterns: `Tuple(_)` and `Struct { .. }` not covered
--> $DIR/match_with_exhaustive_patterns.rs:33:11
|
LL | match x {}
- | ^
+ | ^ patterns `Tuple(_)` and `Struct { .. }` not covered
|
= help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms
diff --git a/src/test/ui/rfc-2091-track-caller/caller-location-intrinsic.rs b/src/test/ui/rfc-2091-track-caller/caller-location-intrinsic.rs
index 1c4d466..0a79aea 100644
--- a/src/test/ui/rfc-2091-track-caller/caller-location-intrinsic.rs
+++ b/src/test/ui/rfc-2091-track-caller/caller-location-intrinsic.rs
@@ -1,21 +1,27 @@
// run-pass
-#![feature(core_intrinsics)]
+#![feature(track_caller)]
+
+#[inline(never)]
+#[track_caller]
+fn defeat_const_prop() -> &'static core::panic::Location<'static> {
+ core::panic::Location::caller()
+}
macro_rules! caller_location_from_macro {
- () => (core::intrinsics::caller_location());
+ () => (defeat_const_prop());
}
fn main() {
- let loc = core::intrinsics::caller_location();
+ let loc = defeat_const_prop();
assert_eq!(loc.file(), file!());
- assert_eq!(loc.line(), 10);
+ assert_eq!(loc.line(), 16);
assert_eq!(loc.column(), 15);
- // `caller_location()` in a macro should behave similarly to `file!` and `line!`,
+ // `Location::caller()` in a macro should behave similarly to `file!` and `line!`,
// i.e. point to where the macro was invoked, instead of the macro itself.
let loc2 = caller_location_from_macro!();
assert_eq!(loc2.file(), file!());
- assert_eq!(loc2.line(), 17);
+ assert_eq!(loc2.line(), 23);
assert_eq!(loc2.column(), 16);
}
diff --git a/src/test/ui/rfc-2091-track-caller/const-caller-location.rs b/src/test/ui/rfc-2091-track-caller/const-caller-location.rs
new file mode 100644
index 0000000..0614c52
--- /dev/null
+++ b/src/test/ui/rfc-2091-track-caller/const-caller-location.rs
@@ -0,0 +1,41 @@
+// run-pass
+
+#![feature(const_fn, track_caller)]
+
+use std::panic::Location;
+
+const LOCATION: &Location = Location::caller();
+
+const TRACKED: &Location = tracked();
+#[track_caller]
+const fn tracked() -> &'static Location <'static> {
+ Location::caller()
+}
+
+const NESTED: &Location = nested_location();
+const fn nested_location() -> &'static Location<'static> {
+ Location::caller()
+}
+
+const CONTAINED: &Location = contained();
+const fn contained() -> &'static Location<'static> {
+ tracked()
+}
+
+fn main() {
+ assert_eq!(LOCATION.file(), file!());
+ assert_eq!(LOCATION.line(), 7);
+ assert_eq!(LOCATION.column(), 29);
+
+ assert_eq!(TRACKED.file(), file!());
+ assert_eq!(TRACKED.line(), 9);
+ assert_eq!(TRACKED.column(), 28);
+
+ assert_eq!(NESTED.file(), file!());
+ assert_eq!(NESTED.line(), 17);
+ assert_eq!(NESTED.column(), 5);
+
+ assert_eq!(CONTAINED.file(), file!());
+ assert_eq!(CONTAINED.line(), 22);
+ assert_eq!(CONTAINED.column(), 5);
+}
diff --git a/src/test/ui/rfc-2091-track-caller/error-odd-syntax.rs b/src/test/ui/rfc-2091-track-caller/error-odd-syntax.rs
index d400db8..d656023 100644
--- a/src/test/ui/rfc-2091-track-caller/error-odd-syntax.rs
+++ b/src/test/ui/rfc-2091-track-caller/error-odd-syntax.rs
@@ -1,4 +1,4 @@
-#![feature(track_caller)] //~ WARN the feature `track_caller` is incomplete
+#![feature(track_caller)]
#[track_caller(1)]
fn f() {}
diff --git a/src/test/ui/rfc-2091-track-caller/error-odd-syntax.stderr b/src/test/ui/rfc-2091-track-caller/error-odd-syntax.stderr
index a53a8ee..8906fa5 100644
--- a/src/test/ui/rfc-2091-track-caller/error-odd-syntax.stderr
+++ b/src/test/ui/rfc-2091-track-caller/error-odd-syntax.stderr
@@ -4,13 +4,5 @@
LL | #[track_caller(1)]
| ^^^^^^^^^^^^^^^^^^ help: must be of the form: `#[track_caller]`
-warning: the feature `track_caller` is incomplete and may cause the compiler to crash
- --> $DIR/error-odd-syntax.rs:1:12
- |
-LL | #![feature(track_caller)]
- | ^^^^^^^^^^^^
- |
- = note: `#[warn(incomplete_features)]` on by default
-
error: aborting due to previous error
diff --git a/src/test/ui/rfc-2091-track-caller/error-with-invalid-abi.rs b/src/test/ui/rfc-2091-track-caller/error-with-invalid-abi.rs
index 162c638..20d2961 100644
--- a/src/test/ui/rfc-2091-track-caller/error-with-invalid-abi.rs
+++ b/src/test/ui/rfc-2091-track-caller/error-with-invalid-abi.rs
@@ -1,6 +1,7 @@
-#![feature(track_caller)] //~ WARN the feature `track_caller` is incomplete
+#![feature(track_caller)]
-#[track_caller] //~ ERROR Rust ABI is required to use `#[track_caller]`
+#[track_caller]
extern "C" fn f() {}
+//~^^ ERROR `#[track_caller]` requires Rust ABI
fn main() {}
diff --git a/src/test/ui/rfc-2091-track-caller/error-with-invalid-abi.stderr b/src/test/ui/rfc-2091-track-caller/error-with-invalid-abi.stderr
index ad89b14..2a3a438 100644
--- a/src/test/ui/rfc-2091-track-caller/error-with-invalid-abi.stderr
+++ b/src/test/ui/rfc-2091-track-caller/error-with-invalid-abi.stderr
@@ -1,12 +1,4 @@
-warning: the feature `track_caller` is incomplete and may cause the compiler to crash
- --> $DIR/error-with-invalid-abi.rs:1:12
- |
-LL | #![feature(track_caller)]
- | ^^^^^^^^^^^^
- |
- = note: `#[warn(incomplete_features)]` on by default
-
-error[E0737]: Rust ABI is required to use `#[track_caller]`
+error[E0737]: `#[track_caller]` requires Rust ABI
--> $DIR/error-with-invalid-abi.rs:3:1
|
LL | #[track_caller]
diff --git a/src/test/ui/rfc-2091-track-caller/error-with-naked.rs b/src/test/ui/rfc-2091-track-caller/error-with-naked.rs
index bbbcec3..dd9e5d0 100644
--- a/src/test/ui/rfc-2091-track-caller/error-with-naked.rs
+++ b/src/test/ui/rfc-2091-track-caller/error-with-naked.rs
@@ -1,4 +1,4 @@
-#![feature(naked_functions, track_caller)] //~ WARN the feature `track_caller` is incomplete
+#![feature(naked_functions, track_caller)]
#[track_caller]
#[naked]
diff --git a/src/test/ui/rfc-2091-track-caller/error-with-naked.stderr b/src/test/ui/rfc-2091-track-caller/error-with-naked.stderr
index 93e6f7a..2f5003c 100644
--- a/src/test/ui/rfc-2091-track-caller/error-with-naked.stderr
+++ b/src/test/ui/rfc-2091-track-caller/error-with-naked.stderr
@@ -1,11 +1,3 @@
-warning: the feature `track_caller` is incomplete and may cause the compiler to crash
- --> $DIR/error-with-naked.rs:1:29
- |
-LL | #![feature(naked_functions, track_caller)]
- | ^^^^^^^^^^^^
- |
- = note: `#[warn(incomplete_features)]` on by default
-
error[E0736]: cannot use `#[track_caller]` with `#[naked]`
--> $DIR/error-with-naked.rs:3:1
|
diff --git a/src/test/ui/rfc-2091-track-caller/error-with-trait-decl.rs b/src/test/ui/rfc-2091-track-caller/error-with-trait-decl.rs
index 4fd768d..ef037ab 100644
--- a/src/test/ui/rfc-2091-track-caller/error-with-trait-decl.rs
+++ b/src/test/ui/rfc-2091-track-caller/error-with-trait-decl.rs
@@ -1,4 +1,4 @@
-#![feature(track_caller)] //~ WARN the feature `track_caller` is incomplete
+#![feature(track_caller)]
trait Trait {
#[track_caller] //~ ERROR: `#[track_caller]` may not be used on trait methods
diff --git a/src/test/ui/rfc-2091-track-caller/error-with-trait-decl.stderr b/src/test/ui/rfc-2091-track-caller/error-with-trait-decl.stderr
index 72ed6f8..ded721d 100644
--- a/src/test/ui/rfc-2091-track-caller/error-with-trait-decl.stderr
+++ b/src/test/ui/rfc-2091-track-caller/error-with-trait-decl.stderr
@@ -1,11 +1,3 @@
-warning: the feature `track_caller` is incomplete and may cause the compiler to crash
- --> $DIR/error-with-trait-decl.rs:1:12
- |
-LL | #![feature(track_caller)]
- | ^^^^^^^^^^^^
- |
- = note: `#[warn(incomplete_features)]` on by default
-
error[E0738]: `#[track_caller]` may not be used on trait methods
--> $DIR/error-with-trait-decl.rs:4:5
|
diff --git a/src/test/ui/rfc-2091-track-caller/error-with-trait-default-impl.rs b/src/test/ui/rfc-2091-track-caller/error-with-trait-default-impl.rs
index 2139ba5..17e4bf4 100644
--- a/src/test/ui/rfc-2091-track-caller/error-with-trait-default-impl.rs
+++ b/src/test/ui/rfc-2091-track-caller/error-with-trait-default-impl.rs
@@ -1,4 +1,4 @@
-#![feature(track_caller)] //~ WARN the feature `track_caller` is incomplete
+#![feature(track_caller)]
trait Trait {
#[track_caller] //~ ERROR: `#[track_caller]` may not be used on trait methods
diff --git a/src/test/ui/rfc-2091-track-caller/error-with-trait-default-impl.stderr b/src/test/ui/rfc-2091-track-caller/error-with-trait-default-impl.stderr
index 05689c9..867eb91 100644
--- a/src/test/ui/rfc-2091-track-caller/error-with-trait-default-impl.stderr
+++ b/src/test/ui/rfc-2091-track-caller/error-with-trait-default-impl.stderr
@@ -1,11 +1,3 @@
-warning: the feature `track_caller` is incomplete and may cause the compiler to crash
- --> $DIR/error-with-trait-default-impl.rs:1:12
- |
-LL | #![feature(track_caller)]
- | ^^^^^^^^^^^^
- |
- = note: `#[warn(incomplete_features)]` on by default
-
error[E0738]: `#[track_caller]` may not be used on trait methods
--> $DIR/error-with-trait-default-impl.rs:4:5
|
diff --git a/src/test/ui/rfc-2091-track-caller/error-with-trait-fn-impl.rs b/src/test/ui/rfc-2091-track-caller/error-with-trait-fn-impl.rs
index b565e11..75f20f7 100644
--- a/src/test/ui/rfc-2091-track-caller/error-with-trait-fn-impl.rs
+++ b/src/test/ui/rfc-2091-track-caller/error-with-trait-fn-impl.rs
@@ -1,6 +1,6 @@
// check-fail
-#![feature(track_caller)] //~ WARN the feature `track_caller` is incomplete
+#![feature(track_caller)]
trait Trait {
fn unwrap(&self);
diff --git a/src/test/ui/rfc-2091-track-caller/error-with-trait-fn-impl.stderr b/src/test/ui/rfc-2091-track-caller/error-with-trait-fn-impl.stderr
index 707b367..fafceef 100644
--- a/src/test/ui/rfc-2091-track-caller/error-with-trait-fn-impl.stderr
+++ b/src/test/ui/rfc-2091-track-caller/error-with-trait-fn-impl.stderr
@@ -1,11 +1,3 @@
-warning: the feature `track_caller` is incomplete and may cause the compiler to crash
- --> $DIR/error-with-trait-fn-impl.rs:3:12
- |
-LL | #![feature(track_caller)]
- | ^^^^^^^^^^^^
- |
- = note: `#[warn(incomplete_features)]` on by default
-
error[E0738]: `#[track_caller]` may not be used on trait methods
--> $DIR/error-with-trait-fn-impl.rs:10:5
|
diff --git a/src/test/ui/rfc-2091-track-caller/intrinsic-wrapper.rs b/src/test/ui/rfc-2091-track-caller/intrinsic-wrapper.rs
new file mode 100644
index 0000000..76e62b8
--- /dev/null
+++ b/src/test/ui/rfc-2091-track-caller/intrinsic-wrapper.rs
@@ -0,0 +1,21 @@
+// run-pass
+
+#![feature(track_caller)]
+
+macro_rules! caller_location_from_macro {
+ () => (core::panic::Location::caller());
+}
+
+fn main() {
+ let loc = core::panic::Location::caller();
+ assert_eq!(loc.file(), file!());
+ assert_eq!(loc.line(), 10);
+ assert_eq!(loc.column(), 15);
+
+ // `Location::caller()` in a macro should behave similarly to `file!` and `line!`,
+ // i.e. point to where the macro was invoked, instead of the macro itself.
+ let loc2 = caller_location_from_macro!();
+ assert_eq!(loc2.file(), file!());
+ assert_eq!(loc2.line(), 17);
+ assert_eq!(loc2.column(), 16);
+}
diff --git a/src/test/ui/rfc-2091-track-caller/only-for-fns.rs b/src/test/ui/rfc-2091-track-caller/only-for-fns.rs
index 01ebf13..0fd59b4 100644
--- a/src/test/ui/rfc-2091-track-caller/only-for-fns.rs
+++ b/src/test/ui/rfc-2091-track-caller/only-for-fns.rs
@@ -1,4 +1,4 @@
-#![feature(track_caller)] //~ WARN the feature `track_caller` is incomplete
+#![feature(track_caller)]
#[track_caller]
struct S;
diff --git a/src/test/ui/rfc-2091-track-caller/only-for-fns.stderr b/src/test/ui/rfc-2091-track-caller/only-for-fns.stderr
index 3301da7..7becb9c 100644
--- a/src/test/ui/rfc-2091-track-caller/only-for-fns.stderr
+++ b/src/test/ui/rfc-2091-track-caller/only-for-fns.stderr
@@ -1,11 +1,3 @@
-warning: the feature `track_caller` is incomplete and may cause the compiler to crash
- --> $DIR/only-for-fns.rs:1:12
- |
-LL | #![feature(track_caller)]
- | ^^^^^^^^^^^^
- |
- = note: `#[warn(incomplete_features)]` on by default
-
error[E0739]: attribute should be applied to function
--> $DIR/only-for-fns.rs:3:1
|
diff --git a/src/test/ui/rfc-2091-track-caller/pass.rs b/src/test/ui/rfc-2091-track-caller/pass.rs
index f2c3f0d..eef83b3 100644
--- a/src/test/ui/rfc-2091-track-caller/pass.rs
+++ b/src/test/ui/rfc-2091-track-caller/pass.rs
@@ -1,5 +1,5 @@
// run-pass
-#![feature(track_caller)] //~ WARN the feature `track_caller` is incomplete
+#![feature(track_caller)]
#[track_caller]
fn f() {}
diff --git a/src/test/ui/rfc-2091-track-caller/pass.stderr b/src/test/ui/rfc-2091-track-caller/pass.stderr
deleted file mode 100644
index b1fd23a..0000000
--- a/src/test/ui/rfc-2091-track-caller/pass.stderr
+++ /dev/null
@@ -1,8 +0,0 @@
-warning: the feature `track_caller` is incomplete and may cause the compiler to crash
- --> $DIR/pass.rs:2:12
- |
-LL | #![feature(track_caller)]
- | ^^^^^^^^^^^^
- |
- = note: `#[warn(incomplete_features)]` on by default
-
diff --git a/src/test/ui/rfc-2091-track-caller/track-caller-attribute.rs b/src/test/ui/rfc-2091-track-caller/track-caller-attribute.rs
new file mode 100644
index 0000000..8436ee5
--- /dev/null
+++ b/src/test/ui/rfc-2091-track-caller/track-caller-attribute.rs
@@ -0,0 +1,40 @@
+// run-pass
+
+#![feature(const_fn, track_caller)]
+
+use std::panic::Location;
+
+#[track_caller]
+fn tracked() -> &'static Location<'static> {
+ Location::caller()
+}
+
+fn nested_intrinsic() -> &'static Location<'static> {
+ Location::caller()
+}
+
+fn nested_tracked() -> &'static Location<'static> {
+ tracked()
+}
+
+fn main() {
+ let location = Location::caller();
+ assert_eq!(location.file(), file!());
+ assert_eq!(location.line(), 21);
+ assert_eq!(location.column(), 20);
+
+ let tracked = tracked();
+ assert_eq!(tracked.file(), file!());
+ assert_eq!(tracked.line(), 26);
+ assert_eq!(tracked.column(), 19);
+
+ let nested = nested_intrinsic();
+ assert_eq!(nested.file(), file!());
+ assert_eq!(nested.line(), 13);
+ assert_eq!(nested.column(), 5);
+
+ let contained = nested_tracked();
+ assert_eq!(contained.file(), file!());
+ assert_eq!(contained.line(), 17);
+ assert_eq!(contained.column(), 5);
+}
diff --git a/src/test/ui/self/self-vs-path-ambiguity.stderr b/src/test/ui/self/self-vs-path-ambiguity.stderr
index 5ce6a81..2beef50 100644
--- a/src/test/ui/self/self-vs-path-ambiguity.stderr
+++ b/src/test/ui/self/self-vs-path-ambiguity.stderr
@@ -2,7 +2,7 @@
--> $DIR/self-vs-path-ambiguity.rs:9:11
|
LL | fn i(&'a self::S: &S) {}
- | ^^ unexpected lifetime
+ | ^^ help: remove the lifetime
error: aborting due to previous error
diff --git a/src/test/ui/span/issue-42234-unknown-receiver-type.rs b/src/test/ui/span/issue-42234-unknown-receiver-type.rs
index 58138e2..d3292bb 100644
--- a/src/test/ui/span/issue-42234-unknown-receiver-type.rs
+++ b/src/test/ui/span/issue-42234-unknown-receiver-type.rs
@@ -9,8 +9,8 @@
}
fn courier_to_des_moines_and_points_west(data: &[u32]) -> String {
- data.iter() //~ ERROR type annotations needed
- .sum::<_>()
+ data.iter()
+ .sum::<_>() //~ ERROR type annotations needed
.to_string()
}
diff --git a/src/test/ui/span/issue-42234-unknown-receiver-type.stderr b/src/test/ui/span/issue-42234-unknown-receiver-type.stderr
index 30c9adb..9824d87 100644
--- a/src/test/ui/span/issue-42234-unknown-receiver-type.stderr
+++ b/src/test/ui/span/issue-42234-unknown-receiver-type.stderr
@@ -4,16 +4,15 @@
LL | let x: Option<_> = None;
| - consider giving `x` the explicit type `std::option::Option<_>`, where the type parameter `T` is specified
LL | x.unwrap().method_that_could_exist_on_some_type();
- | ^^^^^^ cannot infer type for `T`
+ | ^^^^^^ cannot infer type for type parameter `T`
|
= note: type must be known at this point
error[E0282]: type annotations needed
- --> $DIR/issue-42234-unknown-receiver-type.rs:12:5
+ --> $DIR/issue-42234-unknown-receiver-type.rs:13:10
|
-LL | / data.iter()
-LL | | .sum::<_>()
- | |___________________^ cannot infer type
+LL | .sum::<_>()
+ | ^^^ cannot infer type
|
= note: type must be known at this point
diff --git a/src/test/ui/span/macro-ty-params.rs b/src/test/ui/span/macro-ty-params.rs
index b077d59..713b9eb 100644
--- a/src/test/ui/span/macro-ty-params.rs
+++ b/src/test/ui/span/macro-ty-params.rs
@@ -10,5 +10,4 @@
foo::<T>!(); //~ ERROR generic arguments in macro path
foo::<>!(); //~ ERROR generic arguments in macro path
m!(Default<>); //~ ERROR generic arguments in macro path
- //~^ ERROR unexpected generic arguments in path
}
diff --git a/src/test/ui/span/macro-ty-params.stderr b/src/test/ui/span/macro-ty-params.stderr
index 39b3edc..21683b2 100644
--- a/src/test/ui/span/macro-ty-params.stderr
+++ b/src/test/ui/span/macro-ty-params.stderr
@@ -10,17 +10,11 @@
LL | foo::<>!();
| ^^
-error: unexpected generic arguments in path
- --> $DIR/macro-ty-params.rs:12:8
- |
-LL | m!(Default<>);
- | ^^^^^^^^^
-
error: generic arguments in macro path
--> $DIR/macro-ty-params.rs:12:15
|
LL | m!(Default<>);
| ^^
-error: aborting due to 4 previous errors
+error: aborting due to 3 previous errors
diff --git a/src/test/ui/span/type-annotations-needed-expr.stderr b/src/test/ui/span/type-annotations-needed-expr.stderr
index e32a542..8366285 100644
--- a/src/test/ui/span/type-annotations-needed-expr.stderr
+++ b/src/test/ui/span/type-annotations-needed-expr.stderr
@@ -2,7 +2,10 @@
--> $DIR/type-annotations-needed-expr.rs:2:39
|
LL | let _ = (vec![1,2,3]).into_iter().sum() as f64;
- | ^^^ cannot infer type for `S`
+ | ^^^
+ | |
+ | cannot infer type for type parameter `S`
+ | help: consider specifying the type argument in the method call: `sum::<S>`
|
= note: type must be known at this point
diff --git a/src/test/ui/suggestions/option-content-move2.rs b/src/test/ui/suggestions/option-content-move2.rs
new file mode 100644
index 0000000..88e8a5b
--- /dev/null
+++ b/src/test/ui/suggestions/option-content-move2.rs
@@ -0,0 +1,16 @@
+struct NotCopyable;
+
+fn func<F: FnMut() -> H, H: FnMut()>(_: F) {}
+
+fn parse() {
+ let mut var = None;
+ func(|| {
+ // Shouldn't suggest `move ||.as_ref()` here
+ move || {
+ //~^ ERROR: cannot move out of `var`
+ var = Some(NotCopyable);
+ }
+ });
+}
+
+fn main() {}
diff --git a/src/test/ui/suggestions/option-content-move2.stderr b/src/test/ui/suggestions/option-content-move2.stderr
new file mode 100644
index 0000000..71f7453
--- /dev/null
+++ b/src/test/ui/suggestions/option-content-move2.stderr
@@ -0,0 +1,18 @@
+error[E0507]: cannot move out of `var`, a captured variable in an `FnMut` closure
+ --> $DIR/option-content-move2.rs:9:9
+ |
+LL | let mut var = None;
+ | ------- captured outer variable
+...
+LL | move || {
+ | ^^^^^^^ move out of `var` occurs here
+LL |
+LL | var = Some(NotCopyable);
+ | ---
+ | |
+ | move occurs because `var` has type `std::option::Option<NotCopyable>`, which does not implement the `Copy` trait
+ | move occurs due to use in closure
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0507`.
diff --git a/src/test/ui/suggestions/raw-name-use-suggestion.rs b/src/test/ui/suggestions/raw-name-use-suggestion.rs
index 6c01383..0a8073c 100644
--- a/src/test/ui/suggestions/raw-name-use-suggestion.rs
+++ b/src/test/ui/suggestions/raw-name-use-suggestion.rs
@@ -5,5 +5,5 @@
fn main() {
foo::let(); //~ ERROR expected identifier, found keyword `let`
- r#break(); //~ ERROR cannot find function `break` in this scope
+ r#break(); //~ ERROR cannot find function `r#break` in this scope
}
diff --git a/src/test/ui/suggestions/raw-name-use-suggestion.stderr b/src/test/ui/suggestions/raw-name-use-suggestion.stderr
index 58eb87c..62b7631 100644
--- a/src/test/ui/suggestions/raw-name-use-suggestion.stderr
+++ b/src/test/ui/suggestions/raw-name-use-suggestion.stderr
@@ -20,7 +20,7 @@
LL | foo::r#let();
| ^^^^^
-error[E0425]: cannot find function `break` in this scope
+error[E0425]: cannot find function `r#break` in this scope
--> $DIR/raw-name-use-suggestion.rs:8:5
|
LL | r#break();
diff --git a/src/test/ui/tail-typeck.stderr b/src/test/ui/tail-typeck.stderr
index eeeb258..69f8ffa 100644
--- a/src/test/ui/tail-typeck.stderr
+++ b/src/test/ui/tail-typeck.stderr
@@ -5,6 +5,11 @@
| ----- ^^^ expected `isize`, found `usize`
| |
| expected `isize` because of return type
+ |
+help: you can convert an `usize` to `isize` and panic if the converted value wouldn't fit
+ |
+LL | fn f() -> isize { return g().try_into().unwrap(); }
+ | ^^^^^^^^^^^^^^^^^^^^^^^
error: aborting due to previous error
diff --git a/src/test/ui/traits/trait-impl-of-supertrait-has-wrong-lifetime-parameters.stderr b/src/test/ui/traits/trait-impl-of-supertrait-has-wrong-lifetime-parameters.stderr
index 88c9c47..9fdcd4d 100644
--- a/src/test/ui/traits/trait-impl-of-supertrait-has-wrong-lifetime-parameters.stderr
+++ b/src/test/ui/traits/trait-impl-of-supertrait-has-wrong-lifetime-parameters.stderr
@@ -14,9 +14,13 @@
|
LL | impl<'a,'b> T2<'a, 'b> for S<'a, 'b> {
| ^^
- = note: ...so that the types are compatible:
- expected T1<'a>
- found T1<'_>
+note: ...so that the types are compatible
+ --> $DIR/trait-impl-of-supertrait-has-wrong-lifetime-parameters.rs:24:13
+ |
+LL | impl<'a,'b> T2<'a, 'b> for S<'a, 'b> {
+ | ^^^^^^^^^^
+ = note: expected `T1<'a>`
+ found `T1<'_>`
error: aborting due to previous error
diff --git a/src/test/ui/traits/trait-static-method-generic-inference.stderr b/src/test/ui/traits/trait-static-method-generic-inference.stderr
index 22931c5..f9718da 100644
--- a/src/test/ui/traits/trait-static-method-generic-inference.stderr
+++ b/src/test/ui/traits/trait-static-method-generic-inference.stderr
@@ -1,11 +1,13 @@
-error[E0283]: type annotations needed: cannot resolve `_: base::HasNew<base::Foo>`
+error[E0283]: type annotations needed
--> $DIR/trait-static-method-generic-inference.rs:24:25
|
LL | fn new() -> T;
| -------------- required by `base::HasNew::new`
...
LL | let _f: base::Foo = base::HasNew::new();
- | ^^^^^^^^^^^^^^^^^
+ | ^^^^^^^^^^^^^^^^^ cannot infer type
+ |
+ = note: cannot resolve `_: base::HasNew<base::Foo>`
error: aborting due to previous error
diff --git a/src/test/ui/traits/traits-multidispatch-convert-ambig-dest.stderr b/src/test/ui/traits/traits-multidispatch-convert-ambig-dest.stderr
index d7d2704..7bcda23 100644
--- a/src/test/ui/traits/traits-multidispatch-convert-ambig-dest.stderr
+++ b/src/test/ui/traits/traits-multidispatch-convert-ambig-dest.stderr
@@ -2,7 +2,7 @@
--> $DIR/traits-multidispatch-convert-ambig-dest.rs:26:5
|
LL | test(22, std::default::Default::default());
- | ^^^^ cannot infer type for `U`
+ | ^^^^ cannot infer type for type parameter `U`
error: aborting due to previous error
diff --git a/src/test/ui/type-alias-impl-trait/bound_reduction2.rs b/src/test/ui/type-alias-impl-trait/bound_reduction2.rs
index 9194468..1becb1e 100644
--- a/src/test/ui/type-alias-impl-trait/bound_reduction2.rs
+++ b/src/test/ui/type-alias-impl-trait/bound_reduction2.rs
@@ -9,6 +9,7 @@
type Foo<V> = impl Trait<V>;
//~^ ERROR could not find defining uses
+//~| ERROR the trait bound `T: TraitWithAssoc` is not satisfied
trait Trait<U> {}
diff --git a/src/test/ui/type-alias-impl-trait/bound_reduction2.stderr b/src/test/ui/type-alias-impl-trait/bound_reduction2.stderr
index bb22d58..1eb4cf2 100644
--- a/src/test/ui/type-alias-impl-trait/bound_reduction2.stderr
+++ b/src/test/ui/type-alias-impl-trait/bound_reduction2.stderr
@@ -1,5 +1,14 @@
+error[E0277]: the trait bound `T: TraitWithAssoc` is not satisfied
+ --> $DIR/bound_reduction2.rs:10:1
+ |
+LL | type Foo<V> = impl Trait<V>;
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ the trait `TraitWithAssoc` is not implemented for `T`
+...
+LL | fn foo_desugared<T: TraitWithAssoc>(_: T) -> Foo<T::Assoc> {
+ | -- help: consider further restricting this bound: `T: TraitWithAssoc +`
+
error: defining opaque type use does not fully define opaque type: generic parameter `V` is specified as concrete type `<T as TraitWithAssoc>::Assoc`
- --> $DIR/bound_reduction2.rs:17:1
+ --> $DIR/bound_reduction2.rs:18:1
|
LL | / fn foo_desugared<T: TraitWithAssoc>(_: T) -> Foo<T::Assoc> {
LL | | ()
@@ -12,5 +21,6 @@
LL | type Foo<V> = impl Trait<V>;
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^
-error: aborting due to 2 previous errors
+error: aborting due to 3 previous errors
+For more information about this error, try `rustc --explain E0277`.
diff --git a/src/test/ui/type-inference/or_else-multiple-type-params.rs b/src/test/ui/type-inference/or_else-multiple-type-params.rs
new file mode 100644
index 0000000..b15de2a
--- /dev/null
+++ b/src/test/ui/type-inference/or_else-multiple-type-params.rs
@@ -0,0 +1,10 @@
+use std::process::{Command, Stdio};
+
+fn main() {
+ let process = Command::new("wc")
+ .stdout(Stdio::piped())
+ .spawn()
+ .or_else(|err| { //~ ERROR type annotations needed
+ panic!("oh no: {:?}", err);
+ }).unwrap();
+}
diff --git a/src/test/ui/type-inference/or_else-multiple-type-params.stderr b/src/test/ui/type-inference/or_else-multiple-type-params.stderr
new file mode 100644
index 0000000..141cc25
--- /dev/null
+++ b/src/test/ui/type-inference/or_else-multiple-type-params.stderr
@@ -0,0 +1,12 @@
+error[E0282]: type annotations needed
+ --> $DIR/or_else-multiple-type-params.rs:7:10
+ |
+LL | .or_else(|err| {
+ | ^^^^^^^
+ | |
+ | cannot infer type for type parameter `F`
+ | help: consider specifying the type arguments in the method call: `or_else::<F, O>`
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0282`.
diff --git a/src/test/ui/type-inference/sort_by_key.rs b/src/test/ui/type-inference/sort_by_key.rs
new file mode 100644
index 0000000..afc4d90
--- /dev/null
+++ b/src/test/ui/type-inference/sort_by_key.rs
@@ -0,0 +1,5 @@
+fn main() {
+ let mut lst: [([i32; 10], bool); 10] = [([0; 10], false); 10];
+ lst.sort_by_key(|&(v, _)| v.iter().sum()); //~ ERROR type annotations needed
+ println!("{:?}", lst);
+}
diff --git a/src/test/ui/type-inference/sort_by_key.stderr b/src/test/ui/type-inference/sort_by_key.stderr
new file mode 100644
index 0000000..1d386bd
--- /dev/null
+++ b/src/test/ui/type-inference/sort_by_key.stderr
@@ -0,0 +1,11 @@
+error[E0282]: type annotations needed
+ --> $DIR/sort_by_key.rs:3:9
+ |
+LL | lst.sort_by_key(|&(v, _)| v.iter().sum());
+ | ^^^^^^^^^^^ --- help: consider specifying the type argument in the method call: `sum::<S>`
+ | |
+ | cannot infer type for type parameter `K`
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0282`.
diff --git a/src/test/ui/type-inference/unbounded-associated-type.rs b/src/test/ui/type-inference/unbounded-associated-type.rs
new file mode 100644
index 0000000..0167e94
--- /dev/null
+++ b/src/test/ui/type-inference/unbounded-associated-type.rs
@@ -0,0 +1,16 @@
+trait T {
+ type A;
+ fn foo(&self) -> Self::A {
+ panic!()
+ }
+}
+
+struct S<X>(std::marker::PhantomData<X>);
+
+impl<X> T for S<X> {
+ type A = X;
+}
+
+fn main() {
+ S(std::marker::PhantomData).foo(); //~ ERROR type annotations needed
+}
diff --git a/src/test/ui/type-inference/unbounded-associated-type.stderr b/src/test/ui/type-inference/unbounded-associated-type.stderr
new file mode 100644
index 0000000..726dd4b
--- /dev/null
+++ b/src/test/ui/type-inference/unbounded-associated-type.stderr
@@ -0,0 +1,15 @@
+error[E0282]: type annotations needed
+ --> $DIR/unbounded-associated-type.rs:15:5
+ |
+LL | type A;
+ | ------- `<Self as T>::A` defined here
+...
+LL | S(std::marker::PhantomData).foo();
+ | ^--------------------------------
+ | |
+ | this method call resolves to `<Self as T>::A`
+ | cannot infer type for type parameter `X`
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0282`.
diff --git a/src/test/ui/type-inference/unbounded-type-param-in-fn-with-assoc-type.rs b/src/test/ui/type-inference/unbounded-type-param-in-fn-with-assoc-type.rs
new file mode 100644
index 0000000..81d054b
--- /dev/null
+++ b/src/test/ui/type-inference/unbounded-type-param-in-fn-with-assoc-type.rs
@@ -0,0 +1,9 @@
+#[allow(invalid_type_param_default)]
+
+fn foo<T, U = u64>() -> (T, U) {
+ panic!()
+}
+
+fn main() {
+ foo(); //~ ERROR type annotations needed
+}
diff --git a/src/test/ui/type-inference/unbounded-type-param-in-fn-with-assoc-type.stderr b/src/test/ui/type-inference/unbounded-type-param-in-fn-with-assoc-type.stderr
new file mode 100644
index 0000000..52039d0
--- /dev/null
+++ b/src/test/ui/type-inference/unbounded-type-param-in-fn-with-assoc-type.stderr
@@ -0,0 +1,9 @@
+error[E0282]: type annotations needed
+ --> $DIR/unbounded-type-param-in-fn-with-assoc-type.rs:8:5
+ |
+LL | foo();
+ | ^^^ cannot infer type for type parameter `T`
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0282`.
diff --git a/src/test/ui/type-inference/unbounded-type-param-in-fn.rs b/src/test/ui/type-inference/unbounded-type-param-in-fn.rs
new file mode 100644
index 0000000..1f336ed
--- /dev/null
+++ b/src/test/ui/type-inference/unbounded-type-param-in-fn.rs
@@ -0,0 +1,7 @@
+fn foo<T>() -> T {
+ panic!()
+}
+
+fn main() {
+ foo(); //~ ERROR type annotations needed
+}
diff --git a/src/test/ui/type-inference/unbounded-type-param-in-fn.stderr b/src/test/ui/type-inference/unbounded-type-param-in-fn.stderr
new file mode 100644
index 0000000..8d317df
--- /dev/null
+++ b/src/test/ui/type-inference/unbounded-type-param-in-fn.stderr
@@ -0,0 +1,9 @@
+error[E0282]: type annotations needed
+ --> $DIR/unbounded-type-param-in-fn.rs:6:5
+ |
+LL | foo();
+ | ^^^ cannot infer type for type parameter `T`
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0282`.
diff --git a/src/test/ui/type/type-annotation-needed.rs b/src/test/ui/type/type-annotation-needed.rs
index 3b1521d..a420515 100644
--- a/src/test/ui/type/type-annotation-needed.rs
+++ b/src/test/ui/type/type-annotation-needed.rs
@@ -5,4 +5,6 @@
fn main() {
foo(42);
//~^ ERROR type annotations needed
+ //~| NOTE cannot infer type
+ //~| NOTE cannot resolve
}
diff --git a/src/test/ui/type/type-annotation-needed.stderr b/src/test/ui/type/type-annotation-needed.stderr
index 460bbe9..9442544 100644
--- a/src/test/ui/type/type-annotation-needed.stderr
+++ b/src/test/ui/type/type-annotation-needed.stderr
@@ -1,4 +1,4 @@
-error[E0283]: type annotations needed: cannot resolve `_: std::convert::Into<std::string::String>`
+error[E0283]: type annotations needed
--> $DIR/type-annotation-needed.rs:6:5
|
LL | fn foo<T: Into<String>>(x: i32) {}
@@ -6,6 +6,11 @@
...
LL | foo(42);
| ^^^
+ | |
+ | cannot infer type for type parameter `T`
+ | help: consider specifying the type argument in the function call: `foo::<T>`
+ |
+ = note: cannot resolve `_: std::convert::Into<std::string::String>`
error: aborting due to previous error
diff --git a/src/test/ui/type/type-check-defaults.rs b/src/test/ui/type/type-check-defaults.rs
index 5748c9b..5380fae 100644
--- a/src/test/ui/type/type-check-defaults.rs
+++ b/src/test/ui/type/type-check-defaults.rs
@@ -4,9 +4,9 @@
struct Foo<T, U: FromIterator<T>>(T, U);
struct WellFormed<Z = Foo<i32, i32>>(Z);
-//~^ ERROR a collection of type `i32` cannot be built from an iterator over elements of type `i32`
+//~^ ERROR a value of type `i32` cannot be built from an iterator over elements of type `i32`
struct WellFormedNoBounds<Z:?Sized = Foo<i32, i32>>(Z);
-//~^ ERROR a collection of type `i32` cannot be built from an iterator over elements of type `i32`
+//~^ ERROR a value of type `i32` cannot be built from an iterator over elements of type `i32`
struct Bounds<T:Copy=String>(T);
//~^ ERROR the trait bound `std::string::String: std::marker::Copy` is not satisfied [E0277]
diff --git a/src/test/ui/type/type-check-defaults.stderr b/src/test/ui/type/type-check-defaults.stderr
index 6802bc3..6f84b37 100644
--- a/src/test/ui/type/type-check-defaults.stderr
+++ b/src/test/ui/type/type-check-defaults.stderr
@@ -1,21 +1,21 @@
-error[E0277]: a collection of type `i32` cannot be built from an iterator over elements of type `i32`
+error[E0277]: a value of type `i32` cannot be built from an iterator over elements of type `i32`
--> $DIR/type-check-defaults.rs:6:19
|
LL | struct Foo<T, U: FromIterator<T>>(T, U);
| ---------------------------------------- required by `Foo`
LL | struct WellFormed<Z = Foo<i32, i32>>(Z);
- | ^ a collection of type `i32` cannot be built from `std::iter::Iterator<Item=i32>`
+ | ^ value of type `i32` cannot be built from `std::iter::Iterator<Item=i32>`
|
= help: the trait `std::iter::FromIterator<i32>` is not implemented for `i32`
-error[E0277]: a collection of type `i32` cannot be built from an iterator over elements of type `i32`
+error[E0277]: a value of type `i32` cannot be built from an iterator over elements of type `i32`
--> $DIR/type-check-defaults.rs:8:27
|
LL | struct Foo<T, U: FromIterator<T>>(T, U);
| ---------------------------------------- required by `Foo`
...
LL | struct WellFormedNoBounds<Z:?Sized = Foo<i32, i32>>(Z);
- | ^ a collection of type `i32` cannot be built from `std::iter::Iterator<Item=i32>`
+ | ^ value of type `i32` cannot be built from `std::iter::Iterator<Item=i32>`
|
= help: the trait `std::iter::FromIterator<i32>` is not implemented for `i32`
diff --git a/src/test/ui/type/type-check/cannot_infer_local_or_vec.stderr b/src/test/ui/type/type-check/cannot_infer_local_or_vec.stderr
index 6524bf5..53cc769 100644
--- a/src/test/ui/type/type-check/cannot_infer_local_or_vec.stderr
+++ b/src/test/ui/type/type-check/cannot_infer_local_or_vec.stderr
@@ -2,7 +2,7 @@
--> $DIR/cannot_infer_local_or_vec.rs:2:13
|
LL | let x = vec![];
- | - ^^^^^^ cannot infer type for `T`
+ | - ^^^^^^ cannot infer type for type parameter `T`
| |
| consider giving `x` the explicit type `std::vec::Vec<T>`, where the type parameter `T` is specified
|
diff --git a/src/test/ui/type/type-check/cannot_infer_local_or_vec_in_tuples.stderr b/src/test/ui/type/type-check/cannot_infer_local_or_vec_in_tuples.stderr
index 6d1ef240..df7228c 100644
--- a/src/test/ui/type/type-check/cannot_infer_local_or_vec_in_tuples.stderr
+++ b/src/test/ui/type/type-check/cannot_infer_local_or_vec_in_tuples.stderr
@@ -2,7 +2,7 @@
--> $DIR/cannot_infer_local_or_vec_in_tuples.rs:2:18
|
LL | let (x, ) = (vec![], );
- | ----- ^^^^^^ cannot infer type for `T`
+ | ----- ^^^^^^ cannot infer type for type parameter `T`
| |
| consider giving this pattern the explicit type `(std::vec::Vec<T>,)`, where the type parameter `T` is specified
|
diff --git a/src/test/ui/type/type-check/issue-22897.stderr b/src/test/ui/type/type-check/issue-22897.stderr
index 2b3f069..fae7b79 100644
--- a/src/test/ui/type/type-check/issue-22897.stderr
+++ b/src/test/ui/type/type-check/issue-22897.stderr
@@ -2,7 +2,7 @@
--> $DIR/issue-22897.rs:4:5
|
LL | [];
- | ^^ cannot infer type for `[_; 0]`
+ | ^^ cannot infer type for array `[_; 0]`
error: aborting due to previous error
diff --git a/src/test/ui/type/type-check/issue-40294.stderr b/src/test/ui/type/type-check/issue-40294.stderr
index 508783a..4fc0285 100644
--- a/src/test/ui/type/type-check/issue-40294.stderr
+++ b/src/test/ui/type/type-check/issue-40294.stderr
@@ -1,4 +1,4 @@
-error[E0283]: type annotations needed: cannot resolve `&'a T: Foo`
+error[E0283]: type annotations needed
--> $DIR/issue-40294.rs:5:1
|
LL | trait Foo: Sized {
@@ -11,7 +11,9 @@
LL | | x.foo();
LL | | y.foo();
LL | | }
- | |_^
+ | |_^ cannot infer type for reference `&'a T`
+ |
+ = note: cannot resolve `&'a T: Foo`
error: aborting due to previous error
diff --git a/src/test/ui/type/type-check/issue-67273-assignment-match-prior-arm-bool-expected-unit.rs b/src/test/ui/type/type-check/issue-67273-assignment-match-prior-arm-bool-expected-unit.rs
new file mode 100644
index 0000000..e23c0d0
--- /dev/null
+++ b/src/test/ui/type/type-check/issue-67273-assignment-match-prior-arm-bool-expected-unit.rs
@@ -0,0 +1,27 @@
+fn main() {
+ let mut i: i64;
+ // Expected type is an inference variable `?T`
+ // because the `match` is used as a statement.
+ // This is the "initial" type of the `coercion`.
+ match i {
+ // Add `bool` to the overall `coercion`.
+ 0 => true,
+
+ // Necessary to cause the ICE:
+ 1 => true,
+
+ // Suppose that we had `let _: bool = match i { ... }`.
+ // In that case, as the expected type would be `bool`,
+ // we would suggest `i == 1` as a fix.
+ //
+ // However, no type error happens when checking `i = 1` because `expected == ?T`,
+ // which will unify with `typeof(i = 1) == ()`.
+ //
+ // However, in #67273, we would delay the unification of this arm with the above
+ // because we used the hitherto accumulated coercion as opposed to the "initial" type.
+ 2 => i = 1,
+ //~^ ERROR match arms have incompatible types
+
+ _ => (),
+ }
+}
diff --git a/src/test/ui/type/type-check/issue-67273-assignment-match-prior-arm-bool-expected-unit.stderr b/src/test/ui/type/type-check/issue-67273-assignment-match-prior-arm-bool-expected-unit.stderr
new file mode 100644
index 0000000..3547285
--- /dev/null
+++ b/src/test/ui/type/type-check/issue-67273-assignment-match-prior-arm-bool-expected-unit.stderr
@@ -0,0 +1,22 @@
+error[E0308]: match arms have incompatible types
+ --> $DIR/issue-67273-assignment-match-prior-arm-bool-expected-unit.rs:22:14
+ |
+LL | / match i {
+LL | | // Add `bool` to the overall `coercion`.
+LL | | 0 => true,
+ | | ---- this is found to be of type `bool`
+LL | |
+LL | | // Necessary to cause the ICE:
+LL | | 1 => true,
+ | | ---- this is found to be of type `bool`
+... |
+LL | | 2 => i = 1,
+ | | ^^^^^ expected `bool`, found `()`
+... |
+LL | | _ => (),
+LL | | }
+ | |_____- `match` arms have incompatible types
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0308`.
diff --git a/src/test/ui/type/type-dependent-def-issue-49241.rs b/src/test/ui/type/type-dependent-def-issue-49241.rs
index 5ad50ff..a25e3ba 100644
--- a/src/test/ui/type/type-dependent-def-issue-49241.rs
+++ b/src/test/ui/type/type-dependent-def-issue-49241.rs
@@ -3,5 +3,5 @@
const l: usize = v.count(); //~ ERROR attempt to use a non-constant value in a constant
let s: [u32; l] = v.into_iter().collect();
//~^ ERROR evaluation of constant value failed
- //~^^ ERROR a collection of type
+ //~^^ ERROR a value of type
}
diff --git a/src/test/ui/type/type-dependent-def-issue-49241.stderr b/src/test/ui/type/type-dependent-def-issue-49241.stderr
index 851004d..18a69c5 100644
--- a/src/test/ui/type/type-dependent-def-issue-49241.stderr
+++ b/src/test/ui/type/type-dependent-def-issue-49241.stderr
@@ -10,11 +10,11 @@
LL | let s: [u32; l] = v.into_iter().collect();
| ^ referenced constant has errors
-error[E0277]: a collection of type `[u32; _]` cannot be built from an iterator over elements of type `{integer}`
+error[E0277]: a value of type `[u32; _]` cannot be built from an iterator over elements of type `{integer}`
--> $DIR/type-dependent-def-issue-49241.rs:4:37
|
LL | let s: [u32; l] = v.into_iter().collect();
- | ^^^^^^^ a collection of type `[u32; _]` cannot be built from `std::iter::Iterator<Item={integer}>`
+ | ^^^^^^^ value of type `[u32; _]` cannot be built from `std::iter::Iterator<Item={integer}>`
|
= help: the trait `std::iter::FromIterator<{integer}>` is not implemented for `[u32; _]`
diff --git a/src/test/ui/unconstrained-none.stderr b/src/test/ui/unconstrained-none.stderr
index eb918b2..6c4fde9 100644
--- a/src/test/ui/unconstrained-none.stderr
+++ b/src/test/ui/unconstrained-none.stderr
@@ -2,7 +2,7 @@
--> $DIR/unconstrained-none.rs:4:5
|
LL | None;
- | ^^^^ cannot infer type for `T`
+ | ^^^^ cannot infer type for type parameter `T`
error: aborting due to previous error
diff --git a/src/test/ui/unconstrained-ref.stderr b/src/test/ui/unconstrained-ref.stderr
index d9a129a..d6985a6 100644
--- a/src/test/ui/unconstrained-ref.stderr
+++ b/src/test/ui/unconstrained-ref.stderr
@@ -2,7 +2,7 @@
--> $DIR/unconstrained-ref.rs:6:5
|
LL | S { o: &None };
- | ^ cannot infer type for `T`
+ | ^ cannot infer type for type parameter `T`
error: aborting due to previous error
diff --git a/src/test/ui/underscore-lifetime/dyn-trait-underscore.stderr b/src/test/ui/underscore-lifetime/dyn-trait-underscore.stderr
index d0475bf..e6029e0d 100644
--- a/src/test/ui/underscore-lifetime/dyn-trait-underscore.stderr
+++ b/src/test/ui/underscore-lifetime/dyn-trait-underscore.stderr
@@ -18,9 +18,13 @@
LL | Box::new(items.iter())
| ^^^^^
= note: but, the lifetime must be valid for the static lifetime...
- = note: ...so that the expression is assignable:
- expected std::boxed::Box<(dyn std::iter::Iterator<Item = &T> + 'static)>
- found std::boxed::Box<dyn std::iter::Iterator<Item = &T>>
+note: ...so that the expression is assignable
+ --> $DIR/dyn-trait-underscore.rs:8:5
+ |
+LL | Box::new(items.iter())
+ | ^^^^^^^^^^^^^^^^^^^^^^
+ = note: expected `std::boxed::Box<(dyn std::iter::Iterator<Item = &T> + 'static)>`
+ found `std::boxed::Box<dyn std::iter::Iterator<Item = &T>>`
error: aborting due to previous error
diff --git a/src/test/ui/uninhabited/uninhabited-matches-feature-gated.stderr b/src/test/ui/uninhabited/uninhabited-matches-feature-gated.stderr
index 7af6075..18ffdcc 100644
--- a/src/test/ui/uninhabited/uninhabited-matches-feature-gated.stderr
+++ b/src/test/ui/uninhabited/uninhabited-matches-feature-gated.stderr
@@ -9,6 +9,9 @@
error[E0004]: non-exhaustive patterns: type `&Void` is non-empty
--> $DIR/uninhabited-matches-feature-gated.rs:12:19
|
+LL | enum Void {}
+ | ------------ `Void` defined here
+...
LL | let _ = match x {};
| ^
|
diff --git a/src/test/ui/vector-no-ann.stderr b/src/test/ui/vector-no-ann.stderr
index 28100d7..62fc42f 100644
--- a/src/test/ui/vector-no-ann.stderr
+++ b/src/test/ui/vector-no-ann.stderr
@@ -2,7 +2,7 @@
--> $DIR/vector-no-ann.rs:2:16
|
LL | let _foo = Vec::new();
- | ---- ^^^^^^^^ cannot infer type for `T`
+ | ---- ^^^^^^^^ cannot infer type for type parameter `T`
| |
| consider giving `_foo` the explicit type `std::vec::Vec<T>`, where the type parameter `T` is specified
diff --git a/src/test/ui/wrong-ret-type.stderr b/src/test/ui/wrong-ret-type.stderr
index 440620f..c1274bd 100644
--- a/src/test/ui/wrong-ret-type.stderr
+++ b/src/test/ui/wrong-ret-type.stderr
@@ -5,6 +5,11 @@
| ----- ^ expected `usize`, found `isize`
| |
| expected `usize` because of return type
+ |
+help: you can convert an `isize` to `usize` and panic if the converted value wouldn't fit
+ |
+LL | fn mk_int() -> usize { let i: isize = 3; return i.try_into().unwrap(); }
+ | ^^^^^^^^^^^^^^^^^^^^^
error: aborting due to previous error
diff --git a/src/tools/compiletest/src/header.rs b/src/tools/compiletest/src/header.rs
index dc4811e..46cce63 100644
--- a/src/tools/compiletest/src/header.rs
+++ b/src/tools/compiletest/src/header.rs
@@ -71,6 +71,7 @@
pub ignore: Ignore,
pub should_fail: bool,
pub aux: Vec<String>,
+ pub aux_crate: Vec<(String, String)>,
pub revisions: Vec<String>,
}
@@ -80,6 +81,7 @@
ignore: Ignore::Run,
should_fail: false,
aux: Vec::new(),
+ aux_crate: Vec::new(),
revisions: vec![],
};
@@ -157,6 +159,10 @@
props.aux.push(s);
}
+ if let Some(ac) = config.parse_aux_crate(ln) {
+ props.aux_crate.push(ac);
+ }
+
if let Some(r) = config.parse_revisions(ln) {
props.revisions.extend(r);
}
@@ -311,10 +317,9 @@
// directory as the test, but for backwards compatibility reasons
// we also check the auxiliary directory)
pub aux_builds: Vec<String>,
- // A list of crates to pass '--extern-private name:PATH' flags for
- // This should be a subset of 'aux_build'
- // FIXME: Replace this with a better solution: https://github.com/rust-lang/rust/pull/54020
- pub extern_private: Vec<String>,
+ // Similar to `aux_builds`, but a list of NAME=somelib.rs of dependencies
+ // to build and pass with the `--extern` flag.
+ pub aux_crates: Vec<(String, String)>,
// Environment settings to use for compiling
pub rustc_env: Vec<(String, String)>,
// Environment variables to unset prior to compiling.
@@ -387,7 +392,7 @@
run_flags: None,
pp_exact: None,
aux_builds: vec![],
- extern_private: vec![],
+ aux_crates: vec![],
revisions: vec![],
rustc_env: vec![],
unset_rustc_env: vec![],
@@ -514,8 +519,8 @@
self.aux_builds.push(ab);
}
- if let Some(ep) = config.parse_extern_private(ln) {
- self.extern_private.push(ep);
+ if let Some(ac) = config.parse_aux_crate(ln) {
+ self.aux_crates.push(ac);
}
if let Some(ee) = config.parse_env(ln, "exec-env") {
@@ -713,8 +718,14 @@
.map(|r| r.trim().to_string())
}
- fn parse_extern_private(&self, line: &str) -> Option<String> {
- self.parse_name_value_directive(line, "extern-private")
+ fn parse_aux_crate(&self, line: &str) -> Option<(String, String)> {
+ self.parse_name_value_directive(line, "aux-crate").map(|r| {
+ let mut parts = r.trim().splitn(2, '=');
+ (
+ parts.next().expect("aux-crate name").to_string(),
+ parts.next().expect("aux-crate value").to_string(),
+ )
+ })
}
fn parse_compile_flags(&self, line: &str) -> Option<String> {
diff --git a/src/tools/compiletest/src/runtest.rs b/src/tools/compiletest/src/runtest.rs
index 15ae67f..4808684 100644
--- a/src/tools/compiletest/src/runtest.rs
+++ b/src/tools/compiletest/src/runtest.rs
@@ -1776,93 +1776,16 @@
create_dir_all(&aux_dir).unwrap();
}
- // Use a Vec instead of a HashMap to preserve original order
- let mut extern_priv = self.props.extern_private.clone();
-
- let mut add_extern_priv = |priv_dep: &str, dylib: bool| {
- let lib_name = get_lib_name(priv_dep, dylib);
- rustc
- .arg("--extern-private")
- .arg(format!("{}={}", priv_dep, aux_dir.join(lib_name).to_str().unwrap()));
- };
-
for rel_ab in &self.props.aux_builds {
- let aux_testpaths = self.compute_aux_test_paths(rel_ab);
- let aux_props =
- self.props
- .from_aux_file(&aux_testpaths.file, self.revision, self.config);
- let aux_output = TargetLocation::ThisDirectory(self.aux_output_dir_name());
- let aux_cx = TestCx {
- config: self.config,
- props: &aux_props,
- testpaths: &aux_testpaths,
- revision: self.revision,
- };
- // Create the directory for the stdout/stderr files.
- create_dir_all(aux_cx.output_base_dir()).unwrap();
- let mut aux_rustc = aux_cx.make_compile_args(&aux_testpaths.file, aux_output);
-
- let (dylib, crate_type) = if aux_props.no_prefer_dynamic {
- (true, None)
- } else if self.config.target.contains("cloudabi")
- || self.config.target.contains("emscripten")
- || (self.config.target.contains("musl")
- && !aux_props.force_host
- && !self.config.host.contains("musl"))
- || self.config.target.contains("wasm32")
- || self.config.target.contains("nvptx")
- || self.is_vxworks_pure_static()
- {
- // We primarily compile all auxiliary libraries as dynamic libraries
- // to avoid code size bloat and large binaries as much as possible
- // for the test suite (otherwise including libstd statically in all
- // executables takes up quite a bit of space).
- //
- // For targets like MUSL or Emscripten, however, there is no support for
- // dynamic libraries so we just go back to building a normal library. Note,
- // however, that for MUSL if the library is built with `force_host` then
- // it's ok to be a dylib as the host should always support dylibs.
- (false, Some("lib"))
- } else {
- (true, Some("dylib"))
- };
-
- let trimmed = rel_ab.trim_end_matches(".rs").to_string();
-
- // Normally, every 'extern-private' has a correspodning 'aux-build'
- // entry. If so, we remove it from our list of private crates,
- // and add an '--extern-private' flag to rustc
- if extern_priv.remove_item(&trimmed).is_some() {
- add_extern_priv(&trimmed, dylib);
- }
-
- if let Some(crate_type) = crate_type {
- aux_rustc.args(&["--crate-type", crate_type]);
- }
-
- aux_rustc.arg("-L").arg(&aux_dir);
-
- let auxres = aux_cx.compose_and_run(
- aux_rustc,
- aux_cx.config.compile_lib_path.to_str().unwrap(),
- Some(aux_dir.to_str().unwrap()),
- None,
- );
- if !auxres.status.success() {
- self.fatal_proc_rec(
- &format!(
- "auxiliary build of {:?} failed to compile: ",
- aux_testpaths.file.display()
- ),
- &auxres,
- );
- }
+ self.build_auxiliary(rel_ab, &aux_dir);
}
- // Add any '--extern-private' entries without a matching
- // 'aux-build'
- for private_lib in extern_priv {
- add_extern_priv(&private_lib, true);
+ for (aux_name, aux_path) in &self.props.aux_crates {
+ let is_dylib = self.build_auxiliary(&aux_path, &aux_dir);
+ let lib_name = get_lib_name(&aux_path.trim_end_matches(".rs").replace('-', "_"),
+ is_dylib);
+ rustc.arg("--extern")
+ .arg(format!("{}={}/{}", aux_name, aux_dir.display(), lib_name));
}
self.props.unset_rustc_env.clone()
@@ -1877,6 +1800,74 @@
)
}
+ /// Builds an aux dependency.
+ ///
+ /// Returns whether or not it is a dylib.
+ fn build_auxiliary(&self, source_path: &str, aux_dir: &Path) -> bool {
+ let aux_testpaths = self.compute_aux_test_paths(source_path);
+ let aux_props =
+ self.props
+ .from_aux_file(&aux_testpaths.file, self.revision, self.config);
+ let aux_output = TargetLocation::ThisDirectory(self.aux_output_dir_name());
+ let aux_cx = TestCx {
+ config: self.config,
+ props: &aux_props,
+ testpaths: &aux_testpaths,
+ revision: self.revision,
+ };
+ // Create the directory for the stdout/stderr files.
+ create_dir_all(aux_cx.output_base_dir()).unwrap();
+ let mut aux_rustc = aux_cx.make_compile_args(&aux_testpaths.file, aux_output);
+
+ let (dylib, crate_type) = if aux_props.no_prefer_dynamic {
+ (true, None)
+ } else if self.config.target.contains("cloudabi")
+ || self.config.target.contains("emscripten")
+ || (self.config.target.contains("musl")
+ && !aux_props.force_host
+ && !self.config.host.contains("musl"))
+ || self.config.target.contains("wasm32")
+ || self.config.target.contains("nvptx")
+ || self.is_vxworks_pure_static()
+ {
+ // We primarily compile all auxiliary libraries as dynamic libraries
+ // to avoid code size bloat and large binaries as much as possible
+ // for the test suite (otherwise including libstd statically in all
+ // executables takes up quite a bit of space).
+ //
+ // For targets like MUSL or Emscripten, however, there is no support for
+ // dynamic libraries so we just go back to building a normal library. Note,
+ // however, that for MUSL if the library is built with `force_host` then
+ // it's ok to be a dylib as the host should always support dylibs.
+ (false, Some("lib"))
+ } else {
+ (true, Some("dylib"))
+ };
+
+ if let Some(crate_type) = crate_type {
+ aux_rustc.args(&["--crate-type", crate_type]);
+ }
+
+ aux_rustc.arg("-L").arg(&aux_dir);
+
+ let auxres = aux_cx.compose_and_run(
+ aux_rustc,
+ aux_cx.config.compile_lib_path.to_str().unwrap(),
+ Some(aux_dir.to_str().unwrap()),
+ None,
+ );
+ if !auxres.status.success() {
+ self.fatal_proc_rec(
+ &format!(
+ "auxiliary build of {:?} failed to compile: ",
+ aux_testpaths.file.display()
+ ),
+ &auxres,
+ );
+ }
+ dylib
+ }
+
fn compose_and_run(
&self,
mut command: Command,
diff --git a/src/tools/miri b/src/tools/miri
index a0ba079..048af40 160000
--- a/src/tools/miri
+++ b/src/tools/miri
@@ -1 +1 @@
-Subproject commit a0ba079b6af0f8c07c33dd8af72a51c997e58967
+Subproject commit 048af409232fc2d7f8fbe5469080dc8bb702c498
diff --git a/src/tools/rls b/src/tools/rls
index 9ec2b8c..8f1c275 160000
--- a/src/tools/rls
+++ b/src/tools/rls
@@ -1 +1 @@
-Subproject commit 9ec2b8cb57c87517bcb506ac302eae339ffa2025
+Subproject commit 8f1c2756d76c3dd728b925b65eec0106eb3102ea
diff --git a/src/tools/rustfmt b/src/tools/rustfmt
index 33e3667..1838235 160000
--- a/src/tools/rustfmt
+++ b/src/tools/rustfmt
@@ -1 +1 @@
-Subproject commit 33e3667085e4c73d4391c6168552458eb47664de
+Subproject commit 1838235248bbde125bbc6c12fb493e1979088bb5
diff --git a/src/tools/tidy/src/deps.rs b/src/tools/tidy/src/deps.rs
index 7b928a2..36e4129 100644
--- a/src/tools/tidy/src/deps.rs
+++ b/src/tools/tidy/src/deps.rs
@@ -135,6 +135,7 @@
Crate("polonius-engine"),
Crate("ppv-lite86"),
Crate("proc-macro2"),
+ Crate("punycode"),
Crate("quick-error"),
Crate("quote"),
Crate("rand"),