*.ico binary
*.woff binary
*.woff2 binary
-
-# Needed as part of converting rustfmt to a subtree, can hopefully be removed later.
-src/tools/rustfmt/tests/source/issue-3494/crlf.rs -text
-src/tools/rustfmt/tests/source/comment_crlf_newline.rs -text
-src/tools/rustfmt/tests/source/configs/enum_discrim_align_threshold/40.rs -text
-src/tools/rustfmt/tests/target/issue-3494/crlf.rs -text
-src/tools/rustfmt/tests/target/comment_crlf_newline.rs -text
-src/tools/rustfmt/tests/target/configs/enum_discrim_align_threshold/40.rs -text
- name: x86_64-gnu
os: ubuntu-latest-xl
env: {}
+ - name: x86_64-gnu-stable
+ env:
+ IMAGE: x86_64-gnu
+ RUST_CI_OVERRIDE_RELEASE_CHANNEL: stable
+ os: ubuntu-latest-xl
- name: x86_64-gnu-aux
os: ubuntu-latest-xl
env: {}
Lee Jeffery <leejeffery@gmail.com> Lee Jeffery <lee@leejeffery.co.uk>
Lee Wondong <wdlee91@gmail.com>
Lennart Kudling <github@kudling.de>
+Léo Lanteri Thauvin <leseulartichaut@gmail.com>
+Léo Lanteri Thauvin <leseulartichaut@gmail.com> <38361244+LeSeulArtichaut@users.noreply.github.com>
Léo Testard <leo.testard@gmail.com>
Lindsey Kuper <lindsey@composition.al> <lindsey@rockstargirl.org>
Lindsey Kuper <lindsey@composition.al> <lkuper@mozilla.com>
"humantime 2.0.1",
"ignore",
"im-rc",
+ "itertools 0.10.0",
"jobserver",
"lazy_static",
"lazycell",
"pretty_env_logger",
"rand 0.8.3",
"rustc-workspace-hack",
- "rustfix",
- "semver 0.10.0",
+ "rustfix 0.6.0",
+ "semver 1.0.3",
"serde",
"serde_ignored",
"serde_json",
[[package]]
name = "cc"
-version = "1.0.67"
+version = "1.0.68"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "e3c69b077ad434294d3ce9f1f6143a2a4b89a8a2d54ef813d85003a4fd1137fd"
+checksum = "4a72c244c1ff497a746a7e1fb3d14bd08420ecda70c8f25c7112f2781652d787"
dependencies = [
"jobserver",
]
version = "0.1.54"
dependencies = [
"cargo_metadata 0.12.0",
- "clippy-mini-macro-test",
"clippy_lints",
"compiletest_rs",
"derive-new",
+ "filetime",
"quote",
"regex",
"rustc-workspace-hack",
"tester",
]
-[[package]]
-name = "clippy-mini-macro-test"
-version = "0.2.0"
-
[[package]]
name = "clippy_dev"
version = "0.0.1"
[[package]]
name = "compiler_builtins"
-version = "0.1.43"
+version = "0.1.45"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "65af2dcae4779003dfa91aedc6ade7bdc7ba685944e50a8b4f9380df376a4466"
+checksum = "787187ae221adfcda34b03006f1617099e4ae26b50e5a4db282496014ab75837"
dependencies = [
"cc",
"rustc-std-workspace-core",
"libc",
"miow 0.3.6",
"regex",
- "rustfix",
+ "rustfix 0.5.1",
"serde",
"serde_json",
"tracing",
"log",
"miow 0.3.6",
"regex",
- "rustfix",
+ "rustfix 0.5.1",
"serde",
"serde_derive",
"serde_json",
"either",
]
+[[package]]
+name = "itertools"
+version = "0.10.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "37d572918e350e82412fe766d24b15e6682fb2ed2bbe018280caa810397cb319"
+dependencies = [
+ "either",
+]
+
[[package]]
name = "itoa"
version = "0.4.6"
"fs-err",
"getopts",
"jsonpath_lib",
- "lazy_static",
+ "once_cell",
"regex",
- "serde",
"serde_json",
- "shlex 0.1.1",
+ "shlex",
]
[[package]]
"serde",
"serde_derive",
"serde_json",
- "shlex 1.0.0",
+ "shlex",
"tempfile",
"toml",
]
[[package]]
name = "measureme"
-version = "9.1.1"
+version = "9.1.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "49cf14eb7d2eea897d9949b68f19e165638755e3a1a3c0941b6b6c3e00141f2c"
+checksum = "78f7a41bc6f856a2cf0e95094ad5121f82500e2d9a0f3c0171d98f6566d8117d"
dependencies = [
"log",
"memmap2",
[[package]]
name = "memchr"
-version = "2.3.3"
+version = "2.4.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "3728d817d99e5ac407411fa471ff9800a778d88a24685968b36824eaf4bee400"
+checksum = "b16bd47d9e329435e309c58469fe0791c2d0d1ba96ec0954152a5ae2b04387dc"
[[package]]
name = "memmap2"
"hex 0.4.2",
"libc",
"log",
+ "measureme",
"rand 0.8.3",
"rustc-workspace-hack",
"rustc_version",
"rustc-std-workspace-core",
]
+[[package]]
+name = "object"
+version = "0.25.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "f8bc1d42047cf336f0f939c99e97183cf31551bf0f2865a2ec9c8d91fd4ffb5e"
+dependencies = [
+ "crc32fast",
+ "indexmap",
+ "memchr",
+]
+
[[package]]
name = "once_cell"
version = "1.7.2"
[[package]]
name = "racer"
-version = "2.1.46"
+version = "2.1.48"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "e7cbda48a9124ed2e83766d2c15e3725710d344abca35fad8cf52341a55883b1"
+checksum = "7fec2e85e7a30f8fd31b7cf288ad363b5e51fd2cb6f53b416b0cfaabd84e1ccb"
dependencies = [
"bitflags",
"clap",
"anyhow",
"cargo",
"cargo-util",
- "cargo_metadata 0.8.2",
+ "cargo_metadata 0.12.0",
"clippy_lints",
"crossbeam-channel",
"difference",
[[package]]
name = "rustc-ap-rustc_arena"
-version = "718.0.0"
+version = "722.0.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "526610f47139efa440178239553b59ea805ff57a532b4e295c71d2a9b18fd676"
+checksum = "550ca1a0925d31a0af089b18c89f5adf3b286e319e3e1f1a5204c21bd2f17371"
dependencies = [
"rustc-ap-rustc_data_structures",
"smallvec",
[[package]]
name = "rustc-ap-rustc_ast"
-version = "718.0.0"
+version = "722.0.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "cf6a9dda0804a7243b0282e3b75a8cf4654c7a61f033e587751941e1fe39391b"
+checksum = "4aa53b68080df17994a54747f7c37b0686288a670efb9ba3b382ce62e744aed2"
dependencies = [
"bitflags",
"rustc-ap-rustc_data_structures",
[[package]]
name = "rustc-ap-rustc_ast_pretty"
-version = "718.0.0"
+version = "722.0.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "82f5019be8b41a58664169fd2f4b1a37fe82705681db394b76419e4e87d40ab1"
+checksum = "0ae71e68fada466a4b2c39c79ca6aee3226587abe6787170d2f6c92237569565"
dependencies = [
"rustc-ap-rustc_ast",
"rustc-ap-rustc_span",
[[package]]
name = "rustc-ap-rustc_data_structures"
-version = "718.0.0"
+version = "722.0.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "a701717fb14549331085756b9741ae3b4bf35808489f1887d72c1d0e0fe52b77"
+checksum = "faa484d6e0ca32d1d82303647275c696f745599b3d97e686f396ceef5b99d7ae"
dependencies = [
"arrayvec",
"bitflags",
[[package]]
name = "rustc-ap-rustc_errors"
-version = "718.0.0"
+version = "722.0.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "e3182ce85e8bfc96443475547f2f5aa2b5e67655d9b88721795f36f0ba9e265a"
+checksum = "5f85ba19cca320ad797e3a29c35cab9bddfff0e7adbde336a436249e54cee7b1"
dependencies = [
"annotate-snippets",
"atty",
[[package]]
name = "rustc-ap-rustc_feature"
-version = "718.0.0"
+version = "722.0.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "eed033b93270126ef60963c3ebbd0e026bf53b985172b6366c7b0e7881c9d507"
+checksum = "97d538adab96b8b2b1ca9fcd4c8c47d4e23e862a23d1a38b6c15cd8fd52b34b1"
dependencies = [
"rustc-ap-rustc_data_structures",
"rustc-ap-rustc_span",
[[package]]
name = "rustc-ap-rustc_fs_util"
-version = "718.0.0"
+version = "722.0.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "28ee6531986a205101e09fd143d7bf31897388f33b1814d4bcc45fd62211dca6"
+checksum = "8ad6f13d240944fa8f360d2f3b849a7cadaec75e477829e7dde61e838deda83d"
[[package]]
name = "rustc-ap-rustc_graphviz"
-version = "718.0.0"
+version = "722.0.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "3398fddc0e23d2db89c036f8952ddf78cadc597f7059752116e69483e164a5b6"
+checksum = "08b3451153cc5828c02cc4f1a0df146d25ac4b3382a112e25fd9d3f5bff15cdc"
[[package]]
name = "rustc-ap-rustc_index"
-version = "718.0.0"
+version = "722.0.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "dca4e27eb5b701f6bbd47d8fc9d242378fca3e4107a519a28415c2989c4a3bd3"
+checksum = "cd39a9f01b442c629bdff5778cb3dd29b7c2ea4afe62d5ab61d216bd1b556692"
dependencies = [
"arrayvec",
"rustc-ap-rustc_macros",
[[package]]
name = "rustc-ap-rustc_lexer"
-version = "718.0.0"
+version = "722.0.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "786bbfe9d4d5264294c1819dbf1497a2480b583d5eda1ca9ae22e12d6661f5df"
+checksum = "a5de290c44a90e671d2cd730062b9ef73d11155da7e44e7741d633e1e51e616e"
dependencies = [
"unicode-xid",
]
[[package]]
name = "rustc-ap-rustc_lint_defs"
-version = "718.0.0"
+version = "722.0.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "be2f045e2b999c154ec505d5fea69c994b742f3ebd2f552d11a6c81723921e47"
+checksum = "69570b4beb61088926b131579865bbe70d124d30778c46307a62ec8b310ae462"
dependencies = [
"rustc-ap-rustc_ast",
"rustc-ap-rustc_data_structures",
[[package]]
name = "rustc-ap-rustc_macros"
-version = "718.0.0"
+version = "722.0.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "27789cd26d6b9e2fdfa68a262a20664d79ca67d31a3886d40fb88ebf6935869c"
+checksum = "86bd877df37f15c5a44d9679d1b5207ebc95f3943fbc336eeac670195ac58610"
dependencies = [
"proc-macro2",
"quote",
[[package]]
name = "rustc-ap-rustc_parse"
-version = "718.0.0"
+version = "722.0.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "1dc331f4958350679679e619d63a891e8d5d34ef99087068c89aa9e657d52caa"
+checksum = "02502d8522ba31d0bcad28a78822b68c1b6ba947a2b4aa6a2341b30594379b80"
dependencies = [
"bitflags",
"rustc-ap-rustc_ast",
[[package]]
name = "rustc-ap-rustc_serialize"
-version = "718.0.0"
+version = "722.0.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "e9a6824a462c4c1a379e911b0faf86d303a54bcf8673d4cc445195085966a4a4"
+checksum = "5f741f8e9aee6323fbe127329490608a5a250cc0072ac91e684ef62518cdb1ff"
dependencies = [
"indexmap",
"smallvec",
[[package]]
name = "rustc-ap-rustc_session"
-version = "718.0.0"
+version = "722.0.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "a782a5f6ada0dbe089c6416ad0104f0b8a8bdb4bd26ea95e5fefaec67aed5e8a"
+checksum = "dba61eca749f4fced4427ad1cc7f23342cfc6527c3bcc624e3aa56abc1f81298"
dependencies = [
"bitflags",
"getopts",
[[package]]
name = "rustc-ap-rustc_span"
-version = "718.0.0"
+version = "722.0.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "a257546cb264b250c7abdb81239bb02f18a274a966211755a3ea89411b122214"
+checksum = "a642e8d6fc883f34e0778e079f8242ac40c6614a6b7a0ef61681333e847f5e62"
dependencies = [
"cfg-if 0.1.10",
"md-5",
[[package]]
name = "rustc-ap-rustc_target"
-version = "718.0.0"
+version = "722.0.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "b5a72dd689421bcb5750f3ed0dedf367076e714ef0ba56c02ed391b9a8582862"
+checksum = "80feebd8c323b80dd73a395fa7fabba9e2098b6277670ff89c473f618ffa07de"
dependencies = [
"bitflags",
"rustc-ap-rustc_data_structures",
"rustc_incremental",
"rustc_index",
"rustc_llvm",
+ "rustc_metadata",
"rustc_middle",
"rustc_serialize",
"rustc_session",
"itertools 0.9.0",
"jobserver",
"libc",
- "object",
+ "object 0.25.2",
"pathdiff",
"rustc_apfloat",
"rustc_ast",
"rand 0.7.3",
"rustc_ast",
"rustc_data_structures",
+ "rustc_errors",
"rustc_fs_util",
"rustc_graphviz",
"rustc_hir",
"serde_json",
]
+[[package]]
+name = "rustfix"
+version = "0.6.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "6f0be05fc0675ef4f47119dc39cfc46636bb77d4fc4ef1bd851b9c3f7697f32a"
+dependencies = [
+ "anyhow",
+ "log",
+ "serde",
+ "serde_json",
+]
+
[[package]]
name = "rustfmt-config_proc_macro"
version = "0.2.0"
"serde",
]
+[[package]]
+name = "semver"
+version = "1.0.3"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "5f3aac57ee7f3272d8395c6e4f502f434f0e289fcd62876f70daa008c20dcabe"
+dependencies = [
+ "serde",
+]
+
[[package]]
name = "semver-parser"
version = "0.7.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "45bb67a18fa91266cc7807181f62f9178a6873bfad7dc788c42e6430db40184f"
-[[package]]
-name = "shlex"
-version = "0.1.1"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "7fdf1b9db47230893d76faad238fd6097fd6d6a9245cd7a4d90dbd639536bbd2"
-
[[package]]
name = "shlex"
version = "1.0.0"
"hermit-abi",
"libc",
"miniz_oxide",
- "object",
+ "object 0.22.0",
"panic_abort",
"panic_unwind",
"profiler_builtins",
[[package]]
name = "tar"
-version = "0.4.33"
+version = "0.4.35"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "c0bcfbd6a598361fda270d82469fff3d65089dc33e175c9a131f7b4cd395f228"
+checksum = "7d779dc6aeff029314570f666ec83f19df7280bb36ef338442cfa8c604021b80"
dependencies = [
"filetime",
"libc",
+Version 1.53.0 (2021-06-17)
+============================
+
+Language
+-----------------------
+- [You can now use unicode for identifiers.][83799] This allows multilingual
+ identifiers but still doesn't allow glyphs that are not considered characters
+ such as `◆` or `🦀`. More specifically you can now use any identifier that
+ matches the UAX #31 "Unicode Identifier and Pattern Syntax" standard. This
+ is the same standard as languages like Python, however Rust uses NFC
+ normalization which may be different from other languages.
+- [You can now specify "or patterns" inside pattern matches.][79278]
+ Previously you could only use `|` (OR) on complete patterns. E.g.
+ ```rust
+ let x = Some(2u8);
+ // Before
+ matches!(x, Some(1) | Some(2));
+ // Now
+ matches!(x, Some(1 | 2));
+ ```
+- [Added the `:pat_param` `macro_rules!` matcher.][83386] This matcher
+ has the same semantics as the `:pat` matcher. This is to allow `:pat`
+ to change semantics to being a pattern fragment in a future edition.
+
+Compiler
+-----------------------
+- [Updated the minimum external LLVM version to LLVM 10.][83387]
+- [Added Tier 3\* support for the `wasm64-unknown-unknown` target.][80525]
+- [Improved debuginfo for closures and async functions on Windows MSVC.][83941]
+
+\* Refer to Rust's [platform support page][platform-support-doc] for more
+information on Rust's tiered platform support.
+
+Libraries
+-----------------------
+- [Abort messages will now forward to `android_set_abort_message` on
+ Android platforms when available.][81469]
+- [`slice::IterMut<'_, T>` now implements `AsRef<[T]>`][82771]
+- [Arrays of any length now implement `IntoIterator`.][84147]
+ Currently calling `.into_iter()` as a method on an array will
+ return `impl Iterator<Item=&T>`, but this may change in a
+ future edition to change `Item` to `T`. Calling `IntoIterator::into_iter`
+ directly on arrays will provide `impl Iterator<Item=T>` as expected.
+- [`leading_zeros`, and `trailing_zeros` are now available on all
+ `NonZero` integer types.][84082]
+- [`{f32, f64}::from_str` now parse and print special values
+ (`NaN`, `-0`) according to IEEE RFC 754.][78618]
+- [You can now index into slices using `(Bound<usize>, Bound<usize>)`.][77704]
+- [Add the `BITS` associated constant to all numeric types.][82565]
+
+Stabilised APIs
+---------------
+- [`AtomicBool::fetch_update`]
+- [`AtomicPtr::fetch_update`]
+- [`BTreeMap::retain`]
+- [`BTreeSet::retain`]
+- [`BufReader::seek_relative`]
+- [`DebugStruct::non_exhaustive`]
+- [`Duration::MAX`]
+- [`Duration::ZERO`]
+- [`Duration::is_zero`]
+- [`Duration::saturating_add`]
+- [`Duration::saturating_mul`]
+- [`Duration::saturating_sub`]
+- [`ErrorKind::Unsupported`]
+- [`Option::insert`]
+- [`Ordering::is_eq`]
+- [`Ordering::is_ge`]
+- [`Ordering::is_gt`]
+- [`Ordering::is_le`]
+- [`Ordering::is_lt`]
+- [`Ordering::is_ne`]
+- [`OsStr::is_ascii`]
+- [`OsStr::make_ascii_lowercase`]
+- [`OsStr::make_ascii_uppercase`]
+- [`OsStr::to_ascii_lowercase`]
+- [`OsStr::to_ascii_uppercase`]
+- [`Peekable::peek_mut`]
+- [`Rc::decrement_strong_count`]
+- [`Rc::increment_strong_count`]
+- [`Vec::extend_from_within`]
+- [`array::from_mut`]
+- [`array::from_ref`]
+- [`cmp::max_by_key`]
+- [`cmp::max_by`]
+- [`cmp::min_by_key`]
+- [`cmp::min_by`]
+- [`f32::is_subnormal`]
+- [`f64::is_subnormal`]
+
+Cargo
+-----------------------
+- [Cargo now supports git repositories where the default `HEAD` branch is not
+ "master".][cargo/9392] This also includes a switch to the version 3 `Cargo.lock` format
+ which can handle default branches correctly.
+- [macOS targets now default to `unpacked` split-debuginfo.][cargo/9298]
+- [The `authors` field is no longer included in `Cargo.toml` for new
+ projects.][cargo/9282]
+
+Rustdoc
+-----------------------
+- [Added the `rustdoc::bare_urls` lint that warns when you have URLs
+ without hyperlinks.][81764]
+
+Compatibility Notes
+-------------------
+- [Implement token-based handling of attributes during expansion][82608]
+- [`Ipv4::from_str` will now reject octal format IP addresses in addition
+ to rejecting hexadecimal IP addresses.][83652] The octal format can lead
+ to confusion and potential security vulnerabilities and [is no
+ longer recommended][ietf6943].
+- [The added `BITS` constant may conflict with external definitions.][85667]
+ In particular, this was known to be a problem in the `lexical-core` crate,
+ but they have published fixes for semantic versions 0.4 through 0.7. To
+ update this dependency alone, use `cargo update -p lexical-core`.
+
+Internal Only
+-------------
+These changes provide no direct user facing benefits, but represent significant
+improvements to the internals and overall performance of rustc and
+related tools.
+
+- [Rework the `std::sys::windows::alloc` implementation.][83065]
+- [rustdoc: Don't enter an infer_ctxt in get_blanket_impls for impls that aren't blanket impls.][82864]
+- [rustdoc: Only look at blanket impls in `get_blanket_impls`][83681]
+- [Rework rustdoc const type][82873]
+
+[85667]: https://github.com/rust-lang/rust/pull/85667
+[83386]: https://github.com/rust-lang/rust/pull/83386
+[82771]: https://github.com/rust-lang/rust/pull/82771
+[84147]: https://github.com/rust-lang/rust/pull/84147
+[84082]: https://github.com/rust-lang/rust/pull/84082
+[83799]: https://github.com/rust-lang/rust/pull/83799
+[83681]: https://github.com/rust-lang/rust/pull/83681
+[83652]: https://github.com/rust-lang/rust/pull/83652
+[83387]: https://github.com/rust-lang/rust/pull/83387
+[82873]: https://github.com/rust-lang/rust/pull/82873
+[82864]: https://github.com/rust-lang/rust/pull/82864
+[82608]: https://github.com/rust-lang/rust/pull/82608
+[82565]: https://github.com/rust-lang/rust/pull/82565
+[80525]: https://github.com/rust-lang/rust/pull/80525
+[79278]: https://github.com/rust-lang/rust/pull/79278
+[78618]: https://github.com/rust-lang/rust/pull/78618
+[77704]: https://github.com/rust-lang/rust/pull/77704
+[83941]: https://github.com/rust-lang/rust/pull/83941
+[83065]: https://github.com/rust-lang/rust/pull/83065
+[81764]: https://github.com/rust-lang/rust/pull/81764
+[81469]: https://github.com/rust-lang/rust/pull/81469
+[cargo/9298]: https://github.com/rust-lang/cargo/pull/9298
+[cargo/9282]: https://github.com/rust-lang/cargo/pull/9282
+[cargo/9392]: https://github.com/rust-lang/cargo/pull/9392
+[`AtomicBool::fetch_update`]: https://doc.rust-lang.org/std/sync/atomic/struct.AtomicBool.html#method.fetch_update
+[`AtomicPtr::fetch_update`]: https://doc.rust-lang.org/std/sync/atomic/struct.AtomicPtr.html#method.fetch_update
+[`BTreeMap::retain`]: https://doc.rust-lang.org/std/collections/struct.BTreeMap.html#method.retain
+[`BTreeSet::retain`]: https://doc.rust-lang.org/std/collections/struct.BTreeSet.html#method.retain
+[`BufReader::seek_relative`]: https://doc.rust-lang.org/std/io/struct.BufReader.html#method.seek_relative
+[`DebugStruct::non_exhaustive`]: https://doc.rust-lang.org/std/fmt/struct.DebugStruct.html#method.finish_non_exhaustive
+[`Duration::MAX`]: https://doc.rust-lang.org/std/time/struct.Duration.html#associatedconstant.MAX
+[`Duration::ZERO`]: https://doc.rust-lang.org/std/time/struct.Duration.html#associatedconstant.ZERO
+[`Duration::is_zero`]: https://doc.rust-lang.org/std/time/struct.Duration.html#method.is_zero
+[`Duration::saturating_add`]: https://doc.rust-lang.org/std/time/struct.Duration.html#method.saturating_add
+[`Duration::saturating_mul`]: https://doc.rust-lang.org/std/time/struct.Duration.html#method.saturating_mul
+[`Duration::saturating_sub`]: https://doc.rust-lang.org/std/time/struct.Duration.html#method.saturating_sub
+[`ErrorKind::Unsupported`]: https://doc.rust-lang.org/std/io/enum.ErrorKind.html#variant.Unsupported
+[`Option::insert`]: https://doc.rust-lang.org/std/option/enum.Option.html#method.insert
+[`Ordering::is_eq`]: https://doc.rust-lang.org/std/cmp/enum.Ordering.html#method.is_eq
+[`Ordering::is_ge`]: https://doc.rust-lang.org/std/cmp/enum.Ordering.html#method.is_ge
+[`Ordering::is_gt`]: https://doc.rust-lang.org/std/cmp/enum.Ordering.html#method.is_gt
+[`Ordering::is_le`]: https://doc.rust-lang.org/std/cmp/enum.Ordering.html#method.is_le
+[`Ordering::is_lt`]: https://doc.rust-lang.org/std/cmp/enum.Ordering.html#method.is_lt
+[`Ordering::is_ne`]: https://doc.rust-lang.org/std/cmp/enum.Ordering.html#method.is_ne
+[`OsStr::eq_ignore_ascii_case`]: https://doc.rust-lang.org/std/ffi/struct.OsStr.html#method.eq_ignore_ascii_case
+[`OsStr::is_ascii`]: https://doc.rust-lang.org/std/ffi/struct.OsStr.html#method.is_ascii
+[`OsStr::make_ascii_lowercase`]: https://doc.rust-lang.org/std/ffi/struct.OsStr.html#method.make_ascii_lowercase
+[`OsStr::make_ascii_uppercase`]: https://doc.rust-lang.org/std/ffi/struct.OsStr.html#method.make_ascii_uppercase
+[`OsStr::to_ascii_lowercase`]: https://doc.rust-lang.org/std/ffi/struct.OsStr.html#method.to_ascii_lowercase
+[`OsStr::to_ascii_uppercase`]: https://doc.rust-lang.org/std/ffi/struct.OsStr.html#method.to_ascii_uppercase
+[`Peekable::peek_mut`]: https://doc.rust-lang.org/std/iter/struct.Peekable.html#method.peek_mut
+[`Rc::decrement_strong_count`]: https://doc.rust-lang.org/std/rc/struct.Rc.html#method.increment_strong_count
+[`Rc::increment_strong_count`]: https://doc.rust-lang.org/std/rc/struct.Rc.html#method.increment_strong_count
+[`Vec::extend_from_within`]: https://doc.rust-lang.org/beta/std/vec/struct.Vec.html#method.extend_from_within
+[`array::from_mut`]: https://doc.rust-lang.org/beta/std/array/fn.from_mut.html
+[`array::from_ref`]: https://doc.rust-lang.org/beta/std/array/fn.from_ref.html
+[`cmp::max_by_key`]: https://doc.rust-lang.org/beta/std/cmp/fn.max_by_key.html
+[`cmp::max_by`]: https://doc.rust-lang.org/beta/std/cmp/fn.max_by.html
+[`cmp::min_by_key`]: https://doc.rust-lang.org/beta/std/cmp/fn.min_by_key.html
+[`cmp::min_by`]: https://doc.rust-lang.org/beta/std/cmp/fn.min_by.html
+[`f32::is_subnormal`]: https://doc.rust-lang.org/std/primitive.f64.html#method.is_subnormal
+[`f64::is_subnormal`]: https://doc.rust-lang.org/std/primitive.f64.html#method.is_subnormal
+[ietf6943]: https://datatracker.ietf.org/doc/html/rfc6943#section-3.1.1
+
+
Version 1.52.1 (2021-05-10)
============================
- [Rustc now catches more cases of `pub_use_of_private_extern_crate`][80763]
- [Changes in how proc macros handle whitespace may lead to panics when used
with older `proc-macro-hack` versions. A `cargo update` should be sufficient to fix this in all cases.][84136]
+- [Turn `#[derive]` into a regular macro attribute][79078]
[84136]: https://github.com/rust-lang/rust/issues/84136
[80763]: https://github.com/rust-lang/rust/pull/80763
[78429]: https://github.com/rust-lang/rust/pull/78429
[82733]: https://github.com/rust-lang/rust/pull/82733
[82594]: https://github.com/rust-lang/rust/pull/82594
+[79078]: https://github.com/rust-lang/rust/pull/79078
[cargo/9181]: https://github.com/rust-lang/cargo/pull/9181
[`char::MAX`]: https://doc.rust-lang.org/std/primitive.char.html#associatedconstant.MAX
[`char::REPLACEMENT_CHARACTER`]: https://doc.rust-lang.org/std/primitive.char.html#associatedconstant.REPLACEMENT_CHARACTER
(m_smallest_normalized, m_smallest_normalized, "-0x1p-125", Status::OK, Category::Normal),
];
- for &(x, y, e_result, e_status, e_category) in &special_cases[..] {
+ for (x, y, e_result, e_status, e_category) in special_cases {
let status;
let result = unpack!(status=, x + y);
assert_eq!(status, e_status);
(m_smallest_normalized, m_smallest_normalized, "0x0p+0", Status::OK, Category::Zero),
];
- for &(x, y, e_result, e_status, e_category) in &special_cases[..] {
+ for (x, y, e_result, e_status, e_category) in special_cases {
let status;
let result = unpack!(status=, x - y);
assert_eq!(status, e_status);
(m_smallest_normalized, m_smallest_normalized, "0x0p+0", underflow_status, Category::Zero),
];
- for &(x, y, e_result, e_status, e_category) in &special_cases[..] {
+ for (x, y, e_result, e_status, e_category) in special_cases {
let status;
let result = unpack!(status=, x * y);
assert_eq!(status, e_status);
(m_smallest_normalized, m_smallest_normalized, "0x1p+0", Status::OK, Category::Normal),
];
- for &(x, y, e_result, e_status, e_category) in &special_cases[..] {
+ for (x, y, e_result, e_status, e_category) in special_cases {
let status;
let result = unpack!(status=, x / y);
assert_eq!(status, e_status);
(0x7ff8000000000000, 0x3ff0000000000000, Category::NaN, Round::NearestTiesToEven),
];
- for &(op1, op2, expected, round) in &data {
+ for (op1, op2, expected, round) in data {
{
let mut a1 = DoubleDouble::from_bits(op1);
let a2 = DoubleDouble::from_bits(op2);
),
];
- for &(op1, op2, expected, round) in &data {
+ for (op1, op2, expected, round) in data {
{
let mut a1 = DoubleDouble::from_bits(op1);
let a2 = DoubleDouble::from_bits(op2);
),
];
- for &(op1, op2, expected, round) in &data {
+ for (op1, op2, expected, round) in data {
let mut a1 = DoubleDouble::from_bits(op1);
let a2 = DoubleDouble::from_bits(op2);
a1 = a1.sub_r(a2, round).value;
(0, 0x3ff0000000000000, Category::Zero, Round::NearestTiesToEven),
];
- for &(op1, op2, expected, round) in &data {
+ for (op1, op2, expected, round) in data {
{
let mut a1 = DoubleDouble::from_bits(op1);
let a2 = DoubleDouble::from_bits(op2);
),
];
- for &(op1, op2, expected, round) in &data {
+ for (op1, op2, expected, round) in data {
{
let mut a1 = DoubleDouble::from_bits(op1);
let a2 = DoubleDouble::from_bits(op2);
),
];
- for &(op1, op2, expected, round) in &data {
+ for (op1, op2, expected, round) in data {
let mut a1 = DoubleDouble::from_bits(op1);
let a2 = DoubleDouble::from_bits(op2);
a1 = a1.div_r(a2, round).value;
),
];
- for &(op1, op2, expected) in &data {
+ for (op1, op2, expected) in data {
let a1 = DoubleDouble::from_bits(op1);
let a2 = DoubleDouble::from_bits(op2);
let result = a1.ieee_rem(a2).value;
),
];
- for &(op1, op2, expected) in &data {
+ for (op1, op2, expected) in data {
let a1 = DoubleDouble::from_bits(op1);
let a2 = DoubleDouble::from_bits(op2);
let r = (a1 % a2).value;
(0x7ff0000000000000, 0x7ff0000000000000, Some(Ordering::Equal)),
];
- for &(op1, op2, expected) in &data {
+ for (op1, op2, expected) in data {
let a1 = DoubleDouble::from_bits(op1);
let a2 = DoubleDouble::from_bits(op2);
assert_eq!(expected, a1.partial_cmp(&a2), "compare({:#x}, {:#x})", op1, op2,);
(0x7ff0000000000000, 0x7ff0000000000000, true),
];
- for &(op1, op2, expected) in &data {
+ for (op1, op2, expected) in data {
let a1 = DoubleDouble::from_bits(op1);
let a2 = DoubleDouble::from_bits(op2);
assert_eq!(expected, a1.bitwise_eq(a2), "{:#x} = {:#x}", op1, op2);
PatKind::Ident(_, _, Some(p)) => p.walk(it),
// Walk into each field of struct.
- PatKind::Struct(_, fields, _) => fields.iter().for_each(|field| field.pat.walk(it)),
+ PatKind::Struct(_, _, fields, _) => fields.iter().for_each(|field| field.pat.walk(it)),
// Sequence of patterns.
- PatKind::TupleStruct(_, s) | PatKind::Tuple(s) | PatKind::Slice(s) | PatKind::Or(s) => {
- s.iter().for_each(|p| p.walk(it))
- }
+ PatKind::TupleStruct(_, _, s)
+ | PatKind::Tuple(s)
+ | PatKind::Slice(s)
+ | PatKind::Or(s) => s.iter().for_each(|p| p.walk(it)),
// Trivial wrappers over inner patterns.
PatKind::Box(s) | PatKind::Ref(s, _) | PatKind::Paren(s) => s.walk(it),
/// A struct or struct variant pattern (e.g., `Variant {x, y, ..}`).
/// The `bool` is `true` in the presence of a `..`.
- Struct(Path, Vec<PatField>, /* recovered */ bool),
+ Struct(Option<QSelf>, Path, Vec<PatField>, /* recovered */ bool),
/// A tuple struct/variant pattern (`Variant(x, y, .., z)`).
- TupleStruct(Path, Vec<P<Pat>>),
+ TupleStruct(Option<QSelf>, Path, Vec<P<Pat>>),
/// An or-pattern `A | B | C`.
/// Invariant: `pats.len() >= 2`.
#[derive(Clone, Encodable, Decodable, Debug)]
pub struct StructExpr {
+ pub qself: Option<QSelf>,
pub path: Path,
pub fields: Vec<ExprField>,
pub rest: StructRest,
Nonterminal::NtMeta(attr_item) => attr_item.tokens_mut(),
Nonterminal::NtPath(path) => path.tokens_mut(),
Nonterminal::NtVis(vis) => vis.tokens_mut(),
- _ => panic!("Called tokens_mut on {:?}", self),
+ Nonterminal::NtBlock(block) => block.tokens_mut(),
+ Nonterminal::NtIdent(..) | Nonterminal::NtLifetime(..) | Nonterminal::NtTT(..) => None,
}
}
}
#![feature(box_patterns)]
#![cfg_attr(bootstrap, feature(const_fn_unsize))]
#![feature(const_fn_transmute)]
-#![feature(const_panic)]
#![feature(crate_visibility_modifier)]
#![feature(iter_zip)]
#![feature(label_break_value)]
#![feature(nll)]
+#![feature(min_specialization)]
#![recursion_limit = "256"]
#[macro_use]
visit_opt(sub, |sub| vis.visit_pat(sub));
}
PatKind::Lit(e) => vis.visit_expr(e),
- PatKind::TupleStruct(path, elems) => {
+ PatKind::TupleStruct(qself, path, elems) => {
+ vis.visit_qself(qself);
vis.visit_path(path);
visit_vec(elems, |elem| vis.visit_pat(elem));
}
vis.visit_qself(qself);
vis.visit_path(path);
}
- PatKind::Struct(path, fields, _etc) => {
+ PatKind::Struct(qself, path, fields, _etc) => {
+ vis.visit_qself(qself);
vis.visit_path(path);
fields.flat_map_in_place(|field| vis.flat_map_pat_field(field));
}
}
ExprKind::MacCall(mac) => vis.visit_mac_call(mac),
ExprKind::Struct(se) => {
- let StructExpr { path, fields, rest } = se.deref_mut();
+ let StructExpr { qself, path, fields, rest } = se.deref_mut();
+ vis.visit_qself(qself);
vis.visit_path(path);
fields.flat_map_in_place(|field| vis.flat_map_expr_field(field));
match rest {
AttrAnnotatedTokenTree::Attributes(data) => {
let mut outer_attrs = Vec::new();
let mut inner_attrs = Vec::new();
- let attrs: Vec<_> = data.attrs.clone().into();
- for attr in attrs {
+ for attr in &data.attrs {
match attr.style {
crate::AttrStyle::Outer => {
assert!(
// so we never reach this code.
let mut builder = TokenStreamBuilder::new();
- for inner_attr in &inner_attrs {
+ for inner_attr in inner_attrs {
builder.push(inner_attr.tokens().to_tokenstream());
}
builder.push(delim_tokens.clone());
pub fn walk_pat<'a, V: Visitor<'a>>(visitor: &mut V, pattern: &'a Pat) {
match pattern.kind {
- PatKind::TupleStruct(ref path, ref elems) => {
+ PatKind::TupleStruct(ref opt_qself, ref path, ref elems) => {
+ if let Some(ref qself) = *opt_qself {
+ visitor.visit_ty(&qself.ty);
+ }
visitor.visit_path(path, pattern.id);
walk_list!(visitor, visit_pat, elems);
}
}
visitor.visit_path(path, pattern.id)
}
- PatKind::Struct(ref path, ref fields, _) => {
+ PatKind::Struct(ref opt_qself, ref path, ref fields, _) => {
+ if let Some(ref qself) = *opt_qself {
+ visitor.visit_ty(&qself.ty);
+ }
visitor.visit_path(path, pattern.id);
walk_list!(visitor, visit_pat_field, fields);
}
visitor.visit_anon_const(count)
}
ExprKind::Struct(ref se) => {
+ if let Some(ref qself) = se.qself {
+ visitor.visit_ty(&qself.ty);
+ }
visitor.visit_path(&se.path, expression.id);
walk_list!(visitor, visit_expr_field, &se.fields);
match &se.rest {
hir::ExprKind::Struct(
self.arena.alloc(self.lower_qpath(
e.id,
- &None,
+ &se.qself,
&se.path,
ParamMode::Optional,
ImplTraitContext::disallowed(),
/// It is not a complete check, but just tries to reject most paths early
/// if they are not tuple structs.
/// Type checking will take care of the full validation later.
- fn extract_tuple_struct_path<'a>(&mut self, expr: &'a Expr) -> Option<&'a Path> {
- // For tuple struct destructuring, it must be a non-qualified path (like in patterns).
- if let ExprKind::Path(None, path) = &expr.kind {
- // Does the path resolves to something disallowed in a tuple struct/variant pattern?
+ fn extract_tuple_struct_path<'a>(
+ &mut self,
+ expr: &'a Expr,
+ ) -> Option<(&'a Option<QSelf>, &'a Path)> {
+ if let ExprKind::Path(qself, path) = &expr.kind {
+ // Does the path resolve to something disallowed in a tuple struct/variant pattern?
if let Some(partial_res) = self.resolver.get_partial_res(expr.id) {
if partial_res.unresolved_segments() == 0
&& !partial_res.base_res().expected_in_tuple_struct_pat()
return None;
}
}
- return Some(path);
+ return Some((qself, path));
}
None
}
}
// Tuple structs.
ExprKind::Call(callee, args) => {
- if let Some(path) = self.extract_tuple_struct_path(callee) {
+ if let Some((qself, path)) = self.extract_tuple_struct_path(callee) {
let (pats, rest) = self.destructure_sequence(
args,
"tuple struct or variant",
);
let qpath = self.lower_qpath(
callee.id,
- &None,
+ qself,
path,
ParamMode::Optional,
ImplTraitContext::disallowed(),
}));
let qpath = self.lower_qpath(
lhs.id,
- &None,
+ &se.qself,
&se.path,
ParamMode::Optional,
ImplTraitContext::disallowed(),
use rustc_ast::{self as ast, *};
use rustc_ast_pretty::pprust;
use rustc_data_structures::captures::Captures;
-use rustc_data_structures::fx::FxHashSet;
+use rustc_data_structures::fx::{FxHashMap, FxHashSet};
use rustc_data_structures::sync::Lrc;
use rustc_errors::{struct_span_err, Applicability};
use rustc_hir as hir;
fn next_node_id(&mut self) -> NodeId;
- fn trait_map(&self) -> &NodeMap<Vec<hir::TraitCandidate>>;
+ fn take_trait_map(&mut self) -> NodeMap<Vec<hir::TraitCandidate>>;
fn opt_local_def_id(&self, node: NodeId) -> Option<LocalDefId>;
lifetimes_to_define: Vec::new(),
is_collecting_in_band_lifetimes: false,
in_scope_lifetimes: Vec::new(),
- allow_try_trait: Some([sym::control_flow_enum, sym::try_trait_v2][..].into()),
+ allow_try_trait: Some([sym::try_trait_v2][..].into()),
allow_gen_future: Some([sym::gen_future][..].into()),
}
.lower_crate(krate)
fn allocate_use_tree_hir_id_counters(&mut self, tree: &UseTree) {
match tree.kind {
UseTreeKind::Simple(_, id1, id2) => {
- for &id in &[id1, id2] {
+ for id in [id1, id2] {
self.lctx.allocate_hir_id_counter(id);
}
}
let proc_macros =
c.proc_macros.iter().map(|id| self.node_id_to_hir_id[*id].unwrap()).collect();
- let trait_map = self
- .resolver
- .trait_map()
- .iter()
- .filter_map(|(&k, v)| {
- self.node_id_to_hir_id.get(k).and_then(|id| id.as_ref()).map(|id| (*id, v.clone()))
- })
- .collect();
+ let mut trait_map: FxHashMap<_, FxHashMap<_, _>> = FxHashMap::default();
+ for (k, v) in self.resolver.take_trait_map().into_iter() {
+ if let Some(Some(hir_id)) = self.node_id_to_hir_id.get(k) {
+ let map = trait_map.entry(hir_id.owner).or_default();
+ map.insert(hir_id.local_id, v.into_boxed_slice());
+ }
+ }
let mut def_id_to_hir_id = IndexVec::default();
break self.lower_pat_ident(pattern, binding_mode, ident, lower_sub);
}
PatKind::Lit(ref e) => break hir::PatKind::Lit(self.lower_expr(e)),
- PatKind::TupleStruct(ref path, ref pats) => {
+ PatKind::TupleStruct(ref qself, ref path, ref pats) => {
let qpath = self.lower_qpath(
pattern.id,
- &None,
+ qself,
path,
ParamMode::Optional,
ImplTraitContext::disallowed(),
);
break hir::PatKind::Path(qpath);
}
- PatKind::Struct(ref path, ref fields, etc) => {
+ PatKind::Struct(ref qself, ref path, ref fields, etc) => {
let qpath = self.lower_qpath(
pattern.id,
- &None,
+ qself,
path,
ParamMode::Optional,
ImplTraitContext::disallowed(),
self.err_handler()
.struct_span_err(
*span,
- "only foreign or `unsafe extern \"C\" functions may be C-variadic",
+ "only foreign or `unsafe extern \"C\"` functions may be C-variadic",
)
.emit();
}
) {
let mut max_param: Option<ParamKindOrd> = None;
let mut out_of_order = FxHashMap::default();
- let mut param_idents = vec![];
+ let mut param_idents = Vec::with_capacity(generics.len());
- for param in generics {
- let ident = Some(param.ident.to_string());
- let (kind, bounds, span) = (¶m.kind, Some(&*param.bounds), param.ident.span);
+ for (idx, param) in generics.iter().enumerate() {
+ let ident = param.ident;
+ let (kind, bounds, span) = (¶m.kind, ¶m.bounds, ident.span);
let (ord_kind, ident) = match ¶m.kind {
- GenericParamKind::Lifetime => (ParamKindOrd::Lifetime, ident),
- GenericParamKind::Type { default: _ } => (ParamKindOrd::Type, ident),
+ GenericParamKind::Lifetime => (ParamKindOrd::Lifetime, ident.to_string()),
+ GenericParamKind::Type { default: _ } => (ParamKindOrd::Type, ident.to_string()),
GenericParamKind::Const { ref ty, kw_span: _, default: _ } => {
let ty = pprust::ty_to_string(ty);
let unordered = sess.features_untracked().unordered_const_ty_params();
- (ParamKindOrd::Const { unordered }, Some(format!("const {}: {}", param.ident, ty)))
+ (ParamKindOrd::Const { unordered }, format!("const {}: {}", ident, ty))
}
};
- if let Some(ident) = ident {
- param_idents.push((kind, ord_kind, bounds, param_idents.len(), ident));
- }
- let max_param = &mut max_param;
+ param_idents.push((kind, ord_kind, bounds, idx, ident));
match max_param {
- Some(max_param) if *max_param > ord_kind => {
- let entry = out_of_order.entry(ord_kind).or_insert((*max_param, vec![]));
+ Some(max_param) if max_param > ord_kind => {
+ let entry = out_of_order.entry(ord_kind).or_insert((max_param, vec![]));
entry.1.push(span);
}
- Some(_) | None => *max_param = Some(ord_kind),
+ Some(_) | None => max_param = Some(ord_kind),
};
}
- let mut ordered_params = "<".to_string();
if !out_of_order.is_empty() {
+ let mut ordered_params = "<".to_string();
param_idents.sort_by_key(|&(_, po, _, i, _)| (po, i));
let mut first = true;
for (kind, _, bounds, _, ident) in param_idents {
ordered_params += ", ";
}
ordered_params += &ident;
- if let Some(bounds) = bounds {
- if !bounds.is_empty() {
- ordered_params += ": ";
- ordered_params += &pprust::bounds_to_string(&bounds);
- }
+
+ if !bounds.is_empty() {
+ ordered_params += ": ";
+ ordered_params += &pprust::bounds_to_string(&bounds);
}
+
match kind {
GenericParamKind::Type { default: Some(default) } => {
ordered_params += " = ";
}
GenericParamKind::Type { default: None } => (),
GenericParamKind::Lifetime => (),
- // FIXME(const_generics_defaults)
- GenericParamKind::Const { ty: _, kw_span: _, default: _ } => (),
+ GenericParamKind::Const { ty: _, kw_span: _, default: Some(default) } => {
+ ordered_params += " = ";
+ ordered_params += &pprust::expr_to_string(&*default.value);
+ }
+ GenericParamKind::Const { ty: _, kw_span: _, default: None } => (),
}
first = false;
}
- }
- ordered_params += ">";
- for (param_ord, (max_param, spans)) in &out_of_order {
- let mut err =
- handler.struct_span_err(
+ ordered_params += ">";
+
+ for (param_ord, (max_param, spans)) in &out_of_order {
+ let mut err = handler.struct_span_err(
spans.clone(),
&format!(
"{} parameters must be declared prior to {} parameters",
param_ord, max_param,
),
);
- err.span_suggestion(
- span,
- &format!(
- "reorder the parameters: lifetimes, {}",
- if sess.features_untracked().const_generics {
- "then consts and types"
- } else {
- "then types, then consts"
- }
- ),
- ordered_params.clone(),
- Applicability::MachineApplicable,
- );
- err.emit();
+ err.span_suggestion(
+ span,
+ &format!(
+ "reorder the parameters: lifetimes, {}",
+ if sess.features_untracked().unordered_const_ty_params() {
+ "then consts and types"
+ } else {
+ "then types, then consts"
+ }
+ ),
+ ordered_params.clone(),
+ Applicability::MachineApplicable,
+ );
+ err.emit();
+ }
}
}
}}
gate_doc!(
- include => external_doc
cfg => doc_cfg
masked => doc_masked
notable_trait => doc_notable_trait
"async closures are unstable",
"to use an async block, remove the `||`: `async {`"
);
+ gate_all!(more_qualified_paths, "usage of qualified paths in this context is experimental");
gate_all!(generators, "yield syntax is experimental");
gate_all!(raw_ref_op, "raw address of syntax is experimental");
gate_all!(const_trait_bound_opt_out, "`?const` on trait bounds is experimental");
#![feature(bindings_after_at)]
#![feature(iter_is_partitioned)]
-#![feature(box_syntax)]
#![feature(box_patterns)]
#![recursion_limit = "256"]
fn print_expr_struct(
&mut self,
+ qself: &Option<ast::QSelf>,
path: &ast::Path,
fields: &[ast::ExprField],
rest: &ast::StructRest,
) {
- self.print_path(path, true, 0);
+ if let Some(qself) = qself {
+ self.print_qpath(path, qself, true);
+ } else {
+ self.print_path(path, true, 0);
+ }
self.s.word("{");
self.commasep_cmnt(
Consistent,
self.print_expr_repeat(element, count);
}
ast::ExprKind::Struct(ref se) => {
- self.print_expr_struct(&se.path, &se.fields, &se.rest);
+ self.print_expr_struct(&se.qself, &se.path, &se.fields, &se.rest);
}
ast::ExprKind::Tup(ref exprs) => {
self.print_expr_tup(exprs);
self.print_pat(p);
}
}
- PatKind::TupleStruct(ref path, ref elts) => {
- self.print_path(path, true, 0);
+ PatKind::TupleStruct(ref qself, ref path, ref elts) => {
+ if let Some(qself) = qself {
+ self.print_qpath(path, qself, true);
+ } else {
+ self.print_path(path, true, 0);
+ }
self.popen();
self.commasep(Inconsistent, &elts[..], |s, p| s.print_pat(p));
self.pclose();
PatKind::Path(Some(ref qself), ref path) => {
self.print_qpath(path, qself, false);
}
- PatKind::Struct(ref path, ref fields, etc) => {
- self.print_path(path, true, 0);
+ PatKind::Struct(ref qself, ref path, ref fields, etc) => {
+ if let Some(qself) = qself {
+ self.print_qpath(path, qself, true);
+ } else {
+ self.print_path(path, true, 0);
+ }
self.nbsp();
self.word_space("{");
self.commasep_cmnt(
let msg = "format argument must be a string literal";
let fmt_sp = efmt.span;
+ let efmt_kind_is_lit: bool = matches!(efmt.kind, ast::ExprKind::Lit(_));
let (fmt_str, fmt_style, fmt_span) = match expr_to_spanned_string(ecx, efmt, msg) {
Ok(mut fmt) if append_newline => {
fmt.0 = Symbol::intern(&format!("{}\n", fmt.0));
if !parser.errors.is_empty() {
let err = parser.errors.remove(0);
- let sp = fmt_span.from_inner(err.span);
+ let sp = if efmt_kind_is_lit {
+ fmt_span.from_inner(err.span)
+ } else {
+ // The format string could be another macro invocation, e.g.:
+ // format!(concat!("abc", "{}"), 4);
+ // However, `err.span` is an inner span relative to the *result* of
+ // the macro invocation, which is why we would get a nonsensical
+ // result calling `fmt_span.from_inner(err.span)` as above, and
+ // might even end up inside a multibyte character (issue #86085).
+ // Therefore, we conservatively report the error for the entire
+ // argument span here.
+ fmt_span
+ };
let mut e = ecx.struct_span_err(sp, &format!("invalid format string: {}", err.description));
e.span_label(sp, err.label + " in format string");
if let Some(note) = err.note {
"allow_fail",
cx.expr_bool(sp, should_fail(&cx.sess, &item)),
),
+ // compile_fail: true | false
+ field("compile_fail", cx.expr_bool(sp, false)),
+ // no_run: true | false
+ field("no_run", cx.expr_bool(sp, false)),
// should_panic: ...
field(
"should_panic",
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "cf1de2fe8c75bc145a2f577add951f8134889b4795d47466a54a5c846d691693"
-[[package]]
-name = "byteorder"
-version = "1.4.2"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "ae44d1a3d5a19df61dd0c8beb138458ac2a53a7ac09eba97d55592540004306b"
-
[[package]]
name = "cfg-if"
version = "1.0.0"
[[package]]
name = "cranelift-bforest"
-version = "0.73.0"
-source = "git+https://github.com/bytecodealliance/wasmtime/?branch=main#45bee40f338c631bff4a799288101ba328c7ad36"
+version = "0.74.0"
+source = "git+https://github.com/bytecodealliance/wasmtime.git?branch=main#76c6b83f6a21a12a11d4f890490f8acb6329a600"
dependencies = [
"cranelift-entity",
]
[[package]]
name = "cranelift-codegen"
-version = "0.73.0"
-source = "git+https://github.com/bytecodealliance/wasmtime/?branch=main#45bee40f338c631bff4a799288101ba328c7ad36"
+version = "0.74.0"
+source = "git+https://github.com/bytecodealliance/wasmtime.git?branch=main#76c6b83f6a21a12a11d4f890490f8acb6329a600"
dependencies = [
- "byteorder",
"cranelift-bforest",
"cranelift-codegen-meta",
"cranelift-codegen-shared",
"regalloc",
"smallvec",
"target-lexicon",
- "thiserror",
]
[[package]]
name = "cranelift-codegen-meta"
-version = "0.73.0"
-source = "git+https://github.com/bytecodealliance/wasmtime/?branch=main#45bee40f338c631bff4a799288101ba328c7ad36"
+version = "0.74.0"
+source = "git+https://github.com/bytecodealliance/wasmtime.git?branch=main#76c6b83f6a21a12a11d4f890490f8acb6329a600"
dependencies = [
"cranelift-codegen-shared",
"cranelift-entity",
[[package]]
name = "cranelift-codegen-shared"
-version = "0.73.0"
-source = "git+https://github.com/bytecodealliance/wasmtime/?branch=main#45bee40f338c631bff4a799288101ba328c7ad36"
+version = "0.74.0"
+source = "git+https://github.com/bytecodealliance/wasmtime.git?branch=main#76c6b83f6a21a12a11d4f890490f8acb6329a600"
[[package]]
name = "cranelift-entity"
-version = "0.73.0"
-source = "git+https://github.com/bytecodealliance/wasmtime/?branch=main#45bee40f338c631bff4a799288101ba328c7ad36"
+version = "0.74.0"
+source = "git+https://github.com/bytecodealliance/wasmtime.git?branch=main#76c6b83f6a21a12a11d4f890490f8acb6329a600"
[[package]]
name = "cranelift-frontend"
-version = "0.73.0"
-source = "git+https://github.com/bytecodealliance/wasmtime/?branch=main#45bee40f338c631bff4a799288101ba328c7ad36"
+version = "0.74.0"
+source = "git+https://github.com/bytecodealliance/wasmtime.git?branch=main#76c6b83f6a21a12a11d4f890490f8acb6329a600"
dependencies = [
"cranelift-codegen",
"log",
[[package]]
name = "cranelift-jit"
-version = "0.73.0"
-source = "git+https://github.com/bytecodealliance/wasmtime/?branch=main#45bee40f338c631bff4a799288101ba328c7ad36"
+version = "0.74.0"
+source = "git+https://github.com/bytecodealliance/wasmtime.git?branch=main#76c6b83f6a21a12a11d4f890490f8acb6329a600"
dependencies = [
"anyhow",
"cranelift-codegen",
"cranelift-entity",
"cranelift-module",
"cranelift-native",
- "errno",
"libc",
"log",
"region",
[[package]]
name = "cranelift-module"
-version = "0.73.0"
-source = "git+https://github.com/bytecodealliance/wasmtime/?branch=main#45bee40f338c631bff4a799288101ba328c7ad36"
+version = "0.74.0"
+source = "git+https://github.com/bytecodealliance/wasmtime.git?branch=main#76c6b83f6a21a12a11d4f890490f8acb6329a600"
dependencies = [
"anyhow",
"cranelift-codegen",
"cranelift-entity",
"log",
- "thiserror",
]
[[package]]
name = "cranelift-native"
-version = "0.73.0"
-source = "git+https://github.com/bytecodealliance/wasmtime/?branch=main#45bee40f338c631bff4a799288101ba328c7ad36"
+version = "0.74.0"
+source = "git+https://github.com/bytecodealliance/wasmtime.git?branch=main#76c6b83f6a21a12a11d4f890490f8acb6329a600"
dependencies = [
"cranelift-codegen",
"target-lexicon",
[[package]]
name = "cranelift-object"
-version = "0.73.0"
-source = "git+https://github.com/bytecodealliance/wasmtime/?branch=main#45bee40f338c631bff4a799288101ba328c7ad36"
+version = "0.74.0"
+source = "git+https://github.com/bytecodealliance/wasmtime.git?branch=main#76c6b83f6a21a12a11d4f890490f8acb6329a600"
dependencies = [
"anyhow",
"cranelift-codegen",
"cfg-if",
]
-[[package]]
-name = "errno"
-version = "0.2.7"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "fa68f2fb9cae9d37c9b2b3584aba698a2e97f72d7aef7b9f7aa71d8b54ce46fe"
-dependencies = [
- "errno-dragonfly",
- "libc",
- "winapi",
-]
-
-[[package]]
-name = "errno-dragonfly"
-version = "0.1.1"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "14ca354e36190500e1e1fb267c647932382b54053c50b14970856c0b00a35067"
-dependencies = [
- "gcc",
- "libc",
-]
-
-[[package]]
-name = "gcc"
-version = "0.3.55"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "8f5f3913fa0bfe7ee1fd8248b6b9f42a5af4b9d65ec2dd2c3c26132b950ecfc2"
-
[[package]]
name = "gimli"
-version = "0.23.0"
+version = "0.24.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "f6503fe142514ca4799d4c26297c4248239fe8838d827db6bd6065c6ed29a6ce"
+checksum = "0e4075386626662786ddb0ec9081e7c7eeb1ba31951f447ca780ef9f5d568189"
dependencies = [
"indexmap",
]
[[package]]
name = "object"
-version = "0.23.0"
+version = "0.24.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "a9a7ab5d64814df0fe4a4b5ead45ed6c5f181ee3ff04ba344313a6c80446c5d4"
+checksum = "1a5b3dd1c072ee7963717671d1ca129f1048fda25edea6b752bfc71ac8854170"
dependencies = [
"crc32fast",
"indexmap",
]
-[[package]]
-name = "proc-macro2"
-version = "1.0.24"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "1e0704ee1a7e00d7bb417d0770ea303c1bccbabf0ef1667dae92b5967f5f8a71"
-dependencies = [
- "unicode-xid",
-]
-
-[[package]]
-name = "quote"
-version = "1.0.9"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "c3d0b9745dc2debf507c8422de05d7226cc1f0644216dfdfead988f9b1ab32a7"
-dependencies = [
- "proc-macro2",
-]
-
[[package]]
name = "regalloc"
version = "0.0.31"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "fe0f37c9e8f3c5a4a66ad655a93c74daac4ad00c441533bf5c6e7990bb42604e"
-[[package]]
-name = "syn"
-version = "1.0.60"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "c700597eca8a5a762beb35753ef6b94df201c81cca676604f547495a0d7f0081"
-dependencies = [
- "proc-macro2",
- "quote",
- "unicode-xid",
-]
-
[[package]]
name = "target-lexicon"
version = "0.12.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "64ae3b39281e4b14b8123bdbaddd472b7dfe215e444181f2f9d2443c2444f834"
-[[package]]
-name = "thiserror"
-version = "1.0.24"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "e0f4a65597094d4483ddaed134f409b2cb7c1beccf25201a9f73c719254fa98e"
-dependencies = [
- "thiserror-impl",
-]
-
-[[package]]
-name = "thiserror-impl"
-version = "1.0.24"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "7765189610d8241a44529806d6fd1f2e0a08734313a35d5b3a556f92b381f3c0"
-dependencies = [
- "proc-macro2",
- "quote",
- "syn",
-]
-
-[[package]]
-name = "unicode-xid"
-version = "0.2.1"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "f7fe0bb3479651439c9112f72b6c505038574c9fbb575ed1bf3b797fa39dd564"
-
[[package]]
name = "winapi"
version = "0.3.9"
[dependencies]
# These have to be in sync with each other
-cranelift-codegen = { git = "https://github.com/bytecodealliance/wasmtime/", branch = "main", features = ["unwind"] }
-cranelift-frontend = { git = "https://github.com/bytecodealliance/wasmtime/", branch = "main" }
-cranelift-module = { git = "https://github.com/bytecodealliance/wasmtime/", branch = "main" }
-cranelift-native = { git = "https://github.com/bytecodealliance/wasmtime/", branch = "main" }
-cranelift-jit = { git = "https://github.com/bytecodealliance/wasmtime/", branch = "main", optional = true }
-cranelift-object = { git = "https://github.com/bytecodealliance/wasmtime/", branch = "main" }
+cranelift-codegen = { git = "https://github.com/bytecodealliance/wasmtime.git", branch = "main", features = ["unwind"] }
+cranelift-frontend = { git = "https://github.com/bytecodealliance/wasmtime.git", branch = "main" }
+cranelift-module = { git = "https://github.com/bytecodealliance/wasmtime.git", branch = "main" }
+cranelift-native = { git = "https://github.com/bytecodealliance/wasmtime.git", branch = "main" }
+cranelift-jit = { git = "https://github.com/bytecodealliance/wasmtime.git", branch = "main", optional = true }
+cranelift-object = { git = "https://github.com/bytecodealliance/wasmtime.git", branch = "main" }
target-lexicon = "0.12.0"
-gimli = { version = "0.23.0", default-features = false, features = ["write"]}
-object = { version = "0.23.0", default-features = false, features = ["std", "read_core", "write", "archive", "coff", "elf", "macho", "pe"] }
+gimli = { version = "0.24.0", default-features = false, features = ["write"]}
+object = { version = "0.24.0", default-features = false, features = ["std", "read_core", "write", "archive", "coff", "elf", "macho", "pe"] }
ar = { git = "https://github.com/bjorn3/rust-ar.git", branch = "do_not_remove_cg_clif_ranlib" }
indexmap = "1.0.2"
smallvec = "1.6.1"
# Uncomment to use local checkout of cranelift
-#[patch."https://github.com/bytecodealliance/wasmtime/"]
+#[patch."https://github.com/bytecodealliance/wasmtime.git"]
#cranelift-codegen = { path = "../wasmtime/cranelift/codegen" }
#cranelift-frontend = { path = "../wasmtime/cranelift/frontend" }
#cranelift-module = { path = "../wasmtime/cranelift/module" }
-#cranelift-native = { path = ../wasmtime/cranelift/native" }
+#cranelift-native = { path = "../wasmtime/cranelift/native" }
#cranelift-jit = { path = "../wasmtime/cranelift/jit" }
#cranelift-object = { path = "../wasmtime/cranelift/object" }
opt-level = 0
debug = false
-[profile.dev.package.syn]
-opt-level = 0
-debug = false
-
-[profile.release.package.syn]
-opt-level = 0
-debug = false
-
[package.metadata.rust-analyzer]
rustc_private = true
[[package]]
name = "cc"
-version = "1.0.67"
+version = "1.0.68"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "e3c69b077ad434294d3ce9f1f6143a2a4b89a8a2d54ef813d85003a4fd1137fd"
+checksum = "4a72c244c1ff497a746a7e1fb3d14bd08420ecda70c8f25c7112f2781652d787"
[[package]]
name = "cfg-if"
[[package]]
name = "compiler_builtins"
-version = "0.1.40"
+version = "0.1.43"
dependencies = [
"rustc-std-workspace-core",
]
[[package]]
name = "libc"
-version = "0.2.94"
+version = "0.2.95"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "18794a8ad5b29321f790b55d93dfba91e125cb1a9edbd4f8e3150acc771c1a5e"
+checksum = "789da6d93f1b866ffe175afc5322a4d76c038605a1c3319bb57b06967ca98a36"
dependencies = [
"rustc-std-workspace-core",
]
[[package]]
name = "rustc-demangle"
-version = "0.1.18"
+version = "0.1.19"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "6e3bad0ee36814ca07d7968269dd4b7ec89ec2da10c4bb613928d3077083c232"
+checksum = "410f7acf3cb3a44527c5d9546bad4bf4e6c460915d5f9f2fc524498bfe8f70ce"
dependencies = [
"compiler_builtins",
"rustc-std-workspace-core",
git clone https://github.com/rust-lang/compiler-builtins.git || echo "rust-lang/compiler-builtins has already been cloned"
pushd compiler-builtins
git checkout -- .
-git checkout 0.1.40
+git checkout 0.1.43
git apply ../../crate_patches/000*-compiler-builtins-*.patch
popd
--- /dev/null
+From 1d574bf5e32d51641dcacaf8ef777e95b44f6f2a Mon Sep 17 00:00:00 2001
+From: bjorn3 <bjorn3@users.noreply.github.com>
+Date: Thu, 18 Feb 2021 18:30:55 +0100
+Subject: [PATCH] Disable 128bit atomic operations
+
+Cranelift doesn't support them yet
+---
+ src/mem/mod.rs | 12 ------------
+ 1 file changed, 12 deletions(-)
+
+diff --git a/src/mem/mod.rs b/src/mem/mod.rs
+index 107762c..2d1ae10 100644
+--- a/src/mem/mod.rs
++++ b/src/mem/mod.rs
+@@ -137,10 +137,6 @@ intrinsics! {
+ pub extern "C" fn __llvm_memcpy_element_unordered_atomic_8(dest: *mut u64, src: *const u64, bytes: usize) -> () {
+ memcpy_element_unordered_atomic(dest, src, bytes);
+ }
+- #[cfg(target_has_atomic_load_store = "128")]
+- pub extern "C" fn __llvm_memcpy_element_unordered_atomic_16(dest: *mut u128, src: *const u128, bytes: usize) -> () {
+- memcpy_element_unordered_atomic(dest, src, bytes);
+- }
+
+ #[cfg(target_has_atomic_load_store = "8")]
+ pub extern "C" fn __llvm_memmove_element_unordered_atomic_1(dest: *mut u8, src: *const u8, bytes: usize) -> () {
+@@ -158,10 +154,6 @@ intrinsics! {
+ pub extern "C" fn __llvm_memmove_element_unordered_atomic_8(dest: *mut u64, src: *const u64, bytes: usize) -> () {
+ memmove_element_unordered_atomic(dest, src, bytes);
+ }
+- #[cfg(target_has_atomic_load_store = "128")]
+- pub extern "C" fn __llvm_memmove_element_unordered_atomic_16(dest: *mut u128, src: *const u128, bytes: usize) -> () {
+- memmove_element_unordered_atomic(dest, src, bytes);
+- }
+
+ #[cfg(target_has_atomic_load_store = "8")]
+ pub extern "C" fn __llvm_memset_element_unordered_atomic_1(s: *mut u8, c: u8, bytes: usize) -> () {
+@@ -179,8 +171,4 @@ intrinsics! {
+ pub extern "C" fn __llvm_memset_element_unordered_atomic_8(s: *mut u64, c: u8, bytes: usize) -> () {
+ memset_element_unordered_atomic(s, c, bytes);
+ }
+- #[cfg(target_has_atomic_load_store = "128")]
+- pub extern "C" fn __llvm_memset_element_unordered_atomic_16(s: *mut u128, c: u8, bytes: usize) -> () {
+- memset_element_unordered_atomic(s, c, bytes);
+- }
+ }
+--
+2.26.2.7.g19db9cfb68
+
+++ /dev/null
-From 7078cca3cb614e1e82da428380b4e16fc3afef46 Mon Sep 17 00:00:00 2001
-From: bjorn3 <bjorn3@users.noreply.github.com>
-Date: Thu, 21 Jan 2021 14:46:36 +0100
-Subject: [PATCH] Remove rotate_left from Int
-
----
- src/int/mod.rs | 5 -----
- 1 file changed, 5 deletions(-)
-
-diff --git a/src/int/mod.rs b/src/int/mod.rs
-index 06054c8..3bea17b 100644
---- a/src/int/mod.rs
-+++ b/src/int/mod.rs
-@@ -85,7 +85,6 @@ pub trait Int:
- fn wrapping_sub(self, other: Self) -> Self;
- fn wrapping_shl(self, other: u32) -> Self;
- fn wrapping_shr(self, other: u32) -> Self;
-- fn rotate_left(self, other: u32) -> Self;
- fn overflowing_add(self, other: Self) -> (Self, bool);
- fn leading_zeros(self) -> u32;
- }
-@@ -209,10 +208,6 @@ macro_rules! int_impl_common {
- <Self>::wrapping_shr(self, other)
- }
-
-- fn rotate_left(self, other: u32) -> Self {
-- <Self>::rotate_left(self, other)
-- }
--
- fn overflowing_add(self, other: Self) -> (Self, bool) {
- <Self>::overflowing_add(self, other)
- }
---
-2.26.2.7.g19db9cfb68
-
+++ /dev/null
-From 1d574bf5e32d51641dcacaf8ef777e95b44f6f2a Mon Sep 17 00:00:00 2001
-From: bjorn3 <bjorn3@users.noreply.github.com>
-Date: Thu, 18 Feb 2021 18:30:55 +0100
-Subject: [PATCH] Disable 128bit atomic operations
-
-Cranelift doesn't support them yet
----
- src/mem/mod.rs | 12 ------------
- 1 file changed, 12 deletions(-)
-
-diff --git a/src/mem/mod.rs b/src/mem/mod.rs
-index 107762c..2d1ae10 100644
---- a/src/mem/mod.rs
-+++ b/src/mem/mod.rs
-@@ -137,10 +137,6 @@ intrinsics! {
- pub extern "C" fn __llvm_memcpy_element_unordered_atomic_8(dest: *mut u64, src: *const u64, bytes: usize) -> () {
- memcpy_element_unordered_atomic(dest, src, bytes);
- }
-- #[cfg(target_has_atomic_load_store = "128")]
-- pub extern "C" fn __llvm_memcpy_element_unordered_atomic_16(dest: *mut u128, src: *const u128, bytes: usize) -> () {
-- memcpy_element_unordered_atomic(dest, src, bytes);
-- }
-
- #[cfg(target_has_atomic_load_store = "8")]
- pub extern "C" fn __llvm_memmove_element_unordered_atomic_1(dest: *mut u8, src: *const u8, bytes: usize) -> () {
-@@ -158,10 +154,6 @@ intrinsics! {
- pub extern "C" fn __llvm_memmove_element_unordered_atomic_8(dest: *mut u64, src: *const u64, bytes: usize) -> () {
- memmove_element_unordered_atomic(dest, src, bytes);
- }
-- #[cfg(target_has_atomic_load_store = "128")]
-- pub extern "C" fn __llvm_memmove_element_unordered_atomic_16(dest: *mut u128, src: *const u128, bytes: usize) -> () {
-- memmove_element_unordered_atomic(dest, src, bytes);
-- }
-
- #[cfg(target_has_atomic_load_store = "8")]
- pub extern "C" fn __llvm_memset_element_unordered_atomic_1(s: *mut u8, c: u8, bytes: usize) -> () {
-@@ -179,8 +171,4 @@ intrinsics! {
- pub extern "C" fn __llvm_memset_element_unordered_atomic_8(s: *mut u64, c: u8, bytes: usize) -> () {
- memset_element_unordered_atomic(s, c, bytes);
- }
-- #[cfg(target_has_atomic_load_store = "128")]
-- pub extern "C" fn __llvm_memset_element_unordered_atomic_16(s: *mut u128, c: u8, bytes: usize) -> () {
-- memset_element_unordered_atomic(s, c, bytes);
-- }
- }
---
-2.26.2.7.g19db9cfb68
-
);
let r = _mm_slli_si128(a, 16);
assert_eq_m128i(r, _mm_set1_epi8(0));
-
- #[rustfmt::skip]
- let a = _mm_setr_epi8(
- 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16,
- );
- let r = _mm_slli_si128(a, -1);
- assert_eq_m128i(_mm_set1_epi8(0), r);
-
- #[rustfmt::skip]
- let a = _mm_setr_epi8(
- 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16,
- );
- let r = _mm_slli_si128(a, -0x80000000);
- assert_eq_m128i(r, _mm_set1_epi8(0));
}
#[cfg(target_arch = "x86_64")]
8, 9, 10, 11, 12, 13, 14, 15
);
let r1 = _mm_extract_epi8(a, 0);
- let r2 = _mm_extract_epi8(a, 19);
+ let r2 = _mm_extract_epi8(a, 3);
assert_eq!(r1, 0xFF);
assert_eq!(r2, 3);
}
pub fn decode_finite<T: DecodableFloat>(v: T) -> Decoded {
match decode(v).1 {
-diff --git a/library/core/tests/num/int_macros.rs b/library/core/tests/num/int_macros.rs
-index 0475aeb..9558198 100644
---- a/library/core/tests/num/int_macros.rs
-+++ b/library/core/tests/num/int_macros.rs
-@@ -88,6 +88,7 @@ mod tests {
- assert_eq!(x.trailing_ones(), 0);
- }
-
-+ /*
- #[test]
- fn test_rotate() {
- assert_eq!(A.rotate_left(6).rotate_right(2).rotate_right(4), A);
-@@ -112,6 +113,7 @@ mod tests {
- assert_eq!(B.rotate_left(128), B);
- assert_eq!(C.rotate_left(128), C);
- }
-+ */
-
- #[test]
- fn test_swap_bytes() {
-diff --git a/library/core/tests/num/uint_macros.rs b/library/core/tests/num/uint_macros.rs
-index 04ed14f..a6e372e 100644
---- a/library/core/tests/num/uint_macros.rs
-+++ b/library/core/tests/num/uint_macros.rs
-@@ -52,6 +52,7 @@ mod tests {
- assert_eq!(x.trailing_ones(), 0);
- }
-
-+ /*
- #[test]
- fn test_rotate() {
- assert_eq!(A.rotate_left(6).rotate_right(2).rotate_right(4), A);
-@@ -76,6 +77,7 @@ mod tests {
- assert_eq!(B.rotate_left(128), B);
- assert_eq!(C.rotate_left(128), C);
- }
-+ */
-
- #[test]
- fn test_swap_bytes() {
diff --git a/library/core/tests/ptr.rs b/library/core/tests/ptr.rs
index 1a6be3a..42dbd59 100644
--- a/library/core/tests/ptr.rs
[toolchain]
-channel = "nightly-2021-04-28"
+channel = "nightly-2021-05-26"
components = ["rust-src", "rustc-dev", "llvm-tools-preview"]
+
[patch."https://github.com/rust-lang/rust-clippy"]
clippy_lints = { path = "src/tools/clippy/clippy_lints" }
-diff --git a/compiler/rustc_data_structures/Cargo.toml b/compiler/rustc_data_structures/Cargo.toml
-index 23e689fcae7..5f077b765b6 100644
---- a/compiler/rustc_data_structures/Cargo.toml
-+++ b/compiler/rustc_data_structures/Cargo.toml
-@@ -32,7 +32,6 @@ tempfile = "3.0.5"
-
- [dependencies.parking_lot]
- version = "0.11"
--features = ["nightly"]
-
- [target.'cfg(windows)'.dependencies]
- winapi = { version = "0.3", features = ["fileapi", "psapi"] }
diff --git a/library/alloc/Cargo.toml b/library/alloc/Cargo.toml
index d95b5b7f17f..00b6f0e3635 100644
--- a/library/alloc/Cargo.toml
[dependencies]
core = { path = "../core" }
--compiler_builtins = { version = "0.1.39", features = ['rustc-dep-of-std'] }
-+compiler_builtins = { version = "0.1.40", features = ['rustc-dep-of-std', 'no-asm'] }
+-compiler_builtins = { version = "0.1.40", features = ['rustc-dep-of-std'] }
++compiler_builtins = { version = "0.1.43", features = ['rustc-dep-of-std', 'no-asm'] }
[dev-dependencies]
rand = "0.7"
+ rand_xorshift = "0.2"
EOF
cat > config.toml <<EOF
pushd regex
echo "[TEST] rust-lang/regex example shootout-regex-dna"
cargo clean
+ export RUSTFLAGS="$RUSTFLAGS --cap-lints warn" # newer aho_corasick versions throw a deprecation warning
# Make sure `[codegen mono items] start` doesn't poison the diff
../build/cargo.sh build --example shootout-regex-dna --target $TARGET_TRIPLE
if [[ "$HOST_TRIPLE" = "$TARGET_TRIPLE" ]]; then
};
if !self.no_builtin_ranlib {
- match object::File::parse(&data) {
+ match object::File::parse(&*data) {
Ok(object) => {
symbol_table.insert(
entry_name.as_bytes().to_vec(),
}
}
}
+
+ fn inject_dll_import_lib(
+ &mut self,
+ _lib_name: &str,
+ _dll_imports: &[rustc_middle::middle::cstore::DllImport],
+ _tmpdir: &rustc_data_structures::temp_dir::MaybeTempDir,
+ ) {
+ bug!("injecting dll imports is not supported");
+ }
}
impl<'a> ArArchiveBuilder<'a> {
// Verify function
verify_func(tcx, &clif_comments, &context.func);
- // Perform rust specific optimizations
- tcx.sess.time("optimize clif ir", || {
- crate::optimize::optimize_function(tcx, instance, context, &mut clif_comments);
- });
-
// If the return block is not reachable, then the SSA builder may have inserted an `iconst.i128`
// instruction, which doesn't have an encoding.
context.compute_cfg();
// invalidate it when it would change.
context.domtree.clear();
- context.want_disasm = crate::pretty_clif::should_write_ir(tcx);
+ // Perform rust specific optimizations
+ tcx.sess.time("optimize clif ir", || {
+ crate::optimize::optimize_function(tcx, instance, context, &mut clif_comments);
+ });
// Define function
tcx.sess.time("define function", || {
+ context.want_disasm = crate::pretty_clif::should_write_ir(tcx);
module
.define_function(func_id, context, &mut NullTrapSink {}, &mut NullStackMapSink {})
.unwrap()
pub(crate) fn codegen_panic<'tcx>(fx: &mut FunctionCx<'_, '_, 'tcx>, msg_str: &str, span: Span) {
let location = fx.get_caller_location(span).load_scalar(fx);
- let msg_ptr = fx.anonymous_str("assert", msg_str);
+ let msg_ptr = fx.anonymous_str(msg_str);
let msg_len = fx.bcx.ins().iconst(fx.pointer_type, i64::try_from(msg_str.len()).unwrap());
let args = [msg_ptr, msg_len, location];
self.module.isa().triple()
}
- pub(crate) fn anonymous_str(&mut self, prefix: &str, msg: &str) -> Value {
- use std::collections::hash_map::DefaultHasher;
- use std::hash::{Hash, Hasher};
-
- let mut hasher = DefaultHasher::new();
- msg.hash(&mut hasher);
- let msg_hash = hasher.finish();
+ pub(crate) fn anonymous_str(&mut self, msg: &str) -> Value {
let mut data_ctx = DataContext::new();
data_ctx.define(msg.as_bytes().to_vec().into_boxed_slice());
- let msg_id = self
- .module
- .declare_data(&format!("__{}_{:08x}", prefix, msg_hash), Linkage::Local, false, false)
- .unwrap();
+ let msg_id = self.module.declare_anonymous_data(false, false).unwrap();
// Ignore DuplicateDefinition error, as the data will be the same
let _ = self.module.define_data(msg_id, &data_ctx);
#[cfg(feature = "jit")]
pub(crate) fn $register(builder: &mut cranelift_jit::JITBuilder) {
- for &(name, val) in &[$((stringify!($name), $name as *const u8)),*] {
+ for (name, val) in [$((stringify!($name), $name as *const u8)),*] {
builder.symbol(name, val);
}
}
/// Can be set using `-Cllvm-args=display_cg_time=...`.
pub display_cg_time: bool,
+ /// The register allocator to use.
+ ///
+ /// Defaults to the value of `CG_CLIF_REGALLOC` or `backtracking` otherwise. Can be set using
+ /// `-Cllvm-args=regalloc=...`.
+ pub regalloc: String,
+
/// Enable the Cranelift ir verifier for all compilation passes. If not set it will only run
/// once before passing the clif ir to Cranelift for compilation.
///
args.split(' ').map(|arg| arg.to_string()).collect()
},
display_cg_time: bool_env_var("CG_CLIF_DISPLAY_CG_TIME"),
+ regalloc: std::env::var("CG_CLIF_REGALLOC")
+ .unwrap_or_else(|_| "backtracking".to_string()),
enable_verifier: cfg!(debug_assertions) || bool_env_var("CG_CLIF_ENABLE_VERIFIER"),
disable_incr_cache: bool_env_var("CG_CLIF_DISABLE_INCR_CACHE"),
}
match name {
"mode" => config.codegen_mode = value.parse()?,
"display_cg_time" => config.display_cg_time = parse_bool(name, value)?,
+ "regalloc" => config.regalloc = value.to_string(),
"enable_verifier" => config.enable_verifier = parse_bool(name, value)?,
"disable_incr_cache" => config.disable_incr_cache = parse_bool(name, value)?,
_ => return Err(format!("Unknown option `{}`", name)),
use rustc_errors::ErrorReported;
use rustc_middle::middle::codegen_fn_attrs::CodegenFnAttrFlags;
use rustc_middle::mir::interpret::{
- alloc_range, read_target_uint, AllocId, Allocation, ConstValue, ErrorHandled, GlobalAlloc, Scalar,
+ alloc_range, read_target_uint, AllocId, Allocation, ConstValue, ErrorHandled, GlobalAlloc,
+ Scalar,
};
use rustc_middle::ty::ConstKind;
data_ctx.set_align(alloc.align.bytes());
if let Some(section_name) = section_name {
- // FIXME set correct segment for Mach-O files
- data_ctx.set_segment_section("", &*section_name);
+ let (segment_name, section_name) = if tcx.sess.target.is_like_osx {
+ if let Some(names) = section_name.split_once(',') {
+ names
+ } else {
+ tcx.sess.fatal(&format!(
+ "#[link_section = \"{}\"] is not valid for macos target: must be segment and section separated by comma",
+ section_name
+ ));
+ }
+ } else {
+ ("", &*section_name)
+ };
+ data_ctx.set_segment_section(segment_name, section_name);
}
let bytes = alloc.inspect_with_uninit_and_ptr_outside_interpreter(0..alloc.len()).to_vec();
operand: &Operand<'tcx>,
) -> Option<ConstValue<'tcx>> {
match operand {
- Operand::Copy(_) | Operand::Move(_) => None,
Operand::Constant(const_) => match const_.literal {
ConstantKind::Ty(const_) => {
fx.monomorphize(const_).eval(fx.tcx, ParamEnv::reveal_all()).val.try_to_value()
}
ConstantKind::Val(val, _) => Some(val),
},
+ // FIXME(rust-lang/rust#85105): Casts like `IMM8 as u32` result in the const being stored
+ // inside a temporary before being passed to the intrinsic requiring the const argument.
+ // This code tries to find a single constant defining definition of the referenced local.
+ Operand::Copy(place) | Operand::Move(place) => {
+ if !place.projection.is_empty() {
+ return None;
+ }
+ let mut computed_const_val = None;
+ for bb_data in fx.mir.basic_blocks() {
+ for stmt in &bb_data.statements {
+ match &stmt.kind {
+ StatementKind::Assign(local_and_rvalue) if &local_and_rvalue.0 == place => {
+ match &local_and_rvalue.1 {
+ Rvalue::Cast(CastKind::Misc, operand, ty) => {
+ if computed_const_val.is_some() {
+ return None; // local assigned twice
+ }
+ if !matches!(ty.kind(), ty::Uint(_) | ty::Int(_)) {
+ return None;
+ }
+ let const_val = mir_operand_get_const_val(fx, operand)?;
+ if fx.layout_of(ty).size
+ != const_val.try_to_scalar_int()?.size()
+ {
+ return None;
+ }
+ computed_const_val = Some(const_val);
+ }
+ Rvalue::Use(operand) => {
+ computed_const_val = mir_operand_get_const_val(fx, operand)
+ }
+ _ => return None,
+ }
+ }
+ StatementKind::SetDiscriminant { place: stmt_place, variant_index: _ }
+ if &**stmt_place == place =>
+ {
+ return None;
+ }
+ StatementKind::LlvmInlineAsm(_) | StatementKind::CopyNonOverlapping(_) => {
+ return None;
+ } // conservative handling
+ StatementKind::Assign(_)
+ | StatementKind::FakeRead(_)
+ | StatementKind::SetDiscriminant { .. }
+ | StatementKind::StorageLive(_)
+ | StatementKind::StorageDead(_)
+ | StatementKind::Retag(_, _)
+ | StatementKind::AscribeUserType(_, _)
+ | StatementKind::Coverage(_)
+ | StatementKind::Nop => {}
+ }
+ }
+ match &bb_data.terminator().kind {
+ TerminatorKind::Goto { .. }
+ | TerminatorKind::SwitchInt { .. }
+ | TerminatorKind::Resume
+ | TerminatorKind::Abort
+ | TerminatorKind::Return
+ | TerminatorKind::Unreachable
+ | TerminatorKind::Drop { .. }
+ | TerminatorKind::Assert { .. } => {}
+ TerminatorKind::DropAndReplace { .. }
+ | TerminatorKind::Yield { .. }
+ | TerminatorKind::GeneratorDrop
+ | TerminatorKind::FalseEdge { .. }
+ | TerminatorKind::FalseUnwind { .. } => unreachable!(),
+ TerminatorKind::InlineAsm { .. } => return None,
+ TerminatorKind::Call { destination: Some((call_place, _)), .. }
+ if call_place == place =>
+ {
+ return None;
+ }
+ TerminatorKind::Call { .. } => {}
+ }
+ }
+ computed_const_val
+ }
}
}
let mut object = None;
let work_product = cgu.work_product(tcx);
if let Some(saved_file) = &work_product.saved_file {
- let obj_out = tcx
- .output_filenames(())
- .temp_path(OutputType::Object, Some(&cgu.name().as_str()));
+ let obj_out =
+ tcx.output_filenames(()).temp_path(OutputType::Object, Some(&cgu.name().as_str()));
object = Some(obj_out.clone());
let source_file = rustc_incremental::in_incr_comp_dir(&incr_comp_session_dir, &saved_file);
if let Err(err) = rustc_fs_util::link_or_copy(&source_file, &obj_out) {
}
}
}
- crate::main_shim::maybe_create_entry_wrapper(tcx, &mut module, &mut cx.unwind_context, false);
+ crate::main_shim::maybe_create_entry_wrapper(
+ tcx,
+ &mut module,
+ &mut cx.unwind_context,
+ false,
+ cgu.is_primary(),
+ );
let debug_context = cx.debug_context;
let unwind_context = cx.unwind_context;
metadata: EncodedMetadata,
need_metadata_module: bool,
) -> Box<(CodegenResults, FxHashMap<WorkProductId, WorkProduct>)> {
- use rustc_span::symbol::sym;
-
- let crate_attrs = tcx.hir().attrs(rustc_hir::CRATE_HIR_ID);
- let subsystem = tcx.sess.first_attr_value_str_by_name(crate_attrs, sym::windows_subsystem);
- let windows_subsystem = subsystem.map(|subsystem| {
- if subsystem != sym::windows && subsystem != sym::console {
- tcx.sess.fatal(&format!(
- "invalid windows subsystem `{}`, only \
- `windows` and `console` are allowed",
- subsystem
- ));
- }
- subsystem.to_string()
- });
-
let mut work_products = FxHashMap::default();
let cgus = if tcx.sess.opts.output_types.should_codegen() {
.as_str()
.to_string();
- let tmp_file = tcx
- .output_filenames(())
- .temp_path(OutputType::Metadata, Some(&metadata_cgu_name));
+ let tmp_file =
+ tcx.output_filenames(()).temp_path(OutputType::Metadata, Some(&metadata_cgu_name));
let obj = crate::backend::with_object(tcx.sess, &metadata_cgu_name, |object| {
crate::metadata::write_metadata(tcx, object);
Box::new((
CodegenResults {
- crate_name: tcx.crate_name(LOCAL_CRATE),
modules,
allocator_module,
metadata_module,
metadata,
- windows_subsystem,
linker_info: LinkerInfo::new(tcx, crate::target_triple(tcx.sess).to_string()),
crate_info: CrateInfo::new(tcx),
},
.collect::<Vec<_>>()
.join("\n");
- let output_object_file =
- tcx.output_filenames(()).temp_path(OutputType::Object, Some(cgu_name));
+ let output_object_file = tcx.output_filenames(()).temp_path(OutputType::Object, Some(cgu_name));
// Assemble `global_asm`
let global_asm_object_file = add_file_stem_postfix(output_object_file.clone(), ".asm");
&mut jit_module,
&mut cx.unwind_context,
true,
+ true,
);
(jit_module, cx)
use object::{Object, ObjectSymbol};
let lib = libloading::Library::new(&path).unwrap();
let obj = std::fs::read(path).unwrap();
- let obj = object::File::parse(&obj).unwrap();
+ let obj = object::File::parse(&*obj).unwrap();
imported_symbols.extend(obj.dynamic_symbols().filter_map(|symbol| {
let name = symbol.name().unwrap().to_string();
if name.is_empty() || !symbol.is_global() || symbol.is_undefined() {
let true_ = fx.bcx.ins().iconst(types::I32, 1);
fx.bcx.ins().trapnz(true_, TrapCode::User(1));
return;
- } else if template[0] == InlineAsmTemplatePiece::String("mov rsi, rbx".to_string())
- && template[1] == InlineAsmTemplatePiece::String("\n".to_string())
- && template[2] == InlineAsmTemplatePiece::String("cpuid".to_string())
- && template[3] == InlineAsmTemplatePiece::String("\n".to_string())
- && template[4] == InlineAsmTemplatePiece::String("xchg rsi, rbx".to_string())
+ } else if template[0] == InlineAsmTemplatePiece::String("movq %rbx, ".to_string())
+ && matches!(
+ template[1],
+ InlineAsmTemplatePiece::Placeholder { operand_idx: 0, modifier: Some('r'), span: _ }
+ )
+ && template[2] == InlineAsmTemplatePiece::String("\n".to_string())
+ && template[3] == InlineAsmTemplatePiece::String("cpuid".to_string())
+ && template[4] == InlineAsmTemplatePiece::String("\n".to_string())
+ && template[5] == InlineAsmTemplatePiece::String("xchgq %rbx, ".to_string())
+ && matches!(
+ template[6],
+ InlineAsmTemplatePiece::Placeholder { operand_idx: 0, modifier: Some('r'), span: _ }
+ )
{
assert_eq!(operands.len(), 4);
- let (leaf, eax_place) = match operands[0] {
+ let (leaf, eax_place) = match operands[1] {
InlineAsmOperand::InOut { reg, late: true, ref in_value, out_place } => {
let reg = expect_reg(reg);
assert_eq!(reg, InlineAsmReg::X86(X86InlineAsmReg::ax));
}
_ => unreachable!(),
};
- let ebx_place = match operands[1] {
+ let ebx_place = match operands[0] {
InlineAsmOperand::Out { reg, late: true, place } => {
- let reg = expect_reg(reg);
- assert_eq!(reg, InlineAsmReg::X86(X86InlineAsmReg::si));
+ assert_eq!(
+ reg,
+ InlineAsmRegOrRegClass::RegClass(InlineAsmRegClass::X86(
+ X86InlineAsmRegClass::reg
+ ))
+ );
crate::base::codegen_place(fx, place.unwrap())
}
_ => unreachable!(),
) -> (Value, Value, Value, Value) {
let leaf_0 = fx.bcx.create_block();
let leaf_1 = fx.bcx.create_block();
+ let leaf_7 = fx.bcx.create_block();
let leaf_8000_0000 = fx.bcx.create_block();
let leaf_8000_0001 = fx.bcx.create_block();
let unsupported_leaf = fx.bcx.create_block();
let mut switch = cranelift_frontend::Switch::new();
switch.set_entry(0, leaf_0);
switch.set_entry(1, leaf_1);
+ switch.set_entry(7, leaf_7);
switch.set_entry(0x8000_0000, leaf_8000_0000);
switch.set_entry(0x8000_0001, leaf_8000_0001);
switch.emit(&mut fx.bcx, leaf, unsupported_leaf);
let edx_features = fx.bcx.ins().iconst(types::I32, 1 << 25 /* sse */ | 1 << 26 /* sse2 */);
fx.bcx.ins().jump(dest, &[cpu_signature, additional_information, ecx_features, edx_features]);
+ fx.bcx.switch_to_block(leaf_7);
+ // This leaf technically has subleaves, but we just return zero for all subleaves.
+ let zero = fx.bcx.ins().iconst(types::I32, 0);
+ fx.bcx.ins().jump(dest, &[zero, zero, zero, zero]);
+
fx.bcx.switch_to_block(leaf_8000_0000);
let extended_max_basic_leaf = fx.bcx.ins().iconst(types::I32, 0);
let zero = fx.bcx.ins().iconst(types::I32, 0);
pub(crate) use cpuid::codegen_cpuid_call;
pub(crate) use llvm::codegen_llvm_intrinsic_call;
-use rustc_span::symbol::{sym, kw};
use rustc_middle::ty::print::with_no_trimmed_paths;
+use rustc_span::symbol::{kw, sym};
use crate::prelude::*;
use cranelift_codegen::ir::AtomicRmwOp;
extern crate rustc_hir;
extern crate rustc_incremental;
extern crate rustc_index;
+extern crate rustc_metadata;
extern crate rustc_session;
extern crate rustc_span;
extern crate rustc_target;
use rustc_codegen_ssa::CodegenResults;
use rustc_errors::ErrorReported;
use rustc_middle::dep_graph::{WorkProduct, WorkProductId};
-use rustc_middle::middle::cstore::{EncodedMetadata, MetadataLoader};
-use rustc_middle::ty::query::Providers;
+use rustc_middle::middle::cstore::EncodedMetadata;
use rustc_session::config::OutputFilenames;
use rustc_session::Session;
}
}
- fn metadata_loader(&self) -> Box<dyn MetadataLoader + Sync> {
- Box::new(rustc_codegen_ssa::back::metadata::DefaultMetadataLoader)
- }
-
- fn provide(&self, _providers: &mut Providers) {}
- fn provide_extern(&self, _providers: &mut Providers) {}
-
fn target_features(&self, _sess: &Session) -> Vec<rustc_span::Symbol> {
vec![]
}
+ fn print_version(&self) {
+ println!("Cranelift version: {}", cranelift_codegen::VERSION);
+ }
+
fn codegen_crate(
&self,
tcx: TyCtxt<'_>,
sess,
&codegen_results,
outputs,
- &codegen_results.crate_name.as_str(),
+ &codegen_results.crate_info.local_crate_name.as_str(),
);
Ok(())
flags_builder.set("enable_llvm_abi_extensions", "true").unwrap();
+ flags_builder.set("regalloc", &backend_config.regalloc).unwrap();
+
use rustc_session::config::OptLevel;
match sess.opts.optimize {
OptLevel::No => {
builder
}
Some(value) => {
- let mut builder = cranelift_codegen::isa::lookup_variant(target_triple, variant).unwrap();
+ let mut builder =
+ cranelift_codegen::isa::lookup_variant(target_triple, variant).unwrap();
if let Err(_) = builder.enable(value) {
sess.fatal("The specified target cpu isn't currently supported by Cranelift.");
}
builder
}
None => {
- let mut builder = cranelift_codegen::isa::lookup_variant(target_triple, variant).unwrap();
+ let mut builder =
+ cranelift_codegen::isa::lookup_variant(target_triple, variant).unwrap();
// Don't use "haswell" as the default, as it implies `has_lzcnt`.
// macOS CI is still at Ivy Bridge EP, so `lzcnt` is interpreted as `bsr`.
builder.enable("nehalem").unwrap();
builder
}
};
-
+
isa_builder.finish(flags)
}
module: &mut impl Module,
unwind_context: &mut UnwindContext,
is_jit: bool,
+ is_primary_cgu: bool,
) {
let (main_def_id, is_main_fn) = match tcx.entry_fn(()) {
Some((def_id, entry_ty)) => (
None => return,
};
- let instance = Instance::mono(tcx, main_def_id).polymorphize(tcx);
- if !is_jit && module.get_name(&*tcx.symbol_name(instance).name).is_none() {
+ if main_def_id.is_local() {
+ let instance = Instance::mono(tcx, main_def_id).polymorphize(tcx);
+ if !is_jit && module.get_name(&*tcx.symbol_name(instance).name).is_none() {
+ return;
+ }
+ } else if !is_primary_cgu {
return;
}
use std::io::Write;
let metadata = tcx.encode_metadata();
- let mut compressed = tcx.metadata_encoding_version();
+ let mut compressed = rustc_metadata::METADATA_HEADER.to_vec();
FrameEncoder::new(&mut compressed).write_all(&metadata.raw_data).unwrap();
object.add_rustc_section(
use std::path::PathBuf;
-use rustc_middle::bug;
+use rustc_codegen_ssa::back::link::linker_and_flavor;
use rustc_session::Session;
-use rustc_target::spec::LinkerFlavor;
/// Tries to infer the path of a binary for the target toolchain from the linker name.
pub(crate) fn get_toolchain_binary(sess: &Session, tool: &str) -> PathBuf {
linker
}
-
-// Adapted from https://github.com/rust-lang/rust/blob/5db778affee7c6600c8e7a177c48282dab3f6292/src/librustc_codegen_ssa/back/link.rs#L848-L931
-fn linker_and_flavor(sess: &Session) -> (PathBuf, LinkerFlavor) {
- fn infer_from(
- sess: &Session,
- linker: Option<PathBuf>,
- flavor: Option<LinkerFlavor>,
- ) -> Option<(PathBuf, LinkerFlavor)> {
- match (linker, flavor) {
- (Some(linker), Some(flavor)) => Some((linker, flavor)),
- // only the linker flavor is known; use the default linker for the selected flavor
- (None, Some(flavor)) => Some((
- PathBuf::from(match flavor {
- LinkerFlavor::Em => {
- if cfg!(windows) {
- "emcc.bat"
- } else {
- "emcc"
- }
- }
- LinkerFlavor::Gcc => {
- if cfg!(any(target_os = "solaris", target_os = "illumos")) {
- // On historical Solaris systems, "cc" may have
- // been Sun Studio, which is not flag-compatible
- // with "gcc". This history casts a long shadow,
- // and many modern illumos distributions today
- // ship GCC as "gcc" without also making it
- // available as "cc".
- "gcc"
- } else {
- "cc"
- }
- }
- LinkerFlavor::Ld => "ld",
- LinkerFlavor::Msvc => "link.exe",
- LinkerFlavor::Lld(_) => "lld",
- LinkerFlavor::PtxLinker => "rust-ptx-linker",
- }),
- flavor,
- )),
- (Some(linker), None) => {
- let stem = linker.file_stem().and_then(|stem| stem.to_str()).unwrap_or_else(|| {
- sess.fatal("couldn't extract file stem from specified linker")
- });
-
- let flavor = if stem == "emcc" {
- LinkerFlavor::Em
- } else if stem == "gcc"
- || stem.ends_with("-gcc")
- || stem == "clang"
- || stem.ends_with("-clang")
- {
- LinkerFlavor::Gcc
- } else if stem == "ld" || stem == "ld.lld" || stem.ends_with("-ld") {
- LinkerFlavor::Ld
- } else if stem == "link" || stem == "lld-link" {
- LinkerFlavor::Msvc
- } else if stem == "lld" || stem == "rust-lld" {
- LinkerFlavor::Lld(sess.target.lld_flavor)
- } else {
- // fall back to the value in the target spec
- sess.target.linker_flavor
- };
-
- Some((linker, flavor))
- }
- (None, None) => None,
- }
- }
-
- // linker and linker flavor specified via command line have precedence over what the target
- // specification specifies
- if let Some(ret) = infer_from(sess, sess.opts.cg.linker.clone(), sess.opts.cg.linker_flavor) {
- return ret;
- }
-
- if let Some(ret) = infer_from(
- sess,
- sess.target.linker.clone().map(PathBuf::from),
- Some(sess.target.linker_flavor),
- ) {
- return ret;
- }
-
- bug!("Not enough information provided to determine how to invoke the linker");
-}
}
let real_msg = format!("trap at {:?} ({}): {}\0", fx.instance, fx.symbol_name, msg);
- let msg_ptr = fx.anonymous_str("trap", &real_msg);
+ let msg_ptr = fx.anonymous_str(&real_msg);
fx.bcx.ins().call(puts, &[msg_ptr]);
}
dst_align,
src_align,
true,
+ MemFlags::trusted(),
);
}
CValueInner::ByRef(_, Some(_)) => todo!(),
// FIXME dedup this logic between miri, cg_llvm and cg_clif
use crate::prelude::*;
-
-const DROP_FN_INDEX: usize = 0;
-const SIZE_INDEX: usize = 1;
-const ALIGN_INDEX: usize = 2;
+use ty::VtblEntry;
fn vtable_memflags() -> MemFlags {
let mut flags = MemFlags::trusted(); // A vtable access is always aligned and will never trap.
pointer_ty(fx.tcx),
vtable_memflags(),
vtable,
- (DROP_FN_INDEX * usize_size) as i32,
+ (ty::COMMON_VTABLE_ENTRIES_DROPINPLACE * usize_size) as i32,
)
}
pointer_ty(fx.tcx),
vtable_memflags(),
vtable,
- (SIZE_INDEX * usize_size) as i32,
+ (ty::COMMON_VTABLE_ENTRIES_SIZE * usize_size) as i32,
)
}
pointer_ty(fx.tcx),
vtable_memflags(),
vtable,
- (ALIGN_INDEX * usize_size) as i32,
+ (ty::COMMON_VTABLE_ENTRIES_SIZE * usize_size) as i32,
)
}
pointer_ty(fx.tcx),
vtable_memflags(),
vtable,
- ((idx + 3) * usize_size as usize) as i32,
+ (idx * usize_size as usize) as i32,
);
(ptr, func_ref)
}
Instance::resolve_drop_in_place(tcx, layout.ty).polymorphize(fx.tcx),
);
- let mut components: Vec<_> = vec![Some(drop_in_place_fn), None, None];
-
- let methods_root;
- let methods = if let Some(trait_ref) = trait_ref {
- methods_root = tcx.vtable_methods(trait_ref.with_self_ty(tcx, layout.ty));
- methods_root.iter()
+ let vtable_entries = if let Some(trait_ref) = trait_ref {
+ tcx.vtable_entries(trait_ref.with_self_ty(tcx, layout.ty))
} else {
- (&[]).iter()
+ ty::COMMON_VTABLE_ENTRIES
};
- let methods = methods.cloned().map(|opt_mth| {
- opt_mth.map(|(def_id, substs)| {
- import_function(
- tcx,
- fx.module,
- Instance::resolve_for_vtable(tcx, ParamEnv::reveal_all(), def_id, substs)
- .unwrap()
- .polymorphize(fx.tcx),
- )
- })
- });
- components.extend(methods);
let mut data_ctx = DataContext::new();
let mut data = ::std::iter::repeat(0u8)
- .take(components.len() * usize_size)
+ .take(vtable_entries.len() * usize_size)
.collect::<Vec<u8>>()
.into_boxed_slice();
- write_usize(fx.tcx, &mut data, SIZE_INDEX, layout.size.bytes());
- write_usize(fx.tcx, &mut data, ALIGN_INDEX, layout.align.abi.bytes());
+ for (idx, entry) in vtable_entries.iter().enumerate() {
+ match entry {
+ VtblEntry::MetadataSize => {
+ write_usize(fx.tcx, &mut data, idx, layout.size.bytes());
+ }
+ VtblEntry::MetadataAlign => {
+ write_usize(fx.tcx, &mut data, idx, layout.align.abi.bytes());
+ }
+ VtblEntry::MetadataDropInPlace | VtblEntry::Vacant | VtblEntry::Method(_, _) => {}
+ }
+ }
data_ctx.define(data);
- for (i, component) in components.into_iter().enumerate() {
- if let Some(func_id) = component {
- let func_ref = fx.module.declare_func_in_data(func_id, &mut data_ctx);
- data_ctx.write_function_addr((i * usize_size) as u32, func_ref);
+ for (idx, entry) in vtable_entries.iter().enumerate() {
+ match entry {
+ VtblEntry::MetadataDropInPlace => {
+ let func_ref = fx.module.declare_func_in_data(drop_in_place_fn, &mut data_ctx);
+ data_ctx.write_function_addr((idx * usize_size) as u32, func_ref);
+ }
+ VtblEntry::Method(def_id, substs) => {
+ let func_id = import_function(
+ tcx,
+ fx.module,
+ Instance::resolve_for_vtable(tcx, ParamEnv::reveal_all(), *def_id, substs)
+ .unwrap()
+ .polymorphize(fx.tcx),
+ );
+ let func_ref = fx.module.declare_func_in_data(func_id, &mut data_ctx);
+ data_ctx.write_function_addr((idx * usize_size) as u32, func_ref);
+ }
+ VtblEntry::MetadataSize | VtblEntry::MetadataAlign | VtblEntry::Vacant => {}
}
}
rustc_incremental = { path = "../rustc_incremental" }
rustc_index = { path = "../rustc_index" }
rustc_llvm = { path = "../rustc_llvm" }
+rustc_metadata = { path = "../rustc_metadata" }
rustc_session = { path = "../rustc_session" }
rustc_serialize = { path = "../rustc_serialize" }
rustc_target = { path = "../rustc_target" }
InlineAsmArch::Mips | InlineAsmArch::Mips64 => {}
InlineAsmArch::SpirV => {}
InlineAsmArch::Wasm32 => {}
+ InlineAsmArch::Bpf => {}
}
}
if !options.contains(InlineAsmOptions::NOMEM) {
InlineAsmRegClass::X86(X86InlineAsmRegClass::zmm_reg) => "v",
InlineAsmRegClass::X86(X86InlineAsmRegClass::kreg) => "^Yk",
InlineAsmRegClass::Wasm(WasmInlineAsmRegClass::local) => "r",
+ InlineAsmRegClass::Bpf(BpfInlineAsmRegClass::reg) => "r",
+ InlineAsmRegClass::Bpf(BpfInlineAsmRegClass::wreg) => "w",
InlineAsmRegClass::SpirV(SpirVInlineAsmRegClass::reg) => {
bug!("LLVM backend does not support SPIR-V")
}
},
InlineAsmRegClass::X86(X86InlineAsmRegClass::kreg) => None,
InlineAsmRegClass::Wasm(WasmInlineAsmRegClass::local) => None,
+ InlineAsmRegClass::Bpf(_) => None,
InlineAsmRegClass::SpirV(SpirVInlineAsmRegClass::reg) => {
bug!("LLVM backend does not support SPIR-V")
}
| InlineAsmRegClass::X86(X86InlineAsmRegClass::zmm_reg) => cx.type_f32(),
InlineAsmRegClass::X86(X86InlineAsmRegClass::kreg) => cx.type_i16(),
InlineAsmRegClass::Wasm(WasmInlineAsmRegClass::local) => cx.type_i32(),
+ InlineAsmRegClass::Bpf(BpfInlineAsmRegClass::reg) => cx.type_i64(),
+ InlineAsmRegClass::Bpf(BpfInlineAsmRegClass::wreg) => cx.type_i32(),
InlineAsmRegClass::SpirV(SpirVInlineAsmRegClass::reg) => {
bug!("LLVM backend does not support SPIR-V")
}
use std::str;
use crate::llvm::archive_ro::{ArchiveRO, Child};
-use crate::llvm::{self, ArchiveKind};
+use crate::llvm::{self, ArchiveKind, LLVMMachineType, LLVMRustCOFFShortExport};
use rustc_codegen_ssa::back::archive::{find_library, ArchiveBuilder};
use rustc_codegen_ssa::{looks_like_rust_object_file, METADATA_FILENAME};
+use rustc_data_structures::temp_dir::MaybeTempDir;
+use rustc_middle::middle::cstore::DllImport;
use rustc_session::Session;
use rustc_span::symbol::Symbol;
}
}
+/// Map machine type strings to values of LLVM's MachineTypes enum.
+fn llvm_machine_type(cpu: &str) -> LLVMMachineType {
+ match cpu {
+ "x86_64" => LLVMMachineType::AMD64,
+ "x86" => LLVMMachineType::I386,
+ "aarch64" => LLVMMachineType::ARM64,
+ "arm" => LLVMMachineType::ARM,
+ _ => panic!("unsupported cpu type {}", cpu),
+ }
+}
+
impl<'a> ArchiveBuilder<'a> for LlvmArchiveBuilder<'a> {
/// Creates a new static archive, ready for modifying the archive specified
/// by `config`.
self.config.sess.fatal(&format!("failed to build archive: {}", e));
}
}
+
+ fn inject_dll_import_lib(
+ &mut self,
+ lib_name: &str,
+ dll_imports: &[DllImport],
+ tmpdir: &MaybeTempDir,
+ ) {
+ let output_path = {
+ let mut output_path: PathBuf = tmpdir.as_ref().to_path_buf();
+ output_path.push(format!("{}_imports", lib_name));
+ output_path.with_extension("lib")
+ };
+
+ // we've checked for \0 characters in the library name already
+ let dll_name_z = CString::new(lib_name).unwrap();
+ // All import names are Rust identifiers and therefore cannot contain \0 characters.
+ // FIXME: when support for #[link_name] implemented, ensure that import.name values don't
+ // have any \0 characters
+ let import_name_vector: Vec<CString> = dll_imports
+ .iter()
+ .map(if self.config.sess.target.arch == "x86" {
+ |import: &DllImport| CString::new(format!("_{}", import.name.to_string())).unwrap()
+ } else {
+ |import: &DllImport| CString::new(import.name.to_string()).unwrap()
+ })
+ .collect();
+
+ let output_path_z = rustc_fs_util::path_to_c_string(&output_path);
+
+ tracing::trace!("invoking LLVMRustWriteImportLibrary");
+ tracing::trace!(" dll_name {:#?}", dll_name_z);
+ tracing::trace!(" output_path {}", output_path.display());
+ tracing::trace!(
+ " import names: {}",
+ dll_imports.iter().map(|import| import.name.to_string()).collect::<Vec<_>>().join(", "),
+ );
+
+ let ffi_exports: Vec<LLVMRustCOFFShortExport> = import_name_vector
+ .iter()
+ .map(|name_z| LLVMRustCOFFShortExport::from_name(name_z.as_ptr()))
+ .collect();
+ let result = unsafe {
+ crate::llvm::LLVMRustWriteImportLibrary(
+ dll_name_z.as_ptr(),
+ output_path_z.as_ptr(),
+ ffi_exports.as_ptr(),
+ ffi_exports.len(),
+ llvm_machine_type(&self.config.sess.target.arch) as u16,
+ !self.config.sess.target.is_like_msvc,
+ )
+ };
+
+ if result == crate::llvm::LLVMRustResult::Failure {
+ self.config.sess.fatal(&format!(
+ "Error creating import library for {}: {}",
+ lib_name,
+ llvm::last_error().unwrap_or("unknown LLVM error".to_string())
+ ));
+ }
+
+ self.add_archive(&output_path, |_| false).unwrap_or_else(|e| {
+ self.config.sess.fatal(&format!(
+ "failed to add native library {}: {}",
+ output_path.display(),
+ e
+ ));
+ });
+ }
}
impl<'a> LlvmArchiveBuilder<'a> {
let section_name = if tcx.sess.target.is_like_osx { "__DATA,.rustc" } else { ".rustc" };
let (metadata_llcx, metadata_llmod) = (&*llvm_module.llcx, llvm_module.llmod());
- let mut compressed = tcx.metadata_encoding_version();
+ let mut compressed = rustc_metadata::METADATA_HEADER.to_vec();
FrameEncoder::new(&mut compressed).write_all(&metadata.raw_data).unwrap();
let llmeta = common::bytes_in_context(metadata_llcx, &compressed);
Visibility::Protected => llvm::Visibility::Protected,
}
}
-
-pub fn linkage_from_llvm(linkage: llvm::Linkage) -> Linkage {
- match linkage {
- llvm::Linkage::ExternalLinkage => Linkage::External,
- llvm::Linkage::AvailableExternallyLinkage => Linkage::AvailableExternally,
- llvm::Linkage::LinkOnceAnyLinkage => Linkage::LinkOnceAny,
- llvm::Linkage::LinkOnceODRLinkage => Linkage::LinkOnceODR,
- llvm::Linkage::WeakAnyLinkage => Linkage::WeakAny,
- llvm::Linkage::WeakODRLinkage => Linkage::WeakODR,
- llvm::Linkage::AppendingLinkage => Linkage::Appending,
- llvm::Linkage::InternalLinkage => Linkage::Internal,
- llvm::Linkage::PrivateLinkage => Linkage::Private,
- llvm::Linkage::ExternalWeakLinkage => Linkage::ExternalWeak,
- llvm::Linkage::CommonLinkage => Linkage::Common,
- }
-}
-
-pub fn visibility_from_llvm(linkage: llvm::Visibility) -> Visibility {
- match linkage {
- llvm::Visibility::Default => Visibility::Default,
- llvm::Visibility::Hidden => Visibility::Hidden,
- llvm::Visibility::Protected => Visibility::Protected,
- }
-}
}
impl ty::layout::HasTyCtxt<'tcx> for Builder<'_, '_, 'tcx> {
+ #[inline]
fn tcx(&self) -> TyCtxt<'tcx> {
self.cx.tcx
}
}
impl HasTargetSpec for Builder<'_, '_, 'tcx> {
+ #[inline]
fn target_spec(&self) -> &Target {
&self.cx.target_spec()
}
impl Deref for Builder<'_, 'll, 'tcx> {
type Target = CodegenCx<'ll, 'tcx>;
+ #[inline]
fn deref(&self) -> &Self::Target {
self.cx
}
use rustc_middle::ty::layout::{FnAbiExt, HasTyCtxt};
use rustc_middle::ty::{self, Instance, TypeFoldable};
-use rustc_target::spec::RelocModel;
/// Codegens a reference to a fn/method item, monomorphizing and
/// inlining as it goes.
llvm::LLVMSetDLLStorageClass(llfn, llvm::DLLStorageClass::DllImport);
}
- if cx.tcx.sess.relocation_model() == RelocModel::Static {
+ if cx.should_assume_dso_local(llfn, true) {
llvm::LLVMRustSetDSOLocal(llfn, true);
}
}
use rustc_middle::ty::{self, Instance, Ty};
use rustc_middle::{bug, span_bug};
use rustc_target::abi::{AddressSpace, Align, HasDataLayout, LayoutOf, Primitive, Scalar, Size};
-use rustc_target::spec::RelocModel;
use tracing::debug;
pub fn const_alloc_to_llvm(cx: &CodegenCx<'ll, '_>, alloc: &Allocation) -> &'ll Value {
}
}
- if self.tcx.sess.relocation_model() == RelocModel::Static {
- unsafe {
+ unsafe {
+ if self.should_assume_dso_local(g, true) {
llvm::LLVMRustSetDSOLocal(g, true);
}
}
set_global_alignment(&self, g, self.align_of(ty));
llvm::LLVMSetInitializer(g, v);
- let linkage = base::linkage_from_llvm(llvm::LLVMRustGetLinkage(g));
- let visibility = base::visibility_from_llvm(llvm::LLVMRustGetVisibility(g));
- if self.should_assume_dso_local(linkage, visibility) {
+ if self.should_assume_dso_local(g, true) {
llvm::LLVMRustSetDSOLocal(g, true);
}
}
impl HasDataLayout for CodegenCx<'ll, 'tcx> {
+ #[inline]
fn data_layout(&self) -> &TargetDataLayout {
&self.tcx.data_layout
}
}
impl HasTargetSpec for CodegenCx<'ll, 'tcx> {
+ #[inline]
fn target_spec(&self) -> &Target {
&self.tcx.sess.target
}
}
impl ty::layout::HasTyCtxt<'tcx> for CodegenCx<'ll, 'tcx> {
+ #[inline]
fn tcx(&self) -> TyCtxt<'tcx> {
self.tcx
}
enum_type: Ty<'tcx>,
layout: TyAndLayout<'tcx>,
tag_type_metadata: Option<&'ll DIType>,
- containing_scope: &'ll DIScope,
common_members: Vec<Option<&'ll DIType>>,
span: Span,
}
_ => bug!(),
};
- // This will always find the metadata in the type map.
let fallback = use_enum_fallback(cx);
- let self_metadata = if fallback {
- self.containing_scope
- } else {
- type_metadata(cx, self.enum_type, self.span)
- };
+ // This will always find the metadata in the type map.
+ let self_metadata = type_metadata(cx, self.enum_type, self.span);
match self.layout.variants {
Variants::Single { index } => {
cx,
self.layout,
variant_info,
- NoTag,
+ None,
self_metadata,
self.span,
);
..
} => {
let tag_info = if fallback {
- RegularTag {
+ // For MSVC, we generate a union of structs for each variant with an explicit
+ // discriminant field roughly equivalent to the following C:
+ // ```c
+ // union enum$<{name}> {
+ // struct {variant 0 name} {
+ // tag$ variant$;
+ // <variant 0 fields>
+ // } variant0;
+ // <other variant structs>
+ // }
+ // ```
+ // The natvis in `intrinsic.nativs` then matches on `this.variant0.variant$` to
+ // determine which variant is active and then displays it.
+ Some(DirectTag {
tag_field: Field::from(tag_field),
tag_type_metadata: self.tag_type_metadata.unwrap(),
- }
+ })
} else {
// This doesn't matter in this case.
- NoTag
+ None
};
variants
.iter_enumerated()
MemberDescription {
name: if fallback {
- String::new()
+ format!("variant{}", i.as_u32())
} else {
variant_info.variant_name()
},
ref variants,
tag_field,
} => {
+ let calculate_niche_value = |i: VariantIdx| {
+ if i == dataful_variant {
+ None
+ } else {
+ let value = (i.as_u32() as u128)
+ .wrapping_sub(niche_variants.start().as_u32() as u128)
+ .wrapping_add(niche_start);
+ let value = tag.value.size(cx).truncate(value);
+ // NOTE(eddyb) do *NOT* remove this assert, until
+ // we pass the full 128-bit value to LLVM, otherwise
+ // truncation will be silent and remain undetected.
+ assert_eq!(value as u64 as u128, value);
+ Some(value as u64)
+ }
+ };
+
+ // For MSVC, we will generate a union of two fields, one for the dataful variant
+ // and one that just points to the discriminant. We also create an enum that
+ // contains tag values for the non-dataful variants and make the discriminant field
+ // that type. We then use natvis to render the enum type correctly in Windbg/VS.
+ // This will generate debuginfo roughly equivalent to the following C:
+ // ```c
+ // union enum$<{name}, {min niche}, {max niche}, {dataful variant name}> {
+ // struct <dataful variant name> {
+ // <fields in dataful variant>
+ // } dataful_variant;
+ // enum Discriminant$ {
+ // <non-dataful variants>
+ // } discriminant;
+ // }
+ // ```
+ // The natvis in `intrinsic.natvis` matches on the type name `enum$<*, *, *, *>`
+ // and evaluates `this.discriminant`. If the value is between the min niche and max
+ // niche, then the enum is in the dataful variant and `this.dataful_variant` is
+ // rendered. Otherwise, the enum is in one of the non-dataful variants. In that
+ // case, we just need to render the name of the `this.discriminant` enum.
if fallback {
- let variant = self.layout.for_variant(cx, dataful_variant);
- // Create a description of the non-null variant.
- let (variant_type_metadata, member_description_factory) = describe_enum_variant(
+ let dataful_variant_layout = self.layout.for_variant(cx, dataful_variant);
+
+ let mut discr_enum_ty = tag.value.to_ty(cx.tcx);
+ // If the niche is the NULL value of a reference, then `discr_enum_ty` will be a RawPtr.
+ // CodeView doesn't know what to do with enums whose base type is a pointer so we fix this up
+ // to just be `usize`.
+ if let ty::RawPtr(_) = discr_enum_ty.kind() {
+ discr_enum_ty = cx.tcx.types.usize;
+ }
+
+ let tags: Vec<_> = variants
+ .iter_enumerated()
+ .filter_map(|(variant_idx, _)| {
+ calculate_niche_value(variant_idx).map(|tag| {
+ let variant = variant_info_for(variant_idx);
+ let name = variant.variant_name();
+
+ Some(unsafe {
+ llvm::LLVMRustDIBuilderCreateEnumerator(
+ DIB(cx),
+ name.as_ptr().cast(),
+ name.len(),
+ tag as i64,
+ !discr_enum_ty.is_signed(),
+ )
+ })
+ })
+ })
+ .collect();
+
+ let discr_enum = unsafe {
+ llvm::LLVMRustDIBuilderCreateEnumerationType(
+ DIB(cx),
+ self_metadata,
+ "Discriminant$".as_ptr().cast(),
+ "Discriminant$".len(),
+ unknown_file_metadata(cx),
+ UNKNOWN_LINE_NUMBER,
+ tag.value.size(cx).bits(),
+ tag.value.align(cx).abi.bits() as u32,
+ create_DIArray(DIB(cx), &tags),
+ type_metadata(cx, discr_enum_ty, self.span),
+ true,
+ )
+ };
+
+ let variant_info = variant_info_for(dataful_variant);
+ let (variant_type_metadata, member_desc_factory) = describe_enum_variant(
cx,
- variant,
- variant_info_for(dataful_variant),
- OptimizedTag,
- self.containing_scope,
+ dataful_variant_layout,
+ variant_info,
+ Some(NicheTag),
+ self_metadata,
self.span,
);
- let variant_member_descriptions =
- member_description_factory.create_member_descriptions(cx);
+ let member_descriptions = member_desc_factory.create_member_descriptions(cx);
set_members_of_composite_type(
cx,
self.enum_type,
variant_type_metadata,
- variant_member_descriptions,
+ member_descriptions,
Some(&self.common_members),
);
- // Encode the information about the null variant in the union
- // member's name.
- let mut name = String::from("RUST$ENCODED$ENUM$");
- // Right now it's not even going to work for `niche_start > 0`,
- // and for multiple niche variants it only supports the first.
- fn compute_field_path<'a, 'tcx>(
- cx: &CodegenCx<'a, 'tcx>,
- name: &mut String,
- layout: TyAndLayout<'tcx>,
- offset: Size,
- size: Size,
- ) {
- for i in 0..layout.fields.count() {
- let field_offset = layout.fields.offset(i);
- if field_offset > offset {
- continue;
- }
- let inner_offset = offset - field_offset;
- let field = layout.field(cx, i);
- if inner_offset + size <= field.size {
- write!(name, "{}$", i).unwrap();
- compute_field_path(cx, name, field, inner_offset, size);
- }
- }
- }
- compute_field_path(
- cx,
- &mut name,
- self.layout,
- self.layout.fields.offset(tag_field),
- self.layout.field(cx, tag_field).size,
- );
- let variant_info = variant_info_for(*niche_variants.start());
- variant_info.map_struct_name(|variant_name| {
- name.push_str(variant_name);
- });
-
- // Create the (singleton) list of descriptions of union members.
- vec![MemberDescription {
- name,
- type_metadata: variant_type_metadata,
- offset: Size::ZERO,
- size: variant.size,
- align: variant.align.abi,
- flags: DIFlags::FlagZero,
- discriminant: None,
- source_info: variant_info.source_info(cx),
- }]
+ let (size, align) =
+ cx.size_and_align_of(dataful_variant_layout.field(cx, tag_field).ty);
+
+ vec![
+ MemberDescription {
+ // Name the dataful variant so that we can identify it for natvis
+ name: "dataful_variant".to_string(),
+ type_metadata: variant_type_metadata,
+ offset: Size::ZERO,
+ size: self.layout.size,
+ align: self.layout.align.abi,
+ flags: DIFlags::FlagZero,
+ discriminant: None,
+ source_info: variant_info.source_info(cx),
+ },
+ MemberDescription {
+ name: "discriminant".into(),
+ type_metadata: discr_enum,
+ offset: dataful_variant_layout.fields.offset(tag_field),
+ size,
+ align,
+ flags: DIFlags::FlagZero,
+ discriminant: None,
+ source_info: None,
+ },
+ ]
} else {
variants
.iter_enumerated()
cx,
variant,
variant_info,
- OptimizedTag,
+ Some(NicheTag),
self_metadata,
self.span,
);
Some(&self.common_members),
);
- let niche_value = if i == dataful_variant {
- None
- } else {
- let value = (i.as_u32() as u128)
- .wrapping_sub(niche_variants.start().as_u32() as u128)
- .wrapping_add(niche_start);
- let value = tag.value.size(cx).truncate(value);
- // NOTE(eddyb) do *NOT* remove this assert, until
- // we pass the full 128-bit value to LLVM, otherwise
- // truncation will be silent and remain undetected.
- assert_eq!(value as u64 as u128, value);
- Some(value as u64)
- };
+ let niche_value = calculate_niche_value(i);
MemberDescription {
name: variant_info.variant_name(),
}
}
-// FIXME: terminology here should be aligned with `abi::TagEncoding`.
-// `OptimizedTag` is `TagEncoding::Niche`, `RegularTag` is `TagEncoding::Direct`.
-// `NoTag` should be removed; users should use `Option<EnumTagInfo>` instead.
#[derive(Copy, Clone)]
enum EnumTagInfo<'ll> {
- RegularTag { tag_field: Field, tag_type_metadata: &'ll DIType },
- OptimizedTag,
- NoTag,
+ DirectTag { tag_field: Field, tag_type_metadata: &'ll DIType },
+ NicheTag,
}
#[derive(Copy, Clone)]
cx: &CodegenCx<'ll, 'tcx>,
layout: layout::TyAndLayout<'tcx>,
variant: VariantInfo<'_, 'tcx>,
- discriminant_info: EnumTagInfo<'ll>,
+ discriminant_info: Option<EnumTagInfo<'ll>>,
containing_scope: &'ll DIScope,
span: Span,
) -> (&'ll DICompositeType, MemberDescriptionFactory<'ll, 'tcx>) {
let (offsets, args) = if use_enum_fallback(cx) {
// If this is not a univariant enum, there is also the discriminant field.
let (discr_offset, discr_arg) = match discriminant_info {
- RegularTag { tag_field, .. } => {
+ Some(DirectTag { tag_field, .. }) => {
// We have the layout of an enum variant, we need the layout of the outer enum
let enum_layout = cx.layout_of(layout.ty);
let offset = enum_layout.fields.offset(tag_field.as_usize());
- let args =
- ("RUST$ENUM$DISR".to_owned(), enum_layout.field(cx, tag_field.as_usize()).ty);
+ let args = ("variant$".to_owned(), enum_layout.field(cx, tag_field.as_usize()).ty);
(Some(offset), Some(args))
}
_ => (None, None),
offsets,
args,
tag_type_metadata: match discriminant_info {
- RegularTag { tag_type_metadata, .. } => Some(tag_type_metadata),
+ Some(DirectTag { tag_type_metadata, .. }) => Some(tag_type_metadata),
_ => None,
},
span,
if use_enum_fallback(cx) {
let discriminant_type_metadata = match layout.variants {
- Variants::Single { .. }
- | Variants::Multiple { tag_encoding: TagEncoding::Niche { .. }, .. } => None,
- Variants::Multiple { tag_encoding: TagEncoding::Direct, ref tag, .. } => {
+ Variants::Single { .. } => None,
+ Variants::Multiple { tag_encoding: TagEncoding::Niche { .. }, ref tag, .. }
+ | Variants::Multiple { tag_encoding: TagEncoding::Direct, ref tag, .. } => {
Some(discriminant_type_metadata(tag.value))
}
};
unsafe {
llvm::LLVMRustDIBuilderCreateUnionType(
DIB(cx),
- containing_scope,
+ None,
enum_name.as_ptr().cast(),
enum_name.len(),
file_metadata,
enum_type,
layout,
tag_type_metadata: discriminant_type_metadata,
- containing_scope,
common_members: vec![],
span,
}),
enum_type,
layout,
tag_type_metadata: None,
- containing_scope,
common_members: outer_fields,
span,
}),
llvm::LLVMRustDIBuilderCreateUnionType(
DIB(cx),
- containing_scope,
+ Some(containing_scope),
union_type_name.as_ptr().cast(),
union_type_name.len(),
unknown_file_metadata(cx),
use rustc_data_structures::fx::FxHashMap;
use rustc_errors::{ErrorReported, FatalError, Handler};
use rustc_middle::dep_graph::{WorkProduct, WorkProductId};
-use rustc_middle::middle::cstore::{EncodedMetadata, MetadataLoaderDyn};
-use rustc_middle::ty::{self, TyCtxt};
+use rustc_middle::middle::cstore::EncodedMetadata;
+use rustc_middle::ty::TyCtxt;
use rustc_session::config::{OptLevel, OutputFilenames, PrintRequest};
use rustc_session::Session;
use rustc_span::symbol::Symbol;
target_features(sess)
}
- fn metadata_loader(&self) -> Box<MetadataLoaderDyn> {
- Box::new(rustc_codegen_ssa::back::metadata::DefaultMetadataLoader)
- }
-
- fn provide(&self, _providers: &mut ty::query::Providers) {}
- fn provide_extern(&self, _providers: &mut ty::query::Providers) {}
-
fn codegen_crate<'tcx>(
&self,
tcx: TyCtxt<'tcx>,
sess,
&codegen_results,
outputs,
- &codegen_results.crate_name.as_str(),
+ &codegen_results.crate_info.local_crate_name.as_str(),
);
Ok(())
Success,
Failure,
}
+
+// Rust version of the C struct with the same name in rustc_llvm/llvm-wrapper/RustWrapper.cpp.
+#[repr(C)]
+pub struct LLVMRustCOFFShortExport {
+ pub name: *const c_char,
+}
+
+impl LLVMRustCOFFShortExport {
+ pub fn from_name(name: *const c_char) -> LLVMRustCOFFShortExport {
+ LLVMRustCOFFShortExport { name }
+ }
+}
+
+/// Translation of LLVM's MachineTypes enum, defined in llvm\include\llvm\BinaryFormat\COFF.h.
+///
+/// We include only architectures supported on Windows.
+#[derive(Copy, Clone, PartialEq)]
+#[repr(C)]
+pub enum LLVMMachineType {
+ AMD64 = 0x8664,
+ I386 = 0x14c,
+ ARM64 = 0xaa64,
+ ARM = 0x01c0,
+}
+
// Consts for the LLVM CallConv type, pre-cast to usize.
/// LLVM CallingConv::ID. Should we wrap this?
// LLVMRustVisibility
#[repr(C)]
-#[derive(Copy, Clone)]
+#[derive(Copy, Clone, PartialEq)]
pub enum Visibility {
Default = 0,
Hidden = 1,
extern "C" {
pub type PassManagerBuilder;
}
-extern "C" {
- pub type ObjectFile;
-}
-#[repr(C)]
-pub struct SectionIterator<'a>(InvariantOpaque<'a>);
extern "C" {
pub type Pass;
}
pub fn LLVMDeleteGlobal(GlobalVar: &Value);
pub fn LLVMGetInitializer(GlobalVar: &Value) -> Option<&Value>;
pub fn LLVMSetInitializer(GlobalVar: &'a Value, ConstantVal: &'a Value);
+ pub fn LLVMIsThreadLocal(GlobalVar: &Value) -> Bool;
pub fn LLVMSetThreadLocal(GlobalVar: &Value, IsThreadLocal: Bool);
pub fn LLVMSetThreadLocalMode(GlobalVar: &Value, Mode: ThreadLocalMode);
pub fn LLVMIsGlobalConstant(GlobalVar: &Value) -> Bool;
pub fn LLVMDisposeMessage(message: *mut c_char);
- // Stuff that's in llvm-wrapper/ because it's not upstream yet.
-
- /// Opens an object file.
- pub fn LLVMCreateObjectFile(
- MemBuf: &'static mut MemoryBuffer,
- ) -> Option<&'static mut ObjectFile>;
- /// Closes an object file.
- pub fn LLVMDisposeObjectFile(ObjFile: &'static mut ObjectFile);
-
- /// Enumerates the sections in an object file.
- pub fn LLVMGetSections(ObjFile: &'a ObjectFile) -> &'a mut SectionIterator<'a>;
- /// Destroys a section iterator.
- pub fn LLVMDisposeSectionIterator(SI: &'a mut SectionIterator<'a>);
- /// Returns `true` if the section iterator is at the end of the section
- /// list:
- pub fn LLVMIsSectionIteratorAtEnd(ObjFile: &'a ObjectFile, SI: &SectionIterator<'a>) -> Bool;
- /// Moves the section iterator to point to the next section.
- pub fn LLVMMoveToNextSection(SI: &SectionIterator<'_>);
- /// Returns the current section size.
- pub fn LLVMGetSectionSize(SI: &SectionIterator<'_>) -> c_ulonglong;
- /// Returns the current section contents as a string buffer.
- pub fn LLVMGetSectionContents(SI: &SectionIterator<'_>) -> *const c_char;
-
- /// Reads the given file and returns it as a memory buffer. Use
- /// LLVMDisposeMemoryBuffer() to get rid of it.
- pub fn LLVMRustCreateMemoryBufferWithContentsOfFile(
- Path: *const c_char,
- ) -> Option<&'static mut MemoryBuffer>;
-
pub fn LLVMStartMultithreaded() -> Bool;
/// Returns a string describing the last error caused by an LLVMRust* call.
pub fn LLVMRustDIBuilderCreateUnionType(
Builder: &DIBuilder<'a>,
- Scope: &'a DIScope,
+ Scope: Option<&'a DIScope>,
Name: *const c_char,
NameLen: size_t,
File: &'a DIFile,
pub fn LLVMRustArchiveIteratorFree(AIR: &'a mut ArchiveIterator<'a>);
pub fn LLVMRustDestroyArchive(AR: &'static mut Archive);
- #[allow(improper_ctypes)]
- pub fn LLVMRustGetSectionName(
- SI: &SectionIterator<'_>,
- data: &mut Option<std::ptr::NonNull<c_char>>,
- ) -> size_t;
-
#[allow(improper_ctypes)]
pub fn LLVMRustWriteTwineToString(T: &Twine, s: &RustString);
) -> &'a mut RustArchiveMember<'a>;
pub fn LLVMRustArchiveMemberFree(Member: &'a mut RustArchiveMember<'a>);
+ pub fn LLVMRustWriteImportLibrary(
+ ImportName: *const c_char,
+ Path: *const c_char,
+ Exports: *const LLVMRustCOFFShortExport,
+ NumExports: usize,
+ Machine: u16,
+ MinGW: bool,
+ ) -> LLVMRustResult;
+
pub fn LLVMRustSetDataLayoutFromTargetMachine(M: &'a Module, TM: &'a TargetMachine);
pub fn LLVMRustBuildOperandBundleDef(
}
}
-// Memory-managed interface to object files.
-
-pub struct ObjectFile {
- pub llof: &'static mut ffi::ObjectFile,
-}
-
-unsafe impl Send for ObjectFile {}
-
-impl ObjectFile {
- // This will take ownership of llmb
- pub fn new(llmb: &'static mut MemoryBuffer) -> Option<ObjectFile> {
- unsafe {
- let llof = LLVMCreateObjectFile(llmb)?;
- Some(ObjectFile { llof })
- }
- }
-}
-
-impl Drop for ObjectFile {
- fn drop(&mut self) {
- unsafe {
- LLVMDisposeObjectFile(&mut *(self.llof as *mut _));
- }
- }
-}
-
-// Memory-managed interface to section iterators.
-
-pub struct SectionIter<'a> {
- pub llsi: &'a mut SectionIterator<'a>,
-}
-
-impl Drop for SectionIter<'a> {
- fn drop(&mut self) {
- unsafe {
- LLVMDisposeSectionIterator(&mut *(self.llsi as *mut _));
- }
- }
-}
-
-pub fn mk_section_iter(llof: &ffi::ObjectFile) -> SectionIter<'_> {
- unsafe { SectionIter { llsi: LLVMGetSections(llof) } }
-}
-
pub fn set_section(llglobal: &Value, section_name: &str) {
let section_name_cstr = CString::new(section_name).expect("unexpected CString error");
unsafe {
use crate::back::write::create_informational_target_machine;
-use crate::llvm;
+use crate::{llvm, llvm_util};
use libc::c_int;
use rustc_codegen_ssa::target_features::supported_target_features;
use rustc_data_structures::fx::FxHashSet;
if !sess.opts.debugging_opts.no_generate_arange_section {
add("-generate-arange-section", false);
}
+
+ // FIXME(nagisa): disable the machine outliner by default in LLVM versions 11, where it was
+ // introduced and up.
+ //
+ // This should remain in place until https://reviews.llvm.org/D103167 is fixed. If LLVM
+ // has been upgraded since, consider adjusting the version check below to contain an upper
+ // bound.
+ if llvm_util::get_version() >= (11, 0, 0) {
+ add("-enable-machine-outliner=never", false);
+ }
+
match sess.opts.debugging_opts.merge_functions.unwrap_or(sess.target.merge_functions) {
MergeFunctions::Disabled | MergeFunctions::Trampolines => {}
MergeFunctions::Aliases => {
unsafe {
llvm::LLVMRustSetLinkage(g, base::linkage_to_llvm(linkage));
llvm::LLVMRustSetVisibility(g, base::visibility_to_llvm(visibility));
- if self.should_assume_dso_local(linkage, visibility) {
+ if self.should_assume_dso_local(g, false) {
llvm::LLVMRustSetDSOLocal(g, true);
}
}
attributes::from_fn_attrs(self, lldecl, instance);
unsafe {
- if self.should_assume_dso_local(linkage, visibility) {
+ if self.should_assume_dso_local(lldecl, false) {
llvm::LLVMRustSetDSOLocal(lldecl, true);
}
}
}
impl CodegenCx<'ll, 'tcx> {
- /// Whether a definition (NB: not declaration!) can be assumed to be local to a group of
+ /// Whether a definition or declaration can be assumed to be local to a group of
/// libraries that form a single DSO or executable.
pub(crate) unsafe fn should_assume_dso_local(
&self,
- linkage: Linkage,
- visibility: Visibility,
+ llval: &llvm::Value,
+ is_declaration: bool,
) -> bool {
- if matches!(linkage, Linkage::Internal | Linkage::Private) {
+ let linkage = llvm::LLVMRustGetLinkage(llval);
+ let visibility = llvm::LLVMRustGetVisibility(llval);
+
+ if matches!(linkage, llvm::Linkage::InternalLinkage | llvm::Linkage::PrivateLinkage) {
return true;
}
- if visibility != Visibility::Default && linkage != Linkage::ExternalWeak {
+ if visibility != llvm::Visibility::Default && linkage != llvm::Linkage::ExternalWeakLinkage
+ {
return true;
}
- // Static relocation model should force copy relocations everywhere.
- if self.tcx.sess.relocation_model() == RelocModel::Static {
+ // Symbols from executables can't really be imported any further.
+ let all_exe = self.tcx.sess.crate_types().iter().all(|ty| *ty == CrateType::Executable);
+ let is_declaration_for_linker =
+ is_declaration || linkage == llvm::Linkage::AvailableExternallyLinkage;
+ if all_exe && !is_declaration_for_linker {
return true;
}
- // Symbols from executables can't really be imported any further.
- if self.tcx.sess.crate_types().iter().all(|ty| *ty == CrateType::Executable) {
+ // PowerPC64 prefers TOC indirection to avoid copy relocations.
+ if matches!(&*self.tcx.sess.target.arch, "powerpc64" | "powerpc64le") {
+ return false;
+ }
+
+ // Thread-local variables generally don't support copy relocations.
+ let is_thread_local_var = llvm::LLVMIsAGlobalVariable(llval)
+ .map(|v| llvm::LLVMIsThreadLocal(v) == llvm::True)
+ .unwrap_or(false);
+ if is_thread_local_var {
+ return false;
+ }
+
+ // Static relocation model should force copy relocations everywhere.
+ if self.tcx.sess.relocation_model() == RelocModel::Static {
return true;
}
[dependencies]
bitflags = "1.2.1"
-cc = "1.0.67"
+cc = "1.0.68"
itertools = "0.9"
tracing = "0.1"
libc = "0.2.50"
rustc_apfloat = { path = "../rustc_apfloat" }
rustc_attr = { path = "../rustc_attr" }
rustc_symbol_mangling = { path = "../rustc_symbol_mangling" }
-rustc_data_structures = { path = "../rustc_data_structures"}
+rustc_data_structures = { path = "../rustc_data_structures" }
rustc_errors = { path = "../rustc_errors" }
rustc_fs_util = { path = "../rustc_fs_util" }
rustc_hir = { path = "../rustc_hir" }
rustc_session = { path = "../rustc_session" }
[dependencies.object]
-version = "0.22.0"
+version = "0.25.2"
default-features = false
-features = ["read_core", "elf", "macho", "pe", "unaligned", "archive"]
+features = ["read_core", "elf", "macho", "pe", "unaligned", "archive", "write"]
+use rustc_data_structures::temp_dir::MaybeTempDir;
+use rustc_middle::middle::cstore::DllImport;
use rustc_session::Session;
use rustc_span::symbol::Symbol;
fn update_symbols(&mut self);
fn build(self);
+
+ fn inject_dll_import_lib(
+ &mut self,
+ lib_name: &str,
+ dll_imports: &[DllImport],
+ tmpdir: &MaybeTempDir,
+ );
}
-use rustc_data_structures::fx::FxHashSet;
+use rustc_data_structures::fx::{FxHashMap, FxHashSet};
use rustc_data_structures::temp_dir::MaybeTempDir;
use rustc_errors::Handler;
use rustc_fs_util::fix_windows_verbatim_for_gcc;
use rustc_hir::def_id::CrateNum;
-use rustc_middle::middle::cstore::{EncodedMetadata, LibSource};
+use rustc_middle::middle::cstore::{DllImport, LibSource};
use rustc_middle::middle::dependency_format::Linkage;
-use rustc_session::config::{self, CFGuard, CrateType, DebugInfo};
+use rustc_session::config::{self, CFGuard, CrateType, DebugInfo, LdImpl, Strip};
use rustc_session::config::{OutputFilenames, OutputType, PrintRequest};
use rustc_session::output::{check_file_is_writeable, invalid_output_for_target, out_filename};
use rustc_session::search_paths::PathKind;
/// need out of the shared crate context before we get rid of it.
use rustc_session::{filesearch, Session};
use rustc_span::symbol::Symbol;
+use rustc_target::abi::Endian;
use rustc_target::spec::crt_objects::{CrtObjects, CrtObjectsFallback};
use rustc_target::spec::{LinkOutputKind, LinkerFlavor, LldFlavor, SplitDebuginfo};
use rustc_target::spec::{PanicStrategy, RelocModel, RelroLevel, SanitizerSet, Target};
};
use cc::windows_registry;
+use object::elf;
+use object::write::Object;
+use object::{Architecture, BinaryFormat, Endianness, FileFlags, SectionFlags, SectionKind};
use tempfile::Builder as TempFileBuilder;
+use std::cmp::Ordering;
use std::ffi::OsString;
use std::path::{Path, PathBuf};
use std::process::{ExitStatus, Output, Stdio};
/// building an `.rlib` (stomping over one another), or writing an `.rmeta` into a
/// directory being searched for `extern crate` (observing an incomplete file).
/// The returned path is the temporary file containing the complete metadata.
-pub fn emit_metadata(sess: &Session, metadata: &EncodedMetadata, tmpdir: &MaybeTempDir) -> PathBuf {
+pub fn emit_metadata(sess: &Session, metadata: &[u8], tmpdir: &MaybeTempDir) -> PathBuf {
let out_filename = tmpdir.as_ref().join(METADATA_FILENAME);
- let result = fs::write(&out_filename, &metadata.raw_data);
+ let result = fs::write(&out_filename, metadata);
if let Err(e) = result {
sess.fatal(&format!("failed to write {}: {}", out_filename.display(), e));
}
}
+ for (raw_dylib_name, raw_dylib_imports) in
+ collate_raw_dylibs(&codegen_results.crate_info.used_libraries)
+ {
+ ab.inject_dll_import_lib(&raw_dylib_name, &raw_dylib_imports, tmpdir);
+ }
+
// After adding all files to the archive, we need to update the
// symbol table of the archive.
ab.update_symbols();
// code above.
match flavor {
RlibFlavor::Normal => {
- // Instead of putting the metadata in an object file section, rlibs
- // contain the metadata in a separate file.
- ab.add_file(&emit_metadata(sess, &codegen_results.metadata, tmpdir));
+ // metadata in rlib files is wrapped in a "dummy" object file for
+ // the target platform so the rlib can be processed entirely by
+ // normal linkers for the platform.
+ let metadata = create_metadata_file(sess, &codegen_results.metadata.raw_data);
+ ab.add_file(&emit_metadata(sess, &metadata, tmpdir));
// After adding all files to the archive, we need to update the
// symbol table of the archive. This currently dies on macOS (see
}
}
}
+ return ab;
+
+ // For rlibs we "pack" rustc metadata into a dummy object file. When rustc
+ // creates a dylib crate type it will pass `--whole-archive` (or the
+ // platform equivalent) to include all object files from an rlib into the
+ // final dylib itself. This causes linkers to iterate and try to include all
+ // files located in an archive, so if metadata is stored in an archive then
+ // it needs to be of a form that the linker will be able to process.
+ //
+ // Note, though, that we don't actually want this metadata to show up in any
+ // final output of the compiler. Instead this is purely for rustc's own
+ // metadata tracking purposes.
+ //
+ // With the above in mind, each "flavor" of object format gets special
+ // handling here depending on the target:
+ //
+ // * MachO - macos-like targets will insert the metadata into a section that
+ // is sort of fake dwarf debug info. Inspecting the source of the macos
+ // linker this causes these sections to be skipped automatically because
+ // it's not in an allowlist of otherwise well known dwarf section names to
+ // go into the final artifact.
+ //
+ // * WebAssembly - we actually don't have any container format for this
+ // target. WebAssembly doesn't support the `dylib` crate type anyway so
+ // there's no need for us to support this at this time. Consequently the
+ // metadata bytes are simply stored as-is into an rlib.
+ //
+ // * COFF - Windows-like targets create an object with a section that has
+ // the `IMAGE_SCN_LNK_REMOVE` flag set which ensures that if the linker
+ // ever sees the section it doesn't process it and it's removed.
+ //
+ // * ELF - All other targets are similar to Windows in that there's a
+ // `SHF_EXCLUDE` flag we can set on sections in an object file to get
+ // automatically removed from the final output.
+ //
+ // Note that this metdata format is kept in sync with
+ // `rustc_codegen_ssa/src/back/metadata.rs`.
+ fn create_metadata_file(sess: &Session, metadata: &[u8]) -> Vec<u8> {
+ let endianness = match sess.target.options.endian {
+ Endian::Little => Endianness::Little,
+ Endian::Big => Endianness::Big,
+ };
+ let architecture = match &sess.target.arch[..] {
+ "arm" => Architecture::Arm,
+ "aarch64" => Architecture::Aarch64,
+ "x86" => Architecture::I386,
+ "s390x" => Architecture::S390x,
+ "mips" => Architecture::Mips,
+ "mips64" => Architecture::Mips64,
+ "x86_64" => {
+ if sess.target.pointer_width == 32 {
+ Architecture::X86_64_X32
+ } else {
+ Architecture::X86_64
+ }
+ }
+ "powerpc" => Architecture::PowerPc,
+ "powerpc64" => Architecture::PowerPc64,
+ "riscv32" => Architecture::Riscv32,
+ "riscv64" => Architecture::Riscv64,
+ "sparc64" => Architecture::Sparc64,
+
+ // This is used to handle all "other" targets. This includes targets
+ // in two categories:
+ //
+ // * Some targets don't have support in the `object` crate just yet
+ // to write an object file. These targets are likely to get filled
+ // out over time.
+ //
+ // * Targets like WebAssembly don't support dylibs, so the purpose
+ // of putting metadata in object files, to support linking rlibs
+ // into dylibs, is moot.
+ //
+ // In both of these cases it means that linking into dylibs will
+ // not be supported by rustc. This doesn't matter for targets like
+ // WebAssembly and for targets not supported by the `object` crate
+ // yet it means that work will need to be done in the `object` crate
+ // to add a case above.
+ _ => return metadata.to_vec(),
+ };
+
+ if sess.target.is_like_osx {
+ let mut file = Object::new(BinaryFormat::MachO, architecture, endianness);
+
+ let section =
+ file.add_section(b"__DWARF".to_vec(), b".rmeta".to_vec(), SectionKind::Debug);
+ file.append_section_data(section, metadata, 1);
+ file.write().unwrap()
+ } else if sess.target.is_like_windows {
+ const IMAGE_SCN_LNK_REMOVE: u32 = 0;
+ let mut file = Object::new(BinaryFormat::Coff, architecture, endianness);
+
+ let section = file.add_section(Vec::new(), b".rmeta".to_vec(), SectionKind::Debug);
+ file.section_mut(section).flags =
+ SectionFlags::Coff { characteristics: IMAGE_SCN_LNK_REMOVE };
+ file.append_section_data(section, metadata, 1);
+ file.write().unwrap()
+ } else {
+ const SHF_EXCLUDE: u64 = 0x80000000;
+ let mut file = Object::new(BinaryFormat::Elf, architecture, endianness);
+
+ match &sess.target.arch[..] {
+ // copied from `mipsel-linux-gnu-gcc foo.c -c` and
+ // inspecting the resulting `e_flags` field.
+ "mips" => {
+ let e_flags = elf::EF_MIPS_ARCH_32R2 | elf::EF_MIPS_CPIC | elf::EF_MIPS_PIC;
+ file.flags = FileFlags::Elf { e_flags };
+ }
+ // copied from `mips64el-linux-gnuabi64-gcc foo.c -c`
+ "mips64" => {
+ let e_flags = elf::EF_MIPS_ARCH_64R2 | elf::EF_MIPS_CPIC | elf::EF_MIPS_PIC;
+ file.flags = FileFlags::Elf { e_flags };
+ }
+
+ // copied from `riscv64-linux-gnu-gcc foo.c -c`, note though
+ // that the `+d` target feature represents whether the double
+ // float abi is enabled.
+ "riscv64" if sess.target.options.features.contains("+d") => {
+ let e_flags = elf::EF_RISCV_RVC | elf::EF_RISCV_FLOAT_ABI_DOUBLE;
+ file.flags = FileFlags::Elf { e_flags };
+ }
+
+ _ => {}
+ }
+
+ let section = file.add_section(Vec::new(), b".rmeta".to_vec(), SectionKind::Debug);
+ file.section_mut(section).flags = SectionFlags::Elf { sh_flags: SHF_EXCLUDE };
+ file.append_section_data(section, metadata, 1);
+ file.write().unwrap()
+ }
+ }
+}
+
+/// Extract all symbols defined in raw-dylib libraries, collated by library name.
+///
+/// If we have multiple extern blocks that specify symbols defined in the same raw-dylib library,
+/// then the CodegenResults value contains one NativeLib instance for each block. However, the
+/// linker appears to expect only a single import library for each library used, so we need to
+/// collate the symbols together by library name before generating the import libraries.
+fn collate_raw_dylibs(used_libraries: &[NativeLib]) -> Vec<(String, Vec<DllImport>)> {
+ let mut dylib_table: FxHashMap<String, FxHashSet<Symbol>> = FxHashMap::default();
+
+ for lib in used_libraries {
+ if lib.kind == NativeLibKind::RawDylib {
+ let name = lib.name.unwrap_or_else(||
+ bug!("`link` attribute with kind = \"raw-dylib\" and no name should have caused error earlier")
+ );
+ let name = if matches!(lib.verbatim, Some(true)) {
+ name.to_string()
+ } else {
+ format!("{}.dll", name)
+ };
+ dylib_table
+ .entry(name)
+ .or_default()
+ .extend(lib.dll_imports.iter().map(|import| import.name));
+ }
+ }
- ab
+ // FIXME: when we add support for ordinals, fix this to propagate ordinals. Also figure out
+ // what we should do if we have two DllImport values with the same name but different
+ // ordinals.
+ let mut result = dylib_table
+ .into_iter()
+ .map(|(lib_name, imported_names)| {
+ let mut names = imported_names
+ .iter()
+ .map(|name| DllImport { name: *name, ordinal: None })
+ .collect::<Vec<_>>();
+ names.sort_unstable_by(|a: &DllImport, b: &DllImport| {
+ match a.name.as_str().cmp(&b.name.as_str()) {
+ Ordering::Equal => a.ordinal.cmp(&b.ordinal),
+ x => x,
+ }
+ });
+ (lib_name, names)
+ })
+ .collect::<Vec<_>>();
+ result.sort_unstable_by(|a: &(String, Vec<DllImport>), b: &(String, Vec<DllImport>)| {
+ a.0.cmp(&b.0)
+ });
+ result
}
/// Create a static archive.
}
}
- fn escape_string(s: &[u8]) -> String {
- str::from_utf8(s).map(|s| s.to_owned()).unwrap_or_else(|_| {
- let mut x = "Non-UTF-8 output: ".to_string();
- x.extend(s.iter().flat_map(|&b| ascii::escape_default(b)).map(char::from));
- x
- })
- }
-
match prog {
Ok(prog) => {
if !prog.status.success() {
// ... and otherwise we're processing a `*.dwp` packed dwarf file.
SplitDebuginfo::Packed => link_dwarf_object(sess, &out_filename),
}
+
+ if sess.target.is_like_osx {
+ if let Some(option) = osx_strip_opt(sess.opts.debugging_opts.strip) {
+ strip_symbols_in_osx(sess, &out_filename, option);
+ }
+ }
}
-fn link_sanitizers(sess: &Session, crate_type: CrateType, linker: &mut dyn Linker) {
+fn strip_symbols_in_osx<'a>(sess: &'a Session, out_filename: &Path, option: &str) {
+ let prog = Command::new("strip").arg(option).arg(out_filename).output();
+ match prog {
+ Ok(prog) => {
+ if !prog.status.success() {
+ let mut output = prog.stderr.clone();
+ output.extend_from_slice(&prog.stdout);
+ sess.struct_warn(&format!(
+ "stripping debug info with `strip` failed: {}",
+ prog.status
+ ))
+ .note(&escape_string(&output))
+ .emit();
+ }
+ }
+ Err(e) => sess.fatal(&format!("unable to run `strip`: {}", e)),
+ }
+}
+
+fn osx_strip_opt<'a>(strip: Strip) -> Option<&'a str> {
+ match strip {
+ Strip::Debuginfo => Some("-S"),
+ Strip::Symbols => Some("-x"),
+ Strip::None => None,
+ }
+}
+
+fn escape_string(s: &[u8]) -> String {
+ str::from_utf8(s).map(|s| s.to_owned()).unwrap_or_else(|_| {
+ let mut x = "Non-UTF-8 output: ".to_string();
+ x.extend(s.iter().flat_map(|&b| ascii::escape_default(b)).map(char::from));
+ x
+ })
+}
+
+fn add_sanitizer_libraries(sess: &Session, crate_type: CrateType, linker: &mut dyn Linker) {
// On macOS the runtimes are distributed as dylibs which should be linked to
// both executables and dynamic shared objects. Everywhere else the runtimes
// are currently distributed as static liraries which should be linked to
&& (info.compiler_builtins == Some(cnum) || info.is_no_builtins.contains(&cnum))
}
-fn linker_and_flavor(sess: &Session) -> (PathBuf, LinkerFlavor) {
+// This functions tries to determine the appropriate linker (and corresponding LinkerFlavor) to use
+pub fn linker_and_flavor(sess: &Session) -> (PathBuf, LinkerFlavor) {
fn infer_from(
sess: &Session,
linker: Option<PathBuf>,
LinkerFlavor::Msvc => "link.exe",
LinkerFlavor::Lld(_) => "lld",
LinkerFlavor::PtxLinker => "rust-ptx-linker",
+ LinkerFlavor::BpfLinker => "bpf-linker",
}),
flavor,
)),
|| stem.ends_with("-clang")
{
LinkerFlavor::Gcc
+ } else if stem == "wasm-ld" || stem.ends_with("-wasm-ld") {
+ LinkerFlavor::Lld(LldFlavor::Wasm)
} else if stem == "ld" || stem == "ld.lld" || stem.ends_with("-ld") {
LinkerFlavor::Ld
} else if stem == "link" || stem == "lld-link" {
}
}
-/// Link native libraries corresponding to the current crate and all libraries corresponding to
-/// all its dependency crates.
-/// FIXME: Consider combining this with the functions above adding object files for the local crate.
-fn link_local_crate_native_libs_and_dependent_crate_libs<'a, B: ArchiveBuilder<'a>>(
- cmd: &mut dyn Linker,
- sess: &'a Session,
- crate_type: CrateType,
- codegen_results: &CodegenResults,
- tmpdir: &Path,
-) {
- // Take careful note of the ordering of the arguments we pass to the linker
- // here. Linkers will assume that things on the left depend on things to the
- // right. Things on the right cannot depend on things on the left. This is
- // all formally implemented in terms of resolving symbols (libs on the right
- // resolve unknown symbols of libs on the left, but not vice versa).
- //
- // For this reason, we have organized the arguments we pass to the linker as
- // such:
- //
- // 1. The local object that LLVM just generated
- // 2. Local native libraries
- // 3. Upstream rust libraries
- // 4. Upstream native libraries
- //
- // The rationale behind this ordering is that those items lower down in the
- // list can't depend on items higher up in the list. For example nothing can
- // depend on what we just generated (e.g., that'd be a circular dependency).
- // Upstream rust libraries are not allowed to depend on our local native
- // libraries as that would violate the structure of the DAG, in that
- // scenario they are required to link to them as well in a shared fashion.
- //
- // Note that upstream rust libraries may contain native dependencies as
- // well, but they also can't depend on what we just started to add to the
- // link line. And finally upstream native libraries can't depend on anything
- // in this DAG so far because they're only dylibs and dylibs can only depend
- // on other dylibs (e.g., other native deps).
- //
- // If -Zlink-native-libraries=false is set, then the assumption is that an
- // external build system already has the native dependencies defined, and it
- // will provide them to the linker itself.
- if sess.opts.debugging_opts.link_native_libraries {
- add_local_native_libraries(cmd, sess, codegen_results);
- }
- add_upstream_rust_crates::<B>(cmd, sess, codegen_results, crate_type, tmpdir);
- if sess.opts.debugging_opts.link_native_libraries {
- add_upstream_native_libraries(cmd, sess, codegen_results, crate_type);
- }
-}
-
/// Add sysroot and other globally set directories to the directory search list.
fn add_library_search_dirs(cmd: &mut dyn Linker, sess: &Session, self_contained: bool) {
// The default library location, we need this to find the runtime.
) {
// FIXME (#2397): At some point we want to rpath our guesses as to
// where extern libraries might live, based on the
- // addl_lib_search_paths
+ // add_lib_search_paths
if sess.opts.cg.rpath {
- let target_triple = sess.opts.target_triple.triple();
- let mut get_install_prefix_lib_path = || {
- let install_prefix = option_env!("CFG_PREFIX").expect("CFG_PREFIX");
- let tlib = rustc_target::target_rustlib_path(&sess.sysroot, target_triple).join("lib");
- let mut path = PathBuf::from(install_prefix);
- path.push(&tlib);
-
- path
- };
let mut rpath_config = RPathConfig {
used_crates: &codegen_results.crate_info.used_crates_dynamic,
out_filename: out_filename.to_path_buf(),
has_rpath: sess.target.has_rpath,
is_like_osx: sess.target.is_like_osx,
linker_is_gnu: sess.target.linker_is_gnu,
- get_install_prefix_lib_path: &mut get_install_prefix_lib_path,
};
cmd.args(&rpath::get_rpath_flags(&mut rpath_config));
}
}
/// Produce the linker command line containing linker path and arguments.
-/// `NO-OPT-OUT` marks the arguments that cannot be removed from the command line
-/// by the user without creating a custom target specification.
-/// `OBJECT-FILES` specify whether the arguments can add object files.
-/// `CUSTOMIZATION-POINT` means that arbitrary arguments defined by the user
-/// or by the target spec can be inserted here.
-/// `AUDIT-ORDER` - need to figure out whether the option is order-dependent or not.
+///
+/// When comments in the function say "order-(in)dependent" they mean order-dependence between
+/// options and libraries/object files. For example `--whole-archive` (order-dependent) applies
+/// to specific libraries passed after it, and `-o` (output file, order-independent) applies
+/// to the linking process as a whole.
+/// Order-independent options may still override each other in order-dependent fashion,
+/// e.g `--foo=yes --foo=no` may be equivalent to `--foo=no`.
fn linker_with_args<'a, B: ArchiveBuilder<'a>>(
path: &Path,
flavor: LinkerFlavor,
let cmd = &mut *codegen_results.linker_info.to_linker(base_cmd, &sess, flavor);
let link_output_kind = link_output_kind(sess, crate_type);
- // NO-OPT-OUT, OBJECT-FILES-MAYBE, CUSTOMIZATION-POINT
+ // ------------ Early order-dependent options ------------
+
+ // If we're building something like a dynamic library then some platforms
+ // need to make sure that all symbols are exported correctly from the
+ // dynamic library.
+ // Must be passed before any libraries to prevent the symbols to export from being thrown away,
+ // at least on some platforms (e.g. windows-gnu).
+ cmd.export_symbols(tmpdir, crate_type);
+
+ // Can be used for adding custom CRT objects or overriding order-dependent options above.
+ // FIXME: In practice built-in target specs use this for arbitrary order-independent options,
+ // introduce a target spec option for order-independent linker options and migrate built-in
+ // specs to it.
add_pre_link_args(cmd, sess, flavor);
- // NO-OPT-OUT, OBJECT-FILES-NO
+ // ------------ Object code and libraries, order-dependent ------------
+
+ // Pre-link CRT objects.
+ add_pre_link_objects(cmd, sess, link_output_kind, crt_objects_fallback);
+
+ // Sanitizer libraries.
+ add_sanitizer_libraries(sess, crate_type, cmd);
+
+ // Object code from the current crate.
+ // Take careful note of the ordering of the arguments we pass to the linker
+ // here. Linkers will assume that things on the left depend on things to the
+ // right. Things on the right cannot depend on things on the left. This is
+ // all formally implemented in terms of resolving symbols (libs on the right
+ // resolve unknown symbols of libs on the left, but not vice versa).
+ //
+ // For this reason, we have organized the arguments we pass to the linker as
+ // such:
+ //
+ // 1. The local object that LLVM just generated
+ // 2. Local native libraries
+ // 3. Upstream rust libraries
+ // 4. Upstream native libraries
+ //
+ // The rationale behind this ordering is that those items lower down in the
+ // list can't depend on items higher up in the list. For example nothing can
+ // depend on what we just generated (e.g., that'd be a circular dependency).
+ // Upstream rust libraries are not supposed to depend on our local native
+ // libraries as that would violate the structure of the DAG, in that
+ // scenario they are required to link to them as well in a shared fashion.
+ // (The current implementation still doesn't prevent it though, see the FIXME below.)
+ //
+ // Note that upstream rust libraries may contain native dependencies as
+ // well, but they also can't depend on what we just started to add to the
+ // link line. And finally upstream native libraries can't depend on anything
+ // in this DAG so far because they can only depend on other native libraries
+ // and such dependencies are also required to be specified.
+ add_local_crate_regular_objects(cmd, codegen_results);
+ add_local_crate_metadata_objects(cmd, crate_type, codegen_results);
+ add_local_crate_allocator_objects(cmd, codegen_results);
+
+ // Avoid linking to dynamic libraries unless they satisfy some undefined symbols
+ // at the point at which they are specified on the command line.
+ // Must be passed before any (dynamic) libraries to have effect on them.
+ // On Solaris-like systems, `-z ignore` acts as both `--as-needed` and `--gc-sections`
+ // so it will ignore unreferenced ELF sections from relocatable objects.
+ // For that reason, we put this flag after metadata objects as they would otherwise be removed.
+ // FIXME: Support more fine-grained dead code removal on Solaris/illumos
+ // and move this option back to the top.
+ cmd.add_as_needed();
+
+ // FIXME: Move this below to other native libraries
+ // (or alternatively link all native libraries after their respective crates).
+ // This change is somewhat breaking in practice due to local static libraries being linked
+ // as whole-archive (#85144), so removing whole-archive may be a pre-requisite.
+ if sess.opts.debugging_opts.link_native_libraries {
+ add_local_native_libraries(cmd, sess, codegen_results);
+ }
+
+ // Rust libraries.
+ add_upstream_rust_crates::<B>(cmd, sess, codegen_results, crate_type, tmpdir);
+
+ // Native libraries linked with `#[link]` attributes at and `-l` command line options.
+ // If -Zlink-native-libraries=false is set, then the assumption is that an
+ // external build system already has the native dependencies defined, and it
+ // will provide them to the linker itself.
+ if sess.opts.debugging_opts.link_native_libraries {
+ add_upstream_native_libraries(cmd, sess, codegen_results, crate_type);
+ }
+
+ // Library linking above uses some global state for things like `-Bstatic`/`-Bdynamic` to make
+ // command line shorter, reset it to default here before adding more libraries.
+ cmd.reset_per_library_state();
+
+ // FIXME: Built-in target specs occasionally use this for linking system libraries,
+ // eliminate all such uses by migrating them to `#[link]` attributes in `lib(std,c,unwind)`
+ // and remove the option.
+ add_late_link_args(cmd, sess, flavor, crate_type, codegen_results);
+
+ // ------------ Arbitrary order-independent options ------------
+
+ // Add order-independent options determined by rustc from its compiler options,
+ // target properties and source code.
+ add_order_independent_options(
+ cmd,
+ sess,
+ link_output_kind,
+ crt_objects_fallback,
+ flavor,
+ crate_type,
+ codegen_results,
+ out_filename,
+ tmpdir,
+ );
+
+ // Can be used for arbitrary order-independent options.
+ // In practice may also be occasionally used for linking native libraries.
+ // Passed after compiler-generated options to support manual overriding when necessary.
+ add_user_defined_link_args(cmd, sess);
+
+ // ------------ Object code and libraries, order-dependent ------------
+
+ // Post-link CRT objects.
+ add_post_link_objects(cmd, sess, link_output_kind, crt_objects_fallback);
+
+ // ------------ Late order-dependent options ------------
+
+ // Doesn't really make sense.
+ // FIXME: In practice built-in target specs use this for arbitrary order-independent options,
+ // introduce a target spec option for order-independent linker options, migrate built-in specs
+ // to it and remove the option.
+ add_post_link_args(cmd, sess, flavor);
+
+ cmd.take_cmd()
+}
+
+fn add_order_independent_options(
+ cmd: &mut dyn Linker,
+ sess: &Session,
+ link_output_kind: LinkOutputKind,
+ crt_objects_fallback: bool,
+ flavor: LinkerFlavor,
+ crate_type: CrateType,
+ codegen_results: &CodegenResults,
+ out_filename: &Path,
+ tmpdir: &Path,
+) {
+ add_gcc_ld_path(cmd, sess, flavor);
+
add_apple_sdk(cmd, sess, flavor);
- // NO-OPT-OUT
add_link_script(cmd, sess, tmpdir, crate_type);
- // NO-OPT-OUT, OBJECT-FILES-NO, AUDIT-ORDER
if sess.target.is_like_fuchsia && crate_type == CrateType::Executable {
let prefix = if sess.opts.debugging_opts.sanitizer.contains(SanitizerSet::ADDRESS) {
"asan/"
cmd.arg(format!("--dynamic-linker={}ld.so.1", prefix));
}
- // NO-OPT-OUT, OBJECT-FILES-NO, AUDIT-ORDER
if sess.target.eh_frame_header {
cmd.add_eh_frame_header();
}
- // NO-OPT-OUT, OBJECT-FILES-NO, AUDIT-ORDER
// Make the binary compatible with data execution prevention schemes.
cmd.add_no_exec();
- // NO-OPT-OUT, OBJECT-FILES-NO
- // Avoid linking to dynamic libraries unless they satisfy some undefined symbols
- // at the point at which they are specified on the command line.
- // Must be passed before any dynamic libraries.
- cmd.add_as_needed();
-
- // NO-OPT-OUT, OBJECT-FILES-NO
if crt_objects_fallback {
cmd.no_crt_objects();
}
- // NO-OPT-OUT, OBJECT-FILES-YES
- add_pre_link_objects(cmd, sess, link_output_kind, crt_objects_fallback);
-
- // NO-OPT-OUT, OBJECT-FILES-NO, AUDIT-ORDER
if sess.target.is_like_emscripten {
cmd.arg("-s");
cmd.arg(if sess.panic_strategy() == PanicStrategy::Abort {
});
}
- // OBJECT-FILES-YES, AUDIT-ORDER
- link_sanitizers(sess, crate_type, cmd);
+ if flavor == LinkerFlavor::PtxLinker {
+ // Provide the linker with fallback to internal `target-cpu`.
+ cmd.arg("--fallback-arch");
+ cmd.arg(&codegen_results.linker_info.target_cpu);
+ } else if flavor == LinkerFlavor::BpfLinker {
+ cmd.arg("--cpu");
+ cmd.arg(&codegen_results.linker_info.target_cpu);
+ cmd.arg("--cpu-features");
+ cmd.arg(match &sess.opts.cg.target_feature {
+ feat if !feat.is_empty() => feat,
+ _ => &sess.target.options.features,
+ });
+ }
- // OBJECT-FILES-NO, AUDIT-ORDER
- // Linker plugins should be specified early in the list of arguments
- // FIXME: How "early" exactly?
cmd.linker_plugin_lto();
- // NO-OPT-OUT, OBJECT-FILES-NO, AUDIT-ORDER
- // FIXME: Order-dependent, at least relatively to other args adding searh directories.
add_library_search_dirs(cmd, sess, crt_objects_fallback);
- // OBJECT-FILES-YES
- add_local_crate_regular_objects(cmd, codegen_results);
-
- // NO-OPT-OUT, OBJECT-FILES-NO, AUDIT-ORDER
cmd.output_filename(out_filename);
- // OBJECT-FILES-NO, AUDIT-ORDER
if crate_type == CrateType::Executable && sess.target.is_like_windows {
- if let Some(ref s) = codegen_results.windows_subsystem {
+ if let Some(ref s) = codegen_results.crate_info.windows_subsystem {
cmd.subsystem(s);
}
}
- // NO-OPT-OUT, OBJECT-FILES-NO, AUDIT-ORDER
- // If we're building something like a dynamic library then some platforms
- // need to make sure that all symbols are exported correctly from the
- // dynamic library.
- cmd.export_symbols(tmpdir, crate_type);
-
- // OBJECT-FILES-YES
- add_local_crate_metadata_objects(cmd, crate_type, codegen_results);
-
- // OBJECT-FILES-YES
- add_local_crate_allocator_objects(cmd, codegen_results);
-
- // OBJECT-FILES-NO, AUDIT-ORDER
- // FIXME: Order dependent, applies to the following objects. Where should it be placed?
// Try to strip as much out of the generated object by removing unused
// sections if possible. See more comments in linker.rs
if !sess.link_dead_code() {
cmd.gc_sections(keep_metadata);
}
- // NO-OPT-OUT, OBJECT-FILES-NO, AUDIT-ORDER
cmd.set_output_kind(link_output_kind, out_filename);
- // OBJECT-FILES-NO, AUDIT-ORDER
add_relro_args(cmd, sess);
- // OBJECT-FILES-NO, AUDIT-ORDER
// Pass optimization flags down to the linker.
cmd.optimize();
- // OBJECT-FILES-NO, AUDIT-ORDER
// Pass debuginfo and strip flags down to the linker.
cmd.debuginfo(sess.opts.debugging_opts.strip);
- // OBJECT-FILES-NO, AUDIT-ORDER
// We want to prevent the compiler from accidentally leaking in any system libraries,
// so by default we tell linkers not to link to any default libraries.
if !sess.opts.cg.default_linker_libraries && sess.target.no_default_libraries {
cmd.no_default_libraries();
}
- // OBJECT-FILES-YES
- link_local_crate_native_libs_and_dependent_crate_libs::<B>(
- cmd,
- sess,
- crate_type,
- codegen_results,
- tmpdir,
- );
-
- // OBJECT-FILES-NO, AUDIT-ORDER
if sess.opts.cg.profile_generate.enabled() || sess.instrument_coverage() {
cmd.pgo_gen();
}
- // OBJECT-FILES-NO, AUDIT-ORDER
if sess.opts.cg.control_flow_guard != CFGuard::Disabled {
cmd.control_flow_guard();
}
- // OBJECT-FILES-NO, AUDIT-ORDER
add_rpath_args(cmd, sess, codegen_results, out_filename);
-
- // OBJECT-FILES-MAYBE, CUSTOMIZATION-POINT
- add_user_defined_link_args(cmd, sess);
-
- // NO-OPT-OUT, OBJECT-FILES-NO, AUDIT-ORDER
- cmd.finalize();
-
- // NO-OPT-OUT, OBJECT-FILES-MAYBE, CUSTOMIZATION-POINT
- add_late_link_args(cmd, sess, flavor, crate_type, codegen_results);
-
- // NO-OPT-OUT, OBJECT-FILES-YES
- add_post_link_objects(cmd, sess, link_output_kind, crt_objects_fallback);
-
- // NO-OPT-OUT, OBJECT-FILES-MAYBE, CUSTOMIZATION-POINT
- add_post_link_args(cmd, sess, flavor);
-
- cmd.take_cmd()
}
/// # Native library linking
}
// Adds the static "rlib" versions of all crates to the command line.
- // There's a bit of magic which happens here specifically related to LTO and
- // dynamic libraries. Specifically:
- //
- // * For LTO, we remove upstream object files.
- // * For dylibs we remove metadata and bytecode from upstream rlibs
+ // There's a bit of magic which happens here specifically related to LTO,
+ // namely that we remove upstream object files.
//
// When performing LTO, almost(*) all of the bytecode from the upstream
// libraries has already been included in our object file output. As a
// their bytecode wasn't included. The object files in those libraries must
// still be passed to the linker.
//
- // When making a dynamic library, linkers by default don't include any
- // object files in an archive if they're not necessary to resolve the link.
- // We basically want to convert the archive (rlib) to a dylib, though, so we
- // *do* want everything included in the output, regardless of whether the
- // linker thinks it's needed or not. As a result we must use the
- // --whole-archive option (or the platform equivalent). When using this
- // option the linker will fail if there are non-objects in the archive (such
- // as our own metadata and/or bytecode). All in all, for rlibs to be
- // entirely included in dylibs, we need to remove all non-object files.
- //
- // Note, however, that if we're not doing LTO or we're not producing a dylib
- // (aka we're making an executable), we can just pass the rlib blindly to
- // the linker (fast) because it's fine if it's not actually included as
- // we're at the end of the dependency chain.
+ // Note, however, that if we're not doing LTO we can just pass the rlib
+ // blindly to the linker (fast) because it's fine if it's not actually
+ // included as we're at the end of the dependency chain.
fn add_static_crate<'a, B: ArchiveBuilder<'a>>(
cmd: &mut dyn Linker,
sess: &'a Session,
let src = &codegen_results.crate_info.used_crate_source[&cnum];
let cratepath = &src.rlib.as_ref().unwrap().0;
+ let mut link_upstream = |path: &Path| {
+ // If we're creating a dylib, then we need to include the
+ // whole of each object in our archive into that artifact. This is
+ // because a `dylib` can be reused as an intermediate artifact.
+ //
+ // Note, though, that we don't want to include the whole of a
+ // compiler-builtins crate (e.g., compiler-rt) because it'll get
+ // repeatedly linked anyway.
+ let path = fix_windows_verbatim_for_gcc(path);
+ if crate_type == CrateType::Dylib
+ && codegen_results.crate_info.compiler_builtins != Some(cnum)
+ {
+ cmd.link_whole_rlib(&path);
+ } else {
+ cmd.link_rlib(&path);
+ }
+ };
+
// See the comment above in `link_staticlib` and `link_rlib` for why if
// there's a static library that's not relevant we skip all object
// files.
if (!are_upstream_rust_objects_already_included(sess)
|| ignored_for_lto(sess, &codegen_results.crate_info, cnum))
- && crate_type != CrateType::Dylib
&& !skip_native
{
- cmd.link_rlib(&fix_windows_verbatim_for_gcc(cratepath));
+ link_upstream(cratepath);
return;
}
return;
}
archive.build();
-
- // If we're creating a dylib, then we need to include the
- // whole of each object in our archive into that artifact. This is
- // because a `dylib` can be reused as an intermediate artifact.
- //
- // Note, though, that we don't want to include the whole of a
- // compiler-builtins crate (e.g., compiler-rt) because it'll get
- // repeatedly linked anyway.
- if crate_type == CrateType::Dylib
- && codegen_results.crate_info.compiler_builtins != Some(cnum)
- {
- cmd.link_whole_rlib(&fix_windows_verbatim_for_gcc(&dst));
- } else {
- cmd.link_rlib(&fix_windows_verbatim_for_gcc(&dst));
- }
+ link_upstream(&dst);
});
}
// already included them when we included the rust library
// previously
NativeLibKind::Static { bundle: None | Some(true), .. } => {}
- NativeLibKind::RawDylib => {
- // FIXME(#58713): Proper handling for raw dylibs.
- bug!("raw_dylib feature not yet implemented");
- }
+ NativeLibKind::RawDylib => {}
}
}
}
Err(e) => Err(format!("failed to get {} SDK path: {}", sdk_name, e)),
}
}
+
+fn add_gcc_ld_path(cmd: &mut dyn Linker, sess: &Session, flavor: LinkerFlavor) {
+ if let Some(ld_impl) = sess.opts.debugging_opts.gcc_ld {
+ if let LinkerFlavor::Gcc = flavor {
+ match ld_impl {
+ LdImpl::Lld => {
+ let tools_path =
+ sess.host_filesearch(PathKind::All).get_tools_search_paths(false);
+ let lld_path = tools_path
+ .into_iter()
+ .map(|p| p.join("gcc-ld"))
+ .find(|p| {
+ p.join(if sess.host.is_like_windows { "ld.exe" } else { "ld" }).exists()
+ })
+ .unwrap_or_else(|| sess.fatal("rust-lld (as ld) not found"));
+ cmd.cmd().arg({
+ let mut arg = OsString::from("-B");
+ arg.push(lld_path);
+ arg
+ });
+ }
+ }
+ } else {
+ sess.fatal("option `-Z gcc-ld` is used even though linker flavor is not gcc");
+ }
+ }
+}
/// need out of the shared crate context before we get rid of it.
#[derive(Encodable, Decodable)]
pub struct LinkerInfo {
- target_cpu: String,
+ pub(super) target_cpu: String,
exports: FxHashMap<CrateType, Vec<String>>,
}
Box::new(WasmLd::new(cmd, sess, self)) as Box<dyn Linker>
}
- LinkerFlavor::PtxLinker => {
- Box::new(PtxLinker { cmd, sess, info: self }) as Box<dyn Linker>
+ LinkerFlavor::PtxLinker => Box::new(PtxLinker { cmd, sess }) as Box<dyn Linker>,
+
+ LinkerFlavor::BpfLinker => {
+ Box::new(BpfLinker { cmd, sess, info: self }) as Box<dyn Linker>
}
}
}
fn add_eh_frame_header(&mut self) {}
fn add_no_exec(&mut self) {}
fn add_as_needed(&mut self) {}
- fn finalize(&mut self);
+ fn reset_per_library_state(&mut self) {}
}
impl dyn Linker + '_ {
// eliminate the metadata. If we're building an executable, however,
// --gc-sections drops the size of hello world from 1.8MB to 597K, a 67%
// reduction.
- } else if self.sess.target.linker_is_gnu && !keep_metadata {
+ } else if (self.sess.target.linker_is_gnu || self.sess.target.is_like_wasm)
+ && !keep_metadata
+ {
self.linker_arg("--gc-sections");
}
}
fn no_gc_sections(&mut self) {
if self.sess.target.is_like_osx {
self.linker_arg("-no_dead_strip");
- } else if self.sess.target.linker_is_gnu {
+ } else if self.sess.target.linker_is_gnu || self.sess.target.is_like_wasm {
self.linker_arg("--no-gc-sections");
}
}
fn optimize(&mut self) {
- if !self.sess.target.linker_is_gnu {
+ if !self.sess.target.linker_is_gnu && !self.sess.target.is_like_wasm {
return;
}
fn control_flow_guard(&mut self) {}
fn debuginfo(&mut self, strip: Strip) {
+ // MacOS linker doesn't support stripping symbols directly anymore.
+ if self.sess.target.is_like_osx {
+ return;
+ }
+
match strip {
Strip::None => {}
Strip::Debuginfo => {
- // MacOS linker does not support longhand argument --strip-debug
- self.linker_arg("-S");
+ self.linker_arg("--strip-debug");
}
Strip::Symbols => {
- // MacOS linker does not support longhand argument --strip-all
- self.linker_arg("-s");
+ self.linker_arg("--strip-all");
}
}
}
self.linker_arg(&subsystem);
}
- fn finalize(&mut self) {
+ fn reset_per_library_state(&mut self) {
self.hint_dynamic(); // Reset to default before returning the composed command line.
}
}
}
- fn finalize(&mut self) {}
-
// MSVC doesn't need group indicators
fn group_start(&mut self) {}
fn group_end(&mut self) {}
// noop
}
- fn finalize(&mut self) {}
-
// Appears not necessary on Emscripten
fn group_start(&mut self) {}
fn group_end(&mut self) {}
fn subsystem(&mut self, _subsystem: &str) {}
- fn finalize(&mut self) {}
-
// Not needed for now with LLD
fn group_start(&mut self) {}
fn group_end(&mut self) {}
pub struct PtxLinker<'a> {
cmd: Command,
sess: &'a Session,
- info: &'a LinkerInfo,
}
impl<'a> Linker for PtxLinker<'a> {
self.cmd.arg("-o").arg(path);
}
- fn finalize(&mut self) {
- // Provide the linker with fallback to internal `target-cpu`.
- self.cmd.arg("--fallback-arch").arg(&self.info.target_cpu);
+ fn link_dylib(&mut self, _lib: Symbol, _verbatim: bool, _as_needed: bool) {
+ panic!("external dylibs not supported")
+ }
+
+ fn link_rust_dylib(&mut self, _lib: Symbol, _path: &Path) {
+ panic!("external dylibs not supported")
+ }
+
+ fn link_staticlib(&mut self, _lib: Symbol, _verbatim: bool) {
+ panic!("staticlibs not supported")
+ }
+
+ fn link_whole_staticlib(&mut self, _lib: Symbol, _verbatim: bool, _search_path: &[PathBuf]) {
+ panic!("staticlibs not supported")
+ }
+
+ fn framework_path(&mut self, _path: &Path) {
+ panic!("frameworks not supported")
+ }
+
+ fn link_framework(&mut self, _framework: Symbol, _as_needed: bool) {
+ panic!("frameworks not supported")
+ }
+
+ fn full_relro(&mut self) {}
+
+ fn partial_relro(&mut self) {}
+
+ fn no_relro(&mut self) {}
+
+ fn gc_sections(&mut self, _keep_metadata: bool) {}
+
+ fn no_gc_sections(&mut self) {}
+
+ fn pgo_gen(&mut self) {}
+
+ fn no_crt_objects(&mut self) {}
+
+ fn no_default_libraries(&mut self) {}
+
+ fn control_flow_guard(&mut self) {}
+
+ fn export_symbols(&mut self, _tmpdir: &Path, _crate_type: CrateType) {}
+
+ fn subsystem(&mut self, _subsystem: &str) {}
+
+ fn group_start(&mut self) {}
+
+ fn group_end(&mut self) {}
+
+ fn linker_plugin_lto(&mut self) {}
+}
+
+pub struct BpfLinker<'a> {
+ cmd: Command,
+ sess: &'a Session,
+ info: &'a LinkerInfo,
+}
+
+impl<'a> Linker for BpfLinker<'a> {
+ fn cmd(&mut self) -> &mut Command {
+ &mut self.cmd
+ }
+
+ fn set_output_kind(&mut self, _output_kind: LinkOutputKind, _out_filename: &Path) {}
+
+ fn link_rlib(&mut self, path: &Path) {
+ self.cmd.arg(path);
+ }
+
+ fn link_whole_rlib(&mut self, path: &Path) {
+ self.cmd.arg(path);
+ }
+
+ fn include_path(&mut self, path: &Path) {
+ self.cmd.arg("-L").arg(path);
+ }
+
+ fn debuginfo(&mut self, _strip: Strip) {
+ self.cmd.arg("--debug");
+ }
+
+ fn add_object(&mut self, path: &Path) {
+ self.cmd.arg(path);
+ }
+
+ fn optimize(&mut self) {
+ self.cmd.arg(match self.sess.opts.optimize {
+ OptLevel::No => "-O0",
+ OptLevel::Less => "-O1",
+ OptLevel::Default => "-O2",
+ OptLevel::Aggressive => "-O3",
+ OptLevel::Size => "-Os",
+ OptLevel::SizeMin => "-Oz",
+ });
+ }
+
+ fn output_filename(&mut self, path: &Path) {
+ self.cmd.arg("-o").arg(path);
}
fn link_dylib(&mut self, _lib: Symbol, _verbatim: bool, _as_needed: bool) {
fn control_flow_guard(&mut self) {}
- fn export_symbols(&mut self, _tmpdir: &Path, _crate_type: CrateType) {}
+ fn export_symbols(&mut self, tmpdir: &Path, crate_type: CrateType) {
+ let path = tmpdir.join("symbols");
+ let res: io::Result<()> = try {
+ let mut f = BufWriter::new(File::create(&path)?);
+ for sym in self.info.exports[&crate_type].iter() {
+ writeln!(f, "{}", sym)?;
+ }
+ };
+ if let Err(e) = res {
+ self.sess.fatal(&format!("failed to write symbols file: {}", e));
+ } else {
+ self.cmd.arg("--export-symbols").arg(&path);
+ }
+ }
fn subsystem(&mut self, _subsystem: &str) {}
use std::fs::File;
use std::path::Path;
+use object::{Object, ObjectSection};
use rustc_data_structures::memmap::Mmap;
use rustc_data_structures::owning_ref::OwningRef;
use rustc_data_structures::rustc_erase_owner;
let entry = entry_result
.map_err(|e| format!("failed to parse rlib '{}': {}", path.display(), e))?;
if entry.name() == METADATA_FILENAME.as_bytes() {
- return Ok(entry.data());
+ let data = entry
+ .data(data)
+ .map_err(|e| format!("failed to parse rlib '{}': {}", path.display(), e))?;
+ return search_for_metadata(path, data, ".rmeta");
}
}
}
fn get_dylib_metadata(&self, _target: &Target, path: &Path) -> Result<MetadataRef, String> {
- use object::{Object, ObjectSection};
-
- load_metadata_with(path, |data| {
- let file = object::File::parse(&data)
- .map_err(|e| format!("failed to parse dylib '{}': {}", path.display(), e))?;
- file.section_by_name(".rustc")
- .ok_or_else(|| format!("no .rustc section in '{}'", path.display()))?
- .data()
- .map_err(|e| {
- format!("failed to read .rustc section in '{}': {}", path.display(), e)
- })
- })
+ load_metadata_with(path, |data| search_for_metadata(path, data, ".rustc"))
}
}
+
+fn search_for_metadata<'a>(
+ path: &Path,
+ bytes: &'a [u8],
+ section: &str,
+) -> Result<&'a [u8], String> {
+ let file = match object::File::parse(bytes) {
+ Ok(f) => f,
+ // The parse above could fail for odd reasons like corruption, but for
+ // now we just interpret it as this target doesn't support metadata
+ // emission in object files so the entire byte slice itself is probably
+ // a metadata file. Ideally though if necessary we could at least check
+ // the prefix of bytes to see if it's an actual metadata object and if
+ // not forward the error along here.
+ Err(_) => return Ok(bytes),
+ };
+ file.section_by_name(section)
+ .ok_or_else(|| format!("no `{}` section in '{}'", section, path.display()))?
+ .data()
+ .map_err(|e| format!("failed to read {} section in '{}': {}", section, path.display(), e))
+}
pub is_like_osx: bool,
pub has_rpath: bool,
pub linker_is_gnu: bool,
- pub get_install_prefix_lib_path: &'a mut dyn FnMut() -> PathBuf,
}
pub fn get_rpath_flags(config: &mut RPathConfig<'_>) -> Vec<String> {
// Use relative paths to the libraries. Binaries can be moved
// as long as they maintain the relative relationship to the
// crates they depend on.
- let rel_rpaths = get_rpaths_relative_to_output(config, libs);
+ let rpaths = get_rpaths_relative_to_output(config, libs);
- // And a final backup rpath to the global library location.
- let fallback_rpaths = vec![get_install_prefix_rpath(config)];
-
- fn log_rpaths(desc: &str, rpaths: &[String]) {
- debug!("{} rpaths:", desc);
- for rpath in rpaths {
- debug!(" {}", *rpath);
- }
+ debug!("rpaths:");
+ for rpath in &rpaths {
+ debug!(" {}", rpath);
}
- log_rpaths("relative", &rel_rpaths);
- log_rpaths("fallback", &fallback_rpaths);
-
- let mut rpaths = rel_rpaths;
- rpaths.extend_from_slice(&fallback_rpaths);
-
// Remove duplicates
minimize_rpaths(&rpaths)
}
diff_paths(path, base)
}
-fn get_install_prefix_rpath(config: &mut RPathConfig<'_>) -> String {
- let path = (config.get_install_prefix_lib_path)();
- let path = env::current_dir().unwrap().join(&path);
- // FIXME (#9639): This needs to handle non-utf8 paths
- path.to_str().expect("non-utf8 component in rpath").to_owned()
-}
-
fn minimize_rpaths(rpaths: &[String]) -> Vec<String> {
let mut set = FxHashSet::default();
let mut minimized = Vec::new();
is_like_osx: true,
linker_is_gnu: false,
out_filename: PathBuf::from("bin/rustc"),
- get_install_prefix_lib_path: &mut || panic!(),
};
let res = get_rpath_relative_to_output(config, Path::new("lib/libstd.so"));
assert_eq!(res, "@loader_path/../lib");
let config = &mut RPathConfig {
used_crates: &[],
out_filename: PathBuf::from("bin/rustc"),
- get_install_prefix_lib_path: &mut || panic!(),
has_rpath: true,
is_like_osx: false,
linker_is_gnu: true,
pub fn provide_extern(providers: &mut Providers) {
providers.is_reachable_non_generic = is_reachable_non_generic_provider_extern;
providers.upstream_monomorphizations_for = upstream_monomorphizations_for_provider;
- providers.wasm_import_module_map = wasm_import_module_map;
}
fn symbol_export_level(tcx: TyCtxt<'_>, sym_def_id: DefId) -> SymbolExportLevel {
use rustc_session::config::{Passes, SwitchWithOptPath};
use rustc_session::Session;
use rustc_span::source_map::SourceMap;
-use rustc_span::symbol::{sym, Symbol};
+use rustc_span::symbol::sym;
use rustc_span::{BytePos, FileName, InnerSpan, Pos, Span};
use rustc_target::spec::{MergeFunctions, PanicStrategy, SanitizerSet};
let (coordinator_send, coordinator_receive) = channel();
let sess = tcx.sess;
- let crate_name = tcx.crate_name(LOCAL_CRATE);
let crate_attrs = tcx.hir().attrs(rustc_hir::CRATE_HIR_ID);
let no_builtins = tcx.sess.contains_name(crate_attrs, sym::no_builtins);
let is_compiler_builtins = tcx.sess.contains_name(crate_attrs, sym::compiler_builtins);
- let subsystem = tcx.sess.first_attr_value_str_by_name(crate_attrs, sym::windows_subsystem);
- let windows_subsystem = subsystem.map(|subsystem| {
- if subsystem != sym::windows && subsystem != sym::console {
- tcx.sess.fatal(&format!(
- "invalid windows subsystem `{}`, only \
- `windows` and `console` are allowed",
- subsystem
- ));
- }
- subsystem.to_string()
- });
let linker_info = LinkerInfo::new(tcx, target_cpu);
let crate_info = CrateInfo::new(tcx);
OngoingCodegen {
backend,
- crate_name,
metadata,
- windows_subsystem,
linker_info,
crate_info,
pub struct OngoingCodegen<B: ExtraBackendMethods> {
pub backend: B,
- pub crate_name: Symbol,
pub metadata: EncodedMetadata,
- pub windows_subsystem: Option<String>,
pub linker_info: LinkerInfo,
pub crate_info: CrateInfo,
pub coordinator_send: Sender<Box<dyn Any + Send>>,
(
CodegenResults {
- crate_name: self.crate_name,
metadata: self.metadata,
- windows_subsystem: self.windows_subsystem,
linker_info: self.linker_info,
crate_info: self.crate_info,
use rustc_session::cgu_reuse_tracker::CguReuse;
use rustc_session::config::{self, EntryFnType};
use rustc_session::Session;
+use rustc_span::symbol::sym;
use rustc_target::abi::{Align, LayoutOf, VariantIdx};
use std::ops::{Deref, DerefMut};
impl CrateInfo {
pub fn new(tcx: TyCtxt<'_>) -> CrateInfo {
+ let local_crate_name = tcx.crate_name(LOCAL_CRATE);
+ let crate_attrs = tcx.hir().attrs(rustc_hir::CRATE_HIR_ID);
+ let subsystem = tcx.sess.first_attr_value_str_by_name(crate_attrs, sym::windows_subsystem);
+ let windows_subsystem = subsystem.map(|subsystem| {
+ if subsystem != sym::windows && subsystem != sym::console {
+ tcx.sess.fatal(&format!(
+ "invalid windows subsystem `{}`, only \
+ `windows` and `console` are allowed",
+ subsystem
+ ));
+ }
+ subsystem.to_string()
+ });
+
let mut info = CrateInfo {
+ local_crate_name,
panic_runtime: None,
compiler_builtins: None,
profiler_runtime: None,
lang_item_to_crate: Default::default(),
missing_lang_items: Default::default(),
dependency_formats: tcx.dependency_formats(()),
+ windows_subsystem,
};
let lang_items = tcx.lang_items();
/// only whitespace or comments). According to LLVM Code Coverage Mapping documentation, "A count
/// for a gap area is only used as the line execution count if there are no other regions on a
/// line."
+#[derive(Debug)]
pub struct FunctionCoverage<'tcx> {
instance: Instance<'tcx>,
source_hash: u64,
expression_id, lhs, op, rhs, region
);
let expression_index = self.expression_index(u32::from(expression_id));
+ debug_assert!(
+ expression_index.as_usize() < self.expressions.len(),
+ "expression_index {} is out of range for expressions.len() = {}
+ for {:?}",
+ expression_index.as_usize(),
+ self.expressions.len(),
+ self,
+ );
if let Some(previous_expression) = self.expressions[expression_index].replace(Expression {
lhs,
op,
use rustc_data_structures::fx::FxHashSet;
use rustc_hir as hir;
use rustc_hir::def_id::DefId;
-use rustc_middle::ty::{self, subst::SubstsRef, Ty, TyCtxt};
+use rustc_middle::ty::{self, subst::SubstsRef, AdtDef, Ty, TyCtxt};
+use rustc_target::abi::{TagEncoding, Variants};
use std::fmt::Write;
ty::Float(float_ty) => output.push_str(float_ty.name_str()),
ty::Foreign(def_id) => push_item_name(tcx, def_id, qualified, output),
ty::Adt(def, substs) => {
- push_item_name(tcx, def.did, qualified, output);
- push_type_params(tcx, substs, output, visited);
+ if def.is_enum() && cpp_like_names {
+ msvc_enum_fallback(tcx, t, def, substs, output, visited);
+ } else {
+ push_item_name(tcx, def.did, qualified, output);
+ push_type_params(tcx, substs, output, visited);
+ }
}
ty::Tuple(component_types) => {
if cpp_like_names {
}
}
+ /// MSVC names enums differently than other platforms so that the debugging visualization
+ // format (natvis) is able to understand enums and render the active variant correctly in the
+ // debugger. For more information, look in `src/etc/natvis/intrinsic.natvis` and
+ // `EnumMemberDescriptionFactor::create_member_descriptions`.
+ fn msvc_enum_fallback(
+ tcx: TyCtxt<'tcx>,
+ ty: Ty<'tcx>,
+ def: &AdtDef,
+ substs: SubstsRef<'tcx>,
+ output: &mut String,
+ visited: &mut FxHashSet<Ty<'tcx>>,
+ ) {
+ let layout = tcx.layout_of(tcx.param_env(def.did).and(ty)).expect("layout error");
+
+ if let Variants::Multiple {
+ tag_encoding: TagEncoding::Niche { dataful_variant, .. },
+ tag,
+ variants,
+ ..
+ } = &layout.variants
+ {
+ let dataful_variant_layout = &variants[*dataful_variant];
+
+ // calculate the range of values for the dataful variant
+ let dataful_discriminant_range =
+ &dataful_variant_layout.largest_niche.as_ref().unwrap().scalar.valid_range;
+
+ let min = dataful_discriminant_range.start();
+ let min = tag.value.size(&tcx).truncate(*min);
+
+ let max = dataful_discriminant_range.end();
+ let max = tag.value.size(&tcx).truncate(*max);
+
+ output.push_str("enum$<");
+ push_item_name(tcx, def.did, true, output);
+ push_type_params(tcx, substs, output, visited);
+
+ let dataful_variant_name = def.variants[*dataful_variant].ident.as_str();
+
+ output.push_str(&format!(", {}, {}, {}>", min, max, dataful_variant_name));
+ } else {
+ output.push_str("enum$<");
+ push_item_name(tcx, def.did, true, output);
+ push_type_params(tcx, substs, output, visited);
+ output.push('>');
+ }
+ }
+
fn push_item_name(tcx: TyCtxt<'tcx>, def_id: DefId, qualified: bool, output: &mut String) {
if qualified {
output.push_str(&tcx.crate_name(def_id.krate).as_str());
ty::Dynamic(..) => {
// load size/align from vtable
let vtable = info.unwrap();
- (meth::SIZE.get_usize(bx, vtable), meth::ALIGN.get_usize(bx, vtable))
+ (
+ meth::VirtualIndex::from_index(ty::COMMON_VTABLE_ENTRIES_SIZE)
+ .get_usize(bx, vtable),
+ meth::VirtualIndex::from_index(ty::COMMON_VTABLE_ENTRIES_ALIGN)
+ .get_usize(bx, vtable),
+ )
}
ty::Slice(_) | ty::Str => {
let unit = layout.field(bx, 0);
#![doc(html_root_url = "https://doc.rust-lang.org/nightly/nightly-rustc/")]
-#![feature(assert_matches)]
#![feature(bool_to_option)]
#![feature(box_patterns)]
-#![feature(drain_filter)]
#![feature(try_blocks)]
#![feature(in_band_lifetimes)]
#![feature(nll)]
#![feature(associated_type_bounds)]
-#![feature(iter_zip)]
#![recursion_limit = "256"]
-#![feature(box_syntax)]
//! This crate contains codegen code that is used by all codegen backends (LLVM and others).
//! The backend-agnostic functions of this crate use functions defined in various traits that
pub name: Option<Symbol>,
pub cfg: Option<ast::MetaItem>,
pub verbatim: Option<bool>,
+ pub dll_imports: Vec<cstore::DllImport>,
}
impl From<&cstore::NativeLib> for NativeLib {
fn from(lib: &cstore::NativeLib) -> Self {
- NativeLib { kind: lib.kind, name: lib.name, cfg: lib.cfg.clone(), verbatim: lib.verbatim }
+ NativeLib {
+ kind: lib.kind,
+ name: lib.name,
+ cfg: lib.cfg.clone(),
+ verbatim: lib.verbatim,
+ dll_imports: lib.dll_imports.clone(),
+ }
}
}
/// and the corresponding properties without referencing information outside of a `CrateInfo`.
#[derive(Debug, Encodable, Decodable)]
pub struct CrateInfo {
+ pub local_crate_name: Symbol,
pub panic_runtime: Option<CrateNum>,
pub compiler_builtins: Option<CrateNum>,
pub profiler_runtime: Option<CrateNum>,
pub lang_item_to_crate: FxHashMap<LangItem, CrateNum>,
pub missing_lang_items: FxHashMap<CrateNum, Vec<LangItem>>,
pub dependency_formats: Lrc<Dependencies>,
+ pub windows_subsystem: Option<String>,
}
#[derive(Encodable, Decodable)]
pub struct CodegenResults {
- pub crate_name: Symbol,
pub modules: Vec<CompiledModule>,
pub allocator_module: Option<CompiledModule>,
pub metadata_module: Option<CompiledModule>,
pub metadata: rustc_middle::middle::cstore::EncodedMetadata,
- pub windows_subsystem: Option<String>,
pub linker_info: back::linker::LinkerInfo,
pub crate_info: CrateInfo,
}
use crate::traits::*;
-use rustc_middle::ty::{self, Instance, Ty};
+use rustc_middle::ty::{self, Instance, Ty, VtblEntry, COMMON_VTABLE_ENTRIES};
use rustc_target::abi::call::FnAbi;
#[derive(Copy, Clone, Debug)]
pub struct VirtualIndex(u64);
-pub const DESTRUCTOR: VirtualIndex = VirtualIndex(0);
-pub const SIZE: VirtualIndex = VirtualIndex(1);
-pub const ALIGN: VirtualIndex = VirtualIndex(2);
-
impl<'a, 'tcx> VirtualIndex {
pub fn from_index(index: usize) -> Self {
- VirtualIndex(index as u64 + 3)
+ VirtualIndex(index as u64)
}
pub fn get_fn<Bx: BuilderMethods<'a, 'tcx>>(
// Not in the cache; build it.
let nullptr = cx.const_null(cx.type_i8p_ext(cx.data_layout().instruction_address_space));
- let methods_root;
- let methods = if let Some(trait_ref) = trait_ref {
- methods_root = tcx.vtable_methods(trait_ref.with_self_ty(tcx, ty));
- methods_root.iter()
+ let vtable_entries = if let Some(trait_ref) = trait_ref {
+ tcx.vtable_entries(trait_ref.with_self_ty(tcx, ty))
} else {
- (&[]).iter()
+ COMMON_VTABLE_ENTRIES
};
- let methods = methods.cloned().map(|opt_mth| {
- opt_mth.map_or(nullptr, |(def_id, substs)| {
- cx.get_fn_addr(
+ let layout = cx.layout_of(ty);
+ // /////////////////////////////////////////////////////////////////////////////////////////////
+ // If you touch this code, be sure to also make the corresponding changes to
+ // `get_vtable` in `rust_mir/interpret/traits.rs`.
+ // /////////////////////////////////////////////////////////////////////////////////////////////
+ let components: Vec<_> = vtable_entries
+ .iter()
+ .map(|entry| match entry {
+ VtblEntry::MetadataDropInPlace => {
+ cx.get_fn_addr(Instance::resolve_drop_in_place(cx.tcx(), ty))
+ }
+ VtblEntry::MetadataSize => cx.const_usize(layout.size.bytes()),
+ VtblEntry::MetadataAlign => cx.const_usize(layout.align.abi.bytes()),
+ VtblEntry::Vacant => nullptr,
+ VtblEntry::Method(def_id, substs) => cx.get_fn_addr(
ty::Instance::resolve_for_vtable(
cx.tcx(),
ty::ParamEnv::reveal_all(),
- def_id,
+ *def_id,
substs,
)
.unwrap()
.polymorphize(cx.tcx()),
- )
+ ),
})
- });
-
- let layout = cx.layout_of(ty);
- // /////////////////////////////////////////////////////////////////////////////////////////////
- // If you touch this code, be sure to also make the corresponding changes to
- // `get_vtable` in `rust_mir/interpret/traits.rs`.
- // /////////////////////////////////////////////////////////////////////////////////////////////
- let components: Vec<_> = [
- cx.get_fn_addr(Instance::resolve_drop_in_place(cx.tcx(), ty)),
- cx.const_usize(layout.size.bytes()),
- cx.const_usize(layout.align.abi.bytes()),
- ]
- .iter()
- .cloned()
- .chain(methods)
- .collect();
+ .collect();
let vtable_const = cx.const_struct(&components, false);
let align = cx.data_layout().pointer_align.abi;
use rustc_index::bit_set::BitSet;
use rustc_index::vec::{Idx, IndexVec};
use rustc_middle::mir::traversal;
-use rustc_middle::mir::visit::{
- MutatingUseContext, NonMutatingUseContext, NonUseContext, PlaceContext, Visitor,
-};
+use rustc_middle::mir::visit::{MutatingUseContext, NonMutatingUseContext, PlaceContext, Visitor};
use rustc_middle::mir::{self, Location, TerminatorKind};
-use rustc_middle::ty;
use rustc_middle::ty::layout::HasTyCtxt;
use rustc_target::abi::LayoutOf;
let mir = fx.mir;
let mut analyzer = LocalAnalyzer::new(fx);
- analyzer.visit_body(&mir);
+ // If there exists a local definition that dominates all uses of that local,
+ // the definition should be visited first. Traverse blocks in preorder which
+ // is a topological sort of dominance partial order.
+ for (bb, data) in traversal::preorder(&mir) {
+ analyzer.visit_basic_block_data(bb, data);
+ }
for (local, decl) in mir.local_decls.iter_enumerated() {
let ty = fx.monomorphize(decl.ty);
if let mir::ProjectionElem::Deref = elem {
// Deref projections typically only read the pointer.
- // (the exception being `VarDebugInfo` contexts, handled below)
base_context = PlaceContext::NonMutatingUse(NonMutatingUseContext::Copy);
-
- // Indirect debuginfo requires going through memory, that only
- // the debugger accesses, following our emitted DWARF pointer ops.
- //
- // FIXME(eddyb) Investigate the possibility of relaxing this, but
- // note that `llvm.dbg.declare` *must* be used for indirect places,
- // even if we start using `llvm.dbg.value` for all other cases,
- // as we don't necessarily know when the value changes, but only
- // where it lives in memory.
- //
- // It's possible `llvm.dbg.declare` could support starting from
- // a pointer that doesn't point to an `alloca`, but this would
- // only be useful if we know the pointer being `Deref`'d comes
- // from an immutable place, and if `llvm.dbg.declare` calls
- // must be at the very start of the function, then only function
- // arguments could contain such pointers.
- if context == PlaceContext::NonUse(NonUseContext::VarDebugInfo) {
- // We use `NonUseContext::VarDebugInfo` for the base,
- // which might not force the base local to memory,
- // so we have to do it manually.
- self.visit_local(&place_ref.local, context, location);
- }
- }
-
- // `NonUseContext::VarDebugInfo` needs to flow all the
- // way down to the base local (see `visit_local`).
- if context == PlaceContext::NonUse(NonUseContext::VarDebugInfo) {
- base_context = context;
}
self.process_place(&place_base, base_context, location);
);
}
} else {
- // FIXME this is super_place code, is repeated here to avoid cloning place or changing
- // visit_place API
- let mut context = context;
-
- if !place_ref.projection.is_empty() {
- context = if context.is_mutating_use() {
- PlaceContext::MutatingUse(MutatingUseContext::Projection)
- } else {
- PlaceContext::NonMutatingUse(NonMutatingUseContext::Projection)
- };
- }
-
self.visit_local(&place_ref.local, context, location);
- self.visit_projection(*place_ref, context, location);
}
}
}
self.visit_rvalue(rvalue, location);
}
- fn visit_terminator(&mut self, terminator: &mir::Terminator<'tcx>, location: Location) {
- let check = match terminator.kind {
- mir::TerminatorKind::Call { func: mir::Operand::Constant(ref c), ref args, .. } => {
- match *c.ty().kind() {
- ty::FnDef(did, _) => Some((did, args)),
- _ => None,
- }
- }
- _ => None,
- };
- if let Some((def_id, args)) = check {
- if Some(def_id) == self.fx.cx.tcx().lang_items().box_free_fn() {
- // box_free(x) shares with `drop x` the property that it
- // is not guaranteed to be statically dominated by the
- // definition of x, so x must always be in an alloca.
- if let mir::Operand::Move(ref place) = args[0] {
- self.visit_place(
- place,
- PlaceContext::MutatingUse(MutatingUseContext::Drop),
- location,
- );
- }
- }
- }
-
- self.super_terminator(terminator, location);
- }
-
fn visit_place(&mut self, place: &mir::Place<'tcx>, context: PlaceContext, location: Location) {
debug!("visit_place(place={:?}, context={:?})", place, context);
self.process_place(&place.as_ref(), context, location);
let fn_abi = FnAbi::of_instance(&bx, virtual_drop, &[]);
let vtable = args[1];
args = &args[..1];
- (meth::DESTRUCTOR.get_fn(&mut bx, vtable, &fn_abi), fn_abi)
+ (
+ meth::VirtualIndex::from_index(ty::COMMON_VTABLE_ENTRIES_DROPINPLACE)
+ .get_fn(&mut bx, vtable, &fn_abi),
+ fn_abi,
+ )
}
_ => (bx.get_fn_addr(drop_fn), FnAbi::of_instance(&bx, drop_fn, &[])),
};
];
const WASM_ALLOWED_FEATURES: &[(&str, Option<Symbol>)] = &[
- ("simd128", Some(sym::wasm_target_feature)),
+ ("simd128", None),
("atomics", Some(sym::wasm_target_feature)),
("nontrapping-fptoint", Some(sym::wasm_target_feature)),
];
+const BPF_ALLOWED_FEATURES: &[(&str, Option<Symbol>)] = &[("alu32", Some(sym::bpf_target_feature))];
+
/// When rustdoc is running, provide a list of all known features so that all their respective
/// primitives may be documented.
///
.chain(MIPS_ALLOWED_FEATURES.iter())
.chain(RISCV_ALLOWED_FEATURES.iter())
.chain(WASM_ALLOWED_FEATURES.iter())
+ .chain(BPF_ALLOWED_FEATURES.iter())
.cloned()
}
"powerpc" | "powerpc64" => POWERPC_ALLOWED_FEATURES,
"riscv32" | "riscv64" => RISCV_ALLOWED_FEATURES,
"wasm32" | "wasm64" => WASM_ALLOWED_FEATURES,
+ "bpf" => BPF_ALLOWED_FEATURES,
_ => &[],
}
}
None
}
- fn metadata_loader(&self) -> Box<MetadataLoaderDyn>;
- fn provide(&self, _providers: &mut Providers);
- fn provide_extern(&self, _providers: &mut Providers);
+ /// The metadata loader used to load rlib and dylib metadata.
+ ///
+ /// Alternative codegen backends may want to use different rlib or dylib formats than the
+ /// default native static archives and dynamic libraries.
+ fn metadata_loader(&self) -> Box<MetadataLoaderDyn> {
+ Box::new(crate::back::metadata::DefaultMetadataLoader)
+ }
+
+ fn provide(&self, _providers: &mut Providers) {}
+ fn provide_extern(&self, _providers: &mut Providers) {}
fn codegen_crate<'tcx>(
&self,
tcx: TyCtxt<'tcx>,
version = "0.11"
[target.'cfg(windows)'.dependencies]
-winapi = { version = "0.3", features = ["fileapi", "psapi"] }
+winapi = { version = "0.3", features = ["fileapi", "psapi", "winerror"] }
[target.'cfg(not(target_arch = "wasm32"))'.dependencies]
memmap2 = "0.2.1"
+++ /dev/null
-//! This module provides a way to deal with self-referential data.
-//!
-//! The main idea is to allocate such data in a generator frame and then
-//! give access to it by executing user-provided closures inside that generator.
-//! The module provides a safe abstraction for the latter task.
-//!
-//! The interface consists of two exported macros meant to be used together:
-//! * `declare_box_region_type` wraps a generator inside a struct with `access`
-//! method which accepts closures.
-//! * `box_region_allow_access` is a helper which should be called inside
-//! a generator to actually execute those closures.
-
-use std::marker::PhantomData;
-use std::ops::{Generator, GeneratorState};
-use std::pin::Pin;
-
-#[derive(Copy, Clone)]
-pub struct AccessAction(*mut dyn FnMut());
-
-impl AccessAction {
- pub fn get(self) -> *mut dyn FnMut() {
- self.0
- }
-}
-
-#[derive(Copy, Clone)]
-pub enum Action {
- Initial,
- Access(AccessAction),
- Complete,
-}
-
-pub struct PinnedGenerator<I, A, R> {
- generator: Pin<Box<dyn Generator<Action, Yield = YieldType<I, A>, Return = R>>>,
-}
-
-impl<I, A, R> PinnedGenerator<I, A, R> {
- pub fn new<T: Generator<Action, Yield = YieldType<I, A>, Return = R> + 'static>(
- generator: T,
- ) -> (I, Self) {
- let mut result = PinnedGenerator { generator: Box::pin(generator) };
-
- // Run it to the first yield to set it up
- let init = match Pin::new(&mut result.generator).resume(Action::Initial) {
- GeneratorState::Yielded(YieldType::Initial(y)) => y,
- _ => panic!(),
- };
-
- (init, result)
- }
-
- pub unsafe fn access(&mut self, closure: *mut dyn FnMut()) {
- // Call the generator, which in turn will call the closure
- if let GeneratorState::Complete(_) =
- Pin::new(&mut self.generator).resume(Action::Access(AccessAction(closure)))
- {
- panic!()
- }
- }
-
- pub fn complete(&mut self) -> R {
- // Tell the generator we want it to complete, consuming it and yielding a result
- let result = Pin::new(&mut self.generator).resume(Action::Complete);
- if let GeneratorState::Complete(r) = result { r } else { panic!() }
- }
-}
-
-#[derive(PartialEq)]
-pub struct Marker<T>(PhantomData<T>);
-
-impl<T> Marker<T> {
- pub unsafe fn new() -> Self {
- Marker(PhantomData)
- }
-}
-
-pub enum YieldType<I, A> {
- Initial(I),
- Accessor(Marker<A>),
-}
-
-#[macro_export]
-#[allow_internal_unstable(fn_traits)]
-macro_rules! declare_box_region_type {
- (impl $v:vis
- $name: ident,
- $yield_type:ty,
- for($($lifetimes:tt)*),
- ($($args:ty),*) -> ($reti:ty, $retc:ty)
- ) => {
- $v struct $name($crate::box_region::PinnedGenerator<
- $reti,
- for<$($lifetimes)*> fn(($($args,)*)),
- $retc
- >);
-
- impl $name {
- fn new<T: ::std::ops::Generator<$crate::box_region::Action, Yield = $yield_type, Return = $retc> + 'static>(
- generator: T
- ) -> ($reti, Self) {
- let (initial, pinned) = $crate::box_region::PinnedGenerator::new(generator);
- (initial, $name(pinned))
- }
-
- $v fn access<F: for<$($lifetimes)*> FnOnce($($args,)*) -> R, R>(&mut self, f: F) -> R {
- // Turn the FnOnce closure into *mut dyn FnMut()
- // so we can pass it in to the generator
- let mut r = None;
- let mut f = Some(f);
- let mut_f: &mut dyn for<$($lifetimes)*> FnMut(($($args,)*)) =
- &mut |args| {
- let f = f.take().unwrap();
- r = Some(FnOnce::call_once(f, args));
- };
- let mut_f = mut_f as *mut dyn for<$($lifetimes)*> FnMut(($($args,)*));
-
- // Get the generator to call our closure
- unsafe {
- self.0.access(::std::mem::transmute(mut_f));
- }
-
- // Unwrap the result
- r.unwrap()
- }
-
- $v fn complete(mut self) -> $retc {
- self.0.complete()
- }
-
- fn initial_yield(value: $reti) -> $yield_type {
- $crate::box_region::YieldType::Initial(value)
- }
- }
- };
-
- ($v:vis $name: ident, for($($lifetimes:tt)*), ($($args:ty),*) -> ($reti:ty, $retc:ty)) => {
- declare_box_region_type!(
- impl $v $name,
- $crate::box_region::YieldType<$reti, for<$($lifetimes)*> fn(($($args,)*))>,
- for($($lifetimes)*),
- ($($args),*) -> ($reti, $retc)
- );
- };
-}
-
-#[macro_export]
-#[allow_internal_unstable(fn_traits)]
-macro_rules! box_region_allow_access {
- (for($($lifetimes:tt)*), ($($args:ty),*), ($($exprs:expr),*), $action:ident) => {
- loop {
- match $action {
- $crate::box_region::Action::Access(accessor) => {
- let accessor: &mut dyn for<$($lifetimes)*> FnMut($($args),*) = unsafe {
- ::std::mem::transmute(accessor.get())
- };
- (*accessor)(($($exprs),*));
- unsafe {
- let marker = $crate::box_region::Marker::<
- for<$($lifetimes)*> fn(($($args,)*))
- >::new();
- $action = yield $crate::box_region::YieldType::Accessor(marker);
- };
- }
- $crate::box_region::Action::Complete => break,
- $crate::box_region::Action::Initial => panic!("unexpected box_region action: Initial"),
- }
- }
- }
-}
Ok(Lock { _file: file })
}
}
+
+ pub fn error_unsupported(err: &io::Error) -> bool {
+ matches!(err.raw_os_error(), Some(libc::ENOTSUP) | Some(libc::ENOSYS))
+ }
}
// Note that we don't need a Drop impl to execute `flock(fd, LOCK_UN)`. Lock acquired by
Ok(Lock { file })
}
}
+
+ pub fn error_unsupported(err: &io::Error) -> bool {
+ matches!(err.raw_os_error(), Some(libc::ENOTSUP) | Some(libc::ENOSYS))
+ }
}
impl Drop for Lock {
use std::mem;
use std::os::windows::prelude::*;
+ use winapi::shared::winerror::ERROR_INVALID_FUNCTION;
use winapi::um::minwinbase::{OVERLAPPED, LOCKFILE_FAIL_IMMEDIATELY, LOCKFILE_EXCLUSIVE_LOCK};
use winapi::um::fileapi::LockFileEx;
use winapi::um::winnt::{FILE_SHARE_DELETE, FILE_SHARE_READ, FILE_SHARE_WRITE};
Ok(Lock { _file: file })
}
}
+
+ pub fn error_unsupported(err: &io::Error) -> bool {
+ err.raw_os_error() == Some(ERROR_INVALID_FUNCTION as i32)
+ }
}
// Note that we don't need a Drop impl on the Windows: The file is unlocked
#![feature(array_windows)]
#![feature(control_flow_enum)]
#![feature(in_band_lifetimes)]
-#![feature(unboxed_closures)]
-#![feature(generator_trait)]
-#![feature(fn_traits)]
#![feature(min_specialization)]
#![feature(auto_traits)]
#![feature(nll)]
#![feature(allow_internal_unstable)]
#![feature(hash_raw_entry)]
-#![feature(stmt_expr_attributes)]
#![feature(core_intrinsics)]
#![feature(test)]
#![feature(associated_type_bounds)]
pub mod base_n;
pub mod binary_search_util;
-pub mod box_region;
pub mod captures;
pub mod flock;
pub mod functor;
pub mod tiny_list;
pub mod transitive_relation;
pub mod vec_linked_list;
+pub mod vec_map;
pub mod work_queue;
pub use atomic_ref::AtomicRef;
pub mod frozen;
return Ok(());
}
- match self.active_cache.entry(cache_key.clone()) {
+ match self.active_cache.entry(cache_key) {
Entry::Occupied(o) => {
let node = &mut self.nodes[*o.get()];
if let Some(parent_index) = parent {
&& self
.error_cache
.get(&obligation_tree_id)
- .map(|errors| errors.contains(&cache_key))
- .unwrap_or(false);
+ .map_or(false, |errors| errors.contains(v.key()));
if already_failed {
Err(())
Some(rpos) => {
// Cycle detected.
processor.process_backedge(
- stack[rpos..].iter().map(GetObligation(&self.nodes)),
+ stack[rpos..].iter().map(|&i| &self.nodes[i].obligation),
PhantomData,
);
}
});
}
}
-
-// I need a Clone closure.
-#[derive(Clone)]
-struct GetObligation<'a, O>(&'a [Node<O>]);
-
-impl<'a, 'b, O> FnOnce<(&'b usize,)> for GetObligation<'a, O> {
- type Output = &'a O;
- extern "rust-call" fn call_once(self, args: (&'b usize,)) -> &'a O {
- &self.0[*args.0].obligation
- }
-}
-
-impl<'a, 'b, O> FnMut<(&'b usize,)> for GetObligation<'a, O> {
- extern "rust-call" fn call_mut(&mut self, args: (&'b usize,)) -> &'a O {
- &self.0[*args.0].obligation
- }
-}
entries.sort_unstable_by(|&(ref sk1, _), &(ref sk2, _)| sk1.cmp(sk2));
entries.hash_stable(hcx, hasher);
}
-
-/// A vector container that makes sure that its items are hashed in a stable
-/// order.
-#[derive(Debug)]
-pub struct StableVec<T>(Vec<T>);
-
-impl<T> StableVec<T> {
- pub fn new(v: Vec<T>) -> Self {
- StableVec(v)
- }
-}
-
-impl<T> ::std::ops::Deref for StableVec<T> {
- type Target = Vec<T>;
-
- fn deref(&self) -> &Vec<T> {
- &self.0
- }
-}
-
-impl<T, HCX> HashStable<HCX> for StableVec<T>
-where
- T: HashStable<HCX> + ToStableHashKey<HCX>,
-{
- fn hash_stable(&self, hcx: &mut HCX, hasher: &mut StableHasher) {
- let StableVec(ref v) = *self;
-
- let mut sorted: Vec<_> = v.iter().map(|x| x.to_stable_hash_key(hcx)).collect();
- sorted.sort_unstable();
- sorted.hash_stable(hcx, hasher);
- }
-}
use std::ops::Add;
use std::panic::{resume_unwind, catch_unwind, AssertUnwindSafe};
- /// This is a single threaded variant of AtomicCell provided by crossbeam.
- /// Unlike `Atomic` this is intended for all `Copy` types,
- /// but it lacks the explicit ordering arguments.
- #[derive(Debug)]
- pub struct AtomicCell<T: Copy>(Cell<T>);
-
- impl<T: Copy> AtomicCell<T> {
- #[inline]
- pub fn new(v: T) -> Self {
- AtomicCell(Cell::new(v))
- }
-
- #[inline]
- pub fn get_mut(&mut self) -> &mut T {
- self.0.get_mut()
- }
- }
-
- impl<T: Copy> AtomicCell<T> {
- #[inline]
- pub fn into_inner(self) -> T {
- self.0.into_inner()
- }
-
- #[inline]
- pub fn load(&self) -> T {
- self.0.get()
- }
-
- #[inline]
- pub fn store(&self, val: T) {
- self.0.set(val)
- }
-
- #[inline]
- pub fn swap(&self, val: T) -> T {
- self.0.replace(val)
- }
- }
-
/// This is a single threaded variant of `AtomicU64`, `AtomicUsize`, etc.
- /// It differs from `AtomicCell` in that it has explicit ordering arguments
- /// and is only intended for use with the native atomic types.
+ /// It has explicit ordering arguments and is only intended for use with
+ /// the native atomic types.
/// You should use this type through the `AtomicU64`, `AtomicUsize`, etc, type aliases
/// as it's not intended to be used separately.
#[derive(Debug)]
(oper_a(), oper_b())
}
- pub struct SerialScope;
-
- impl SerialScope {
- pub fn spawn<F>(&self, f: F)
- where F: FnOnce(&SerialScope)
- {
- f(self)
- }
- }
-
- pub fn scope<F, R>(f: F) -> R
- where F: FnOnce(&SerialScope) -> R
- {
- f(&SerialScope)
- }
-
#[macro_export]
macro_rules! parallel {
($($blocks:tt),*) => {
pub use std::sync::atomic::{AtomicBool, AtomicUsize, AtomicU32, AtomicU64};
- pub use crossbeam_utils::atomic::AtomicCell;
-
pub use std::sync::Arc as Lrc;
pub use std::sync::Weak as Weak;
unsafe impl<T> Pointer for Box<T> {
const BITS: usize = std::mem::align_of::<T>().trailing_zeros() as usize;
+ #[inline]
fn into_usize(self) -> usize {
Box::into_raw(self) as usize
}
+ #[inline]
unsafe fn from_usize(ptr: usize) -> Self {
Box::from_raw(ptr as *mut T)
}
unsafe impl<T> Pointer for Rc<T> {
const BITS: usize = std::mem::align_of::<T>().trailing_zeros() as usize;
+ #[inline]
fn into_usize(self) -> usize {
Rc::into_raw(self) as usize
}
+ #[inline]
unsafe fn from_usize(ptr: usize) -> Self {
Rc::from_raw(ptr as *const T)
}
unsafe impl<T> Pointer for Arc<T> {
const BITS: usize = std::mem::align_of::<T>().trailing_zeros() as usize;
+ #[inline]
fn into_usize(self) -> usize {
Arc::into_raw(self) as usize
}
+ #[inline]
unsafe fn from_usize(ptr: usize) -> Self {
Arc::from_raw(ptr as *const T)
}
unsafe impl<'a, T: 'a> Pointer for &'a T {
const BITS: usize = std::mem::align_of::<T>().trailing_zeros() as usize;
+ #[inline]
fn into_usize(self) -> usize {
self as *const T as usize
}
+ #[inline]
unsafe fn from_usize(ptr: usize) -> Self {
&*(ptr as *const T)
}
unsafe impl<'a, T: 'a> Pointer for &'a mut T {
const BITS: usize = std::mem::align_of::<T>().trailing_zeros() as usize;
+ #[inline]
fn into_usize(self) -> usize {
self as *mut T as usize
}
+ #[inline]
unsafe fn from_usize(ptr: usize) -> Self {
&mut *(ptr as *mut T)
}
--- /dev/null
+use std::borrow::Borrow;
+use std::iter::FromIterator;
+use std::slice::{Iter, IterMut};
+use std::vec::IntoIter;
+
+use crate::stable_hasher::{HashStable, StableHasher};
+
+/// A map type implemented as a vector of pairs `K` (key) and `V` (value).
+/// It currently provides a subset of all the map operations, the rest could be added as needed.
+#[derive(Clone, Encodable, Decodable, Debug)]
+pub struct VecMap<K, V>(Vec<(K, V)>);
+
+impl<K, V> VecMap<K, V>
+where
+ K: PartialEq,
+{
+ pub fn new() -> Self {
+ VecMap(Default::default())
+ }
+
+ /// Sets the value of the entry, and returns the entry's old value.
+ pub fn insert(&mut self, k: K, v: V) -> Option<V> {
+ if let Some(elem) = self.0.iter_mut().find(|(key, _)| *key == k) {
+ Some(std::mem::replace(&mut elem.1, v))
+ } else {
+ self.0.push((k, v));
+ None
+ }
+ }
+
+ /// Gets a reference to the value in the entry.
+ pub fn get<Q: ?Sized>(&self, k: &Q) -> Option<&V>
+ where
+ K: Borrow<Q>,
+ Q: Eq,
+ {
+ self.0.iter().find(|(key, _)| k == key.borrow()).map(|elem| &elem.1)
+ }
+
+ /// Returns the value corresponding to the supplied predicate filter.
+ ///
+ /// The supplied predicate will be applied to each (key, value) pair and it will return a
+ /// reference to the values where the predicate returns `true`.
+ pub fn get_by(&self, mut predicate: impl FnMut(&(K, V)) -> bool) -> Option<&V> {
+ self.0.iter().find(|kv| predicate(kv)).map(|elem| &elem.1)
+ }
+
+ /// Returns `true` if the map contains a value for the specified key.
+ ///
+ /// The key may be any borrowed form of the map's key type,
+ /// [`Eq`] on the borrowed form *must* match those for
+ /// the key type.
+ pub fn contains_key<Q: ?Sized>(&self, k: &Q) -> bool
+ where
+ K: Borrow<Q>,
+ Q: Eq,
+ {
+ self.get(k).is_some()
+ }
+
+ /// Returns `true` if the map contains no elements.
+ pub fn is_empty(&self) -> bool {
+ self.0.is_empty()
+ }
+
+ pub fn iter(&self) -> Iter<'_, (K, V)> {
+ self.into_iter()
+ }
+
+ pub fn iter_mut(&mut self) -> IterMut<'_, (K, V)> {
+ self.into_iter()
+ }
+}
+
+impl<K, V> Default for VecMap<K, V> {
+ #[inline]
+ fn default() -> Self {
+ Self(Default::default())
+ }
+}
+
+impl<K, V> From<Vec<(K, V)>> for VecMap<K, V> {
+ fn from(vec: Vec<(K, V)>) -> Self {
+ Self(vec)
+ }
+}
+
+impl<K, V> Into<Vec<(K, V)>> for VecMap<K, V> {
+ fn into(self) -> Vec<(K, V)> {
+ self.0
+ }
+}
+
+impl<K, V> FromIterator<(K, V)> for VecMap<K, V> {
+ fn from_iter<I: IntoIterator<Item = (K, V)>>(iter: I) -> Self {
+ Self(iter.into_iter().collect())
+ }
+}
+
+impl<'a, K, V> IntoIterator for &'a VecMap<K, V> {
+ type Item = &'a (K, V);
+ type IntoIter = Iter<'a, (K, V)>;
+
+ #[inline]
+ fn into_iter(self) -> Self::IntoIter {
+ self.0.iter()
+ }
+}
+
+impl<'a, K, V> IntoIterator for &'a mut VecMap<K, V> {
+ type Item = &'a mut (K, V);
+ type IntoIter = IterMut<'a, (K, V)>;
+
+ #[inline]
+ fn into_iter(self) -> Self::IntoIter {
+ self.0.iter_mut()
+ }
+}
+
+impl<K, V> IntoIterator for VecMap<K, V> {
+ type Item = (K, V);
+ type IntoIter = IntoIter<(K, V)>;
+
+ #[inline]
+ fn into_iter(self) -> Self::IntoIter {
+ self.0.into_iter()
+ }
+}
+
+impl<K, V> Extend<(K, V)> for VecMap<K, V> {
+ fn extend<I: IntoIterator<Item = (K, V)>>(&mut self, iter: I) {
+ self.0.extend(iter);
+ }
+
+ fn extend_one(&mut self, item: (K, V)) {
+ self.0.extend_one(item);
+ }
+
+ fn extend_reserve(&mut self, additional: usize) {
+ self.0.extend_reserve(additional);
+ }
+}
+
+impl<K, V, CTX> HashStable<CTX> for VecMap<K, V>
+where
+ K: HashStable<CTX> + Eq,
+ V: HashStable<CTX>,
+{
+ fn hash_stable(&self, hcx: &mut CTX, hasher: &mut StableHasher) {
+ self.0.hash_stable(hcx, hasher)
+ }
+}
+
+#[cfg(test)]
+mod tests;
--- /dev/null
+use super::*;
+
+impl<K, V> VecMap<K, V> {
+ fn into_vec(self) -> Vec<(K, V)> {
+ self.0.into()
+ }
+}
+
+#[test]
+fn test_from_iterator() {
+ assert_eq!(
+ std::iter::empty().collect::<VecMap<i32, bool>>().into_vec(),
+ Vec::<(i32, bool)>::new()
+ );
+ assert_eq!(std::iter::once((42, true)).collect::<VecMap<_, _>>().into_vec(), vec![(42, true)]);
+ assert_eq!(
+ vec![(1, true), (2, false)].into_iter().collect::<VecMap<_, _>>().into_vec(),
+ vec![(1, true), (2, false)]
+ );
+}
+
+#[test]
+fn test_into_iterator_owned() {
+ assert_eq!(VecMap::new().into_iter().collect::<Vec<(i32, bool)>>(), Vec::<(i32, bool)>::new());
+ assert_eq!(VecMap::from(vec![(1, true)]).into_iter().collect::<Vec<_>>(), vec![(1, true)]);
+ assert_eq!(
+ VecMap::from(vec![(1, true), (2, false)]).into_iter().collect::<Vec<_>>(),
+ vec![(1, true), (2, false)]
+ );
+}
+
+#[test]
+fn test_insert() {
+ let mut v = VecMap::new();
+ assert_eq!(v.insert(1, true), None);
+ assert_eq!(v.insert(2, false), None);
+ assert_eq!(v.clone().into_vec(), vec![(1, true), (2, false)]);
+ assert_eq!(v.insert(1, false), Some(true));
+ assert_eq!(v.into_vec(), vec![(1, false), (2, false)]);
+}
+
+#[test]
+fn test_get() {
+ let v = vec![(1, true), (2, false)].into_iter().collect::<VecMap<_, _>>();
+ assert_eq!(v.get(&1), Some(&true));
+ assert_eq!(v.get(&2), Some(&false));
+ assert_eq!(v.get(&3), None);
+}
use rustc_errors::registry::{InvalidErrorCode, Registry};
use rustc_errors::{ErrorReported, PResult};
use rustc_feature::find_gated_cfg;
-use rustc_interface::util::{self, collect_crate_types, get_builtin_codegen_backend};
+use rustc_interface::util::{self, collect_crate_types, get_codegen_backend};
use rustc_interface::{interface, Queries};
use rustc_lint::LintStore;
use rustc_metadata::locator;
}
}
-// Whether to stop or continue compilation.
+/// Whether to stop or continue compilation.
#[derive(Copy, Clone, Debug, Eq, PartialEq)]
pub enum Compilation {
Stop,
println!("commit-date: {}", unw(util::commit_date_str()));
println!("host: {}", config::host_triple());
println!("release: {}", unw(util::release_str()));
- if cfg!(feature = "llvm") {
- get_builtin_codegen_backend(&None, "llvm")().print_version();
- }
+
+ let debug_flags = matches.opt_strs("Z");
+ let backend_name = debug_flags.iter().find_map(|x| {
+ if x.starts_with("codegen-backend=") {
+ Some(&x["codegen-backends=".len()..])
+ } else {
+ None
+ }
+ });
+ get_codegen_backend(&None, backend_name).print_version();
}
}
}
// Don't handle -W help here, because we might first load plugins.
- let r = matches.opt_strs("Z");
- if r.iter().any(|x| *x == "help") {
+ let debug_flags = matches.opt_strs("Z");
+ if debug_flags.iter().any(|x| *x == "help") {
describe_debug_flags();
return None;
}
}
if cg_flags.iter().any(|x| *x == "passes=list") {
- if cfg!(feature = "llvm") {
- get_builtin_codegen_backend(&None, "llvm")().print_passes();
- }
+ let backend_name = debug_flags.iter().find_map(|x| {
+ if x.starts_with("codegen-backend=") {
+ Some(&x["codegen-backends=".len()..])
+ } else {
+ None
+ }
+ });
+ get_codegen_backend(&None, backend_name).print_passes();
return None;
}
E0309: include_str!("./error_codes/E0309.md"),
E0310: include_str!("./error_codes/E0310.md"),
E0312: include_str!("./error_codes/E0312.md"),
+E0316: include_str!("./error_codes/E0316.md"),
E0317: include_str!("./error_codes/E0317.md"),
E0321: include_str!("./error_codes/E0321.md"),
E0322: include_str!("./error_codes/E0322.md"),
E0311, // thing may not live long enough
E0313, // lifetime of borrowed pointer outlives lifetime of captured
// variable
- E0314, // closure outlives stack frame
- E0315, // cannot invoke closure outside of its lifetime
- E0316, // nested quantification of lifetimes
+// E0314, // closure outlives stack frame
+// E0315, // cannot invoke closure outside of its lifetime
// E0319, // trait impls for defaulted traits allowed just for structs/enums
E0320, // recursive overflow during dropck
// E0372, // coherence not object safe
// E0470, removed
// E0471, // constant evaluation error (in pattern)
E0472, // llvm_asm! is unsupported on this target
- E0473, // dereference of reference outside its lifetime
- E0474, // captured variable `..` does not outlive the enclosing closure
- E0475, // index of slice outside its lifetime
+// E0473, // dereference of reference outside its lifetime
+// E0474, // captured variable `..` does not outlive the enclosing closure
+// E0475, // index of slice outside its lifetime
E0476, // lifetime of the source pointer does not outlive lifetime bound...
- E0479, // the type `..` (provided as the value of a type parameter) is...
- E0480, // lifetime of method receiver does not outlive the method call
- E0481, // lifetime of function argument does not outlive the function call
+// E0479, // the type `..` (provided as the value of a type parameter) is...
+// E0480, // lifetime of method receiver does not outlive the method call
+// E0481, // lifetime of function argument does not outlive the function call
E0482, // lifetime of return value does not outlive the function call
- E0483, // lifetime of operand does not outlive the operation
- E0484, // reference is not valid at the time of borrow
- E0485, // automatically reference is not valid at the time of borrow
- E0486, // type of expression contains references that are not valid during..
- E0487, // unsafe use of destructor: destructor might be called while...
- E0488, // lifetime of variable does not enclose its declaration
- E0489, // type/lifetime parameter not in scope here
+// E0483, // lifetime of operand does not outlive the operation
+// E0484, // reference is not valid at the time of borrow
+// E0485, // automatically reference is not valid at the time of borrow
+// E0486, // type of expression contains references that are not valid during..
+// E0487, // unsafe use of destructor: destructor might be called while...
+// E0488, // lifetime of variable does not enclose its declaration
+// E0489, // type/lifetime parameter not in scope here
E0490, // a value of type `..` is borrowed for too long
E0498, // malformed plugin attribute
E0514, // metadata version mismatch
--- /dev/null
+A `where` clause contains a nested quantification over lifetimes.
+
+Erroneous code example:
+
+```compile_fail,E0316
+trait Tr<'a, 'b> {}
+
+fn foo<T>(t: T)
+where
+ for<'a> &'a T: for<'b> Tr<'a, 'b>, // error: nested quantification
+{
+}
+```
+
+Rust syntax allows lifetime quantifications in two places within
+`where` clauses: Quantifying over the trait bound only (as in
+`Ty: for<'l> Trait<'l>`) and quantifying over the whole clause
+(as in `for<'l> &'l Ty: Trait<'l>`). Using both in the same clause
+leads to a nested lifetime quantification, which is not supported.
+
+The following example compiles, because the clause with the nested
+quantification has been rewritten to use only one `for<>`:
+
+```
+trait Tr<'a, 'b> {}
+
+fn foo<T>(t: T)
+where
+ for<'a, 'b> &'a T: Tr<'a, 'b>, // ok
+{
+}
+```
The problem here is that if the given type or one of its fields implements the
`Drop` trait, this `Drop` implementation cannot be called within a const
context since it may run arbitrary, non-const-checked code. To prevent this
-issue, ensure all values with custom a custom `Drop` implementation escape the
+issue, ensure all values with a custom `Drop` implementation escape the
initializer.
```
Add `'static` requirement to fix them:
-```compile_fail,E0759
+```
# use std::fmt::Debug;
-fn foo(x: &i32) -> impl Debug + 'static { // ok!
+fn foo(x: &'static i32) -> impl Debug + 'static { // ok!
x
}
-fn bar(x: &i32) -> Box<dyn Debug + 'static> { // ok!
+fn bar(x: &'static i32) -> Box<dyn Debug + 'static> { // ok!
Box::new(x)
}
```
$(
$enc.emit_struct_field(
stringify!($name),
- idx,
+ idx == 0,
|enc| $name.encode(enc),
)?;
idx += 1;
// Special-case encoder to skip tool_metadata if not set
impl<E: Encoder> Encodable<E> for Diagnostic {
fn encode(&self, s: &mut E) -> Result<(), E::Error> {
- s.emit_struct("diagnostic", 7, |s| {
+ s.emit_struct(false, |s| {
let mut idx = 0;
idx = encode_fields!(
self.inner.borrow_mut().bug(msg)
}
+ #[inline]
pub fn err_count(&self) -> usize {
self.inner.borrow().err_count()
}
}
}
+ #[inline]
fn err_count(&self) -> usize {
self.err_count + self.stashed_diagnostics.len()
}
self.resolver.check_unused_macros();
}
- /// Resolves a path mentioned inside Rust code.
+ /// Resolves a `path` mentioned inside Rust code, returning an absolute path.
///
- /// This unifies the logic used for resolving `include_X!`, and `#[doc(include)]` file paths.
+ /// This unifies the logic used for resolving `include_X!`.
///
- /// Returns an absolute path to the file that `path` refers to.
+ /// FIXME: move this to `rustc_builtin_macros` and make it private.
pub fn resolve_path(
&self,
path: impl Into<PathBuf>,
) -> P<ast::Expr> {
self.expr(
span,
- ast::ExprKind::Struct(P(ast::StructExpr { path, fields, rest: ast::StructRest::None })),
+ ast::ExprKind::Struct(P(ast::StructExpr {
+ qself: None,
+ path,
+ fields,
+ rest: ast::StructRest::None,
+ })),
)
}
pub fn expr_struct_ident(
path: ast::Path,
subpats: Vec<P<ast::Pat>>,
) -> P<ast::Pat> {
- self.pat(span, PatKind::TupleStruct(path, subpats))
+ self.pat(span, PatKind::TupleStruct(None, path, subpats))
}
pub fn pat_struct(
&self,
path: ast::Path,
field_pats: Vec<ast::PatField>,
) -> P<ast::Pat> {
- self.pat(span, PatKind::Struct(path, field_pats, false))
+ self.pat(span, PatKind::Struct(None, path, field_pats, false))
}
pub fn pat_tuple(&self, span: Span, pats: Vec<P<ast::Pat>>) -> P<ast::Pat> {
self.pat(span, PatKind::Tuple(pats))
use rustc_ast::token;
use rustc_ast::tokenstream::TokenStream;
use rustc_ast::visit::{self, AssocCtxt, Visitor};
-use rustc_ast::{AstLike, AttrItem, Block, Inline, ItemKind, LitKind, MacArgs};
+use rustc_ast::{AstLike, Block, Inline, ItemKind, MacArgs};
use rustc_ast::{MacCallStmt, MacStmtStyle, MetaItemKind, ModKind, NestedMetaItem};
use rustc_ast::{NodeId, PatKind, Path, StmtKind, Unsafe};
use rustc_ast_pretty::pprust;
-use rustc_attr::{self as attr, is_builtin_attr};
+use rustc_attr::is_builtin_attr;
use rustc_data_structures::map_in_place::MapInPlace;
use rustc_data_structures::stack::ensure_sufficient_stack;
use rustc_data_structures::sync::Lrc;
use rustc_session::lint::BuiltinLintDiagnostics;
use rustc_session::parse::{feature_err, ParseSess};
use rustc_session::Limit;
-use rustc_span::symbol::{sym, Ident, Symbol};
-use rustc_span::{ExpnId, FileName, Span, DUMMY_SP};
+use rustc_span::symbol::{sym, Ident};
+use rustc_span::{ExpnId, FileName, Span};
use smallvec::{smallvec, SmallVec};
-use std::io::ErrorKind;
use std::ops::DerefMut;
use std::path::PathBuf;
use std::rc::Rc;
-use std::{iter, mem, slice};
+use std::{iter, mem};
macro_rules! ast_fragments {
(
noop_flat_map_generic_param(param, self)
}
- fn visit_attribute(&mut self, at: &mut ast::Attribute) {
- // turn `#[doc(include="filename")]` attributes into `#[doc(include(file="filename",
- // contents="file contents")]` attributes
- if !self.cx.sess.check_name(at, sym::doc) {
- return noop_visit_attribute(at, self);
- }
-
- if let Some(list) = at.meta_item_list() {
- if !list.iter().any(|it| it.has_name(sym::include)) {
- return noop_visit_attribute(at, self);
- }
-
- let mut items = vec![];
-
- for mut it in list {
- if !it.has_name(sym::include) {
- items.push({
- noop_visit_meta_list_item(&mut it, self);
- it
- });
- continue;
- }
-
- if let Some(file) = it.value_str() {
- let err_count = self.cx.sess.parse_sess.span_diagnostic.err_count();
- self.check_attributes(slice::from_ref(at));
- if self.cx.sess.parse_sess.span_diagnostic.err_count() > err_count {
- // avoid loading the file if they haven't enabled the feature
- return noop_visit_attribute(at, self);
- }
-
- let filename = match self.cx.resolve_path(&*file.as_str(), it.span()) {
- Ok(filename) => filename,
- Err(mut err) => {
- err.emit();
- continue;
- }
- };
-
- match self.cx.source_map().load_file(&filename) {
- Ok(source_file) => {
- let src = source_file
- .src
- .as_ref()
- .expect("freshly loaded file should have a source");
- let src_interned = Symbol::intern(src.as_str());
-
- let include_info = vec![
- ast::NestedMetaItem::MetaItem(attr::mk_name_value_item_str(
- Ident::with_dummy_span(sym::file),
- file,
- DUMMY_SP,
- )),
- ast::NestedMetaItem::MetaItem(attr::mk_name_value_item_str(
- Ident::with_dummy_span(sym::contents),
- src_interned,
- DUMMY_SP,
- )),
- ];
-
- let include_ident = Ident::with_dummy_span(sym::include);
- let item = attr::mk_list_item(include_ident, include_info);
- items.push(ast::NestedMetaItem::MetaItem(item));
- }
- Err(e) => {
- let lit_span = it.name_value_literal_span().unwrap();
-
- if e.kind() == ErrorKind::InvalidData {
- self.cx
- .struct_span_err(
- lit_span,
- &format!("{} wasn't a utf-8 file", filename.display()),
- )
- .span_label(lit_span, "contains invalid utf-8")
- .emit();
- } else {
- let mut err = self.cx.struct_span_err(
- lit_span,
- &format!("couldn't read {}: {}", filename.display(), e),
- );
- err.span_label(lit_span, "couldn't read file");
-
- err.emit();
- }
- }
- }
- } else {
- let mut err = self
- .cx
- .struct_span_err(it.span(), "expected path to external documentation");
-
- // Check if the user erroneously used `doc(include(...))` syntax.
- let literal = it.meta_item_list().and_then(|list| {
- if list.len() == 1 {
- list[0].literal().map(|literal| &literal.kind)
- } else {
- None
- }
- });
-
- let (path, applicability) = match &literal {
- Some(LitKind::Str(path, ..)) => {
- (path.to_string(), Applicability::MachineApplicable)
- }
- _ => (String::from("<path>"), Applicability::HasPlaceholders),
- };
-
- err.span_suggestion(
- it.span(),
- "provide a file path with `=`",
- format!("include = \"{}\"", path),
- applicability,
- );
-
- err.emit();
- }
- }
-
- let meta = attr::mk_list_item(Ident::with_dummy_span(sym::doc), items);
- *at = ast::Attribute {
- kind: ast::AttrKind::Normal(
- AttrItem { path: meta.path, args: meta.kind.mac_args(meta.span), tokens: None },
- None,
- ),
- span: at.span,
- id: at.id,
- style: at.style,
- };
- } else {
- noop_visit_attribute(at, self)
- }
- }
-
fn visit_id(&mut self, id: &mut ast::NodeId) {
if self.monotonic {
debug_assert_eq!(*id, ast::DUMMY_NODE_ID);
-#![feature(bool_to_option)]
#![feature(crate_visibility_modifier)]
#![feature(decl_macro)]
#![feature(destructuring_assignment)]
+#![feature(format_args_capture)]
#![feature(iter_zip)]
#![feature(proc_macro_diagnostic)]
#![feature(proc_macro_internals)]
use rustc_data_structures::fx::FxHashMap;
use rustc_data_structures::sync::Lrc;
+use rustc_span::symbol::Ident;
use std::borrow::Cow;
use std::collections::hash_map::Entry::{Occupied, Vacant};
use std::mem;
/// Use the given sequence of token trees (`ms`) as a matcher. Match the token
/// stream from the given `parser` against it and return the match.
-pub(super) fn parse_tt(parser: &mut Cow<'_, Parser<'_>>, ms: &[TokenTree]) -> NamedParseResult {
+pub(super) fn parse_tt(
+ parser: &mut Cow<'_, Parser<'_>>,
+ ms: &[TokenTree],
+ macro_name: Ident,
+) -> NamedParseResult {
// A queue of possible matcher positions. We initialize it with the matcher position in which
// the "dot" is before the first token of the first token tree in `ms`. `inner_parse_loop` then
// processes all of these possible matcher positions and produces possible next positions into
return Error(
parser.token.span,
format!(
- "local ambiguity: multiple parsing options: {}",
+ "local ambiguity when calling macro `{macro_name}`: multiple parsing options: {}",
match next_items.len() {
0 => format!("built-in NTs {}.", nts),
1 => format!("built-in NTs {} or 1 other option.", nts),
// are not recorded. On the first `Success(..)`ful matcher, the spans are merged.
let mut gated_spans_snapshot = mem::take(&mut *sess.gated_spans.spans.borrow_mut());
- match parse_tt(&mut Cow::Borrowed(&parser), lhs_tt) {
+ match parse_tt(&mut Cow::Borrowed(&parser), lhs_tt, name) {
Success(named_matches) => {
// The matcher was `Success(..)`ful.
// Merge the gated spans from parsing the matcher with the pre-existing ones.
_ => continue,
};
if let Success(_) =
- parse_tt(&mut Cow::Borrowed(&parser_from_cx(sess, arg.clone())), lhs_tt)
+ parse_tt(&mut Cow::Borrowed(&parser_from_cx(sess, arg.clone())), lhs_tt, name)
{
if comma_span.is_dummy() {
err.note("you might be missing a comma");
];
let parser = Parser::new(&sess.parse_sess, body, true, rustc_parse::MACRO_ARGUMENTS);
- let argument_map = match parse_tt(&mut Cow::Borrowed(&parser), &argument_gram) {
+ let argument_map = match parse_tt(&mut Cow::Borrowed(&parser), &argument_gram, def.ident) {
Success(m) => m,
Failure(token, msg) => {
let s = parse_failure_msg(&token);
&sess.parse_sess,
def.id,
features,
+ edition,
)
.pop()
.unwrap();
&sess.parse_sess,
def.id,
features,
+ edition,
)
.pop()
.unwrap();
use rustc_session::parse::ParseSess;
use rustc_span::symbol::{kw, Ident};
-use rustc_span::Span;
+use rustc_span::edition::Edition;
+use rustc_span::{Span, SyntaxContext};
use rustc_data_structures::sync::Lrc;
/// - `sess`: the parsing session. Any errors will be emitted to this session.
/// - `node_id`: the NodeId of the macro we are parsing.
/// - `features`: language features so we can do feature gating.
+/// - `edition`: the edition of the crate defining the macro
///
/// # Returns
///
sess: &ParseSess,
node_id: NodeId,
features: &Features,
+ edition: Edition,
) -> Vec<TokenTree> {
// Will contain the final collection of `self::TokenTree`
let mut result = Vec::new();
while let Some(tree) = trees.next() {
// Given the parsed tree, if there is a metavar and we are expecting matchers, actually
// parse out the matcher (i.e., in `$id:ident` this would parse the `:` and `ident`).
- let tree = parse_tree(tree, &mut trees, expect_matchers, sess, node_id, features);
+ let tree = parse_tree(tree, &mut trees, expect_matchers, sess, node_id, features, edition);
match tree {
TokenTree::MetaVar(start_sp, ident) if expect_matchers => {
let span = match trees.next() {
let kind =
token::NonterminalKind::from_symbol(frag.name, || {
- span.edition()
+ // FIXME(#85708) - once we properly decode a foreign
+ // crate's `SyntaxContext::root`, then we can replace
+ // this with just `span.edition()`. A
+ // `SyntaxContext::root()` from the current crate will
+ // have the edition of the current crate, and a
+ // `SyntaxxContext::root()` from a foreign crate will
+ // have the edition of that crate (which we manually
+ // retrieve via the `edition` parameter).
+ if span.ctxt() == SyntaxContext::root() {
+ edition
+ } else {
+ span.edition()
+ }
})
.unwrap_or_else(
|| {
/// - `expect_matchers`: same as for `parse` (see above).
/// - `sess`: the parsing session. Any errors will be emitted to this session.
/// - `features`: language features so we can do feature gating.
+/// - `edition` - the edition of the crate defining the macro
fn parse_tree(
tree: tokenstream::TokenTree,
outer_trees: &mut impl Iterator<Item = tokenstream::TokenTree>,
sess: &ParseSess,
node_id: NodeId,
features: &Features,
+ edition: Edition,
) -> TokenTree {
// Depending on what `tree` is, we could be parsing different parts of a macro
match tree {
sess.span_diagnostic.span_err(span.entire(), &msg);
}
// Parse the contents of the sequence itself
- let sequence = parse(tts, expect_matchers, sess, node_id, features);
+ let sequence = parse(tts, expect_matchers, sess, node_id, features, edition);
// Get the Kleene operator and optional separator
let (separator, kleene) =
parse_sep_and_kleene_op(&mut trees, span.entire(), sess);
span,
Lrc::new(Delimited {
delim,
- tts: parse(tts, expect_matchers, sess, node_id, features),
+ tts: parse(tts, expect_matchers, sess, node_id, features, edition),
}),
),
}
"impl z { fn a (self: Foo, &myarg: i32) {} }",
];
- for &src in &srcs {
+ for src in srcs {
let spans = get_spans_of_pat_idents(src);
let (lo, hi) = (spans[0].lo(), spans[0].hi());
assert!(
(accepted, extended_key_value_attributes, "1.54.0", Some(78835), None),
/// Allows unsizing coercions in `const fn`.
(accepted, const_fn_unsize, "1.54.0", Some(64992), None),
+ /// Allows `impl Trait` with multiple unrelated lifetimes.
+ (accepted, member_constraints, "1.54.0", Some(61997), None),
// -------------------------------------------------------------------------
// feature-group-end: accepted features
(active, f16c_target_feature, "1.36.0", Some(44839), None),
(active, riscv_target_feature, "1.45.0", Some(44839), None),
(active, ermsb_target_feature, "1.49.0", Some(44839), None),
+ (active, bpf_target_feature, "1.54.0", Some(44839), None),
// -------------------------------------------------------------------------
// feature-group-end: actual feature gates (target features)
/// Allows `#[doc(masked)]`.
(active, doc_masked, "1.21.0", Some(44027), None),
- /// Allows `#[doc(include = "some-file")]`.
- (active, external_doc, "1.22.0", Some(44732), None),
-
/// Allows using `crate` as visibility modifier, synonymous with `pub(crate)`.
(active, crate_visibility_modifier, "1.23.0", Some(53120), None),
/// Allows explicit discriminants on non-unit enum variants.
(active, arbitrary_enum_discriminant, "1.37.0", Some(60553), None),
- /// Allows `impl Trait` with multiple unrelated lifetimes.
- (active, member_constraints, "1.37.0", Some(61997), None),
-
/// Allows `async || body` closures.
(active, async_closure, "1.37.0", Some(62290), None),
/// Allows unnamed fields of struct and union type
(active, unnamed_fields, "1.53.0", Some(49804), None),
+ /// Allows qualified paths in struct expressions, struct patterns and tuple struct patterns.
+ (active, more_qualified_paths, "1.54.0", Some(80080), None),
+
// -------------------------------------------------------------------------
// feature-group-end: actual feature gates
// -------------------------------------------------------------------------
rustc_attr!(TEST, rustc_evaluate_where_clauses, AssumedUsed, template!(Word)),
rustc_attr!(TEST, rustc_if_this_changed, AssumedUsed, template!(Word, List: "DepNode")),
rustc_attr!(TEST, rustc_then_this_would_need, AssumedUsed, template!(List: "DepNode")),
- rustc_attr!(
- TEST, rustc_dirty, AssumedUsed,
- template!(List: r#"cfg = "...", /*opt*/ label = "...", /*opt*/ except = "...""#),
- ),
rustc_attr!(
TEST, rustc_clean, AssumedUsed,
template!(List: r#"cfg = "...", /*opt*/ label = "...", /*opt*/ except = "...""#),
(removed, const_fn, "1.54.0", Some(57563), None,
Some("split into finer-grained feature gates")),
+ /// Allows `#[doc(include = "some-file")]`.
+ (removed, external_doc, "1.54.0", Some(44732), None,
+ Some("use #[doc = include_str!(\"filename\")] instead, which handles macro invocations")),
+
// -------------------------------------------------------------------------
// feature-group-end: removed features
// -------------------------------------------------------------------------
.iter_enumerated()
.map(move |(index, key)| (index, key, &self.def_path_hashes[index]))
}
-
- pub fn all_def_path_hashes_and_def_ids(
- &self,
- krate: CrateNum,
- ) -> impl Iterator<Item = (DefPathHash, DefId)> + '_ {
- self.def_path_hashes
- .iter_enumerated()
- .map(move |(index, hash)| (*hash, DefId { krate, index }))
- }
}
/// The definition table containing node definitions.
self.table.index_to_key.len()
}
+ #[inline]
pub fn def_key(&self, id: LocalDefId) -> DefKey {
self.table.def_key(id.local_def_index)
}
pub fn iter_local_def_id(&self) -> impl Iterator<Item = LocalDefId> + '_ {
self.def_id_to_hir_id.iter_enumerated().map(|(k, _)| k)
}
+
+ #[inline(always)]
+ pub fn local_def_path_hash_to_def_id(&self, hash: DefPathHash) -> Option<LocalDefId> {
+ self.table
+ .def_path_hash_to_index
+ .get(&hash)
+ .map(|&local_def_index| LocalDefId { local_def_index })
+ }
}
#[derive(Copy, Clone, PartialEq, Debug)]
// ignore-tidy-filelength
use crate::def::{CtorKind, DefKind, Res};
use crate::def_id::DefId;
-crate use crate::hir_id::HirId;
+crate use crate::hir_id::{HirId, ItemLocalId};
use crate::{itemlikevisit, LangItem};
use rustc_ast::util::parser::ExprPrecedence;
pub use rustc_ast::{BorrowKind, ImplPolarity, IsAuto};
pub use rustc_ast::{CaptureBy, Movability, Mutability};
use rustc_ast::{InlineAsmOptions, InlineAsmTemplatePiece};
+use rustc_data_structures::fx::FxHashMap;
use rustc_data_structures::sync::{par_for_each_in, Send, Sync};
use rustc_macros::HashStable_Generic;
use rustc_span::source_map::Spanned;
/// they are declared in the static array generated by proc_macro_harness.
pub proc_macros: Vec<HirId>,
- pub trait_map: BTreeMap<HirId, Vec<TraitCandidate>>,
+ /// Map indicating what traits are in scope for places where this
+ /// is relevant; generated by resolve.
+ pub trait_map: FxHashMap<LocalDefId, FxHashMap<ItemLocalId, Box<[TraitCandidate]>>>,
/// Collected attributes from HIR nodes.
pub attrs: BTreeMap<HirId, &'hir [Attribute]>,
}
impl FnRetTy<'_> {
+ #[inline]
pub fn span(&self) -> Span {
match *self {
Self::DefaultReturn(span) => span,
//! [rustc dev guide]: https://rustc-dev-guide.rust-lang.org/hir.html
#![feature(crate_visibility_modifier)]
-#![feature(const_panic)]
#![cfg_attr(bootstrap, feature(extended_key_value_attributes))]
#![feature(in_band_lifetimes)]
#![feature(once_cell)]
+#![feature(min_specialization)]
#![recursion_limit = "256"]
#[macro_use]
TraitItem, TraitItemId, Ty, VisibilityKind,
};
use crate::hir_id::{HirId, ItemLocalId};
-use rustc_span::def_id::{DefPathHash, LocalDefId};
+use rustc_span::def_id::DefPathHash;
/// Requirements for a `StableHashingContext` to be used in this crate.
/// This is a hack to allow using the `HashStable_Generic` derive macro
fn hash_hir_ty(&mut self, _: &Ty<'_>, hasher: &mut StableHasher);
fn hash_hir_visibility_kind(&mut self, _: &VisibilityKind<'_>, hasher: &mut StableHasher);
fn hash_hir_item_like<F: FnOnce(&mut Self)>(&mut self, f: F);
- fn local_def_path_hash(&self, def_id: LocalDefId) -> DefPathHash;
}
impl<HirCtx: crate::HashStableContext> ToStableHashKey<HirCtx> for HirId {
#[inline]
fn to_stable_hash_key(&self, hcx: &HirCtx) -> (DefPathHash, ItemLocalId) {
- let def_path_hash = hcx.local_def_path_hash(self.owner);
+ let def_path_hash = self.owner.to_stable_hash_key(hcx);
(def_path_hash, self.local_id)
}
}
#[inline]
fn to_stable_hash_key(&self, hcx: &HirCtx) -> DefPathHash {
- hcx.local_def_path_hash(self.def_id)
+ self.def_id.to_stable_hash_key(hcx)
}
}
#[inline]
fn to_stable_hash_key(&self, hcx: &HirCtx) -> DefPathHash {
- hcx.local_def_path_hash(self.def_id)
+ self.def_id.to_stable_hash_key(hcx)
}
}
#[inline]
fn to_stable_hash_key(&self, hcx: &HirCtx) -> DefPathHash {
- hcx.local_def_path_hash(self.def_id)
+ self.def_id.to_stable_hash_key(hcx)
}
}
#[inline]
fn to_stable_hash_key(&self, hcx: &HirCtx) -> DefPathHash {
- hcx.local_def_path_hash(self.def_id)
+ self.def_id.to_stable_hash_key(hcx)
}
}
rustc_span = { path = "../rustc_span" }
rustc_fs_util = { path = "../rustc_fs_util" }
rustc_session = { path = "../rustc_session" }
+rustc_errors = { path = "../rustc_errors" }
-//! Debugging code to test fingerprints computed for query results.
-//! For each node marked with `#[rustc_clean]` or `#[rustc_dirty]`,
-//! we will compare the fingerprint from the current and from the previous
+//! Debugging code to test fingerprints computed for query results. For each node marked with
+//! `#[rustc_clean]` we will compare the fingerprint from the current and from the previous
//! compilation session as appropriate:
//!
//! - `#[rustc_clean(cfg="rev2", except="typeck")]` if we are
use std::vec::Vec;
const EXCEPT: Symbol = sym::except;
-const LABEL: Symbol = sym::label;
const CFG: Symbol = sym::cfg;
// Base and Extra labels to build up the labels
/// For generic cases like inline-assembly, modules, etc.
const LABELS_HIR_ONLY: &[&[&str]] = &[BASE_HIR];
+/// Impl `DepNode`s.
+const LABELS_TRAIT: &[&[&str]] = &[
+ BASE_HIR,
+ &[label_strs::associated_item_def_ids, label_strs::predicates_of, label_strs::generics_of],
+];
+
/// Impl `DepNode`s.
const LABELS_IMPL: &[&[&str]] = &[BASE_HIR, BASE_IMPL];
dirty: Labels,
}
-impl Assertion {
- fn from_clean_labels(labels: Labels) -> Assertion {
- Assertion { clean: labels, dirty: Labels::default() }
- }
-
- fn from_dirty_labels(labels: Labels) -> Assertion {
- Assertion { clean: Labels::default(), dirty: labels }
- }
-}
-
pub fn check_dirty_clean_annotations(tcx: TyCtxt<'_>) {
if !tcx.sess.opts.debugging_opts.query_dep_graph {
return;
}
- // can't add `#[rustc_dirty]` etc without opting in to this feature
+ // can't add `#[rustc_clean]` etc without opting in to this feature
if !tcx.features().rustc_attrs {
return;
}
let mut dirty_clean_visitor = DirtyCleanVisitor { tcx, checked_attrs: Default::default() };
krate.visit_all_item_likes(&mut dirty_clean_visitor);
- let mut all_attrs = FindAllAttrs {
- tcx,
- attr_names: &[sym::rustc_dirty, sym::rustc_clean],
- found_attrs: vec![],
- };
+ let mut all_attrs = FindAllAttrs { tcx, found_attrs: vec![] };
intravisit::walk_crate(&mut all_attrs, krate);
// Note that we cannot use the existing "unused attribute"-infrastructure
impl DirtyCleanVisitor<'tcx> {
/// Possibly "deserialize" the attribute into a clean/dirty assertion
fn assertion_maybe(&mut self, item_id: LocalDefId, attr: &Attribute) -> Option<Assertion> {
- let is_clean = if self.tcx.sess.check_name(attr, sym::rustc_dirty) {
- false
- } else if self.tcx.sess.check_name(attr, sym::rustc_clean) {
- true
- } else {
+ if !self.tcx.sess.check_name(attr, sym::rustc_clean) {
// skip: not rustc_clean/dirty
return None;
- };
+ }
if !check_config(self.tcx, attr) {
// skip: not the correct `cfg=`
return None;
}
- let assertion = if let Some(labels) = self.labels(attr) {
- if is_clean {
- Assertion::from_clean_labels(labels)
- } else {
- Assertion::from_dirty_labels(labels)
- }
- } else {
- self.assertion_auto(item_id, attr, is_clean)
- };
+ let assertion = self.assertion_auto(item_id, attr);
Some(assertion)
}
/// Gets the "auto" assertion on pre-validated attr, along with the `except` labels.
- fn assertion_auto(
- &mut self,
- item_id: LocalDefId,
- attr: &Attribute,
- is_clean: bool,
- ) -> Assertion {
+ fn assertion_auto(&mut self, item_id: LocalDefId, attr: &Attribute) -> Assertion {
let (name, mut auto) = self.auto_labels(item_id, attr);
let except = self.except(attr);
for e in except.iter() {
self.tcx.sess.span_fatal(attr.span, &msg);
}
}
- if is_clean {
- Assertion { clean: auto, dirty: except }
- } else {
- Assertion { clean: except, dirty: auto }
- }
- }
-
- fn labels(&self, attr: &Attribute) -> Option<Labels> {
- for item in attr.meta_item_list().unwrap_or_else(Vec::new) {
- if item.has_name(LABEL) {
- let value = expect_associated_value(self.tcx, &item);
- return Some(self.resolve_labels(&item, value));
- }
- }
- None
+ Assertion { clean: auto, dirty: except }
}
/// `except=` attribute value
HirItem::Union(..) => ("ItemUnion", LABELS_ADT),
// Represents a Trait Declaration
- // FIXME(michaelwoerister): trait declaration is buggy because sometimes some of
- // the depnodes don't exist (because they legitimately didn't need to be
- // calculated)
- //
- // michaelwoerister and vitiral came up with a possible solution,
- // to just do this before every query
- // ```
- // ::rustc_middle::ty::query::plumbing::force_from_dep_node(tcx, dep_node)
- // ```
- //
- // However, this did not seem to work effectively and more bugs were hit.
- // Nebie @vitiral gave up :)
- //
- //HirItem::Trait(..) => ("ItemTrait", LABELS_TRAIT),
+ HirItem::Trait(..) => ("ItemTrait", LABELS_TRAIT),
// An implementation, eg `impl<A> Trait for Foo { .. }`
HirItem::Impl { .. } => ("ItemKind::Impl", LABELS_IMPL),
}
}
-/// Given a `#[rustc_dirty]` or `#[rustc_clean]` attribute, scan
-/// for a `cfg="foo"` attribute and check whether we have a cfg
-/// flag called `foo`.
-///
-/// Also make sure that the `label` and `except` fields do not
-/// both exist.
+/// Given a `#[rustc_clean]` attribute, scan for a `cfg="foo"` attribute and check whether we have
+/// a cfg flag called `foo`.
fn check_config(tcx: TyCtxt<'_>, attr: &Attribute) -> bool {
debug!("check_config(attr={:?})", attr);
let config = &tcx.sess.parse_sess.config;
debug!("check_config: config={:?}", config);
- let (mut cfg, mut except, mut label) = (None, false, false);
+ let mut cfg = None;
for item in attr.meta_item_list().unwrap_or_else(Vec::new) {
if item.has_name(CFG) {
let value = expect_associated_value(tcx, &item);
debug!("check_config: searching for cfg {:?}", value);
cfg = Some(config.contains(&(value, None)));
- }
- if item.has_name(LABEL) {
- label = true;
- }
- if item.has_name(EXCEPT) {
- except = true;
+ } else if !item.has_name(EXCEPT) {
+ tcx.sess.span_err(attr.span, &format!("unknown item `{}`", item.name_or_empty()));
}
}
- if label && except {
- tcx.sess.span_fatal(attr.span, "must specify only one of: `label`, `except`");
- }
-
match cfg {
None => tcx.sess.span_fatal(attr.span, "no cfg attribute"),
Some(c) => c,
}
}
-// A visitor that collects all #[rustc_dirty]/#[rustc_clean] attributes from
+// A visitor that collects all #[rustc_clean] attributes from
// the HIR. It is used to verify that we really ran checks for all annotated
// nodes.
-pub struct FindAllAttrs<'a, 'tcx> {
+pub struct FindAllAttrs<'tcx> {
tcx: TyCtxt<'tcx>,
- attr_names: &'a [Symbol],
found_attrs: Vec<&'tcx Attribute>,
}
-impl FindAllAttrs<'_, 'tcx> {
+impl FindAllAttrs<'tcx> {
fn is_active_attr(&mut self, attr: &Attribute) -> bool {
- for attr_name in self.attr_names {
- if self.tcx.sess.check_name(attr, *attr_name) && check_config(self.tcx, attr) {
- return true;
- }
+ if self.tcx.sess.check_name(attr, sym::rustc_clean) && check_config(self.tcx, attr) {
+ return true;
}
false
fn report_unchecked_attrs(&self, mut checked_attrs: FxHashSet<ast::AttrId>) {
for attr in &self.found_attrs {
if !checked_attrs.contains(&attr.id) {
- self.tcx.sess.span_err(
- attr.span,
- "found unchecked `#[rustc_dirty]` / `#[rustc_clean]` attribute",
- );
+ self.tcx.sess.span_err(attr.span, "found unchecked `#[rustc_clean]` attribute");
checked_attrs.insert(attr.id);
}
}
}
}
-impl intravisit::Visitor<'tcx> for FindAllAttrs<'_, 'tcx> {
+impl intravisit::Visitor<'tcx> for FindAllAttrs<'tcx> {
type Map = Map<'tcx>;
fn nested_visit_map(&mut self) -> intravisit::NestedVisitorMap<Self::Map> {
use rustc_data_structures::fx::{FxHashMap, FxHashSet};
use rustc_data_structures::svh::Svh;
use rustc_data_structures::{base_n, flock};
+use rustc_errors::ErrorReported;
use rustc_fs_util::{link_or_copy, LinkOrCopy};
use rustc_session::{CrateDisambiguator, Session};
sess: &Session,
crate_name: &str,
crate_disambiguator: CrateDisambiguator,
-) {
+) -> Result<(), ErrorReported> {
if sess.opts.incremental.is_none() {
- return;
+ return Ok(());
}
let _timer = sess.timer("incr_comp_prepare_session_directory");
// {incr-comp-dir}/{crate-name-and-disambiguator}
let crate_dir = crate_path(sess, crate_name, crate_disambiguator);
debug!("crate-dir: {}", crate_dir.display());
- if create_dir(sess, &crate_dir, "crate").is_err() {
- return;
- }
+ create_dir(sess, &crate_dir, "crate")?;
// Hack: canonicalize the path *after creating the directory*
// because, on windows, long paths can cause problems;
crate_dir.display(),
err
));
- return;
+ return Err(ErrorReported);
}
};
// Lock the new session directory. If this fails, return an
// error without retrying
- let (directory_lock, lock_file_path) = match lock_directory(sess, &session_dir) {
- Ok(e) => e,
- Err(_) => return,
- };
+ let (directory_lock, lock_file_path) = lock_directory(sess, &session_dir)?;
// Now that we have the lock, we can actually create the session
// directory
- if create_dir(sess, &session_dir, "session").is_err() {
- return;
- }
+ create_dir(sess, &session_dir, "session")?;
// Find a suitable source directory to copy from. Ignore those that we
// have already tried before.
);
sess.init_incr_comp_session(session_dir, directory_lock, false);
- return;
+ return Ok(());
};
debug!("attempting to copy data from source: {}", source_directory.display());
}
sess.init_incr_comp_session(session_dir, directory_lock, true);
- return;
+ return Ok(());
} else {
debug!("copying failed - trying next directory");
directory_path
}
-fn create_dir(sess: &Session, path: &Path, dir_tag: &str) -> Result<(), ()> {
+fn create_dir(sess: &Session, path: &Path, dir_tag: &str) -> Result<(), ErrorReported> {
match std_fs::create_dir_all(path) {
Ok(()) => {
debug!("{} directory created successfully", dir_tag);
path.display(),
err
));
- Err(())
+ Err(ErrorReported)
}
}
}
/// Allocate the lock-file and lock it.
-fn lock_directory(sess: &Session, session_dir: &Path) -> Result<(flock::Lock, PathBuf), ()> {
+fn lock_directory(
+ sess: &Session,
+ session_dir: &Path,
+) -> Result<(flock::Lock, PathBuf), ErrorReported> {
let lock_file_path = lock_file_path(session_dir);
debug!("lock_directory() - lock_file: {}", lock_file_path.display());
) {
// the lock should be exclusive
Ok(lock) => Ok((lock, lock_file_path)),
- Err(err) => {
- sess.err(&format!(
+ Err(lock_err) => {
+ let mut err = sess.struct_err(&format!(
"incremental compilation: could not create \
- session directory lock file: {}",
- err
+ session directory lock file: {}",
+ lock_err
));
- Err(())
+ if flock::Lock::error_unsupported(&lock_err) {
+ err.note(&format!(
+ "the filesystem for the incremental path at {} \
+ does not appear to support locking, consider changing the \
+ incremental path to a filesystem that supports locking \
+ or disable incremental compilation",
+ session_dir.display()
+ ));
+ if std::env::var_os("CARGO").is_some() {
+ err.help(
+ "incremental compilation can be disabled by setting the \
+ environment variable CARGO_INCREMENTAL=0 (see \
+ https://doc.rust-lang.org/cargo/reference/profiles.html#incremental)",
+ );
+ err.help(
+ "the entire build directory can be changed to a different \
+ filesystem by setting the environment variable CARGO_TARGET_DIR \
+ to a different path (see \
+ https://doc.rust-lang.org/cargo/reference/config.html#buildtarget-dir)",
+ );
+ }
+ }
+ err.emit();
+ Err(ErrorReported)
}
}
}
//! Code to save/load the dep-graph from files.
use rustc_data_structures::fx::FxHashMap;
-use rustc_hir::definitions::DefPathTable;
-use rustc_middle::dep_graph::{PreviousDepGraph, SerializedDepGraph, WorkProduct, WorkProductId};
+use rustc_middle::dep_graph::{SerializedDepGraph, WorkProduct, WorkProductId};
use rustc_middle::ty::query::OnDiskCache;
use rustc_serialize::opaque::Decoder;
use rustc_serialize::Decodable;
Error { message: String },
}
-impl LoadResult<(PreviousDepGraph, WorkProductMap)> {
- pub fn open(self, sess: &Session) -> (PreviousDepGraph, WorkProductMap) {
+impl LoadResult<(SerializedDepGraph, WorkProductMap)> {
+ pub fn open(self, sess: &Session) -> (SerializedDepGraph, WorkProductMap) {
match self {
LoadResult::Error { message } => {
sess.warn(&message);
}
}
-pub type DepGraphFuture = MaybeAsync<LoadResult<(PreviousDepGraph, WorkProductMap)>>;
+pub type DepGraphFuture = MaybeAsync<LoadResult<(SerializedDepGraph, WorkProductMap)>>;
/// Launch a thread and load the dependency graph in the background.
pub fn load_dep_graph(sess: &Session) -> DepGraphFuture {
let dep_graph = SerializedDepGraph::decode(&mut decoder)
.expect("Error reading cached dep-graph");
- LoadResult::Ok { data: (PreviousDepGraph::new(dep_graph), prev_work_products) }
+ LoadResult::Ok { data: (dep_graph, prev_work_products) }
}
}
}))
/// If we are not in incremental compilation mode, returns `None`.
/// Otherwise, tries to load the query result cache from disk,
/// creating an empty cache if it could not be loaded.
-pub fn load_query_result_cache<'a>(
- sess: &'a Session,
- def_path_table: &DefPathTable,
-) -> Option<OnDiskCache<'a>> {
+pub fn load_query_result_cache<'a>(sess: &'a Session) -> Option<OnDiskCache<'a>> {
if sess.opts.incremental.is_none() {
return None;
}
sess.is_nightly_build(),
) {
LoadResult::Ok { data: (bytes, start_pos) } => {
- Some(OnDiskCache::new(sess, bytes, start_pos, def_path_table))
+ Some(OnDiskCache::new(sess, bytes, start_pos))
}
_ => Some(OnDiskCache::new_empty(sess.source_map())),
}
use rustc_data_structures::fx::FxHashMap;
use rustc_data_structures::sync::join;
-use rustc_middle::dep_graph::{DepGraph, PreviousDepGraph, WorkProduct, WorkProductId};
+use rustc_middle::dep_graph::{DepGraph, SerializedDepGraph, WorkProduct, WorkProductId};
use rustc_middle::ty::TyCtxt;
use rustc_serialize::opaque::{FileEncodeResult, FileEncoder};
use rustc_serialize::Encodable as RustcEncodable;
pub fn build_dep_graph(
sess: &Session,
- prev_graph: PreviousDepGraph,
+ prev_graph: SerializedDepGraph,
prev_work_products: FxHashMap<WorkProductId, WorkProduct>,
) -> Option<DepGraph> {
if sess.opts.incremental.is_none() {
}
Some(DepGraph::new(
+ &sess.prof,
prev_graph,
prev_work_products,
encoder,
#![feature(allow_internal_unstable)]
#![feature(bench_black_box)]
-#![feature(const_panic)]
#![feature(extend_one)]
#![feature(iter_zip)]
#![feature(unboxed_closures)]
/// `u32::MAX`. You can also customize things like the `Debug` impl,
/// what traits are derived, and so forth via the macro.
#[macro_export]
-#[allow_internal_unstable(step_trait, step_trait_ext, rustc_attrs)]
+#[allow_internal_unstable(step_trait, rustc_attrs, trusted_step)]
macro_rules! newtype_index {
// ---- public rules ----
}
}
- unsafe impl ::std::iter::Step for $type {
+ impl ::std::iter::Step for $type {
#[inline]
fn steps_between(start: &Self, end: &Self) -> Option<usize> {
<usize as ::std::iter::Step>::steps_between(
}
}
+ // Safety: The implementation of `Step` upholds all invariants.
+ unsafe impl ::std::iter::TrustedStep for $type {}
+
impl From<$type> for u32 {
#[inline]
fn from(v: $type) -> u32 {
)
}
- fn push_outlives(&mut self, sup: ty::Region<'tcx>, sub: ty::Region<'tcx>) {
+ fn push_outlives(
+ &mut self,
+ sup: ty::Region<'tcx>,
+ sub: ty::Region<'tcx>,
+ _info: ty::VarianceDiagInfo<'tcx>,
+ ) {
self.obligations.push(Obligation {
cause: self.cause.clone(),
param_env: self.param_env,
match dir {
EqTo => self.equate(a_is_expected).relate(a_ty, b_ty),
SubtypeOf => self.sub(a_is_expected).relate(a_ty, b_ty),
- SupertypeOf => {
- self.sub(a_is_expected).relate_with_variance(ty::Contravariant, a_ty, b_ty)
- }
+ SupertypeOf => self.sub(a_is_expected).relate_with_variance(
+ ty::Contravariant,
+ ty::VarianceDiagInfo::default(),
+ a_ty,
+ b_ty,
+ ),
}?;
Ok(())
fn relate_with_variance<T: Relate<'tcx>>(
&mut self,
variance: ty::Variance,
+ _info: ty::VarianceDiagInfo<'tcx>,
a: T,
b: T,
) -> RelateResult<'tcx, T> {
if self.tcx().lazy_normalization() =>
{
assert_eq!(promoted, None);
- let substs = self.relate_with_variance(ty::Variance::Invariant, substs, substs)?;
+ let substs = self.relate_with_variance(
+ ty::Variance::Invariant,
+ ty::VarianceDiagInfo::default(),
+ substs,
+ substs,
+ )?;
Ok(self.tcx().mk_const(ty::Const {
ty: c.ty,
val: ty::ConstKind::Unevaluated(ty::Unevaluated { def, substs, promoted }),
fn relate_with_variance<T: Relate<'tcx>>(
&mut self,
_variance: ty::Variance,
+ _info: ty::VarianceDiagInfo<'tcx>,
a: T,
b: T,
) -> RelateResult<'tcx, T> {
if self.tcx().lazy_normalization() =>
{
assert_eq!(promoted, None);
- let substs = self.relate_with_variance(ty::Variance::Invariant, substs, substs)?;
+ let substs = self.relate_with_variance(
+ ty::Variance::Invariant,
+ ty::VarianceDiagInfo::default(),
+ substs,
+ substs,
+ )?;
Ok(self.tcx().mk_const(ty::Const {
ty: c.ty,
val: ty::ConstKind::Unevaluated(ty::Unevaluated { def, substs, promoted }),
fn relate_with_variance<T: Relate<'tcx>>(
&mut self,
_: ty::Variance,
+ _info: ty::VarianceDiagInfo<'tcx>,
a: T,
b: T,
) -> RelateResult<'tcx, T> {
use rustc_hir::def_id::DefId;
use rustc_hir::lang_items::LangItem;
use rustc_hir::{Item, ItemKind, Node};
+use rustc_middle::dep_graph::DepContext;
use rustc_middle::ty::error::TypeError;
use rustc_middle::ty::{
self,
}
fn path_crate(self, cnum: CrateNum) -> Result<Self::Path, Self::Error> {
- Ok(vec![self.tcx.original_crate_name(cnum).to_string()])
+ Ok(vec![self.tcx.crate_name(cnum).to_string()])
}
fn path_qualified(
self,
struct_span_err!(self.tcx.sess, span, E0580, "{}", failure_str)
}
FailureCode::Error0308(failure_str) => {
- struct_span_err!(self.tcx.sess, span, E0308, "{}", failure_str)
+ let mut err = struct_span_err!(self.tcx.sess, span, E0308, "{}", failure_str);
+ if let ValuePairs::Types(ty::error::ExpectedFound { expected, found }) =
+ trace.values
+ {
+ // If a tuple of length one was expected and the found expression has
+ // parentheses around it, perhaps the user meant to write `(expr,)` to
+ // build a tuple (issue #86100)
+ match (expected.kind(), found.kind()) {
+ (ty::Tuple(_), ty::Tuple(_)) => {}
+ (ty::Tuple(_), _) if expected.tuple_fields().count() == 1 => {
+ if let Ok(code) = self.tcx.sess().source_map().span_to_snippet(span) {
+ if let Some(code) =
+ code.strip_prefix('(').and_then(|s| s.strip_suffix(')'))
+ {
+ err.span_suggestion(
+ span,
+ "use a trailing comma to create a tuple with one element",
+ format!("({},)", code),
+ Applicability::MaybeIncorrect,
+ );
+ }
+ }
+ }
+ _ => {}
+ }
+ }
+ err
}
FailureCode::Error0644(failure_str) => {
struct_span_err!(self.tcx.sess, span, E0644, "{}", failure_str)
let fn_decl = hir.fn_decl_by_hir_id(owner_id).unwrap();
let poly_fn_sig = self.tcx().fn_sig(id);
let fn_sig = self.tcx().liberate_late_bound_regions(id, poly_fn_sig);
- body.params.iter().enumerate().find_map(|(index, param)| {
- // May return None; sometimes the tables are not yet populated.
- let ty = fn_sig.inputs()[index];
- let mut found_anon_region = false;
- let new_param_ty = self.tcx().fold_regions(ty, &mut false, |r, _| {
- if *r == *anon_region {
- found_anon_region = true;
- replace_region
+ body.params
+ .iter()
+ .take(if fn_sig.c_variadic {
+ fn_sig.inputs().len()
+ } else {
+ assert_eq!(fn_sig.inputs().len(), body.params.len());
+ body.params.len()
+ })
+ .enumerate()
+ .find_map(|(index, param)| {
+ // May return None; sometimes the tables are not yet populated.
+ let ty = fn_sig.inputs()[index];
+ let mut found_anon_region = false;
+ let new_param_ty = self.tcx().fold_regions(ty, &mut false, |r, _| {
+ if *r == *anon_region {
+ found_anon_region = true;
+ replace_region
+ } else {
+ r
+ }
+ });
+ if found_anon_region {
+ let ty_hir_id = fn_decl.inputs[index].hir_id;
+ let param_ty_span = hir.span(ty_hir_id);
+ let is_first = index == 0;
+ Some(AnonymousParamInfo {
+ param,
+ param_ty: new_param_ty,
+ param_ty_span,
+ bound_region,
+ is_first,
+ })
} else {
- r
+ None
}
- });
- if found_anon_region {
- let ty_hir_id = fn_decl.inputs[index].hir_id;
- let param_ty_span = hir.span(ty_hir_id);
- let is_first = index == 0;
- Some(AnonymousParamInfo {
- param,
- param_ty: new_param_ty,
- param_ty_span,
- bound_region,
- is_first,
- })
- } else {
- None
- }
- })
+ })
}
pub(super) fn future_return_type(
fn relate_with_variance<T: Relate<'tcx>>(
&mut self,
variance: ty::Variance,
+ _info: ty::VarianceDiagInfo<'tcx>,
a: T,
b: T,
) -> RelateResult<'tcx, T> {
// When higher-ranked types are involved, computing the LUB is
// very challenging, switch to invariance. This is obviously
// overly conservative but works ok in practice.
- self.relate_with_variance(ty::Variance::Invariant, a, b)?;
+ self.relate_with_variance(ty::Variance::Invariant, ty::VarianceDiagInfo::default(), a, b)?;
Ok(a)
}
}
fn relate_with_variance<T: Relate<'tcx>>(
&mut self,
variance: ty::Variance,
+ _info: ty::VarianceDiagInfo<'tcx>,
a: T,
b: T,
) -> RelateResult<'tcx, T> {
// When higher-ranked types are involved, computing the LUB is
// very challenging, switch to invariance. This is obviously
// overly conservative but works ok in practice.
- self.relate_with_variance(ty::Variance::Invariant, a, b)?;
+ self.relate_with_variance(ty::Variance::Invariant, ty::VarianceDiagInfo::default(), a, b)?;
Ok(a)
}
}
/// - Bivariant means that it doesn't matter.
ambient_variance: ty::Variance,
+ ambient_variance_info: ty::VarianceDiagInfo<'tcx>,
+
/// When we pass through a set of binders (e.g., when looking into
/// a `fn` type), we push a new bound region scope onto here. This
/// will contain the instantiated region for each region in those
/// satisfied for the two types to be related. `sub` and `sup` may
/// be regions from the type or new variables created through the
/// delegate.
- fn push_outlives(&mut self, sup: ty::Region<'tcx>, sub: ty::Region<'tcx>);
+ fn push_outlives(
+ &mut self,
+ sup: ty::Region<'tcx>,
+ sub: ty::Region<'tcx>,
+ info: ty::VarianceDiagInfo<'tcx>,
+ );
fn const_equate(&mut self, a: &'tcx ty::Const<'tcx>, b: &'tcx ty::Const<'tcx>);
delegate: D,
ambient_variance: ty::Variance,
) -> Self {
- Self { infcx, delegate, ambient_variance, a_scopes: vec![], b_scopes: vec![] }
+ Self {
+ infcx,
+ delegate,
+ ambient_variance,
+ ambient_variance_info: ty::VarianceDiagInfo::default(),
+ a_scopes: vec![],
+ b_scopes: vec![],
+ }
}
fn ambient_covariance(&self) -> bool {
/// Push a new outlives requirement into our output set of
/// constraints.
- fn push_outlives(&mut self, sup: ty::Region<'tcx>, sub: ty::Region<'tcx>) {
+ fn push_outlives(
+ &mut self,
+ sup: ty::Region<'tcx>,
+ sub: ty::Region<'tcx>,
+ info: ty::VarianceDiagInfo<'tcx>,
+ ) {
debug!("push_outlives({:?}: {:?})", sup, sub);
- self.delegate.push_outlives(sup, sub);
+ self.delegate.push_outlives(sup, sub, info);
}
/// Relate a projection type and some value type lazily. This will always
fn relate_with_variance<T: Relate<'tcx>>(
&mut self,
variance: ty::Variance,
+ info: ty::VarianceDiagInfo<'tcx>,
a: T,
b: T,
) -> RelateResult<'tcx, T> {
let old_ambient_variance = self.ambient_variance;
self.ambient_variance = self.ambient_variance.xform(variance);
+ self.ambient_variance_info = self.ambient_variance_info.clone().xform(info);
debug!("relate_with_variance: ambient_variance = {:?}", self.ambient_variance);
if self.ambient_covariance() {
// Covariance: a <= b. Hence, `b: a`.
- self.push_outlives(v_b, v_a);
+ self.push_outlives(v_b, v_a, self.ambient_variance_info.clone());
}
if self.ambient_contravariance() {
// Contravariant: b <= a. Hence, `a: b`.
- self.push_outlives(v_a, v_b);
+ self.push_outlives(v_a, v_b, self.ambient_variance_info.clone());
}
Ok(a)
fn relate_with_variance<T: Relate<'tcx>>(
&mut self,
variance: ty::Variance,
+ _info: ty::VarianceDiagInfo<'tcx>,
a: T,
b: T,
) -> RelateResult<'tcx, T> {
self.combine_map(t).insert(vars, c);
self.undo_log.push(AddCombination(t, vars));
let new_r = tcx.mk_region(ReVar(c));
- for &old_r in &[a, b] {
+ for old_r in [a, b] {
match t {
Glb => self.make_subregion(origin.clone(), new_r, old_r),
Lub => self.make_subregion(origin.clone(), old_r, new_r),
fn relate_with_variance<T: Relate<'tcx>>(
&mut self,
variance: ty::Variance,
+ _info: ty::VarianceDiagInfo<'tcx>,
a: T,
b: T,
) -> RelateResult<'tcx, T> {
#![feature(bool_to_option)]
#![feature(box_patterns)]
#![feature(box_syntax)]
-#![feature(const_panic)]
#![feature(extend_one)]
#![feature(iter_zip)]
#![feature(never_type)]
#![feature(in_band_lifetimes)]
#![feature(control_flow_enum)]
+#![feature(min_specialization)]
#![recursion_limit = "512"] // For rustdoc
#[macro_use]
#![feature(bool_to_option)]
#![feature(box_patterns)]
-#![feature(box_syntax)]
#![feature(internal_output_capture)]
#![feature(nll)]
-#![feature(generator_trait)]
-#![feature(generators)]
#![feature(once_cell)]
#![recursion_limit = "256"]
use rustc_ast::{self as ast, visit};
use rustc_codegen_ssa::back::link::emit_metadata;
use rustc_codegen_ssa::traits::CodegenBackend;
+use rustc_data_structures::parallel;
use rustc_data_structures::steal::Steal;
use rustc_data_structures::sync::{par_iter, Lrc, OnceCell, ParallelIterator, WorkerLocal};
use rustc_data_structures::temp_dir::MaybeTempDir;
-use rustc_data_structures::{box_region_allow_access, declare_box_region_type, parallel};
use rustc_errors::{ErrorReported, PResult};
use rustc_expand::base::ExtCtxt;
use rustc_hir::def_id::LOCAL_CRATE;
use std::ffi::OsString;
use std::io::{self, BufWriter, Write};
use std::lazy::SyncLazy;
+use std::marker::PhantomPinned;
use std::path::PathBuf;
+use std::pin::Pin;
use std::rc::Rc;
use std::{env, fs, iter};
counter.count
}
-declare_box_region_type!(
- pub BoxedResolver,
- for(),
- (&mut Resolver<'_>) -> (Result<ast::Crate>, ResolverOutputs)
-);
+pub use boxed_resolver::BoxedResolver;
+mod boxed_resolver {
+ use super::*;
+
+ pub struct BoxedResolver(Pin<Box<BoxedResolverInner>>);
+
+ struct BoxedResolverInner {
+ session: Lrc<Session>,
+ resolver_arenas: Option<ResolverArenas<'static>>,
+ resolver: Option<Resolver<'static>>,
+ _pin: PhantomPinned,
+ }
+
+ // Note: Drop order is important to prevent dangling references. Resolver must be dropped first,
+ // then resolver_arenas and finally session.
+ impl Drop for BoxedResolverInner {
+ fn drop(&mut self) {
+ self.resolver.take();
+ self.resolver_arenas.take();
+ }
+ }
+
+ impl BoxedResolver {
+ pub(super) fn new<F>(session: Lrc<Session>, make_resolver: F) -> Result<(ast::Crate, Self)>
+ where
+ F: for<'a> FnOnce(
+ &'a Session,
+ &'a ResolverArenas<'a>,
+ ) -> Result<(ast::Crate, Resolver<'a>)>,
+ {
+ let mut boxed_resolver = Box::new(BoxedResolverInner {
+ session,
+ resolver_arenas: Some(Resolver::arenas()),
+ resolver: None,
+ _pin: PhantomPinned,
+ });
+ // SAFETY: `make_resolver` takes a resolver arena with an arbitrary lifetime and
+ // returns a resolver with the same lifetime as the arena. We ensure that the arena
+ // outlives the resolver in the drop impl and elsewhere so these transmutes are sound.
+ unsafe {
+ let (crate_, resolver) = make_resolver(
+ std::mem::transmute::<&Session, &Session>(&boxed_resolver.session),
+ std::mem::transmute::<&ResolverArenas<'_>, &ResolverArenas<'_>>(
+ boxed_resolver.resolver_arenas.as_ref().unwrap(),
+ ),
+ )?;
+ boxed_resolver.resolver = Some(resolver);
+ Ok((crate_, BoxedResolver(Pin::new_unchecked(boxed_resolver))))
+ }
+ }
+
+ pub fn access<F: for<'a> FnOnce(&mut Resolver<'a>) -> R, R>(&mut self, f: F) -> R {
+ // SAFETY: The resolver doesn't need to be pinned.
+ let mut resolver = unsafe {
+ self.0.as_mut().map_unchecked_mut(|boxed_resolver| &mut boxed_resolver.resolver)
+ };
+ f((&mut *resolver).as_mut().unwrap())
+ }
+
+ pub fn to_resolver_outputs(resolver: Rc<RefCell<BoxedResolver>>) -> ResolverOutputs {
+ match Rc::try_unwrap(resolver) {
+ Ok(resolver) => {
+ let mut resolver = resolver.into_inner();
+ // SAFETY: The resolver doesn't need to be pinned.
+ let mut resolver = unsafe {
+ resolver
+ .0
+ .as_mut()
+ .map_unchecked_mut(|boxed_resolver| &mut boxed_resolver.resolver)
+ };
+ resolver.take().unwrap().into_outputs()
+ }
+ Err(resolver) => resolver.borrow_mut().access(|resolver| resolver.clone_outputs()),
+ }
+ }
+ }
+}
/// Runs the "early phases" of the compiler: initial `cfg` processing, loading compiler plugins,
/// syntax expansion, secondary `cfg` expansion, synthesis of a test
// its contents but the results of name resolution on those contents. Hopefully we'll push
// this back at some point.
let crate_name = crate_name.to_string();
- let (result, resolver) = BoxedResolver::new(static move |mut action| {
- let _ = action;
- let sess = &*sess;
- let resolver_arenas = Resolver::arenas();
- let res = configure_and_expand_inner(
+ BoxedResolver::new(sess, move |sess, resolver_arenas| {
+ configure_and_expand_inner(
sess,
&lint_store,
krate,
&crate_name,
&resolver_arenas,
- &*metadata_loader,
- );
- let mut resolver = match res {
- Err(v) => {
- yield BoxedResolver::initial_yield(Err(v));
- panic!()
- }
- Ok((krate, resolver)) => {
- action = yield BoxedResolver::initial_yield(Ok(krate));
- resolver
- }
- };
- box_region_allow_access!(for(), (&mut Resolver<'_>), (&mut resolver), action);
- resolver.into_outputs()
- });
- result.map(|k| (k, resolver))
-}
-
-impl BoxedResolver {
- pub fn to_resolver_outputs(resolver: Rc<RefCell<BoxedResolver>>) -> ResolverOutputs {
- match Rc::try_unwrap(resolver) {
- Ok(resolver) => resolver.into_inner().complete(),
- Err(resolver) => resolver.borrow_mut().access(|resolver| resolver.clone_outputs()),
- }
- }
+ metadata_loader,
+ )
+ })
}
pub fn register_plugins<'a>(
let disambiguator = util::compute_crate_disambiguator(sess);
sess.crate_disambiguator.set(disambiguator).expect("not yet initialized");
- rustc_incremental::prepare_session_directory(sess, &crate_name, disambiguator);
+ rustc_incremental::prepare_session_directory(sess, &crate_name, disambiguator)?;
if sess.opts.incremental.is_some() {
sess.time("incr_comp_garbage_collect_session_directories", || {
fn configure_and_expand_inner<'a>(
sess: &'a Session,
- lint_store: &'a LintStore,
+ lint_store: &LintStore,
mut krate: ast::Crate,
crate_name: &str,
resolver_arenas: &'a ResolverArenas<'a>,
- metadata_loader: &'a MetadataLoaderDyn,
+ metadata_loader: Box<MetadataLoaderDyn>,
) -> Result<(ast::Crate, Resolver<'a>)> {
tracing::trace!("configure_and_expand_inner");
pre_expansion_lint(sess, lint_store, &krate, crate_name);
) -> QueryContext<'tcx> {
let sess = &compiler.session();
- let def_path_table = resolver_outputs.definitions.def_path_table();
- let query_result_on_disk_cache =
- rustc_incremental::load_query_result_cache(sess, def_path_table);
+ let query_result_on_disk_cache = rustc_incremental::load_query_result_cache(sess);
let codegen_backend = compiler.codegen_backend();
let mut local_providers = *DEFAULT_QUERY_PROVIDERS;
query_result_on_disk_cache,
queries.as_dyn(),
&crate_name,
- &outputs,
+ outputs,
)
})
});
.tempdir_in(out_filename.parent().unwrap())
.unwrap_or_else(|err| tcx.sess.fatal(&format!("couldn't create a temp dir: {}", err)));
let metadata_tmpdir = MaybeTempDir::new(metadata_tmpdir, tcx.sess.opts.cg.save_temps);
- let metadata_filename = emit_metadata(tcx.sess, &metadata, &metadata_tmpdir);
+ let metadata_filename = emit_metadata(tcx.sess, &metadata.raw_data, &metadata_tmpdir);
if let Err(e) = util::non_durable_rename(&metadata_filename, &out_filename) {
tcx.sess.fatal(&format!("failed to write {}: {}", out_filename.display(), e));
}
self.compiler.register_lints.as_deref().unwrap_or_else(|| empty),
krate,
&crate_name,
- );
+ )?;
// Compute the dependency graph (in the background). We want to do
// this as early as possible, to give the DepGraph maximum time to
// called, which happens within passes::register_plugins().
self.dep_graph_future().ok();
- result
+ Ok(result)
})
}
self.prepare_outputs.compute(|| {
let expansion_result = self.expansion()?;
let (krate, boxed_resolver, _) = &*expansion_result.peek();
- let crate_name = self.crate_name()?;
- let crate_name = crate_name.peek();
+ let crate_name = self.crate_name()?.peek();
passes::prepare_outputs(
self.session(),
self.compiler,
}
pub fn linker(&'tcx self) -> Result<Linker> {
- let dep_graph = self.dep_graph()?;
- let prepare_outputs = self.prepare_outputs()?;
- let crate_hash = self.global_ctxt()?.peek_mut().enter(|tcx| tcx.crate_hash(LOCAL_CRATE));
- let ongoing_codegen = self.ongoing_codegen()?;
-
let sess = self.session().clone();
let codegen_backend = self.codegen_backend().clone();
+ let dep_graph = self.dep_graph()?.peek().clone();
+ let prepare_outputs = self.prepare_outputs()?.take();
+ let crate_hash = self.global_ctxt()?.peek_mut().enter(|tcx| tcx.crate_hash(LOCAL_CRATE));
+ let ongoing_codegen = self.ongoing_codegen()?.take();
+
Ok(Linker {
sess,
- dep_graph: dep_graph.peek().clone(),
- prepare_outputs: prepare_outputs.take(),
- crate_hash,
- ongoing_codegen: ongoing_codegen.take(),
codegen_backend,
+
+ dep_graph,
+ prepare_outputs,
+ crate_hash,
+ ongoing_codegen,
})
}
}
pub struct Linker {
+ // compilation inputs
sess: Lrc<Session>,
+ codegen_backend: Lrc<Box<dyn CodegenBackend>>,
+
+ // compilation outputs
dep_graph: DepGraph,
prepare_outputs: OutputFilenames,
crate_hash: Svh,
ongoing_codegen: Box<dyn Any>,
- codegen_backend: Lrc<Box<dyn CodegenBackend>>,
}
impl Linker {
(String::from("d"), Level::Forbid),
];
- assert_same_hash(&v1, &v2);
+ // The hash should be order-dependent
+ assert_different_hash(&v1, &v2);
}
#[test]
},
];
- assert_same_hash(&v1, &v2);
- assert_same_hash(&v1, &v3);
- assert_same_hash(&v2, &v3);
+ // The hash should be order-dependent
+ assert_different_hash(&v1, &v2);
+ assert_different_hash(&v1, &v3);
+ assert_different_hash(&v2, &v3);
}
#[test]
use std::panic;
use std::path::{Path, PathBuf};
use std::sync::atomic::{AtomicBool, Ordering};
-use std::sync::{Arc, Mutex, Once};
+use std::sync::{Arc, Mutex};
use std::thread;
use tracing::info;
let codegen_backend = if let Some(make_codegen_backend) = make_codegen_backend {
make_codegen_backend(&sopts)
} else {
- get_codegen_backend(&sopts)
+ get_codegen_backend(
+ &sopts.maybe_sysroot,
+ sopts.debugging_opts.codegen_backend.as_ref().map(|name| &name[..]),
+ )
};
// target_override is documented to be called before init(), so this is okay
}
}
-pub fn get_codegen_backend(sopts: &config::Options) -> Box<dyn CodegenBackend> {
- static INIT: Once = Once::new();
-
- static mut LOAD: fn() -> Box<dyn CodegenBackend> = || unreachable!();
+/// Get the codegen backend based on the name and specified sysroot.
+///
+/// A name of `None` indicates that the default backend should be used.
+pub fn get_codegen_backend(
+ maybe_sysroot: &Option<PathBuf>,
+ backend_name: Option<&str>,
+) -> Box<dyn CodegenBackend> {
+ static LOAD: SyncOnceCell<unsafe fn() -> Box<dyn CodegenBackend>> = SyncOnceCell::new();
- INIT.call_once(|| {
+ let load = LOAD.get_or_init(|| {
#[cfg(feature = "llvm")]
const DEFAULT_CODEGEN_BACKEND: &str = "llvm";
#[cfg(not(feature = "llvm"))]
const DEFAULT_CODEGEN_BACKEND: &str = "cranelift";
- let codegen_name = sopts
- .debugging_opts
- .codegen_backend
- .as_ref()
- .map(|name| &name[..])
- .unwrap_or(DEFAULT_CODEGEN_BACKEND);
-
- let backend = match codegen_name {
+ match backend_name.unwrap_or(DEFAULT_CODEGEN_BACKEND) {
filename if filename.contains('.') => load_backend_from_dylib(filename.as_ref()),
- codegen_name => get_builtin_codegen_backend(&sopts.maybe_sysroot, codegen_name),
- };
-
- unsafe {
- LOAD = backend;
+ #[cfg(feature = "llvm")]
+ "llvm" => rustc_codegen_llvm::LlvmCodegenBackend::new,
+ backend_name => get_codegen_sysroot(maybe_sysroot, backend_name),
}
});
- unsafe { LOAD() }
+
+ // SAFETY: In case of a builtin codegen backend this is safe. In case of an external codegen
+ // backend we hope that the backend links against the same rustc_driver version. If this is not
+ // the case, we get UB.
+ unsafe { load() }
}
// This is used for rustdoc, but it uses similar machinery to codegen backend
}
}
-pub fn get_builtin_codegen_backend(
- maybe_sysroot: &Option<PathBuf>,
- backend_name: &str,
-) -> fn() -> Box<dyn CodegenBackend> {
- match backend_name {
- #[cfg(feature = "llvm")]
- "llvm" => rustc_codegen_llvm::LlvmCodegenBackend::new,
- _ => get_codegen_sysroot(maybe_sysroot, backend_name),
- }
-}
-
pub fn get_codegen_sysroot(
maybe_sysroot: &Option<PathBuf>,
backend_name: &str,
if let Some(list) = attr.meta_item_list() {
for meta in list {
- if meta.has_name(sym::include) || meta.has_name(sym::hidden) {
+ if meta.has_name(sym::hidden) {
return true;
}
}
}
}
- /// Checks the validity of lint names derived from the command line
- pub fn check_lint_name_cmdline(&self, sess: &Session, lint_name: &str, level: Level) {
+ /// Checks the validity of lint names derived from the command line. Returns
+ /// true if the lint is valid, false otherwise.
+ pub fn check_lint_name_cmdline(
+ &self,
+ sess: &Session,
+ lint_name: &str,
+ level: Option<Level>,
+ ) -> bool {
let db = match self.check_lint_name(lint_name, None) {
CheckLintNameResult::Ok(_) => None,
CheckLintNameResult::Warning(ref msg, _) => Some(sess.struct_warn(msg)),
};
if let Some(mut db) = db {
- let msg = format!(
- "requested on the command line with `{} {}`",
- match level {
- Level::Allow => "-A",
- Level::Warn => "-W",
- Level::Deny => "-D",
- Level::Forbid => "-F",
- },
- lint_name
- );
- db.note(&msg);
+ if let Some(level) = level {
+ let msg = format!(
+ "requested on the command line with `{} {}`",
+ match level {
+ Level::Allow => "-A",
+ Level::Warn => "-W",
+ Level::Deny => "-D",
+ Level::Forbid => "-F",
+ },
+ lint_name
+ );
+ db.note(&msg);
+ }
db.emit();
+ false
+ } else {
+ true
}
}
}
fn path_crate(self, cnum: CrateNum) -> Result<Self::Path, Self::Error> {
- Ok(vec![self.tcx.original_crate_name(cnum)])
+ Ok(vec![self.tcx.crate_name(cnum)])
}
fn path_qualified(
self.sets.lint_cap = sess.opts.lint_cap.unwrap_or(Level::Forbid);
for &(ref lint_name, level) in &sess.opts.lint_opts {
- store.check_lint_name_cmdline(sess, &lint_name, level);
+ store.check_lint_name_cmdline(sess, &lint_name, Some(level));
let orig_level = level;
// If the cap is less than this specified level, e.g., if we've got
}
}
+ for lint_name in &sess.opts.force_warns {
+ let valid = store.check_lint_name_cmdline(sess, lint_name, None);
+ if valid {
+ let lints = store
+ .find_lints(lint_name)
+ .unwrap_or_else(|_| bug!("A valid lint failed to produce a lint ids"));
+ self.sets.force_warns.extend(&lints);
+ }
+ }
+
self.sets.list.push(LintSet::CommandLine { specs });
}
LintLevelSource::Default => false,
LintLevelSource::Node(symbol, _, _) => self.store.is_lint_group(symbol),
LintLevelSource::CommandLine(symbol, _) => self.store.is_lint_group(symbol),
+ LintLevelSource::ForceWarn(_symbol) => {
+ bug!("forced warn lint returned a forbid lint level")
+ }
};
debug!(
"fcw_warning={:?}, specs.get(&id) = {:?}, old_src={:?}, id_name={:?}",
LintLevelSource::CommandLine(_, _) => {
diag_builder.note("`forbid` lint level was set on command line");
}
+ _ => bug!("forced warn lint returned a forbid lint level"),
}
diag_builder.emit();
};
#![feature(iter_zip)]
#![feature(never_type)]
#![feature(nll)]
-#![feature(half_open_range_patterns)]
-#![feature(exclusive_range_pattern)]
#![feature(control_flow_enum)]
#![recursion_limit = "256"]
| ast::ItemKind::Struct(..)
| ast::ItemKind::Union(..) => self.check_case(cx, "type", &it.ident),
ast::ItemKind::Trait(..) => self.check_case(cx, "trait", &it.ident),
+ ast::ItemKind::TraitAlias(..) => self.check_case(cx, "trait alias", &it.ident),
_ => (),
}
}
use rustc_errors::Applicability;
use rustc_hir as hir;
use rustc_hir::{is_range_literal, ExprKind, Node};
-use rustc_index::vec::Idx;
use rustc_middle::ty::layout::{IntegerExt, SizeSkeleton};
use rustc_middle::ty::subst::SubstsRef;
use rustc_middle::ty::{self, AdtKind, Ty, TyCtxt, TypeFoldable};
use rustc_span::symbol::sym;
use rustc_span::{Span, DUMMY_SP};
use rustc_target::abi::Abi;
-use rustc_target::abi::{Integer, LayoutOf, TagEncoding, VariantIdx, Variants};
+use rustc_target::abi::{Integer, LayoutOf, TagEncoding, Variants};
use rustc_target::spec::abi::Abi as SpecAbi;
use std::cmp;
variant: &'a ty::VariantDef,
) -> Option<&'a ty::FieldDef> {
let param_env = tcx.param_env(variant.def_id);
- for field in &variant.fields {
+ variant.fields.iter().find(|field| {
let field_ty = tcx.type_of(field.did);
let is_zst = tcx.layout_of(param_env.and(field_ty)).map_or(false, |layout| layout.is_zst());
-
- if !is_zst {
- return Some(field);
- }
- }
-
- None
+ !is_zst
+ })
}
/// Is type known to be non-null?
return false;
}
- for variant in &def.variants {
- if let Some(field) = transparent_newtype_field(cx.tcx, variant) {
- if ty_is_known_nonnull(cx, field.ty(tcx, substs), mode) {
- return true;
- }
- }
- }
-
- false
+ def.variants
+ .iter()
+ .filter_map(|variant| transparent_newtype_field(cx.tcx, variant))
+ .any(|field| ty_is_known_nonnull(cx, field.ty(tcx, substs), mode))
}
_ => false,
}
) -> Option<Ty<'tcx>> {
debug!("is_repr_nullable_ptr(cx, ty = {:?})", ty);
if let ty::Adt(ty_def, substs) = ty.kind() {
- if ty_def.variants.len() != 2 {
- return None;
- }
-
- let get_variant_fields = |index| &ty_def.variants[VariantIdx::new(index)].fields;
- let variant_fields = [get_variant_fields(0), get_variant_fields(1)];
- let fields = if variant_fields[0].is_empty() {
- &variant_fields[1]
- } else if variant_fields[1].is_empty() {
- &variant_fields[0]
- } else {
- return None;
+ let field_ty = match &ty_def.variants.raw[..] {
+ [var_one, var_two] => match (&var_one.fields[..], &var_two.fields[..]) {
+ ([], [field]) | ([field], []) => field.ty(cx.tcx, substs),
+ _ => return None,
+ },
+ _ => return None,
};
- if fields.len() != 1 {
- return None;
- }
-
- let field_ty = fields[0].ty(cx.tcx, substs);
if !ty_is_known_nonnull(cx, field_ty, ckind) {
return None;
}
}
match *ty.kind() {
- ty::Adt(def, _) if def.is_box() && matches!(self.mode, CItemKind::Definition) => {
- FfiSafe
- }
-
ty::Adt(def, substs) => {
+ if def.is_box() && matches!(self.mode, CItemKind::Definition) {
+ if ty.boxed_ty().is_sized(tcx.at(DUMMY_SP), self.cx.param_env) {
+ return FfiSafe;
+ } else {
+ return FfiUnsafe {
+ ty,
+ reason: format!("box cannot be represented as a single pointer"),
+ help: None,
+ };
+ }
+ }
if def.is_phantom_data() {
return FfiPhantom(ty);
}
// The other cases do not contain sub-patterns.
| Wild | Rest | Lit(..) | MacCall(..) | Range(..) | Ident(.., None) | Path(..) => {},
// These are list-like patterns; parens can always be removed.
- TupleStruct(_, ps) | Tuple(ps) | Slice(ps) | Or(ps) => for p in ps {
+ TupleStruct(_, _, ps) | Tuple(ps) | Slice(ps) | Or(ps) => for p in ps {
self.check_unused_parens_pat(cx, p, false, false);
},
- Struct(_, fps, _) => for f in fps {
+ Struct(_, _, fps, _) => for f in fps {
self.check_unused_parens_pat(cx, &f.pat, false, false);
},
// Avoid linting on `i @ (p0 | .. | pn)` and `box (p0 | .. | pn)`, #64106.
USELESS_DEPRECATED,
UNSUPPORTED_NAKED_FUNCTIONS,
MISSING_ABI,
+ INVALID_DOC_ATTRIBUTES,
SEMICOLON_IN_EXPRESSIONS_FROM_MACROS,
DISJOINT_CAPTURE_MIGRATION,
LEGACY_DERIVE_HELPERS,
/// before applying the suggestion.
#[derive(Copy, Clone, Debug, PartialEq, Hash, Encodable, Decodable)]
pub enum Applicability {
- /// The suggestion is definitely what the user intended. This suggestion should be
+ /// The suggestion is definitely what the user intended, or maintains the exact meaning of the code.
+ /// This suggestion should be automatically applied.
+ ///
+ /// In case of multiple `MachineApplicable` suggestions (whether as part of
+ /// the same `multipart_suggestion` or not), all of them should be
/// automatically applied.
MachineApplicable,
[build-dependencies]
build_helper = { path = "../../src/build_helper" }
-cc = "1.0.67"
+cc = "1.0.68"
"nvptx",
"hexagon",
"riscv",
+ "bpf",
];
let required_components = &[
#include "llvm/IR/Instructions.h"
#include "llvm/IR/Intrinsics.h"
#include "llvm/Object/Archive.h"
+#include "llvm/Object/COFFImportFile.h"
#include "llvm/Object/ObjectFile.h"
#include "llvm/Bitcode/BitcodeWriterPass.h"
#include "llvm/Support/Signals.h"
install_fatal_error_handler(FatalErrorHandler);
}
-extern "C" LLVMMemoryBufferRef
-LLVMRustCreateMemoryBufferWithContentsOfFile(const char *Path) {
- ErrorOr<std::unique_ptr<MemoryBuffer>> BufOr =
- MemoryBuffer::getFile(Path, -1, false);
- if (!BufOr) {
- LLVMRustSetLastError(BufOr.getError().message().c_str());
- return nullptr;
- }
- return wrap(BufOr.get().release());
-}
-
extern "C" char *LLVMRustGetLastError(void) {
char *Ret = LastError;
LastError = nullptr;
}
}
-// Note that the two following functions look quite similar to the
-// LLVMGetSectionName function. Sadly, it appears that this function only
-// returns a char* pointer, which isn't guaranteed to be null-terminated. The
-// function provided by LLVM doesn't return the length, so we've created our own
-// function which returns the length as well as the data pointer.
-//
-// For an example of this not returning a null terminated string, see
-// lib/Object/COFFObjectFile.cpp in the getSectionName function. One of the
-// branches explicitly creates a StringRef without a null terminator, and then
-// that's returned.
-
-inline section_iterator *unwrap(LLVMSectionIteratorRef SI) {
- return reinterpret_cast<section_iterator *>(SI);
-}
-
-extern "C" size_t LLVMRustGetSectionName(LLVMSectionIteratorRef SI,
- const char **Ptr) {
- auto NameOrErr = (*unwrap(SI))->getName();
- if (!NameOrErr)
- report_fatal_error(NameOrErr.takeError());
- *Ptr = NameOrErr->data();
- return NameOrErr->size();
-}
-
// LLVMArrayType function does not support 64-bit ElementCount
extern "C" LLVMTypeRef LLVMRustArrayType(LLVMTypeRef ElementTy,
uint64_t ElementCount) {
LLVMRustBuildMaxNum(LLVMBuilderRef B, LLVMValueRef LHS, LLVMValueRef RHS) {
return wrap(unwrap(B)->CreateMaxNum(unwrap(LHS),unwrap(RHS)));
}
+
+// This struct contains all necessary info about a symbol exported from a DLL.
+// At the moment, it's just the symbol's name, but we use a separate struct to
+// make it easier to add other information like ordinal later.
+struct LLVMRustCOFFShortExport {
+ const char* name;
+};
+
+// Machine must be a COFF machine type, as defined in PE specs.
+extern "C" LLVMRustResult LLVMRustWriteImportLibrary(
+ const char* ImportName,
+ const char* Path,
+ const LLVMRustCOFFShortExport* Exports,
+ size_t NumExports,
+ uint16_t Machine,
+ bool MinGW)
+{
+ std::vector<llvm::object::COFFShortExport> ConvertedExports;
+ ConvertedExports.reserve(NumExports);
+
+ for (size_t i = 0; i < NumExports; ++i) {
+ ConvertedExports.push_back(llvm::object::COFFShortExport{
+ Exports[i].name, // Name
+ std::string{}, // ExtName
+ std::string{}, // SymbolName
+ std::string{}, // AliasTarget
+ 0, // Ordinal
+ false, // Noname
+ false, // Data
+ false, // Private
+ false // Constant
+ });
+ }
+
+ auto Error = llvm::object::writeImportLibrary(
+ ImportName,
+ Path,
+ ConvertedExports,
+ static_cast<llvm::COFF::MachineTypes>(Machine),
+ MinGW);
+ if (Error) {
+ std::string errorString;
+ llvm::raw_string_ostream stream(errorString);
+ stream << Error;
+ stream.flush();
+ LLVMRustSetLastError(errorString.c_str());
+ return LLVMRustResult::Failure;
+ } else {
+ return LLVMRustResult::Success;
+ }
+}
LLVMInitializeWebAssemblyAsmPrinter,
LLVMInitializeWebAssemblyAsmParser
);
+ init_target!(
+ llvm_component = "bpf",
+ LLVMInitializeBPFTargetInfo,
+ LLVMInitializeBPFTarget,
+ LLVMInitializeBPFTargetMC,
+ LLVMInitializeBPFAsmPrinter,
+ LLVMInitializeBPFAsmParser
+ );
}
let decode_body = match s.variants() {
[vi] => {
let construct = vi.construct(|field, index| decode_field(field, index, true));
- let n_fields = vi.ast().fields.len();
quote! {
::rustc_serialize::Decoder::read_struct(
__decoder,
- #ty_name,
- #n_fields,
|__decoder| { ::std::result::Result::Ok(#construct) },
)
}
quote! {
::rustc_serialize::Decoder::read_enum(
__decoder,
- #ty_name,
|__decoder| {
::rustc_serialize::Decoder::read_enum_variant(
__decoder,
quote! {
match ::rustc_serialize::Decoder::#decode_method(
- __decoder, #opt_field_name #index, #decode_inner_method) {
+ __decoder, #opt_field_name #decode_inner_method) {
::std::result::Result::Ok(__res) => __res,
::std::result::Result::Err(__err) => return ::std::result::Result::Err(__err),
}
}
});
- let ty_name = s.ast().ident.to_string();
let encode_body = match s.variants() {
[_] => {
let mut field_idx = 0usize;
.ident
.as_ref()
.map_or_else(|| field_idx.to_string(), |i| i.to_string());
+ let first = field_idx == 0;
let result = quote! {
match ::rustc_serialize::Encoder::emit_struct_field(
__encoder,
#field_name,
- #field_idx,
+ #first,
|__encoder|
::rustc_serialize::Encodable::<#encoder_ty>::encode(#bind_ident, __encoder),
) {
})
.collect::<TokenStream>()
});
+ let no_fields = field_idx == 0;
quote! {
- ::rustc_serialize::Encoder::emit_struct(__encoder, #ty_name, #field_idx, |__encoder| {
+ ::rustc_serialize::Encoder::emit_struct(__encoder, #no_fields, |__encoder| {
::std::result::Result::Ok(match *self { #encode_inner })
})
}
.iter()
.map(|binding| {
let bind_ident = &binding.binding;
+ let first = field_idx == 0;
let result = quote! {
match ::rustc_serialize::Encoder::emit_enum_variant_arg(
__encoder,
- #field_idx,
+ #first,
|__encoder|
::rustc_serialize::Encodable::<#encoder_ty>::encode(#bind_ident, __encoder),
) {
result
});
quote! {
- ::rustc_serialize::Encoder::emit_enum(__encoder, #ty_name, |__encoder| {
+ ::rustc_serialize::Encoder::emit_enum(__encoder, |__encoder| {
match *self {
#encode_inner
}
pub struct CrateLoader<'a> {
// Immutable configuration.
sess: &'a Session,
- metadata_loader: &'a MetadataLoaderDyn,
+ metadata_loader: Box<MetadataLoaderDyn>,
local_crate_name: Symbol,
// Mutable output.
cstore: CStore,
impl<'a> CrateLoader<'a> {
pub fn new(
sess: &'a Session,
- metadata_loader: &'a MetadataLoaderDyn,
+ metadata_loader: Box<MetadataLoaderDyn>,
local_crate_name: &str,
) -> Self {
let local_crate_stable_id =
info!("falling back to a load");
let mut locator = CrateLocator::new(
self.sess,
- self.metadata_loader,
+ &*self.metadata_loader,
name,
hash,
host_hash,
#![doc(html_root_url = "https://doc.rust-lang.org/nightly/nightly-rustc/")]
-#![feature(core_intrinsics)]
#![feature(crate_visibility_modifier)]
#![feature(drain_filter)]
#![feature(in_band_lifetimes)]
#![feature(once_cell)]
#![feature(proc_macro_internals)]
#![feature(min_specialization)]
-#![feature(stmt_expr_attributes)]
#![feature(try_blocks)]
#![feature(never_type)]
#![recursion_limit = "256"]
pub mod creader;
pub mod dynamic_lib;
pub mod locator;
+
+pub use rmeta::METADATA_HEADER;
use rustc_errors::struct_span_err;
use rustc_hir as hir;
use rustc_hir::itemlikevisit::ItemLikeVisitor;
-use rustc_middle::middle::cstore::NativeLib;
+use rustc_middle::middle::cstore::{DllImport, NativeLib};
use rustc_middle::ty::TyCtxt;
use rustc_session::parse::feature_err;
use rustc_session::utils::NativeLibKind;
impl ItemLikeVisitor<'tcx> for Collector<'tcx> {
fn visit_item(&mut self, it: &'tcx hir::Item<'tcx>) {
- let abi = match it.kind {
- hir::ItemKind::ForeignMod { abi, .. } => abi,
+ let (abi, foreign_mod_items) = match it.kind {
+ hir::ItemKind::ForeignMod { abi, items } => (abi, items),
_ => return,
};
foreign_module: Some(it.def_id.to_def_id()),
wasm_import_module: None,
verbatim: None,
+ dll_imports: Vec::new(),
};
let mut kind_specified = false;
.span_label(m.span, "missing `name` argument")
.emit();
}
+
+ if lib.kind == NativeLibKind::RawDylib {
+ match abi {
+ Abi::C { .. } => (),
+ Abi::Cdecl => (),
+ _ => {
+ if sess.target.arch == "x86" {
+ sess.span_fatal(
+ it.span,
+ r#"`#[link(kind = "raw-dylib")]` only supports C and Cdecl ABIs"#,
+ );
+ }
+ }
+ };
+ lib.dll_imports.extend(
+ foreign_mod_items
+ .iter()
+ .map(|child_item| DllImport { name: child_item.ident.name, ordinal: None }),
+ );
+ }
+
self.register_native_lib(Some(m.span), lib);
}
}
)
.emit();
}
- if lib.kind == NativeLibKind::RawDylib && !self.tcx.features().raw_dylib {
- feature_err(
- &self.tcx.sess.parse_sess,
- sym::raw_dylib,
- span.unwrap_or(rustc_span::DUMMY_SP),
- "kind=\"raw-dylib\" is unstable",
- )
- .emit();
+ // this just unwraps lib.name; we already established that it isn't empty above.
+ if let (NativeLibKind::RawDylib, Some(lib_name)) = (lib.kind, lib.name) {
+ let span = match span {
+ Some(s) => s,
+ None => {
+ bug!("raw-dylib libraries are not supported on the command line");
+ }
+ };
+
+ if !self.tcx.sess.target.options.is_like_windows {
+ self.tcx.sess.span_fatal(
+ span,
+ "`#[link(...)]` with `kind = \"raw-dylib\"` only supported on Windows",
+ );
+ } else if !self.tcx.sess.target.options.is_like_msvc {
+ self.tcx.sess.span_warn(
+ span,
+ "`#[link(...)]` with `kind = \"raw-dylib\"` not supported on windows-gnu",
+ );
+ }
+
+ if lib_name.as_str().contains('\0') {
+ self.tcx.sess.span_err(span, "library name may not contain NUL characters");
+ }
+
+ if !self.tcx.features().raw_dylib {
+ feature_err(
+ &self.tcx.sess.parse_sess,
+ sym::raw_dylib,
+ span,
+ "kind=\"raw-dylib\" is unstable",
+ )
+ .emit();
+ }
}
+
self.libs.push(lib);
}
foreign_module: None,
wasm_import_module: None,
verbatim: passed_lib.verbatim,
+ dll_imports: Vec::new(),
};
self.register_native_lib(None, lib);
} else {
self.cdata.expect("missing CrateMetadata in DecodeContext")
}
+ fn map_encoded_cnum_to_current(&self, cnum: CrateNum) -> CrateNum {
+ if cnum == LOCAL_CRATE { self.cdata().cnum } else { self.cdata().cnum_map[cnum] }
+ }
+
fn read_lazy_with_meta<T: ?Sized + LazyMeta>(
&mut self,
meta: T::Meta,
{
let tcx = self.tcx();
- let key = ty::CReaderCacheKey { cnum: self.cdata().cnum, pos: shorthand };
+ let key = ty::CReaderCacheKey { cnum: Some(self.cdata().cnum), pos: shorthand };
if let Some(&ty) = tcx.ty_rcache.borrow().get(&key) {
return Ok(ty);
r
}
- fn map_encoded_cnum_to_current(&self, cnum: CrateNum) -> CrateNum {
- if cnum == LOCAL_CRATE { self.cdata().cnum } else { self.cdata().cnum_map[cnum] }
- }
-
fn decode_alloc_id(&mut self) -> Result<rustc_middle::mir::interpret::AllocId, Self::Error> {
if let Some(alloc_decoding_session) = self.alloc_decoding_session {
alloc_decoding_session.decode_alloc_id(self)
self.root.hash
}
+ fn num_def_ids(&self) -> usize {
+ self.root.tables.def_keys.size()
+ }
+
fn local_def_id(&self, index: DefIndex) -> DefId {
DefId { krate: self.cnum, index }
}
use crate::creader::{CStore, LoadedMacro};
use crate::foreign_modules;
use crate::native_libs;
-use crate::rmeta::{self, encoder};
+use crate::rmeta::encoder;
use rustc_ast as ast;
use rustc_ast::expand::allocator::AllocatorKind;
is_ctfe_mir_available => { cdata.is_ctfe_mir_available(def_id.index) }
dylib_dependency_formats => { cdata.get_dylib_dependency_formats(tcx) }
+ is_private_dep => { cdata.private_dep }
is_panic_runtime => { cdata.root.panic_runtime }
is_compiler_builtins => { cdata.root.compiler_builtins }
has_global_allocator => { cdata.root.has_global_allocator }
crate_disambiguator => { cdata.root.disambiguator }
crate_hash => { cdata.root.hash }
crate_host_hash => { cdata.host_hash }
- original_crate_name => { cdata.root.name }
+ crate_name => { cdata.root.name }
extra_filename => { cdata.root.extra_filename.clone() }
let r = *cdata.dep_kind.lock();
r
}
- crate_name => { cdata.root.name }
item_children => {
let mut result = SmallVec::<[_; 8]>::new();
cdata.each_child_of_item(def_id.index, |child| result.push(child), tcx.sess);
is_statically_included_foreign_item: |tcx, id| {
matches!(tcx.native_library_kind(id), Some(NativeLibKind::Static { .. }))
},
+ is_private_dep: |_tcx, cnum| {
+ assert_eq!(cnum, LOCAL_CRATE);
+ false
+ },
native_library_kind: |tcx, id| {
tcx.native_libraries(id.krate)
.iter()
self.get_crate_data(def_id.krate).module_expansion(def_id.index, sess)
}
+ /// Only public-facing way to traverse all the definitions in a non-local crate.
+ /// Critically useful for this third-party project: <https://github.com/hacspec/hacspec>.
+ /// See <https://github.com/rust-lang/rust/pull/85889> for context.
+ pub fn num_def_ids_untracked(&self, cnum: CrateNum) -> usize {
+ self.get_crate_data(cnum).num_def_ids()
+ }
+
pub fn item_attrs(&self, def_id: DefId, sess: &Session) -> Vec<ast::Attribute> {
self.get_crate_data(def_id.krate).get_item_attrs(def_id.index, sess).collect()
}
self.get_crate_data(cnum).root.name
}
- fn crate_is_private_dep_untracked(&self, cnum: CrateNum) -> bool {
- self.get_crate_data(cnum).private_dep
- }
-
fn crate_disambiguator_untracked(&self, cnum: CrateNum) -> CrateDisambiguator {
self.get_crate_data(cnum).root.disambiguator
}
encoder::encode_metadata(tcx)
}
- fn metadata_encoding_version(&self) -> &[u8] {
- rmeta::METADATA_HEADER
- }
-
fn allocator_kind(&self) -> Option<AllocatorKind> {
self.allocator_kind()
}
});
record!(self.tables.span[def_id] <- tcx.def_span(def_id));
record!(self.tables.attributes[def_id] <- tcx.get_attrs(def_id));
- record!(self.tables.expn_that_defined[def_id] <- self.tcx.expansion_that_defined(def_id));
+ record!(self.tables.expn_that_defined[def_id] <- self.tcx.expn_that_defined(def_id));
if should_encode_visibility(def_kind) {
record!(self.tables.visibility[def_id] <- self.tcx.visibility(def_id));
}
.iter()
.map(|&cnum| {
let dep = CrateDep {
- name: self.tcx.original_crate_name(cnum),
+ name: self.tcx.crate_name(cnum),
hash: self.tcx.crate_hash(cnum),
host_hash: self.tcx.crate_host_hash(cnum),
kind: self.tcx.dep_kind(cnum),
/// This header is followed by the position of the `CrateRoot`,
/// which is encoded as a 32-bit big-endian unsigned integer,
/// and further followed by the rustc version string.
-crate const METADATA_HEADER: &[u8; 8] = &[b'r', b'u', b's', b't', 0, 0, 0, METADATA_VERSION];
+pub const METADATA_HEADER: &[u8] = &[b'r', b'u', b's', b't', 0, 0, 0, METADATA_VERSION];
/// Additional metadata for a `Lazy<T>` where `T` may not be `Sized`,
/// e.g. for `Lazy<[T]>`, this is the length (count of `T` values).
// required that their size stay the same, but we don't want to change
// it inadvertently. This assert just ensures we're aware of any change.
#[cfg(any(target_arch = "x86", target_arch = "x86_64"))]
-static_assert_size!(DepNode, 18);
+static_assert_size!(DepNode, 17);
#[cfg(not(any(target_arch = "x86", target_arch = "x86_64")))]
static_assert_size!(DepNode, 24);
pub type DepGraph = rustc_query_system::dep_graph::DepGraph<DepKind>;
pub type TaskDeps = rustc_query_system::dep_graph::TaskDeps<DepKind>;
pub type DepGraphQuery = rustc_query_system::dep_graph::DepGraphQuery<DepKind>;
-pub type PreviousDepGraph = rustc_query_system::dep_graph::PreviousDepGraph<DepKind>;
pub type SerializedDepGraph = rustc_query_system::dep_graph::SerializedDepGraph<DepKind>;
pub type EdgeFilter = rustc_query_system::dep_graph::debug::EdgeFilter<DepKind>;
use crate::arena::Arena;
-use crate::hir::map::{HirOwnerData, Map};
-use crate::hir::{IndexedHir, Owner, OwnerNodes, ParentedNode};
+use crate::hir::map::Map;
+use crate::hir::{IndexedHir, OwnerNodes, ParentedNode};
use crate::ich::StableHashingContext;
use rustc_data_structures::fingerprint::Fingerprint;
use rustc_data_structures::fx::FxHashMap;
/// Source map
source_map: &'a SourceMap,
- map: IndexVec<LocalDefId, HirOwnerData<'hir>>,
+ map: IndexVec<LocalDefId, Option<&'hir mut OwnerNodes<'hir>>>,
parenting: FxHashMap<LocalDefId, HirId>,
/// The parent of this node
current_dep_node_owner: LocalDefId { local_def_index: CRATE_DEF_INDEX },
definitions,
hcx,
- map: (0..definitions.def_index_count())
- .map(|_| HirOwnerData { signature: None, with_bodies: None })
- .collect(),
+ map: IndexVec::from_fn_n(|_| None, definitions.def_index_count()),
parenting: FxHashMap::default(),
};
collector.insert_entry(
pub(super) fn finalize_and_compute_crate_hash(mut self) -> IndexedHir<'hir> {
// Insert bodies into the map
for (id, body) in self.krate.bodies.iter() {
- let bodies = &mut self.map[id.hir_id.owner].with_bodies.as_mut().unwrap().bodies;
+ let bodies = &mut self.map[id.hir_id.owner].as_mut().unwrap().bodies;
assert!(bodies.insert(id.hir_id.local_id, body).is_none());
}
IndexedHir { map: self.map, parenting: self.parenting }
let data = &mut self.map[id.owner];
- if data.with_bodies.is_none() {
- data.with_bodies = Some(arena.alloc(OwnerNodes {
+ if i == 0 {
+ debug_assert!(data.is_none());
+ *data = Some(arena.alloc(OwnerNodes {
hash,
nodes: IndexVec::new(),
bodies: FxHashMap::default(),
}));
- }
-
- let nodes = data.with_bodies.as_mut().unwrap();
-
- if i == 0 {
- // Overwrite the dummy hash with the real HIR owner hash.
- nodes.hash = hash;
-
- debug_assert!(data.signature.is_none());
- data.signature = Some(self.arena.alloc(Owner { node: entry.node }));
let dk_parent = self.definitions.def_key(id.owner).parent;
if let Some(dk_parent) = dk_parent {
debug_assert_eq!(self.parenting.get(&id.owner), Some(&entry.parent));
}
} else {
- assert_eq!(entry.parent.owner, id.owner);
- insert_vec_map(
- &mut nodes.nodes,
- id.local_id,
- ParentedNode { parent: entry.parent.local_id, node: entry.node },
- );
+ debug_assert_eq!(entry.parent.owner, id.owner);
}
+
+ let data = data.as_mut().unwrap();
+
+ insert_vec_map(
+ &mut data.nodes,
+ id.local_id,
+ ParentedNode { parent: entry.parent.local_id, node: entry.node },
+ );
}
fn insert(&mut self, span: Span, hir_id: HirId, node: Node<'hir>) {
use self::collector::NodeCollector;
-use crate::hir::{AttributeMap, HirOwnerData, IndexedHir};
+use crate::hir::{AttributeMap, IndexedHir};
use crate::middle::cstore::CrateStore;
use crate::ty::TyCtxt;
use rustc_ast as ast;
.filter_map(|(def_id, hod)| {
let def_path_hash = tcx.definitions.def_path_hash(def_id);
let mut hasher = StableHasher::new();
- hod.with_bodies.as_ref()?.hash_stable(&mut hcx, &mut hasher);
+ hod.as_ref()?.hash_stable(&mut hcx, &mut hasher);
AttributeMap { map: &tcx.untracked_crate.attrs, prefix: def_id }
.hash_stable(&mut hcx, &mut hasher);
Some((def_path_hash, hasher.finish()))
use rustc_data_structures::stable_hasher::{HashStable, StableHasher};
use rustc_hir::def_id::LocalDefId;
use rustc_hir::*;
-use rustc_index::vec::IndexVec;
+use rustc_index::vec::{Idx, IndexVec};
use rustc_span::DUMMY_SP;
use std::collections::BTreeMap;
-#[derive(Debug)]
-struct HirOwnerData<'hir> {
- signature: Option<&'hir Owner<'hir>>,
- with_bodies: Option<&'hir mut OwnerNodes<'hir>>,
-}
-
+/// Result of HIR indexing.
#[derive(Debug)]
pub struct IndexedHir<'hir> {
- map: IndexVec<LocalDefId, HirOwnerData<'hir>>,
+ /// Contents of the HIR owned by each definition. None for definitions that are not HIR owners.
+ // The `mut` comes from construction time, and is harmless since we only ever hand out
+ // immutable refs to IndexedHir.
+ map: IndexVec<LocalDefId, Option<&'hir mut OwnerNodes<'hir>>>,
+ /// Map from each owner to its parent's HirId inside another owner.
+ // This map is separate from `map` to eventually allow for per-owner indexing.
parenting: FxHashMap<LocalDefId, HirId>,
}
-#[derive(Debug)]
+/// Top-level HIR node for current owner. This only contains the node for which
+/// `HirId::local_id == 0`, and excludes bodies.
+#[derive(Copy, Clone, Debug)]
pub struct Owner<'tcx> {
node: Node<'tcx>,
}
}
}
+/// HIR node coupled with its parent's id in the same HIR owner.
+///
+/// The parent is trash when the node is a HIR owner.
#[derive(Clone, Debug)]
pub struct ParentedNode<'tcx> {
parent: ItemLocalId,
#[derive(Debug)]
pub struct OwnerNodes<'tcx> {
+ /// Pre-computed hash of the full HIR.
hash: Fingerprint,
+ /// Full HIR for the current owner.
+ // The zeroth node's parent is trash, but is never accessed.
nodes: IndexVec<ItemLocalId, Option<ParentedNode<'tcx>>>,
+ /// Content of local bodies.
bodies: FxHashMap<ItemLocalId, &'tcx Body<'tcx>>,
}
}
}
+/// Attributes owner by a HIR owner. It is build as a slice inside the attributes map, restricted
+/// to the nodes whose `HirId::owner` is `prefix`.
#[derive(Copy, Clone)]
pub struct AttributeMap<'tcx> {
map: &'tcx BTreeMap<HirId, &'tcx [Attribute]>,
providers.index_hir = map::index_hir;
providers.crate_hash = map::crate_hash;
providers.hir_module_items = |tcx, id| &tcx.untracked_crate.modules[&id];
- providers.hir_owner = |tcx, id| tcx.index_hir(()).map[id].signature;
- providers.hir_owner_nodes = |tcx, id| tcx.index_hir(()).map[id].with_bodies.as_deref();
+ providers.hir_owner = |tcx, id| {
+ let owner = tcx.index_hir(()).map[id].as_ref()?;
+ let node = owner.nodes[ItemLocalId::new(0)].as_ref()?.node;
+ Some(Owner { node })
+ };
+ providers.hir_owner_nodes = |tcx, id| tcx.index_hir(()).map[id].as_deref();
providers.hir_owner_parent = |tcx, id| {
let index = tcx.index_hir(());
index.parenting.get(&id).copied().unwrap_or(CRATE_HIR_ID)
};
providers.opt_def_kind = |tcx, def_id| tcx.hir().opt_def_kind(def_id.expect_local());
providers.all_local_trait_impls = |tcx, ()| &tcx.hir_crate(()).trait_impls;
+ providers.expn_that_defined = |tcx, id| {
+ let id = id.expect_local();
+ tcx.definitions.expansion_that_defined(id)
+ };
}
use rustc_span::symbol::Symbol;
use rustc_span::{BytePos, CachingSourceMapView, SourceFile, SpanData};
-use rustc_span::def_id::{CrateNum, CRATE_DEF_INDEX};
use smallvec::SmallVec;
use std::cmp::Ord;
use std::thread::LocalKey;
}
#[inline]
- fn hash_crate_num(&mut self, cnum: CrateNum, hasher: &mut StableHasher) {
- let hcx = self;
- hcx.def_path_hash(DefId { krate: cnum, index: CRATE_DEF_INDEX }).hash_stable(hcx, hasher);
- }
-
- #[inline]
- fn hash_def_id(&mut self, def_id: DefId, hasher: &mut StableHasher) {
- let hcx = self;
- hcx.def_path_hash(def_id).hash_stable(hcx, hasher);
+ fn def_path_hash(&self, def_id: DefId) -> DefPathHash {
+ self.def_path_hash(def_id)
}
fn expn_id_cache() -> &'static LocalKey<rustc_span::ExpnIdCache> {
use rustc_data_structures::fingerprint::Fingerprint;
use rustc_data_structures::stable_hasher::{HashStable, StableHasher, ToStableHashKey};
use rustc_hir as hir;
-use rustc_hir::def_id::{CrateNum, DefId, LocalDefId, CRATE_DEF_INDEX};
use rustc_hir::definitions::DefPathHash;
use smallvec::SmallVec;
use std::mem;
self.node_id_hashing_mode = prev_hash_node_ids;
}
-
- #[inline]
- fn local_def_path_hash(&self, def_id: LocalDefId) -> DefPathHash {
- self.local_def_path_hash(def_id)
- }
-}
-
-impl<'a> ToStableHashKey<StableHashingContext<'a>> for DefId {
- type KeyType = DefPathHash;
-
- #[inline]
- fn to_stable_hash_key(&self, hcx: &StableHashingContext<'a>) -> DefPathHash {
- hcx.def_path_hash(*self)
- }
-}
-
-impl<'a> HashStable<StableHashingContext<'a>> for LocalDefId {
- #[inline]
- fn hash_stable(&self, hcx: &mut StableHashingContext<'a>, hasher: &mut StableHasher) {
- hcx.def_path_hash(self.to_def_id()).hash_stable(hcx, hasher);
- }
-}
-
-impl<'a> ToStableHashKey<StableHashingContext<'a>> for LocalDefId {
- type KeyType = DefPathHash;
-
- #[inline]
- fn to_stable_hash_key(&self, hcx: &StableHashingContext<'a>) -> DefPathHash {
- hcx.def_path_hash(self.to_def_id())
- }
-}
-
-impl<'a> ToStableHashKey<StableHashingContext<'a>> for CrateNum {
- type KeyType = DefPathHash;
-
- #[inline]
- fn to_stable_hash_key(&self, hcx: &StableHashingContext<'a>) -> DefPathHash {
- let def_id = DefId { krate: *self, index: CRATE_DEF_INDEX };
- def_id.to_stable_hash_key(hcx)
- }
}
impl<'a> ToStableHashKey<StableHashingContext<'a>> for hir::ItemLocalId {
}
impl<'tcx> CanonicalVarValues<'tcx> {
+ #[inline]
pub fn len(&self) -> usize {
self.var_values.len()
}
#![feature(bool_to_option)]
#![feature(box_patterns)]
#![feature(box_syntax)]
-#![feature(const_panic)]
#![feature(core_intrinsics)]
#![feature(discriminant_kind)]
#![feature(never_type)]
use std::cmp;
use crate::ich::StableHashingContext;
-use rustc_data_structures::fx::FxHashMap;
+use rustc_data_structures::fx::{FxHashMap, FxHashSet};
use rustc_data_structures::stable_hasher::{HashStable, StableHasher};
use rustc_errors::{DiagnosticBuilder, DiagnosticId};
use rustc_hir::HirId;
/// The provided `Level` is the level specified on the command line.
/// (The actual level may be lower due to `--cap-lints`.)
CommandLine(Symbol, Level),
+
+ /// Lint is being forced to warn no matter what.
+ ForceWarn(Symbol),
}
impl LintLevelSource {
LintLevelSource::Default => symbol::kw::Default,
LintLevelSource::Node(name, _, _) => name,
LintLevelSource::CommandLine(name, _) => name,
+ LintLevelSource::ForceWarn(name) => name,
}
}
LintLevelSource::Default => DUMMY_SP,
LintLevelSource::Node(_, span, _) => span,
LintLevelSource::CommandLine(_, _) => DUMMY_SP,
+ LintLevelSource::ForceWarn(_) => DUMMY_SP,
}
}
}
pub struct LintLevelSets {
pub list: Vec<LintSet>,
pub lint_cap: Level,
+ pub force_warns: FxHashSet<LintId>,
}
#[derive(Debug)]
impl LintLevelSets {
pub fn new() -> Self {
- LintLevelSets { list: Vec::new(), lint_cap: Level::Forbid }
+ LintLevelSets {
+ list: Vec::new(),
+ lint_cap: Level::Forbid,
+ force_warns: FxHashSet::default(),
+ }
}
pub fn get_lint_level(
aux: Option<&FxHashMap<LintId, LevelAndSource>>,
sess: &Session,
) -> LevelAndSource {
+ // Check whether we should always warn
+ if self.force_warns.contains(&LintId::of(lint)) {
+ return (Level::Warn, LintLevelSource::ForceWarn(Symbol::intern(lint.name)));
+ }
+
let (level, mut src) = self.get_lint_id_level(LintId::of(lint), idx, aux);
// If `level` is none then we actually assume the default level for this
impl<'a> HashStable<StableHashingContext<'a>> for LintLevelMap {
#[inline]
fn hash_stable(&self, hcx: &mut StableHashingContext<'a>, hasher: &mut StableHasher) {
- let LintLevelMap { ref sets, ref id_to_set } = *self;
+ let LintLevelMap { ref sets, ref id_to_set, .. } = *self;
id_to_set.hash_stable(hcx, hasher);
- let LintLevelSets { ref list, lint_cap } = *sets;
+ let LintLevelSets { ref list, lint_cap, .. } = *sets;
lint_cap.hash_stable(hcx, hasher);
);
}
}
+ LintLevelSource::ForceWarn(_) => {
+ sess.diag_note_once(
+ &mut err,
+ DiagnosticMessageId::from(lint),
+ "warning forced by `force-warns` commandline option",
+ );
+ }
}
err.code(DiagnosticId::Lint { name, has_future_breakage });
pub foreign_module: Option<DefId>,
pub wasm_import_module: Option<Symbol>,
pub verbatim: Option<bool>,
+ pub dll_imports: Vec<DllImport>,
+}
+
+#[derive(Clone, Debug, Encodable, Decodable, HashStable)]
+pub struct DllImport {
+ pub name: Symbol,
+ pub ordinal: Option<u16>,
}
#[derive(Clone, TyEncodable, TyDecodable, HashStable, Debug)]
// "queries" used in resolve that aren't tracked for incremental compilation
fn crate_name_untracked(&self, cnum: CrateNum) -> Symbol;
- fn crate_is_private_dep_untracked(&self, cnum: CrateNum) -> bool;
fn crate_disambiguator_untracked(&self, cnum: CrateNum) -> CrateDisambiguator;
fn crate_hash_untracked(&self, cnum: CrateNum) -> Svh;
// utility functions
fn encode_metadata(&self, tcx: TyCtxt<'_>) -> EncodedMetadata;
- fn metadata_encoding_version(&self) -> &[u8];
fn allocator_kind(&self) -> Option<AllocatorKind>;
}
pub fn metadata_symbol_name(tcx: TyCtxt<'_>) -> String {
format!(
"rust_metadata_{}_{}",
- tcx.original_crate_name(LOCAL_CRATE),
+ tcx.crate_name(LOCAL_CRATE),
tcx.crate_disambiguator(LOCAL_CRATE).to_fingerprint().to_hex()
)
}
//! A subset of a mir body used for const evaluatability checking.
-use crate::mir;
-use crate::ty;
+use crate::mir::{self, CastKind};
+use crate::ty::{self, Ty};
rustc_index::newtype_index! {
/// An index into an `AbstractConst`.
Binop(mir::BinOp, NodeId, NodeId),
UnaryOp(mir::UnOp, NodeId),
FunctionCall(NodeId, &'tcx [NodeId]),
+ Cast(CastKind, NodeId, Ty<'tcx>),
}
#[derive(Debug, Copy, Clone, PartialEq, Eq, HashStable, TyEncodable, TyDecodable)]
/// Invalid metadata in a wide pointer (using `str` to avoid allocations).
InvalidMeta(&'static str),
/// Invalid drop function in vtable.
- InvalidDropFn(FnSig<'tcx>),
+ InvalidVtableDropFn(FnSig<'tcx>),
+ /// Invalid size in a vtable: too large.
+ InvalidVtableSize,
+ /// Invalid alignment in a vtable: too large, or not a power of 2.
+ InvalidVtableAlignment(String),
/// Reading a C string that does not end within its allocation.
UnterminatedCString(Pointer),
/// Dereferencing a dangling pointer after it got freed.
/// The value validity check found a problem.
/// Should only be thrown by `validity.rs` and always point out which part of the value
/// is the problem.
- ValidationFailure(String),
+ ValidationFailure {
+ /// The "path" to the value in question, e.g. `.0[5].field` for a struct
+ /// field in the 6th element of an array that is the first element of a tuple.
+ path: Option<String>,
+ msg: String,
+ },
/// Using a non-boolean `u8` as bool.
InvalidBool(u8),
/// Using a non-character `u32` as character.
RemainderByZero => write!(f, "calculating the remainder with a divisor of zero"),
PointerArithOverflow => write!(f, "overflowing in-bounds pointer arithmetic"),
InvalidMeta(msg) => write!(f, "invalid metadata in wide pointer: {}", msg),
- InvalidDropFn(sig) => write!(
+ InvalidVtableDropFn(sig) => write!(
f,
"invalid drop function signature: got {}, expected exactly one argument which must be a pointer type",
sig
),
+ InvalidVtableSize => {
+ write!(f, "invalid vtable: size is bigger than largest supported object")
+ }
+ InvalidVtableAlignment(msg) => write!(f, "invalid vtable: alignment {}", msg),
UnterminatedCString(p) => write!(
f,
"reading a null-terminated string starting at {} with no null found before end of allocation",
),
WriteToReadOnly(a) => write!(f, "writing to {} which is read-only", a),
DerefFunctionPointer(a) => write!(f, "accessing {} which contains a function", a),
- ValidationFailure(ref err) => write!(f, "type validation failed: {}", err),
+ ValidationFailure { path: None, msg } => write!(f, "type validation failed: {}", msg),
+ ValidationFailure { path: Some(path), msg } => {
+ write!(f, "type validation failed at {}: {}", path, msg)
+ }
InvalidBool(b) => {
write!(f, "interpreting an invalid 8-bit value as a bool: 0x{:02x}", b)
}
}
/// A trait for machine-specific errors (or other "machine stop" conditions).
-pub trait MachineStopType: AsAny + fmt::Display + Send {}
-impl MachineStopType for String {}
+pub trait MachineStopType: AsAny + fmt::Display + Send {
+ /// If `true`, emit a hard error instead of going through the `CONST_ERR` lint
+ fn is_hard_err(&self) -> bool {
+ false
+ }
+}
impl dyn MachineStopType {
#[inline(always)]
}
impl InterpError<'_> {
- /// Some errors to string formatting even if the error is never printed.
+ /// Some errors do string formatting even if the error is never printed.
/// To avoid performance issues, there are places where we want to be sure to never raise these formatting errors,
/// so this method lets us detect them and `bug!` on unexpected errors.
pub fn formatted_string(&self) -> bool {
match self {
InterpError::Unsupported(UnsupportedOpInfo::Unsupported(_))
- | InterpError::UndefinedBehavior(UndefinedBehaviorInfo::ValidationFailure(_))
+ | InterpError::UndefinedBehavior(UndefinedBehaviorInfo::ValidationFailure { .. })
| InterpError::UndefinedBehavior(UndefinedBehaviorInfo::Ub(_)) => true,
_ => false,
}
}
impl AllocDecodingState {
+ #[inline]
pub fn new_decoding_session(&self) -> AllocDecodingSession<'_> {
static DECODER_SESSION_ID: AtomicU32 = AtomicU32::new(0);
let counter = DECODER_SESSION_ID.fetch_add(1, Ordering::SeqCst);
///
/// Terminator may not be None after construction of the basic block is complete. This accessor
/// provides a convenience way to reach the terminator.
+ #[inline]
pub fn terminator(&self) -> &Terminator<'tcx> {
self.terminator.as_ref().expect("invalid terminator state")
}
+ #[inline]
pub fn terminator_mut(&mut self) -> &mut Terminator<'tcx> {
self.terminator.as_mut().expect("invalid terminator state")
}
/// If this place represents a local variable like `_X` with no
/// projections, return `Some(_X)`.
+ #[inline]
pub fn as_local(&self) -> Option<Local> {
match *self {
PlaceRef { local, projection: [] } => Some(local),
}
}
+ #[inline]
pub fn last_projection(&self) -> Option<(PlaceRef<'tcx>, PlaceElem<'tcx>)> {
if let &[ref proj_base @ .., elem] = self.projection {
Some((PlaceRef { local: self.local, projection: proj_base }, elem))
_ => None,
}
}
+ #[inline]
pub fn ty(&self) -> Ty<'tcx> {
self.literal.ty()
}
}
impl From<&'tcx ty::Const<'tcx>> for ConstantKind<'tcx> {
+ #[inline]
fn from(ct: &'tcx ty::Const<'tcx>) -> Self {
Self::Ty(ct)
}
pub fn codegen_dep_node(&self, tcx: TyCtxt<'tcx>) -> DepNode {
crate::dep_graph::make_compile_mono_item(tcx, self)
}
+
+ /// Returns the item's `CrateNum`
+ pub fn krate(&self) -> CrateNum {
+ match self {
+ MonoItem::Fn(ref instance) => instance.def_id().krate,
+ MonoItem::Static(def_id) => def_id.krate,
+ MonoItem::GlobalAsm(..) => LOCAL_CRATE,
+ }
+ }
}
impl<'a, 'tcx> HashStable<StableHashingContext<'a>> for MonoItem<'tcx> {
}
impl<'tcx> CodegenUnit<'tcx> {
+ #[inline]
pub fn new(name: Symbol) -> CodegenUnit<'tcx> {
CodegenUnit { name, items: Default::default(), size_estimate: None, primary: false }
}
self.size_estimate = Some(self.items.keys().map(|mi| mi.size_estimate(tcx)).sum());
}
+ #[inline]
pub fn size_estimate(&self) -> usize {
// Should only be called if `estimate_size` has previously been called.
self.size_estimate.expect("estimate_size must be called before getting a size_estimate")
use crate::mir::{abstract_const, Body, Promoted};
use crate::ty::{self, Ty, TyCtxt};
-use rustc_data_structures::fx::FxHashMap;
use rustc_data_structures::sync::Lrc;
+use rustc_data_structures::vec_map::VecMap;
use rustc_errors::ErrorReported;
use rustc_hir as hir;
use rustc_hir::def_id::{DefId, LocalDefId};
use rustc_index::bit_set::BitMatrix;
use rustc_index::vec::IndexVec;
+use rustc_middle::ty::OpaqueTypeKey;
use rustc_span::Span;
use rustc_target::abi::VariantIdx;
use smallvec::SmallVec;
/// All the opaque types that are restricted to concrete types
/// by this function. Unlike the value in `TypeckResults`, this has
/// unerased regions.
- pub concrete_opaque_types: FxHashMap<DefId, ty::ResolvedOpaqueTy<'tcx>>,
+ pub concrete_opaque_types: VecMap<OpaqueTypeKey<'tcx>, Ty<'tcx>>,
pub closure_requirements: Option<ClosureRegionRequirements<'tcx>>,
pub used_mut_upvars: SmallVec<[Field; 8]>,
}
///
/// This can be conveniently accessed by methods on `tcx.hir()`.
/// Avoid calling this query directly.
- query hir_owner(key: LocalDefId) -> Option<&'tcx crate::hir::Owner<'tcx>> {
+ query hir_owner(key: LocalDefId) -> Option<crate::hir::Owner<'tcx>> {
eval_always
desc { |tcx| "HIR owner of `{}`", tcx.def_path_str(key.to_def_id()) }
}
desc { |tcx| "elaborating item bounds for `{}`", tcx.def_path_str(key) }
}
- query projection_ty_from_predicates(key: (DefId, DefId)) -> Option<ty::ProjectionTy<'tcx>> {
- desc { |tcx| "finding projection type inside predicates of `{}`", tcx.def_path_str(key.0) }
- }
-
query native_libraries(_: CrateNum) -> Lrc<Vec<NativeLib>> {
desc { "looking up the native libraries of a linked crate" }
}
desc { |tcx| "parent module of `{}`", tcx.def_path_str(key.to_def_id()) }
}
- /// Internal helper query. Use `tcx.expansion_that_defined` instead
query expn_that_defined(key: DefId) -> rustc_span::ExpnId {
+ eval_always
desc { |tcx| "expansion that defined `{}`", tcx.def_path_str(key) }
}
/// Fetch the THIR for a given body. If typeck for that body failed, returns an empty `Thir`.
query thir_body(key: ty::WithOptConstParam<LocalDefId>) -> (&'tcx Steal<thir::Thir<'tcx>>, thir::ExprId) {
+ // Perf tests revealed that hashing THIR is inefficient (see #85729).
+ no_hash
desc { |tcx| "building THIR for `{}`", tcx.def_path_str(key.did.to_def_id()) }
}
desc { |tcx| "checking if item has mir available: `{}`", tcx.def_path_str(key) }
}
- query vtable_methods(key: ty::PolyTraitRef<'tcx>)
- -> &'tcx [Option<(DefId, SubstsRef<'tcx>)>] {
- desc { |tcx| "finding all methods for trait {}", tcx.def_path_str(key.def_id()) }
+ query vtable_entries(key: ty::PolyTraitRef<'tcx>)
+ -> &'tcx [ty::VtblEntry<'tcx>] {
+ desc { |tcx| "finding all vtable entries for trait {}", tcx.def_path_str(key.def_id()) }
}
query codegen_fulfill_obligation(
desc { "computing whether impls specialize one another" }
}
query in_scope_traits_map(_: LocalDefId)
- -> Option<&'tcx FxHashMap<ItemLocalId, StableVec<TraitCandidate>>> {
- eval_always
+ -> Option<&'tcx FxHashMap<ItemLocalId, Box<[TraitCandidate]>>> {
desc { "traits in scope at a block" }
}
eval_always
desc { "looking up the hash of a host version of a crate" }
}
- query original_crate_name(_: CrateNum) -> Symbol {
- eval_always
- desc { "looking up the original name a crate" }
- }
query extra_filename(_: CrateNum) -> String {
eval_always
desc { "looking up the extra filename for a crate" }
eval_always
desc { "generating a postorder list of CrateNums" }
}
+ /// Returns whether or not the crate with CrateNum 'cnum'
+ /// is marked as a private dependency
+ query is_private_dep(c: CrateNum) -> bool {
+ eval_always
+ desc { "check whether crate {} is a private dependency", c }
+ }
query upvars_mentioned(def_id: DefId) -> Option<&'tcx FxIndexMap<hir::HirId, hir::Upvar>> {
desc { |tcx| "collecting upvars mentioned in `{}`", tcx.def_path_str(def_id) }
pub safety_mode: BlockSafety,
}
+#[derive(Debug, HashStable)]
+pub struct Adt<'tcx> {
+ pub adt_def: &'tcx AdtDef,
+ pub variant_index: VariantIdx,
+ pub substs: SubstsRef<'tcx>,
+
+ /// Optional user-given substs: for something like `let x =
+ /// Bar::<T> { ... }`.
+ pub user_ty: Option<Canonical<'tcx, UserType<'tcx>>>,
+
+ pub fields: Box<[FieldExpr]>,
+ pub base: Option<FruInfo<'tcx>>,
+}
+
#[derive(Copy, Clone, Debug, HashStable)]
pub enum BlockSafety {
Safe,
// `Expr` is used a lot. Make sure it doesn't unintentionally get bigger.
#[cfg(all(target_arch = "x86_64", target_pointer_width = "64"))]
-rustc_data_structures::static_assert_size!(Expr<'_>, 144);
+rustc_data_structures::static_assert_size!(Expr<'_>, 104);
/// The Thir trait implementor lowers their expressions (`&'tcx H::Expr`)
/// into instances of this `Expr` enum. This lowering can be done
Tuple {
fields: Box<[ExprId]>,
},
- Adt {
- adt_def: &'tcx AdtDef,
- variant_index: VariantIdx,
- substs: SubstsRef<'tcx>,
-
- /// Optional user-given substs: for something like `let x =
- /// Bar::<T> { ... }`.
- user_ty: Option<Canonical<'tcx, UserType<'tcx>>>,
-
- fields: Box<[FieldExpr]>,
- base: Option<FruInfo<'tcx>>,
- },
+ Adt(Box<Adt<'tcx>>),
PlaceTypeAscription {
source: ExprId,
/// Type that the user gave to this expression
fn relate_with_variance<T: Relate<'tcx>>(
&mut self,
_: ty::Variance,
+ _: ty::VarianceDiagInfo<'tcx>,
a: T,
b: T,
) -> RelateResult<'tcx, T> {
/// 1. The simplest cases are where a pointer is not adjusted fat vs thin.
/// Here the pointer will be dereferenced N times (where a dereference can
/// happen to raw or borrowed pointers or any smart pointer which implements
-/// Deref, including Box<_>). The types of dereferences is given by
+/// `Deref`, including `Box<_>`). The types of dereferences is given by
/// `autoderefs`. It can then be auto-referenced zero or one times, indicated
/// by `autoref`, to either a raw or borrowed pointer. In these cases unsize is
/// `false`.
/// with a thin pointer, deref a number of times, unsize the underlying data,
/// then autoref. The 'unsize' phase may change a fixed length array to a
/// dynamically sized one, a concrete object to a trait object, or statically
-/// sized struct to a dynamically sized one. E.g., &[i32; 4] -> &[i32] is
+/// sized struct to a dynamically sized one. E.g., `&[i32; 4]` -> `&[i32]` is
/// represented by:
///
/// ```
/// ```
///
/// Note that for a struct, the 'deep' unsizing of the struct is not recorded.
-/// E.g., `struct Foo<T> { x: T }` we can coerce &Foo<[i32; 4]> to &Foo<[i32]>
+/// E.g., `struct Foo<T> { x: T }` we can coerce `&Foo<[i32; 4]>` to `&Foo<[i32]>`
/// The autoderef and -ref are the same as in the above example, but the type
/// stored in `unsize` is `Foo<[i32]>`, we don't store any further detail about
/// the underlying conversions from `[i32; 4]` to `[i32]`.
/// that case, we have the pointer we need coming in, so there are no
/// autoderefs, and no autoref. Instead we just do the `Unsize` transformation.
/// At some point, of course, `Box` should move out of the compiler, in which
-/// case this is analogous to transforming a struct. E.g., Box<[i32; 4]> ->
-/// Box<[i32]> is an `Adjust::Unsize` with the target `Box<[i32]>`.
+/// case this is analogous to transforming a struct. E.g., `Box<[i32; 4]>` ->
+/// `Box<[i32]>` is an `Adjust::Unsize` with the target `Box<[i32]>`.
#[derive(Clone, TyEncodable, TyDecodable, HashStable, TypeFoldable)]
pub struct Adjustment<'tcx> {
pub kind: Adjust<'tcx>,
use crate::hir::place::{
Place as HirPlace, PlaceBase as HirPlaceBase, ProjectionKind as HirProjectionKind,
};
-use crate::ty;
+use crate::{mir, ty};
use rustc_data_structures::fx::{FxHashMap, FxIndexMap};
use rustc_hir as hir;
use self::BorrowKind::*;
+// Captures are represented using fields inside a structure.
+// This represents accessing self in the closure structure
+pub const CAPTURE_STRUCT_LOCAL: mir::Local = mir::Local::from_u32(1);
+
#[derive(
Clone,
Copy,
use crate::ty::subst::SubstsRef;
use crate::ty::{self, List, Ty, TyCtxt};
use rustc_data_structures::fx::FxHashMap;
-use rustc_hir::def_id::{CrateNum, DefId};
+use rustc_hir::def_id::DefId;
use rustc_serialize::{Decodable, Decoder, Encodable, Encoder};
use rustc_span::Span;
use std::hash::Hash;
where
F: FnOnce(&mut Self) -> R;
- fn map_encoded_cnum_to_current(&self, cnum: CrateNum) -> CrateNum;
-
fn positioned_at_shorthand(&self) -> bool {
(self.peek_byte() & (SHORTHAND_OFFSET as u8)) != 0
}
use rustc_data_structures::fx::{FxHashMap, FxHashSet};
use rustc_data_structures::profiling::SelfProfilerRef;
use rustc_data_structures::sharded::{IntoPointer, ShardedHashMap};
-use rustc_data_structures::stable_hasher::{HashStable, StableHasher, StableVec};
+use rustc_data_structures::stable_hasher::{HashStable, StableHasher};
use rustc_data_structures::steal::Steal;
use rustc_data_structures::sync::{self, Lock, Lrc, WorkerLocal};
+use rustc_data_structures::vec_map::VecMap;
use rustc_errors::ErrorReported;
use rustc_hir as hir;
use rustc_hir::def::{DefKind, Res};
use rustc_index::vec::{Idx, IndexVec};
use rustc_macros::HashStable;
use rustc_middle::mir::FakeReadCause;
+use rustc_middle::ty::OpaqueTypeKey;
use rustc_serialize::opaque::{FileEncodeResult, FileEncoder};
use rustc_session::config::{BorrowckMode, CrateType, OutputFilenames};
use rustc_session::lint::{Level, Lint};
use rustc_session::Session;
+use rustc_span::def_id::StableCrateId;
use rustc_span::source_map::MultiSpan;
use rustc_span::symbol::{kw, sym, Ident, Symbol};
use rustc_span::{Span, DUMMY_SP};
}
}
-/// All information necessary to validate and reveal an `impl Trait`.
-#[derive(TyEncodable, TyDecodable, Debug, HashStable)]
-pub struct ResolvedOpaqueTy<'tcx> {
- /// The revealed type as seen by this function.
- pub concrete_type: Ty<'tcx>,
- /// Generic parameters on the opaque type as passed by this function.
- /// For `type Foo<A, B> = impl Bar<A, B>; fn foo<T, U>() -> Foo<T, U> { .. }`
- /// this is `[T, U]`, not `[A, B]`.
- pub substs: SubstsRef<'tcx>,
-}
-
/// Whenever a value may be live across a generator yield, the type of that value winds up in the
/// `GeneratorInteriorTypeCause` struct. This struct adds additional information about such
/// captured types that can be useful for diagnostics. In particular, it stores the span that
/// All the opaque types that are restricted to concrete types
/// by this function.
- pub concrete_opaque_types: FxHashMap<DefId, ResolvedOpaqueTy<'tcx>>,
+ pub concrete_opaque_types: VecMap<OpaqueTypeKey<'tcx>, Ty<'tcx>>,
/// Tracks the minimum captures required for a closure;
/// see `MinCaptureInformationMap` for more details.
/// Resolutions of `extern crate` items produced by resolver.
extern_crate_map: FxHashMap<LocalDefId, CrateNum>,
- /// Map indicating what traits are in scope for places where this
- /// is relevant; generated by resolve.
- trait_map: FxHashMap<LocalDefId, FxHashMap<ItemLocalId, StableVec<TraitCandidate>>>,
-
/// Export map produced by name resolution.
export_map: ExportMap<LocalDefId>,
/// The definite name of the current crate after taking into account
/// attributes, commandline parameters, etc.
- pub crate_name: Symbol,
+ crate_name: Symbol,
/// Data layout specification for the current target.
pub data_layout: TargetDataLayout,
on_disk_cache: Option<query::OnDiskCache<'tcx>>,
queries: &'tcx dyn query::QueryEngine<'tcx>,
crate_name: &str,
- output_filenames: &OutputFilenames,
+ output_filenames: OutputFilenames,
) -> GlobalCtxt<'tcx> {
let data_layout = TargetDataLayout::parse(&s.target).unwrap_or_else(|err| {
s.fatal(&err);
let common_consts = CommonConsts::new(&interners, &common_types);
let cstore = resolutions.cstore;
- let mut trait_map: FxHashMap<_, FxHashMap<_, _>> = FxHashMap::default();
- for (hir_id, v) in krate.trait_map.iter() {
- let map = trait_map.entry(hir_id.owner).or_default();
- map.insert(hir_id.local_id, StableVec::new(v.to_vec()));
- }
-
GlobalCtxt {
sess: s,
lint_store,
consts: common_consts,
visibilities: resolutions.visibilities,
extern_crate_map: resolutions.extern_crate_map,
- trait_map,
export_map: resolutions.export_map,
maybe_unused_trait_imports: resolutions.maybe_unused_trait_imports,
maybe_unused_extern_crates: resolutions.maybe_unused_extern_crates,
stability_interner: Default::default(),
const_stability_interner: Default::default(),
alloc_map: Lock::new(interpret::AllocMap::new()),
- output_filenames: Arc::new(output_filenames.clone()),
+ output_filenames: Arc::new(output_filenames),
main_def: resolutions.main_def,
}
}
}
}
- /// Returns whether or not the crate with CrateNum 'cnum'
- /// is marked as a private dependency
- pub fn is_private_dep(self, cnum: CrateNum) -> bool {
- if cnum == LOCAL_CRATE { false } else { self.cstore.crate_is_private_dep_untracked(cnum) }
- }
-
#[inline]
pub fn def_path_hash(self, def_id: DefId) -> rustc_hir::definitions::DefPathHash {
if let Some(def_id) = def_id.as_local() {
}
}
+ #[inline]
+ pub fn stable_crate_id(self, cnum: CrateNum) -> StableCrateId {
+ self.def_path_hash(cnum.as_def_id()).stable_crate_id()
+ }
+
pub fn def_path_debug_str(self, def_id: DefId) -> String {
// We are explicitly not going through queries here in order to get
// crate name and disambiguator since this code is called from debug!()
)
}
- pub fn metadata_encoding_version(self) -> Vec<u8> {
- self.cstore.metadata_encoding_version().to_vec()
- }
-
pub fn encode_metadata(self) -> EncodedMetadata {
let _prof_timer = self.prof.verbose_generic_activity("generate_crate_metadata");
self.cstore.encode_metadata(self)
struct_lint_level(self.sess, lint, level, src, None, decorate);
}
- pub fn in_scope_traits(self, id: HirId) -> Option<&'tcx StableVec<TraitCandidate>> {
- self.in_scope_traits_map(id.owner).and_then(|map| map.get(&id.local_id))
+ pub fn in_scope_traits(self, id: HirId) -> Option<&'tcx [TraitCandidate]> {
+ let map = self.in_scope_traits_map(id.owner)?;
+ let candidates = map.get(&id.local_id)?;
+ Some(&*candidates)
}
pub fn named_region(self, id: HirId) -> Option<resolve_lifetime::Region> {
}
pub fn provide(providers: &mut ty::query::Providers) {
- providers.in_scope_traits_map = |tcx, id| tcx.gcx.trait_map.get(&id);
+ providers.in_scope_traits_map = |tcx, id| tcx.hir_crate(()).trait_map.get(&id);
providers.module_exports = |tcx, id| tcx.gcx.export_map.get(&id).map(|v| &v[..]);
providers.crate_name = |tcx, id| {
assert_eq!(id, LOCAL_CRATE);
/// ADTs with no type arguments.
pub fn is_simple_text(&self) -> bool {
match self.kind() {
- Adt(_, substs) => substs.types().next().is_none(),
+ Adt(_, substs) => substs.non_erasable_generics().next().is_none(),
Ref(_, ty, _) => ty.is_simple_text(),
_ => self.is_simple_ty(),
}
}
impl<'tcx> Generics {
+ #[inline]
pub fn count(&self) -> usize {
self.parent_count + self.params.len()
}
for &i in &inverse_memory_index {
let field = fields[i as usize];
if !sized {
- bug!("univariant: field #{} of `{}` comes after unsized field", offsets.len(), ty);
+ self.tcx.sess.delay_span_bug(
+ DUMMY_SP,
+ &format!(
+ "univariant: field #{} of `{}` comes after unsized field",
+ offsets.len(),
+ ty
+ ),
+ );
}
if field.is_unsized() {
fn adjust_for_abi(&mut self, cx: &C, abi: SpecAbi);
}
-fn fn_can_unwind(
+pub fn fn_can_unwind(
panic_strategy: PanicStrategy,
codegen_fn_attr_flags: CodegenFnAttrFlags,
call_conv: Conv,
}
}
+pub fn conv_from_spec_abi(tcx: TyCtxt<'_>, abi: SpecAbi) -> Conv {
+ use rustc_target::spec::abi::Abi::*;
+ match tcx.sess.target.adjust_abi(abi) {
+ RustIntrinsic | PlatformIntrinsic | Rust | RustCall => Conv::Rust,
+
+ // It's the ABI's job to select this, not ours.
+ System { .. } => bug!("system abi should be selected elsewhere"),
+ EfiApi => bug!("eficall abi should be selected elsewhere"),
+
+ Stdcall { .. } => Conv::X86Stdcall,
+ Fastcall => Conv::X86Fastcall,
+ Vectorcall => Conv::X86VectorCall,
+ Thiscall { .. } => Conv::X86ThisCall,
+ C { .. } => Conv::C,
+ Unadjusted => Conv::C,
+ Win64 => Conv::X86_64Win64,
+ SysV64 => Conv::X86_64SysV,
+ Aapcs => Conv::ArmAapcs,
+ CCmseNonSecureCall => Conv::CCmseNonSecureCall,
+ PtxKernel => Conv::PtxKernel,
+ Msp430Interrupt => Conv::Msp430Intr,
+ X86Interrupt => Conv::X86Intr,
+ AmdGpuKernel => Conv::AmdGpuKernel,
+ AvrInterrupt => Conv::AvrInterrupt,
+ AvrNonBlockingInterrupt => Conv::AvrNonBlockingInterrupt,
+ Wasm => Conv::C,
+
+ // These API constants ought to be more specific...
+ Cdecl => Conv::C,
+ }
+}
+
+pub fn fn_ptr_codegen_fn_attr_flags() -> CodegenFnAttrFlags {
+ // Assume that fn pointers may always unwind
+ CodegenFnAttrFlags::UNWIND
+}
+
impl<'tcx, C> FnAbiExt<'tcx, C> for call::FnAbi<'tcx, Ty<'tcx>>
where
C: LayoutOf<Ty = Ty<'tcx>, TyAndLayout = TyAndLayout<'tcx>>
+ HasParamEnv<'tcx>,
{
fn of_fn_ptr(cx: &C, sig: ty::PolyFnSig<'tcx>, extra_args: &[Ty<'tcx>]) -> Self {
- // Assume that fn pointers may always unwind
- let codegen_fn_attr_flags = CodegenFnAttrFlags::UNWIND;
-
- call::FnAbi::new_internal(cx, sig, extra_args, None, codegen_fn_attr_flags, false)
+ call::FnAbi::new_internal(cx, sig, extra_args, None, fn_ptr_codegen_fn_attr_flags(), false)
}
fn of_instance(cx: &C, instance: ty::Instance<'tcx>, extra_args: &[Ty<'tcx>]) -> Self {
let sig = cx.tcx().normalize_erasing_late_bound_regions(ty::ParamEnv::reveal_all(), sig);
- use rustc_target::spec::abi::Abi::*;
- let conv = match cx.tcx().sess.target.adjust_abi(sig.abi) {
- RustIntrinsic | PlatformIntrinsic | Rust | RustCall => Conv::Rust,
-
- // It's the ABI's job to select this, not ours.
- System { .. } => bug!("system abi should be selected elsewhere"),
- EfiApi => bug!("eficall abi should be selected elsewhere"),
-
- Stdcall { .. } => Conv::X86Stdcall,
- Fastcall => Conv::X86Fastcall,
- Vectorcall => Conv::X86VectorCall,
- Thiscall { .. } => Conv::X86ThisCall,
- C { .. } => Conv::C,
- Unadjusted => Conv::C,
- Win64 => Conv::X86_64Win64,
- SysV64 => Conv::X86_64SysV,
- Aapcs => Conv::ArmAapcs,
- CCmseNonSecureCall => Conv::CCmseNonSecureCall,
- PtxKernel => Conv::PtxKernel,
- Msp430Interrupt => Conv::Msp430Intr,
- X86Interrupt => Conv::X86Intr,
- AmdGpuKernel => Conv::AmdGpuKernel,
- AvrInterrupt => Conv::AvrInterrupt,
- AvrNonBlockingInterrupt => Conv::AvrNonBlockingInterrupt,
- Wasm => Conv::C,
-
- // These API constants ought to be more specific...
- Cdecl => Conv::C,
- };
+ let conv = conv_from_spec_abi(cx.tcx(), sig.abi);
let mut inputs = sig.inputs();
let extra_args = if sig.abi == RustCall {
target.os == "linux" && target.arch == "sparc64" && target_env_gnu_like;
let linux_powerpc_gnu_like =
target.os == "linux" && target.arch == "powerpc" && target_env_gnu_like;
+ use SpecAbi::*;
let rust_abi = matches!(sig.abi, RustIntrinsic | PlatformIntrinsic | Rust | RustCall);
// Handle safe Rust thin and fat pointers.
unsafe impl<'a, T: 'a> rustc_data_structures::tagged_ptr::Pointer for &'a List<T> {
const BITS: usize = std::mem::align_of::<usize>().trailing_zeros() as usize;
+ #[inline]
fn into_usize(self) -> usize {
self as *const List<T> as usize
}
+ #[inline]
unsafe fn from_usize(ptr: usize) -> Self {
&*(ptr as *const List<T>)
}
use rustc_hir::def_id::{CrateNum, DefId, LocalDefId, LocalDefIdMap, CRATE_DEF_INDEX};
use rustc_hir::{Constness, Node};
use rustc_macros::HashStable;
-use rustc_span::hygiene::ExpnId;
use rustc_span::symbol::{kw, Ident, Symbol};
use rustc_span::Span;
use rustc_target::abi::Align;
pub use self::context::{
tls, CanonicalUserType, CanonicalUserTypeAnnotation, CanonicalUserTypeAnnotations,
CtxtInterners, DelaySpanBugEmitted, FreeRegionInfo, GeneratorInteriorTypeCause, GlobalCtxt,
- Lift, ResolvedOpaqueTy, TyCtxt, TypeckResults, UserType, UserTypeAnnotationIndex,
+ Lift, TyCtxt, TypeckResults, UserType, UserTypeAnnotationIndex,
};
pub use self::instance::{Instance, InstanceDef};
pub use self::list::List;
ExistentialPredicate, ExistentialProjection, ExistentialTraitRef, FnSig, FreeRegion, GenSig,
GeneratorSubsts, GeneratorSubstsParts, ParamConst, ParamTy, PolyExistentialProjection,
PolyExistentialTraitRef, PolyFnSig, PolyGenSig, PolyTraitRef, ProjectionTy, Region, RegionKind,
- RegionVid, TraitRef, TyKind, TypeAndMut, UpvarSubsts,
+ RegionVid, TraitRef, TyKind, TypeAndMut, UpvarSubsts, VarianceDiagInfo, VarianceDiagMutKind,
};
pub use self::trait_def::TraitDef;
// the types of AST nodes.
#[derive(Copy, Clone, PartialEq, Eq, Hash)]
pub struct CReaderCacheKey {
- pub cnum: CrateNum,
+ pub cnum: Option<CrateNum>,
pub pos: usize,
}
}
}
+#[derive(Copy, Clone, Debug, PartialEq, Eq, HashStable, TyEncodable, TyDecodable)]
+pub struct OpaqueTypeKey<'tcx> {
+ pub def_id: DefId,
+ pub substs: SubstsRef<'tcx>,
+}
+
rustc_index::newtype_index! {
/// "Universes" are used during type- and trait-checking in the
/// presence of `for<..>` binders to control what sets of names are
unsafe impl rustc_data_structures::tagged_ptr::Tag for traits::Reveal {
const BITS: usize = 1;
+ #[inline]
fn into_usize(self) -> usize {
match self {
traits::Reveal::UserFacing => 0,
traits::Reveal::All => 1,
}
}
+ #[inline]
unsafe fn from_usize(ptr: usize) -> Self {
match ptr {
0 => traits::Reveal::UserFacing,
}
/// Returns this same environment but with no caller bounds.
+ #[inline]
pub fn without_caller_bounds(self) -> Self {
Self::new(List::empty(), self.reveal())
}
fn item_name_from_def_id(self, def_id: DefId) -> Option<Symbol> {
if def_id.index == CRATE_DEF_INDEX {
- Some(self.original_crate_name(def_id.krate))
+ Some(self.crate_name(def_id.krate))
} else {
let def_key = self.def_key(def_id);
match def_key.disambiguated_data.data {
&& use_name
.span
.ctxt()
- .hygienic_eq(def_name.span.ctxt(), self.expansion_that_defined(def_parent_def_id))
- }
-
- pub fn expansion_that_defined(self, scope: DefId) -> ExpnId {
- match scope.as_local() {
- // Parsing and expansion aren't incremental, so we don't
- // need to go through a query for the same-crate case.
- Some(scope) => self.hir().definitions().expansion_that_defined(scope),
- None => self.expn_that_defined(scope),
- }
+ .hygienic_eq(def_name.span.ctxt(), self.expn_that_defined(def_parent_def_id))
}
pub fn adjust_ident(self, mut ident: Ident, scope: DefId) -> Ident {
- ident.span.normalize_to_macros_2_0_and_adjust(self.expansion_that_defined(scope));
+ ident.span.normalize_to_macros_2_0_and_adjust(self.expn_that_defined(scope));
ident
}
block: hir::HirId,
) -> (Ident, DefId) {
let scope =
- match ident.span.normalize_to_macros_2_0_and_adjust(self.expansion_that_defined(scope))
- {
+ match ident.span.normalize_to_macros_2_0_and_adjust(self.expn_that_defined(scope)) {
Some(actual_expansion) => {
self.hir().definitions().parent_module_of_macro_def(actual_expansion)
}
fmt::Display::fmt(&self.name, fmt)
}
}
+
+#[derive(Clone, Copy, Debug, PartialEq, HashStable)]
+pub enum VtblEntry<'tcx> {
+ MetadataDropInPlace,
+ MetadataSize,
+ MetadataAlign,
+ Vacant,
+ Method(DefId, SubstsRef<'tcx>),
+}
+
+pub const COMMON_VTABLE_ENTRIES: &[VtblEntry<'_>] =
+ &[VtblEntry::MetadataDropInPlace, VtblEntry::MetadataSize, VtblEntry::MetadataAlign];
+
+pub const COMMON_VTABLE_ENTRIES_DROPINPLACE: usize = 0;
+pub const COMMON_VTABLE_ENTRIES_SIZE: usize = 1;
+pub const COMMON_VTABLE_ENTRIES_ALIGN: usize = 2;
}
// Re-exported `extern crate` (#43189).
DefPathData::CrateRoot => {
- data = DefPathData::TypeNs(self.tcx().original_crate_name(def_id.krate));
+ data = DefPathData::TypeNs(self.tcx().crate_name(def_id.krate));
}
_ => {}
}
self = self.comma_sep(substs.as_generator().upvar_tys())?;
}
p!(")");
- }
- if substs.as_generator().is_valid() {
- p!(" ", print(substs.as_generator().witness()));
+ if substs.as_generator().is_valid() {
+ p!(" ", print(substs.as_generator().witness()));
+ }
}
p!("]")
use crate::ty::util::AlwaysRequiresDrop;
use crate::ty::{self, AdtSizedConstraint, CrateInherentImpls, ParamEnvAnd, Ty, TyCtxt};
use rustc_data_structures::fx::{FxHashMap, FxHashSet, FxIndexMap};
-use rustc_data_structures::stable_hasher::StableVec;
use rustc_data_structures::steal::Steal;
use rustc_data_structures::svh::Svh;
use rustc_data_structures::sync::Lrc;
use rustc_data_structures::thin_vec::ThinVec;
use rustc_data_structures::unhash::UnhashMap;
use rustc_errors::Diagnostic;
-use rustc_hir::def_id::{CrateNum, DefId, DefIndex, LocalDefId, LOCAL_CRATE};
-use rustc_hir::definitions::{DefPathHash, DefPathTable};
+use rustc_hir::def_id::{CrateNum, DefId, DefIndex, LocalDefId, StableCrateId, LOCAL_CRATE};
+use rustc_hir::definitions::DefPathHash;
use rustc_index::vec::{Idx, IndexVec};
use rustc_query_system::dep_graph::DepContext;
use rustc_query_system::query::QueryContext;
opaque::{self, FileEncodeResult, FileEncoder, IntEncodedWithFixedSize},
Decodable, Decoder, Encodable, Encoder,
};
-use rustc_session::{CrateDisambiguator, Session};
+use rustc_session::Session;
use rustc_span::hygiene::{
ExpnDataDecodeMode, ExpnDataEncodeMode, ExpnId, HygieneDecodeContext, HygieneEncodeContext,
SyntaxContext, SyntaxContextData,
use rustc_span::CachingSourceMapView;
use rustc_span::{BytePos, ExpnData, SourceFile, Span, DUMMY_SP};
use std::collections::hash_map::Entry;
-use std::iter::FromIterator;
use std::mem;
const TAG_FILE_FOOTER: u128 = 0xC0FFEE_C0FFEE_C0FFEE_C0FFEE_C0FFEE;
// session.
current_diagnostics: Lock<FxHashMap<DepNodeIndex, Vec<Diagnostic>>>,
- prev_cnums: Vec<(u32, String, CrateDisambiguator)>,
- cnum_map: OnceCell<IndexVec<CrateNum, Option<CrateNum>>>,
+ cnum_map: OnceCell<UnhashMap<StableCrateId, CrateNum>>,
source_map: &'sess SourceMap,
file_index_to_stable_id: FxHashMap<SourceFileIndex, StableSourceFileId>,
// during the next compilation session.
latest_foreign_def_path_hashes: Lock<UnhashMap<DefPathHash, RawDefId>>,
- // Maps `DefPathHashes` to their corresponding `LocalDefId`s for all
- // local items in the current compilation session. This is only populated
- // when we are in incremental mode and have loaded a pre-existing cache
- // from disk, since this map is only used when deserializing a `DefPathHash`
- // from the incremental cache.
- local_def_path_hash_to_def_id: UnhashMap<DefPathHash, LocalDefId>,
// Caches all lookups of `DefPathHashes`, both for local and foreign
// definitions. A definition from the previous compilation session
// may no longer exist in the current compilation session, so
#[derive(Encodable, Decodable)]
struct Footer {
file_index_to_stable_id: FxHashMap<SourceFileIndex, StableSourceFileId>,
- prev_cnums: Vec<(u32, String, CrateDisambiguator)>,
query_result_index: EncodedQueryResultIndex,
diagnostics_index: EncodedQueryResultIndex,
// The location of all allocations.
impl<'sess> OnDiskCache<'sess> {
/// Creates a new `OnDiskCache` instance from the serialized data in `data`.
- pub fn new(
- sess: &'sess Session,
- data: Vec<u8>,
- start_pos: usize,
- def_path_table: &DefPathTable,
- ) -> Self {
+ pub fn new(sess: &'sess Session, data: Vec<u8>, start_pos: usize) -> Self {
debug_assert!(sess.opts.incremental.is_some());
// Wrap in a scope so we can borrow `data`.
serialized_data: data,
file_index_to_stable_id: footer.file_index_to_stable_id,
file_index_to_file: Default::default(),
- prev_cnums: footer.prev_cnums,
cnum_map: OnceCell::new(),
source_map: sess.source_map(),
current_diagnostics: Default::default(),
hygiene_context: Default::default(),
foreign_def_path_hashes: footer.foreign_def_path_hashes,
latest_foreign_def_path_hashes: Default::default(),
- local_def_path_hash_to_def_id: UnhashMap::from_iter(
- def_path_table
- .all_def_path_hashes_and_def_ids(LOCAL_CRATE)
- .map(|(hash, def_id)| (hash, def_id.as_local().unwrap())),
- ),
def_path_hash_to_def_id_cache: Default::default(),
}
}
serialized_data: Vec::new(),
file_index_to_stable_id: Default::default(),
file_index_to_file: Default::default(),
- prev_cnums: vec![],
cnum_map: OnceCell::new(),
source_map,
current_diagnostics: Default::default(),
hygiene_context: Default::default(),
foreign_def_path_hashes: Default::default(),
latest_foreign_def_path_hashes: Default::default(),
- local_def_path_hash_to_def_id: Default::default(),
def_path_hash_to_def_id_cache: Default::default(),
}
}
interpret_alloc_index
};
- let sorted_cnums = sorted_cnums_including_local_crate(tcx);
- let prev_cnums: Vec<_> = sorted_cnums
- .iter()
- .map(|&cnum| {
- let crate_name = tcx.original_crate_name(cnum).to_string();
- let crate_disambiguator = tcx.crate_disambiguator(cnum);
- (cnum.as_u32(), crate_name, crate_disambiguator)
- })
- .collect();
-
let mut syntax_contexts = FxHashMap::default();
let mut expn_ids = FxHashMap::default();
TAG_FILE_FOOTER,
&Footer {
file_index_to_stable_id,
- prev_cnums,
query_result_index,
diagnostics_index,
interpret_alloc_index,
// DO NOT WRITE ANYTHING TO THE ENCODER AFTER THIS POINT! The address
// of the footer must be the last thing in the data stream.
- return Ok(());
-
- fn sorted_cnums_including_local_crate(tcx: TyCtxt<'_>) -> Vec<CrateNum> {
- let mut cnums = vec![LOCAL_CRATE];
- cnums.extend_from_slice(tcx.crates());
- cnums.sort_unstable();
- // Just to be sure...
- cnums.dedup();
- cnums
- }
+ Ok(())
})
}
self.foreign_def_path_hashes.get(hash).copied()
}
- fn try_remap_cnum(&self, tcx: TyCtxt<'_>, cnum: u32) -> Option<CrateNum> {
- let cnum_map =
- self.cnum_map.get_or_init(|| Self::compute_cnum_map(tcx, &self.prev_cnums[..]));
- debug!("try_remap_cnum({}): cnum_map={:?}", cnum, cnum_map);
+ fn try_remap_cnum(&self, tcx: TyCtxt<'_>, stable_crate_id: StableCrateId) -> Option<CrateNum> {
+ let cnum_map = self.cnum_map.get_or_init(|| Self::compute_cnum_map(tcx));
+ debug!("try_remap_cnum({:?}): cnum_map={:?}", stable_crate_id, cnum_map);
- cnum_map[CrateNum::from_u32(cnum)]
+ cnum_map.get(&stable_crate_id).copied()
}
pub(crate) fn store_foreign_def_id_hash(&self, def_id: DefId, hash: DefPathHash) {
where
T: Decodable<CacheDecoder<'a, 'tcx>>,
{
- let cnum_map =
- self.cnum_map.get_or_init(|| Self::compute_cnum_map(tcx, &self.prev_cnums[..]));
+ let cnum_map = self.cnum_map.get_or_init(|| Self::compute_cnum_map(tcx));
let mut decoder = CacheDecoder {
tcx,
// current-session-`CrateNum`. There might be `CrateNum`s from the previous
// `Session` that don't occur in the current one. For these, the mapping
// maps to None.
- fn compute_cnum_map(
- tcx: TyCtxt<'_>,
- prev_cnums: &[(u32, String, CrateDisambiguator)],
- ) -> IndexVec<CrateNum, Option<CrateNum>> {
+ fn compute_cnum_map(tcx: TyCtxt<'_>) -> UnhashMap<StableCrateId, CrateNum> {
tcx.dep_graph.with_ignore(|| {
- let current_cnums = tcx
- .all_crate_nums(())
+ tcx.all_crate_nums(())
.iter()
+ .chain(std::iter::once(&LOCAL_CRATE))
.map(|&cnum| {
- let crate_name = tcx.original_crate_name(cnum).to_string();
- let crate_disambiguator = tcx.crate_disambiguator(cnum);
- ((crate_name, crate_disambiguator), cnum)
+ let hash = tcx.def_path_hash(cnum.as_def_id()).stable_crate_id();
+ (hash, cnum)
})
- .collect::<FxHashMap<_, _>>();
-
- let map_size = prev_cnums.iter().map(|&(cnum, ..)| cnum).max().unwrap_or(0) + 1;
- let mut map = IndexVec::from_elem_n(None, map_size as usize);
-
- for &(prev_cnum, ref crate_name, crate_disambiguator) in prev_cnums {
- let key = (crate_name.clone(), crate_disambiguator);
- map[CrateNum::from_u32(prev_cnum)] = current_cnums.get(&key).cloned();
- }
-
- map[LOCAL_CRATE] = Some(LOCAL_CRATE);
- map
+ .collect()
})
}
debug!("def_path_hash_to_def_id({:?})", hash);
// Check if the `DefPathHash` corresponds to a definition in the current
// crate
- if let Some(def_id) = self.local_def_path_hash_to_def_id.get(&hash).cloned() {
+ if let Some(def_id) = tcx.definitions.local_def_path_hash_to_def_id(hash) {
let def_id = def_id.to_def_id();
e.insert(Some(def_id));
return Some(def_id);
debug!("def_path_hash_to_def_id({:?}): raw_def_id = {:?}", hash, raw_def_id);
// If the owning crate no longer exists, the corresponding definition definitely
// no longer exists.
- let krate = self.try_remap_cnum(tcx, raw_def_id.krate)?;
+ let krate = self.try_remap_cnum(tcx, hash.stable_crate_id())?;
debug!("def_path_hash_to_def_id({:?}): krate = {:?}", hash, krate);
// If our `DefPathHash` corresponded to a definition in the local crate,
// we should have either found it in `local_def_path_hash_to_def_id`, or
tcx: TyCtxt<'tcx>,
opaque: opaque::Decoder<'a>,
source_map: &'a SourceMap,
- cnum_map: &'a IndexVec<CrateNum, Option<CrateNum>>,
+ cnum_map: &'a UnhashMap<StableCrateId, CrateNum>,
file_index_to_file: &'a Lock<FxHashMap<SourceFileIndex, Lrc<SourceFile>>>,
file_index_to_stable_id: &'a FxHashMap<SourceFileIndex, StableSourceFileId>,
alloc_decoding_session: AllocDecodingSession<'a>,
{
let tcx = self.tcx();
- let cache_key =
- ty::CReaderCacheKey { cnum: CrateNum::ReservedForIncrCompCache, pos: shorthand };
+ let cache_key = ty::CReaderCacheKey { cnum: None, pos: shorthand };
if let Some(&ty) = tcx.ty_rcache.borrow().get(&cache_key) {
return Ok(ty);
r
}
- fn map_encoded_cnum_to_current(&self, cnum: CrateNum) -> CrateNum {
- self.cnum_map[cnum].unwrap_or_else(|| bug!("could not find new `CrateNum` for {:?}", cnum))
- }
-
fn decode_alloc_id(&mut self) -> Result<interpret::AllocId, Self::Error> {
let alloc_decoding_session = self.alloc_decoding_session;
alloc_decoding_session.decode_alloc_id(self)
impl<'a, 'tcx> Decodable<CacheDecoder<'a, 'tcx>> for CrateNum {
fn decode(d: &mut CacheDecoder<'a, 'tcx>) -> Result<Self, String> {
- let cnum = CrateNum::from_u32(u32::decode(d)?);
- Ok(d.map_encoded_cnum_to_current(cnum))
+ let stable_id = StableCrateId::decode(d)?;
+ let cnum = d.cnum_map[&stable_id];
+ Ok(cnum)
}
}
}
}
+impl<'a, 'tcx, E> Encodable<CacheEncoder<'a, 'tcx, E>> for CrateNum
+where
+ E: 'a + OpaqueEncoder,
+{
+ fn encode(&self, s: &mut CacheEncoder<'a, 'tcx, E>) -> Result<(), E::Error> {
+ s.tcx.stable_crate_id(*self).encode(s)
+ }
+}
+
impl<'a, 'tcx, E> Encodable<CacheEncoder<'a, 'tcx, E>> for DefId
where
E: 'a + OpaqueEncoder,
fn relate_with_variance<T: Relate<'tcx>>(
&mut self,
variance: ty::Variance,
+ info: ty::VarianceDiagInfo<'tcx>,
a: T,
b: T,
) -> RelateResult<'tcx, T>;
///////////////////////////////////////////////////////////////////////////
// Relate impls
-impl<'tcx> Relate<'tcx> for ty::TypeAndMut<'tcx> {
- fn relate<R: TypeRelation<'tcx>>(
- relation: &mut R,
- a: ty::TypeAndMut<'tcx>,
- b: ty::TypeAndMut<'tcx>,
- ) -> RelateResult<'tcx, ty::TypeAndMut<'tcx>> {
- debug!("{}.mts({:?}, {:?})", relation.tag(), a, b);
- if a.mutbl != b.mutbl {
- Err(TypeError::Mutability)
- } else {
- let mutbl = a.mutbl;
- let variance = match mutbl {
- ast::Mutability::Not => ty::Covariant,
- ast::Mutability::Mut => ty::Invariant,
- };
- let ty = relation.relate_with_variance(variance, a.ty, b.ty)?;
- Ok(ty::TypeAndMut { ty, mutbl })
- }
+pub fn relate_type_and_mut<'tcx, R: TypeRelation<'tcx>>(
+ relation: &mut R,
+ a: ty::TypeAndMut<'tcx>,
+ b: ty::TypeAndMut<'tcx>,
+ kind: ty::VarianceDiagMutKind,
+) -> RelateResult<'tcx, ty::TypeAndMut<'tcx>> {
+ debug!("{}.mts({:?}, {:?})", relation.tag(), a, b);
+ if a.mutbl != b.mutbl {
+ Err(TypeError::Mutability)
+ } else {
+ let mutbl = a.mutbl;
+ let (variance, info) = match mutbl {
+ ast::Mutability::Not => (ty::Covariant, ty::VarianceDiagInfo::None),
+ ast::Mutability::Mut => (ty::Invariant, ty::VarianceDiagInfo::Mut { kind, ty: a.ty }),
+ };
+ let ty = relation.relate_with_variance(variance, info, a.ty, b.ty)?;
+ Ok(ty::TypeAndMut { ty, mutbl })
}
}
let params = iter::zip(a_subst, b_subst).enumerate().map(|(i, (a, b))| {
let variance = variances.map_or(ty::Invariant, |v| v[i]);
- relation.relate_with_variance(variance, a, b)
+ relation.relate_with_variance(variance, ty::VarianceDiagInfo::default(), a, b)
});
tcx.mk_substs(params)
if is_output {
relation.relate(a, b)
} else {
- relation.relate_with_variance(ty::Contravariant, a, b)
+ relation.relate_with_variance(
+ ty::Contravariant,
+ ty::VarianceDiagInfo::default(),
+ a,
+ b,
+ )
}
})
.enumerate()
b.item_def_id,
)))
} else {
- let ty = relation.relate_with_variance(ty::Invariant, a.ty, b.ty)?;
- let substs = relation.relate_with_variance(ty::Invariant, a.substs, b.substs)?;
+ let ty = relation.relate_with_variance(
+ ty::Invariant,
+ ty::VarianceDiagInfo::default(),
+ a.ty,
+ b.ty,
+ )?;
+ let substs = relation.relate_with_variance(
+ ty::Invariant,
+ ty::VarianceDiagInfo::default(),
+ a.substs,
+ b.substs,
+ )?;
Ok(ty::ExistentialProjection { item_def_id: a.item_def_id, substs, ty })
}
}
(&ty::Dynamic(a_obj, a_region), &ty::Dynamic(b_obj, b_region)) => {
let region_bound = relation.with_cause(Cause::ExistentialRegionBound, |relation| {
- relation.relate_with_variance(ty::Contravariant, a_region, b_region)
+ relation.relate_with_variance(
+ ty::Contravariant,
+ ty::VarianceDiagInfo::default(),
+ a_region,
+ b_region,
+ )
})?;
Ok(tcx.mk_dynamic(relation.relate(a_obj, b_obj)?, region_bound))
}
}
(&ty::RawPtr(a_mt), &ty::RawPtr(b_mt)) => {
- let mt = relation.relate(a_mt, b_mt)?;
+ let mt = relate_type_and_mut(relation, a_mt, b_mt, ty::VarianceDiagMutKind::RawPtr)?;
Ok(tcx.mk_ptr(mt))
}
(&ty::Ref(a_r, a_ty, a_mutbl), &ty::Ref(b_r, b_ty, b_mutbl)) => {
- let r = relation.relate_with_variance(ty::Contravariant, a_r, b_r)?;
+ let r = relation.relate_with_variance(
+ ty::Contravariant,
+ ty::VarianceDiagInfo::default(),
+ a_r,
+ b_r,
+ )?;
let a_mt = ty::TypeAndMut { ty: a_ty, mutbl: a_mutbl };
let b_mt = ty::TypeAndMut { ty: b_ty, mutbl: b_mutbl };
- let mt = relation.relate(a_mt, b_mt)?;
+ let mt = relate_type_and_mut(relation, a_mt, b_mt, ty::VarianceDiagMutKind::Ref)?;
Ok(tcx.mk_ref(r, mt))
}
(ty::ConstKind::Unevaluated(au), ty::ConstKind::Unevaluated(bu))
if au.def == bu.def && au.promoted == bu.promoted =>
{
- let substs =
- relation.relate_with_variance(ty::Variance::Invariant, au.substs, bu.substs)?;
+ let substs = relation.relate_with_variance(
+ ty::Variance::Invariant,
+ ty::VarianceDiagInfo::default(),
+ au.substs,
+ bu.substs,
+ )?;
return Ok(tcx.mk_const(ty::Const {
val: ty::ConstKind::Unevaluated(ty::Unevaluated {
def: au.def,
#[inline]
pub fn is_enum(&self) -> bool {
- match self.kind() {
- Adt(adt_def, _) => adt_def.is_enum(),
- _ => false,
- }
+ matches!(self.kind(), Adt(adt_def, _) if adt_def.is_enum())
+ }
+
+ #[inline]
+ pub fn is_union(&self) -> bool {
+ matches!(self.kind(), Adt(adt_def, _) if adt_def.is_union())
}
#[inline]
matches!(self.kind(), Int(ty::IntTy::Isize) | Uint(ty::UintTy::Usize))
}
- #[inline]
- pub fn is_machine(&self) -> bool {
- matches!(self.kind(), Int(..) | Uint(..) | Float(..))
- }
-
#[inline]
pub fn has_concrete_skeleton(&self) -> bool {
!matches!(self.kind(), Param(_) | Infer(_) | Error(_))
}
}
}
+
+/// Extra information about why we ended up with a particular variance.
+/// This is only used to add more information to error messages, and
+/// has no effect on soundness. While choosing the 'wrong' `VarianceDiagInfo`
+/// may lead to confusing notes in error messages, it will never cause
+/// a miscompilation or unsoundness.
+///
+/// When in doubt, use `VarianceDiagInfo::default()`
+#[derive(Clone, Debug, PartialEq, Eq, PartialOrd, Ord)]
+pub enum VarianceDiagInfo<'tcx> {
+ /// No additional information - this is the default.
+ /// We will not add any additional information to error messages.
+ None,
+ /// We switched our variance because a type occurs inside
+ /// the generic argument of a mutable reference or pointer
+ /// (`*mut T` or `&mut T`). In either case, our variance
+ /// will always be `Invariant`.
+ Mut {
+ /// Tracks whether we had a mutable pointer or reference,
+ /// for better error messages
+ kind: VarianceDiagMutKind,
+ /// The type parameter of the mutable pointer/reference
+ /// (the `T` in `&mut T` or `*mut T`).
+ ty: Ty<'tcx>,
+ },
+}
+
+#[derive(Clone, Debug, PartialEq, Eq, PartialOrd, Ord)]
+pub enum VarianceDiagMutKind {
+ /// A mutable raw pointer (`*mut T`)
+ RawPtr,
+ /// A mutable reference (`&mut T`)
+ Ref,
+}
+
+impl<'tcx> VarianceDiagInfo<'tcx> {
+ /// Mirrors `Variance::xform` - used to 'combine' the existing
+ /// and new `VarianceDiagInfo`s when our variance changes.
+ pub fn xform(self, other: VarianceDiagInfo<'tcx>) -> VarianceDiagInfo<'tcx> {
+ // For now, just use the first `VarianceDiagInfo::Mut` that we see
+ match self {
+ VarianceDiagInfo::None => other,
+ VarianceDiagInfo::Mut { .. } => self,
+ }
+ }
+}
+
+impl<'tcx> Default for VarianceDiagInfo<'tcx> {
+ fn default() -> Self {
+ Self::None
+ }
+}
}
/// Interpret these substitutions as the substitutions of a generator type.
- /// Closure substitutions have a particular structure controlled by the
+ /// Generator substitutions have a particular structure controlled by the
/// compiler that encodes information like the signature and generator kind;
/// see `ty::GeneratorSubsts` struct for more comments.
pub fn as_generator(&'tcx self) -> GeneratorSubsts<'tcx> {
use rustc_data_structures::graph;
use rustc_index::vec::IndexVec;
use rustc_middle::mir::ConstraintCategory;
-use rustc_middle::ty::RegionVid;
+use rustc_middle::ty::{RegionVid, VarianceDiagInfo};
use rustc_span::DUMMY_SP;
use crate::borrow_check::{
/// Marker trait that controls whether a `R1: R2` constraint
/// represents an edge `R1 -> R2` or `R2 -> R1`.
crate trait ConstraintGraphDirecton: Copy + 'static {
- fn start_region(c: &OutlivesConstraint) -> RegionVid;
- fn end_region(c: &OutlivesConstraint) -> RegionVid;
+ fn start_region(c: &OutlivesConstraint<'_>) -> RegionVid;
+ fn end_region(c: &OutlivesConstraint<'_>) -> RegionVid;
fn is_normal() -> bool;
}
crate struct Normal;
impl ConstraintGraphDirecton for Normal {
- fn start_region(c: &OutlivesConstraint) -> RegionVid {
+ fn start_region(c: &OutlivesConstraint<'_>) -> RegionVid {
c.sup
}
- fn end_region(c: &OutlivesConstraint) -> RegionVid {
+ fn end_region(c: &OutlivesConstraint<'_>) -> RegionVid {
c.sub
}
crate struct Reverse;
impl ConstraintGraphDirecton for Reverse {
- fn start_region(c: &OutlivesConstraint) -> RegionVid {
+ fn start_region(c: &OutlivesConstraint<'_>) -> RegionVid {
c.sub
}
- fn end_region(c: &OutlivesConstraint) -> RegionVid {
+ fn end_region(c: &OutlivesConstraint<'_>) -> RegionVid {
c.sup
}
/// R2` is treated as an edge `R1 -> R2`. We use this graph to
/// construct SCCs for region inference but also for error
/// reporting.
- crate fn new(direction: D, set: &OutlivesConstraintSet, num_region_vars: usize) -> Self {
+ crate fn new(direction: D, set: &OutlivesConstraintSet<'_>, num_region_vars: usize) -> Self {
let mut first_constraints = IndexVec::from_elem_n(None, num_region_vars);
let mut next_constraints = IndexVec::from_elem(None, &set.outlives);
/// Given the constraint set from which this graph was built
/// creates a region graph so that you can iterate over *regions*
/// and not constraints.
- crate fn region_graph<'rg>(
+ crate fn region_graph<'rg, 'tcx>(
&'rg self,
- set: &'rg OutlivesConstraintSet,
+ set: &'rg OutlivesConstraintSet<'tcx>,
static_region: RegionVid,
- ) -> RegionGraph<'rg, D> {
+ ) -> RegionGraph<'rg, 'tcx, D> {
RegionGraph::new(set, self, static_region)
}
/// Given a region `R`, iterate over all constraints `R: R1`.
- crate fn outgoing_edges<'a>(
+ crate fn outgoing_edges<'a, 'tcx>(
&'a self,
region_sup: RegionVid,
- constraints: &'a OutlivesConstraintSet,
+ constraints: &'a OutlivesConstraintSet<'tcx>,
static_region: RegionVid,
- ) -> Edges<'a, D> {
+ ) -> Edges<'a, 'tcx, D> {
//if this is the `'static` region and the graph's direction is normal,
//then setup the Edges iterator to return all regions #53178
if region_sup == static_region && D::is_normal() {
}
}
-crate struct Edges<'s, D: ConstraintGraphDirecton> {
+crate struct Edges<'s, 'tcx, D: ConstraintGraphDirecton> {
graph: &'s ConstraintGraph<D>,
- constraints: &'s OutlivesConstraintSet,
+ constraints: &'s OutlivesConstraintSet<'tcx>,
pointer: Option<OutlivesConstraintIndex>,
next_static_idx: Option<usize>,
static_region: RegionVid,
}
-impl<'s, D: ConstraintGraphDirecton> Iterator for Edges<'s, D> {
- type Item = OutlivesConstraint;
+impl<'s, 'tcx, D: ConstraintGraphDirecton> Iterator for Edges<'s, 'tcx, D> {
+ type Item = OutlivesConstraint<'tcx>;
fn next(&mut self) -> Option<Self::Item> {
if let Some(p) = self.pointer {
self.pointer = self.graph.next_constraints[p];
- Some(self.constraints[p])
+ Some(self.constraints[p].clone())
} else if let Some(next_static_idx) = self.next_static_idx {
self.next_static_idx = if next_static_idx == (self.graph.first_constraints.len() - 1) {
None
sub: next_static_idx.into(),
locations: Locations::All(DUMMY_SP),
category: ConstraintCategory::Internal,
+ variance_info: VarianceDiagInfo::default(),
})
} else {
None
/// This struct brings together a constraint set and a (normal, not
/// reverse) constraint graph. It implements the graph traits and is
/// usd for doing the SCC computation.
-crate struct RegionGraph<'s, D: ConstraintGraphDirecton> {
- set: &'s OutlivesConstraintSet,
+crate struct RegionGraph<'s, 'tcx, D: ConstraintGraphDirecton> {
+ set: &'s OutlivesConstraintSet<'tcx>,
constraint_graph: &'s ConstraintGraph<D>,
static_region: RegionVid,
}
-impl<'s, D: ConstraintGraphDirecton> RegionGraph<'s, D> {
+impl<'s, 'tcx, D: ConstraintGraphDirecton> RegionGraph<'s, 'tcx, D> {
/// Creates a "dependency graph" where each region constraint `R1:
/// R2` is treated as an edge `R1 -> R2`. We use this graph to
/// construct SCCs for region inference but also for error
/// reporting.
crate fn new(
- set: &'s OutlivesConstraintSet,
+ set: &'s OutlivesConstraintSet<'tcx>,
constraint_graph: &'s ConstraintGraph<D>,
static_region: RegionVid,
) -> Self {
/// Given a region `R`, iterate over all regions `R1` such that
/// there exists a constraint `R: R1`.
- crate fn outgoing_regions(&self, region_sup: RegionVid) -> Successors<'_, D> {
+ crate fn outgoing_regions(&self, region_sup: RegionVid) -> Successors<'_, 'tcx, D> {
Successors {
edges: self.constraint_graph.outgoing_edges(region_sup, self.set, self.static_region),
}
}
}
-crate struct Successors<'s, D: ConstraintGraphDirecton> {
- edges: Edges<'s, D>,
+crate struct Successors<'s, 'tcx, D: ConstraintGraphDirecton> {
+ edges: Edges<'s, 'tcx, D>,
}
-impl<'s, D: ConstraintGraphDirecton> Iterator for Successors<'s, D> {
+impl<'s, 'tcx, D: ConstraintGraphDirecton> Iterator for Successors<'s, 'tcx, D> {
type Item = RegionVid;
fn next(&mut self) -> Option<Self::Item> {
}
}
-impl<'s, D: ConstraintGraphDirecton> graph::DirectedGraph for RegionGraph<'s, D> {
+impl<'s, 'tcx, D: ConstraintGraphDirecton> graph::DirectedGraph for RegionGraph<'s, 'tcx, D> {
type Node = RegionVid;
}
-impl<'s, D: ConstraintGraphDirecton> graph::WithNumNodes for RegionGraph<'s, D> {
+impl<'s, 'tcx, D: ConstraintGraphDirecton> graph::WithNumNodes for RegionGraph<'s, 'tcx, D> {
fn num_nodes(&self) -> usize {
self.constraint_graph.first_constraints.len()
}
}
-impl<'s, D: ConstraintGraphDirecton> graph::WithSuccessors for RegionGraph<'s, D> {
+impl<'s, 'tcx, D: ConstraintGraphDirecton> graph::WithSuccessors for RegionGraph<'s, 'tcx, D> {
fn successors(&self, node: Self::Node) -> <Self as graph::GraphSuccessors<'_>>::Iter {
self.outgoing_regions(node)
}
}
-impl<'s, 'graph, D: ConstraintGraphDirecton> graph::GraphSuccessors<'graph> for RegionGraph<'s, D> {
+impl<'s, 'graph, 'tcx, D: ConstraintGraphDirecton> graph::GraphSuccessors<'graph>
+ for RegionGraph<'s, 'tcx, D>
+{
type Item = RegionVid;
- type Iter = Successors<'graph, D>;
+ // FIXME - why can't this be `'graph, 'tcx`
+ type Iter = Successors<'graph, 'graph, D>;
}
use rustc_data_structures::graph::scc::Sccs;
use rustc_index::vec::IndexVec;
use rustc_middle::mir::ConstraintCategory;
-use rustc_middle::ty::RegionVid;
+use rustc_middle::ty::{RegionVid, VarianceDiagInfo};
use std::fmt;
use std::ops::Index;
/// a unique `OutlivesConstraintIndex` and you can index into the set
/// (`constraint_set[i]`) to access the constraint details.
#[derive(Clone, Default)]
-crate struct OutlivesConstraintSet {
- outlives: IndexVec<OutlivesConstraintIndex, OutlivesConstraint>,
+crate struct OutlivesConstraintSet<'tcx> {
+ outlives: IndexVec<OutlivesConstraintIndex, OutlivesConstraint<'tcx>>,
}
-impl OutlivesConstraintSet {
- crate fn push(&mut self, constraint: OutlivesConstraint) {
+impl<'tcx> OutlivesConstraintSet<'tcx> {
+ crate fn push(&mut self, constraint: OutlivesConstraint<'tcx>) {
debug!(
"OutlivesConstraintSet::push({:?}: {:?} @ {:?}",
constraint.sup, constraint.sub, constraint.locations
Sccs::new(region_graph)
}
- crate fn outlives(&self) -> &IndexVec<OutlivesConstraintIndex, OutlivesConstraint> {
+ crate fn outlives(&self) -> &IndexVec<OutlivesConstraintIndex, OutlivesConstraint<'tcx>> {
&self.outlives
}
}
-impl Index<OutlivesConstraintIndex> for OutlivesConstraintSet {
- type Output = OutlivesConstraint;
+impl<'tcx> Index<OutlivesConstraintIndex> for OutlivesConstraintSet<'tcx> {
+ type Output = OutlivesConstraint<'tcx>;
fn index(&self, i: OutlivesConstraintIndex) -> &Self::Output {
&self.outlives[i]
}
}
-#[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Ord)]
-pub struct OutlivesConstraint {
+#[derive(Clone, PartialEq, Eq, PartialOrd, Ord)]
+pub struct OutlivesConstraint<'tcx> {
// NB. The ordering here is not significant for correctness, but
// it is for convenience. Before we dump the constraints in the
// debugging logs, we sort them, and we'd like the "super region"
/// What caused this constraint?
pub category: ConstraintCategory,
+
+ /// Variance diagnostic information
+ pub variance_info: VarianceDiagInfo<'tcx>,
}
-impl fmt::Debug for OutlivesConstraint {
+impl<'tcx> fmt::Debug for OutlivesConstraint<'tcx> {
fn fmt(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result {
- write!(formatter, "({:?}: {:?}) due to {:?}", self.sup, self.sub, self.locations)
+ write!(
+ formatter,
+ "({:?}: {:?}) due to {:?} ({:?})",
+ self.sup, self.sub, self.locations, self.variance_info
+ )
}
}
use rustc_hir as hir;
use rustc_hir::def_id::DefId;
use rustc_hir::{AsyncGeneratorKind, GeneratorKind};
-use rustc_index::vec::Idx;
use rustc_middle::mir::{
self, AggregateKind, BindingForm, BorrowKind, ClearCrossCrate, ConstraintCategory,
- FakeReadCause, Local, LocalDecl, LocalInfo, LocalKind, Location, Operand, Place, PlaceRef,
+ FakeReadCause, LocalDecl, LocalInfo, LocalKind, Location, Operand, Place, PlaceRef,
ProjectionElem, Rvalue, Statement, StatementKind, Terminator, TerminatorKind, VarBindingForm,
};
use rustc_middle::ty::{self, suggest_constraining_type_param, Ty, TypeFoldable};
bug!("temporary or return pointer with a name")
}
LocalKind::Var => "local variable ",
- LocalKind::Arg if !self.upvars.is_empty() && local == Local::new(1) => {
+ LocalKind::Arg
+ if !self.upvars.is_empty() && local == ty::CAPTURE_STRUCT_LOCAL =>
+ {
"variable captured by `move` "
}
LocalKind::Arg => "function parameter ",
use rustc_span::symbol::Symbol;
use rustc_span::Span;
+use crate::borrow_check::region_infer::BlameConstraint;
use crate::borrow_check::{
borrow_set::BorrowData, nll::ConstraintDescription, region_infer::Cause, MirBorrowckCtxt,
WriteKind,
borrow_region: RegionVid,
outlived_region: RegionVid,
) -> (ConstraintCategory, bool, Span, Option<RegionName>) {
- let (category, from_closure, span) = self.regioncx.best_blame_constraint(
- &self.body,
- borrow_region,
- NllRegionVariableOrigin::FreeRegion,
- |r| self.regioncx.provides_universal_region(r, borrow_region, outlived_region),
- );
+ let BlameConstraint { category, from_closure, span, variance_info: _ } =
+ self.regioncx.best_blame_constraint(
+ &self.body,
+ borrow_region,
+ NllRegionVariableOrigin::FreeRegion,
+ |r| self.regioncx.provides_universal_region(r, borrow_region, outlived_region),
+ );
let outlived_fr_name = self.give_region_a_name(outlived_region);
use rustc_hir as hir;
use rustc_hir::Node;
-use rustc_index::vec::Idx;
use rustc_middle::hir::map::Map;
use rustc_middle::mir::{Mutability, Place, PlaceRef, ProjectionElem};
use rustc_middle::ty::{self, Ty, TyCtxt};
}
}
PlaceRef { local: _, projection: [proj_base @ .., ProjectionElem::Deref] } => {
- if the_place_err.local == Local::new(1)
+ if the_place_err.local == ty::CAPTURE_STRUCT_LOCAL
&& proj_base.is_empty()
&& !self.upvars.is_empty()
{
item_msg = format!("`{}`", access_place_desc.unwrap());
- debug_assert!(self.body.local_decls[Local::new(1)].ty.is_region_ptr());
+ debug_assert!(
+ self.body.local_decls[ty::CAPTURE_STRUCT_LOCAL].ty.is_region_ptr()
+ );
debug_assert!(is_closure_or_generator(
Place::ty_from(
the_place_err.local,
}
}
- PlaceRef {
- local,
- projection: [ProjectionElem::Deref],
- // FIXME document what is this 1 magic number about
- } if local == Local::new(1) && !self.upvars.is_empty() => {
+ PlaceRef { local, projection: [ProjectionElem::Deref] }
+ if local == ty::CAPTURE_STRUCT_LOCAL && !self.upvars.is_empty() =>
+ {
self.expected_fn_found_fn_mut_call(&mut err, span, act);
}
{
let lt_name = &src[1..ws_pos];
let ty = &src[ws_pos..];
- return (assignment_rhs_span, format!("&{} mut {}", lt_name, ty));
+ if !ty.trim_start().starts_with("mut") {
+ return (assignment_rhs_span, format!("&{} mut {}", lt_name, ty));
+ }
} else if let Some(stripped) = src.strip_prefix('&') {
- return (assignment_rhs_span, format!("&mut {}", stripped));
+ if !stripped.trim_start().starts_with("mut") {
+ return (assignment_rhs_span, format!("&mut {}", stripped));
+ }
}
}
}
use crate::util::borrowck_errors;
+use crate::borrow_check::region_infer::BlameConstraint;
use crate::borrow_check::{
nll::ConstraintDescription,
region_infer::{values::RegionElement, TypeTest},
) {
debug!("report_region_error(fr={:?}, outlived_fr={:?})", fr, outlived_fr);
- let (category, _, span) =
+ let BlameConstraint { category, span, variance_info, from_closure: _ } =
self.regioncx.best_blame_constraint(&self.body, fr, fr_origin, |r| {
self.regioncx.provides_universal_region(r, fr, outlived_fr)
});
- debug!("report_region_error: category={:?} {:?}", category, span);
+ debug!("report_region_error: category={:?} {:?} {:?}", category, span, variance_info);
// Check if we can use one of the "nice region errors".
if let (Some(f), Some(o)) = (self.to_error_region(fr), self.to_error_region(outlived_fr)) {
let nice = NiceRegionError::new_from_span(self.infcx, span, o, f);
span,
};
- let diag = match (category, fr_is_local, outlived_fr_is_local) {
+ let mut diag = match (category, fr_is_local, outlived_fr_is_local) {
(ConstraintCategory::Return(kind), true, false) if self.is_closure_fn_mut(fr) => {
self.report_fnmut_error(&errci, kind)
}
}
};
+ match variance_info {
+ ty::VarianceDiagInfo::None => {}
+ ty::VarianceDiagInfo::Mut { kind, ty } => {
+ let kind_name = match kind {
+ ty::VarianceDiagMutKind::Ref => "reference",
+ ty::VarianceDiagMutKind::RawPtr => "pointer",
+ };
+ diag.note(&format!("requirement occurs because of a mutable {kind_name} to {ty}",));
+ diag.note(&format!("mutable {kind_name}s are invariant over their type parameter"));
+ diag.help("see <https://doc.rust-lang.org/nomicon/subtyping.html> for more information about variance");
+ }
+ }
+
diag.buffer(&mut self.errors_buffer);
}
// no move out from an earlier location) then this is an attempt at initialization
// of the union - we should error in that case.
let tcx = this.infcx.tcx;
- if let ty::Adt(def, _) = base.ty(this.body(), tcx).ty.kind() {
- if def.is_union() {
- if this.move_data.path_map[mpi].iter().any(|moi| {
- this.move_data.moves[*moi].source.is_predecessor_of(location, this.body)
- }) {
- return;
- }
+ if base.ty(this.body(), tcx).ty.is_union() {
+ if this.move_data.path_map[mpi].iter().any(|moi| {
+ this.move_data.moves[*moi].source.is_predecessor_of(location, this.body)
+ }) {
+ return;
}
}
//! The entry point of the NLL borrow checker.
-use rustc_data_structures::fx::FxHashMap;
+use rustc_data_structures::vec_map::VecMap;
use rustc_errors::Diagnostic;
-use rustc_hir::def_id::DefId;
use rustc_index::vec::IndexVec;
use rustc_infer::infer::InferCtxt;
use rustc_middle::mir::{
BasicBlock, Body, ClosureOutlivesSubject, ClosureRegionRequirements, LocalKind, Location,
Promoted,
};
-use rustc_middle::ty::{self, RegionKind, RegionVid};
+use rustc_middle::ty::{self, OpaqueTypeKey, RegionKind, RegionVid, Ty};
use rustc_span::symbol::sym;
use std::env;
use std::fmt::Debug;
/// closure requirements to propagate, and any generated errors.
crate struct NllOutput<'tcx> {
pub regioncx: RegionInferenceContext<'tcx>,
- pub opaque_type_values: FxHashMap<DefId, ty::ResolvedOpaqueTy<'tcx>>,
+ pub opaque_type_values: VecMap<OpaqueTypeKey<'tcx>, Ty<'tcx>>,
pub polonius_output: Option<Rc<PoloniusOutput>>,
pub opt_closure_req: Option<ClosureRegionRequirements<'tcx>>,
pub nll_errors: RegionErrors<'tcx>,
body: &Body<'tcx>,
regioncx: &RegionInferenceContext<'tcx>,
closure_region_requirements: &Option<ClosureRegionRequirements<'_>>,
- opaque_type_values: &FxHashMap<DefId, ty::ResolvedOpaqueTy<'tcx>>,
+ opaque_type_values: &VecMap<OpaqueTypeKey<'tcx>, Ty<'tcx>>,
errors_buffer: &mut Vec<Diagnostic>,
) {
let tcx = infcx.tcx;
Overlap::EqualOrDisjoint
} else {
let ty = Place::ty_from(pi1_local, pi1_proj_base, body, tcx).ty;
- match ty.kind() {
- ty::Adt(def, _) if def.is_union() => {
- // Different fields of a union, we are basically stuck.
- debug!("place_element_conflict: STUCK-UNION");
- Overlap::Arbitrary
- }
- _ => {
- // Different fields of a struct (`a.x` vs. `a.y`). Disjoint!
- debug!("place_element_conflict: DISJOINT-FIELD");
- Overlap::Disjoint
- }
+ if ty.is_union() {
+ // Different fields of a union, we are basically stuck.
+ debug!("place_element_conflict: STUCK-UNION");
+ Overlap::Arbitrary
+ } else {
+ // Different fields of a struct (`a.x` vs. `a.y`). Disjoint!
+ debug!("place_element_conflict: DISJOINT-FIELD");
+ Overlap::Disjoint
}
}
}
let mut constraints: Vec<_> = self.constraints.outlives().iter().collect();
constraints.sort();
for constraint in &constraints {
- let OutlivesConstraint { sup, sub, locations, category } = constraint;
+ let OutlivesConstraint { sup, sub, locations, category, variance_info: _ } = constraint;
let (name, arg) = match locations {
Locations::All(span) => {
("All", tcx.sess.source_map().span_to_embeddable_string(*span))
impl<'a, 'this, 'tcx> dot::Labeller<'this> for RawConstraints<'a, 'tcx> {
type Node = RegionVid;
- type Edge = OutlivesConstraint;
+ type Edge = OutlivesConstraint<'tcx>;
fn graph_id(&'this self) -> dot::Id<'this> {
dot::Id::new("RegionInferenceContext").unwrap()
fn node_label(&'this self, n: &RegionVid) -> dot::LabelText<'this> {
dot::LabelText::LabelStr(format!("{:?}", n).into())
}
- fn edge_label(&'this self, e: &OutlivesConstraint) -> dot::LabelText<'this> {
+ fn edge_label(&'this self, e: &OutlivesConstraint<'tcx>) -> dot::LabelText<'this> {
dot::LabelText::LabelStr(format!("{:?}", e.locations).into())
}
}
impl<'a, 'this, 'tcx> dot::GraphWalk<'this> for RawConstraints<'a, 'tcx> {
type Node = RegionVid;
- type Edge = OutlivesConstraint;
+ type Edge = OutlivesConstraint<'tcx>;
fn nodes(&'this self) -> dot::Nodes<'this, RegionVid> {
let vids: Vec<RegionVid> = self.regioncx.definitions.indices().collect();
vids.into()
}
- fn edges(&'this self) -> dot::Edges<'this, OutlivesConstraint> {
+ fn edges(&'this self) -> dot::Edges<'this, OutlivesConstraint<'tcx>> {
(&self.regioncx.constraints.outlives().raw[..]).into()
}
// Render `a: b` as `a -> b`, indicating the flow
// of data during inference.
- fn source(&'this self, edge: &OutlivesConstraint) -> RegionVid {
+ fn source(&'this self, edge: &OutlivesConstraint<'tcx>) -> RegionVid {
edge.sup
}
- fn target(&'this self, edge: &OutlivesConstraint) -> RegionVid {
+ fn target(&'this self, edge: &OutlivesConstraint<'tcx>) -> RegionVid {
edge.sub
}
}
liveness_constraints: LivenessValues<RegionVid>,
/// The outlives constraints computed by the type-check.
- constraints: Frozen<OutlivesConstraintSet>,
+ constraints: Frozen<OutlivesConstraintSet<'tcx>>,
/// The constraint-set, but in graph form, making it easy to traverse
/// the constraints adjacent to a particular region. Used to construct
Error,
}
-#[derive(Copy, Clone, PartialEq, Eq, Debug)]
-enum Trace {
+#[derive(Clone, PartialEq, Eq, Debug)]
+enum Trace<'tcx> {
StartRegion,
- FromOutlivesConstraint(OutlivesConstraint),
+ FromOutlivesConstraint(OutlivesConstraint<'tcx>),
NotVisited,
}
universal_regions: Rc<UniversalRegions<'tcx>>,
placeholder_indices: Rc<PlaceholderIndices>,
universal_region_relations: Frozen<UniversalRegionRelations<'tcx>>,
- outlives_constraints: OutlivesConstraintSet,
+ outlives_constraints: OutlivesConstraintSet<'tcx>,
member_constraints_in: MemberConstraintSet<'tcx, RegionVid>,
closure_bounds_mapping: FxHashMap<
Location,
crate fn retrieve_closure_constraint_info(
&self,
body: &Body<'tcx>,
- constraint: &OutlivesConstraint,
- ) -> (ConstraintCategory, bool, Span) {
+ constraint: &OutlivesConstraint<'tcx>,
+ ) -> BlameConstraint<'tcx> {
let loc = match constraint.locations {
- Locations::All(span) => return (constraint.category, false, span),
+ Locations::All(span) => {
+ return BlameConstraint {
+ category: constraint.category,
+ from_closure: false,
+ span,
+ variance_info: constraint.variance_info.clone(),
+ };
+ }
Locations::Single(loc) => loc,
};
let opt_span_category =
self.closure_bounds_mapping[&loc].get(&(constraint.sup, constraint.sub));
- opt_span_category.map(|&(category, span)| (category, true, span)).unwrap_or((
- constraint.category,
- false,
- body.source_info(loc).span,
- ))
+ opt_span_category
+ .map(|&(category, span)| BlameConstraint {
+ category,
+ from_closure: true,
+ span: span,
+ variance_info: constraint.variance_info.clone(),
+ })
+ .unwrap_or(BlameConstraint {
+ category: constraint.category,
+ from_closure: false,
+ span: body.source_info(loc).span,
+ variance_info: constraint.variance_info.clone(),
+ })
}
/// Finds a good span to blame for the fact that `fr1` outlives `fr2`.
fr1_origin: NllRegionVariableOrigin,
fr2: RegionVid,
) -> (ConstraintCategory, Span) {
- let (category, _, span) = self.best_blame_constraint(body, fr1, fr1_origin, |r| {
- self.provides_universal_region(r, fr1, fr2)
- });
+ let BlameConstraint { category, span, .. } =
+ self.best_blame_constraint(body, fr1, fr1_origin, |r| {
+ self.provides_universal_region(r, fr1, fr2)
+ });
(category, span)
}
&self,
from_region: RegionVid,
target_test: impl Fn(RegionVid) -> bool,
- ) -> Option<(Vec<OutlivesConstraint>, RegionVid)> {
+ ) -> Option<(Vec<OutlivesConstraint<'tcx>>, RegionVid)> {
let mut context = IndexVec::from_elem(Trace::NotVisited, &self.definitions);
context[from_region] = Trace::StartRegion;
let mut result = vec![];
let mut p = r;
loop {
- match context[p] {
+ match context[p].clone() {
Trace::NotVisited => {
bug!("found unvisited region {:?} on path to {:?}", p, r)
}
Trace::FromOutlivesConstraint(c) => {
- result.push(c);
p = c.sup;
+ result.push(c);
}
Trace::StartRegion => {
// Always inline this closure because it can be hot.
let mut handle_constraint = #[inline(always)]
- |constraint: OutlivesConstraint| {
+ |constraint: OutlivesConstraint<'tcx>| {
debug_assert_eq!(constraint.sup, r);
let sub_region = constraint.sub;
if let Trace::NotVisited = context[sub_region] {
sub: constraint.min_choice,
locations: Locations::All(p_c.definition_span),
category: ConstraintCategory::OpaqueType,
+ variance_info: ty::VarianceDiagInfo::default(),
};
handle_constraint(constraint);
}
from_region: RegionVid,
from_region_origin: NllRegionVariableOrigin,
target_test: impl Fn(RegionVid) -> bool,
- ) -> (ConstraintCategory, bool, Span) {
+ ) -> BlameConstraint<'tcx> {
debug!(
"best_blame_constraint(from_region={:?}, from_region_origin={:?})",
from_region, from_region_origin
debug!(
"best_blame_constraint: path={:#?}",
path.iter()
- .map(|&c| format!(
+ .map(|c| format!(
"{:?} ({:?}: {:?})",
c,
self.constraint_sccs.scc(c.sup),
);
// Classify each of the constraints along the path.
- let mut categorized_path: Vec<(ConstraintCategory, bool, Span)> = path
+ let mut categorized_path: Vec<BlameConstraint<'tcx>> = path
.iter()
.map(|constraint| {
if constraint.category == ConstraintCategory::ClosureBounds {
self.retrieve_closure_constraint_info(body, &constraint)
} else {
- (constraint.category, false, constraint.locations.span(body))
+ BlameConstraint {
+ category: constraint.category,
+ from_closure: false,
+ span: constraint.locations.span(body),
+ variance_info: constraint.variance_info.clone(),
+ }
}
})
.collect();
};
let find_region = |i: &usize| {
- let constraint = path[*i];
+ let constraint = &path[*i];
let constraint_sup_scc = self.constraint_sccs.scc(constraint.sup);
if blame_source {
- match categorized_path[*i].0 {
+ match categorized_path[*i].category {
ConstraintCategory::OpaqueType
| ConstraintCategory::Boring
| ConstraintCategory::BoringNoLocation
_ => constraint_sup_scc != target_scc,
}
} else {
- match categorized_path[*i].0 {
+ match categorized_path[*i].category {
ConstraintCategory::OpaqueType
| ConstraintCategory::Boring
| ConstraintCategory::BoringNoLocation
if let Some(i) = best_choice {
if let Some(next) = categorized_path.get(i + 1) {
- if matches!(categorized_path[i].0, ConstraintCategory::Return(_))
- && next.0 == ConstraintCategory::OpaqueType
+ if matches!(categorized_path[i].category, ConstraintCategory::Return(_))
+ && next.category == ConstraintCategory::OpaqueType
{
// The return expression is being influenced by the return type being
// impl Trait, point at the return type and not the return expr.
- return *next;
+ return next.clone();
}
}
- if categorized_path[i].0 == ConstraintCategory::Return(ReturnConstraint::Normal) {
+ if categorized_path[i].category == ConstraintCategory::Return(ReturnConstraint::Normal)
+ {
let field = categorized_path.iter().find_map(|p| {
- if let ConstraintCategory::ClosureUpvar(f) = p.0 { Some(f) } else { None }
+ if let ConstraintCategory::ClosureUpvar(f) = p.category {
+ Some(f)
+ } else {
+ None
+ }
});
if let Some(field) = field {
- categorized_path[i].0 =
+ categorized_path[i].category =
ConstraintCategory::Return(ReturnConstraint::ClosureUpvar(field));
}
}
- return categorized_path[i];
+ return categorized_path[i].clone();
}
// If that search fails, that is.. unusual. Maybe everything
// is in the same SCC or something. In that case, find what
// appears to be the most interesting point to report to the
// user via an even more ad-hoc guess.
- categorized_path.sort_by(|p0, p1| p0.0.cmp(&p1.0));
+ categorized_path.sort_by(|p0, p1| p0.category.cmp(&p1.category));
debug!("`: sorted_path={:#?}", categorized_path);
- *categorized_path.first().unwrap()
+ categorized_path.remove(0)
}
}
.collect()
}
}
+
+#[derive(Clone, Debug)]
+pub struct BlameConstraint<'tcx> {
+ pub category: ConstraintCategory,
+ pub from_closure: bool,
+ pub span: Span,
+ pub variance_info: ty::VarianceDiagInfo<'tcx>,
+}
-use rustc_data_structures::fx::FxHashMap;
-use rustc_hir::def_id::DefId;
+use rustc_data_structures::vec_map::VecMap;
use rustc_infer::infer::InferCtxt;
-use rustc_middle::ty::{self, TyCtxt, TypeFoldable};
+use rustc_middle::ty::{self, OpaqueTypeKey, Ty, TyCtxt, TypeFoldable};
use rustc_span::Span;
use rustc_trait_selection::opaque_types::InferCtxtExt;
pub(in crate::borrow_check) fn infer_opaque_types(
&self,
infcx: &InferCtxt<'_, 'tcx>,
- opaque_ty_decls: FxHashMap<DefId, ty::ResolvedOpaqueTy<'tcx>>,
+ opaque_ty_decls: VecMap<OpaqueTypeKey<'tcx>, Ty<'tcx>>,
span: Span,
- ) -> FxHashMap<DefId, ty::ResolvedOpaqueTy<'tcx>> {
+ ) -> VecMap<OpaqueTypeKey<'tcx>, Ty<'tcx>> {
opaque_ty_decls
.into_iter()
- .map(|(opaque_def_id, ty::ResolvedOpaqueTy { concrete_type, substs })| {
+ .map(|(opaque_type_key, concrete_type)| {
+ let substs = opaque_type_key.substs;
debug!(?concrete_type, ?substs);
let mut subst_regions = vec![self.universal_regions.fr_static];
debug!(?universal_concrete_type, ?universal_substs);
+ let opaque_type_key =
+ OpaqueTypeKey { def_id: opaque_type_key.def_id, substs: universal_substs };
let remapped_type = infcx.infer_opaque_definition_from_instantiation(
- opaque_def_id,
- universal_substs,
+ opaque_type_key,
universal_concrete_type,
span,
);
- (
- opaque_def_id,
- ty::ResolvedOpaqueTy { concrete_type: remapped_type, substs: universal_substs },
- )
+ (opaque_type_key, remapped_type)
})
.collect()
}
category: self.category,
sub,
sup,
+ variance_info: ty::VarianceDiagInfo::default(),
});
}
fn regions_that_outlive_free_regions(
num_region_vars: usize,
universal_regions: &UniversalRegions<'tcx>,
- constraint_set: &OutlivesConstraintSet,
+ constraint_set: &OutlivesConstraintSet<'tcx>,
) -> FxHashSet<RegionVid> {
// Build a graph of the outlives constraints thus far. This is
// a reverse graph, so for each constraint `R1: R2` we have an
use rustc_data_structures::frozen::Frozen;
use rustc_data_structures::fx::{FxHashMap, FxHashSet};
+use rustc_data_structures::vec_map::VecMap;
use rustc_errors::struct_span_err;
use rustc_hir as hir;
-use rustc_hir::def_id::{DefId, LocalDefId};
+use rustc_hir::def_id::LocalDefId;
use rustc_hir::lang_items::LangItem;
use rustc_index::vec::{Idx, IndexVec};
use rustc_infer::infer::canonical::QueryRegionConstraints;
use rustc_middle::ty::fold::TypeFoldable;
use rustc_middle::ty::subst::{GenericArgKind, Subst, SubstsRef, UserSubsts};
use rustc_middle::ty::{
- self, CanonicalUserTypeAnnotation, CanonicalUserTypeAnnotations, RegionVid, ToPredicate, Ty,
- TyCtxt, UserType, UserTypeAnnotationIndex, WithConstness,
+ self, CanonicalUserTypeAnnotation, CanonicalUserTypeAnnotations, OpaqueTypeKey, RegionVid,
+ ToPredicate, Ty, TyCtxt, UserType, UserTypeAnnotationIndex, WithConstness,
};
use rustc_span::{Span, DUMMY_SP};
use rustc_target::abi::VariantIdx;
let _prof_timer = typeck.infcx.tcx.prof.generic_activity("polonius_fact_generation");
let location_table = cx.location_table;
facts.outlives.extend(cx.constraints.outlives_constraints.outlives().iter().flat_map(
- |constraint: &OutlivesConstraint| {
+ |constraint: &OutlivesConstraint<'_>| {
if let Some(from_location) = constraint.locations.from_location() {
Either::Left(iter::once((
constraint.sup,
let locations = location.to_locations();
for constraint in constraints.outlives().iter() {
- let mut constraint = *constraint;
+ let mut constraint = constraint.clone();
constraint.locations = locations;
if let ConstraintCategory::Return(_)
| ConstraintCategory::UseAsConst
reported_errors: FxHashSet<(Ty<'tcx>, Span)>,
borrowck_context: &'a mut BorrowCheckContext<'a, 'tcx>,
universal_region_relations: &'a UniversalRegionRelations<'tcx>,
- opaque_type_values: FxHashMap<DefId, ty::ResolvedOpaqueTy<'tcx>>,
+ opaque_type_values: VecMap<OpaqueTypeKey<'tcx>, Ty<'tcx>>,
}
struct BorrowCheckContext<'a, 'tcx> {
crate struct MirTypeckResults<'tcx> {
crate constraints: MirTypeckRegionConstraints<'tcx>,
pub(in crate::borrow_check) universal_region_relations: Frozen<UniversalRegionRelations<'tcx>>,
- crate opaque_type_values: FxHashMap<DefId, ty::ResolvedOpaqueTy<'tcx>>,
+ crate opaque_type_values: VecMap<OpaqueTypeKey<'tcx>, Ty<'tcx>>,
}
/// A collection of region constraints that must be satisfied for the
/// hence it must report on their liveness constraints.
crate liveness_constraints: LivenessValues<RegionVid>,
- crate outlives_constraints: OutlivesConstraintSet,
+ crate outlives_constraints: OutlivesConstraintSet<'tcx>,
crate member_constraints: MemberConstraintSet<'tcx, RegionVid>,
borrowck_context,
reported_errors: Default::default(),
universal_region_relations,
- opaque_type_values: FxHashMap::default(),
+ opaque_type_values: VecMap::default(),
};
checker.check_user_type_annotations();
checker
let param_env = self.param_env;
let body = self.body;
let concrete_opaque_types = &tcx.typeck(anon_owner_def_id).concrete_opaque_types;
- let mut opaque_type_values = Vec::new();
+ let mut opaque_type_values = VecMap::new();
debug!("eq_opaque_type_and_type: mir_def_id={:?}", body.source.def_id());
let opaque_type_map = self.fully_perform_op(
.eq(output_ty, revealed_ty)?,
);
- for (&opaque_def_id, opaque_decl) in &opaque_type_map {
+ for &(opaque_type_key, opaque_decl) in &opaque_type_map {
let resolved_ty = infcx.resolve_vars_if_possible(opaque_decl.concrete_ty);
let concrete_is_opaque = if let ty::Opaque(def_id, _) = resolved_ty.kind() {
- *def_id == opaque_def_id
+ *def_id == opaque_type_key.def_id
} else {
false
};
- let opaque_defn_ty = match concrete_opaque_types.get(&opaque_def_id) {
+
+ let concrete_ty = match concrete_opaque_types
+ .get_by(|(key, _)| key.def_id == opaque_type_key.def_id)
+ {
None => {
if !concrete_is_opaque {
tcx.sess.delay_span_bug(
body.span,
&format!(
"Non-defining use of {:?} with revealed type",
- opaque_def_id,
+ opaque_type_key.def_id,
),
);
}
continue;
}
- Some(opaque_defn_ty) => opaque_defn_ty,
+ Some(concrete_ty) => concrete_ty,
};
- debug!("opaque_defn_ty = {:?}", opaque_defn_ty);
- let subst_opaque_defn_ty =
- opaque_defn_ty.concrete_type.subst(tcx, opaque_decl.substs);
+ debug!("concrete_ty = {:?}", concrete_ty);
+ let subst_opaque_defn_ty = concrete_ty.subst(tcx, opaque_type_key.substs);
let renumbered_opaque_defn_ty =
renumber::renumber_regions(infcx, subst_opaque_defn_ty);
debug!(
"eq_opaque_type_and_type: concrete_ty={:?}={:?} opaque_defn_ty={:?}",
- opaque_decl.concrete_ty, resolved_ty, renumbered_opaque_defn_ty,
+ concrete_ty, resolved_ty, renumbered_opaque_defn_ty,
);
if !concrete_is_opaque {
.at(&ObligationCause::dummy(), param_env)
.eq(opaque_decl.concrete_ty, renumbered_opaque_defn_ty)?,
);
- opaque_type_values.push((
- opaque_def_id,
- ty::ResolvedOpaqueTy {
- concrete_type: renumbered_opaque_defn_ty,
- substs: opaque_decl.substs,
- },
- ));
+ opaque_type_values.insert(opaque_type_key, renumbered_opaque_defn_ty);
} else {
// We're using an opaque `impl Trait` type without
// 'revealing' it. For example, code like this:
// gets 'revealed' into
debug!(
"eq_opaque_type_and_type: non-defining use of {:?}",
- opaque_def_id,
+ opaque_type_key.def_id,
);
}
}
// prove that `T: Iterator` where `T` is the type we
// instantiated it with).
if let Some(opaque_type_map) = opaque_type_map {
- for (opaque_def_id, opaque_decl) in opaque_type_map {
+ for (opaque_type_key, opaque_decl) in opaque_type_map {
self.fully_perform_op(
locations,
ConstraintCategory::OpaqueType,
CustomTypeOp::new(
|_cx| {
infcx.constrain_opaque_type(
- opaque_def_id,
+ opaque_type_key,
&opaque_decl,
GenerateMemberConstraints::IfNoStaticBound,
universal_region_relations,
sub: borrow_region.to_region_vid(),
locations: location.to_locations(),
category,
+ variance_info: ty::VarianceDiagInfo::default(),
});
match mutbl {
)
}
- fn push_outlives(&mut self, sup: ty::Region<'tcx>, sub: ty::Region<'tcx>) {
+ fn push_outlives(
+ &mut self,
+ sup: ty::Region<'tcx>,
+ sub: ty::Region<'tcx>,
+ info: ty::VarianceDiagInfo<'tcx>,
+ ) {
if let Some(borrowck_context) = &mut self.borrowck_context {
let sub = borrowck_context.universal_regions.to_region_vid(sub);
let sup = borrowck_context.universal_regions.to_region_vid(sup);
sub,
locations: self.locations,
category: self.category,
+ variance_info: info,
});
}
}
use super::InterpCx;
use crate::interpret::{
- struct_error, ErrorHandled, FrameInfo, InterpError, InterpErrorInfo, Machine,
+ struct_error, ErrorHandled, FrameInfo, InterpError, InterpErrorInfo, Machine, MachineStopType,
};
/// The CTFE machine has some custom error kinds.
Abort(String),
}
+impl MachineStopType for ConstEvalErrKind {
+ fn is_hard_err(&self) -> bool {
+ match self {
+ Self::Panic { .. } => true,
+ _ => false,
+ }
+ }
+}
+
// The errors become `MachineStop` with plain strings when being raised.
// `ConstEvalErr` (in `librustc_middle/mir/interpret/error.rs`) knows to
// handle these.
impl<'tcx> Into<InterpErrorInfo<'tcx>> for ConstEvalErrKind {
fn into(self) -> InterpErrorInfo<'tcx> {
- err_machine_stop!(self.to_string()).into()
+ err_machine_stop!(self).into()
}
}
tcx: TyCtxtAt<'tcx>,
message: &str,
emit: impl FnOnce(DiagnosticBuilder<'_>),
- lint_root: Option<hir::HirId>,
+ mut lint_root: Option<hir::HirId>,
) -> ErrorHandled {
- let must_error = match self.error {
- err_inval!(Layout(LayoutError::Unknown(_))) | err_inval!(TooGeneric) => {
- return ErrorHandled::TooGeneric;
- }
- err_inval!(AlreadyReported(error_reported)) => {
- return ErrorHandled::Reported(error_reported);
- }
- // We must *always* hard error on these, even if the caller wants just a lint.
- err_inval!(Layout(LayoutError::SizeOverflow(_))) => true,
- _ => false,
- };
- trace!("reporting const eval failure at {:?}", self.span);
-
- let err_msg = match &self.error {
- InterpError::MachineStop(msg) => {
- // A custom error (`ConstEvalErrKind` in `librustc_mir/interp/const_eval/error.rs`).
- // Should be turned into a string by now.
- msg.downcast_ref::<String>().expect("invalid MachineStop payload").clone()
- }
- err => err.to_string(),
- };
-
let finish = |mut err: DiagnosticBuilder<'_>, span_msg: Option<String>| {
+ trace!("reporting const eval failure at {:?}", self.span);
if let Some(span_msg) = span_msg {
err.span_label(self.span, span_msg);
}
emit(err)
};
- if must_error {
- // The `message` makes little sense here, this is a more serious error than the
- // caller thinks anyway.
- // See <https://github.com/rust-lang/rust/pull/63152>.
- finish(struct_error(tcx, &err_msg), None);
- ErrorHandled::Reported(ErrorReported)
- } else {
- // Regular case.
- if let Some(lint_root) = lint_root {
- // Report as lint.
- let hir_id = self
- .stacktrace
- .iter()
- .rev()
- .find_map(|frame| frame.lint_root)
- .unwrap_or(lint_root);
- tcx.struct_span_lint_hir(
- rustc_session::lint::builtin::CONST_ERR,
- hir_id,
- tcx.span,
- |lint| finish(lint.build(message), Some(err_msg)),
- );
- ErrorHandled::Linted
- } else {
- // Report as hard error.
- finish(struct_error(tcx, message), Some(err_msg));
- ErrorHandled::Reported(ErrorReported)
+ // Special handling for certain errors
+ match &self.error {
+ // Don't emit a new diagnostic for these errors
+ err_inval!(Layout(LayoutError::Unknown(_))) | err_inval!(TooGeneric) => {
+ return ErrorHandled::TooGeneric;
+ }
+ err_inval!(AlreadyReported(error_reported)) => {
+ return ErrorHandled::Reported(*error_reported);
+ }
+ err_inval!(Layout(LayoutError::SizeOverflow(_))) => {
+ // We must *always* hard error on these, even if the caller wants just a lint.
+ // The `message` makes little sense here, this is a more serious error than the
+ // caller thinks anyway.
+ // See <https://github.com/rust-lang/rust/pull/63152>.
+ finish(struct_error(tcx, &self.error.to_string()), None);
+ return ErrorHandled::Reported(ErrorReported);
}
+ _ => {}
+ };
+
+ // If we have a 'hard error', then set `lint_root` to `None` so that we don't
+ // emit a lint.
+ if matches!(&self.error, InterpError::MachineStop(err) if err.is_hard_err()) {
+ lint_root = None;
+ }
+
+ let err_msg = self.error.to_string();
+
+ // Regular case - emit a lint.
+ if let Some(lint_root) = lint_root {
+ // Report as lint.
+ let hir_id =
+ self.stacktrace.iter().rev().find_map(|frame| frame.lint_root).unwrap_or(lint_root);
+ tcx.struct_span_lint_hir(
+ rustc_session::lint::builtin::CONST_ERR,
+ hir_id,
+ tcx.span,
+ |lint| finish(lint.build(message), Some(err_msg)),
+ );
+ ErrorHandled::Linted
+ } else {
+ // Report as hard error.
+ finish(struct_error(tcx, message), Some(err_msg));
+ ErrorHandled::Reported(ErrorReported)
}
}
}
use rustc_middle::ty::{self, subst::Subst, TyCtxt};
use rustc_span::source_map::Span;
use rustc_target::abi::{Abi, LayoutOf};
+use std::borrow::Cow;
use std::convert::TryInto;
pub fn note_on_undefined_behavior_error() -> &'static str {
))
} else {
let msg = if is_static {
- "could not evaluate static initializer"
+ Cow::from("could not evaluate static initializer")
} else {
- "evaluation of constant value failed"
+ // If the current item has generics, we'd like to enrich the message with the
+ // instance and its substs: to show the actual compile-time values, in addition to
+ // the expression, leading to the const eval error.
+ let instance = &key.value.instance;
+ if !instance.substs.is_empty() {
+ let instance = with_no_trimmed_paths(|| instance.to_string());
+ let msg = format!("evaluation of `{}` failed", instance);
+ Cow::from(msg)
+ } else {
+ Cow::from("evaluation of constant value failed")
+ }
};
- Err(err.report_as_error(ecx.tcx.at(ecx.cur_span()), msg))
+
+ Err(err.report_as_error(ecx.tcx.at(ecx.cur_span()), &msg))
}
}
Ok(mplace) => {
use crate::interpret::{
self, compile_time_machine, AllocId, Allocation, Frame, ImmTy, InterpCx, InterpResult, Memory,
- OpTy, PlaceTy, Pointer, Scalar,
+ OpTy, PlaceTy, Pointer, Scalar, StackPopUnwind,
};
use super::error::*;
_abi: Abi,
args: &[OpTy<'tcx>],
_ret: Option<(&PlaceTy<'tcx>, mir::BasicBlock)>,
- _unwind: Option<mir::BasicBlock>, // unwinding is not supported in consts
+ _unwind: StackPopUnwind, // unwinding is not supported in consts
) -> InterpResult<'tcx, Option<&'mir mir::Body<'tcx>>> {
debug!("find_mir_or_eval_fn: {:?}", instance);
instance: ty::Instance<'tcx>,
args: &[OpTy<'tcx>],
ret: Option<(&PlaceTy<'tcx>, mir::BasicBlock)>,
- _unwind: Option<mir::BasicBlock>,
+ _unwind: StackPopUnwind,
) -> InterpResult<'tcx> {
// Shared intrinsics.
if ecx.emulate_intrinsic(instance, args, ret)? {
// Check if we are assigning into a field of a union, if so, lookup the place
// of the union so it is marked as initialized again.
if let Some((place_base, ProjectionElem::Field(_, _))) = place.last_projection() {
- if let ty::Adt(def, _) = place_base.ty(self.builder.body, self.builder.tcx).ty.kind() {
- if def.is_union() {
- place = place_base;
- }
+ if place_base.ty(self.builder.body, self.builder.tcx).ty.is_union() {
+ place = place_base;
}
}
pub lint_root: Option<hir::HirId>,
}
-#[derive(Clone, Eq, PartialEq, Debug, HashStable)] // Miri debug-prints these
+/// Unwind information.
+#[derive(Clone, Copy, Eq, PartialEq, Debug, HashStable)]
+pub enum StackPopUnwind {
+ /// The cleanup block.
+ Cleanup(mir::BasicBlock),
+ /// No cleanup needs to be done.
+ Skip,
+ /// Unwinding is not allowed (UB).
+ NotAllowed,
+}
+
+#[derive(Clone, Copy, Eq, PartialEq, Debug, HashStable)] // Miri debug-prints these
pub enum StackPopCleanup {
/// Jump to the next block in the caller, or cause UB if None (that's a function
/// that may never return). Also store layout of return place so
/// we can validate it at that layout.
/// `ret` stores the block we jump to on a normal return, while `unwind`
/// stores the block used for cleanup during unwinding.
- Goto { ret: Option<mir::BasicBlock>, unwind: Option<mir::BasicBlock> },
+ Goto { ret: Option<mir::BasicBlock>, unwind: StackPopUnwind },
/// Just do nothing: Used by Main and for the `box_alloc` hook in miri.
/// `cleanup` says whether locals are deallocated. Static computation
/// wants them leaked to intern what they need (and just throw away
/// *Unwind* to the given `target` basic block.
/// Do *not* use for returning! Use `return_to_block` instead.
///
- /// If `target` is `None`, that indicates the function does not need cleanup during
- /// unwinding, and we will just keep propagating that upwards.
- pub fn unwind_to_block(&mut self, target: Option<mir::BasicBlock>) {
+ /// If `target` is `StackPopUnwind::Skip`, that indicates the function does not need cleanup
+ /// during unwinding, and we will just keep propagating that upwards.
+ ///
+ /// If `target` is `StackPopUnwind::NotAllowed`, that indicates the function does not allow
+ /// unwinding, and doing so is UB.
+ pub fn unwind_to_block(&mut self, target: StackPopUnwind) -> InterpResult<'tcx> {
self.frame_mut().loc = match target {
- Some(block) => Ok(mir::Location { block, statement_index: 0 }),
- None => Err(self.frame_mut().body.span),
+ StackPopUnwind::Cleanup(block) => Ok(mir::Location { block, statement_index: 0 }),
+ StackPopUnwind::Skip => Err(self.frame_mut().body.span),
+ StackPopUnwind::NotAllowed => {
+ throw_ub_format!("unwinding past a stack frame that does not allow unwinding")
+ }
};
+ Ok(())
}
/// Pops the current frame from the stack, deallocating the
}
}
+ let return_to_block = frame.return_to_block;
+
// Now where do we jump next?
// Usually we want to clean up (deallocate locals), but in a few rare cases we don't.
// In that case, we return early. We also avoid validation in that case,
// because this is CTFE and the final value will be thoroughly validated anyway.
- let (cleanup, next_block) = match frame.return_to_block {
- StackPopCleanup::Goto { ret, unwind } => {
- (true, Some(if unwinding { unwind } else { ret }))
- }
- StackPopCleanup::None { cleanup, .. } => (cleanup, None),
+ let cleanup = match return_to_block {
+ StackPopCleanup::Goto { .. } => true,
+ StackPopCleanup::None { cleanup, .. } => cleanup,
};
if !cleanup {
assert!(self.stack().is_empty(), "only the topmost frame should ever be leaked");
- assert!(next_block.is_none(), "tried to skip cleanup when we have a next block!");
assert!(!unwinding, "tried to skip cleanup during unwinding");
// Leak the locals, skip validation, skip machine hook.
return Ok(());
// Normal return, figure out where to jump.
if unwinding {
// Follow the unwind edge.
- let unwind = next_block.expect("Encountered StackPopCleanup::None when unwinding!");
- self.unwind_to_block(unwind);
+ let unwind = match return_to_block {
+ StackPopCleanup::Goto { unwind, .. } => unwind,
+ StackPopCleanup::None { .. } => {
+ panic!("Encountered StackPopCleanup::None when unwinding!")
+ }
+ };
+ self.unwind_to_block(unwind)
} else {
// Follow the normal return edge.
- if let Some(ret) = next_block {
- self.return_to_block(ret)?;
+ match return_to_block {
+ StackPopCleanup::Goto { ret, .. } => self.return_to_block(ret),
+ StackPopCleanup::None { .. } => Ok(()),
}
}
-
- Ok(())
}
/// Mark a storage as live, killing the previous content.
let alloc = type_name::alloc_type_name(tcx, tp_ty);
ConstValue::Slice { data: alloc, start: 0, end: alloc.len() }
}
- sym::needs_drop => ConstValue::from_bool(tp_ty.needs_drop(tcx, param_env)),
+ sym::needs_drop => {
+ ensure_monomorphic_enough(tcx, tp_ty)?;
+ ConstValue::from_bool(tp_ty.needs_drop(tcx, param_env))
+ }
sym::min_align_of | sym::pref_align_of => {
+ // Correctly handles non-monomorphic calls, so there is no need for ensure_monomorphic_enough.
let layout = tcx.layout_of(param_env.and(tp_ty)).map_err(|e| err_inval!(Layout(e)))?;
let n = match name {
sym::pref_align_of => layout.align.pref.bytes(),
ConstValue::from_u64(tcx.type_id_hash(tp_ty))
}
sym::variant_count => match tp_ty.kind() {
+ // Correctly handles non-monomorphic calls, so there is no need for ensure_monomorphic_enough.
ty::Adt(ref adt, _) => ConstValue::from_machine_usize(adt.variants.len() as u64, &tcx),
ty::Projection(_)
| ty::Opaque(_, _)
use rustc_hir::def_id::CrateNum;
-use rustc_hir::definitions::{DefPathData, DisambiguatedDefPathData};
+use rustc_hir::definitions::DisambiguatedDefPathData;
use rustc_middle::mir::interpret::Allocation;
use rustc_middle::ty::{
self,
}
fn path_crate(mut self, cnum: CrateNum) -> Result<Self::Path, Self::Error> {
- self.path.push_str(&self.tcx.original_crate_name(cnum).as_str());
+ self.path.push_str(&self.tcx.crate_name(cnum).as_str());
Ok(self)
}
) -> Result<Self::Path, Self::Error> {
self = print_prefix(self)?;
- // Skip `::{{constructor}}` on tuple/unit structs.
- if disambiguated_data.data == DefPathData::Ctor {
- return Ok(self);
- }
-
write!(self.path, "::{}", disambiguated_data.data).unwrap();
Ok(self)
use super::{
AllocId, Allocation, CheckInAllocMsg, Frame, ImmTy, InterpCx, InterpResult, LocalValue,
- MemPlace, Memory, MemoryKind, OpTy, Operand, PlaceTy, Pointer, Scalar,
+ MemPlace, Memory, MemoryKind, OpTy, Operand, PlaceTy, Pointer, Scalar, StackPopUnwind,
};
/// Data returned by Machine::stack_pop,
abi: Abi,
args: &[OpTy<'tcx, Self::PointerTag>],
ret: Option<(&PlaceTy<'tcx, Self::PointerTag>, mir::BasicBlock)>,
- unwind: Option<mir::BasicBlock>,
+ unwind: StackPopUnwind,
) -> InterpResult<'tcx, Option<&'mir mir::Body<'tcx>>>;
/// Execute `fn_val`. It is the hook's responsibility to advance the instruction
abi: Abi,
args: &[OpTy<'tcx, Self::PointerTag>],
ret: Option<(&PlaceTy<'tcx, Self::PointerTag>, mir::BasicBlock)>,
- unwind: Option<mir::BasicBlock>,
+ unwind: StackPopUnwind,
) -> InterpResult<'tcx>;
/// Directly process an intrinsic without pushing a stack frame. It is the hook's
instance: ty::Instance<'tcx>,
args: &[OpTy<'tcx, Self::PointerTag>],
ret: Option<(&PlaceTy<'tcx, Self::PointerTag>, mir::BasicBlock)>,
- unwind: Option<mir::BasicBlock>,
+ unwind: StackPopUnwind,
) -> InterpResult<'tcx>;
/// Called to evaluate `Assert` MIR terminators that trigger a panic.
_abi: Abi,
_args: &[OpTy<$tcx>],
_ret: Option<(&PlaceTy<$tcx>, mir::BasicBlock)>,
- _unwind: Option<mir::BasicBlock>,
+ _unwind: StackPopUnwind,
) -> InterpResult<$tcx> {
match fn_val {}
}
pub use rustc_middle::mir::interpret::*; // have all the `interpret` symbols in one place: here
-pub use self::eval_context::{Frame, FrameInfo, InterpCx, LocalState, LocalValue, StackPopCleanup};
+pub use self::eval_context::{
+ Frame, FrameInfo, InterpCx, LocalState, LocalValue, StackPopCleanup, StackPopUnwind,
+};
pub use self::intern::{intern_const_alloc_recursive, InternKind};
pub use self::machine::{compile_time_machine, AllocMap, Machine, MayLeak, StackPopJump};
pub use self::memory::{AllocCheck, AllocRef, AllocRefMut, FnVal, Memory, MemoryKind};
use rustc_target::abi::{HasDataLayout, LayoutOf, Size, VariantIdx, Variants};
use super::{
- alloc_range, mir_assign_valid_types, AllocId, AllocMap, AllocRef, AllocRefMut, Allocation,
- ConstAlloc, ImmTy, Immediate, InterpCx, InterpResult, LocalValue, Machine, MemoryKind, OpTy,
- Operand, Pointer, PointerArithmetic, Scalar, ScalarMaybeUninit,
+ alloc_range, mir_assign_valid_types, AllocRef, AllocRefMut, ConstAlloc, ImmTy, Immediate,
+ InterpCx, InterpResult, LocalValue, Machine, MemoryKind, OpTy, Operand, Pointer,
+ PointerArithmetic, Scalar, ScalarMaybeUninit,
};
#[derive(Copy, Clone, Debug, Hash, PartialEq, Eq, HashStable)]
// FIXME: Working around https://github.com/rust-lang/rust/issues/54385
Tag: Debug + Copy + Eq + Hash + 'static,
M: Machine<'mir, 'tcx, PointerTag = Tag>,
- // FIXME: Working around https://github.com/rust-lang/rust/issues/24159
- M::MemoryMap: AllocMap<AllocId, (MemoryKind<M::MemoryKind>, Allocation<Tag, M::AllocExtra>)>,
{
/// Take a value, which represents a (thin or wide) reference, and make it a place.
/// Alignment is just based on the type. This is the inverse of `MemPlace::to_ref()`.
use std::borrow::Cow;
use std::convert::TryFrom;
-use rustc_middle::ty::layout::TyAndLayout;
+use rustc_middle::middle::codegen_fn_attrs::CodegenFnAttrFlags;
+use rustc_middle::ty::layout::{self, TyAndLayout};
use rustc_middle::ty::Instance;
use rustc_middle::{
mir,
use super::{
FnVal, ImmTy, InterpCx, InterpResult, MPlaceTy, Machine, OpTy, PlaceTy, StackPopCleanup,
+ StackPopUnwind,
};
impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
+ fn fn_can_unwind(&self, attrs: CodegenFnAttrFlags, abi: Abi) -> bool {
+ layout::fn_can_unwind(
+ self.tcx.sess.panic_strategy(),
+ attrs,
+ layout::conv_from_spec_abi(*self.tcx, abi),
+ abi,
+ )
+ }
+
pub(super) fn eval_terminator(
&mut self,
terminator: &mir::Terminator<'tcx>,
let old_stack = self.frame_idx();
let old_loc = self.frame().loc;
let func = self.eval_operand(func, None)?;
- let (fn_val, abi) = match *func.layout.ty.kind() {
+ let (fn_val, abi, caller_can_unwind) = match *func.layout.ty.kind() {
ty::FnPtr(sig) => {
let caller_abi = sig.abi();
let fn_ptr = self.read_scalar(&func)?.check_init()?;
let fn_val = self.memory.get_fn(fn_ptr)?;
- (fn_val, caller_abi)
+ (
+ fn_val,
+ caller_abi,
+ self.fn_can_unwind(layout::fn_ptr_codegen_fn_attr_flags(), caller_abi),
+ )
}
ty::FnDef(def_id, substs) => {
let sig = func.layout.ty.fn_sig(*self.tcx);
self.resolve(ty::WithOptConstParam::unknown(def_id), substs)?,
),
sig.abi(),
+ self.fn_can_unwind(self.tcx.codegen_fn_attrs(def_id).flags, sig.abi()),
)
}
_ => span_bug!(
}
None => None,
};
- self.eval_fn_call(fn_val, abi, &args[..], ret, *cleanup)?;
+ self.eval_fn_call(
+ fn_val,
+ abi,
+ &args[..],
+ ret,
+ match (cleanup, caller_can_unwind) {
+ (Some(cleanup), true) => StackPopUnwind::Cleanup(*cleanup),
+ (None, true) => StackPopUnwind::Skip,
+ (_, false) => StackPopUnwind::NotAllowed,
+ },
+ )?;
// Sanity-check that `eval_fn_call` either pushed a new frame or
// did a jump to another block.
if self.frame_idx() == old_stack && self.frame().loc == old_loc {
caller_abi: Abi,
args: &[OpTy<'tcx, M::PointerTag>],
ret: Option<(&PlaceTy<'tcx, M::PointerTag>, mir::BasicBlock)>,
- unwind: Option<mir::BasicBlock>,
+ mut unwind: StackPopUnwind,
) -> InterpResult<'tcx> {
trace!("eval_fn_call: {:#?}", fn_val);
}
};
+ let get_abi = |this: &Self, instance_ty: Ty<'tcx>| match instance_ty.kind() {
+ ty::FnDef(..) => instance_ty.fn_sig(*this.tcx).abi(),
+ ty::Closure(..) => Abi::RustCall,
+ ty::Generator(..) => Abi::Rust,
+ _ => span_bug!(this.cur_span(), "unexpected callee ty: {:?}", instance_ty),
+ };
+
// ABI check
- let check_abi = |this: &Self, instance_ty: Ty<'tcx>| -> InterpResult<'tcx> {
- if M::enforce_abi(this) {
- let callee_abi = match instance_ty.kind() {
- ty::FnDef(..) => instance_ty.fn_sig(*this.tcx).abi(),
- ty::Closure(..) => Abi::RustCall,
- ty::Generator(..) => Abi::Rust,
- _ => span_bug!(this.cur_span(), "unexpected callee ty: {:?}", instance_ty),
- };
- let normalize_abi = |abi| match abi {
- Abi::Rust | Abi::RustCall | Abi::RustIntrinsic | Abi::PlatformIntrinsic =>
- // These are all the same ABI, really.
- {
- Abi::Rust
- }
- abi => abi,
- };
- if normalize_abi(caller_abi) != normalize_abi(callee_abi) {
- throw_ub_format!(
- "calling a function with ABI {} using caller ABI {}",
- callee_abi.name(),
- caller_abi.name()
- )
+ let check_abi = |callee_abi: Abi| -> InterpResult<'tcx> {
+ let normalize_abi = |abi| match abi {
+ Abi::Rust | Abi::RustCall | Abi::RustIntrinsic | Abi::PlatformIntrinsic =>
+ // These are all the same ABI, really.
+ {
+ Abi::Rust
}
+ abi => abi,
+ };
+ if normalize_abi(caller_abi) != normalize_abi(callee_abi) {
+ throw_ub_format!(
+ "calling a function with ABI {} using caller ABI {}",
+ callee_abi.name(),
+ caller_abi.name()
+ )
}
Ok(())
};
match instance.def {
ty::InstanceDef::Intrinsic(..) => {
- check_abi(self, instance.ty(*self.tcx, self.param_env))?;
+ if M::enforce_abi(self) {
+ check_abi(get_abi(self, instance.ty(*self.tcx, self.param_env)))?;
+ }
assert!(caller_abi == Abi::RustIntrinsic || caller_abi == Abi::PlatformIntrinsic);
M::call_intrinsic(self, instance, args, ret, unwind)
}
// Check against the ABI of the MIR body we are calling (not the ABI of `instance`;
// these can differ when `find_mir_or_eval_fn` does something clever like resolve
// exported symbol names).
- check_abi(self, self.tcx.type_of(body.source.def_id()))?;
+ let callee_def_id = body.source.def_id();
+ let callee_abi = get_abi(self, self.tcx.type_of(callee_def_id));
+
+ if M::enforce_abi(self) {
+ check_abi(callee_abi)?;
+ }
+
+ if !matches!(unwind, StackPopUnwind::NotAllowed)
+ && !self
+ .fn_can_unwind(self.tcx.codegen_fn_attrs(callee_def_id).flags, callee_abi)
+ {
+ // The callee cannot unwind.
+ unwind = StackPopUnwind::NotAllowed;
+ }
self.push_stack_frame(
instance,
Abi::Rust,
&[arg.into()],
Some((&dest.into(), target)),
- unwind,
+ match unwind {
+ Some(cleanup) => StackPopUnwind::Cleanup(cleanup),
+ None => StackPopUnwind::Skip,
+ },
)
}
}
use std::convert::TryFrom;
use rustc_middle::mir::interpret::{InterpResult, Pointer, PointerArithmetic, Scalar};
-use rustc_middle::ty::{self, Instance, Ty};
+use rustc_middle::ty::{
+ self, Instance, Ty, VtblEntry, COMMON_VTABLE_ENTRIES, COMMON_VTABLE_ENTRIES_ALIGN,
+ COMMON_VTABLE_ENTRIES_DROPINPLACE, COMMON_VTABLE_ENTRIES_SIZE,
+};
use rustc_target::abi::{Align, LayoutOf, Size};
use super::util::ensure_monomorphic_enough;
return Ok(vtable);
}
- let methods = if let Some(poly_trait_ref) = poly_trait_ref {
+ let vtable_entries = if let Some(poly_trait_ref) = poly_trait_ref {
let trait_ref = poly_trait_ref.with_self_ty(*self.tcx, ty);
let trait_ref = self.tcx.erase_regions(trait_ref);
- self.tcx.vtable_methods(trait_ref)
+ self.tcx.vtable_entries(trait_ref)
} else {
- &[]
+ COMMON_VTABLE_ENTRIES
};
let layout = self.layout_of(ty)?;
// If you touch this code, be sure to also make the corresponding changes to
// `get_vtable` in `rust_codegen_llvm/meth.rs`.
// /////////////////////////////////////////////////////////////////////////////////////////
- let vtable_size = ptr_size * u64::try_from(methods.len()).unwrap().checked_add(3).unwrap();
+ let vtable_size = ptr_size * u64::try_from(vtable_entries.len()).unwrap();
let vtable = self.memory.allocate(vtable_size, ptr_align, MemoryKind::Vtable);
let drop = Instance::resolve_drop_in_place(tcx, ty);
let drop = self.memory.create_fn_alloc(FnVal::Instance(drop));
- // Prepare the fn ptrs we will write into the vtable later.
- let fn_ptrs = methods
- .iter()
- .enumerate() // remember the original position
- .filter_map(|(i, method)| {
- if let Some((def_id, substs)) = method { Some((i, def_id, substs)) } else { None }
- })
- .map(|(i, def_id, substs)| {
- let instance =
- ty::Instance::resolve_for_vtable(tcx, self.param_env, *def_id, substs)
- .ok_or_else(|| err_inval!(TooGeneric))?;
- Ok((i, self.memory.create_fn_alloc(FnVal::Instance(instance))))
- })
- .collect::<InterpResult<'tcx, Vec<(usize, Pointer<M::PointerTag>)>>>()?;
-
// No need to do any alignment checks on the memory accesses below, because we know the
// allocation is correctly aligned as we created it above. Also we're only offsetting by
// multiples of `ptr_align`, which means that it will stay aligned to `ptr_align`.
+ let scalars = vtable_entries
+ .iter()
+ .map(|entry| -> InterpResult<'tcx, _> {
+ match entry {
+ VtblEntry::MetadataDropInPlace => Ok(Some(drop.into())),
+ VtblEntry::MetadataSize => Ok(Some(Scalar::from_uint(size, ptr_size).into())),
+ VtblEntry::MetadataAlign => Ok(Some(Scalar::from_uint(align, ptr_size).into())),
+ VtblEntry::Vacant => Ok(None),
+ VtblEntry::Method(def_id, substs) => {
+ // Prepare the fn ptr we write into the vtable.
+ let instance =
+ ty::Instance::resolve_for_vtable(tcx, self.param_env, *def_id, substs)
+ .ok_or_else(|| err_inval!(TooGeneric))?;
+ let fn_ptr = self.memory.create_fn_alloc(FnVal::Instance(instance));
+ Ok(Some(fn_ptr.into()))
+ }
+ }
+ })
+ .collect::<Result<Vec<_>, _>>()?;
let mut vtable_alloc =
self.memory.get_mut(vtable.into(), vtable_size, ptr_align)?.expect("not a ZST");
- vtable_alloc.write_ptr_sized(ptr_size * 0, drop.into())?;
- vtable_alloc.write_ptr_sized(ptr_size * 1, Scalar::from_uint(size, ptr_size).into())?;
- vtable_alloc.write_ptr_sized(ptr_size * 2, Scalar::from_uint(align, ptr_size).into())?;
-
- for (i, fn_ptr) in fn_ptrs.into_iter() {
- vtable_alloc.write_ptr_sized(ptr_size * (3 + i as u64), fn_ptr.into())?;
+ for (idx, scalar) in scalars.into_iter().enumerate() {
+ if let Some(scalar) = scalar {
+ let idx: u64 = u64::try_from(idx).unwrap();
+ vtable_alloc.write_ptr_sized(ptr_size * idx, scalar)?;
+ }
}
M::after_static_mem_initialized(self, vtable, vtable_size)?;
}
/// Resolves the function at the specified slot in the provided
- /// vtable. An index of '0' corresponds to the first method
- /// declared in the trait of the provided vtable.
+ /// vtable. Currently an index of '3' (`COMMON_VTABLE_ENTRIES.len()`)
+ /// corresponds to the first method declared in the trait of the provided vtable.
pub fn get_vtable_slot(
&self,
vtable: Scalar<M::PointerTag>,
idx: u64,
) -> InterpResult<'tcx, FnVal<'tcx, M::ExtraFnVal>> {
let ptr_size = self.pointer_size();
- // Skip over the 'drop_ptr', 'size', and 'align' fields.
- let vtable_slot = vtable.ptr_offset(ptr_size * idx.checked_add(3).unwrap(), self)?;
+ let vtable_slot = vtable.ptr_offset(ptr_size * idx, self)?;
let vtable_slot = self
.memory
.get(vtable_slot, ptr_size, self.tcx.data_layout.pointer_align.abi)?
&self,
vtable: Scalar<M::PointerTag>,
) -> InterpResult<'tcx, (ty::Instance<'tcx>, Ty<'tcx>)> {
+ let pointer_size = self.pointer_size();
// We don't care about the pointee type; we just want a pointer.
let vtable = self
.memory
- .get(vtable, self.tcx.data_layout.pointer_size, self.tcx.data_layout.pointer_align.abi)?
+ .get(
+ vtable,
+ pointer_size * u64::try_from(COMMON_VTABLE_ENTRIES.len()).unwrap(),
+ self.tcx.data_layout.pointer_align.abi,
+ )?
.expect("cannot be a ZST");
- let drop_fn = vtable.read_ptr_sized(Size::ZERO)?.check_init()?;
+ let drop_fn = vtable
+ .read_ptr_sized(
+ pointer_size * u64::try_from(COMMON_VTABLE_ENTRIES_DROPINPLACE).unwrap(),
+ )?
+ .check_init()?;
// We *need* an instance here, no other kind of function value, to be able
// to determine the type.
let drop_instance = self.memory.get_fn(drop_fn)?.as_instance()?;
// The drop function takes `*mut T` where `T` is the type being dropped, so get that.
let args = fn_sig.inputs();
if args.len() != 1 {
- throw_ub!(InvalidDropFn(fn_sig));
+ throw_ub!(InvalidVtableDropFn(fn_sig));
}
- let ty = args[0].builtin_deref(true).ok_or_else(|| err_ub!(InvalidDropFn(fn_sig)))?.ty;
+ let ty =
+ args[0].builtin_deref(true).ok_or_else(|| err_ub!(InvalidVtableDropFn(fn_sig)))?.ty;
Ok((drop_instance, ty))
}
// the size, and the align (which we read below).
let vtable = self
.memory
- .get(vtable, 3 * pointer_size, self.tcx.data_layout.pointer_align.abi)?
+ .get(
+ vtable,
+ pointer_size * u64::try_from(COMMON_VTABLE_ENTRIES.len()).unwrap(),
+ self.tcx.data_layout.pointer_align.abi,
+ )?
.expect("cannot be a ZST");
- let size = vtable.read_ptr_sized(pointer_size)?.check_init()?;
+ let size = vtable
+ .read_ptr_sized(pointer_size * u64::try_from(COMMON_VTABLE_ENTRIES_SIZE).unwrap())?
+ .check_init()?;
let size = u64::try_from(self.force_bits(size, pointer_size)?).unwrap();
- let align = vtable.read_ptr_sized(pointer_size * 2)?.check_init()?;
+ let align = vtable
+ .read_ptr_sized(pointer_size * u64::try_from(COMMON_VTABLE_ENTRIES_ALIGN).unwrap())?
+ .check_init()?;
let align = u64::try_from(self.force_bits(align, pointer_size)?).unwrap();
+ let align = Align::from_bytes(align).map_err(|e| err_ub!(InvalidVtableAlignment(e)))?;
if size >= self.tcx.data_layout.obj_size_bound() {
- throw_ub_format!(
- "invalid vtable: \
- size is bigger than largest supported object"
- );
+ throw_ub!(InvalidVtableSize);
}
- Ok((Size::from_bytes(size), Align::from_bytes(align).unwrap()))
+ Ok((Size::from_bytes(size), align))
}
}
macro_rules! throw_validation_failure {
($where:expr, { $( $what_fmt:expr ),+ } $( expected { $( $expected_fmt:expr ),+ } )?) => {{
- let msg = rustc_middle::ty::print::with_no_trimmed_paths(|| {
- let mut msg = String::new();
- msg.push_str("encountered ");
- write!(&mut msg, $($what_fmt),+).unwrap();
+ let mut msg = String::new();
+ msg.push_str("encountered ");
+ write!(&mut msg, $($what_fmt),+).unwrap();
+ $(
+ msg.push_str(", but expected ");
+ write!(&mut msg, $($expected_fmt),+).unwrap();
+ )?
+ let path = rustc_middle::ty::print::with_no_trimmed_paths(|| {
let where_ = &$where;
if !where_.is_empty() {
- msg.push_str(" at ");
- write_path(&mut msg, where_);
+ let mut path = String::new();
+ write_path(&mut path, where_);
+ Some(path)
+ } else {
+ None
}
- $(
- msg.push_str(", but expected ");
- write!(&mut msg, $($expected_fmt),+).unwrap();
- )?
-
- msg
});
- throw_ub!(ValidationFailure(msg))
+ throw_ub!(ValidationFailure { path, msg })
}};
}
err_ub!(InvalidFunctionPointer(..)) |
err_unsup!(ReadBytesAsPointer) =>
{ "invalid drop function pointer in vtable (not pointing to a function)" },
- err_ub!(InvalidDropFn(..)) =>
+ err_ub!(InvalidVtableDropFn(..)) =>
{ "invalid drop function pointer in vtable (function has incompatible signature)" },
);
try_validation!(
self.ecx.read_size_and_align_from_vtable(vtable),
self.path,
+ err_ub!(InvalidVtableSize) =>
+ { "invalid vtable: size is bigger than largest supported object" },
+ err_ub!(InvalidVtableAlignment(msg)) =>
+ { "invalid vtable: alignment {}", msg },
err_unsup!(ReadPointerAsBytes) => { "invalid size or align in vtable" },
);
// FIXME: More checks for the vtable.
#![feature(bool_to_option)]
#![feature(box_patterns)]
#![feature(box_syntax)]
-#![feature(const_panic)]
#![feature(crate_visibility_modifier)]
#![feature(decl_macro)]
#![feature(exact_size_is_empty)]
-#![feature(exhaustive_patterns)]
+#![feature(format_args_capture)]
#![feature(iter_zip)]
#![feature(never_type)]
#![feature(map_try_insert)]
#![feature(min_specialization)]
-#![feature(slice_ptr_len)]
#![feature(slice_ptr_get)]
#![feature(trusted_len)]
#![feature(try_blocks)]
use rustc_data_structures::sync::{par_iter, MTLock, MTRef, ParallelIterator};
use rustc_errors::{ErrorReported, FatalError};
use rustc_hir as hir;
-use rustc_hir::def_id::{DefId, DefIdMap, LocalDefId};
+use rustc_hir::def_id::{DefId, DefIdMap, LocalDefId, LOCAL_CRATE};
use rustc_hir::itemlikevisit::ItemLikeVisitor;
use rustc_hir::lang_items::LangItem;
use rustc_index::bit_set::GrowableBitSet;
use rustc_middle::mir::visit::Visitor as MirVisitor;
use rustc_middle::mir::{self, Local, Location};
use rustc_middle::ty::adjustment::{CustomCoerceUnsized, PointerCast};
+use rustc_middle::ty::print::with_no_trimmed_paths;
use rustc_middle::ty::subst::{GenericArgKind, InternalSubsts};
-use rustc_middle::ty::{self, GenericParamDefKind, Instance, Ty, TyCtxt, TypeFoldable};
+use rustc_middle::ty::{self, GenericParamDefKind, Instance, Ty, TyCtxt, TypeFoldable, VtblEntry};
use rustc_middle::{middle::codegen_fn_attrs::CodegenFnAttrFlags, mir::visit::TyContext};
use rustc_session::config::EntryFnType;
use rustc_session::lint::builtin::LARGE_ASSIGNMENTS;
.collect()
}
-// Collect all monomorphized items reachable from `starting_point`
+/// Collect all monomorphized items reachable from `starting_point`, and emit a note diagnostic if a
+/// post-monorphization error is encountered during a collection step.
fn collect_items_rec<'tcx>(
tcx: TyCtxt<'tcx>,
starting_point: Spanned<MonoItem<'tcx>>,
let mut neighbors = Vec::new();
let recursion_depth_reset;
+ //
+ // Post-monomorphization errors MVP
+ //
+ // We can encounter errors while monomorphizing an item, but we don't have a good way of
+ // showing a complete stack of spans ultimately leading to collecting the erroneous one yet.
+ // (It's also currently unclear exactly which diagnostics and information would be interesting
+ // to report in such cases)
+ //
+ // This leads to suboptimal error reporting: a post-monomorphization error (PME) will be
+ // shown with just a spanned piece of code causing the error, without information on where
+ // it was called from. This is especially obscure if the erroneous mono item is in a
+ // dependency. See for example issue #85155, where, before minimization, a PME happened two
+ // crates downstream from libcore's stdarch, without a way to know which dependency was the
+ // cause.
+ //
+ // If such an error occurs in the current crate, its span will be enough to locate the
+ // source. If the cause is in another crate, the goal here is to quickly locate which mono
+ // item in the current crate is ultimately responsible for causing the error.
+ //
+ // To give at least _some_ context to the user: while collecting mono items, we check the
+ // error count. If it has changed, a PME occurred, and we trigger some diagnostics about the
+ // current step of mono items collection.
+ //
+ let error_count = tcx.sess.diagnostic().err_count();
+
match starting_point.node {
MonoItem::Static(def_id) => {
let instance = Instance::mono(tcx, def_id);
}
}
+ // Check for PMEs and emit a diagnostic if one happened. To try to show relevant edges of the
+ // mono item graph where the PME diagnostics are currently the most problematic (e.g. ones
+ // involving a dependency, and the lack of context is confusing) in this MVP, we focus on
+ // diagnostics on edges crossing a crate boundary: the collected mono items which are not
+ // defined in the local crate.
+ if tcx.sess.diagnostic().err_count() > error_count && starting_point.node.krate() != LOCAL_CRATE
+ {
+ let formatted_item = with_no_trimmed_paths(|| starting_point.node.to_string());
+ tcx.sess.span_note_without_error(
+ starting_point.span,
+ &format!("the above error was encountered while instantiating `{}`", formatted_item),
+ );
+ }
+
record_accesses(tcx, starting_point.node, neighbors.iter().map(|i| &i.node), inlining_map);
for neighbour in neighbors {
assert!(!poly_trait_ref.has_escaping_bound_vars());
// Walk all methods of the trait, including those of its supertraits
- let methods = tcx.vtable_methods(poly_trait_ref);
- let methods = methods
+ let entries = tcx.vtable_entries(poly_trait_ref);
+ let methods = entries
.iter()
- .cloned()
- .filter_map(|method| method)
- .map(|(def_id, substs)| {
- ty::Instance::resolve_for_vtable(
+ .filter_map(|entry| match entry {
+ VtblEntry::MetadataDropInPlace
+ | VtblEntry::MetadataSize
+ | VtblEntry::MetadataAlign
+ | VtblEntry::Vacant => None,
+ VtblEntry::Method(def_id, substs) => ty::Instance::resolve_for_vtable(
tcx,
ty::ParamEnv::reveal_all(),
- def_id,
+ *def_id,
substs,
)
- .unwrap()
+ .filter(|instance| should_codegen_locally(tcx, instance)),
})
- .filter(|&instance| should_codegen_locally(tcx, &instance))
.map(|item| create_fn_mono_item(tcx, item, source));
output.extend(methods);
}
}
fn check_static(&mut self, def_id: DefId, span: Span) {
- assert!(
- !self.tcx.is_thread_local_static(def_id),
- "tls access is checked in `Rvalue::ThreadLocalRef"
- );
+ if self.tcx.is_thread_local_static(def_id) {
+ self.tcx.sess.delay_span_bug(span, "tls access is checked in `Rvalue::ThreadLocalRef");
+ }
self.check_op_spanned(ops::StaticAccess, span)
}
let base_ty = Place::ty_from(place_local, proj_base, self.body, self.tcx).ty;
if let ty::RawPtr(_) = base_ty.kind() {
if proj_base.is_empty() {
- if let (local, []) = (place_local, proj_base) {
- let decl = &self.body.local_decls[local];
- if let Some(box LocalInfo::StaticRef { def_id, .. }) = decl.local_info {
- let span = decl.source_info.span;
- self.check_static(def_id, span);
- return;
- }
+ let decl = &self.body.local_decls[place_local];
+ if let Some(box LocalInfo::StaticRef { def_id, .. }) = decl.local_info {
+ let span = decl.source_info.span;
+ self.check_static(def_id, span);
+ return;
}
}
self.check_op(ops::RawPtrDeref);
| ProjectionElem::Field(..)
| ProjectionElem::Index(_) => {
let base_ty = Place::ty_from(place_local, proj_base, self.body, self.tcx).ty;
- match base_ty.ty_adt_def() {
- Some(def) if def.is_union() => {
- self.check_op(ops::UnionAccess);
- }
-
- _ => {}
+ if base_ty.is_union() {
+ self.check_op(ops::UnionAccess);
}
}
}
}
let base_ty = base.ty(self.body, self.tcx).ty;
- if base_ty.ty_adt_def().map_or(false, |adt| adt.is_union()) {
+ if base_ty.is_union() {
// If we did not hit a `Deref` yet and the overall place use is an assignment, the
// rules are different.
let assign_to_field = !saw_deref
/// Checks whether calling `func_did` needs an `unsafe` context or not, i.e. whether
/// the called function has target features the calling function hasn't.
fn check_target_features(&mut self, func_did: DefId) {
+ // Unsafety isn't required on wasm targets. For more information see
+ // the corresponding check in typeck/src/collect.rs
+ if self.tcx.sess.target.options.is_like_wasm {
+ return;
+ }
+
let callee_features = &self.tcx.codegen_fn_attrs(func_did).target_features;
let self_features = &self.tcx.codegen_fn_attrs(self.body_did).target_features;
// if we applied optimizations, we potentially have some cfg to cleanup to
// make it easier for further passes
if should_simplify {
- simplify_cfg(body);
+ simplify_cfg(tcx, body);
simplify_locals(body, tcx);
}
}
self, compile_time_machine, AllocId, Allocation, ConstValue, CtfeValidationMode, Frame, ImmTy,
Immediate, InterpCx, InterpResult, LocalState, LocalValue, MemPlace, Memory, MemoryKind, OpTy,
Operand as InterpOperand, PlaceTy, Pointer, Scalar, ScalarMaybeUninit, StackPopCleanup,
+ StackPopUnwind,
};
use crate::transform::MirPass;
_abi: Abi,
_args: &[OpTy<'tcx>],
_ret: Option<(&PlaceTy<'tcx>, BasicBlock)>,
- _unwind: Option<BasicBlock>,
+ _unwind: StackPopUnwind,
) -> InterpResult<'tcx, Option<&'mir Body<'tcx>>> {
Ok(None)
}
_instance: ty::Instance<'tcx>,
_args: &[OpTy<'tcx>],
_ret: Option<(&PlaceTy<'tcx>, BasicBlock)>,
- _unwind: Option<BasicBlock>,
+ _unwind: StackPopUnwind,
) -> InterpResult<'tcx> {
throw_machine_stop_str!("calling intrinsics isn't supported in ConstProp")
}
source_info: SourceInfo,
message: &'static str,
panic: AssertKind<impl std::fmt::Debug>,
- ) -> Option<()> {
- let lint_root = self.lint_root(source_info)?;
- self.tcx.struct_span_lint_hir(lint, lint_root, source_info.span, |lint| {
- let mut err = lint.build(message);
- err.span_label(source_info.span, format!("{:?}", panic));
- err.emit()
- });
- None
+ ) {
+ if let Some(lint_root) = self.lint_root(source_info) {
+ self.tcx.struct_span_lint_hir(lint, lint_root, source_info.span, |lint| {
+ let mut err = lint.build(message);
+ err.span_label(source_info.span, format!("{:?}", panic));
+ err.emit()
+ });
+ }
}
fn check_unary_op(
source_info,
"this arithmetic operation will overflow",
AssertKind::OverflowNeg(val.to_const_int()),
- )?;
+ );
+ return None;
}
Some(())
},
r.to_const_int(),
),
- )?;
+ );
+ return None;
}
}
source_info,
"this arithmetic operation will overflow",
AssertKind::Overflow(op, l.to_const_int(), r.to_const_int()),
- )?;
+ );
+ return None;
}
}
Some(())
use crate::util::spanview::{self, SpanViewable};
use rustc_data_structures::fx::FxHashMap;
-use rustc_index::vec::Idx;
use rustc_middle::mir::coverage::*;
use rustc_middle::mir::{self, BasicBlock, TerminatorKind};
use rustc_middle::ty::TyCtxt;
if has_opts_to_apply {
let mut opt_applier = OptApplier { tcx, duplicates };
opt_applier.visit_body(body);
- simplify_cfg(body);
+ simplify_cfg(tcx, body);
}
}
}
traversal, Body, InlineAsmOperand, Local, LocalKind, Location, Operand, Place, PlaceElem,
Rvalue, Statement, StatementKind, Terminator, TerminatorKind,
};
-use rustc_middle::ty::{self, Ty, TyCtxt};
+use rustc_middle::ty::TyCtxt;
// Empirical measurements have resulted in some observations:
// - Running on a body with a single block and 500 locals takes barely any time
// Handle the "subtle case" described above by rejecting any `dest` that is or
// projects through a union.
- let is_union = |ty: Ty<'_>| {
- if let ty::Adt(def, _) = ty.kind() {
- if def.is_union() {
- return true;
- }
- }
-
- false
- };
let mut place_ty = PlaceTy::from_ty(self.body.local_decls[dest.local].ty);
- if is_union(place_ty.ty) {
+ if place_ty.ty.is_union() {
return;
}
for elem in dest.projection {
}
place_ty = place_ty.projection_ty(self.tcx, elem);
- if is_union(place_ty.ty) {
+ if place_ty.ty.is_union() {
return;
}
}
// Since this optimization adds new basic blocks and invalidates others,
// clean up the cfg to make it nicer for other passes
if should_cleanup {
- simplify_cfg(body);
+ simplify_cfg(tcx, body);
}
}
}
// Make sure we remove dead blocks to remove
// unrelated code from the resume part of the function
- simplify::remove_dead_blocks(&mut body);
+ simplify::remove_dead_blocks(tcx, &mut body);
dump_mir(tcx, None, "generator_drop", &0, &body, |_, _| Ok(()));
// Make sure we remove dead blocks to remove
// unrelated code from the drop part of the function
- simplify::remove_dead_blocks(body);
+ simplify::remove_dead_blocks(tcx, body);
dump_mir(tcx, None, "generator_resume", &0, body, |_, _| Ok(()));
}
if inline(tcx, body) {
debug!("running simplify cfg on {:?}", body.source);
CfgSimplifier::new(body).simplify();
- remove_dead_blocks(body);
+ remove_dead_blocks(tcx, body);
}
}
}
use rustc_hir::Mutability;
use rustc_middle::mir::{
BinOp, Body, Constant, LocalDecls, Operand, Place, ProjectionElem, Rvalue, SourceInfo,
- StatementKind,
+ StatementKind, UnOp,
};
use rustc_middle::ty::{self, TyCtxt};
Rvalue::BinaryOp(op @ (BinOp::Eq | BinOp::Ne), box (a, b)) => {
let new = match (op, self.try_eval_bool(a), self.try_eval_bool(b)) {
// Transform "Eq(a, true)" ==> "a"
- (BinOp::Eq, _, Some(true)) => Some(a.clone()),
+ (BinOp::Eq, _, Some(true)) => Some(Rvalue::Use(a.clone())),
// Transform "Ne(a, false)" ==> "a"
- (BinOp::Ne, _, Some(false)) => Some(a.clone()),
+ (BinOp::Ne, _, Some(false)) => Some(Rvalue::Use(a.clone())),
// Transform "Eq(true, b)" ==> "b"
- (BinOp::Eq, Some(true), _) => Some(b.clone()),
+ (BinOp::Eq, Some(true), _) => Some(Rvalue::Use(b.clone())),
// Transform "Ne(false, b)" ==> "b"
- (BinOp::Ne, Some(false), _) => Some(b.clone()),
+ (BinOp::Ne, Some(false), _) => Some(Rvalue::Use(b.clone())),
- // FIXME: Consider combining remaining comparisons into logical operations:
// Transform "Eq(false, b)" ==> "Not(b)"
+ (BinOp::Eq, Some(false), _) => Some(Rvalue::UnaryOp(UnOp::Not, b.clone())),
+
// Transform "Ne(true, b)" ==> "Not(b)"
+ (BinOp::Ne, Some(true), _) => Some(Rvalue::UnaryOp(UnOp::Not, b.clone())),
+
// Transform "Eq(a, false)" ==> "Not(a)"
+ (BinOp::Eq, _, Some(false)) => Some(Rvalue::UnaryOp(UnOp::Not, a.clone())),
+
// Transform "Ne(a, true)" ==> "Not(a)"
+ (BinOp::Ne, _, Some(true)) => Some(Rvalue::UnaryOp(UnOp::Not, a.clone())),
+
_ => None,
};
if let Some(new) = new {
if self.should_combine(source_info, rvalue) {
- *rvalue = Rvalue::Use(new);
+ *rvalue = new;
}
}
}
}
if should_cleanup {
- simplify_cfg(body);
+ simplify_cfg(tcx, body);
}
}
}
}
}
- simplify::remove_dead_blocks(body)
+ simplify::remove_dead_blocks(tcx, body)
}
}
ProjectionElem::Field(..) => {
let base_ty = place_base.ty(self.body, self.tcx).ty;
- if let Some(def) = base_ty.ty_adt_def() {
+ if base_ty.is_union() {
// No promotion of union field accesses.
- if def.is_union() {
- return Err(Unpromotable);
- }
+ return Err(Unpromotable);
}
}
}
// if we applied optimizations, we potentially have some cfg to cleanup to
// make it easier for further passes
if should_simplify {
- simplify_cfg(body);
+ simplify_cfg(tcx, body);
}
}
}
let (basic_blocks, local_decls) = body.basic_blocks_and_local_decls_mut();
for block in basic_blocks.iter_mut() {
for statement in block.statements.iter_mut() {
- match statement.kind {
- StatementKind::Assign(box (place, _)) => {
- let place_ty = place.ty(local_decls, tcx).ty;
- if !maybe_zst(place_ty) {
- continue;
- }
- let layout = match tcx.layout_of(param_env.and(place_ty)) {
- Ok(layout) => layout,
- Err(_) => continue,
- };
- if !layout.is_zst() {
- continue;
- }
- if involves_a_union(place, local_decls, tcx) {
- continue;
- }
- if tcx.consider_optimizing(|| {
- format!(
- "RemoveZsts - Place: {:?} SourceInfo: {:?}",
- place, statement.source_info
- )
- }) {
- statement.make_nop();
- }
+ if let StatementKind::Assign(box (place, _)) = statement.kind {
+ let place_ty = place.ty(local_decls, tcx).ty;
+ if !maybe_zst(place_ty) {
+ continue;
+ }
+ let layout = match tcx.layout_of(param_env.and(place_ty)) {
+ Ok(layout) => layout,
+ Err(_) => continue,
+ };
+ if !layout.is_zst() {
+ continue;
+ }
+ if involves_a_union(place, local_decls, tcx) {
+ continue;
+ }
+ if tcx.consider_optimizing(|| {
+ format!(
+ "RemoveZsts - Place: {:?} SourceInfo: {:?}",
+ place, statement.source_info
+ )
+ }) {
+ statement.make_nop();
}
- _ => {}
}
}
}
tcx: TyCtxt<'tcx>,
) -> bool {
let mut place_ty = PlaceTy::from_ty(local_decls[place.local].ty);
- if is_union(place_ty.ty) {
+ if place_ty.ty.is_union() {
return true;
}
for elem in place.projection {
place_ty = place_ty.projection_ty(tcx, elem);
- if is_union(place_ty.ty) {
+ if place_ty.ty.is_union() {
return true;
}
}
return false;
}
-
-fn is_union(ty: Ty<'_>) -> bool {
- match ty.kind() {
- ty::Adt(def, _) if def.is_union() => true,
- _ => false,
- }
-}
use crate::transform::MirPass;
use rustc_index::vec::{Idx, IndexVec};
+use rustc_middle::mir::coverage::*;
use rustc_middle::mir::visit::{MutVisitor, MutatingUseContext, PlaceContext, Visitor};
use rustc_middle::mir::*;
use rustc_middle::ty::TyCtxt;
}
}
-pub fn simplify_cfg(body: &mut Body<'_>) {
+pub fn simplify_cfg(tcx: TyCtxt<'tcx>, body: &mut Body<'_>) {
CfgSimplifier::new(body).simplify();
- remove_dead_blocks(body);
+ remove_dead_blocks(tcx, body);
// FIXME: Should probably be moved into some kind of pass manager
body.basic_blocks_mut().raw.shrink_to_fit();
Cow::Borrowed(&self.label)
}
- fn run_pass(&self, _tcx: TyCtxt<'tcx>, body: &mut Body<'tcx>) {
+ fn run_pass(&self, tcx: TyCtxt<'tcx>, body: &mut Body<'tcx>) {
debug!("SimplifyCfg({:?}) - simplifying {:?}", self.label, body.source);
- simplify_cfg(body);
+ simplify_cfg(tcx, body);
}
}
}
}
-pub fn remove_dead_blocks(body: &mut Body<'_>) {
+pub fn remove_dead_blocks(tcx: TyCtxt<'tcx>, body: &mut Body<'_>) {
let reachable = traversal::reachable_as_bitset(body);
let num_blocks = body.basic_blocks().len();
if num_blocks == reachable.count() {
}
used_blocks += 1;
}
+
+ if tcx.sess.instrument_coverage() {
+ save_unreachable_coverage(basic_blocks, used_blocks);
+ }
+
basic_blocks.raw.truncate(used_blocks);
for block in basic_blocks {
}
}
+/// Some MIR transforms can determine at compile time that a sequences of
+/// statements will never be executed, so they can be dropped from the MIR.
+/// For example, an `if` or `else` block that is guaranteed to never be executed
+/// because its condition can be evaluated at compile time, such as by const
+/// evaluation: `if false { ... }`.
+///
+/// Those statements are bypassed by redirecting paths in the CFG around the
+/// `dead blocks`; but with `-Z instrument-coverage`, the dead blocks usually
+/// include `Coverage` statements representing the Rust source code regions to
+/// be counted at runtime. Without these `Coverage` statements, the regions are
+/// lost, and the Rust source code will show no coverage information.
+///
+/// What we want to show in a coverage report is the dead code with coverage
+/// counts of `0`. To do this, we need to save the code regions, by injecting
+/// `Unreachable` coverage statements. These are non-executable statements whose
+/// code regions are still recorded in the coverage map, representing regions
+/// with `0` executions.
+fn save_unreachable_coverage(
+ basic_blocks: &mut IndexVec<BasicBlock, BasicBlockData<'_>>,
+ first_dead_block: usize,
+) {
+ let has_live_counters = basic_blocks.raw[0..first_dead_block].iter().any(|live_block| {
+ live_block.statements.iter().any(|statement| {
+ if let StatementKind::Coverage(coverage) = &statement.kind {
+ matches!(coverage.kind, CoverageKind::Counter { .. })
+ } else {
+ false
+ }
+ })
+ });
+ if !has_live_counters {
+ // If there are no live `Counter` `Coverage` statements anymore, don't
+ // move dead coverage to the `START_BLOCK`. Just allow the dead
+ // `Coverage` statements to be dropped with the dead blocks.
+ //
+ // The `generator::StateTransform` MIR pass can create atypical
+ // conditions, where all live `Counter`s are dropped from the MIR.
+ //
+ // At least one Counter per function is required by LLVM (and necessary,
+ // to add the `function_hash` to the counter's call to the LLVM
+ // intrinsic `instrprof.increment()`).
+ return;
+ }
+
+ // Retain coverage info for dead blocks, so coverage reports will still
+ // report `0` executions for the uncovered code regions.
+ let mut dropped_coverage = Vec::new();
+ for dead_block in basic_blocks.raw[first_dead_block..].iter() {
+ for statement in dead_block.statements.iter() {
+ if let StatementKind::Coverage(coverage) = &statement.kind {
+ if let Some(code_region) = &coverage.code_region {
+ dropped_coverage.push((statement.source_info, code_region.clone()));
+ }
+ }
+ }
+ }
+
+ let start_block = &mut basic_blocks[START_BLOCK];
+ for (source_info, code_region) in dropped_coverage {
+ start_block.statements.push(Statement {
+ source_info,
+ kind: StatementKind::Coverage(box Coverage {
+ kind: CoverageKind::Unreachable,
+ code_region: Some(code_region),
+ }),
+ })
+ }
+}
+
pub struct SimplifyLocals;
impl<'tcx> MirPass<'tcx> for SimplifyLocals {
if did_remove_blocks {
// We have dead blocks now, so remove those.
- simplify::remove_dead_blocks(body);
+ simplify::remove_dead_blocks(tcx, body);
}
}
}
}
if replaced {
- simplify::remove_dead_blocks(body);
+ simplify::remove_dead_blocks(tcx, body);
}
}
}
use rustc_middle::mir::traversal;
use rustc_middle::mir::visit::{PlaceContext, Visitor};
use rustc_middle::mir::{
- AggregateKind, BasicBlock, Body, BorrowKind, Local, Location, MirPhase, Operand, PlaceRef,
- Rvalue, SourceScope, Statement, StatementKind, Terminator, TerminatorKind,
+ AggregateKind, BasicBlock, Body, BorrowKind, Local, Location, MirPhase, Operand, PlaceElem,
+ PlaceRef, ProjectionElem, Rvalue, SourceScope, Statement, StatementKind, Terminator,
+ TerminatorKind,
};
use rustc_middle::ty::fold::BottomUpFolder;
use rustc_middle::ty::{self, ParamEnv, Ty, TyCtxt, TypeFoldable};
self.super_operand(operand, location);
}
+ fn visit_projection_elem(
+ &mut self,
+ local: Local,
+ proj_base: &[PlaceElem<'tcx>],
+ elem: PlaceElem<'tcx>,
+ context: PlaceContext,
+ location: Location,
+ ) {
+ if let ProjectionElem::Index(index) = elem {
+ let index_ty = self.body.local_decls[index].ty;
+ if index_ty != self.tcx.types.usize {
+ self.fail(location, format!("bad index ({:?} != usize)", index_ty))
+ }
+ }
+ self.super_projection_elem(local, proj_base, elem, context, location);
+ }
+
fn visit_statement(&mut self, statement: &Statement<'tcx>, location: Location) {
match &statement.kind {
StatementKind::Assign(box (dest, rvalue)) => {
use gsgdt::{Edge, Graph, Node, NodeStyle};
use rustc_hir::def_id::DefId;
-use rustc_index::vec::Idx;
use rustc_middle::mir::*;
use rustc_middle::ty::TyCtxt;
});
filters.split('|').any(|or_filter| {
or_filter.split('&').all(|and_filter| {
- and_filter == "all" || pass_name.contains(and_filter) || node_path.contains(and_filter)
+ let and_filter_trimmed = and_filter.trim();
+ and_filter_trimmed == "all"
+ || pass_name.contains(and_filter_trimmed)
+ || node_path.contains(and_filter_trimmed)
})
})
}
match from_builder.base {
PlaceBase::Local(_) => Ok(from_builder),
PlaceBase::Upvar { var_hir_id, closure_def_id, closure_kind } => {
- // Captures are represented using fields inside a structure.
- // This represents accessing self in the closure structure
- let mut upvar_resolved_place_builder = PlaceBuilder::from(Local::new(1));
+ let mut upvar_resolved_place_builder = PlaceBuilder::from(ty::CAPTURE_STRUCT_LOCAL);
match closure_kind {
ty::ClosureKind::Fn | ty::ClosureKind::FnMut => {
upvar_resolved_place_builder = upvar_resolved_place_builder.deref();
// match x { _ => () } // fake read of `x`
// };
// ```
+ //
for (thir_place, cause, hir_id) in fake_reads.into_iter() {
let place_builder =
unpack!(block = this.as_place_builder(block, &this.thir[*thir_place]));
} => {
// Not in a closure
debug_assert!(
- local == Local::new(1),
+ local == ty::CAPTURE_STRUCT_LOCAL,
"Expected local to be Local(1), found {:?}",
local
);
this.cfg.push_assign(block, source_info, destination, address_of);
block.unit()
}
- ExprKind::Adt { adt_def, variant_index, substs, user_ty, ref fields, ref base } => {
+ ExprKind::Adt(box Adt {
+ adt_def,
+ variant_index,
+ substs,
+ user_ty,
+ ref fields,
+ ref base,
+ }) => {
// See the notes for `ExprKind::Array` in `as_rvalue` and for
// `ExprKind::Borrow` above.
let is_union = adt_def.is_union();
// the given closure and use the necessary information to create upvar
// debuginfo and to fill `self.upvar_mutbls`.
if hir_typeck_results.closure_min_captures.get(&fn_def_id).is_some() {
- let closure_env_arg = Local::new(1);
let mut closure_env_projs = vec![];
- let mut closure_ty = self.local_decls[closure_env_arg].ty;
+ let mut closure_ty = self.local_decls[ty::CAPTURE_STRUCT_LOCAL].ty;
if let ty::Ref(_, ty, _) = closure_ty.kind() {
closure_env_projs.push(ProjectionElem::Deref);
closure_ty = ty;
name,
source_info: SourceInfo::outermost(tcx_hir.span(var_id)),
value: VarDebugInfoContents::Place(Place {
- local: closure_env_arg,
+ local: ty::CAPTURE_STRUCT_LOCAL,
projection: tcx.intern_place_elems(&projs),
}),
});
self.warn_unused_unsafe(
hir_id,
block_span,
- Some(self.tcx.sess.source_map().guess_head_span(enclosing_span)),
+ Some((self.tcx.sess.source_map().guess_head_span(enclosing_span), "block")),
);
f(self);
} else {
f(self);
if let SafetyContext::UnsafeBlock { used: false, span, hir_id } = self.safety_context {
- self.warn_unused_unsafe(hir_id, span, self.body_unsafety.unsafe_fn_sig_span());
+ self.warn_unused_unsafe(
+ hir_id,
+ span,
+ if self.unsafe_op_in_unsafe_fn_allowed() {
+ self.body_unsafety.unsafe_fn_sig_span().map(|span| (span, "fn"))
+ } else {
+ None
+ },
+ );
}
self.safety_context = prev_context;
return;
SafetyContext::UnsafeFn if unsafe_op_in_unsafe_fn_allowed => {}
SafetyContext::UnsafeFn => {
// unsafe_op_in_unsafe_fn is disallowed
- struct_span_err!(
- self.tcx.sess,
+ self.tcx.struct_span_lint_hir(
+ UNSAFE_OP_IN_UNSAFE_FN,
+ self.hir_context,
span,
- E0133,
- "{} is unsafe and requires unsafe block",
- description,
+ |lint| {
+ lint.build(&format!(
+ "{} is unsafe and requires unsafe block (error E0133)",
+ description,
+ ))
+ .span_label(span, description)
+ .note(note)
+ .emit();
+ },
)
- .span_label(span, description)
- .note(note)
- .emit();
}
SafetyContext::Safe => {
let fn_sugg = if unsafe_op_in_unsafe_fn_allowed { " function or" } else { "" };
&self,
hir_id: hir::HirId,
block_span: Span,
- enclosing_span: Option<Span>,
+ enclosing_unsafe: Option<(Span, &'static str)>,
) {
let block_span = self.tcx.sess.source_map().guess_head_span(block_span);
self.tcx.struct_span_lint_hir(UNUSED_UNSAFE, hir_id, block_span, |lint| {
let msg = "unnecessary `unsafe` block";
let mut db = lint.build(msg);
db.span_label(block_span, msg);
- if let Some(enclosing_span) = enclosing_span {
- db.span_label(
- enclosing_span,
- format!("because it's nested under this `unsafe` block"),
- );
+ if let Some((span, kind)) = enclosing_unsafe {
+ db.span_label(span, format!("because it's nested under this `unsafe` {}", kind));
}
db.emit();
});
self.requires_unsafe(expr.span, CallToUnsafeFunction);
} else if let &ty::FnDef(func_did, _) = self.thir[fun].ty.kind() {
// If the called function has target features the calling function hasn't,
- // the call requires `unsafe`.
- if !self
- .tcx
- .codegen_fn_attrs(func_did)
- .target_features
- .iter()
- .all(|feature| self.body_target_features.contains(feature))
+ // the call requires `unsafe`. Don't check this on wasm
+ // targets, though. For more information on wasm see the
+ // is_like_wasm check in typeck/src/collect.rs
+ if !self.tcx.sess.target.options.is_like_wasm
+ && !self
+ .tcx
+ .codegen_fn_attrs(func_did)
+ .target_features
+ .iter()
+ .all(|feature| self.body_target_features.contains(feature))
{
self.requires_unsafe(expr.span, CallToFunctionWith);
}
ExprKind::InlineAsm { .. } | ExprKind::LlvmInlineAsm { .. } => {
self.requires_unsafe(expr.span, UseOfInlineAssembly);
}
- ExprKind::Adt {
+ ExprKind::Adt(box Adt {
adt_def,
variant_index: _,
substs: _,
user_ty: _,
fields: _,
base: _,
- } => match self.tcx.layout_scalar_valid_range(adt_def.did) {
+ }) => match self.tcx.layout_scalar_valid_range(adt_def.did) {
(Bound::Unbounded, Bound::Unbounded) => {}
_ => self.requires_unsafe(expr.span, InitializingTypeWith),
},
self.requires_unsafe(expr.span, CastOfPointerToInt);
}
}
+ ExprKind::Closure {
+ closure_id,
+ substs: _,
+ upvars: _,
+ movability: _,
+ fake_reads: _,
+ } => {
+ let closure_id = closure_id.expect_local();
+ let closure_def = if let Some((did, const_param_id)) =
+ ty::WithOptConstParam::try_lookup(closure_id, self.tcx)
+ {
+ ty::WithOptConstParam { did, const_param_did: Some(const_param_id) }
+ } else {
+ ty::WithOptConstParam::unknown(closure_id)
+ };
+ let (closure_thir, expr) = self.tcx.thir_body(closure_def);
+ let closure_thir = &closure_thir.borrow();
+ let hir_context = self.tcx.hir().local_def_id_to_hir_id(closure_id);
+ let mut closure_visitor =
+ UnsafetyVisitor { thir: closure_thir, hir_context, ..*self };
+ closure_visitor.visit_expr(&closure_thir[expr]);
+ // Unsafe blocks can be used in closures, make sure to take it into account
+ self.safety_context = closure_visitor.safety_context;
+ }
_ => {}
}
}
}
-// FIXME: checking unsafety for closures should be handled by their parent body,
-// as they inherit their "safety context" from their declaration site.
pub fn check_unsafety<'tcx>(tcx: TyCtxt<'tcx>, def: ty::WithOptConstParam<LocalDefId>) {
// THIR unsafeck is gated under `-Z thir-unsafeck`
if !tcx.sess.opts.debugging_opts.thir_unsafeck {
return;
}
+ // Closures are handled by their parent function
+ if tcx.is_closure(def.did.to_def_id()) {
+ tcx.ensure().thir_check_unsafety(tcx.hir().local_def_id_to_hir_id(def.did).owner);
+ return;
+ }
+
let (thir, expr) = tcx.thir_body(def);
let thir = &thir.borrow();
// If `thir` is empty, a type error occured, skip this body.
//! Construction of MIR from HIR.
//!
//! This crate also contains the match exhaustiveness and usefulness checking.
-#![feature(array_windows)]
#![feature(box_patterns)]
#![feature(box_syntax)]
-#![feature(const_panic)]
#![feature(control_flow_enum)]
#![feature(crate_visibility_modifier)]
#![feature(bool_to_option)]
#![feature(iter_zip)]
#![feature(once_cell)]
+#![feature(min_specialization)]
#![recursion_limit = "256"]
#[macro_use]
expr: self.mirror_expr(e),
})
.collect();
- ExprKind::Adt {
+ ExprKind::Adt(Box::new(Adt {
adt_def,
substs,
variant_index: index,
fields: field_refs,
user_ty,
base: None,
- }
+ }))
} else {
ExprKind::Call {
ty: self.typeck_results().node_type(fun.hir_id),
let user_provided_types = self.typeck_results().user_provided_types();
let user_ty = user_provided_types.get(expr.hir_id).copied();
debug!("make_mirror_unadjusted: (struct/union) user_ty={:?}", user_ty);
- ExprKind::Adt {
+ ExprKind::Adt(Box::new(Adt {
adt_def: adt,
variant_index: VariantIdx::new(0),
substs,
.copied()
.collect(),
}),
- }
+ }))
}
AdtKind::Enum => {
let res = self.typeck_results().qpath_res(qpath, expr.hir_id);
self.typeck_results().user_provided_types();
let user_ty = user_provided_types.get(expr.hir_id).copied();
debug!("make_mirror_unadjusted: (variant) user_ty={:?}", user_ty);
- ExprKind::Adt {
+ ExprKind::Adt(Box::new(Adt {
adt_def: adt,
variant_index: index,
substs,
user_ty,
fields: self.field_refs(fields),
base: None,
- }
+ }))
}
_ => {
span_bug!(expr.span, "unexpected res: {:?}", res);
match ty.kind() {
// A unit struct/variant which is used as a value.
// We return a completely different ExprKind here to account for this special case.
- ty::Adt(adt_def, substs) => ExprKind::Adt {
+ ty::Adt(adt_def, substs) => ExprKind::Adt(Box::new(Adt {
adt_def,
variant_index: adt_def.variant_index_with_ctor_id(def_id),
substs,
user_ty: user_provided_type,
fields: box [],
base: None,
- },
+ })),
_ => bug!("unexpected ty: {:?}", ty),
}
}
-use rustc_middle::thir::*;
+use rustc_middle::thir::{self, *};
use rustc_middle::ty::Const;
pub trait Visitor<'a, 'tcx: 'a>: Sized {
visitor.visit_expr(&visitor.thir()[field]);
}
}
- Adt { ref fields, ref base, adt_def: _, variant_index: _, substs: _, user_ty: _ } => {
+ Adt(box thir::Adt {
+ ref fields,
+ ref base,
+ adt_def: _,
+ variant_index: _,
+ substs: _,
+ user_ty: _,
+ }) => {
for field in &**fields {
visitor.visit_expr(&visitor.thir()[field.expr]);
}
#![feature(array_windows)]
#![feature(crate_visibility_modifier)]
#![feature(bindings_after_at)]
-#![feature(iter_order_by)]
#![feature(box_syntax)]
#![feature(box_patterns)]
#![recursion_limit = "256"]
let mut just_parsed_doc_comment = false;
let start_pos = self.token_cursor.num_next_calls;
loop {
- debug!("parse_outer_attributes: self.token={:?}", self.token);
let attr = if self.check(&token::Pound) {
let inner_error_reason = if just_parsed_doc_comment {
"an inner attribute is not permitted following an outer doc comment"
// If we support tokens at all
if let Some(target_tokens) = ret.tokens_mut() {
- if let Some(target_tokens) = target_tokens {
- assert!(
- !self.capture_cfg,
- "Encountered existing tokens with capture_cfg set: {:?}",
- target_tokens
- );
- } else {
+ if target_tokens.is_none() {
// Store se our newly captured tokens into the AST node
*target_tokens = Some(tokens.clone());
- };
+ }
}
let final_attrs = ret.attrs();
let mut snapshot = self.clone();
let path =
Path { segments: vec![], span: self.prev_token.span.shrink_to_lo(), tokens: None };
- let struct_expr = snapshot.parse_struct_expr(path, AttrVec::new(), false);
+ let struct_expr = snapshot.parse_struct_expr(None, path, AttrVec::new(), false);
let block_tail = self.parse_block_tail(lo, s, AttemptLocalParseRecovery::No);
return Some(match (struct_expr, block_tail) {
(Ok(expr), Err(mut err)) => {
/// Parses an expression, forcing tokens to be collected
pub fn parse_expr_force_collect(&mut self) -> PResult<'a, P<Expr>> {
- // If we have outer attributes, then the call to `collect_tokens_trailing_token`
- // will be made for us.
- if matches!(self.token.kind, TokenKind::Pound | TokenKind::DocComment(..)) {
- self.parse_expr()
- } else {
- // If we don't have outer attributes, then we need to ensure
- // that collection happens by using `collect_tokens_no_attrs`.
- // Expression don't support custom inner attributes, so `parse_expr`
- // will never try to collect tokens if we don't have outer attributes.
- self.collect_tokens_no_attrs(|this| this.parse_expr())
- }
+ self.collect_tokens_no_attrs(|this| this.parse_expr())
}
pub fn parse_anon_const_expr(&mut self) -> PResult<'a, AnonConst> {
self.parse_closure_expr(attrs)
} else if self.check(&token::OpenDelim(token::Bracket)) {
self.parse_array_or_repeat_expr(attrs)
- } else if self.eat_lt() {
- let (qself, path) = self.parse_qpath(PathStyle::Expr)?;
- Ok(self.mk_expr(lo.to(path.span), ExprKind::Path(Some(qself), path), attrs))
} else if self.check_path() {
self.parse_path_start_expr(attrs)
} else if self.check_keyword(kw::Move) || self.check_keyword(kw::Static) {
}
fn parse_path_start_expr(&mut self, attrs: AttrVec) -> PResult<'a, P<Expr>> {
- let path = self.parse_path(PathStyle::Expr)?;
+ let (qself, path) = if self.eat_lt() {
+ let (qself, path) = self.parse_qpath(PathStyle::Expr)?;
+ (Some(qself), path)
+ } else {
+ (None, self.parse_path(PathStyle::Expr)?)
+ };
let lo = path.span;
// `!`, as an operator, is prefix, so we know this isn't that.
let (hi, kind) = if self.eat(&token::Not) {
// MACRO INVOCATION expression
+ if qself.is_some() {
+ self.struct_span_err(path.span, "macros cannot use qualified paths").emit();
+ }
let mac = MacCall {
path,
args: self.parse_mac_args()?,
};
(self.prev_token.span, ExprKind::MacCall(mac))
} else if self.check(&token::OpenDelim(token::Brace)) {
- if let Some(expr) = self.maybe_parse_struct_expr(&path, &attrs) {
+ if let Some(expr) = self.maybe_parse_struct_expr(qself.as_ref(), &path, &attrs) {
+ if qself.is_some() {
+ self.sess.gated_spans.gate(sym::more_qualified_paths, path.span);
+ }
return expr;
} else {
- (path.span, ExprKind::Path(None, path))
+ (path.span, ExprKind::Path(qself, path))
}
} else {
- (path.span, ExprKind::Path(None, path))
+ (path.span, ExprKind::Path(qself, path))
};
let expr = self.mk_expr(lo.to(hi), kind, attrs);
fn maybe_parse_struct_expr(
&mut self,
+ qself: Option<&ast::QSelf>,
path: &ast::Path,
attrs: &AttrVec,
) -> Option<PResult<'a, P<Expr>>> {
if let Err(err) = self.expect(&token::OpenDelim(token::Brace)) {
return Some(Err(err));
}
- let expr = self.parse_struct_expr(path.clone(), attrs.clone(), true);
+ let expr = self.parse_struct_expr(qself.cloned(), path.clone(), attrs.clone(), true);
if let (Ok(expr), false) = (&expr, struct_allowed) {
// This is a struct literal, but we don't can't accept them here.
self.error_struct_lit_not_allowed_here(path.span, expr.span);
/// Precondition: already parsed the '{'.
pub(super) fn parse_struct_expr(
&mut self,
+ qself: Option<ast::QSelf>,
pth: ast::Path,
attrs: AttrVec,
recover: bool,
let expr = if recover_async {
ExprKind::Err
} else {
- ExprKind::Struct(P(ast::StructExpr { path: pth, fields, rest: base }))
+ ExprKind::Struct(P(ast::StructExpr { qself, path: pth, fields, rest: base }))
};
Ok(self.mk_expr(span, expr, attrs))
}
self.sess.gated_spans.gate(sym::unnamed_fields, lo);
} else {
let err = if self.check_fn_front_matter(false) {
- let _ = self.parse_fn(&mut Vec::new(), |_| true, lo);
+ // We use `parse_fn` to get a span for the function
+ if let Err(mut db) = self.parse_fn(&mut Vec::new(), |_| true, lo) {
+ db.delay_as_bug();
+ }
let mut err = self.struct_span_err(
lo.to(self.prev_token.span),
&format!("functions are not allowed in {} definitions", adt_ty),
/// Whether or not we should force collection of tokens for an AST node,
/// regardless of whether or not it has attributes
+#[derive(Clone, Copy, PartialEq)]
pub enum ForceCollect {
Yes,
No,
use rustc_ast::ptr::P;
use rustc_ast::token::{self, Nonterminal, NonterminalKind, Token};
+use rustc_ast::AstLike;
use rustc_ast_pretty::pprust;
use rustc_errors::PResult;
use rustc_span::symbol::{kw, Ident};
// which requires having captured tokens available. Since we cannot determine
// in advance whether or not a proc-macro will be (transitively) invoked,
// we always capture tokens for any `Nonterminal` which needs them.
- Ok(match kind {
+ let mut nt = match kind {
NonterminalKind::Item => match self.parse_item(ForceCollect::Yes)? {
Some(item) => token::NtItem(item),
None => {
return Err(self.struct_span_err(self.token.span, msg));
}
}
- })
+ };
+
+ // If tokens are supported at all, they should be collected.
+ if matches!(nt.tokens_mut(), Some(None)) {
+ panic!(
+ "Missing tokens for nt {:?} at {:?}: {:?}",
+ nt,
+ nt.span(),
+ pprust::nonterminal_to_string(&nt)
+ );
+ }
+
+ Ok(nt)
}
}
/// Parse a struct ("record") pattern (e.g. `Foo { ... }` or `Foo::Bar { ... }`).
fn parse_pat_struct(&mut self, qself: Option<QSelf>, path: Path) -> PResult<'a, PatKind> {
if qself.is_some() {
- return self.error_qpath_before_pat(&path, "{");
+ // Feature gate the use of qualified paths in patterns
+ self.sess.gated_spans.gate(sym::more_qualified_paths, path.span);
}
self.bump();
let (fields, etc) = self.parse_pat_fields().unwrap_or_else(|mut e| {
(vec![], true)
});
self.bump();
- Ok(PatKind::Struct(path, fields, etc))
+ Ok(PatKind::Struct(qself, path, fields, etc))
}
/// Parse tuple struct or tuple variant pattern (e.g. `Foo(...)` or `Foo::Bar(...)`).
fn parse_pat_tuple_struct(&mut self, qself: Option<QSelf>, path: Path) -> PResult<'a, PatKind> {
- if qself.is_some() {
- return self.error_qpath_before_pat(&path, "(");
- }
let (fields, _) =
self.parse_paren_comma_seq(|p| p.parse_pat_allow_top_alt(None, RecoverComma::No))?;
- Ok(PatKind::TupleStruct(path, fields))
- }
-
- /// Error when there's a qualified path, e.g. `<Foo as Bar>::Baz`
- /// as the path of e.g., a tuple or record struct pattern.
- fn error_qpath_before_pat(&mut self, path: &Path, token: &str) -> PResult<'a, PatKind> {
- let msg = &format!("unexpected `{}` after qualified path", token);
- let mut err = self.struct_span_err(self.token.span, msg);
- err.span_label(self.token.span, msg);
- err.span_label(path.span, "the qualified path");
- Err(err)
+ if qself.is_some() {
+ self.sess.gated_spans.gate(sym::more_qualified_paths, path.span);
+ }
+ Ok(PatKind::TupleStruct(qself, path, fields))
}
/// Parses the fields of a struct-like pattern.
debug!("parse_generic_args_with_leading_angle_bracket_recovery: (snapshotting)");
match self.parse_angle_args() {
Ok(args) => Ok(args),
- Err(ref mut e) if is_first_invocation && self.unmatched_angle_bracket_count > 0 => {
- // Cancel error from being unable to find `>`. We know the error
- // must have been this due to a non-zero unmatched angle bracket
- // count.
- e.cancel();
-
+ Err(mut e) if is_first_invocation && self.unmatched_angle_bracket_count > 0 => {
// Swap `self` with our backup of the parser state before attempting to parse
// generic arguments.
let snapshot = mem::replace(self, snapshot.unwrap());
- debug!(
- "parse_generic_args_with_leading_angle_bracket_recovery: (snapshot failure) \
- snapshot.count={:?}",
- snapshot.unmatched_angle_bracket_count,
- );
-
// Eat the unmatched angle brackets.
- for _ in 0..snapshot.unmatched_angle_bracket_count {
- self.eat_lt();
- }
-
- // Make a span over ${unmatched angle bracket count} characters.
- let span = lo.with_hi(lo.lo() + BytePos(snapshot.unmatched_angle_bracket_count));
- self.struct_span_err(
- span,
- &format!(
- "unmatched angle bracket{}",
- pluralize!(snapshot.unmatched_angle_bracket_count)
- ),
- )
- .span_suggestion(
- span,
- &format!(
- "remove extra angle bracket{}",
- pluralize!(snapshot.unmatched_angle_bracket_count)
- ),
- String::new(),
- Applicability::MachineApplicable,
- )
- .emit();
+ let all_angle_brackets = (0..snapshot.unmatched_angle_bracket_count)
+ .fold(true, |a, _| a && self.eat_lt());
+
+ if !all_angle_brackets {
+ // If there are other tokens in between the extraneous `<`s, we cannot simply
+ // suggest to remove them. This check also prevents us from accidentally ending
+ // up in the middle of a multibyte character (issue #84104).
+ let _ = mem::replace(self, snapshot);
+ Err(e)
+ } else {
+ // Cancel error from being unable to find `>`. We know the error
+ // must have been this due to a non-zero unmatched angle bracket
+ // count.
+ e.cancel();
+
+ debug!(
+ "parse_generic_args_with_leading_angle_bracket_recovery: (snapshot failure) \
+ snapshot.count={:?}",
+ snapshot.unmatched_angle_bracket_count,
+ );
+
+ // Make a span over ${unmatched angle bracket count} characters.
+ // This is safe because `all_angle_brackets` ensures that there are only `<`s,
+ // i.e. no multibyte characters, in this range.
+ let span =
+ lo.with_hi(lo.lo() + BytePos(snapshot.unmatched_angle_bracket_count));
+ self.struct_span_err(
+ span,
+ &format!(
+ "unmatched angle bracket{}",
+ pluralize!(snapshot.unmatched_angle_bracket_count)
+ ),
+ )
+ .span_suggestion(
+ span,
+ &format!(
+ "remove extra angle bracket{}",
+ pluralize!(snapshot.unmatched_angle_bracket_count)
+ ),
+ String::new(),
+ Applicability::MachineApplicable,
+ )
+ .emit();
- // Try again without unmatched angle bracket characters.
- self.parse_angle_args()
+ // Try again without unmatched angle bracket characters.
+ self.parse_angle_args()
+ }
}
Err(e) => Err(e),
}
// or `auto trait` items. We aim to parse an arbitrary path `a::b` but not something
// that starts like a path (1 token), but it fact not a path.
// Also, we avoid stealing syntax from `parse_item_`.
- self.parse_stmt_path_start(lo, attrs, force_collect)?
+ if force_collect == ForceCollect::Yes {
+ self.collect_tokens_no_attrs(|this| this.parse_stmt_path_start(lo, attrs))
+ } else {
+ self.parse_stmt_path_start(lo, attrs)
+ }?
} else if let Some(item) =
self.parse_item_common(attrs.clone(), false, true, |_| true, force_collect)?
{
self.mk_stmt(lo, StmtKind::Empty)
} else if self.token != token::CloseDelim(token::Brace) {
// Remainder are line-expr stmts.
- let e = self.parse_expr_res(Restrictions::STMT_EXPR, Some(attrs))?;
+ let e = if force_collect == ForceCollect::Yes {
+ self.collect_tokens_no_attrs(|this| {
+ this.parse_expr_res(Restrictions::STMT_EXPR, Some(attrs))
+ })
+ } else {
+ self.parse_expr_res(Restrictions::STMT_EXPR, Some(attrs))
+ }?;
self.mk_stmt(lo.to(e.span), StmtKind::Expr(e))
} else {
self.error_outer_attrs(&attrs.take_for_recovery());
}))
}
- fn parse_stmt_path_start(
- &mut self,
- lo: Span,
- attrs: AttrWrapper,
- force_collect: ForceCollect,
- ) -> PResult<'a, Stmt> {
- let stmt = self.collect_tokens_trailing_token(attrs, force_collect, |this, attrs| {
+ fn parse_stmt_path_start(&mut self, lo: Span, attrs: AttrWrapper) -> PResult<'a, Stmt> {
+ let stmt = self.collect_tokens_trailing_token(attrs, ForceCollect::No, |this, attrs| {
let path = this.parse_path(PathStyle::Expr)?;
if this.eat(&token::Not) {
}
let expr = if this.eat(&token::OpenDelim(token::Brace)) {
- this.parse_struct_expr(path, AttrVec::new(), true)?
+ this.parse_struct_expr(None, path, AttrVec::new(), true)?
} else {
let hi = this.prev_token.span;
this.mk_expr(lo.to(hi), ExprKind::Path(None, path), AttrVec::new())
mut bounds: GenericBounds,
plus: bool,
) -> PResult<'a, TyKind> {
- assert_ne!(self.token, token::Question);
if plus {
self.eat_plus(); // `+`, or `+=` gets split and `+` is discarded
bounds.append(&mut self.parse_generic_bounds(Some(self.prev_token.span))?);
_ => None,
}
}
+ // we check the validity of params elsewhere
+ Target::Param => return false,
_ => None,
} {
return err_fn(meta.span(), &format!("isn't allowed on {}", err));
target: Target,
specified_inline: &mut Option<(bool, Span)>,
) -> bool {
- if target == Target::Use {
+ if target == Target::Use || target == Target::ExternCrate {
let do_inline = meta.name_or_empty() == sym::inline;
if let Some((prev_inline, prev_span)) = *specified_inline {
if do_inline != prev_inline {
let mut is_valid = true;
if let Some(list) = attr.meta().and_then(|mi| mi.meta_item_list().map(|l| l.to_vec())) {
- for meta in list {
+ for meta in &list {
if let Some(i_meta) = meta.meta_item() {
match i_meta.name_or_empty() {
sym::alias
| sym::html_no_source
| sym::html_playground_url
| sym::html_root_url
- | sym::include
| sym::inline
| sym::issue_tracker_base_url
| sym::keyword
);
diag.note("`doc(spotlight)` is now a no-op");
}
+ if i_meta.has_name(sym::include) {
+ if let Some(value) = i_meta.value_str() {
+ // if there are multiple attributes, the suggestion would suggest deleting all of them, which is incorrect
+ let applicability = if list.len() == 1 {
+ Applicability::MachineApplicable
+ } else {
+ Applicability::MaybeIncorrect
+ };
+ let inner = if attr.style == AttrStyle::Inner {
+ "!"
+ } else {
+ ""
+ };
+ diag.span_suggestion(
+ attr.meta().unwrap().span,
+ "use `doc = include_str!` instead",
+ format!(
+ "#{}[doc = include_str!(\"{}\")]",
+ inner, value
+ ),
+ applicability,
+ );
+ }
+ }
diag.emit();
},
);
//! This API is completely unstable and subject to change.
#![doc(html_root_url = "https://doc.rust-lang.org/nightly/nightly-rustc/")]
-#![feature(const_panic)]
#![feature(crate_visibility_modifier)]
#![feature(in_band_lifetimes)]
#![feature(iter_zip)]
#![feature(nll)]
+#![feature(min_specialization)]
#![recursion_limit = "256"]
#[macro_use]
if !remaining_lib_features.is_empty() {
check_features(&mut remaining_lib_features, &local_defined_features);
- for &cnum in &*tcx.crates() {
+ for &cnum in tcx.crates() {
if remaining_lib_features.is_empty() {
break;
}
let leaf = leaf.subst(tcx, ct.substs);
self.visit_const(leaf)
}
+ ACNode::Cast(_, _, ty) => self.visit_ty(ty),
ACNode::Binop(..) | ACNode::UnaryOp(..) | ACNode::FunctionCall(_, _) => {
ControlFlow::CONTINUE
}
pub trait Key {
/// Given an instance of this key, what crate is it referring to?
/// This is used to find the provider.
- fn query_crate(&self) -> CrateNum;
+ fn query_crate_is_local(&self) -> bool;
/// In the event that a cycle occurs, if no explicit span has been
/// given for a query with key `self`, what span should we use?
}
impl Key for () {
- fn query_crate(&self) -> CrateNum {
- LOCAL_CRATE
+ #[inline(always)]
+ fn query_crate_is_local(&self) -> bool {
+ true
}
fn default_span(&self, _: TyCtxt<'_>) -> Span {
}
impl<'tcx> Key for ty::InstanceDef<'tcx> {
- fn query_crate(&self) -> CrateNum {
- LOCAL_CRATE
+ #[inline(always)]
+ fn query_crate_is_local(&self) -> bool {
+ true
}
fn default_span(&self, tcx: TyCtxt<'_>) -> Span {
}
impl<'tcx> Key for ty::Instance<'tcx> {
- fn query_crate(&self) -> CrateNum {
- LOCAL_CRATE
+ #[inline(always)]
+ fn query_crate_is_local(&self) -> bool {
+ true
}
fn default_span(&self, tcx: TyCtxt<'_>) -> Span {
}
impl<'tcx> Key for mir::interpret::GlobalId<'tcx> {
- fn query_crate(&self) -> CrateNum {
- self.instance.query_crate()
+ #[inline(always)]
+ fn query_crate_is_local(&self) -> bool {
+ true
}
fn default_span(&self, tcx: TyCtxt<'_>) -> Span {
}
impl<'tcx> Key for mir::interpret::LitToConstInput<'tcx> {
- fn query_crate(&self) -> CrateNum {
- LOCAL_CRATE
+ #[inline(always)]
+ fn query_crate_is_local(&self) -> bool {
+ true
}
fn default_span(&self, _tcx: TyCtxt<'_>) -> Span {
}
impl Key for CrateNum {
- fn query_crate(&self) -> CrateNum {
- *self
+ #[inline(always)]
+ fn query_crate_is_local(&self) -> bool {
+ *self == LOCAL_CRATE
}
fn default_span(&self, _: TyCtxt<'_>) -> Span {
DUMMY_SP
}
impl Key for LocalDefId {
- fn query_crate(&self) -> CrateNum {
- self.to_def_id().query_crate()
+ #[inline(always)]
+ fn query_crate_is_local(&self) -> bool {
+ true
}
fn default_span(&self, tcx: TyCtxt<'_>) -> Span {
self.to_def_id().default_span(tcx)
}
impl Key for DefId {
- fn query_crate(&self) -> CrateNum {
- self.krate
+ #[inline(always)]
+ fn query_crate_is_local(&self) -> bool {
+ self.krate == LOCAL_CRATE
}
fn default_span(&self, tcx: TyCtxt<'_>) -> Span {
tcx.def_span(*self)
}
impl Key for ty::WithOptConstParam<LocalDefId> {
- fn query_crate(&self) -> CrateNum {
- self.did.query_crate()
+ #[inline(always)]
+ fn query_crate_is_local(&self) -> bool {
+ true
}
fn default_span(&self, tcx: TyCtxt<'_>) -> Span {
self.did.default_span(tcx)
}
impl Key for (DefId, DefId) {
- fn query_crate(&self) -> CrateNum {
- self.0.krate
+ #[inline(always)]
+ fn query_crate_is_local(&self) -> bool {
+ self.0.krate == LOCAL_CRATE
}
fn default_span(&self, tcx: TyCtxt<'_>) -> Span {
self.1.default_span(tcx)
}
impl Key for (ty::Instance<'tcx>, LocalDefId) {
- fn query_crate(&self) -> CrateNum {
- self.0.query_crate()
+ #[inline(always)]
+ fn query_crate_is_local(&self) -> bool {
+ true
}
fn default_span(&self, tcx: TyCtxt<'_>) -> Span {
self.0.default_span(tcx)
}
impl Key for (DefId, LocalDefId) {
- fn query_crate(&self) -> CrateNum {
- self.0.krate
+ #[inline(always)]
+ fn query_crate_is_local(&self) -> bool {
+ self.0.krate == LOCAL_CRATE
}
fn default_span(&self, tcx: TyCtxt<'_>) -> Span {
self.1.default_span(tcx)
}
impl Key for (LocalDefId, DefId) {
- fn query_crate(&self) -> CrateNum {
- LOCAL_CRATE
+ #[inline(always)]
+ fn query_crate_is_local(&self) -> bool {
+ true
}
fn default_span(&self, tcx: TyCtxt<'_>) -> Span {
self.0.default_span(tcx)
}
impl Key for (DefId, Option<Ident>) {
- fn query_crate(&self) -> CrateNum {
- self.0.krate
+ #[inline(always)]
+ fn query_crate_is_local(&self) -> bool {
+ self.0.krate == LOCAL_CRATE
}
fn default_span(&self, tcx: TyCtxt<'_>) -> Span {
tcx.def_span(self.0)
}
impl Key for (DefId, LocalDefId, Ident) {
- fn query_crate(&self) -> CrateNum {
- self.0.krate
+ #[inline(always)]
+ fn query_crate_is_local(&self) -> bool {
+ self.0.krate == LOCAL_CRATE
}
fn default_span(&self, tcx: TyCtxt<'_>) -> Span {
self.1.default_span(tcx)
}
impl Key for (CrateNum, DefId) {
- fn query_crate(&self) -> CrateNum {
- self.0
+ #[inline(always)]
+ fn query_crate_is_local(&self) -> bool {
+ self.0 == LOCAL_CRATE
}
fn default_span(&self, tcx: TyCtxt<'_>) -> Span {
self.1.default_span(tcx)
}
impl Key for (DefId, SimplifiedType) {
- fn query_crate(&self) -> CrateNum {
- self.0.krate
+ #[inline(always)]
+ fn query_crate_is_local(&self) -> bool {
+ self.0.krate == LOCAL_CRATE
}
fn default_span(&self, tcx: TyCtxt<'_>) -> Span {
self.0.default_span(tcx)
}
impl<'tcx> Key for SubstsRef<'tcx> {
- fn query_crate(&self) -> CrateNum {
- LOCAL_CRATE
+ #[inline(always)]
+ fn query_crate_is_local(&self) -> bool {
+ true
}
fn default_span(&self, _: TyCtxt<'_>) -> Span {
DUMMY_SP
}
impl<'tcx> Key for (DefId, SubstsRef<'tcx>) {
- fn query_crate(&self) -> CrateNum {
- self.0.krate
+ #[inline(always)]
+ fn query_crate_is_local(&self) -> bool {
+ self.0.krate == LOCAL_CRATE
}
fn default_span(&self, tcx: TyCtxt<'_>) -> Span {
self.0.default_span(tcx)
(ty::WithOptConstParam<DefId>, SubstsRef<'tcx>),
)
{
- fn query_crate(&self) -> CrateNum {
- (self.0).0.did.krate
+ #[inline(always)]
+ fn query_crate_is_local(&self) -> bool {
+ (self.0).0.did.krate == LOCAL_CRATE
}
fn default_span(&self, tcx: TyCtxt<'_>) -> Span {
(self.0).0.did.default_span(tcx)
}
impl<'tcx> Key for (LocalDefId, DefId, SubstsRef<'tcx>) {
- fn query_crate(&self) -> CrateNum {
- LOCAL_CRATE
+ #[inline(always)]
+ fn query_crate_is_local(&self) -> bool {
+ true
}
fn default_span(&self, tcx: TyCtxt<'_>) -> Span {
self.0.default_span(tcx)
}
impl<'tcx> Key for (ty::ParamEnv<'tcx>, ty::PolyTraitRef<'tcx>) {
- fn query_crate(&self) -> CrateNum {
- self.1.def_id().krate
+ #[inline(always)]
+ fn query_crate_is_local(&self) -> bool {
+ self.1.def_id().krate == LOCAL_CRATE
}
fn default_span(&self, tcx: TyCtxt<'_>) -> Span {
tcx.def_span(self.1.def_id())
}
impl<'tcx> Key for (&'tcx ty::Const<'tcx>, mir::Field) {
- fn query_crate(&self) -> CrateNum {
- LOCAL_CRATE
+ #[inline(always)]
+ fn query_crate_is_local(&self) -> bool {
+ true
}
fn default_span(&self, _: TyCtxt<'_>) -> Span {
DUMMY_SP
}
impl<'tcx> Key for mir::interpret::ConstAlloc<'tcx> {
- fn query_crate(&self) -> CrateNum {
- LOCAL_CRATE
+ #[inline(always)]
+ fn query_crate_is_local(&self) -> bool {
+ true
}
fn default_span(&self, _: TyCtxt<'_>) -> Span {
DUMMY_SP
}
impl<'tcx> Key for ty::PolyTraitRef<'tcx> {
- fn query_crate(&self) -> CrateNum {
- self.def_id().krate
+ #[inline(always)]
+ fn query_crate_is_local(&self) -> bool {
+ self.def_id().krate == LOCAL_CRATE
}
fn default_span(&self, tcx: TyCtxt<'_>) -> Span {
tcx.def_span(self.def_id())
}
impl<'tcx> Key for GenericArg<'tcx> {
- fn query_crate(&self) -> CrateNum {
- LOCAL_CRATE
+ #[inline(always)]
+ fn query_crate_is_local(&self) -> bool {
+ true
}
fn default_span(&self, _: TyCtxt<'_>) -> Span {
DUMMY_SP
}
impl<'tcx> Key for mir::ConstantKind<'tcx> {
- fn query_crate(&self) -> CrateNum {
- LOCAL_CRATE
+ #[inline(always)]
+ fn query_crate_is_local(&self) -> bool {
+ true
}
fn default_span(&self, _: TyCtxt<'_>) -> Span {
DUMMY_SP
}
impl<'tcx> Key for &'tcx ty::Const<'tcx> {
- fn query_crate(&self) -> CrateNum {
- LOCAL_CRATE
+ #[inline(always)]
+ fn query_crate_is_local(&self) -> bool {
+ true
}
fn default_span(&self, _: TyCtxt<'_>) -> Span {
DUMMY_SP
}
impl<'tcx> Key for Ty<'tcx> {
- fn query_crate(&self) -> CrateNum {
- LOCAL_CRATE
+ #[inline(always)]
+ fn query_crate_is_local(&self) -> bool {
+ true
}
fn default_span(&self, _: TyCtxt<'_>) -> Span {
DUMMY_SP
}
impl<'tcx> Key for &'tcx ty::List<ty::Predicate<'tcx>> {
- fn query_crate(&self) -> CrateNum {
- LOCAL_CRATE
+ #[inline(always)]
+ fn query_crate_is_local(&self) -> bool {
+ true
}
fn default_span(&self, _: TyCtxt<'_>) -> Span {
DUMMY_SP
}
impl<'tcx> Key for ty::ParamEnv<'tcx> {
- fn query_crate(&self) -> CrateNum {
- LOCAL_CRATE
+ #[inline(always)]
+ fn query_crate_is_local(&self) -> bool {
+ true
}
fn default_span(&self, _: TyCtxt<'_>) -> Span {
DUMMY_SP
}
impl<'tcx, T: Key> Key for ty::ParamEnvAnd<'tcx, T> {
- fn query_crate(&self) -> CrateNum {
- self.value.query_crate()
+ #[inline(always)]
+ fn query_crate_is_local(&self) -> bool {
+ self.value.query_crate_is_local()
}
fn default_span(&self, tcx: TyCtxt<'_>) -> Span {
self.value.default_span(tcx)
}
impl Key for Symbol {
- fn query_crate(&self) -> CrateNum {
- LOCAL_CRATE
+ #[inline(always)]
+ fn query_crate_is_local(&self) -> bool {
+ true
}
fn default_span(&self, _tcx: TyCtxt<'_>) -> Span {
DUMMY_SP
/// Canonical query goals correspond to abstract trait operations that
/// are not tied to any crate in particular.
impl<'tcx, T> Key for Canonical<'tcx, T> {
- fn query_crate(&self) -> CrateNum {
- LOCAL_CRATE
+ #[inline(always)]
+ fn query_crate_is_local(&self) -> bool {
+ true
}
fn default_span(&self, _tcx: TyCtxt<'_>) -> Span {
}
impl Key for (Symbol, u32, u32) {
- fn query_crate(&self) -> CrateNum {
- LOCAL_CRATE
+ #[inline(always)]
+ fn query_crate_is_local(&self) -> bool {
+ true
}
fn default_span(&self, _tcx: TyCtxt<'_>) -> Span {
}
impl<'tcx> Key for (DefId, Ty<'tcx>, SubstsRef<'tcx>, ty::ParamEnv<'tcx>) {
- fn query_crate(&self) -> CrateNum {
- LOCAL_CRATE
+ #[inline(always)]
+ fn query_crate_is_local(&self) -> bool {
+ true
}
fn default_span(&self, _tcx: TyCtxt<'_>) -> Span {
#![doc(html_root_url = "https://doc.rust-lang.org/nightly/nightly-rustc/")]
#![feature(in_band_lifetimes)]
-#![feature(exhaustive_patterns)]
#![feature(nll)]
#![feature(min_specialization)]
-#![feature(crate_visibility_modifier)]
-#![feature(once_cell)]
#![feature(rustc_attrs)]
-#![feature(never_type)]
#![recursion_limit = "256"]
#[macro_use]
use rustc_data_structures::fingerprint::Fingerprint;
use rustc_data_structures::stable_hasher::{HashStable, StableHasher};
use rustc_errors::{DiagnosticBuilder, Handler};
-use rustc_hir::def_id::LOCAL_CRATE;
use rustc_middle::dep_graph;
use rustc_middle::ich::StableHashingContext;
use rustc_middle::ty::query::{query_keys, query_storage, query_stored, query_values};
use rustc_middle::ty::query::{Providers, QueryEngine};
use rustc_middle::ty::{self, TyCtxt};
use rustc_serialize::opaque;
-use rustc_span::{Span, DUMMY_SP};
+use rustc_span::Span;
#[macro_use]
mod plumbing;
//! manage the caches, and so forth.
use super::queries;
-use rustc_middle::dep_graph::{DepKind, DepNode, DepNodeExt, DepNodeIndex, SerializedDepNodeIndex};
+use rustc_middle::dep_graph::{DepKind, DepNode, DepNodeIndex, SerializedDepNodeIndex};
use rustc_middle::ty::query::on_disk_cache;
use rustc_middle::ty::tls::{self, ImplicitCtxt};
use rustc_middle::ty::{self, TyCtxt};
use rustc_data_structures::thin_vec::ThinVec;
use rustc_errors::Diagnostic;
use rustc_serialize::opaque;
-use rustc_span::def_id::{DefId, LocalDefId};
+use rustc_span::def_id::LocalDefId;
#[derive(Copy, Clone)]
pub struct QueryCtxt<'tcx> {
impl<'tcx> std::ops::Deref for QueryCtxt<'tcx> {
type Target = TyCtxt<'tcx>;
+ #[inline]
fn deref(&self) -> &Self::Target {
&self.tcx
}
}
impl QueryContext for QueryCtxt<'tcx> {
- fn def_path_str(&self, def_id: DefId) -> String {
- self.tcx.def_path_str(def_id)
- }
-
fn current_query_job(&self) -> Option<QueryJobId<Self::DepKind>> {
tls::with_related_context(**self, |icx| icx.query)
}
}
fn try_force_from_dep_node(&self, dep_node: &DepNode) -> bool {
- // FIXME: This match is just a workaround for incremental bugs and should
- // be removed. https://github.com/rust-lang/rust/issues/62649 is one such
- // bug that must be fixed before removing this.
- match dep_node.kind {
- DepKind::hir_owner | DepKind::hir_owner_nodes => {
- if let Some(def_id) = dep_node.extract_def_id(**self) {
- let def_id = def_id.expect_local();
- let hir_id = self.tcx.hir().local_def_id_to_hir_id(def_id);
- if def_id != hir_id.owner {
- // This `DefPath` does not have a
- // corresponding `DepNode` (e.g. a
- // struct field), and the ` DefPath`
- // collided with the `DefPath` of a
- // proper item that existed in the
- // previous compilation session.
- //
- // Since the given `DefPath` does not
- // denote the item that previously
- // existed, we just fail to mark green.
- return false;
- }
- } else {
- // If the node does not exist anymore, we
- // just fail to mark green.
- return false;
- }
- }
- _ => {
- // For other kinds of nodes it's OK to be
- // forced.
- }
- }
-
debug!("try_force_from_dep_node({:?}) --- trying to force", dep_node);
// We must avoid ever having to call `force_from_dep_node()` for a
}
#[inline]
- fn compute(tcx: QueryCtxt<'tcx>, key: Self::Key) -> Self::Value {
- let is_local = key.query_crate() == LOCAL_CRATE;
- let provider = if is_local {
+ fn compute_fn(tcx: QueryCtxt<'tcx>, key: &Self::Key) ->
+ fn(TyCtxt<'tcx>, Self::Key) -> Self::Value
+ {
+ if key.query_crate_is_local() {
tcx.queries.local_providers.$name
} else {
tcx.queries.extern_providers.$name
- };
- provider(*tcx, key)
+ }
}
fn hash_result(
}
fn force_from_dep_node(tcx: QueryCtxt<'_>, dep_node: &DepNode) -> bool {
- if is_anon {
- return false;
- }
-
- if !can_reconstruct_query_key() {
- return false;
- }
-
- if let Some(key) = recover(*tcx, dep_node) {
- force_query::<queries::$name<'_>, _>(tcx, key, DUMMY_SP, *dep_node);
- return true;
- }
-
- false
+ force_query::<queries::$name<'_>, _>(tcx, dep_node)
}
fn try_load_from_on_disk_cache(tcx: QueryCtxt<'_>, dep_node: &DepNode) {
match def_key.disambiguated_data.data {
DefPathData::CrateRoot => {
- crate_name = self.tcx.original_crate_name(def_id.krate).as_str();
+ crate_name = self.tcx.crate_name(def_id.krate).as_str();
name = &*crate_name;
dis = "";
end_index = 3;
use std::mem;
use std::sync::atomic::Ordering::Relaxed;
-use super::prev::PreviousDepGraph;
use super::query::DepGraphQuery;
-use super::serialized::{GraphEncoder, SerializedDepNodeIndex};
+use super::serialized::{GraphEncoder, SerializedDepGraph, SerializedDepNodeIndex};
use super::{DepContext, DepKind, DepNode, HasDepContext, WorkProductId};
use crate::query::QueryContext;
impl DepNodeIndex {
pub const INVALID: DepNodeIndex = DepNodeIndex::MAX;
+ pub const SINGLETON_DEPENDENCYLESS_ANON_NODE: DepNodeIndex = DepNodeIndex::from_u32(0);
}
impl std::convert::From<DepNodeIndex> for QueryInvocationId {
/// The dep-graph from the previous compilation session. It contains all
/// nodes and edges as well as all fingerprints of nodes that have them.
- previous: PreviousDepGraph<K>,
+ previous: SerializedDepGraph<K>,
colors: DepNodeColorMap,
impl<K: DepKind> DepGraph<K> {
pub fn new(
- prev_graph: PreviousDepGraph<K>,
+ profiler: &SelfProfilerRef,
+ prev_graph: SerializedDepGraph<K>,
prev_work_products: FxHashMap<WorkProductId, WorkProduct>,
encoder: FileEncoder,
record_graph: bool,
) -> DepGraph<K> {
let prev_graph_node_count = prev_graph.node_count();
+ let current =
+ CurrentDepGraph::new(prev_graph_node_count, encoder, record_graph, record_stats);
+
+ // Instantiate a dependy-less node only once for anonymous queries.
+ let _green_node_index = current.intern_new_node(
+ profiler,
+ DepNode { kind: DepKind::NULL, hash: current.anon_id_seed.into() },
+ smallvec![],
+ Fingerprint::ZERO,
+ );
+ debug_assert_eq!(_green_node_index, DepNodeIndex::SINGLETON_DEPENDENCYLESS_ANON_NODE);
+
DepGraph {
data: Some(Lrc::new(DepGraphData {
previous_work_products: prev_work_products,
dep_node_debug: Default::default(),
- current: CurrentDepGraph::new(
- prev_graph_node_count,
- encoder,
- record_graph,
- record_stats,
- ),
+ current,
emitting_diagnostics: Default::default(),
emitting_diagnostics_cond_var: Condvar::new(),
previous: prev_graph,
let task_deps = Lock::new(TaskDeps::default());
let result = K::with_deps(Some(&task_deps), op);
let task_deps = task_deps.into_inner();
+ let task_deps = task_deps.reads;
+
+ let dep_node_index = match task_deps.len() {
+ 0 => {
+ // Because the dep-node id of anon nodes is computed from the sets of its
+ // dependencies we already know what the ID of this dependency-less node is
+ // going to be (i.e. equal to the precomputed
+ // `SINGLETON_DEPENDENCYLESS_ANON_NODE`). As a consequence we can skip creating
+ // a `StableHasher` and sending the node through interning.
+ DepNodeIndex::SINGLETON_DEPENDENCYLESS_ANON_NODE
+ }
+ 1 => {
+ // When there is only one dependency, don't bother creating a node.
+ task_deps[0]
+ }
+ _ => {
+ // The dep node indices are hashed here instead of hashing the dep nodes of the
+ // dependencies. These indices may refer to different nodes per session, but this isn't
+ // a problem here because we that ensure the final dep node hash is per session only by
+ // combining it with the per session random number `anon_id_seed`. This hash only need
+ // to map the dependencies to a single value on a per session basis.
+ let mut hasher = StableHasher::new();
+ task_deps.hash(&mut hasher);
+
+ let target_dep_node = DepNode {
+ kind: dep_kind,
+ // Fingerprint::combine() is faster than sending Fingerprint
+ // through the StableHasher (at least as long as StableHasher
+ // is so slow).
+ hash: data.current.anon_id_seed.combine(hasher.finish()).into(),
+ };
- // The dep node indices are hashed here instead of hashing the dep nodes of the
- // dependencies. These indices may refer to different nodes per session, but this isn't
- // a problem here because we that ensure the final dep node hash is per session only by
- // combining it with the per session random number `anon_id_seed`. This hash only need
- // to map the dependencies to a single value on a per session basis.
- let mut hasher = StableHasher::new();
- task_deps.reads.hash(&mut hasher);
-
- let target_dep_node = DepNode {
- kind: dep_kind,
- // Fingerprint::combine() is faster than sending Fingerprint
- // through the StableHasher (at least as long as StableHasher
- // is so slow).
- hash: data.current.anon_id_seed.combine(hasher.finish()).into(),
+ data.current.intern_new_node(
+ cx.profiler(),
+ target_dep_node,
+ task_deps,
+ Fingerprint::ZERO,
+ )
+ }
};
- let dep_node_index = data.current.intern_new_node(
- cx.profiler(),
- target_dep_node,
- task_deps.reads,
- Fingerprint::ZERO,
- );
-
(result, dep_node_index)
} else {
(op(), self.next_virtual_depnode_index())
}
}
+ fn try_mark_parent_green<Ctxt: QueryContext<DepKind = K>>(
+ &self,
+ tcx: Ctxt,
+ data: &DepGraphData<K>,
+ parent_dep_node_index: SerializedDepNodeIndex,
+ dep_node: &DepNode<K>,
+ ) -> Option<()> {
+ let dep_dep_node_color = data.colors.get(parent_dep_node_index);
+ let dep_dep_node = &data.previous.index_to_node(parent_dep_node_index);
+
+ match dep_dep_node_color {
+ Some(DepNodeColor::Green(_)) => {
+ // This dependency has been marked as green before, we are
+ // still fine and can continue with checking the other
+ // dependencies.
+ debug!(
+ "try_mark_previous_green({:?}) --- found dependency {:?} to \
+ be immediately green",
+ dep_node, dep_dep_node,
+ );
+ return Some(());
+ }
+ Some(DepNodeColor::Red) => {
+ // We found a dependency the value of which has changed
+ // compared to the previous compilation session. We cannot
+ // mark the DepNode as green and also don't need to bother
+ // with checking any of the other dependencies.
+ debug!(
+ "try_mark_previous_green({:?}) - END - dependency {:?} was immediately red",
+ dep_node, dep_dep_node,
+ );
+ return None;
+ }
+ None => {}
+ }
+
+ // We don't know the state of this dependency. If it isn't
+ // an eval_always node, let's try to mark it green recursively.
+ if !dep_dep_node.kind.is_eval_always() {
+ debug!(
+ "try_mark_previous_green({:?}) --- state of dependency {:?} ({}) \
+ is unknown, trying to mark it green",
+ dep_node, dep_dep_node, dep_dep_node.hash,
+ );
+
+ let node_index =
+ self.try_mark_previous_green(tcx, data, parent_dep_node_index, dep_dep_node);
+ if node_index.is_some() {
+ debug!(
+ "try_mark_previous_green({:?}) --- managed to MARK dependency {:?} as green",
+ dep_node, dep_dep_node
+ );
+ return Some(());
+ }
+ }
+
+ // We failed to mark it green, so we try to force the query.
+ debug!(
+ "try_mark_previous_green({:?}) --- trying to force dependency {:?}",
+ dep_node, dep_dep_node
+ );
+ if !tcx.try_force_from_dep_node(dep_dep_node) {
+ // The DepNode could not be forced.
+ debug!(
+ "try_mark_previous_green({:?}) - END - dependency {:?} could not be forced",
+ dep_node, dep_dep_node
+ );
+ return None;
+ }
+
+ let dep_dep_node_color = data.colors.get(parent_dep_node_index);
+
+ match dep_dep_node_color {
+ Some(DepNodeColor::Green(_)) => {
+ debug!(
+ "try_mark_previous_green({:?}) --- managed to FORCE dependency {:?} to green",
+ dep_node, dep_dep_node
+ );
+ return Some(());
+ }
+ Some(DepNodeColor::Red) => {
+ debug!(
+ "try_mark_previous_green({:?}) - END - dependency {:?} was red after forcing",
+ dep_node, dep_dep_node
+ );
+ return None;
+ }
+ None => {}
+ }
+
+ if !tcx.dep_context().sess().has_errors_or_delayed_span_bugs() {
+ panic!("try_mark_previous_green() - Forcing the DepNode should have set its color")
+ }
+
+ // 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;
+ }
+
/// Try to mark a dep-node which existed in the previous compilation session as green.
fn try_mark_previous_green<Ctxt: QueryContext<DepKind = K>>(
&self,
let prev_deps = data.previous.edge_targets_from(prev_dep_node_index);
for &dep_dep_node_index in prev_deps {
- let dep_dep_node_color = data.colors.get(dep_dep_node_index);
-
- match dep_dep_node_color {
- Some(DepNodeColor::Green(_)) => {
- // This dependency has been marked as green before, we are
- // still fine and can continue with checking the other
- // dependencies.
- debug!(
- "try_mark_previous_green({:?}) --- found dependency {:?} to \
- be immediately green",
- dep_node,
- data.previous.index_to_node(dep_dep_node_index)
- );
- }
- Some(DepNodeColor::Red) => {
- // We found a dependency the value of which has changed
- // compared to the previous compilation session. We cannot
- // mark the DepNode as green and also don't need to bother
- // with checking any of the other dependencies.
- debug!(
- "try_mark_previous_green({:?}) - END - dependency {:?} was \
- immediately red",
- dep_node,
- data.previous.index_to_node(dep_dep_node_index)
- );
- return None;
- }
- None => {
- let dep_dep_node = &data.previous.index_to_node(dep_dep_node_index);
-
- // We don't know the state of this dependency. If it isn't
- // an eval_always node, let's try to mark it green recursively.
- if !dep_dep_node.kind.is_eval_always() {
- debug!(
- "try_mark_previous_green({:?}) --- state of dependency {:?} ({}) \
- is unknown, trying to mark it green",
- dep_node, dep_dep_node, dep_dep_node.hash,
- );
-
- let node_index = self.try_mark_previous_green(
- tcx,
- data,
- dep_dep_node_index,
- dep_dep_node,
- );
- if node_index.is_some() {
- debug!(
- "try_mark_previous_green({:?}) --- managed to MARK \
- dependency {:?} as green",
- dep_node, dep_dep_node
- );
- continue;
- }
- }
-
- // We failed to mark it green, so we try to force the query.
- debug!(
- "try_mark_previous_green({:?}) --- trying to force \
- dependency {:?}",
- dep_node, dep_dep_node
- );
- if tcx.try_force_from_dep_node(dep_dep_node) {
- let dep_dep_node_color = data.colors.get(dep_dep_node_index);
-
- match dep_dep_node_color {
- Some(DepNodeColor::Green(_)) => {
- debug!(
- "try_mark_previous_green({:?}) --- managed to \
- FORCE dependency {:?} to green",
- dep_node, dep_dep_node
- );
- }
- Some(DepNodeColor::Red) => {
- debug!(
- "try_mark_previous_green({:?}) - END - \
- dependency {:?} was red after forcing",
- dep_node, dep_dep_node
- );
- return None;
- }
- None => {
- if !tcx.dep_context().sess().has_errors_or_delayed_span_bugs() {
- panic!(
- "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 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;
- }
- }
- }
- } else {
- // The DepNode could not be forced.
- debug!(
- "try_mark_previous_green({:?}) - END - dependency {:?} \
- could not be forced",
- dep_node, dep_dep_node
- );
- return None;
- }
- }
- }
+ self.try_mark_parent_green(tcx, data, dep_dep_node_index, dep_node)?
}
// If we got here without hitting a `return` that means that all
}
}
- fn next_virtual_depnode_index(&self) -> DepNodeIndex {
+ pub(crate) fn next_virtual_depnode_index(&self) -> DepNodeIndex {
let index = self.virtual_dep_node_index.fetch_add(1, Relaxed);
DepNodeIndex::from_u32(index)
}
/// For this reason, we avoid storing `DepNode`s more than once as map
/// keys. The `new_node_to_index` map only contains nodes not in the previous
/// graph, and we map nodes in the previous graph to indices via a two-step
-/// mapping. `PreviousDepGraph` maps from `DepNode` to `SerializedDepNodeIndex`,
+/// mapping. `SerializedDepGraph` maps from `DepNode` to `SerializedDepNodeIndex`,
/// and the `prev_index_to_index` vector (which is more compact and faster than
/// using a map) maps from `SerializedDepNodeIndex` to `DepNodeIndex`.
///
fn intern_node(
&self,
profiler: &SelfProfilerRef,
- prev_graph: &PreviousDepGraph<K>,
+ prev_graph: &SerializedDepGraph<K>,
key: DepNode<K>,
edges: EdgesVec,
fingerprint: Option<Fingerprint>,
fn promote_node_and_deps_to_current(
&self,
profiler: &SelfProfilerRef,
- prev_graph: &PreviousDepGraph<K>,
+ prev_graph: &SerializedDepGraph<K>,
prev_index: SerializedDepNodeIndex,
) -> DepNodeIndex {
self.debug_assert_not_in_new_nodes(prev_graph, prev_index);
#[inline]
fn debug_assert_not_in_new_nodes(
&self,
- prev_graph: &PreviousDepGraph<K>,
+ prev_graph: &SerializedDepGraph<K>,
prev_index: SerializedDepNodeIndex,
) {
let node = &prev_graph.index_to_node(prev_index);
pub mod debug;
mod dep_node;
mod graph;
-mod prev;
mod query;
mod serialized;
pub use dep_node::{DepNode, DepNodeParams, WorkProductId};
pub use graph::{hash_result, DepGraph, DepNodeColor, DepNodeIndex, TaskDeps, WorkProduct};
-pub use prev::PreviousDepGraph;
pub use query::DepGraphQuery;
pub use serialized::{SerializedDepGraph, SerializedDepNodeIndex};
+++ /dev/null
-use super::serialized::{SerializedDepGraph, SerializedDepNodeIndex};
-use super::{DepKind, DepNode};
-use rustc_data_structures::fingerprint::Fingerprint;
-use rustc_data_structures::fx::FxHashMap;
-
-#[derive(Debug)]
-pub struct PreviousDepGraph<K: DepKind> {
- data: SerializedDepGraph<K>,
- index: FxHashMap<DepNode<K>, SerializedDepNodeIndex>,
-}
-
-impl<K: DepKind> Default for PreviousDepGraph<K> {
- fn default() -> Self {
- PreviousDepGraph { data: Default::default(), index: Default::default() }
- }
-}
-
-impl<K: DepKind> PreviousDepGraph<K> {
- pub fn new(data: SerializedDepGraph<K>) -> PreviousDepGraph<K> {
- let index: FxHashMap<_, _> =
- data.nodes.iter_enumerated().map(|(idx, &dep_node)| (dep_node, idx)).collect();
- PreviousDepGraph { data, index }
- }
-
- #[inline]
- pub fn edge_targets_from(
- &self,
- dep_node_index: SerializedDepNodeIndex,
- ) -> &[SerializedDepNodeIndex] {
- self.data.edge_targets_from(dep_node_index)
- }
-
- #[inline]
- pub fn index_to_node(&self, dep_node_index: SerializedDepNodeIndex) -> DepNode<K> {
- self.data.nodes[dep_node_index]
- }
-
- #[inline]
- pub fn node_to_index_opt(&self, dep_node: &DepNode<K>) -> Option<SerializedDepNodeIndex> {
- self.index.get(dep_node).cloned()
- }
-
- #[inline]
- pub fn fingerprint_of(&self, dep_node: &DepNode<K>) -> Option<Fingerprint> {
- self.index.get(dep_node).map(|&node_index| self.data.fingerprints[node_index])
- }
-
- #[inline]
- pub fn fingerprint_by_index(&self, dep_node_index: SerializedDepNodeIndex) -> Fingerprint {
- self.data.fingerprints[dep_node_index]
- }
-
- pub fn node_count(&self) -> usize {
- self.index.len()
- }
-}
#[derive(Debug)]
pub struct SerializedDepGraph<K: DepKind> {
/// The set of all DepNodes in the graph
- pub nodes: IndexVec<SerializedDepNodeIndex, DepNode<K>>,
+ nodes: IndexVec<SerializedDepNodeIndex, DepNode<K>>,
/// The set of all Fingerprints in the graph. Each Fingerprint corresponds to
/// the DepNode at the same index in the nodes vector.
- pub fingerprints: IndexVec<SerializedDepNodeIndex, Fingerprint>,
+ fingerprints: IndexVec<SerializedDepNodeIndex, Fingerprint>,
/// For each DepNode, stores the list of edges originating from that
/// DepNode. Encoded as a [start, end) pair indexing into edge_list_data,
/// which holds the actual DepNodeIndices of the target nodes.
- pub edge_list_indices: IndexVec<SerializedDepNodeIndex, (u32, u32)>,
+ edge_list_indices: IndexVec<SerializedDepNodeIndex, (u32, u32)>,
/// A flattened list of all edge targets in the graph. Edge sources are
/// implicit in edge_list_indices.
- pub edge_list_data: Vec<SerializedDepNodeIndex>,
+ edge_list_data: Vec<SerializedDepNodeIndex>,
+ /// Reciprocal map to `nodes`.
+ index: FxHashMap<DepNode<K>, SerializedDepNodeIndex>,
}
impl<K: DepKind> Default for SerializedDepGraph<K> {
fingerprints: Default::default(),
edge_list_indices: Default::default(),
edge_list_data: Default::default(),
+ index: Default::default(),
}
}
}
let targets = self.edge_list_indices[source];
&self.edge_list_data[targets.0 as usize..targets.1 as usize]
}
+
+ #[inline]
+ pub fn index_to_node(&self, dep_node_index: SerializedDepNodeIndex) -> DepNode<K> {
+ self.nodes[dep_node_index]
+ }
+
+ #[inline]
+ pub fn node_to_index_opt(&self, dep_node: &DepNode<K>) -> Option<SerializedDepNodeIndex> {
+ self.index.get(dep_node).cloned()
+ }
+
+ #[inline]
+ pub fn fingerprint_of(&self, dep_node: &DepNode<K>) -> Option<Fingerprint> {
+ self.index.get(dep_node).map(|&node_index| self.fingerprints[node_index])
+ }
+
+ #[inline]
+ pub fn fingerprint_by_index(&self, dep_node_index: SerializedDepNodeIndex) -> Fingerprint {
+ self.fingerprints[dep_node_index]
+ }
+
+ pub fn node_count(&self) -> usize {
+ self.index.len()
+ }
}
impl<'a, K: DepKind + Decodable<opaque::Decoder<'a>>> Decodable<opaque::Decoder<'a>>
let mut edge_list_data = Vec::with_capacity(edge_count);
for _index in 0..node_count {
- d.read_struct("NodeInfo", 3, |d| {
- let dep_node: DepNode<K> = d.read_struct_field("node", 0, Decodable::decode)?;
+ d.read_struct(|d| {
+ let dep_node: DepNode<K> = d.read_struct_field("node", Decodable::decode)?;
let _i: SerializedDepNodeIndex = nodes.push(dep_node);
debug_assert_eq!(_i.index(), _index);
let fingerprint: Fingerprint =
- d.read_struct_field("fingerprint", 1, Decodable::decode)?;
+ d.read_struct_field("fingerprint", Decodable::decode)?;
let _i: SerializedDepNodeIndex = fingerprints.push(fingerprint);
debug_assert_eq!(_i.index(), _index);
- d.read_struct_field("edges", 2, |d| {
+ d.read_struct_field("edges", |d| {
d.read_seq(|d, len| {
let start = edge_list_data.len().try_into().unwrap();
- for e in 0..len {
- let edge = d.read_seq_elt(e, Decodable::decode)?;
+ for _ in 0..len {
+ let edge = d.read_seq_elt(Decodable::decode)?;
edge_list_data.push(edge);
}
let end = edge_list_data.len().try_into().unwrap();
})?;
}
- Ok(SerializedDepGraph { nodes, fingerprints, edge_list_indices, edge_list_data })
+ let index: FxHashMap<_, _> =
+ nodes.iter_enumerated().map(|(idx, &dep_node)| (dep_node, idx)).collect();
+
+ Ok(SerializedDepGraph { nodes, fingerprints, edge_list_indices, edge_list_data, index })
}
}
#![feature(bool_to_option)]
-#![feature(const_panic)]
#![feature(core_intrinsics)]
-#![feature(drain_filter)]
#![feature(hash_raw_entry)]
#![feature(iter_zip)]
#![feature(min_specialization)]
-#![feature(stmt_expr_attributes)]
#[macro_use]
extern crate tracing;
pub dep_kind: CTX::DepKind,
pub eval_always: bool,
- // Don't use this method to compute query results, instead use the methods on TyCtxt
- pub compute: fn(CTX, K) -> V,
-
pub hash_result: fn(&mut CTX::StableHashingContext, &V) -> Option<Fingerprint>,
pub handle_cycle_error: fn(CTX, DiagnosticBuilder<'_>) -> V,
pub cache_on_disk: fn(CTX, &K, Option<&V>) -> bool,
DepNode::construct(tcx, self.dep_kind, key)
}
- pub(crate) fn compute(&self, tcx: CTX, key: K) -> V {
- (self.compute)(tcx, key)
- }
-
pub(crate) fn hash_result(
&self,
hcx: &mut CTX::StableHashingContext,
CTX: 'a;
// Don't use this method to compute query results, instead use the methods on TyCtxt
- fn compute(tcx: CTX, key: Self::Key) -> Self::Value;
+ fn compute_fn(tcx: CTX, key: &Self::Key) -> fn(CTX::DepContext, Self::Key) -> Self::Value;
fn hash_result(
hcx: &mut CTX::StableHashingContext,
anon: Q::ANON,
dep_kind: Q::DEP_KIND,
eval_always: Q::EVAL_ALWAYS,
- compute: Q::compute,
hash_result: Q::hash_result,
handle_cycle_error: Q::handle_cycle_error,
cache_on_disk: Q::cache_on_disk,
use rustc_data_structures::sync::Lock;
use rustc_data_structures::thin_vec::ThinVec;
use rustc_errors::Diagnostic;
-use rustc_span::def_id::DefId;
use rustc_span::Span;
/// Description of a frame in the query stack.
}
pub trait QueryContext: HasDepContext {
- /// Get string representation from DefPath.
- fn def_path_str(&self, def_id: DefId) -> String;
-
/// Get the query information from the TLS context.
fn current_query_job(&self) -> Option<QueryJobId<Self::DepKind>>;
//! generate the actual methods on tcx which find and execute the provider,
//! manage the caches, and so forth.
-use crate::dep_graph::{DepContext, DepKind, DepNode};
+use crate::dep_graph::{DepContext, DepKind, DepNode, DepNodeParams};
use crate::dep_graph::{DepNodeIndex, SerializedDepNodeIndex};
use crate::query::caches::QueryCache;
use crate::query::config::{QueryDescription, QueryVtable, QueryVtableExt};
#[cfg(not(parallel_compiler))]
use rustc_errors::DiagnosticBuilder;
use rustc_errors::{Diagnostic, FatalError};
-use rustc_span::Span;
+use rustc_span::{Span, DUMMY_SP};
use std::collections::hash_map::Entry;
use std::fmt::Debug;
use std::hash::{Hash, Hasher};
key: C::Key,
lookup: QueryLookup,
query: &QueryVtable<CTX, C::Key, C::Value>,
+ compute: fn(CTX::DepContext, C::Key) -> C::Value,
) -> C::Stored
where
C: QueryCache,
- C::Key: crate::dep_graph::DepNodeParams<CTX::DepContext>,
+ C::Key: DepNodeParams<CTX::DepContext>,
CTX: QueryContext,
{
let job = match JobOwner::<'_, CTX::DepKind, C>::try_start(
}
};
- // Fast path for when incr. comp. is off. `to_dep_node` is
- // expensive for some `DepKind`s.
- if !tcx.dep_context().dep_graph().is_fully_enabled() {
- let null_dep_node = DepNode::new_no_params(DepKind::NULL);
- return force_query_with_job(tcx, key, job, null_dep_node, query).0;
+ let dep_graph = tcx.dep_context().dep_graph();
+
+ // Fast path for when incr. comp. is off.
+ if !dep_graph.is_fully_enabled() {
+ let prof_timer = tcx.dep_context().profiler().query_provider();
+ let result = tcx.start_query(job.id, None, || compute(*tcx.dep_context(), key));
+ let dep_node_index = dep_graph.next_virtual_depnode_index();
+ prof_timer.finish_with_query_invocation_id(dep_node_index.into());
+ return job.complete(result, dep_node_index);
}
if query.anon {
let ((result, dep_node_index), diagnostics) = with_diagnostics(|diagnostics| {
tcx.start_query(job.id, diagnostics, || {
- tcx.dep_context().dep_graph().with_anon_task(
- *tcx.dep_context(),
- query.dep_kind,
- || query.compute(tcx, key),
- )
+ dep_graph.with_anon_task(*tcx.dep_context(), query.dep_kind, || {
+ compute(*tcx.dep_context(), key)
+ })
})
});
prof_timer.finish_with_query_invocation_id(dep_node_index.into());
- tcx.dep_context().dep_graph().read_index(dep_node_index);
+ dep_graph.read_index(dep_node_index);
if unlikely!(!diagnostics.is_empty()) {
tcx.store_diagnostics_for_anon_node(dep_node_index, diagnostics);
// promoted to the current session during
// `try_mark_green()`, so we can ignore them here.
let loaded = tcx.start_query(job.id, None, || {
- let marked = tcx.dep_context().dep_graph().try_mark_green_and_read(tcx, &dep_node);
+ let marked = dep_graph.try_mark_green_and_read(tcx, &dep_node);
marked.map(|(prev_dep_node_index, dep_node_index)| {
(
load_from_disk_and_cache_in_memory(
dep_node_index,
&dep_node,
query,
+ compute,
),
dep_node_index,
)
}
}
- let (result, dep_node_index) = force_query_with_job(tcx, key, job, dep_node, query);
- tcx.dep_context().dep_graph().read_index(dep_node_index);
+ let (result, dep_node_index) = force_query_with_job(tcx, key, job, dep_node, query, compute);
+ dep_graph.read_index(dep_node_index);
result
}
dep_node_index: DepNodeIndex,
dep_node: &DepNode<CTX::DepKind>,
query: &QueryVtable<CTX, K, V>,
+ compute: fn(CTX::DepContext, K) -> V,
) -> V
where
CTX: QueryContext,
let prof_timer = tcx.dep_context().profiler().query_provider();
// The dep-graph for this computation is already in-place.
- let result = tcx.dep_context().dep_graph().with_ignore(|| query.compute(tcx, key));
+ let result = tcx.dep_context().dep_graph().with_ignore(|| compute(*tcx.dep_context(), key));
prof_timer.finish_with_query_invocation_id(dep_node_index.into());
job: JobOwner<'_, CTX::DepKind, C>,
dep_node: DepNode<CTX::DepKind>,
query: &QueryVtable<CTX, C::Key, C::Value>,
+ compute: fn(CTX::DepContext, C::Key) -> C::Value,
) -> (C::Stored, DepNodeIndex)
where
C: QueryCache,
if query.eval_always {
tcx.dep_context().dep_graph().with_eval_always_task(
dep_node,
- tcx,
+ *tcx.dep_context(),
key,
- query.compute,
+ compute,
query.hash_result,
)
} else {
tcx.dep_context().dep_graph().with_task(
dep_node,
- tcx,
+ *tcx.dep_context(),
key,
- query.compute,
+ compute,
query.hash_result,
)
}
key: C::Key,
lookup: QueryLookup,
query: &QueryVtable<CTX, C::Key, C::Value>,
+ compute: fn(CTX::DepContext, C::Key) -> C::Value,
) -> C::Stored
where
CTX: QueryContext,
C: QueryCache,
- C::Key: crate::dep_graph::DepNodeParams<CTX::DepContext>,
+ C::Key: DepNodeParams<CTX::DepContext>,
{
- try_execute_query(tcx, state, cache, span, key, lookup, query)
+ try_execute_query(tcx, state, cache, span, key, lookup, query, compute)
}
/// Ensure that either this query has all green inputs or been executed.
state: &QueryState<CTX::DepKind, C::Key>,
cache: &QueryCacheStore<C>,
key: C::Key,
- span: Span,
dep_node: DepNode<CTX::DepKind>,
query: &QueryVtable<CTX, C::Key, C::Value>,
-) where
+ compute: fn(CTX::DepContext, C::Key) -> C::Value,
+) -> bool
+where
C: QueryCache,
- C::Key: crate::dep_graph::DepNodeParams<CTX::DepContext>,
+ C::Key: DepNodeParams<CTX::DepContext>,
CTX: QueryContext,
{
+ debug_assert!(!query.anon);
+
// We may be concurrently trying both execute and force a query.
// Ensure that only one of them runs the query.
let cached = cache.cache.lookup(cache, &key, |_, index| {
});
let lookup = match cached {
- Ok(()) => return,
+ Ok(()) => return true,
Err(lookup) => lookup,
};
tcx,
state,
cache,
- span,
+ DUMMY_SP,
key.clone(),
lookup,
query,
) {
TryGetJob::NotYetStarted(job) => job,
- TryGetJob::Cycle(_) => return,
+ TryGetJob::Cycle(_) => return true,
#[cfg(parallel_compiler)]
- TryGetJob::JobCompleted(_) => return,
+ TryGetJob::JobCompleted(_) => return true,
};
- force_query_with_job(tcx, key, job, dep_node, query);
+
+ force_query_with_job(tcx, key, job, dep_node, query, compute);
+
+ true
}
pub enum QueryMode {
) -> Option<Q::Stored>
where
Q: QueryDescription<CTX>,
- Q::Key: crate::dep_graph::DepNodeParams<CTX::DepContext>,
+ Q::Key: DepNodeParams<CTX::DepContext>,
CTX: QueryContext,
{
let query = &Q::VTABLE;
}
debug!("ty::query::get_query<{}>(key={:?}, span={:?})", Q::NAME, key, span);
- let value =
- get_query_impl(tcx, Q::query_state(tcx), Q::query_cache(tcx), span, key, lookup, query);
+ let compute = Q::compute_fn(tcx, &key);
+ let value = get_query_impl(
+ tcx,
+ Q::query_state(tcx),
+ Q::query_cache(tcx),
+ span,
+ key,
+ lookup,
+ query,
+ compute,
+ );
Some(value)
}
-pub fn force_query<Q, CTX>(tcx: CTX, key: Q::Key, span: Span, dep_node: DepNode<CTX::DepKind>)
+pub fn force_query<Q, CTX>(tcx: CTX, dep_node: &DepNode<CTX::DepKind>) -> bool
where
Q: QueryDescription<CTX>,
- Q::Key: crate::dep_graph::DepNodeParams<CTX::DepContext>,
+ Q::Key: DepNodeParams<CTX::DepContext>,
CTX: QueryContext,
{
- force_query_impl(tcx, Q::query_state(tcx), Q::query_cache(tcx), key, span, dep_node, &Q::VTABLE)
+ if Q::ANON {
+ return false;
+ }
+
+ if !<Q::Key as DepNodeParams<CTX::DepContext>>::can_reconstruct_query_key() {
+ return false;
+ }
+
+ let key = if let Some(key) =
+ <Q::Key as DepNodeParams<CTX::DepContext>>::recover(*tcx.dep_context(), &dep_node)
+ {
+ key
+ } else {
+ return false;
+ };
+
+ let compute = Q::compute_fn(tcx, &key);
+ force_query_impl(
+ tcx,
+ Q::query_state(tcx),
+ Q::query_cache(tcx),
+ key,
+ *dep_node,
+ &Q::VTABLE,
+ compute,
+ )
}
}
err
}
- ResolutionError::BindingShadowsSomethingUnacceptable(what_binding, name, binding) => {
- let res = binding.res();
- let shadows_what = res.descr();
+ ResolutionError::BindingShadowsSomethingUnacceptable {
+ shadowing_binding_descr,
+ name,
+ participle,
+ article,
+ shadowed_binding_descr,
+ shadowed_binding_span,
+ } => {
let mut err = struct_span_err!(
self.session,
span,
E0530,
"{}s cannot shadow {}s",
- what_binding,
- shadows_what
+ shadowing_binding_descr,
+ shadowed_binding_descr,
);
err.span_label(
span,
- format!("cannot be named the same as {} {}", res.article(), shadows_what),
+ format!("cannot be named the same as {} {}", article, shadowed_binding_descr),
);
- let participle = if binding.is_import() { "imported" } else { "defined" };
- let msg = format!("the {} `{}` is {} here", shadows_what, name, participle);
- err.span_label(binding.span, msg);
+ let msg =
+ format!("the {} `{}` is {} here", shadowed_binding_descr, name, participle);
+ err.span_label(shadowed_binding_span, msg);
err
}
- ResolutionError::ForwardDeclaredTyParam => {
+ ResolutionError::ForwardDeclaredGenericParam => {
let mut err = struct_span_err!(
self.session,
span,
self.r.record_partial_res(pat.id, PartialRes::new(res));
self.r.record_pat_span(pat.id, pat.span);
}
- PatKind::TupleStruct(ref path, ref sub_patterns) => {
+ PatKind::TupleStruct(ref qself, ref path, ref sub_patterns) => {
self.smart_resolve_path(
pat.id,
- None,
+ qself.as_ref(),
path,
PathSource::TupleStruct(
pat.span,
PatKind::Path(ref qself, ref path) => {
self.smart_resolve_path(pat.id, qself.as_ref(), path, PathSource::Pat);
}
- PatKind::Struct(ref path, ..) => {
- self.smart_resolve_path(pat.id, None, path, PathSource::Struct);
+ PatKind::Struct(ref qself, ref path, ..) => {
+ self.smart_resolve_path(pat.id, qself.as_ref(), path, PathSource::Struct);
}
PatKind::Or(ref ps) => {
// Add a new set of bindings to the stack. `Or` here records that when a
// to something unusable as a pattern (e.g., constructor function),
// but we still conservatively report an error, see
// issues/33118#issuecomment-233962221 for one reason why.
+ let binding = binding.expect("no binding for a ctor or static");
self.report_error(
ident.span,
- ResolutionError::BindingShadowsSomethingUnacceptable(
- pat_src.descr(),
- ident.name,
- binding.expect("no binding for a ctor or static"),
- ),
+ ResolutionError::BindingShadowsSomethingUnacceptable {
+ shadowing_binding_descr: pat_src.descr(),
+ name: ident.name,
+ participle: if binding.is_import() { "imported" } else { "defined" },
+ article: binding.res().article(),
+ shadowed_binding_descr: binding.res().descr(),
+ shadowed_binding_span: binding.span,
+ },
+ );
+ None
+ }
+ Res::Def(DefKind::ConstParam, def_id) => {
+ // Same as for DefKind::Const above, but here, `binding` is `None`, so we
+ // have to construct the error differently
+ self.report_error(
+ ident.span,
+ ResolutionError::BindingShadowsSomethingUnacceptable {
+ shadowing_binding_descr: pat_src.descr(),
+ name: ident.name,
+ participle: "defined",
+ article: res.article(),
+ shadowed_binding_descr: res.descr(),
+ shadowed_binding_span: self.r.opt_span(def_id).expect("const parameter defined outside of local crate"),
+ }
);
None
}
if ns == ValueNS {
let item_name = path.last().unwrap().ident;
let traits = self.traits_in_scope(item_name, ns);
- self.r.trait_map.insert(id, traits);
+ self.r.trait_map.as_mut().unwrap().insert(id, traits);
}
if PrimTy::from_name(path[0].ident.name).is_some() {
}
ExprKind::Struct(ref se) => {
- self.smart_resolve_path(expr.id, None, &se.path, PathSource::Struct);
+ self.smart_resolve_path(expr.id, se.qself.as_ref(), &se.path, PathSource::Struct);
visit::walk_expr(self, expr);
}
// the field name so that we can do some nice error reporting
// later on in typeck.
let traits = self.traits_in_scope(ident, ValueNS);
- self.r.trait_map.insert(expr.id, traits);
+ self.r.trait_map.as_mut().unwrap().insert(expr.id, traits);
}
ExprKind::MethodCall(ref segment, ..) => {
debug!("(recording candidate traits for expr) recording traits for {}", expr.id);
let traits = self.traits_in_scope(segment.ident, ValueNS);
- self.r.trait_map.insert(expr.id, traits);
+ self.r.trait_map.as_mut().unwrap().insert(expr.id, traits);
}
_ => {
// Nothing to do.
}
impl<'a, 'tcx> LifetimeContext<'a, 'tcx> {
- // FIXME(#37666) this works around a limitation in the region inferencer
- fn hack<F>(&mut self, f: F)
- where
- F: for<'b> FnOnce(&mut LifetimeContext<'b, 'tcx>),
- {
- f(self)
- }
-
fn with<F>(&mut self, wrap_scope: Scope<'_>, f: F)
where
F: for<'b> FnOnce(ScopeRef<'_>, &mut LifetimeContext<'b, 'tcx>),
};
self.with(scope, move |old_scope, this| {
this.check_lifetime_params(old_scope, &generics.params);
- this.hack(walk); // FIXME(#37666) workaround in place of `walk(this)`
+ walk(this);
});
}
#![doc(html_root_url = "https://doc.rust-lang.org/nightly/nightly-rustc/")]
#![feature(box_patterns)]
#![feature(bool_to_option)]
-#![feature(control_flow_enum)]
#![feature(crate_visibility_modifier)]
#![feature(format_args_capture)]
#![feature(iter_zip)]
/* current */ &'static str,
),
/// Error E0530: `X` bindings cannot shadow `Y`s.
- BindingShadowsSomethingUnacceptable(&'static str, Symbol, &'a NameBinding<'a>),
+ BindingShadowsSomethingUnacceptable {
+ shadowing_binding_descr: &'static str,
+ name: Symbol,
+ participle: &'static str,
+ article: &'static str,
+ shadowed_binding_descr: &'static str,
+ shadowed_binding_span: Span,
+ },
/// Error E0128: generic parameters with a default cannot use forward-declared identifiers.
- ForwardDeclaredTyParam, // FIXME(const_generics_defaults)
+ ForwardDeclaredGenericParam,
/// ERROR E0770: the type of const parameters must not depend on other generic parameters.
ParamInTyOfConstParam(Symbol),
/// generic parameters must not be used inside const evaluations.
/// `CrateNum` resolutions of `extern crate` items.
extern_crate_map: FxHashMap<LocalDefId, CrateNum>,
export_map: ExportMap<LocalDefId>,
- trait_map: NodeMap<Vec<TraitCandidate>>,
+ trait_map: Option<NodeMap<Vec<TraitCandidate>>>,
/// A map from nodes to anonymous modules.
/// Anonymous modules are pseudo-modules that are implicitly created around items
self.next_node_id()
}
- fn trait_map(&self) -> &NodeMap<Vec<TraitCandidate>> {
- &self.trait_map
+ fn take_trait_map(&mut self) -> NodeMap<Vec<TraitCandidate>> {
+ std::mem::replace(&mut self.trait_map, None).unwrap()
}
fn opt_local_def_id(&self, node: NodeId) -> Option<LocalDefId> {
session: &'a Session,
krate: &Crate,
crate_name: &str,
- metadata_loader: &'a MetadataLoaderDyn,
+ metadata_loader: Box<MetadataLoaderDyn>,
arenas: &'a ResolverArenas<'a>,
) -> Resolver<'a> {
let root_local_def_id = LocalDefId { local_def_index: CRATE_DEF_INDEX };
label_res_map: Default::default(),
extern_crate_map: Default::default(),
export_map: FxHashMap::default(),
- trait_map: Default::default(),
+ trait_map: Some(NodeMap::default()),
underscore_disambiguator: 0,
empty_module,
module_map,
let res_error = if rib_ident.name == kw::SelfUpper {
ResolutionError::SelfInTyParamDefault
} else {
- ResolutionError::ForwardDeclaredTyParam
+ ResolutionError::ForwardDeclaredGenericParam
};
self.report_error(span, res_error);
}
// FIXME: Should save-analysis beautify doc strings itself or leave it to users?
result.push_str(&beautify_doc_string(val).as_str());
result.push('\n');
- } else if self.tcx.sess.check_name(attr, sym::doc) {
- if let Some(meta_list) = attr.meta_item_list() {
- meta_list
- .into_iter()
- .filter(|it| it.has_name(sym::include))
- .filter_map(|it| it.meta_item_list().map(|l| l.to_owned()))
- .flat_map(|it| it)
- .filter(|meta| meta.has_name(sym::contents))
- .filter_map(|meta| meta.value_str())
- .for_each(|val| {
- result.push_str(&val.as_str());
- result.push('\n');
- });
- }
}
}
d.read_seq(|d, len| {
let mut vec = SmallVec::with_capacity(len);
// FIXME(#48994) - could just be collected into a Result<SmallVec, D::Error>
- for i in 0..len {
- vec.push(d.read_seq_elt(i, |d| Decodable::decode(d))?);
+ for _ in 0..len {
+ vec.push(d.read_seq_elt(|d| Decodable::decode(d))?);
}
Ok(vec)
})
fn decode(d: &mut D) -> Result<LinkedList<T>, D::Error> {
d.read_seq(|d, len| {
let mut list = LinkedList::new();
- for i in 0..len {
- list.push_back(d.read_seq_elt(i, |d| Decodable::decode(d))?);
+ for _ in 0..len {
+ list.push_back(d.read_seq_elt(|d| Decodable::decode(d))?);
}
Ok(list)
})
fn decode(d: &mut D) -> Result<VecDeque<T>, D::Error> {
d.read_seq(|d, len| {
let mut deque: VecDeque<T> = VecDeque::with_capacity(len);
- for i in 0..len {
- deque.push_back(d.read_seq_elt(i, |d| Decodable::decode(d))?);
+ for _ in 0..len {
+ deque.push_back(d.read_seq_elt(|d| Decodable::decode(d))?);
}
Ok(deque)
})
e.emit_map(self.len(), |e| {
for (i, (key, val)) in self.iter().enumerate() {
e.emit_map_elt_key(i, |e| key.encode(e))?;
- e.emit_map_elt_val(i, |e| val.encode(e))?;
+ e.emit_map_elt_val(|e| val.encode(e))?;
}
Ok(())
})
fn decode(d: &mut D) -> Result<BTreeMap<K, V>, D::Error> {
d.read_map(|d, len| {
let mut map = BTreeMap::new();
- for i in 0..len {
- let key = d.read_map_elt_key(i, |d| Decodable::decode(d))?;
- let val = d.read_map_elt_val(i, |d| Decodable::decode(d))?;
+ for _ in 0..len {
+ let key = d.read_map_elt_key(|d| Decodable::decode(d))?;
+ let val = d.read_map_elt_val(|d| Decodable::decode(d))?;
map.insert(key, val);
}
Ok(map)
fn decode(d: &mut D) -> Result<BTreeSet<T>, D::Error> {
d.read_seq(|d, len| {
let mut set = BTreeSet::new();
- for i in 0..len {
- set.insert(d.read_seq_elt(i, |d| Decodable::decode(d))?);
+ for _ in 0..len {
+ set.insert(d.read_seq_elt(|d| Decodable::decode(d))?);
}
Ok(set)
})
e.emit_map(self.len(), |e| {
for (i, (key, val)) in self.iter().enumerate() {
e.emit_map_elt_key(i, |e| key.encode(e))?;
- e.emit_map_elt_val(i, |e| val.encode(e))?;
+ e.emit_map_elt_val(|e| val.encode(e))?;
}
Ok(())
})
d.read_map(|d, len| {
let state = Default::default();
let mut map = HashMap::with_capacity_and_hasher(len, state);
- for i in 0..len {
- let key = d.read_map_elt_key(i, |d| Decodable::decode(d))?;
- let val = d.read_map_elt_val(i, |d| Decodable::decode(d))?;
+ for _ in 0..len {
+ let key = d.read_map_elt_key(|d| Decodable::decode(d))?;
+ let val = d.read_map_elt_val(|d| Decodable::decode(d))?;
map.insert(key, val);
}
Ok(map)
d.read_seq(|d, len| {
let state = Default::default();
let mut set = HashSet::with_capacity_and_hasher(len, state);
- for i in 0..len {
- set.insert(d.read_seq_elt(i, |d| Decodable::decode(d))?);
+ for _ in 0..len {
+ set.insert(d.read_seq_elt(|d| Decodable::decode(d))?);
}
Ok(set)
})
e.emit_map(self.len(), |e| {
for (i, (key, val)) in self.iter().enumerate() {
e.emit_map_elt_key(i, |e| key.encode(e))?;
- e.emit_map_elt_val(i, |e| val.encode(e))?;
+ e.emit_map_elt_val(|e| val.encode(e))?;
}
Ok(())
})
d.read_map(|d, len| {
let state = Default::default();
let mut map = indexmap::IndexMap::with_capacity_and_hasher(len, state);
- for i in 0..len {
- let key = d.read_map_elt_key(i, |d| Decodable::decode(d))?;
- let val = d.read_map_elt_val(i, |d| Decodable::decode(d))?;
+ for _ in 0..len {
+ let key = d.read_map_elt_key(|d| Decodable::decode(d))?;
+ let val = d.read_map_elt_val(|d| Decodable::decode(d))?;
map.insert(key, val);
}
Ok(map)
d.read_seq(|d, len| {
let state = Default::default();
let mut set = indexmap::IndexSet::with_capacity_and_hasher(len, state);
- for i in 0..len {
- set.insert(d.read_seq_elt(i, |d| Decodable::decode(d))?);
+ for _ in 0..len {
+ set.insert(d.read_seq_elt(|d| Decodable::decode(d))?);
}
Ok(set)
})
Ok(())
}
- fn emit_enum<F>(&mut self, _name: &str, f: F) -> EncodeResult
+ fn emit_enum<F>(&mut self, f: F) -> EncodeResult
where
F: FnOnce(&mut Encoder<'a>) -> EncodeResult,
{
}
}
- fn emit_enum_variant_arg<F>(&mut self, idx: usize, f: F) -> EncodeResult
+ fn emit_enum_variant_arg<F>(&mut self, first: bool, f: F) -> EncodeResult
where
F: FnOnce(&mut Encoder<'a>) -> EncodeResult,
{
if self.is_emitting_map_key {
return Err(EncoderError::BadHashmapKey);
}
- if idx != 0 {
+ if !first {
write!(self.writer, ",")?;
}
f(self)
}
- fn emit_enum_struct_variant<F>(
- &mut self,
- name: &str,
- id: usize,
- cnt: usize,
- f: F,
- ) -> EncodeResult
- where
- F: FnOnce(&mut Encoder<'a>) -> EncodeResult,
- {
- if self.is_emitting_map_key {
- return Err(EncoderError::BadHashmapKey);
- }
- self.emit_enum_variant(name, id, cnt, f)
- }
-
- fn emit_enum_struct_variant_field<F>(&mut self, _: &str, idx: usize, f: F) -> EncodeResult
- where
- F: FnOnce(&mut Encoder<'a>) -> EncodeResult,
- {
- if self.is_emitting_map_key {
- return Err(EncoderError::BadHashmapKey);
- }
- self.emit_enum_variant_arg(idx, f)
- }
-
- fn emit_struct<F>(&mut self, _: &str, _: usize, f: F) -> EncodeResult
+ fn emit_struct<F>(&mut self, _: bool, f: F) -> EncodeResult
where
F: FnOnce(&mut Encoder<'a>) -> EncodeResult,
{
Ok(())
}
- fn emit_struct_field<F>(&mut self, name: &str, idx: usize, f: F) -> EncodeResult
+ fn emit_struct_field<F>(&mut self, name: &str, first: bool, f: F) -> EncodeResult
where
F: FnOnce(&mut Encoder<'a>) -> EncodeResult,
{
if self.is_emitting_map_key {
return Err(EncoderError::BadHashmapKey);
}
- if idx != 0 {
+ if !first {
write!(self.writer, ",")?;
}
escape_str(self.writer, name)?;
self.emit_seq_elt(idx, f)
}
- fn emit_tuple_struct<F>(&mut self, _name: &str, len: usize, f: F) -> EncodeResult
- where
- F: FnOnce(&mut Encoder<'a>) -> EncodeResult,
- {
- if self.is_emitting_map_key {
- return Err(EncoderError::BadHashmapKey);
- }
- self.emit_seq(len, f)
- }
- fn emit_tuple_struct_arg<F>(&mut self, idx: usize, f: F) -> EncodeResult
- where
- F: FnOnce(&mut Encoder<'a>) -> EncodeResult,
- {
- if self.is_emitting_map_key {
- return Err(EncoderError::BadHashmapKey);
- }
- self.emit_seq_elt(idx, f)
- }
-
fn emit_option<F>(&mut self, f: F) -> EncodeResult
where
F: FnOnce(&mut Encoder<'a>) -> EncodeResult,
Ok(())
}
- fn emit_map_elt_val<F>(&mut self, _idx: usize, f: F) -> EncodeResult
+ fn emit_map_elt_val<F>(&mut self, f: F) -> EncodeResult
where
F: FnOnce(&mut Encoder<'a>) -> EncodeResult,
{
Ok(())
}
- fn emit_enum<F>(&mut self, _name: &str, f: F) -> EncodeResult
+ fn emit_enum<F>(&mut self, f: F) -> EncodeResult
where
F: FnOnce(&mut PrettyEncoder<'a>) -> EncodeResult,
{
}
}
- fn emit_enum_variant_arg<F>(&mut self, idx: usize, f: F) -> EncodeResult
+ fn emit_enum_variant_arg<F>(&mut self, first: bool, f: F) -> EncodeResult
where
F: FnOnce(&mut PrettyEncoder<'a>) -> EncodeResult,
{
if self.is_emitting_map_key {
return Err(EncoderError::BadHashmapKey);
}
- if idx != 0 {
+ if !first {
writeln!(self.writer, ",")?;
}
spaces(self.writer, self.curr_indent)?;
f(self)
}
- fn emit_enum_struct_variant<F>(
- &mut self,
- name: &str,
- id: usize,
- cnt: usize,
- f: F,
- ) -> EncodeResult
+ fn emit_struct<F>(&mut self, no_fields: bool, f: F) -> EncodeResult
where
F: FnOnce(&mut PrettyEncoder<'a>) -> EncodeResult,
{
if self.is_emitting_map_key {
return Err(EncoderError::BadHashmapKey);
}
- self.emit_enum_variant(name, id, cnt, f)
- }
-
- fn emit_enum_struct_variant_field<F>(&mut self, _: &str, idx: usize, f: F) -> EncodeResult
- where
- F: FnOnce(&mut PrettyEncoder<'a>) -> EncodeResult,
- {
- if self.is_emitting_map_key {
- return Err(EncoderError::BadHashmapKey);
- }
- self.emit_enum_variant_arg(idx, f)
- }
-
- fn emit_struct<F>(&mut self, _: &str, len: usize, f: F) -> EncodeResult
- where
- F: FnOnce(&mut PrettyEncoder<'a>) -> EncodeResult,
- {
- if self.is_emitting_map_key {
- return Err(EncoderError::BadHashmapKey);
- }
- if len == 0 {
+ if no_fields {
write!(self.writer, "{{}}")?;
} else {
write!(self.writer, "{{")?;
Ok(())
}
- fn emit_struct_field<F>(&mut self, name: &str, idx: usize, f: F) -> EncodeResult
+ fn emit_struct_field<F>(&mut self, name: &str, first: bool, f: F) -> EncodeResult
where
F: FnOnce(&mut PrettyEncoder<'a>) -> EncodeResult,
{
if self.is_emitting_map_key {
return Err(EncoderError::BadHashmapKey);
}
- if idx == 0 {
+ if first {
writeln!(self.writer)?;
} else {
writeln!(self.writer, ",")?;
self.emit_seq_elt(idx, f)
}
- fn emit_tuple_struct<F>(&mut self, _: &str, len: usize, f: F) -> EncodeResult
- where
- F: FnOnce(&mut PrettyEncoder<'a>) -> EncodeResult,
- {
- if self.is_emitting_map_key {
- return Err(EncoderError::BadHashmapKey);
- }
- self.emit_seq(len, f)
- }
- fn emit_tuple_struct_arg<F>(&mut self, idx: usize, f: F) -> EncodeResult
- where
- F: FnOnce(&mut PrettyEncoder<'a>) -> EncodeResult,
- {
- if self.is_emitting_map_key {
- return Err(EncoderError::BadHashmapKey);
- }
- self.emit_seq_elt(idx, f)
- }
-
fn emit_option<F>(&mut self, f: F) -> EncodeResult
where
F: FnOnce(&mut PrettyEncoder<'a>) -> EncodeResult,
Ok(())
}
- fn emit_map_elt_val<F>(&mut self, _idx: usize, f: F) -> EncodeResult
+ fn emit_map_elt_val<F>(&mut self, f: F) -> EncodeResult
where
F: FnOnce(&mut PrettyEncoder<'a>) -> EncodeResult,
{
Ok(())
}
- fn read_enum<T, F>(&mut self, _name: &str, f: F) -> DecodeResult<T>
+ fn read_enum<T, F>(&mut self, f: F) -> DecodeResult<T>
where
F: FnOnce(&mut Decoder) -> DecodeResult<T>,
{
f(self, idx)
}
- fn read_enum_variant_arg<T, F>(&mut self, _idx: usize, f: F) -> DecodeResult<T>
+ fn read_enum_variant_arg<T, F>(&mut self, f: F) -> DecodeResult<T>
where
F: FnOnce(&mut Decoder) -> DecodeResult<T>,
{
f(self)
}
- fn read_enum_struct_variant<T, F>(&mut self, names: &[&str], f: F) -> DecodeResult<T>
- where
- F: FnMut(&mut Decoder, usize) -> DecodeResult<T>,
- {
- self.read_enum_variant(names, f)
- }
-
- fn read_enum_struct_variant_field<T, F>(
- &mut self,
- _name: &str,
- idx: usize,
- f: F,
- ) -> DecodeResult<T>
- where
- F: FnOnce(&mut Decoder) -> DecodeResult<T>,
- {
- self.read_enum_variant_arg(idx, f)
- }
-
- fn read_struct<T, F>(&mut self, _name: &str, _len: usize, f: F) -> DecodeResult<T>
+ fn read_struct<T, F>(&mut self, f: F) -> DecodeResult<T>
where
F: FnOnce(&mut Decoder) -> DecodeResult<T>,
{
Ok(value)
}
- fn read_struct_field<T, F>(&mut self, name: &str, _idx: usize, f: F) -> DecodeResult<T>
+ fn read_struct_field<T, F>(&mut self, name: &str, f: F) -> DecodeResult<T>
where
F: FnOnce(&mut Decoder) -> DecodeResult<T>,
{
})
}
- fn read_tuple_arg<T, F>(&mut self, idx: usize, f: F) -> DecodeResult<T>
- where
- F: FnOnce(&mut Decoder) -> DecodeResult<T>,
- {
- self.read_seq_elt(idx, f)
- }
-
- fn read_tuple_struct<T, F>(&mut self, _name: &str, len: usize, f: F) -> DecodeResult<T>
- where
- F: FnOnce(&mut Decoder) -> DecodeResult<T>,
- {
- self.read_tuple(len, f)
- }
-
- fn read_tuple_struct_arg<T, F>(&mut self, idx: usize, f: F) -> DecodeResult<T>
+ fn read_tuple_arg<T, F>(&mut self, f: F) -> DecodeResult<T>
where
F: FnOnce(&mut Decoder) -> DecodeResult<T>,
{
- self.read_tuple_arg(idx, f)
+ self.read_seq_elt(f)
}
fn read_option<T, F>(&mut self, mut f: F) -> DecodeResult<T>
f(self, len)
}
- fn read_seq_elt<T, F>(&mut self, _idx: usize, f: F) -> DecodeResult<T>
+ fn read_seq_elt<T, F>(&mut self, f: F) -> DecodeResult<T>
where
F: FnOnce(&mut Decoder) -> DecodeResult<T>,
{
f(self, len)
}
- fn read_map_elt_key<T, F>(&mut self, _idx: usize, f: F) -> DecodeResult<T>
+ fn read_map_elt_key<T, F>(&mut self, f: F) -> DecodeResult<T>
where
F: FnOnce(&mut Decoder) -> DecodeResult<T>,
{
f(self)
}
- fn read_map_elt_val<T, F>(&mut self, _idx: usize, f: F) -> DecodeResult<T>
+ fn read_map_elt_val<T, F>(&mut self, f: F) -> DecodeResult<T>
where
F: FnOnce(&mut Decoder) -> DecodeResult<T>,
{
#![feature(nll)]
#![feature(associated_type_bounds)]
#![feature(min_specialization)]
-#![feature(vec_spare_capacity)]
#![feature(core_intrinsics)]
-#![feature(maybe_uninit_array_assume_init)]
-#![feature(maybe_uninit_uninit_array)]
#![feature(maybe_uninit_slice)]
#![feature(new_uninit)]
#![cfg_attr(test, feature(test))]
// Compound types:
#[inline]
- fn emit_enum<F>(&mut self, _name: &str, f: F) -> Result<(), Self::Error>
+ fn emit_enum<F>(&mut self, f: F) -> Result<(), Self::Error>
where
F: FnOnce(&mut Self) -> Result<(), Self::Error>,
{
}
#[inline]
- fn emit_enum_variant_arg<F>(&mut self, _a_idx: usize, f: F) -> Result<(), Self::Error>
+ fn emit_enum_variant_arg<F>(&mut self, _first: bool, f: F) -> Result<(), Self::Error>
where
F: FnOnce(&mut Self) -> Result<(), Self::Error>,
{
f(self)
}
- fn emit_enum_struct_variant<F>(
- &mut self,
- v_name: &str,
- v_id: usize,
- len: usize,
- f: F,
- ) -> Result<(), Self::Error>
- where
- F: FnOnce(&mut Self) -> Result<(), Self::Error>,
- {
- self.emit_enum_variant(v_name, v_id, len, f)
- }
-
- fn emit_enum_struct_variant_field<F>(
- &mut self,
- _f_name: &str,
- f_idx: usize,
- f: F,
- ) -> Result<(), Self::Error>
- where
- F: FnOnce(&mut Self) -> Result<(), Self::Error>,
- {
- self.emit_enum_variant_arg(f_idx, f)
- }
-
#[inline]
- fn emit_struct<F>(&mut self, _name: &str, _len: usize, f: F) -> Result<(), Self::Error>
+ fn emit_struct<F>(&mut self, _no_fields: bool, f: F) -> Result<(), Self::Error>
where
F: FnOnce(&mut Self) -> Result<(), Self::Error>,
{
}
#[inline]
- fn emit_struct_field<F>(
- &mut self,
- _f_name: &str,
- _f_idx: usize,
- f: F,
- ) -> Result<(), Self::Error>
+ fn emit_struct_field<F>(&mut self, _f_name: &str, _first: bool, f: F) -> Result<(), Self::Error>
where
F: FnOnce(&mut Self) -> Result<(), Self::Error>,
{
f(self)
}
- fn emit_tuple_struct<F>(&mut self, _name: &str, len: usize, f: F) -> Result<(), Self::Error>
- where
- F: FnOnce(&mut Self) -> Result<(), Self::Error>,
- {
- self.emit_tuple(len, f)
- }
-
- fn emit_tuple_struct_arg<F>(&mut self, f_idx: usize, f: F) -> Result<(), Self::Error>
- where
- F: FnOnce(&mut Self) -> Result<(), Self::Error>,
- {
- self.emit_tuple_arg(f_idx, f)
- }
-
// Specialized types:
fn emit_option<F>(&mut self, f: F) -> Result<(), Self::Error>
where
F: FnOnce(&mut Self) -> Result<(), Self::Error>,
{
- self.emit_enum("Option", f)
+ self.emit_enum(f)
}
#[inline]
}
#[inline]
- fn emit_map_elt_val<F>(&mut self, _idx: usize, f: F) -> Result<(), Self::Error>
+ fn emit_map_elt_val<F>(&mut self, f: F) -> Result<(), Self::Error>
where
F: FnOnce(&mut Self) -> Result<(), Self::Error>,
{
// Compound types:
#[inline]
- fn read_enum<T, F>(&mut self, _name: &str, f: F) -> Result<T, Self::Error>
+ fn read_enum<T, F>(&mut self, f: F) -> Result<T, Self::Error>
where
F: FnOnce(&mut Self) -> Result<T, Self::Error>,
{
}
#[inline]
- fn read_enum_variant_arg<T, F>(&mut self, _a_idx: usize, f: F) -> Result<T, Self::Error>
+ fn read_enum_variant_arg<T, F>(&mut self, f: F) -> Result<T, Self::Error>
where
F: FnOnce(&mut Self) -> Result<T, Self::Error>,
{
f(self)
}
- fn read_enum_struct_variant<T, F>(&mut self, names: &[&str], f: F) -> Result<T, Self::Error>
- where
- F: FnMut(&mut Self, usize) -> Result<T, Self::Error>,
- {
- self.read_enum_variant(names, f)
- }
-
- fn read_enum_struct_variant_field<T, F>(
- &mut self,
- _f_name: &str,
- f_idx: usize,
- f: F,
- ) -> Result<T, Self::Error>
- where
- F: FnOnce(&mut Self) -> Result<T, Self::Error>,
- {
- self.read_enum_variant_arg(f_idx, f)
- }
-
#[inline]
- fn read_struct<T, F>(&mut self, _s_name: &str, _len: usize, f: F) -> Result<T, Self::Error>
+ fn read_struct<T, F>(&mut self, f: F) -> Result<T, Self::Error>
where
F: FnOnce(&mut Self) -> Result<T, Self::Error>,
{
}
#[inline]
- fn read_struct_field<T, F>(
- &mut self,
- _f_name: &str,
- _f_idx: usize,
- f: F,
- ) -> Result<T, Self::Error>
+ fn read_struct_field<T, F>(&mut self, _f_name: &str, f: F) -> Result<T, Self::Error>
where
F: FnOnce(&mut Self) -> Result<T, Self::Error>,
{
}
#[inline]
- fn read_tuple_arg<T, F>(&mut self, _a_idx: usize, f: F) -> Result<T, Self::Error>
+ fn read_tuple_arg<T, F>(&mut self, f: F) -> Result<T, Self::Error>
where
F: FnOnce(&mut Self) -> Result<T, Self::Error>,
{
f(self)
}
- fn read_tuple_struct<T, F>(&mut self, _s_name: &str, len: usize, f: F) -> Result<T, Self::Error>
- where
- F: FnOnce(&mut Self) -> Result<T, Self::Error>,
- {
- self.read_tuple(len, f)
- }
-
- fn read_tuple_struct_arg<T, F>(&mut self, a_idx: usize, f: F) -> Result<T, Self::Error>
- where
- F: FnOnce(&mut Self) -> Result<T, Self::Error>,
- {
- self.read_tuple_arg(a_idx, f)
- }
-
// Specialized types:
fn read_option<T, F>(&mut self, mut f: F) -> Result<T, Self::Error>
where
F: FnMut(&mut Self, bool) -> Result<T, Self::Error>,
{
- self.read_enum("Option", move |this| {
+ self.read_enum(move |this| {
this.read_enum_variant(&["None", "Some"], move |this, idx| match idx {
0 => f(this, false),
1 => f(this, true),
}
#[inline]
- fn read_seq_elt<T, F>(&mut self, _idx: usize, f: F) -> Result<T, Self::Error>
+ fn read_seq_elt<T, F>(&mut self, f: F) -> Result<T, Self::Error>
where
F: FnOnce(&mut Self) -> Result<T, Self::Error>,
{
}
#[inline]
- fn read_map_elt_key<T, F>(&mut self, _idx: usize, f: F) -> Result<T, Self::Error>
+ fn read_map_elt_key<T, F>(&mut self, f: F) -> Result<T, Self::Error>
where
F: FnOnce(&mut Self) -> Result<T, Self::Error>,
{
}
#[inline]
- fn read_map_elt_val<T, F>(&mut self, _idx: usize, f: F) -> Result<T, Self::Error>
+ fn read_map_elt_val<T, F>(&mut self, f: F) -> Result<T, Self::Error>
where
F: FnOnce(&mut Self) -> Result<T, Self::Error>,
{
default fn decode(d: &mut D) -> Result<Vec<T>, D::Error> {
d.read_seq(|d, len| {
let mut v = Vec::with_capacity(len);
- for i in 0..len {
- v.push(d.read_seq_elt(i, |d| Decodable::decode(d))?);
+ for _ in 0..len {
+ v.push(d.read_seq_elt(|d| Decodable::decode(d))?);
}
Ok(v)
})
assert!(len == N);
let mut v = [0u8; N];
for i in 0..len {
- v[i] = d.read_seq_elt(i, |d| Decodable::decode(d))?;
+ v[i] = d.read_seq_elt(|d| Decodable::decode(d))?;
}
Ok(v)
})
impl<S: Encoder, T1: Encodable<S>, T2: Encodable<S>> Encodable<S> for Result<T1, T2> {
fn encode(&self, s: &mut S) -> Result<(), S::Error> {
- s.emit_enum("Result", |s| match *self {
+ s.emit_enum(|s| match *self {
Ok(ref v) => {
- s.emit_enum_variant("Ok", 0, 1, |s| s.emit_enum_variant_arg(0, |s| v.encode(s)))
+ s.emit_enum_variant("Ok", 0, 1, |s| s.emit_enum_variant_arg(true, |s| v.encode(s)))
}
Err(ref v) => {
- s.emit_enum_variant("Err", 1, 1, |s| s.emit_enum_variant_arg(0, |s| v.encode(s)))
+ s.emit_enum_variant("Err", 1, 1, |s| s.emit_enum_variant_arg(true, |s| v.encode(s)))
}
})
}
impl<D: Decoder, T1: Decodable<D>, T2: Decodable<D>> Decodable<D> for Result<T1, T2> {
fn decode(d: &mut D) -> Result<Result<T1, T2>, D::Error> {
- d.read_enum("Result", |d| {
+ d.read_enum(|d| {
d.read_enum_variant(&["Ok", "Err"], |d, disr| match disr {
- 0 => Ok(Ok(d.read_enum_variant_arg(0, |d| T1::decode(d))?)),
- 1 => Ok(Err(d.read_enum_variant_arg(0, |d| T2::decode(d))?)),
+ 0 => Ok(Ok(d.read_enum_variant_arg(|d| T1::decode(d))?)),
+ 1 => Ok(Err(d.read_enum_variant_arg(|d| T2::decode(d))?)),
_ => {
panic!(
"Encountered invalid discriminant while \
fn decode(d: &mut D) -> Result<($($name,)+), D::Error> {
let len: usize = count!($($name)+);
d.read_tuple(len, |d| {
- let mut i = 0;
- let ret = ($(d.read_tuple_arg({ i+=1; i-1 }, |d| -> Result<$name, D::Error> {
+ let ret = ($(d.read_tuple_arg(|d| -> Result<$name, D::Error> {
Decodable::decode(d)
})?,)+);
Ok(ret)
("\"\\uAB12\"", "\u{AB12}"),
];
- for &(i, o) in &s {
+ for (i, o) in s {
let v: string::String = json::decode(i).unwrap();
assert_eq!(v, o);
}
optimize: OptLevel::No,
debuginfo: DebugInfo::None,
lint_opts: Vec::new(),
+ force_warns: Vec::new(),
lint_cap: None,
describe_lints: false,
output_types: OutputTypes(BTreeMap::new()),
if sess.target.has_elf_tls {
ret.insert((sym::target_thread_local, None));
}
- for &(i, align) in &[
+ for (i, align) in [
(8, layout.i8_align.abi),
(16, layout.i16_align.abi),
(32, layout.i32_align.abi),
level",
"LEVEL",
),
+ opt::multi_s(
+ "",
+ "force-warns",
+ "Specifiy lints that should warn even if \
+ they are allowed somewhere else",
+ "LINT",
+ ),
opt::multi_s("C", "codegen", "Set a codegen option", "OPT[=VALUE]"),
opt::flag_s("V", "version", "Print version info and exit"),
opt::flag_s("v", "verbose", "Use verbose output"),
pub fn get_cmd_lint_options(
matches: &getopts::Matches,
error_format: ErrorOutputType,
-) -> (Vec<(String, lint::Level)>, bool, Option<lint::Level>) {
+ debugging_opts: &DebuggingOptions,
+) -> (Vec<(String, lint::Level)>, bool, Option<lint::Level>, Vec<String>) {
let mut lint_opts_with_position = vec![];
let mut describe_lints = false;
- for &level in &[lint::Allow, lint::Warn, lint::Deny, lint::Forbid] {
+ for level in [lint::Allow, lint::Warn, lint::Deny, lint::Forbid] {
for (passed_arg_pos, lint_name) in matches.opt_strs_pos(level.as_str()) {
let arg_pos = if let lint::Forbid = level {
// HACK: forbid is always specified last, so it can't be overridden.
lint::Level::from_str(&cap)
.unwrap_or_else(|| early_error(error_format, &format!("unknown lint level: `{}`", cap)))
});
- (lint_opts, describe_lints, lint_cap)
+
+ if !debugging_opts.unstable_options && matches.opt_present("force-warns") {
+ early_error(
+ error_format,
+ "the `-Z unstable-options` flag must also be passed to enable \
+ the flag `--force-warns=lints`",
+ );
+ }
+
+ let force_warns =
+ matches.opt_strs("force-warns").into_iter().map(|name| name.replace('-', "_")).collect();
+
+ (lint_opts, describe_lints, lint_cap, force_warns)
}
/// Parses the `--color` flag.
prints
}
-fn parse_target_triple(matches: &getopts::Matches, error_format: ErrorOutputType) -> TargetTriple {
+pub fn parse_target_triple(
+ matches: &getopts::Matches,
+ error_format: ErrorOutputType,
+) -> TargetTriple {
match matches.opt_str("target") {
Some(target) if target.ends_with(".json") => {
let path = Path::new(&target);
let crate_types = parse_crate_types_from_list(unparsed_crate_types)
.unwrap_or_else(|e| early_error(error_format, &e[..]));
- let (lint_opts, describe_lints, lint_cap) = get_cmd_lint_options(matches, error_format);
-
let mut debugging_opts = DebuggingOptions::build(matches, error_format);
+ let (lint_opts, describe_lints, lint_cap, force_warns) =
+ get_cmd_lint_options(matches, error_format, &debugging_opts);
+
check_debug_option_stability(&debugging_opts, error_format, json_rendered);
if !debugging_opts.unstable_options && json_unused_externs {
optimize: opt_level,
debuginfo,
lint_opts,
+ force_warns,
lint_cap,
describe_lints,
output_types,
/// we have an opt-in scheme here, so one is hopefully forced to think about
/// how the hash should be calculated when adding a new command-line argument.
crate mod dep_tracking {
+ use super::LdImpl;
use super::{
CFGuard, CrateType, DebugInfo, ErrorOutputType, InstrumentCoverage, LinkerPluginLto,
LtoCli, OptLevel, OutputTypes, Passes, SourceFileHashAlgorithm, SwitchWithOptPath,
)+};
}
- macro_rules! impl_dep_tracking_hash_for_sortable_vec_of {
- ($($t:ty),+ $(,)?) => {$(
- impl DepTrackingHash for Vec<$t> {
- fn hash(&self, hasher: &mut DefaultHasher, error_format: ErrorOutputType) {
- let mut elems: Vec<&$t> = self.iter().collect();
- elems.sort();
- Hash::hash(&elems.len(), hasher);
- for (index, elem) in elems.iter().enumerate() {
- Hash::hash(&index, hasher);
- DepTrackingHash::hash(*elem, hasher, error_format);
- }
+ impl<T: DepTrackingHash> DepTrackingHash for Option<T> {
+ fn hash(&self, hasher: &mut DefaultHasher, error_format: ErrorOutputType) {
+ match self {
+ Some(x) => {
+ Hash::hash(&1, hasher);
+ DepTrackingHash::hash(x, hasher, error_format);
}
+ None => Hash::hash(&0, hasher),
}
- )+};
+ }
}
impl_dep_tracking_hash_via_hash!(
bool,
usize,
+ NonZeroUsize,
u64,
String,
PathBuf,
lint::Level,
- Option<bool>,
- Option<u32>,
- Option<usize>,
- Option<NonZeroUsize>,
- Option<String>,
- Option<(String, u64)>,
- Option<Vec<String>>,
- Option<MergeFunctions>,
- Option<RelocModel>,
- Option<CodeModel>,
- Option<TlsModel>,
- Option<WasiExecModel>,
- Option<PanicStrategy>,
- Option<RelroLevel>,
- Option<InstrumentCoverage>,
- Option<lint::Level>,
- Option<PathBuf>,
+ WasiExecModel,
+ u32,
+ RelocModel,
+ CodeModel,
+ TlsModel,
+ InstrumentCoverage,
CrateType,
MergeFunctions,
PanicStrategy,
TargetTriple,
Edition,
LinkerPluginLto,
- Option<SplitDebuginfo>,
+ SplitDebuginfo,
SwitchWithOptPath,
- Option<SymbolManglingVersion>,
- Option<SourceFileHashAlgorithm>,
+ SymbolManglingVersion,
+ SourceFileHashAlgorithm,
TrimmedDefPaths,
- );
-
- impl_dep_tracking_hash_for_sortable_vec_of!(
- String,
- PathBuf,
- (PathBuf, PathBuf),
- CrateType,
- NativeLib,
- (String, lint::Level),
- (String, u64)
+ Option<LdImpl>,
);
impl<T1, T2> DepTrackingHash for (T1, T2)
}
}
+ impl<T: DepTrackingHash> DepTrackingHash for Vec<T> {
+ fn hash(&self, hasher: &mut DefaultHasher, error_format: ErrorOutputType) {
+ Hash::hash(&self.len(), hasher);
+ for (index, elem) in self.iter().enumerate() {
+ Hash::hash(&index, hasher);
+ DepTrackingHash::hash(elem, hasher, error_format);
+ }
+ }
+ }
+
// This is a stable hash because BTreeMap is a sorted container
crate fn stable_hash(
sub_hashes: BTreeMap<&'static str, &dyn DepTrackingHash>,
debuginfo: DebugInfo [TRACKED],
lint_opts: Vec<(String, lint::Level)> [TRACKED],
lint_cap: Option<lint::Level> [TRACKED],
+ force_warns: Vec<String> [TRACKED],
describe_lints: bool [UNTRACKED],
output_types: OutputTypes [TRACKED],
search_paths: Vec<SearchPath> [UNTRACKED],
pub const parse_target_feature: &str = parse_string;
pub const parse_wasi_exec_model: &str = "either `command` or `reactor`";
pub const parse_split_debuginfo: &str =
- "one of supported split-debuginfo modes (`off` or `dsymutil`)";
+ "one of supported split-debuginfo modes (`off`, `packed`, or `unpacked`)";
+ pub const parse_gcc_ld: &str = "one of: no value, `lld`";
}
mod parse {
}
true
}
+
+ crate fn parse_gcc_ld(slot: &mut Option<LdImpl>, v: Option<&str>) -> bool {
+ match v {
+ None => *slot = None,
+ Some("lld") => *slot = Some(LdImpl::Lld),
+ _ => return false,
+ }
+ true
+ }
}
options! {
"set the optimization fuel quota for a crate"),
function_sections: Option<bool> = (None, parse_opt_bool, [TRACKED],
"whether each function should go in its own section"),
+ gcc_ld: Option<LdImpl> = (None, parse_gcc_ld, [TRACKED], "implementation of ld used by cc"),
graphviz_dark_mode: bool = (false, parse_bool, [UNTRACKED],
"use dark-themed colors in graphviz output (default: no)"),
graphviz_font: String = ("Courier, monospace".to_string(), parse_string, [UNTRACKED],
Command,
Reactor,
}
+
+#[derive(Clone, Copy, Hash)]
+pub enum LdImpl {
+ Lld,
+}
crate_name: &str,
outputs: &OutputFilenames,
) -> PathBuf {
+ // If the command-line specified the path, use that directly.
+ if let Some(Some(out_filename)) = sess.opts.output_types.get(&OutputType::Metadata) {
+ return out_filename.clone();
+ }
+
let libname = format!("{}{}", crate_name, sess.opts.cg.extra_filename);
let out_filename = outputs
pub fn emit_err<'a>(&'a self, err: impl SessionDiagnostic<'a>) {
err.into_diagnostic(self).emit()
}
+ #[inline]
pub fn err_count(&self) -> usize {
self.diagnostic().err_count()
}
self.diagnostic().struct_note_without_error(msg)
}
+ #[inline]
pub fn diagnostic(&self) -> &rustc_errors::Handler {
&self.parse_sess.span_diagnostic
}
if let (Some(first), Some(second)) = (sanitizer_iter.next(), sanitizer_iter.next()) {
sess.err(&format!("`-Zsanitizer={}` is incompatible with `-Zsanitizer={}`", first, second));
}
+
+ // Cannot enable crt-static with sanitizers on Linux
+ if sess.crt_static(None) && !sess.opts.debugging_opts.sanitizer.is_empty() {
+ sess.err(
+ "Sanitizer is incompatible with statically linked libc, \
+ disable it using `-C target-feature=-crt-static`",
+ );
+ }
}
/// Holds data on the current incremental compilation session, if there is one.
use crate::crate_disambiguator::CrateDisambiguator;
use crate::HashStableContext;
use rustc_data_structures::fingerprint::Fingerprint;
-use rustc_data_structures::stable_hasher::{HashStable, StableHasher};
+use rustc_data_structures::stable_hasher::{HashStable, StableHasher, ToStableHashKey};
use rustc_data_structures::AtomicRef;
use rustc_index::vec::Idx;
use rustc_macros::HashStable_Generic;
use std::fmt;
rustc_index::newtype_index! {
- pub struct CrateId {
+ pub struct CrateNum {
ENCODABLE = custom
+ DEBUG_FORMAT = "crate{}"
}
}
-#[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
-pub enum CrateNum {
- /// A special `CrateNum` that we use for the `tcx.rcache` when decoding from
- /// the incr. comp. cache.
- ReservedForIncrCompCache,
- Index(CrateId),
-}
-
/// Item definitions in the currently-compiled crate would have the `CrateNum`
/// `LOCAL_CRATE` in their `DefId`.
-pub const LOCAL_CRATE: CrateNum = CrateNum::Index(CrateId::from_u32(0));
-
-impl Idx for CrateNum {
- #[inline]
- fn new(value: usize) -> Self {
- CrateNum::Index(Idx::new(value))
- }
-
- #[inline]
- fn index(self) -> usize {
- match self {
- CrateNum::Index(idx) => Idx::index(idx),
- _ => panic!("Tried to get crate index of {:?}", self),
- }
- }
-}
+pub const LOCAL_CRATE: CrateNum = CrateNum::from_u32(0);
impl CrateNum {
+ #[inline]
pub fn new(x: usize) -> CrateNum {
CrateNum::from_usize(x)
}
- pub fn from_usize(x: usize) -> CrateNum {
- CrateNum::Index(CrateId::from_usize(x))
- }
-
- pub fn from_u32(x: u32) -> CrateNum {
- CrateNum::Index(CrateId::from_u32(x))
- }
-
- pub fn as_usize(self) -> usize {
- match self {
- CrateNum::Index(id) => id.as_usize(),
- _ => panic!("tried to get index of non-standard crate {:?}", self),
- }
- }
-
- pub fn as_u32(self) -> u32 {
- match self {
- CrateNum::Index(id) => id.as_u32(),
- _ => panic!("tried to get index of non-standard crate {:?}", self),
- }
- }
-
+ #[inline]
pub fn as_def_id(&self) -> DefId {
DefId { krate: *self, index: CRATE_DEF_INDEX }
}
impl fmt::Display for CrateNum {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
- match self {
- CrateNum::Index(id) => fmt::Display::fmt(&id.private, f),
- CrateNum::ReservedForIncrCompCache => write!(f, "crate for decoding incr comp cache"),
- }
+ fmt::Display::fmt(&self.private, f)
}
}
}
}
-impl ::std::fmt::Debug for CrateNum {
- fn fmt(&self, fmt: &mut ::std::fmt::Formatter<'_>) -> ::std::fmt::Result {
- match self {
- CrateNum::Index(id) => write!(fmt, "crate{}", id.private),
- CrateNum::ReservedForIncrCompCache => write!(fmt, "crate for decoding incr comp cache"),
- }
- }
-}
-
/// A `DefPathHash` is a fixed-size representation of a `DefPath` that is
/// stable across crate and compilation session boundaries. It consists of two
/// separate 64-bit hashes. The first uniquely identifies the crate this
impl<E: Encoder> Encodable<E> for DefId {
default fn encode(&self, s: &mut E) -> Result<(), E::Error> {
- s.emit_struct("DefId", 2, |s| {
- s.emit_struct_field("krate", 0, |s| self.krate.encode(s))?;
+ s.emit_struct(false, |s| {
+ s.emit_struct_field("krate", true, |s| self.krate.encode(s))?;
- s.emit_struct_field("index", 1, |s| self.index.encode(s))
+ s.emit_struct_field("index", false, |s| self.index.encode(s))
})
}
}
impl<D: Decoder> Decodable<D> for DefId {
default fn decode(d: &mut D) -> Result<DefId, D::Error> {
- d.read_struct("DefId", 2, |d| {
+ d.read_struct(|d| {
Ok(DefId {
- krate: d.read_struct_field("krate", 0, Decodable::decode)?,
- index: d.read_struct_field("index", 1, Decodable::decode)?,
+ krate: d.read_struct_field("krate", Decodable::decode)?,
+ index: d.read_struct_field("index", Decodable::decode)?,
})
})
}
rustc_data_structures::define_id_collections!(LocalDefIdMap, LocalDefIdSet, LocalDefId);
impl<CTX: HashStableContext> HashStable<CTX> for DefId {
+ #[inline]
+ fn hash_stable(&self, hcx: &mut CTX, hasher: &mut StableHasher) {
+ self.to_stable_hash_key(hcx).hash_stable(hcx, hasher);
+ }
+}
+
+impl<CTX: HashStableContext> HashStable<CTX> for LocalDefId {
+ #[inline]
fn hash_stable(&self, hcx: &mut CTX, hasher: &mut StableHasher) {
- hcx.hash_def_id(*self, hasher)
+ self.to_stable_hash_key(hcx).hash_stable(hcx, hasher);
}
}
impl<CTX: HashStableContext> HashStable<CTX> for CrateNum {
+ #[inline]
fn hash_stable(&self, hcx: &mut CTX, hasher: &mut StableHasher) {
- hcx.hash_crate_num(*self, hasher)
+ self.to_stable_hash_key(hcx).hash_stable(hcx, hasher);
+ }
+}
+
+impl<CTX: HashStableContext> ToStableHashKey<CTX> for DefId {
+ type KeyType = DefPathHash;
+
+ #[inline]
+ fn to_stable_hash_key(&self, hcx: &CTX) -> DefPathHash {
+ hcx.def_path_hash(*self)
+ }
+}
+
+impl<CTX: HashStableContext> ToStableHashKey<CTX> for LocalDefId {
+ type KeyType = DefPathHash;
+
+ #[inline]
+ fn to_stable_hash_key(&self, hcx: &CTX) -> DefPathHash {
+ hcx.def_path_hash(self.to_def_id())
+ }
+}
+
+impl<CTX: HashStableContext> ToStableHashKey<CTX> for CrateNum {
+ type KeyType = DefPathHash;
+
+ #[inline]
+ fn to_stable_hash_key(&self, hcx: &CTX) -> DefPathHash {
+ self.as_def_id().to_stable_hash_key(hcx)
}
}
use crate::SESSION_GLOBALS;
use crate::{BytePos, CachingSourceMapView, ExpnIdCache, SourceFile, Span, DUMMY_SP};
-use crate::def_id::{CrateNum, DefId, CRATE_DEF_INDEX, LOCAL_CRATE};
+use crate::def_id::{CrateNum, DefId, DefPathHash, CRATE_DEF_INDEX, LOCAL_CRATE};
use rustc_data_structures::fingerprint::Fingerprint;
use rustc_data_structures::fx::{FxHashMap, FxHashSet};
use rustc_data_structures::stable_hasher::{HashStable, StableHasher};
}
impl<'a> crate::HashStableContext for DummyHashStableContext<'a> {
- fn hash_def_id(&mut self, def_id: DefId, hasher: &mut StableHasher) {
- def_id.krate.as_u32().hash_stable(self, hasher);
- def_id.index.as_u32().hash_stable(self, hasher);
+ #[inline]
+ fn def_path_hash(&self, def_id: DefId) -> DefPathHash {
+ DefPathHash(Fingerprint::new(
+ def_id.krate.as_u32().into(),
+ def_id.index.as_u32().into(),
+ ))
}
fn expn_id_cache() -> &'static LocalKey<ExpnIdCache> {
&CACHE
}
- fn hash_crate_num(&mut self, krate: CrateNum, hasher: &mut StableHasher) {
- krate.as_u32().hash_stable(self, hasher);
- }
fn hash_spans(&self) -> bool {
true
}
#![doc(html_root_url = "https://doc.rust-lang.org/nightly/nightly-rustc/")]
#![feature(array_windows)]
#![feature(crate_visibility_modifier)]
-#![feature(const_panic)]
#![feature(negative_impls)]
#![feature(nll)]
#![feature(min_specialization)]
use hygiene::Transparency;
pub use hygiene::{DesugaringKind, ExpnData, ExpnId, ExpnKind, ForLoopLoc, MacroKind};
pub mod def_id;
-use def_id::{CrateNum, DefId, LOCAL_CRATE};
+use def_id::{CrateNum, DefId, DefPathHash, LOCAL_CRATE};
pub mod lev_distance;
mod span_encoding;
pub use span_encoding::{Span, DUMMY_SP};
// an added assert statement
impl<S: Encoder> Encodable<S> for RealFileName {
fn encode(&self, encoder: &mut S) -> Result<(), S::Error> {
- encoder.emit_enum("RealFileName", |encoder| match *self {
+ encoder.emit_enum(|encoder| match *self {
RealFileName::LocalPath(ref local_path) => {
encoder.emit_enum_variant("LocalPath", 0, 1, |encoder| {
Ok({
- encoder.emit_enum_variant_arg(0, |encoder| local_path.encode(encoder))?;
+ encoder
+ .emit_enum_variant_arg(true, |encoder| local_path.encode(encoder))?;
})
})
}
// if they have been remapped by --remap-path-prefix
assert!(local_path.is_none());
Ok({
- encoder.emit_enum_variant_arg(0, |encoder| local_path.encode(encoder))?;
- encoder.emit_enum_variant_arg(1, |encoder| virtual_name.encode(encoder))?;
+ encoder
+ .emit_enum_variant_arg(true, |encoder| local_path.encode(encoder))?;
+ encoder
+ .emit_enum_variant_arg(false, |encoder| virtual_name.encode(encoder))?;
})
}),
})
impl<E: Encoder> Encodable<E> for Span {
default fn encode(&self, s: &mut E) -> Result<(), E::Error> {
let span = self.data();
- s.emit_struct("Span", 2, |s| {
- s.emit_struct_field("lo", 0, |s| span.lo.encode(s))?;
- s.emit_struct_field("hi", 1, |s| span.hi.encode(s))
+ s.emit_struct(false, |s| {
+ s.emit_struct_field("lo", true, |s| span.lo.encode(s))?;
+ s.emit_struct_field("hi", false, |s| span.hi.encode(s))
})
}
}
impl<D: Decoder> Decodable<D> for Span {
default fn decode(s: &mut D) -> Result<Span, D::Error> {
- s.read_struct("Span", 2, |d| {
- let lo = d.read_struct_field("lo", 0, Decodable::decode)?;
- let hi = d.read_struct_field("hi", 1, Decodable::decode)?;
+ s.read_struct(|d| {
+ let lo = d.read_struct_field("lo", Decodable::decode)?;
+ let hi = d.read_struct_field("hi", Decodable::decode)?;
Ok(Span::new(lo, hi, SyntaxContext::root()))
})
impl<S: Encoder> Encodable<S> for SourceFile {
fn encode(&self, s: &mut S) -> Result<(), S::Error> {
- s.emit_struct("SourceFile", 8, |s| {
- s.emit_struct_field("name", 0, |s| self.name.encode(s))?;
- s.emit_struct_field("src_hash", 2, |s| self.src_hash.encode(s))?;
- s.emit_struct_field("start_pos", 3, |s| self.start_pos.encode(s))?;
- s.emit_struct_field("end_pos", 4, |s| self.end_pos.encode(s))?;
- s.emit_struct_field("lines", 5, |s| {
+ s.emit_struct(false, |s| {
+ s.emit_struct_field("name", true, |s| self.name.encode(s))?;
+ s.emit_struct_field("src_hash", false, |s| self.src_hash.encode(s))?;
+ s.emit_struct_field("start_pos", false, |s| self.start_pos.encode(s))?;
+ s.emit_struct_field("end_pos", false, |s| self.end_pos.encode(s))?;
+ s.emit_struct_field("lines", false, |s| {
let lines = &self.lines[..];
// Store the length.
s.emit_u32(lines.len() as u32)?;
Ok(())
})?;
- s.emit_struct_field("multibyte_chars", 6, |s| self.multibyte_chars.encode(s))?;
- s.emit_struct_field("non_narrow_chars", 7, |s| self.non_narrow_chars.encode(s))?;
- s.emit_struct_field("name_hash", 8, |s| self.name_hash.encode(s))?;
- s.emit_struct_field("normalized_pos", 9, |s| self.normalized_pos.encode(s))?;
- s.emit_struct_field("cnum", 10, |s| self.cnum.encode(s))
+ s.emit_struct_field("multibyte_chars", false, |s| self.multibyte_chars.encode(s))?;
+ s.emit_struct_field("non_narrow_chars", false, |s| self.non_narrow_chars.encode(s))?;
+ s.emit_struct_field("name_hash", false, |s| self.name_hash.encode(s))?;
+ s.emit_struct_field("normalized_pos", false, |s| self.normalized_pos.encode(s))?;
+ s.emit_struct_field("cnum", false, |s| self.cnum.encode(s))
})
}
}
impl<D: Decoder> Decodable<D> for SourceFile {
fn decode(d: &mut D) -> Result<SourceFile, D::Error> {
- d.read_struct("SourceFile", 8, |d| {
- let name: FileName = d.read_struct_field("name", 0, |d| Decodable::decode(d))?;
+ d.read_struct(|d| {
+ let name: FileName = d.read_struct_field("name", |d| Decodable::decode(d))?;
let src_hash: SourceFileHash =
- d.read_struct_field("src_hash", 2, |d| Decodable::decode(d))?;
- let start_pos: BytePos =
- d.read_struct_field("start_pos", 3, |d| Decodable::decode(d))?;
- let end_pos: BytePos = d.read_struct_field("end_pos", 4, |d| Decodable::decode(d))?;
- let lines: Vec<BytePos> = d.read_struct_field("lines", 5, |d| {
+ d.read_struct_field("src_hash", |d| Decodable::decode(d))?;
+ let start_pos: BytePos = d.read_struct_field("start_pos", |d| Decodable::decode(d))?;
+ let end_pos: BytePos = d.read_struct_field("end_pos", |d| Decodable::decode(d))?;
+ let lines: Vec<BytePos> = d.read_struct_field("lines", |d| {
let num_lines: u32 = Decodable::decode(d)?;
let mut lines = Vec::with_capacity(num_lines as usize);
Ok(lines)
})?;
let multibyte_chars: Vec<MultiByteChar> =
- d.read_struct_field("multibyte_chars", 6, |d| Decodable::decode(d))?;
+ d.read_struct_field("multibyte_chars", |d| Decodable::decode(d))?;
let non_narrow_chars: Vec<NonNarrowChar> =
- d.read_struct_field("non_narrow_chars", 7, |d| Decodable::decode(d))?;
- let name_hash: u128 = d.read_struct_field("name_hash", 8, |d| Decodable::decode(d))?;
+ d.read_struct_field("non_narrow_chars", |d| Decodable::decode(d))?;
+ let name_hash: u128 = d.read_struct_field("name_hash", |d| Decodable::decode(d))?;
let normalized_pos: Vec<NormalizedPos> =
- d.read_struct_field("normalized_pos", 9, |d| Decodable::decode(d))?;
- let cnum: CrateNum = d.read_struct_field("cnum", 10, |d| Decodable::decode(d))?;
+ d.read_struct_field("normalized_pos", |d| Decodable::decode(d))?;
+ let cnum: CrateNum = d.read_struct_field("cnum", |d| Decodable::decode(d))?;
Ok(SourceFile {
name,
start_pos,
/// This is a hack to allow using the [`HashStable_Generic`] derive macro
/// instead of implementing everything in rustc_middle.
pub trait HashStableContext {
- fn hash_def_id(&mut self, _: DefId, hasher: &mut StableHasher);
+ fn def_path_hash(&self, def_id: DefId) -> DefPathHash;
/// Obtains a cache for storing the `Fingerprint` of an `ExpnId`.
/// This method allows us to have multiple `HashStableContext` implementations
/// that hash things in a different way, without the results of one polluting
/// the cache of the other.
fn expn_id_cache() -> &'static LocalKey<ExpnIdCache>;
- fn hash_crate_num(&mut self, _: CrateNum, hasher: &mut StableHasher);
fn hash_spans(&self) -> bool;
fn span_data_to_lines_and_cols(
&mut self,
}
fn span_to_string(&self, sp: Span, prefer_local: bool) -> String {
- if self.files.borrow().source_files.is_empty() && sp.is_dummy() {
+ if self.files.borrow().source_files.is_empty() || sp.is_dummy() {
return "no-location".to_string();
}
box_free,
box_patterns,
box_syntax,
+ bpf_target_feature,
braced_empty_structs,
branch,
breakpoint,
constructor,
contents,
context,
- control_flow_enum,
convert,
copy,
copy_closures,
modifiers,
module,
module_path,
+ more_qualified_paths,
more_struct_aliases,
movbe_target_feature,
move_ref_pattern,
wrapping_add,
wrapping_mul,
wrapping_sub,
+ wreg,
write_bytes,
xmm_reg,
ymm_reg,
substs.hash_stable(&mut hcx, &mut hasher);
if let Some(instantiating_crate) = instantiating_crate {
- tcx.original_crate_name(instantiating_crate)
- .as_str()
- .hash_stable(&mut hcx, &mut hasher);
+ tcx.crate_name(instantiating_crate).as_str().hash_stable(&mut hcx, &mut hasher);
tcx.crate_disambiguator(instantiating_crate).hash_stable(&mut hcx, &mut hasher);
}
}
fn path_crate(mut self, cnum: CrateNum) -> Result<Self::Path, Self::Error> {
- self.write_str(&self.tcx.original_crate_name(cnum).as_str())?;
+ self.write_str(&self.tcx.crate_name(cnum).as_str())?;
Ok(self)
}
fn path_qualified(
self.push("C");
let fingerprint = self.tcx.crate_disambiguator(cnum).to_fingerprint();
self.push_disambiguator(fingerprint.to_smaller_hash());
- let name = self.tcx.original_crate_name(cnum).as_str();
+ let name = self.tcx.crate_name(cnum).as_str();
self.push_ident(&name);
Ok(self)
}
--- /dev/null
+// see https://github.com/llvm/llvm-project/blob/main/llvm/lib/Target/BPF/BPFCallingConv.td
+use crate::abi::call::{ArgAbi, FnAbi};
+
+fn classify_ret<Ty>(ret: &mut ArgAbi<'_, Ty>) {
+ if ret.layout.is_aggregate() || ret.layout.size.bits() > 64 {
+ ret.make_indirect();
+ } else {
+ ret.extend_integer_width_to(32);
+ }
+}
+
+fn classify_arg<Ty>(arg: &mut ArgAbi<'_, Ty>) {
+ if arg.layout.is_aggregate() || arg.layout.size.bits() > 64 {
+ arg.make_indirect();
+ } else {
+ arg.extend_integer_width_to(32);
+ }
+}
+
+pub fn compute_abi_info<Ty>(fn_abi: &mut FnAbi<'_, Ty>) {
+ if !fn_abi.ret.is_ignore() {
+ classify_ret(&mut fn_abi.ret);
+ }
+
+ for arg in &mut fn_abi.args {
+ if arg.is_ignore() {
+ continue;
+ }
+ classify_arg(arg);
+ }
+}
mod amdgpu;
mod arm;
mod avr;
+mod bpf;
mod hexagon;
mod mips;
mod mips64;
}
}
"asmjs" => wasm::compute_c_abi_info(cx, self),
+ "bpf" => bpf::compute_abi_info(self),
a => return Err(format!("unrecognized arch \"{}\" in target specification", a)),
}
if let Ok(cls) = cls_or_mem {
let mut needed_int = 0;
let mut needed_sse = 0;
- for &c in &cls {
+ for c in cls {
match c {
Some(Class::Int) => needed_int += 1,
Some(Class::Sse) => needed_sse += 1,
}
impl HasDataLayout for TargetDataLayout {
+ #[inline]
fn data_layout(&self) -> &TargetDataLayout {
self
}
pub fn for_align<C: HasDataLayout>(cx: &C, wanted: Align) -> Option<Integer> {
let dl = cx.data_layout();
- for &candidate in &[I8, I16, I32, I64, I128] {
+ for candidate in [I8, I16, I32, I64, I128] {
if wanted == candidate.align(dl).abi && wanted.bytes() == candidate.size().bytes() {
return Some(candidate);
}
let dl = cx.data_layout();
// FIXME(eddyb) maybe include I128 in the future, when it works everywhere.
- for &candidate in &[I64, I32, I16] {
+ for candidate in [I64, I32, I16] {
if wanted >= candidate.align(dl).abi && wanted.bytes() >= candidate.size().bytes() {
return candidate;
}
match *self {
FieldsShape::Primitive => 0,
FieldsShape::Union(count) => count.get(),
- FieldsShape::Array { count, .. } => {
- let usize_count = count as usize;
- assert_eq!(usize_count as u64, count);
- usize_count
- }
+ FieldsShape::Array { count, .. } => count.try_into().unwrap(),
FieldsShape::Arbitrary { ref offsets, .. } => offsets.len(),
}
}
unreachable!("FieldsShape::memory_index: `Primitive`s have no fields")
}
FieldsShape::Union(_) | FieldsShape::Array { .. } => i,
- FieldsShape::Arbitrary { ref memory_index, .. } => {
- let r = memory_index[i];
- assert_eq!(r as usize as u32, r);
- r as usize
- }
+ FieldsShape::Arbitrary { ref memory_index, .. } => memory_index[i].try_into().unwrap(),
}
}
impl Abi {
/// Returns `true` if the layout corresponds to an unsized type.
+ #[inline]
pub fn is_unsized(&self) -> bool {
match *self {
Abi::Uninhabited | Abi::Scalar(_) | Abi::ScalarPair(..) | Abi::Vector { .. } => false,
}
/// Returns `true` if this is an uninhabited type
+ #[inline]
pub fn is_uninhabited(&self) -> bool {
matches!(*self, Abi::Uninhabited)
}
/// Returns `true` is this is a scalar type
+ #[inline]
pub fn is_scalar(&self) -> bool {
matches!(*self, Abi::Scalar(_))
}
--- /dev/null
+use super::{InlineAsmArch, InlineAsmType, Target};
+use rustc_macros::HashStable_Generic;
+use std::fmt;
+
+def_reg_class! {
+ Bpf BpfInlineAsmRegClass {
+ reg,
+ wreg,
+ }
+}
+
+impl BpfInlineAsmRegClass {
+ pub fn valid_modifiers(self, _arch: InlineAsmArch) -> &'static [char] {
+ &[]
+ }
+
+ pub fn suggest_class(self, _arch: InlineAsmArch, _ty: InlineAsmType) -> Option<Self> {
+ None
+ }
+
+ pub fn suggest_modifier(
+ self,
+ _arch: InlineAsmArch,
+ _ty: InlineAsmType,
+ ) -> Option<(char, &'static str)> {
+ None
+ }
+
+ pub fn default_modifier(self, _arch: InlineAsmArch) -> Option<(char, &'static str)> {
+ None
+ }
+
+ pub fn supported_types(
+ self,
+ _arch: InlineAsmArch,
+ ) -> &'static [(InlineAsmType, Option<&'static str>)] {
+ match self {
+ Self::reg => types! { _: I8, I16, I32, I64; },
+ Self::wreg => types! { "alu32": I8, I16, I32; },
+ }
+ }
+}
+
+fn only_alu32(
+ _arch: InlineAsmArch,
+ mut has_feature: impl FnMut(&str) -> bool,
+ _target: &Target,
+) -> Result<(), &'static str> {
+ if !has_feature("alu32") {
+ Err("register can't be used without the `alu32` target feature")
+ } else {
+ Ok(())
+ }
+}
+
+def_regs! {
+ Bpf BpfInlineAsmReg BpfInlineAsmRegClass {
+ r0: reg = ["r0"],
+ r1: reg = ["r1"],
+ r2: reg = ["r2"],
+ r3: reg = ["r3"],
+ r4: reg = ["r4"],
+ r5: reg = ["r5"],
+ r6: reg = ["r6"],
+ r7: reg = ["r7"],
+ r8: reg = ["r8"],
+ r9: reg = ["r9"],
+ w0: wreg = ["w0"] % only_alu32,
+ w1: wreg = ["w1"] % only_alu32,
+ w2: wreg = ["w2"] % only_alu32,
+ w3: wreg = ["w3"] % only_alu32,
+ w4: wreg = ["w4"] % only_alu32,
+ w5: wreg = ["w5"] % only_alu32,
+ w6: wreg = ["w6"] % only_alu32,
+ w7: wreg = ["w7"] % only_alu32,
+ w8: wreg = ["w8"] % only_alu32,
+ w9: wreg = ["w9"] % only_alu32,
+
+ #error = ["r10", "w10"] =>
+ "the stack pointer cannot be used as an operand for inline asm",
+ }
+}
+
+impl BpfInlineAsmReg {
+ pub fn emit(
+ self,
+ out: &mut dyn fmt::Write,
+ _arch: InlineAsmArch,
+ _modifier: Option<char>,
+ ) -> fmt::Result {
+ out.write_str(self.name())
+ }
+
+ pub fn overlapping_regs(self, mut cb: impl FnMut(BpfInlineAsmReg)) {
+ cb(self);
+
+ macro_rules! reg_conflicts {
+ (
+ $(
+ $r:ident : $w:ident
+ ),*
+ ) => {
+ match self {
+ $(
+ Self::$r => {
+ cb(Self::$w);
+ }
+ Self::$w => {
+ cb(Self::$r);
+ }
+ )*
+ }
+ };
+ }
+
+ reg_conflicts! {
+ r0 : w0,
+ r1 : w1,
+ r2 : w2,
+ r3 : w3,
+ r4 : w4,
+ r5 : w5,
+ r6 : w6,
+ r7 : w7,
+ r8 : w8,
+ r9 : w9
+ }
+ }
+}
mod aarch64;
mod arm;
+mod bpf;
mod hexagon;
mod mips;
mod nvptx;
pub use aarch64::{AArch64InlineAsmReg, AArch64InlineAsmRegClass};
pub use arm::{ArmInlineAsmReg, ArmInlineAsmRegClass};
+pub use bpf::{BpfInlineAsmReg, BpfInlineAsmRegClass};
pub use hexagon::{HexagonInlineAsmReg, HexagonInlineAsmRegClass};
pub use mips::{MipsInlineAsmReg, MipsInlineAsmRegClass};
pub use nvptx::{NvptxInlineAsmReg, NvptxInlineAsmRegClass};
PowerPC64,
SpirV,
Wasm32,
+ Bpf,
}
impl FromStr for InlineAsmArch {
"mips64" => Ok(Self::Mips64),
"spirv" => Ok(Self::SpirV),
"wasm32" => Ok(Self::Wasm32),
+ "bpf" => Ok(Self::Bpf),
_ => Err(()),
}
}
Mips(MipsInlineAsmReg),
SpirV(SpirVInlineAsmReg),
Wasm(WasmInlineAsmReg),
+ Bpf(BpfInlineAsmReg),
// Placeholder for invalid register constraints for the current target
Err,
}
Self::PowerPC(r) => r.name(),
Self::Hexagon(r) => r.name(),
Self::Mips(r) => r.name(),
+ Self::Bpf(r) => r.name(),
Self::Err => "<reg>",
}
}
Self::PowerPC(r) => InlineAsmRegClass::PowerPC(r.reg_class()),
Self::Hexagon(r) => InlineAsmRegClass::Hexagon(r.reg_class()),
Self::Mips(r) => InlineAsmRegClass::Mips(r.reg_class()),
+ Self::Bpf(r) => InlineAsmRegClass::Bpf(r.reg_class()),
Self::Err => InlineAsmRegClass::Err,
}
}
InlineAsmArch::Wasm32 => {
Self::Wasm(WasmInlineAsmReg::parse(arch, has_feature, target, &name)?)
}
+ InlineAsmArch::Bpf => {
+ Self::Bpf(BpfInlineAsmReg::parse(arch, has_feature, target, &name)?)
+ }
})
}
Self::PowerPC(r) => r.emit(out, arch, modifier),
Self::Hexagon(r) => r.emit(out, arch, modifier),
Self::Mips(r) => r.emit(out, arch, modifier),
+ Self::Bpf(r) => r.emit(out, arch, modifier),
Self::Err => unreachable!("Use of InlineAsmReg::Err"),
}
}
Self::PowerPC(_) => cb(self),
Self::Hexagon(r) => r.overlapping_regs(|r| cb(Self::Hexagon(r))),
Self::Mips(_) => cb(self),
+ Self::Bpf(r) => r.overlapping_regs(|r| cb(Self::Bpf(r))),
Self::Err => unreachable!("Use of InlineAsmReg::Err"),
}
}
Mips(MipsInlineAsmRegClass),
SpirV(SpirVInlineAsmRegClass),
Wasm(WasmInlineAsmRegClass),
+ Bpf(BpfInlineAsmRegClass),
// Placeholder for invalid register constraints for the current target
Err,
}
Self::Mips(r) => r.name(),
Self::SpirV(r) => r.name(),
Self::Wasm(r) => r.name(),
+ Self::Bpf(r) => r.name(),
Self::Err => rustc_span::symbol::sym::reg,
}
}
Self::Mips(r) => r.suggest_class(arch, ty).map(InlineAsmRegClass::Mips),
Self::SpirV(r) => r.suggest_class(arch, ty).map(InlineAsmRegClass::SpirV),
Self::Wasm(r) => r.suggest_class(arch, ty).map(InlineAsmRegClass::Wasm),
+ Self::Bpf(r) => r.suggest_class(arch, ty).map(InlineAsmRegClass::Bpf),
Self::Err => unreachable!("Use of InlineAsmRegClass::Err"),
}
}
Self::Mips(r) => r.suggest_modifier(arch, ty),
Self::SpirV(r) => r.suggest_modifier(arch, ty),
Self::Wasm(r) => r.suggest_modifier(arch, ty),
+ Self::Bpf(r) => r.suggest_modifier(arch, ty),
Self::Err => unreachable!("Use of InlineAsmRegClass::Err"),
}
}
Self::Mips(r) => r.default_modifier(arch),
Self::SpirV(r) => r.default_modifier(arch),
Self::Wasm(r) => r.default_modifier(arch),
+ Self::Bpf(r) => r.default_modifier(arch),
Self::Err => unreachable!("Use of InlineAsmRegClass::Err"),
}
}
Self::Mips(r) => r.supported_types(arch),
Self::SpirV(r) => r.supported_types(arch),
Self::Wasm(r) => r.supported_types(arch),
+ Self::Bpf(r) => r.supported_types(arch),
Self::Err => unreachable!("Use of InlineAsmRegClass::Err"),
}
}
}
InlineAsmArch::SpirV => Self::SpirV(SpirVInlineAsmRegClass::parse(arch, name)?),
InlineAsmArch::Wasm32 => Self::Wasm(WasmInlineAsmRegClass::parse(arch, name)?),
+ InlineAsmArch::Bpf => Self::Bpf(BpfInlineAsmRegClass::parse(arch, name)?),
})
}
Self::Mips(r) => r.valid_modifiers(arch),
Self::SpirV(r) => r.valid_modifiers(arch),
Self::Wasm(r) => r.valid_modifiers(arch),
+ Self::Bpf(r) => r.valid_modifiers(arch),
Self::Err => unreachable!("Use of InlineAsmRegClass::Err"),
}
}
wasm::fill_reg_map(arch, has_feature, target, &mut map);
map
}
+ InlineAsmArch::Bpf => {
+ let mut map = bpf::regclass_map();
+ bpf::fill_reg_map(arch, has_feature, target, &mut map);
+ map
+ }
}
}
#![doc(html_root_url = "https://doc.rust-lang.org/nightly/nightly-rustc/")]
#![feature(bool_to_option)]
-#![feature(const_panic)]
#![feature(nll)]
#![feature(never_type)]
#![feature(associated_type_bounds)]
#![feature(exhaustive_patterns)]
+#![feature(min_specialization)]
use std::path::{Path, PathBuf};
arch: "aarch64".to_string(),
options: TargetOptions {
features: "+neon,+fp-armv8,+apple-a7".to_string(),
- eliminate_frame_pointer: false,
max_atomic_width: Some(128),
unsupported_abis: super::arm_base::unsupported_abis(),
forces_embed_bitcode: true,
arch: "aarch64".to_string(),
options: TargetOptions {
features: "+neon,+fp-armv8,+apple-a12".to_string(),
- eliminate_frame_pointer: false,
max_atomic_width: Some(128),
unsupported_abis: super::arm_base::unsupported_abis(),
forces_embed_bitcode: true,
arch: "aarch64".to_string(),
options: TargetOptions {
features: "+neon,+fp-armv8,+apple-a7".to_string(),
- eliminate_frame_pointer: false,
max_atomic_width: Some(128),
unsupported_abis: super::arm_base::unsupported_abis(),
forces_embed_bitcode: true,
arch: "aarch64".to_string(),
options: TargetOptions {
features: "+neon,+fp-armv8,+apple-a7".to_string(),
- eliminate_frame_pointer: false,
max_atomic_width: Some(128),
unsupported_abis: super::arm_base::unsupported_abis(),
forces_embed_bitcode: true,
families: vec!["unix".to_string()],
is_like_osx: true,
dwarf_version: Some(2),
+ eliminate_frame_pointer: false,
has_rpath: true,
dll_suffix: ".dylib".to_string(),
archive_format: "darwin".to_string(),
executables: true,
link_env_remove: link_env_remove(arch),
has_elf_tls: false,
- eliminate_frame_pointer: false,
..super::apple_base::opts(os)
}
}
--- /dev/null
+use crate::spec::{LinkerFlavor, MergeFunctions, PanicStrategy, TargetOptions};
+use crate::{abi::Endian, spec::abi::Abi};
+
+pub fn opts(endian: Endian) -> TargetOptions {
+ TargetOptions {
+ allow_asm: true,
+ endian,
+ linker_flavor: LinkerFlavor::BpfLinker,
+ atomic_cas: false,
+ executables: true,
+ dynamic_linking: true,
+ no_builtins: true,
+ panic_strategy: PanicStrategy::Abort,
+ position_independent_executables: true,
+ // Disable MergeFunctions since:
+ // - older kernels don't support bpf-to-bpf calls
+ // - on newer kernels, userspace still needs to relocate before calling
+ // BPF_PROG_LOAD and not all BPF libraries do that yet
+ merge_functions: MergeFunctions::Disabled,
+ obj_is_bitcode: true,
+ requires_lto: false,
+ singlethread: true,
+ max_atomic_width: Some(64),
+ unsupported_abis: vec![
+ Abi::Cdecl,
+ Abi::Stdcall { unwind: false },
+ Abi::Stdcall { unwind: true },
+ Abi::Fastcall,
+ Abi::Vectorcall,
+ Abi::Thiscall { unwind: false },
+ Abi::Thiscall { unwind: true },
+ Abi::Aapcs,
+ Abi::Win64,
+ Abi::SysV64,
+ Abi::PtxKernel,
+ Abi::Msp430Interrupt,
+ Abi::X86Interrupt,
+ Abi::AmdGpuKernel,
+ ],
+ ..Default::default()
+ }
+}
--- /dev/null
+use crate::spec::Target;
+use crate::{abi::Endian, spec::bpf_base};
+
+pub fn target() -> Target {
+ Target {
+ llvm_target: "bpfeb".to_string(),
+ data_layout: "E-m:e-p:64:64-i64:64-i128:128-n32:64-S128".to_string(),
+ pointer_width: 64,
+ arch: "bpf".to_string(),
+ options: bpf_base::opts(Endian::Big),
+ }
+}
--- /dev/null
+use crate::spec::Target;
+use crate::{abi::Endian, spec::bpf_base};
+
+pub fn target() -> Target {
+ Target {
+ llvm_target: "bpfel".to_string(),
+ data_layout: "e-m:e-p:64:64-i64:64-i128:128-n32:64-S128".to_string(),
+ pointer_width: 64,
+ arch: "bpf".to_string(),
+ options: bpf_base::opts(Endian::Little),
+ }
+}
mod apple_sdk_base;
mod arm_base;
mod avr_gnu_base;
+mod bpf_base;
mod dragonfly_base;
mod freebsd_base;
mod fuchsia_base;
Msvc,
Lld(LldFlavor),
PtxLinker,
+ BpfLinker,
}
#[derive(Clone, Copy, Debug, Eq, Ord, PartialEq, PartialOrd)]
((LinkerFlavor::Ld), "ld"),
((LinkerFlavor::Msvc), "msvc"),
((LinkerFlavor::PtxLinker), "ptx-linker"),
+ ((LinkerFlavor::BpfLinker), "bpf-linker"),
((LinkerFlavor::Lld(LldFlavor::Wasm)), "wasm-ld"),
((LinkerFlavor::Lld(LldFlavor::Ld64)), "ld64.lld"),
((LinkerFlavor::Lld(LldFlavor::Ld)), "ld.lld"),
("aarch64_be-unknown-linux-gnu", aarch64_be_unknown_linux_gnu),
("aarch64-unknown-linux-gnu_ilp32", aarch64_unknown_linux_gnu_ilp32),
("aarch64_be-unknown-linux-gnu_ilp32", aarch64_be_unknown_linux_gnu_ilp32),
+
+ ("bpfeb-unknown-none", bpfeb_unknown_none),
+ ("bpfel-unknown-none", bpfel_unknown_none),
}
/// Everything `rustc` knows about how to compile for a specific target.
}
impl HasTargetSpec for Target {
+ #[inline]
fn target_spec(&self) -> &Target {
self
}
// dependency on this specific gcc.
asm_args: vec!["-mcpu=msp430".to_string()],
linker: Some("msp430-elf-gcc".to_string()),
+ linker_is_gnu: false,
// There are no atomic CAS instructions available in the MSP430
// instruction set, and the LLVM backend doesn't currently support
// we use the LLD shipped with the Rust toolchain by default
linker: Some("rust-lld".to_owned()),
lld_flavor: LldFlavor::Wasm,
-
- // No need for indirection here, simd types can always be passed by
- // value as the whole module either has simd or not, which is different
- // from x86 (for example) where programs can have functions that don't
- // enable simd features.
- simd_types_indirect: false,
+ linker_is_gnu: false,
pre_link_args,
use rustc_middle::ty::{self, TraitRef, Ty, TyCtxt, WithConstness};
use rustc_middle::ty::{ToPredicate, TypeFoldable};
use rustc_session::DiagnosticMessageId;
+use rustc_span::def_id::LOCAL_CRATE;
use rustc_span::Span;
#[derive(Copy, Clone, Debug)]
.span_label(span, "deref recursion limit reached")
.help(&format!(
"consider adding a `#![recursion_limit=\"{}\"]` attribute to your crate (`{}`)",
- suggested_limit, tcx.crate_name,
+ suggested_limit,
+ tcx.crate_name(LOCAL_CRATE),
))
.emit();
}
use crate::traits::{self, PredicateObligation};
use rustc_data_structures::fx::FxHashMap;
use rustc_data_structures::sync::Lrc;
+use rustc_data_structures::vec_map::VecMap;
use rustc_hir as hir;
-use rustc_hir::def_id::{DefId, DefIdMap, LocalDefId};
+use rustc_hir::def_id::{DefId, LocalDefId};
use rustc_hir::Node;
use rustc_infer::infer::error_reporting::unexpected_hidden_region_diagnostic;
use rustc_infer::infer::free_regions::FreeRegionRelations;
use rustc_infer::infer::type_variable::{TypeVariableOrigin, TypeVariableOriginKind};
use rustc_infer::infer::{self, InferCtxt, InferOk};
use rustc_middle::ty::fold::{BottomUpFolder, TypeFoldable, TypeFolder, TypeVisitor};
-use rustc_middle::ty::subst::{GenericArg, GenericArgKind, InternalSubsts, Subst, SubstsRef};
-use rustc_middle::ty::{self, Ty, TyCtxt};
+use rustc_middle::ty::subst::{GenericArg, GenericArgKind, InternalSubsts, Subst};
+use rustc_middle::ty::{self, OpaqueTypeKey, Ty, TyCtxt};
use rustc_span::Span;
use std::ops::ControlFlow;
-pub type OpaqueTypeMap<'tcx> = DefIdMap<OpaqueTypeDecl<'tcx>>;
+pub type OpaqueTypeMap<'tcx> = VecMap<OpaqueTypeKey<'tcx>, OpaqueTypeDecl<'tcx>>;
/// Information about the opaque types whose values we
/// are inferring in this function (these are the `impl Trait` that
/// The opaque type (`ty::Opaque`) for this declaration.
pub opaque_type: Ty<'tcx>,
- /// The substitutions that we apply to the opaque type that this
- /// `impl Trait` desugars to. e.g., if:
- ///
- /// fn foo<'a, 'b, T>() -> impl Trait<'a>
- ///
- /// winds up desugared to:
- ///
- /// type Foo<'x, X> = impl Trait<'x>
- /// fn foo<'a, 'b, T>() -> Foo<'a, T>
- ///
- /// then `substs` would be `['a, T]`.
- pub substs: SubstsRef<'tcx>,
-
/// The span of this particular definition of the opaque type. So
/// for example:
///
fn constrain_opaque_type<FRR: FreeRegionRelations<'tcx>>(
&self,
- def_id: DefId,
+ opaque_type_key: OpaqueTypeKey<'tcx>,
opaque_defn: &OpaqueTypeDecl<'tcx>,
mode: GenerateMemberConstraints,
free_region_relations: &FRR,
&self,
concrete_ty: Ty<'tcx>,
opaque_defn: &OpaqueTypeDecl<'tcx>,
- opaque_type_def_id: DefId,
+ opaque_type_key: OpaqueTypeKey<'tcx>,
first_own_region_index: usize,
);
- /*private*/
- fn member_constraint_feature_gate(
- &self,
- opaque_defn: &OpaqueTypeDecl<'tcx>,
- opaque_type_def_id: DefId,
- conflict1: ty::Region<'tcx>,
- conflict2: ty::Region<'tcx>,
- ) -> bool;
-
fn infer_opaque_definition_from_instantiation(
&self,
- def_id: DefId,
- substs: SubstsRef<'tcx>,
+ opaque_type_key: OpaqueTypeKey<'tcx>,
instantiated_ty: Ty<'tcx>,
span: Span,
) -> Ty<'tcx>;
) {
debug!("constrain_opaque_types()");
- for (&def_id, opaque_defn) in opaque_types {
+ for &(opaque_type_key, opaque_defn) in opaque_types {
self.constrain_opaque_type(
- def_id,
- opaque_defn,
+ opaque_type_key,
+ &opaque_defn,
GenerateMemberConstraints::WhenRequired,
free_region_relations,
);
/// See `constrain_opaque_types` for documentation.
fn constrain_opaque_type<FRR: FreeRegionRelations<'tcx>>(
&self,
- def_id: DefId,
+ opaque_type_key: OpaqueTypeKey<'tcx>,
opaque_defn: &OpaqueTypeDecl<'tcx>,
mode: GenerateMemberConstraints,
free_region_relations: &FRR,
) {
+ let def_id = opaque_type_key.def_id;
+
debug!("constrain_opaque_type()");
debug!("constrain_opaque_type: def_id={:?}", def_id);
debug!("constrain_opaque_type: opaque_defn={:#?}", opaque_defn);
let bounds = tcx.explicit_item_bounds(def_id);
debug!("constrain_opaque_type: predicates: {:#?}", bounds);
let bounds: Vec<_> =
- bounds.iter().map(|(bound, _)| bound.subst(tcx, opaque_defn.substs)).collect();
+ bounds.iter().map(|(bound, _)| bound.subst(tcx, opaque_type_key.substs)).collect();
debug!("constrain_opaque_type: bounds={:#?}", bounds);
- let opaque_type = tcx.mk_opaque(def_id, opaque_defn.substs);
+ let opaque_type = tcx.mk_opaque(def_id, opaque_type_key.substs);
let required_region_bounds =
required_region_bounds(tcx, opaque_type, bounds.into_iter());
});
}
if let GenerateMemberConstraints::IfNoStaticBound = mode {
- self.generate_member_constraint(concrete_ty, opaque_defn, def_id, first_own_region);
+ self.generate_member_constraint(
+ concrete_ty,
+ opaque_defn,
+ opaque_type_key,
+ first_own_region,
+ );
}
return;
}
// second.
let mut least_region = None;
- for subst_arg in &opaque_defn.substs[first_own_region..] {
+ for subst_arg in &opaque_type_key.substs[first_own_region..] {
let subst_region = match subst_arg.unpack() {
GenericArgKind::Lifetime(r) => r,
GenericArgKind::Type(_) | GenericArgKind::Const(_) => continue,
// ['a, 'b, 'c]`, where `'a..'c` are the
// regions that appear in the impl trait.
- // For now, enforce a feature gate outside of async functions.
- self.member_constraint_feature_gate(opaque_defn, def_id, lr, subst_region);
-
return self.generate_member_constraint(
concrete_ty,
opaque_defn,
- def_id,
+ opaque_type_key,
first_own_region,
);
}
if let GenerateMemberConstraints::IfNoStaticBound = mode {
if least_region != tcx.lifetimes.re_static {
- self.generate_member_constraint(concrete_ty, opaque_defn, def_id, first_own_region);
+ self.generate_member_constraint(
+ concrete_ty,
+ opaque_defn,
+ opaque_type_key,
+ first_own_region,
+ );
}
}
concrete_ty.visit_with(&mut ConstrainOpaqueTypeRegionVisitor {
&self,
concrete_ty: Ty<'tcx>,
opaque_defn: &OpaqueTypeDecl<'tcx>,
- opaque_type_def_id: DefId,
+ opaque_type_key: OpaqueTypeKey<'tcx>,
first_own_region: usize,
) {
// Create the set of choice regions: each region in the hidden
// type can be equal to any of the region parameters of the
// opaque type definition.
let choice_regions: Lrc<Vec<ty::Region<'tcx>>> = Lrc::new(
- opaque_defn.substs[first_own_region..]
+ opaque_type_key.substs[first_own_region..]
.iter()
.filter_map(|arg| match arg.unpack() {
GenericArgKind::Lifetime(r) => Some(r),
concrete_ty.visit_with(&mut ConstrainOpaqueTypeRegionVisitor {
op: |r| {
self.member_constraint(
- opaque_type_def_id,
+ opaque_type_key.def_id,
opaque_defn.definition_span,
concrete_ty,
r,
});
}
- /// Member constraints are presently feature-gated except for
- /// async-await. We expect to lift this once we've had a bit more
- /// time.
- fn member_constraint_feature_gate(
- &self,
- opaque_defn: &OpaqueTypeDecl<'tcx>,
- opaque_type_def_id: DefId,
- conflict1: ty::Region<'tcx>,
- conflict2: ty::Region<'tcx>,
- ) -> bool {
- // If we have `#![feature(member_constraints)]`, no problems.
- if self.tcx.features().member_constraints {
- return false;
- }
-
- let span = self.tcx.def_span(opaque_type_def_id);
-
- // Without a feature-gate, we only generate member-constraints for async-await.
- let context_name = match opaque_defn.origin {
- // No feature-gate required for `async fn`.
- hir::OpaqueTyOrigin::AsyncFn => return false,
-
- // Otherwise, generate the label we'll use in the error message.
- hir::OpaqueTyOrigin::Binding
- | hir::OpaqueTyOrigin::FnReturn
- | hir::OpaqueTyOrigin::TyAlias
- | hir::OpaqueTyOrigin::Misc => "impl Trait",
- };
- let msg = format!("ambiguous lifetime bound in `{}`", context_name);
- let mut err = self.tcx.sess.struct_span_err(span, &msg);
-
- let conflict1_name = conflict1.to_string();
- let conflict2_name = conflict2.to_string();
- let label_owned;
- let label = match (&*conflict1_name, &*conflict2_name) {
- ("'_", "'_") => "the elided lifetimes here do not outlive one another",
- _ => {
- label_owned = format!(
- "neither `{}` nor `{}` outlives the other",
- conflict1_name, conflict2_name,
- );
- &label_owned
- }
- };
- err.span_label(span, label);
-
- if self.tcx.sess.is_nightly_build() {
- err.help("add #![feature(member_constraints)] to the crate attributes to enable");
- }
-
- err.emit();
- true
- }
-
/// Given the fully resolved, instantiated type for an opaque
/// type, i.e., the value of an inference variable like C1 or C2
/// (*), computes the "definition type" for an opaque type
/// `opaque_defn.concrete_ty`
fn infer_opaque_definition_from_instantiation(
&self,
- def_id: DefId,
- substs: SubstsRef<'tcx>,
+ opaque_type_key: OpaqueTypeKey<'tcx>,
instantiated_ty: Ty<'tcx>,
span: Span,
) -> Ty<'tcx> {
+ let OpaqueTypeKey { def_id, substs } = opaque_type_key;
+
debug!(
"infer_opaque_definition_from_instantiation(def_id={:?}, instantiated_ty={:?})",
def_id, instantiated_ty
),
};
if in_definition_scope {
- return self.fold_opaque_ty(ty, def_id.to_def_id(), substs, origin);
+ let opaque_type_key =
+ OpaqueTypeKey { def_id: def_id.to_def_id(), substs };
+ return self.fold_opaque_ty(ty, opaque_type_key, origin);
}
debug!(
fn fold_opaque_ty(
&mut self,
ty: Ty<'tcx>,
- def_id: DefId,
- substs: SubstsRef<'tcx>,
+ opaque_type_key: OpaqueTypeKey<'tcx>,
origin: hir::OpaqueTyOrigin,
) -> Ty<'tcx> {
let infcx = self.infcx;
let tcx = infcx.tcx;
+ let OpaqueTypeKey { def_id, substs } = opaque_type_key;
debug!("instantiate_opaque_types: Opaque(def_id={:?}, substs={:?})", def_id, substs);
// Use the same type variable if the exact same opaque type appears more
// than once in the return type (e.g., if it's passed to a type alias).
- if let Some(opaque_defn) = self.opaque_types.get(&def_id) {
+ if let Some(opaque_defn) = self.opaque_types.get(&opaque_type_key) {
debug!("instantiate_opaque_types: returning concrete ty {:?}", opaque_defn.concrete_ty);
return opaque_defn.concrete_ty;
}
let definition_span = self.value_span;
self.opaque_types.insert(
- def_id,
+ OpaqueTypeKey { def_id, substs },
OpaqueTypeDecl {
opaque_type: ty,
- substs,
definition_span,
concrete_ty: ty_var,
has_required_region_bounds: !required_region_bounds.is_empty(),
ControlFlow::CONTINUE
}
+ Node::Cast(_, _, ty) => {
+ let ty = ty.subst(tcx, ct.substs);
+ if ty.has_infer_types_or_consts() {
+ failure_kind = FailureKind::MentionsInfer;
+ } else if ty.has_param_types_or_consts() {
+ failure_kind = cmp::min(failure_kind, FailureKind::MentionsParam);
+ }
+
+ ControlFlow::CONTINUE
+ }
Node::Binop(_, _, _) | Node::UnaryOp(_, _) | Node::FunctionCall(_, _) => {
ControlFlow::CONTINUE
}
self.nodes[func].used = true;
nodes.iter().for_each(|&n| self.nodes[n].used = true);
}
+ Node::Cast(_, operand, _) => {
+ self.nodes[operand].used = true;
+ }
}
// Nodes start as unused.
self.locals[local] = self.add_node(Node::UnaryOp(op, operand), span);
Ok(())
}
+ Rvalue::Cast(cast_kind, ref operand, ty) => {
+ let operand = self.operand_to_node(span, operand)?;
+ self.locals[local] =
+ self.add_node(Node::Cast(cast_kind, operand, ty), span);
+ Ok(())
+ }
_ => self.error(Some(span), "unsupported rvalue")?,
}
}
// These are not actually relevant for us here, so we can ignore them.
- StatementKind::StorageLive(_) | StatementKind::StorageDead(_) => Ok(()),
+ StatementKind::AscribeUserType(..)
+ | StatementKind::StorageLive(_)
+ | StatementKind::StorageDead(_) => Ok(()),
_ => self.error(Some(stmt.source_info.span), "unsupported statement")?,
}
}
recurse(tcx, ct.subtree(func), f)?;
args.iter().try_for_each(|&arg| recurse(tcx, ct.subtree(arg), f))
}
+ Node::Cast(_, operand, _) => recurse(tcx, ct.subtree(operand), f),
}
}
&& iter::zip(a_args, b_args)
.all(|(&an, &bn)| try_unify(tcx, a.subtree(an), b.subtree(bn)))
}
+ (Node::Cast(a_cast_kind, a_operand, a_ty), Node::Cast(b_cast_kind, b_operand, b_ty))
+ if (a_ty == b_ty) && (a_cast_kind == b_cast_kind) =>
+ {
+ try_unify(tcx, a.subtree(a_operand), b.subtree(b_operand))
+ }
_ => false,
}
}
hir::intravisit::NestedVisitorMap::None
}
+ fn visit_where_predicate(&mut self, _: &'v hir::WherePredicate<'v>) {
+ // Skip where-clauses, to avoid suggesting indirection for type parameters found there.
+ }
+
fn visit_ty(&mut self, ty: &hir::Ty<'_>) {
// We collect the spans of all uses of the "bare" type param, like in `field: T` or
// `field: (T, T)` where we could make `T: ?Sized` while skipping cases that are known to be
Infer, InferTy, ToPredicate, Ty, TyCtxt, TypeFoldable, WithConstness,
};
use rustc_middle::ty::{TypeAndMut, TypeckResults};
+use rustc_span::def_id::LOCAL_CRATE;
use rustc_span::symbol::{kw, sym, Ident, Symbol};
use rustc_span::{BytePos, MultiSpan, Span, DUMMY_SP};
use rustc_target::spec::abi;
let suggested_limit = current_limit * 2;
err.help(&format!(
"consider adding a `#![recursion_limit=\"{}\"]` attribute to your crate (`{}`)",
- suggested_limit, self.tcx.crate_name,
+ suggested_limit,
+ self.tcx.crate_name(LOCAL_CRATE),
));
}
use rustc_infer::traits::{SelectionError, TraitEngine, TraitEngineExt as _, TraitObligation};
use rustc_middle::mir::abstract_const::NotConstEvaluatable;
use rustc_middle::mir::interpret::ErrorHandled;
-use rustc_middle::ty::error::ExpectedFound;
+use rustc_middle::ty::error::{ExpectedFound, TypeError};
use rustc_middle::ty::subst::SubstsRef;
use rustc_middle::ty::ToPredicate;
use rustc_middle::ty::{self, Binder, Const, Ty, TypeFoldable};
)
}
(Err(ErrorHandled::TooGeneric), _) | (_, Err(ErrorHandled::TooGeneric)) => {
- ProcessResult::Unchanged
+ if c1.has_infer_types_or_consts() || c2.has_infer_types_or_consts() {
+ ProcessResult::Unchanged
+ } else {
+ // Two different constants using generic parameters ~> error.
+ let expected_found = ExpectedFound::new(true, c1, c2);
+ ProcessResult::Error(FulfillmentErrorCode::CodeConstEquateError(
+ expected_found,
+ TypeError::ConstMismatch(expected_found),
+ ))
+ }
}
}
}
use rustc_middle::ty::fold::TypeFoldable;
use rustc_middle::ty::subst::{InternalSubsts, SubstsRef};
use rustc_middle::ty::{
- self, GenericParamDefKind, ParamEnv, ToPredicate, Ty, TyCtxt, WithConstness,
+ self, GenericParamDefKind, ParamEnv, ToPredicate, Ty, TyCtxt, VtblEntry, WithConstness,
+ COMMON_VTABLE_ENTRIES,
};
use rustc_span::Span;
/// Given a trait `trait_ref`, iterates the vtable entries
/// that come from `trait_ref`, including its supertraits.
-fn vtable_methods<'tcx>(
+fn vtable_entries<'tcx>(
tcx: TyCtxt<'tcx>,
trait_ref: ty::PolyTraitRef<'tcx>,
-) -> &'tcx [Option<(DefId, SubstsRef<'tcx>)>] {
- debug!("vtable_methods({:?})", trait_ref);
-
- tcx.arena.alloc_from_iter(supertraits(tcx, trait_ref).flat_map(move |trait_ref| {
- let trait_methods = tcx
- .associated_items(trait_ref.def_id())
- .in_definition_order()
- .filter(|item| item.kind == ty::AssocKind::Fn);
-
- // Now list each method's DefId and InternalSubsts (for within its trait).
- // If the method can never be called from this object, produce None.
- trait_methods.map(move |trait_method| {
- debug!("vtable_methods: trait_method={:?}", trait_method);
- let def_id = trait_method.def_id;
-
- // Some methods cannot be called on an object; skip those.
- if !is_vtable_safe_method(tcx, trait_ref.def_id(), &trait_method) {
- debug!("vtable_methods: not vtable safe");
- return None;
- }
+) -> &'tcx [VtblEntry<'tcx>] {
+ debug!("vtable_entries({:?})", trait_ref);
+
+ let entries = COMMON_VTABLE_ENTRIES.iter().cloned().chain(
+ supertraits(tcx, trait_ref).flat_map(move |trait_ref| {
+ let trait_methods = tcx
+ .associated_items(trait_ref.def_id())
+ .in_definition_order()
+ .filter(|item| item.kind == ty::AssocKind::Fn);
+
+ // Now list each method's DefId and InternalSubsts (for within its trait).
+ // If the method can never be called from this object, produce `Vacant`.
+ trait_methods.map(move |trait_method| {
+ debug!("vtable_entries: trait_method={:?}", trait_method);
+ let def_id = trait_method.def_id;
+
+ // Some methods cannot be called on an object; skip those.
+ if !is_vtable_safe_method(tcx, trait_ref.def_id(), &trait_method) {
+ debug!("vtable_entries: not vtable safe");
+ return VtblEntry::Vacant;
+ }
- // The method may have some early-bound lifetimes; add regions for those.
- let substs = trait_ref.map_bound(|trait_ref| {
- InternalSubsts::for_item(tcx, def_id, |param, _| match param.kind {
- GenericParamDefKind::Lifetime => tcx.lifetimes.re_erased.into(),
- GenericParamDefKind::Type { .. } | GenericParamDefKind::Const { .. } => {
- trait_ref.substs[param.index as usize]
- }
- })
- });
-
- // The trait type may have higher-ranked lifetimes in it;
- // erase them if they appear, so that we get the type
- // at some particular call site.
- let substs =
- tcx.normalize_erasing_late_bound_regions(ty::ParamEnv::reveal_all(), substs);
-
- // It's possible that the method relies on where-clauses that
- // do not hold for this particular set of type parameters.
- // Note that this method could then never be called, so we
- // do not want to try and codegen it, in that case (see #23435).
- let predicates = tcx.predicates_of(def_id).instantiate_own(tcx, substs);
- if impossible_predicates(tcx, predicates.predicates) {
- debug!("vtable_methods: predicates do not hold");
- return None;
- }
+ // The method may have some early-bound lifetimes; add regions for those.
+ let substs = trait_ref.map_bound(|trait_ref| {
+ InternalSubsts::for_item(tcx, def_id, |param, _| match param.kind {
+ GenericParamDefKind::Lifetime => tcx.lifetimes.re_erased.into(),
+ GenericParamDefKind::Type { .. } | GenericParamDefKind::Const { .. } => {
+ trait_ref.substs[param.index as usize]
+ }
+ })
+ });
+
+ // The trait type may have higher-ranked lifetimes in it;
+ // erase them if they appear, so that we get the type
+ // at some particular call site.
+ let substs =
+ tcx.normalize_erasing_late_bound_regions(ty::ParamEnv::reveal_all(), substs);
+
+ // It's possible that the method relies on where-clauses that
+ // do not hold for this particular set of type parameters.
+ // Note that this method could then never be called, so we
+ // do not want to try and codegen it, in that case (see #23435).
+ let predicates = tcx.predicates_of(def_id).instantiate_own(tcx, substs);
+ if impossible_predicates(tcx, predicates.predicates) {
+ debug!("vtable_entries: predicates do not hold");
+ return VtblEntry::Vacant;
+ }
- Some((def_id, substs))
- })
- }))
+ VtblEntry::Method(def_id, substs)
+ })
+ }),
+ );
+
+ tcx.arena.alloc_from_iter(entries)
+}
+
+/// Find slot base for trait methods within vtable entries of another trait
+fn vtable_trait_first_method_offset<'tcx>(
+ tcx: TyCtxt<'tcx>,
+ key: (
+ ty::PolyTraitRef<'tcx>, // trait_to_be_found
+ ty::PolyTraitRef<'tcx>, // trait_owning_vtable
+ ),
+) -> usize {
+ let (trait_to_be_found, trait_owning_vtable) = key;
+
+ let mut supertraits = util::supertraits(tcx, trait_owning_vtable);
+
+ // For each of the non-matching predicates that
+ // we pass over, we sum up the set of number of vtable
+ // entries, so that we can compute the offset for the selected
+ // trait.
+ let vtable_base = ty::COMMON_VTABLE_ENTRIES.len()
+ + supertraits
+ .by_ref()
+ .take_while(|t| *t != trait_to_be_found)
+ .map(|t| util::count_own_vtable_entries(tcx, t))
+ .sum::<usize>();
+
+ vtable_base
}
/// Check whether a `ty` implements given trait(trait_def_id).
specialization_graph_of: specialize::specialization_graph_provider,
specializes: specialize::specializes,
codegen_fulfill_obligation: codegen::codegen_fulfill_obligation,
- vtable_methods,
+ vtable_entries,
type_implements_trait,
subst_and_check_impossible_predicates,
mir_abstract_const: |tcx, def_id| {
let leaf = leaf.subst(self.tcx, ct.substs);
self.visit_const(leaf)
}
+ Node::Cast(_, _, ty) => self.visit_ty(ty),
Node::Binop(..) | Node::UnaryOp(..) | Node::FunctionCall(_, _) => {
ControlFlow::CONTINUE
}
let leaf = leaf.subst(self.tcx, ct.substs);
self.visit_const(leaf)
}
+ Node::Cast(_, _, ty) => self.visit_ty(ty),
Node::Binop(..) | Node::UnaryOp(..) | Node::FunctionCall(_, _) => {
ControlFlow::CONTINUE
}
let mut nested = vec![];
let mut supertraits = util::supertraits(tcx, ty::Binder::dummy(object_trait_ref));
-
- // For each of the non-matching predicates that
- // we pass over, we sum up the set of number of vtable
- // entries, so that we can compute the offset for the selected
- // trait.
- let vtable_base = supertraits
- .by_ref()
- .take(index)
- .map(|t| super::util::count_own_vtable_entries(tcx, t))
- .sum();
-
let unnormalized_upcast_trait_ref =
- supertraits.next().expect("supertraits iterator no longer has as many elements");
+ supertraits.nth(index).expect("supertraits iterator no longer has as many elements");
let upcast_trait_ref = normalize_with_depth_to(
self,
}
debug!(?nested, "object nested obligations");
+
+ let vtable_base = super::super::vtable_trait_first_method_offset(
+ tcx,
+ (unnormalized_upcast_trait_ref, ty::Binder::dummy(object_trait_ref)),
+ );
+
Ok(ImplSourceObjectData { upcast_trait_ref, vtable_base, nested })
}
ty::PredicateKind::ConstEquate(c1, c2) => {
debug!(?c1, ?c2, "evaluate_predicate_recursively: equating consts");
+ if self.tcx().features().const_evaluatable_checked {
+ // FIXME: we probably should only try to unify abstract constants
+ // if the constants depend on generic parameters.
+ //
+ // Let's just see where this breaks :shrug:
+ if let (ty::ConstKind::Unevaluated(a), ty::ConstKind::Unevaluated(b)) =
+ (c1.val, c2.val)
+ {
+ if self
+ .tcx()
+ .try_unify_abstract_consts(((a.def, a.substs), (b.def, b.substs)))
+ {
+ return Ok(EvaluatedToOk);
+ }
+ }
+ }
+
let evaluate = |c: &'tcx ty::Const<'tcx>| {
if let ty::ConstKind::Unevaluated(unevaluated) = c.val {
self.infcx
)
}
(Err(ErrorHandled::TooGeneric), _) | (_, Err(ErrorHandled::TooGeneric)) => {
- Ok(EvaluatedToAmbig)
+ if c1.has_infer_types_or_consts() || c2.has_infer_types_or_consts() {
+ Ok(EvaluatedToAmbig)
+ } else {
+ // Two different constants using generic parameters ~> error.
+ Ok(EvaluatedToErr)
+ }
}
}
}
#![feature(crate_visibility_modifier)]
#![feature(in_band_lifetimes)]
#![feature(nll)]
-#![feature(control_flow_enum)]
#![recursion_limit = "256"]
#[macro_use]
self, Binder, Predicate, PredicateKind, ToPredicate, Ty, TyCtxt, WithConstness,
};
use rustc_session::CrateDisambiguator;
-use rustc_span::symbol::Symbol;
use rustc_span::Span;
use rustc_trait_selection::traits;
tcx.sess.local_crate_disambiguator()
}
-fn original_crate_name(tcx: TyCtxt<'_>, crate_num: CrateNum) -> Symbol {
- assert_eq!(crate_num, LOCAL_CRATE);
- tcx.crate_name
-}
-
fn instance_def_size_estimate<'tcx>(
tcx: TyCtxt<'tcx>,
instance_def: ty::InstanceDef<'tcx>,
param_env_reveal_all_normalized,
trait_of_item,
crate_disambiguator,
- original_crate_name,
instance_def_size_estimate,
issue33140_self_ty,
impl_defaultness,
+#![feature(min_specialization)]
+
#[macro_use]
extern crate bitflags;
#[macro_use]
opt_arg_exprs: Option<&'tcx [hir::Expr<'tcx>]>,
) -> Option<(Option<Adjustment<'tcx>>, MethodCallee<'tcx>)> {
// Try the options that are least restrictive on the caller first.
- for &(opt_trait_def_id, method_name, borrow) in &[
+ for (opt_trait_def_id, method_name, borrow) in [
(self.tcx.lang_items().fn_trait(), Ident::with_dummy_span(sym::call), true),
(self.tcx.lang_items().fn_mut_trait(), Ident::with_dummy_span(sym::call_mut), true),
(self.tcx.lang_items().fn_once_trait(), Ident::with_dummy_span(sym::call_once), false),
use rustc_errors::{struct_span_err, Applicability, DiagnosticBuilder, ErrorReported};
use rustc_hir as hir;
use rustc_hir::lang_items::LangItem;
+use rustc_middle::mir::Mutability;
use rustc_middle::ty::adjustment::AllowTwoPhase;
use rustc_middle::ty::cast::{CastKind, CastTy};
use rustc_middle::ty::error::TypeError;
fcx.ty_to_string(self.cast_ty)
);
let mut sugg = None;
+ let mut sugg_mutref = false;
if let ty::Ref(reg, _, mutbl) = *self.cast_ty.kind() {
- if fcx
- .try_coerce(
- self.expr,
- fcx.tcx.mk_ref(reg, TypeAndMut { ty: self.expr_ty, mutbl }),
- self.cast_ty,
- AllowTwoPhase::No,
- )
- .is_ok()
+ if let ty::RawPtr(TypeAndMut { ty: expr_ty, .. }) = *self.expr_ty.kind() {
+ if fcx
+ .try_coerce(
+ self.expr,
+ fcx.tcx.mk_ref(
+ &ty::RegionKind::ReErased,
+ TypeAndMut { ty: expr_ty, mutbl },
+ ),
+ self.cast_ty,
+ AllowTwoPhase::No,
+ )
+ .is_ok()
+ {
+ sugg = Some(format!("&{}*", mutbl.prefix_str()));
+ }
+ } else if let ty::Ref(expr_reg, expr_ty, expr_mutbl) = *self.expr_ty.kind() {
+ if expr_mutbl == Mutability::Not
+ && mutbl == Mutability::Mut
+ && fcx
+ .try_coerce(
+ self.expr,
+ fcx.tcx.mk_ref(
+ expr_reg,
+ TypeAndMut { ty: expr_ty, mutbl: Mutability::Mut },
+ ),
+ self.cast_ty,
+ AllowTwoPhase::No,
+ )
+ .is_ok()
+ {
+ sugg_mutref = true;
+ }
+ }
+
+ if !sugg_mutref
+ && sugg == None
+ && fcx
+ .try_coerce(
+ self.expr,
+ fcx.tcx.mk_ref(reg, TypeAndMut { ty: self.expr_ty, mutbl }),
+ self.cast_ty,
+ AllowTwoPhase::No,
+ )
+ .is_ok()
{
sugg = Some(format!("&{}", mutbl.prefix_str()));
}
sugg = Some(format!("&{}", mutbl.prefix_str()));
}
}
- if let Some(sugg) = sugg {
+ if sugg_mutref {
+ err.span_label(self.span, "invalid cast");
+ err.span_note(self.expr.span, "this reference is immutable");
+ err.span_note(self.cast_span, "trying to cast to a mutable reference type");
+ } else if let Some(sugg) = sugg {
err.span_label(self.span, "invalid cast");
err.span_suggestion_verbose(
self.expr.span.shrink_to_lo(),
- "borrow the value for the cast to be valid",
+ "consider borrowing the value",
sugg,
Applicability::MachineApplicable,
);
use rustc_middle::ty::layout::MAX_SIMD_LANES;
use rustc_middle::ty::subst::GenericArgKind;
use rustc_middle::ty::util::{Discr, IntTypeExt};
-use rustc_middle::ty::{self, ParamEnv, RegionKind, Ty, TyCtxt};
+use rustc_middle::ty::{self, OpaqueTypeKey, ParamEnv, RegionKind, Ty, TyCtxt};
use rustc_session::lint::builtin::UNINHABITED_STATIC;
use rustc_span::symbol::sym;
use rustc_span::{self, MultiSpan, Span};
infcx.instantiate_opaque_types(def_id, hir_id, param_env, opaque_ty, span),
);
- for (def_id, opaque_defn) in opaque_type_map {
+ for (OpaqueTypeKey { def_id, substs }, opaque_defn) in opaque_type_map {
match infcx
.at(&misc_cause, param_env)
- .eq(opaque_defn.concrete_ty, tcx.type_of(def_id).subst(tcx, opaque_defn.substs))
+ .eq(opaque_defn.concrete_ty, tcx.type_of(def_id).subst(tcx, substs))
{
Ok(infer_ok) => inh.register_infer_ok_obligations(infer_ok),
Err(ty_err) => tcx.sess.delay_span_bug(
}
}
+ // Check that we use types valid for use in the lanes of a SIMD "vector register"
+ // These are scalar types which directly match a "machine" type
+ // Yes: Integers, floats, "thin" pointers
+ // No: char, "fat" pointers, compound types
match e.kind() {
- ty::Param(_) => { /* struct<T>(T, T, T, T) is ok */ }
- _ if e.is_machine() => { /* struct(u8, u8, u8, u8) is ok */ }
- ty::Array(ty, _c) if ty.is_machine() => { /* struct([f32; 4]) */ }
+ ty::Param(_) => (), // pass struct<T>(T, T, T, T) through, let monomorphization catch errors
+ ty::Int(_) | ty::Uint(_) | ty::Float(_) | ty::RawPtr(_) => (), // struct(u8, u8, u8, u8) is ok
+ ty::Array(t, _clen)
+ if matches!(
+ t.kind(),
+ ty::Int(_) | ty::Uint(_) | ty::Float(_) | ty::RawPtr(_)
+ ) =>
+ { /* struct([f32; 4]) is ok */ }
_ => {
struct_span_err!(
tcx.sess,
let item_kind = assoc_item_kind_str(impl_);
let mut err_occurred = false;
- for &(kind, trait_count, impl_count) in &matchings {
+ for (kind, trait_count, impl_count) in matchings {
if impl_count != trait_count {
err_occurred = true;
use rustc_hir as hir;
use rustc_hir::lang_items::LangItem;
use rustc_hir::{is_range_literal, Node};
+use rustc_middle::lint::in_external_macro;
use rustc_middle::ty::adjustment::AllowTwoPhase;
use rustc_middle::ty::{self, AssocItem, Ty, TypeAndMut};
use rustc_span::symbol::sym;
use super::method::probe;
use std::fmt;
+use std::iter;
impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
pub fn emit_coerce_suggestions(
checked_ty: Ty<'tcx>,
expected: Ty<'tcx>,
) -> Option<(Span, &'static str, String, Applicability)> {
- let sm = self.sess().source_map();
+ let sess = self.sess();
let sp = expr.span;
- if sm.is_imported(sp) {
- // Ignore if span is from within a macro #41858, #58298. We previously used the macro
- // call span, but that breaks down when the type error comes from multiple calls down.
+
+ // If the span is from an external macro, there's no suggestion we can make.
+ if in_external_macro(sess, sp) {
return None;
}
+ let sm = sess.source_map();
+
let replace_prefix = |s: &str, old: &str, new: &str| {
s.strip_prefix(old).map(|stripped| new.to_string() + stripped)
};
let is_struct_pat_shorthand_field =
self.is_hir_id_from_struct_pattern_shorthand_field(expr.hir_id, sp);
- // If the span is from a macro, then it's hard to extract the text
- // and make a good suggestion, so don't bother.
- let is_macro = sp.from_expansion() && sp.desugaring_kind().is_none();
-
// `ExprKind::DropTemps` is semantically irrelevant for these suggestions.
let expr = expr.peel_drop_temps();
hir::ExprKind::AddrOf(hir::BorrowKind::Ref, _, ref expr),
_,
&ty::Ref(_, checked, _),
- ) if {
- self.infcx.can_sub(self.param_env, checked, &expected).is_ok() && !is_macro
- } =>
- {
+ ) if self.infcx.can_sub(self.param_env, checked, &expected).is_ok() => {
// We have `&T`, check if what was expected was `T`. If so,
// we may want to suggest removing a `&`.
if sm.is_imported(expr.span) {
- if let Ok(src) = sm.span_to_snippet(sp) {
- if let Some(src) = src.strip_prefix('&') {
+ // Go through the spans from which this span was expanded,
+ // and find the one that's pointing inside `sp`.
+ //
+ // E.g. for `&format!("")`, where we want the span to the
+ // `format!()` invocation instead of its expansion.
+ if let Some(call_span) =
+ iter::successors(Some(expr.span), |s| s.parent()).find(|&s| sp.contains(s))
+ {
+ if let Ok(code) = sm.span_to_snippet(call_span) {
return Some((
sp,
"consider removing the borrow",
- src.to_string(),
+ code,
Applicability::MachineApplicable,
));
}
}
return None;
}
- if let Ok(code) = sm.span_to_snippet(expr.span) {
- return Some((
- sp,
- "consider removing the borrow",
- code,
- Applicability::MachineApplicable,
- ));
+ if sp.contains(expr.span) {
+ if let Ok(code) = sm.span_to_snippet(expr.span) {
+ return Some((
+ sp,
+ "consider removing the borrow",
+ code,
+ Applicability::MachineApplicable,
+ ));
+ }
}
}
(
}
}
}
- _ if sp == expr.span && !is_macro => {
+ _ if sp == expr.span => {
if let Some(steps) = self.deref_steps(checked_ty, expected) {
let expr = expr.peel_blocks();
fn relate_with_variance<T: Relate<'tcx>>(
&mut self,
_: ty::Variance,
+ _info: ty::VarianceDiagInfo<'tcx>,
a: T,
b: T,
) -> RelateResult<'tcx, T> {
// that are not closures, then we type-check the closures. This is so
// that we have more information about the types of arguments when we
// type-check the functions. This isn't really the right way to do this.
- for &check_closures in &[false, true] {
+ for check_closures in [false, true] {
debug!("check_closures={}", check_closures);
// More awful hacks: before we check argument types, try to do
use super::MaybeInProgressTables;
use rustc_data_structures::fx::FxHashMap;
+use rustc_data_structures::vec_map::VecMap;
use rustc_hir as hir;
use rustc_hir::def_id::{DefIdMap, LocalDefId};
use rustc_hir::HirIdMap;
use rustc_infer::infer;
use rustc_infer::infer::{InferCtxt, InferOk, TyCtxtInferExt};
use rustc_middle::ty::fold::TypeFoldable;
-use rustc_middle::ty::{self, Ty, TyCtxt};
+use rustc_middle::ty::{self, OpaqueTypeKey, Ty, TyCtxt};
use rustc_span::{self, Span};
use rustc_trait_selection::infer::InferCtxtExt as _;
use rustc_trait_selection::opaque_types::OpaqueTypeDecl;
// associated fresh inference variable. Writeback resolves these
// variables to get the concrete type, which can be used to
// 'de-opaque' OpaqueTypeDecl, after typeck is done with all functions.
- pub(super) opaque_types: RefCell<DefIdMap<OpaqueTypeDecl<'tcx>>>,
+ pub(super) opaque_types: RefCell<VecMap<OpaqueTypeKey<'tcx>, OpaqueTypeDecl<'tcx>>>,
/// A map from inference variables created from opaque
/// type instantiations (`ty::Infer`) to the actual opaque
self.assemble_inherent_impl_for_primitive(lang_def_id);
}
ty::Slice(_) => {
- for &lang_def_id in &[
+ for lang_def_id in [
lang_items.slice_impl(),
lang_items.slice_u8_impl(),
lang_items.slice_alloc_impl(),
return None;
} else {
span = item_name.span;
+
+ // Don't show generic arguments when the method can't be found in any implementation (#81576).
+ let mut ty_str_reported = ty_str.clone();
+ if let ty::Adt(_, ref generics) = actual.kind() {
+ if generics.len() > 0 {
+ let mut autoderef = self.autoderef(span, actual);
+ let candidate_found = autoderef.any(|(ty, _)| {
+ if let ty::Adt(ref adt_deref, _) = ty.kind() {
+ self.tcx
+ .inherent_impls(adt_deref.did)
+ .iter()
+ .filter_map(|def_id| {
+ self.associated_item(
+ *def_id,
+ item_name,
+ Namespace::ValueNS,
+ )
+ })
+ .count()
+ >= 1
+ } else {
+ false
+ }
+ });
+ let has_deref = autoderef.step_count() > 0;
+ if !candidate_found
+ && !has_deref
+ && unsatisfied_predicates.is_empty()
+ {
+ if let Some((path_string, _)) = ty_str.split_once('<') {
+ ty_str_reported = path_string.to_string();
+ }
+ }
+ }
+ }
+
let mut err = struct_span_err!(
tcx.sess,
span,
item_kind,
item_name,
actual.prefix_string(self.tcx),
- ty_str,
+ ty_str_reported,
);
if let Mode::MethodCall = mode {
if let SelfSource::MethodCall(call) = source {
let mut label_span_not_found = || {
if unsatisfied_predicates.is_empty() {
err.span_label(span, format!("{item_kind} not found in `{ty_str}`"));
+ if let ty::Adt(ref adt, _) = rcvr_ty.kind() {
+ let mut inherent_impls_candidate = self
+ .tcx
+ .inherent_impls(adt.did)
+ .iter()
+ .copied()
+ .filter(|def_id| {
+ if let Some(assoc) =
+ self.associated_item(*def_id, item_name, Namespace::ValueNS)
+ {
+ // Check for both mode is the same so we avoid suggesting
+ // incorrect associated item.
+ match (mode, assoc.fn_has_self_parameter, source) {
+ (Mode::MethodCall, true, SelfSource::MethodCall(_)) => {
+ // We check that the suggest type is actually
+ // different from the received one
+ // So we avoid suggestion method with Box<Self>
+ // for instance
+ self.tcx.at(span).type_of(*def_id) != actual
+ && self.tcx.at(span).type_of(*def_id) != rcvr_ty
+ }
+ (Mode::Path, false, _) => true,
+ _ => false,
+ }
+ } else {
+ false
+ }
+ })
+ .collect::<Vec<_>>();
+ if inherent_impls_candidate.len() > 0 {
+ inherent_impls_candidate.sort();
+ inherent_impls_candidate.dedup();
+
+ // number of type to shows at most.
+ let limit = if inherent_impls_candidate.len() == 5 { 5 } else { 4 };
+ let type_candidates = inherent_impls_candidate
+ .iter()
+ .take(limit)
+ .map(|impl_item| {
+ format!("- `{}`", self.tcx.at(span).type_of(*impl_item))
+ })
+ .collect::<Vec<_>>()
+ .join("\n");
+ let additional_types = if inherent_impls_candidate.len() > limit {
+ format!(
+ "\nand {} more types",
+ inherent_impls_candidate.len() - limit
+ )
+ } else {
+ "".to_string()
+ };
+ err.note(&format!(
+ "the {item_kind} was found for\n{}{}",
+ type_candidates, additional_types
+ ));
+ }
+ }
} else {
err.span_label(span, format!("{item_kind} cannot be called on `{ty_str}` due to unsatisfied trait bounds"));
}
expr, base_expr, adjusted_ty, index_ty
);
- for &unsize in &[false, true] {
+ for unsize in [false, true] {
let mut self_ty = adjusted_ty;
if unsize {
// We only unsize arrays here.
// Clear previous flag; after a pointer indirection it does not apply any more.
inside_union = false;
}
- if source.ty_adt_def().map_or(false, |adt| adt.is_union()) {
+ if source.is_union() {
inside_union = true;
}
// Fix up the autoderefs. Autorefs can only occur immediately preceding
impl<'a, 'tcx> euv::Delegate<'tcx> for InferBorrowKind<'a, 'tcx> {
fn fake_read(&mut self, place: Place<'tcx>, cause: FakeReadCause, diag_expr_id: hir::HirId) {
if let PlaceBase::Upvar(_) = place.base {
+ // We need to restrict Fake Read precision to avoid fake reading unsafe code,
+ // such as deref of a raw pointer.
+ let place = restrict_capture_precision(place);
+ let place =
+ restrict_repr_packed_field_ref_capture(self.fcx.tcx, self.fcx.param_env, &place);
self.fake_reads.push((place, cause, diag_expr_id));
}
}
}
fn visit_opaque_types(&mut self, span: Span) {
- for (&def_id, opaque_defn) in self.fcx.opaque_types.borrow().iter() {
- let hir_id = self.tcx().hir().local_def_id_to_hir_id(def_id.expect_local());
+ for &(opaque_type_key, opaque_defn) in self.fcx.opaque_types.borrow().iter() {
+ let hir_id =
+ self.tcx().hir().local_def_id_to_hir_id(opaque_type_key.def_id.expect_local());
let instantiated_ty = self.resolve(opaque_defn.concrete_ty, &hir_id);
debug_assert!(!instantiated_ty.has_escaping_bound_vars());
// ```
// figures out the concrete type with `U`, but the stored type is with `T`.
let definition_ty = self.fcx.infer_opaque_definition_from_instantiation(
- def_id,
- opaque_defn.substs,
+ opaque_type_key,
instantiated_ty,
span,
);
let mut skip_add = false;
- if let ty::Opaque(defin_ty_def_id, _substs) = *definition_ty.kind() {
+ if let ty::Opaque(definition_ty_def_id, _substs) = *definition_ty.kind() {
if let hir::OpaqueTyOrigin::Misc | hir::OpaqueTyOrigin::TyAlias = opaque_defn.origin
{
- if def_id == defin_ty_def_id {
+ if opaque_type_key.def_id == definition_ty_def_id {
debug!(
"skipping adding concrete definition for opaque type {:?} {:?}",
- opaque_defn, defin_ty_def_id
+ opaque_defn, opaque_type_key.def_id
);
skip_add = true;
}
}
}
- if !opaque_defn.substs.needs_infer() {
+ if !opaque_type_key.substs.needs_infer() {
// We only want to add an entry into `concrete_opaque_types`
// if we actually found a defining usage of this opaque type.
// Otherwise, we do nothing - we'll either find a defining usage
// in some other location, or we'll end up emitting an error due
// to the lack of defining usage
if !skip_add {
- let new = ty::ResolvedOpaqueTy {
- concrete_type: definition_ty,
- substs: opaque_defn.substs,
- };
-
- let old = self.typeck_results.concrete_opaque_types.insert(def_id, new);
- if let Some(old) = old {
- if old.concrete_type != definition_ty || old.substs != opaque_defn.substs {
+ let old_concrete_ty = self
+ .typeck_results
+ .concrete_opaque_types
+ .insert(opaque_type_key, definition_ty);
+ if let Some(old_concrete_ty) = old_concrete_ty {
+ if old_concrete_ty != definition_ty {
span_bug!(
span,
"`visit_opaque_types` tried to write different types for the same \
opaque type: {:?}, {:?}, {:?}, {:?}",
- def_id,
+ opaque_type_key.def_id,
definition_ty,
opaque_defn,
- old,
+ old_concrete_ty,
);
}
}
generics_of,
predicates_of,
predicates_defined_on,
- projection_ty_from_predicates,
explicit_predicates_of,
super_predicates_of,
super_predicates_that_define_assoc_type,
}
}
-fn projection_ty_from_predicates(
- tcx: TyCtxt<'tcx>,
- key: (
- // ty_def_id
- DefId,
- // def_id of `N` in `<T as Trait>::N`
- DefId,
- ),
-) -> Option<ty::ProjectionTy<'tcx>> {
- let (ty_def_id, item_def_id) = key;
- let mut projection_ty = None;
- for (predicate, _) in tcx.predicates_of(ty_def_id).predicates {
- if let ty::PredicateKind::Projection(projection_predicate) = predicate.kind().skip_binder()
- {
- if item_def_id == projection_predicate.projection_ty.item_def_id {
- projection_ty = Some(projection_predicate.projection_ty);
- break;
- }
- }
- }
- projection_ty
-}
-
/// Converts a specific `GenericBound` from the AST into a set of
/// predicates that apply to the self type. A vector is returned
/// because this can be anywhere from zero predicates (`T: ?Sized` adds no
Some(sym::rtm_target_feature) => rust_features.rtm_target_feature,
Some(sym::f16c_target_feature) => rust_features.f16c_target_feature,
Some(sym::ermsb_target_feature) => rust_features.ermsb_target_feature,
+ Some(sym::bpf_target_feature) => rust_features.bpf_target_feature,
Some(name) => bug!("unknown target feature gate {}", name),
None => true,
};
}
} else if tcx.sess.check_name(attr, sym::target_feature) {
if !tcx.is_closure(id) && tcx.fn_sig(id).unsafety() == hir::Unsafety::Normal {
- if !tcx.features().target_feature_11 {
+ if tcx.sess.target.is_like_wasm || tcx.sess.opts.actually_rustdoc {
+ // The `#[target_feature]` attribute is allowed on
+ // WebAssembly targets on all functions, including safe
+ // ones. Other targets require that `#[target_feature]` is
+ // only applied to unsafe funtions (pending the
+ // `target_feature_11` feature) because on most targets
+ // execution of instructions that are not supported is
+ // considered undefined behavior. For WebAssembly which is a
+ // 100% safe target at execution time it's not possible to
+ // execute undefined instructions, and even if a future
+ // feature was added in some form for this it would be a
+ // deterministic trap. There is no undefined behavior when
+ // executing WebAssembly so `#[target_feature]` is allowed
+ // on safe functions (but again, only for WebAssembly)
+ //
+ // Note that this is also allowed if `actually_rustdoc` so
+ // if a target is documenting some wasm-specific code then
+ // it's not spuriously denied.
+ } else if !tcx.features().target_feature_11 {
let mut err = feature_err(
&tcx.sess.parse_sess,
sym::target_feature_11,
use rustc_middle::hir::map::Map;
use rustc_middle::ty::subst::{GenericArgKind, InternalSubsts};
use rustc_middle::ty::util::IntTypeExt;
-use rustc_middle::ty::{self, DefIdTree, Ty, TyCtxt, TypeFoldable};
+use rustc_middle::ty::{self, DefIdTree, Ty, TyCtxt, TypeFoldable, TypeFolder};
use rustc_span::symbol::Ident;
use rustc_span::{Span, DUMMY_SP};
let concrete_ty = tcx
.mir_borrowck(owner.expect_local())
.concrete_opaque_types
- .get(&def_id.to_def_id())
- .map(|opaque| opaque.concrete_type)
+ .get_by(|(key, _)| key.def_id == def_id.to_def_id())
+ .map(|concrete_ty| *concrete_ty)
.unwrap_or_else(|| {
tcx.sess.delay_span_bug(
DUMMY_SP,
}
// Calling `mir_borrowck` can lead to cycle errors through
// const-checking, avoid calling it if we don't have to.
- if !self.tcx.typeck(def_id).concrete_opaque_types.contains_key(&self.def_id) {
+ if self
+ .tcx
+ .typeck(def_id)
+ .concrete_opaque_types
+ .get_by(|(key, _)| key.def_id == self.def_id)
+ .is_none()
+ {
debug!(
"find_opaque_ty_constraints: no constraint for `{:?}` at `{:?}`",
self.def_id, def_id,
return;
}
// Use borrowck to get the type with unerased regions.
- let ty = self.tcx.mir_borrowck(def_id).concrete_opaque_types.get(&self.def_id);
- if let Some(ty::ResolvedOpaqueTy { concrete_type, substs }) = ty {
+ let concrete_opaque_types = &self.tcx.mir_borrowck(def_id).concrete_opaque_types;
+ if let Some((opaque_type_key, concrete_type)) =
+ concrete_opaque_types.iter().find(|(key, _)| key.def_id == self.def_id)
+ {
debug!(
"find_opaque_ty_constraints: found constraint for `{:?}` at `{:?}`: {:?}",
- self.def_id, def_id, ty,
+ self.def_id, def_id, concrete_type,
);
// FIXME(oli-obk): trace the actual span from inference to improve errors.
// using `delay_span_bug`, just in case `wfcheck` slips up.
let opaque_generics = self.tcx.generics_of(self.def_id);
let mut used_params: FxHashSet<_> = FxHashSet::default();
- for (i, arg) in substs.iter().enumerate() {
+ for (i, arg) in opaque_type_key.substs.iter().enumerate() {
let arg_is_param = match arg.unpack() {
GenericArgKind::Type(ty) => matches!(ty.kind(), ty::Param(_)),
GenericArgKind::Lifetime(lt) => {
let owner_typeck_results = tcx.typeck(scope_def_id);
let concrete_ty = owner_typeck_results
.concrete_opaque_types
- .get(&opaque_ty_def_id)
- .map(|opaque| opaque.concrete_type)
+ .get_by(|(key, _)| key.def_id == opaque_ty_def_id)
+ .map(|concrete_ty| *concrete_ty)
.unwrap_or_else(|| {
tcx.sess.delay_span_bug(
DUMMY_SP,
span: Span,
item_ident: Ident,
) -> Ty<'_> {
+ // Attempts to make the type nameable by turning FnDefs into FnPtrs.
+ struct MakeNameable<'tcx> {
+ success: bool,
+ tcx: TyCtxt<'tcx>,
+ }
+
+ impl<'tcx> MakeNameable<'tcx> {
+ fn new(tcx: TyCtxt<'tcx>) -> Self {
+ MakeNameable { success: true, tcx }
+ }
+ }
+
+ impl TypeFolder<'tcx> for MakeNameable<'tcx> {
+ fn tcx(&self) -> TyCtxt<'tcx> {
+ self.tcx
+ }
+
+ fn fold_ty(&mut self, ty: Ty<'tcx>) -> Ty<'tcx> {
+ if !self.success {
+ return ty;
+ }
+
+ match ty.kind() {
+ ty::FnDef(def_id, _) => self.tcx.mk_fn_ptr(self.tcx.fn_sig(*def_id)),
+ // FIXME: non-capturing closures should also suggest a function pointer
+ ty::Closure(..) | ty::Generator(..) => {
+ self.success = false;
+ ty
+ }
+ _ => ty.super_fold_with(self),
+ }
+ }
+ }
+
let ty = tcx.diagnostic_only_typeck(def_id).node_type(body_id.hir_id);
// If this came from a free `const` or `static mut?` item,
// The parser provided a sub-optimal `HasPlaceholders` suggestion for the type.
// We are typeck and have the real type, so remove that and suggest the actual type.
err.suggestions.clear();
- err.span_suggestion(
- span,
- "provide a type for the item",
- format!("{}: {}", item_ident, ty),
- Applicability::MachineApplicable,
- )
- .emit_unless(ty.references_error());
+
+ // Suggesting unnameable types won't help.
+ let mut mk_nameable = MakeNameable::new(tcx);
+ let ty = mk_nameable.fold_ty(ty);
+ let sugg_ty = if mk_nameable.success { Some(ty) } else { None };
+ if let Some(sugg_ty) = sugg_ty {
+ err.span_suggestion(
+ span,
+ "provide a type for the item",
+ format!("{}: {}", item_ident, sugg_ty),
+ Applicability::MachineApplicable,
+ );
+ } else {
+ err.span_note(
+ tcx.hir().body(body_id).value.span,
+ &format!("however, the inferred type `{}` cannot be named", ty.to_string()),
+ );
+ }
+
+ err.emit_unless(ty.references_error());
}
None => {
let mut diag = bad_placeholder_type(tcx, vec![span]);
if !ty.references_error() {
- diag.span_suggestion(
- span,
- "replace `_` with the correct type",
- ty.to_string(),
- Applicability::MaybeIncorrect,
- );
+ let mut mk_nameable = MakeNameable::new(tcx);
+ let ty = mk_nameable.fold_ty(ty);
+ let sugg_ty = if mk_nameable.success { Some(ty) } else { None };
+ if let Some(sugg_ty) = sugg_ty {
+ diag.span_suggestion(
+ span,
+ "replace with the correct type",
+ sugg_ty.to_string(),
+ Applicability::MaybeIncorrect,
+ );
+ } else {
+ diag.span_note(
+ tcx.hir().body(body_id).value.span,
+ &format!("however, the inferred type `{}` cannot be named", ty.to_string()),
+ );
+ }
}
diag.emit();
let remove_entire_generics = num_redundant_args >= self.gen_args.args.len();
let remove_lifetime_args = |err: &mut DiagnosticBuilder<'_>| {
- let idx_first_redundant_lt_args = self.num_expected_lifetime_args();
- let span_lo_redundant_lt_args =
- self.gen_args.args[idx_first_redundant_lt_args].span().shrink_to_lo();
- let span_hi_redundant_lt_args = self.gen_args.args
- [idx_first_redundant_lt_args + num_redundant_lt_args - 1]
- .span()
- .shrink_to_hi();
- let eat_comma =
- idx_first_redundant_lt_args + num_redundant_lt_args - 1 != self.gen_args.args.len();
-
- let span_redundant_lt_args = if eat_comma {
- let span_hi = self.gen_args.args
- [idx_first_redundant_lt_args + num_redundant_lt_args - 1]
- .span()
- .shrink_to_hi();
- span_lo_redundant_lt_args.to(span_hi)
- } else {
- span_lo_redundant_lt_args.to(span_hi_redundant_lt_args)
- };
+ let mut lt_arg_spans = Vec::new();
+ let mut found_redundant = false;
+ for arg in self.gen_args.args {
+ if let hir::GenericArg::Lifetime(_) = arg {
+ lt_arg_spans.push(arg.span());
+ if lt_arg_spans.len() > self.num_expected_lifetime_args() {
+ found_redundant = true;
+ }
+ } else if found_redundant {
+ // Argument which is redundant and separated like this `'c`
+ // is not included to avoid including `Bar` in span.
+ // ```
+ // type Foo<'a, T> = &'a T;
+ // let _: Foo<'a, 'b, Bar, 'c>;
+ // ```
+ break;
+ }
+ }
+
+ let span_lo_redundant_lt_args = lt_arg_spans[self.num_expected_lifetime_args()];
+ let span_hi_redundant_lt_args = lt_arg_spans[lt_arg_spans.len() - 1];
+
+ let span_redundant_lt_args = span_lo_redundant_lt_args.to(span_hi_redundant_lt_args);
debug!("span_redundant_lt_args: {:?}", span_redundant_lt_args);
+ let num_redundant_lt_args = lt_arg_spans.len() - self.num_expected_lifetime_args();
let msg_lifetimes = format!(
"remove {} {} argument{}",
- if num_redundant_args == 1 { "this" } else { "these" },
+ if num_redundant_lt_args == 1 { "this" } else { "these" },
"lifetime",
pluralize!(num_redundant_lt_args),
);
};
let remove_type_or_const_args = |err: &mut DiagnosticBuilder<'_>| {
- let idx_first_redundant_type_or_const_args = self.get_lifetime_args_offset()
- + num_redundant_lt_args
- + self.num_expected_type_or_const_args();
+ let mut gen_arg_spans = Vec::new();
+ let mut found_redundant = false;
+ for arg in self.gen_args.args {
+ match arg {
+ hir::GenericArg::Type(_) | hir::GenericArg::Const(_) => {
+ gen_arg_spans.push(arg.span());
+ if gen_arg_spans.len() > self.num_expected_type_or_const_args() {
+ found_redundant = true;
+ }
+ }
+ _ if found_redundant => break,
+ _ => {}
+ }
+ }
let span_lo_redundant_type_or_const_args =
- self.gen_args.args[idx_first_redundant_type_or_const_args].span().shrink_to_lo();
-
- let span_hi_redundant_type_or_const_args = self.gen_args.args
- [idx_first_redundant_type_or_const_args + num_redundant_type_or_const_args - 1]
- .span()
- .shrink_to_hi();
+ gen_arg_spans[self.num_expected_type_or_const_args()];
+ let span_hi_redundant_type_or_const_args = gen_arg_spans[gen_arg_spans.len() - 1];
let span_redundant_type_or_const_args =
span_lo_redundant_type_or_const_args.to(span_hi_redundant_type_or_const_args);
-
debug!("span_redundant_type_or_const_args: {:?}", span_redundant_type_or_const_args);
+ let num_redundant_gen_args =
+ gen_arg_spans.len() - self.num_expected_type_or_const_args();
let msg_types_or_consts = format!(
"remove {} {} argument{}",
- if num_redundant_args == 1 { "this" } else { "these" },
+ if num_redundant_gen_args == 1 { "this" } else { "these" },
"generic",
pluralize!(num_redundant_type_or_const_args),
);
# support. You'll need to write a target specification at least, and most
# likely, teach rustc about the C ABI of the target. Get in touch with the
# Rust team and file an issue if you need assistance in porting!
-#targets = "AArch64;ARM;Hexagon;MSP430;Mips;NVPTX;PowerPC;RISCV;Sparc;SystemZ;WebAssembly;X86"
+#targets = "AArch64;ARM;BPF;Hexagon;MSP430;Mips;NVPTX;PowerPC;RISCV;Sparc;SystemZ;WebAssembly;X86"
# LLVM experimental targets to build support for. These targets are specified in
# the same format as above, but since these targets are experimental, they are
# Use LLVM libunwind as the implementation for Rust's unwinder.
# Accepted values are 'in-tree' (formerly true), 'system' or 'no' (formerly false).
+# This option only applies for Linux and Fuchsia targets.
+# On Linux target, if crt-static is not enabled, 'no' means dynamic link to
+# `libgcc_s.so`, 'in-tree' means static link to the in-tree build of llvm libunwind
+# and 'system' means dynamic link to `libunwind.so`. If crt-static is enabled,
+# the behavior is depend on the libc. On musl target, 'no' and 'in-tree' both
+# means static link to the in-tree build of llvm libunwind, and 'system' means
+# static link to `libunwind.a` provided by system. Due to the limitation of glibc,
+# it must link to `libgcc_eh.a` to get a working output, and this option have no effect.
#llvm-libunwind = 'no'
# Enable Windows Control Flow Guard checks in the standard library.
#[bench]
fn bench_chain_collect(b: &mut Bencher) {
let data = black_box([0; LEN]);
- b.iter(|| data.iter().cloned().chain([1].iter().cloned()).collect::<Vec<_>>());
+ b.iter(|| data.iter().cloned().chain([1]).collect::<Vec<_>>());
}
#[bench]
fn bench_chain_chain_collect(b: &mut Bencher) {
let data = black_box([0; LEN]);
- b.iter(|| {
- data.iter()
- .cloned()
- .chain([1].iter().cloned())
- .chain([2].iter().cloned())
- .collect::<Vec<_>>()
- });
+ b.iter(|| data.iter().cloned().chain([1]).chain([2]).collect::<Vec<_>>());
}
#[bench]
#[cfg(not(no_global_oom_handling))]
#[stable(feature = "from_for_ptrs", since = "1.6.0")]
impl<T> From<T> for Box<T> {
- /// Converts a generic type `T` into a `Box<T>`
+ /// Converts a `T` into a `Box<T>`
///
/// The conversion allocates on the heap and moves `t`
/// from the stack into it.
#[stable(feature = "collection_debug", since = "1.17.0")]
impl<T: fmt::Debug> fmt::Debug for Iter<'_, T> {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
- f.debug_tuple("Iter").field(&self.len).finish()
+ f.debug_tuple("Iter")
+ .field(&*mem::ManuallyDrop::new(LinkedList {
+ head: self.head,
+ tail: self.tail,
+ len: self.len,
+ marker: PhantomData,
+ }))
+ .field(&self.len)
+ .finish()
}
}
/// documentation for more.
#[stable(feature = "rust1", since = "1.0.0")]
pub struct IterMut<'a, T: 'a> {
- // We do *not* exclusively own the entire list here, references to node's `element`
- // have been handed out by the iterator! So be careful when using this; the methods
- // called must be aware that there can be aliasing pointers to `element`.
- list: &'a mut LinkedList<T>,
head: Option<NonNull<Node<T>>>,
tail: Option<NonNull<Node<T>>>,
len: usize,
+ marker: PhantomData<&'a mut Node<T>>,
}
#[stable(feature = "collection_debug", since = "1.17.0")]
impl<T: fmt::Debug> fmt::Debug for IterMut<'_, T> {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
- f.debug_tuple("IterMut").field(&self.list).field(&self.len).finish()
+ f.debug_tuple("IterMut")
+ .field(&*mem::ManuallyDrop::new(LinkedList {
+ head: self.head,
+ tail: self.tail,
+ len: self.len,
+ marker: PhantomData,
+ }))
+ .field(&self.len)
+ .finish()
}
}
#[inline]
#[stable(feature = "rust1", since = "1.0.0")]
pub fn iter_mut(&mut self) -> IterMut<'_, T> {
- IterMut { head: self.head, tail: self.tail, len: self.len, list: self }
+ IterMut { head: self.head, tail: self.tail, len: self.len, marker: PhantomData }
}
/// Provides a cursor at the front element.
/// found; the fourth could match any position in `[1, 4]`.
///
/// ```
- /// #![feature(vecdeque_binary_search)]
/// use std::collections::VecDeque;
///
/// let deque: VecDeque<_> = vec![0, 1, 1, 1, 1, 2, 3, 5, 8, 13, 21, 34, 55].into();
/// sort order:
///
/// ```
- /// #![feature(vecdeque_binary_search)]
/// use std::collections::VecDeque;
///
/// let mut deque: VecDeque<_> = vec![0, 1, 1, 1, 1, 2, 3, 5, 8, 13, 21, 34, 55].into();
/// deque.insert(idx, num);
/// assert_eq!(deque, &[0, 1, 1, 1, 1, 2, 3, 5, 8, 13, 21, 34, 42, 55]);
/// ```
- #[unstable(feature = "vecdeque_binary_search", issue = "78021")]
+ #[stable(feature = "vecdeque_binary_search", since = "1.54.0")]
#[inline]
pub fn binary_search(&self, x: &T) -> Result<usize, usize>
where
/// found; the fourth could match any position in `[1, 4]`.
///
/// ```
- /// #![feature(vecdeque_binary_search)]
/// use std::collections::VecDeque;
///
/// let deque: VecDeque<_> = vec![0, 1, 1, 1, 1, 2, 3, 5, 8, 13, 21, 34, 55].into();
/// let r = deque.binary_search_by(|x| x.cmp(&1));
/// assert!(matches!(r, Ok(1..=4)));
/// ```
- #[unstable(feature = "vecdeque_binary_search", issue = "78021")]
+ #[stable(feature = "vecdeque_binary_search", since = "1.54.0")]
pub fn binary_search_by<'a, F>(&'a self, mut f: F) -> Result<usize, usize>
where
F: FnMut(&'a T) -> Ordering,
/// fourth could match any position in `[1, 4]`.
///
/// ```
- /// #![feature(vecdeque_binary_search)]
/// use std::collections::VecDeque;
///
/// let deque: VecDeque<_> = vec![(0, 0), (2, 1), (4, 1), (5, 1),
/// let r = deque.binary_search_by_key(&1, |&(a, b)| b);
/// assert!(matches!(r, Ok(1..=4)));
/// ```
- #[unstable(feature = "vecdeque_binary_search", issue = "78021")]
+ #[stable(feature = "vecdeque_binary_search", since = "1.54.0")]
#[inline]
pub fn binary_search_by_key<'a, B, F>(&'a self, b: &B, mut f: F) -> Result<usize, usize>
where
/// # Examples
///
/// ```
- /// #![feature(vecdeque_binary_search)]
/// use std::collections::VecDeque;
///
/// let deque: VecDeque<_> = vec![1, 2, 3, 3, 5, 6, 7].into();
/// assert!(deque.iter().take(i).all(|&x| x < 5));
/// assert!(deque.iter().skip(i).all(|&x| !(x < 5)));
/// ```
- #[unstable(feature = "vecdeque_binary_search", issue = "78021")]
+ #[stable(feature = "vecdeque_binary_search", since = "1.54.0")]
pub fn partition_point<P>(&self, mut pred: P) -> usize
where
P: FnMut(&T) -> bool,
-use core::array;
use core::cmp::{self};
use core::mem::replace;
}
pub fn remainder(self) -> impl Iterator<Item = &'b [T]> {
- array::IntoIter::new([self.b0, self.b1])
+ IntoIterator::into_iter([self.b0, self.b1])
}
}
#![allow(unused_attributes)]
#![stable(feature = "alloc", since = "1.36.0")]
#![doc(
- html_root_url = "https://doc.rust-lang.org/nightly/",
html_playground_url = "https://play.rust-lang.org/",
issue_tracker_base_url = "https://github.com/rust-lang/rust/issues/",
test(no_crate_inject, attr(allow(unused_variables), deny(warnings)))
#![feature(iter_zip)]
#![feature(lang_items)]
#![feature(layout_for_ptr)]
-#![feature(maybe_uninit_ref)]
#![feature(negative_impls)]
#![feature(never_type)]
#![feature(nll)]
#![feature(associated_type_bounds)]
#![feature(slice_group_by)]
#![feature(decl_macro)]
+#![feature(bindings_after_at)]
// Allow testing this library
#[cfg(test)]
B: ToOwned + ?Sized,
Rc<B>: From<&'a B> + From<B::Owned>,
{
+ /// Create a reference-counted pointer from
+ /// a clone-on-write pointer by copying its content.
+ ///
+ /// # Example
+ ///
+ /// ```rust
+ /// # use std::rc::Rc;
+ /// # use std::borrow::Cow;
+ /// let cow: Cow<str> = Cow::Borrowed("eggplant");
+ /// let shared: Rc<str> = Rc::from(cow);
+ /// assert_eq!("eggplant", &shared[..]);
+ /// ```
#[inline]
fn from(cow: Cow<'a, B>) -> Rc<B> {
match cow {
}
#[stable(feature = "rc_weak", since = "1.4.0")]
-impl<T: ?Sized> Drop for Weak<T> {
+unsafe impl<#[may_dangle] T: ?Sized> Drop for Weak<T> {
/// Drops the `Weak` pointer.
///
/// # Examples
use core::hash;
#[cfg(not(no_global_oom_handling))]
use core::iter::FromIterator;
-use core::iter::FusedIterator;
+use core::iter::{from_fn, FusedIterator};
#[cfg(not(no_global_oom_handling))]
use core::ops::Add;
#[cfg(not(no_global_oom_handling))]
self.vec.extend_from_slice(string.as_bytes())
}
+ /// Copies elements from `src` range to the end of the string.
+ ///
+ /// ## Panics
+ ///
+ /// Panics if the starting point or end point do not lie on a [`char`]
+ /// boundary, or if they're out of bounds.
+ ///
+ /// ## Examples
+ ///
+ /// ```
+ /// #![feature(string_extend_from_within)]
+ /// let mut string = String::from("abcde");
+ ///
+ /// string.extend_from_within(2..);
+ /// assert_eq!(string, "abcdecde");
+ ///
+ /// string.extend_from_within(..2);
+ /// assert_eq!(string, "abcdecdeab");
+ ///
+ /// string.extend_from_within(4..8);
+ /// assert_eq!(string, "abcdecdeabecde");
+ /// ```
+ #[cfg(not(no_global_oom_handling))]
+ #[unstable(feature = "string_extend_from_within", issue = "none")]
+ pub fn extend_from_within<R>(&mut self, src: R)
+ where
+ R: RangeBounds<usize>,
+ {
+ let src @ Range { start, end } = slice::range(src, ..self.len());
+
+ assert!(self.is_char_boundary(start));
+ assert!(self.is_char_boundary(end));
+
+ self.vec.extend_from_within(src);
+ }
+
/// Returns this `String`'s capacity, in bytes.
///
/// # Examples
{
use core::str::pattern::Searcher;
- let matches = {
+ let rejections = {
let mut searcher = pat.into_searcher(self);
- let mut matches = Vec::new();
-
- while let Some(m) = searcher.next_match() {
- matches.push(m);
- }
-
- matches
+ // Per Searcher::next:
+ //
+ // A Match result needs to contain the whole matched pattern,
+ // however Reject results may be split up into arbitrary many
+ // adjacent fragments. Both ranges may have zero length.
+ //
+ // In practice the implementation of Searcher::next_match tends to
+ // be more efficient, so we use it here and do some work to invert
+ // matches into rejections since that's what we want to copy below.
+ let mut front = 0;
+ let rejections: Vec<_> = from_fn(|| {
+ let (start, end) = searcher.next_match()?;
+ let prev_front = front;
+ front = end;
+ Some((prev_front, start))
+ })
+ .collect();
+ rejections.into_iter().chain(core::iter::once((front, self.len())))
};
- let len = self.len();
- let mut shrunk_by = 0;
+ let mut len = 0;
+ let ptr = self.vec.as_mut_ptr();
+
+ for (start, end) in rejections {
+ let count = end - start;
+ if start != len {
+ // SAFETY: per Searcher::next:
+ //
+ // The stream of Match and Reject values up to a Done will
+ // contain index ranges that are adjacent, non-overlapping,
+ // covering the whole haystack, and laying on utf8
+ // boundaries.
+ unsafe {
+ ptr::copy(ptr.add(start), ptr.add(len), count);
+ }
+ }
+ len += count;
+ }
- // SAFETY: start and end will be on utf8 byte boundaries per
- // the Searcher docs
unsafe {
- for (start, end) in matches {
- ptr::copy(
- self.vec.as_mut_ptr().add(end - shrunk_by),
- self.vec.as_mut_ptr().add(start - shrunk_by),
- len - end,
- );
- shrunk_by += end - start;
- }
- self.vec.set_len(len - shrunk_by);
+ self.vec.set_len(len);
}
}
#[cfg(not(no_global_oom_handling))]
#[stable(feature = "rust1", since = "1.0.0")]
impl From<&str> for String {
+ /// Converts a `&str` into a [`String`].
+ ///
+ /// The result is allocated on the heap.
#[inline]
fn from(s: &str) -> String {
s.to_owned()
#[cfg(not(no_global_oom_handling))]
#[stable(feature = "from_mut_str_for_string", since = "1.44.0")]
impl From<&mut str> for String {
- /// Converts a `&mut str` into a `String`.
+ /// Converts a `&mut str` into a [`String`].
///
/// The result is allocated on the heap.
#[inline]
#[cfg(not(no_global_oom_handling))]
#[stable(feature = "from_ref_string", since = "1.35.0")]
impl From<&String> for String {
+ /// Converts a `&String` into a [`String`].
+ ///
+ /// This clones `s` and returns the clone.
#[inline]
fn from(s: &String) -> String {
s.clone()
#[cfg(not(test))]
#[stable(feature = "string_from_box", since = "1.18.0")]
impl From<Box<str>> for String {
- /// Converts the given boxed `str` slice to a `String`.
+ /// Converts the given boxed `str` slice to a [`String`].
/// It is notable that the `str` slice is owned.
///
/// # Examples
#[cfg(not(no_global_oom_handling))]
#[stable(feature = "box_from_str", since = "1.20.0")]
impl From<String> for Box<str> {
- /// Converts the given `String` to a boxed `str` slice that is owned.
+ /// Converts the given [`String`] to a boxed `str` slice that is owned.
///
/// # Examples
///
#[cfg(not(no_global_oom_handling))]
#[stable(feature = "string_from_cow_str", since = "1.14.0")]
impl<'a> From<Cow<'a, str>> for String {
+ /// Converts a clone-on-write string to an owned
+ /// instance of [`String`].
+ ///
+ /// This extracts the owned string,
+ /// clones the string if it is not already owned.
+ ///
+ /// # Example
+ ///
+ /// ```
+ /// # use std::borrow::Cow;
+ /// // If the string is not owned...
+ /// let cow: Cow<str> = Cow::Borrowed("eggplant");
+ /// // It will allocate on the heap and copy the string.
+ /// let owned: String = String::from(cow);
+ /// assert_eq!(&owned[..], "eggplant");
+ /// ```
fn from(s: Cow<'a, str>) -> String {
s.into_owned()
}
#[cfg(not(no_global_oom_handling))]
#[stable(feature = "rust1", since = "1.0.0")]
impl<'a> From<&'a str> for Cow<'a, str> {
- /// Converts a string slice into a Borrowed variant.
+ /// Converts a string slice into a [`Borrowed`] variant.
/// No heap allocation is performed, and the string
/// is not copied.
///
/// # use std::borrow::Cow;
/// assert_eq!(Cow::from("eggplant"), Cow::Borrowed("eggplant"));
/// ```
+ ///
+ /// [`Borrowed`]: crate::borrow::Cow::Borrowed
#[inline]
fn from(s: &'a str) -> Cow<'a, str> {
Cow::Borrowed(s)
#[cfg(not(no_global_oom_handling))]
#[stable(feature = "rust1", since = "1.0.0")]
impl<'a> From<String> for Cow<'a, str> {
- /// Converts a String into an Owned variant.
+ /// Converts a [`String`] into an [`Owned`] variant.
/// No heap allocation is performed, and the string
/// is not copied.
///
/// let s2 = "eggplant".to_string();
/// assert_eq!(Cow::from(s), Cow::<'static, str>::Owned(s2));
/// ```
+ ///
+ /// [`Owned`]: crate::borrow::Cow::Owned
#[inline]
fn from(s: String) -> Cow<'a, str> {
Cow::Owned(s)
#[cfg(not(no_global_oom_handling))]
#[stable(feature = "cow_from_string_ref", since = "1.28.0")]
impl<'a> From<&'a String> for Cow<'a, str> {
- /// Converts a String reference into a Borrowed variant.
+ /// Converts a [`String`] reference into a [`Borrowed`] variant.
/// No heap allocation is performed, and the string
/// is not copied.
///
/// let s = "eggplant".to_string();
/// assert_eq!(Cow::from(&s), Cow::Borrowed("eggplant"));
/// ```
+ ///
+ /// [`Borrowed`]: crate::borrow::Cow::Borrowed
#[inline]
fn from(s: &'a String) -> Cow<'a, str> {
Cow::Borrowed(s.as_str())
#[stable(feature = "from_string_for_vec_u8", since = "1.14.0")]
impl From<String> for Vec<u8> {
- /// Converts the given `String` to a vector `Vec` that holds values of type `u8`.
+ /// Converts the given [`String`] to a vector [`Vec`] that holds values of type [`u8`].
///
/// # Examples
///
#[cfg(not(no_global_oom_handling))]
#[stable(feature = "from_char_for_string", since = "1.46.0")]
impl From<char> for String {
+ /// Allocates an owned [`String`] from a single character.
+ ///
+ /// # Example
+ /// ```rust
+ /// let c: char = 'a';
+ /// let s: String = String::from(c);
+ /// assert_eq!("a", &s[..]);
+ /// ```
#[inline]
fn from(c: char) -> Self {
c.to_string()
}
#[stable(feature = "arc_weak", since = "1.4.0")]
-impl<T: ?Sized> Drop for Weak<T> {
+unsafe impl<#[may_dangle] T: ?Sized> Drop for Weak<T> {
/// Drops the `Weak` pointer.
///
/// # Examples
B: ToOwned + ?Sized,
Arc<B>: From<&'a B> + From<B::Owned>,
{
+ /// Create an atomically reference-counted pointer from
+ /// a clone-on-write pointer by copying its content.
+ ///
+ /// # Example
+ ///
+ /// ```rust
+ /// # use std::sync::Arc;
+ /// # use std::borrow::Cow;
+ /// let cow: Cow<str> = Cow::Borrowed("eggplant");
+ /// let shared: Arc<str> = Arc::from(cow);
+ /// assert_eq!("eggplant", &shared[..]);
+ /// ```
#[inline]
fn from(cow: Cow<'a, B>) -> Arc<B> {
match cow {
#[stable(feature = "cow_from_vec", since = "1.8.0")]
impl<'a, T: Clone> From<&'a [T]> for Cow<'a, [T]> {
+ /// Creates a [`Borrowed`] variant of [`Cow`]
+ /// from a slice.
+ ///
+ /// This conversion does not allocate or clone the data.
+ ///
+ /// [`Borrowed`]: crate::borrow::Cow::Borrowed
fn from(s: &'a [T]) -> Cow<'a, [T]> {
Cow::Borrowed(s)
}
#[stable(feature = "cow_from_vec", since = "1.8.0")]
impl<'a, T: Clone> From<Vec<T>> for Cow<'a, [T]> {
+ /// Creates an [`Owned`] variant of [`Cow`]
+ /// from an owned instance of [`Vec`].
+ ///
+ /// This conversion does not allocate or clone the data.
+ ///
+ /// [`Owned`]: crate::borrow::Cow::Owned
fn from(v: Vec<T>) -> Cow<'a, [T]> {
Cow::Owned(v)
}
#[stable(feature = "cow_from_vec_ref", since = "1.28.0")]
impl<'a, T: Clone> From<&'a Vec<T>> for Cow<'a, [T]> {
+ /// Creates a [`Borrowed`] variant of [`Cow`]
+ /// from a reference to [`Vec`].
+ ///
+ /// This conversion does not allocate or clone the data.
+ ///
+ /// [`Borrowed`]: crate::borrow::Cow::Borrowed
fn from(v: &'a Vec<T>) -> Cow<'a, [T]> {
Cow::Borrowed(v.as_slice())
}
self.is_none()
}
}
+
+// `Option<num::NonZeroU32>` and similar have a representation guarantee that
+// they're the same size as the corresponding `u32` type, as well as a guarantee
+// that transmuting between `NonZeroU32` and `Option<num::NonZeroU32>` works.
+// While the documentation officially makes it UB to transmute from `None`,
+// we're the standard library so we can make extra inferences, and we know that
+// the only niche available to represent `None` is the one that's all zeros.
+
+macro_rules! impl_is_zero_option_of_nonzero {
+ ($($t:ident,)+) => {$(
+ unsafe impl IsZero for Option<core::num::$t> {
+ #[inline]
+ fn is_zero(&self) -> bool {
+ self.is_none()
+ }
+ }
+ )+};
+}
+
+impl_is_zero_option_of_nonzero!(
+ NonZeroU8,
+ NonZeroU16,
+ NonZeroU32,
+ NonZeroU64,
+ NonZeroU128,
+ NonZeroI8,
+ NonZeroI16,
+ NonZeroI32,
+ NonZeroI64,
+ NonZeroI128,
+ NonZeroUsize,
+ NonZeroIsize,
+);
///
/// ```
/// let mut vec = Vec::with_capacity(10);
- /// vec.extend([1, 2, 3].iter().cloned());
+ /// vec.extend([1, 2, 3]);
/// assert_eq!(vec.capacity(), 10);
/// vec.shrink_to_fit();
/// assert!(vec.capacity() >= 3);
/// ```
/// #![feature(shrink_to)]
/// let mut vec = Vec::with_capacity(10);
- /// vec.extend([1, 2, 3].iter().cloned());
+ /// vec.extend([1, 2, 3]);
/// assert_eq!(vec.capacity(), 10);
/// vec.shrink_to(4);
/// assert!(vec.capacity() >= 4);
///
/// ```
/// let mut vec = Vec::with_capacity(10);
- /// vec.extend([1, 2, 3].iter().cloned());
+ /// vec.extend([1, 2, 3]);
///
/// assert_eq!(vec.capacity(), 10);
/// let slice = vec.into_boxed_slice();
let prev_ptr = ptr.add(gap.write.wrapping_sub(1));
if same_bucket(&mut *read_ptr, &mut *prev_ptr) {
+ // Increase `gap.read` now since the drop may panic.
+ gap.read += 1;
/* We have found duplicate, drop it in-place */
ptr::drop_in_place(read_ptr);
} else {
/* We have filled that place, so go further */
gap.write += 1;
+ gap.read += 1;
}
-
- gap.read += 1;
}
/* Technically we could let `gap` clean up with its Drop, but
}
}
+/// The hash of a vector is the same as that of the corresponding slice,
+/// as required by the `core::borrow::Borrow` implementation.
+///
+/// ```
+/// use std::hash::{BuildHasher, Hash, Hasher};
+///
+/// fn hash_of(x: impl Hash, b: &impl BuildHasher) -> u64 {
+/// let mut h = b.build_hasher();
+/// x.hash(&mut h);
+/// h.finish()
+/// }
+///
+/// let b = std::collections::hash_map::RandomState::new();
+/// let v: Vec<u8> = vec![0xa8, 0x3c, 0x09];
+/// let s: &[u8] = &[0xa8, 0x3c, 0x09];
+/// assert_eq!(hash_of(v, &b), hash_of(s, &b));
+/// ```
#[stable(feature = "rust1", since = "1.0.0")]
impl<T: Hash, A: Allocator> Hash for Vec<T, A> {
#[inline]
/// ```
/// let mut v = vec![1, 2, 3];
/// let new = [7, 8];
- /// let u: Vec<_> = v.splice(..2, new.iter().cloned()).collect();
+ /// let u: Vec<_> = v.splice(..2, new).collect();
/// assert_eq!(v, &[7, 8, 3]);
/// assert_eq!(u, &[1, 2]);
/// ```
use core::mem::ManuallyDrop;
use core::ptr::{self};
-use core::slice::{self};
use super::{IntoIter, SpecExtend, SpecFromIterNested, Vec};
/// |where I: | | |where I: |
/// | Iterator (default)----------+ | | Iterator (default) |
/// | vec::IntoIter | | | TrustedLen |
-/// | SourceIterMarker---fallback-+ | | |
-/// | slice::Iter | | |
-/// | Iterator<Item = &Clone> | +---------------------+
+/// | SourceIterMarker---fallback-+ | +---------------------+
/// +---------------------------------+
/// ```
pub(super) trait SpecFromIter<T, I> {
vec
}
}
-
-impl<'a, T: 'a, I> SpecFromIter<&'a T, I> for Vec<T>
-where
- I: Iterator<Item = &'a T>,
- T: Clone,
-{
- default fn from_iter(iterator: I) -> Self {
- SpecFromIter::from_iter(iterator.cloned())
- }
-}
-
-// This utilizes `iterator.as_slice().to_vec()` since spec_extend
-// must take more steps to reason about the final capacity + length
-// and thus do more work. `to_vec()` directly allocates the correct amount
-// and fills it exactly.
-impl<'a, T: 'a + Clone> SpecFromIter<&'a T, slice::Iter<'a, T>> for Vec<T> {
- #[cfg(not(test))]
- fn from_iter(iterator: slice::Iter<'a, T>) -> Self {
- iterator.as_slice().to_vec()
- }
-
- // HACK(japaric): with cfg(test) the inherent `[T]::to_vec` method, which is
- // required for this method definition, is not available. Instead use the
- // `slice::to_vec` function which is only available with cfg(test)
- // NB see the slice::hack module in slice.rs for more information
- #[cfg(test)]
- fn from_iter(iterator: slice::Iter<'a, T>) -> Self {
- crate::slice::to_vec(iterator.as_slice(), crate::alloc::Global)
- }
-}
/// ```
/// let mut v = vec![0, 1, 2];
/// let new = [7, 8];
-/// let iter: std::vec::Splice<_> = v.splice(1.., new.iter().cloned());
+/// let iter: std::vec::Splice<_> = v.splice(1.., new);
/// ```
#[derive(Debug)]
#[stable(feature = "vec_splice", since = "1.21.0")]
assert_trusted_len(&iter);
assert_eq!(&[Box::new(42), Box::new(24)], &*iter.collect::<Rc<[_]>>());
}
+
+#[test]
+fn weak_may_dangle() {
+ fn hmm<'a>(val: &'a mut Weak<&'a str>) -> Weak<&'a str> {
+ val.clone()
+ }
+
+ // Without #[may_dangle] we get:
+ let mut val = Weak::new();
+ hmm(&mut val);
+ // ~~~~~~~~ borrowed value does not live long enough
+ //
+ // `val` dropped here while still borrowed
+ // borrow might be used here, when `val` is dropped and runs the `Drop` code for type `std::sync::Weak`
+}
#![feature(binary_heap_as_slice)]
#![feature(inplace_iteration)]
#![feature(iter_map_while)]
-#![feature(vecdeque_binary_search)]
#![feature(slice_group_by)]
#![feature(slice_partition_dedup)]
#![feature(vec_spare_capacity)]
assert_trusted_len(&iter);
assert_eq!(&[Box::new(42), Box::new(24)], &*iter.collect::<Rc<[_]>>());
}
+
+#[test]
+fn weak_may_dangle() {
+ fn hmm<'a>(val: &'a mut Weak<&'a str>) -> Weak<&'a str> {
+ val.clone()
+ }
+
+ // Without #[may_dangle] we get:
+ let mut val = Weak::new();
+ hmm(&mut val);
+ // ~~~~~~~~ borrowed value does not live long enough
+ //
+ // `val` dropped here while still borrowed
+ // borrow might be used here, when `val` is dropped and runs the `Drop` code for type `std::rc::Weak`
+}
fn test_splice() {
let mut v = vec![1, 2, 3, 4, 5];
let a = [10, 11, 12];
- v.splice(2..4, a.iter().cloned());
+ v.splice(2..4, a);
assert_eq!(v, &[1, 2, 10, 11, 12, 5]);
v.splice(1..3, Some(20));
assert_eq!(v, &[1, 20, 11, 12, 5]);
fn test_splice_inclusive_range() {
let mut v = vec![1, 2, 3, 4, 5];
let a = [10, 11, 12];
- let t1: Vec<_> = v.splice(2..=3, a.iter().cloned()).collect();
+ let t1: Vec<_> = v.splice(2..=3, a).collect();
assert_eq!(v, &[1, 2, 10, 11, 12, 5]);
assert_eq!(t1, &[3, 4]);
let t2: Vec<_> = v.splice(1..=2, Some(20)).collect();
fn test_splice_out_of_bounds() {
let mut v = vec![1, 2, 3, 4, 5];
let a = [10, 11, 12];
- v.splice(5..6, a.iter().cloned());
+ v.splice(5..6, a);
}
#[test]
fn test_splice_inclusive_out_of_bounds() {
let mut v = vec![1, 2, 3, 4, 5];
let a = [10, 11, 12];
- v.splice(5..=5, a.iter().cloned());
+ v.splice(5..=5, a);
}
#[test]
fn test_splice_forget() {
let mut v = vec![1, 2, 3, 4, 5];
let a = [10, 11, 12];
- std::mem::forget(v.splice(2..4, a.iter().cloned()));
+ std::mem::forget(v.splice(2..4, a));
assert_eq!(v, &[1, 2]);
}
#[test]
fn test_vec_dedup_panicking() {
#[derive(Debug)]
- struct Panic {
- drop_counter: &'static AtomicU32,
+ struct Panic<'a> {
+ drop_counter: &'a Cell<u32>,
value: bool,
index: usize,
}
- impl PartialEq for Panic {
+ impl<'a> PartialEq for Panic<'a> {
fn eq(&self, other: &Self) -> bool {
self.value == other.value
}
}
- impl Drop for Panic {
+ impl<'a> Drop for Panic<'a> {
fn drop(&mut self) {
- let x = self.drop_counter.fetch_add(1, Ordering::SeqCst);
- assert!(x != 4);
+ self.drop_counter.set(self.drop_counter.get() + 1);
+ if !std::thread::panicking() {
+ assert!(self.index != 4);
+ }
}
}
- static DROP_COUNTER: AtomicU32 = AtomicU32::new(0);
+ let drop_counter = &Cell::new(0);
let expected = [
- Panic { drop_counter: &DROP_COUNTER, value: false, index: 0 },
- Panic { drop_counter: &DROP_COUNTER, value: false, index: 5 },
- Panic { drop_counter: &DROP_COUNTER, value: true, index: 6 },
- Panic { drop_counter: &DROP_COUNTER, value: true, index: 7 },
+ Panic { drop_counter, value: false, index: 0 },
+ Panic { drop_counter, value: false, index: 5 },
+ Panic { drop_counter, value: true, index: 6 },
+ Panic { drop_counter, value: true, index: 7 },
];
let mut vec = vec![
- Panic { drop_counter: &DROP_COUNTER, value: false, index: 0 },
+ Panic { drop_counter, value: false, index: 0 },
// these elements get deduplicated
- Panic { drop_counter: &DROP_COUNTER, value: false, index: 1 },
- Panic { drop_counter: &DROP_COUNTER, value: false, index: 2 },
- Panic { drop_counter: &DROP_COUNTER, value: false, index: 3 },
- Panic { drop_counter: &DROP_COUNTER, value: false, index: 4 },
- // here it panics
- Panic { drop_counter: &DROP_COUNTER, value: false, index: 5 },
- Panic { drop_counter: &DROP_COUNTER, value: true, index: 6 },
- Panic { drop_counter: &DROP_COUNTER, value: true, index: 7 },
+ Panic { drop_counter, value: false, index: 1 },
+ Panic { drop_counter, value: false, index: 2 },
+ Panic { drop_counter, value: false, index: 3 },
+ Panic { drop_counter, value: false, index: 4 },
+ // here it panics while dropping the item with index==4
+ Panic { drop_counter, value: false, index: 5 },
+ Panic { drop_counter, value: true, index: 6 },
+ Panic { drop_counter, value: true, index: 7 },
];
- let _ = std::panic::catch_unwind(std::panic::AssertUnwindSafe(|| {
- vec.dedup();
- }));
+ let _ = catch_unwind(AssertUnwindSafe(|| vec.dedup())).unwrap_err();
+
+ assert_eq!(drop_counter.get(), 4);
let ok = vec.iter().zip(expected.iter()).all(|(x, y)| x.index == y.index);
// SAFETY: Callers are only allowed to pass an index that is in bounds
// Additionally Self: TrustedRandomAccess is only implemented for T: Copy which means even
// multiple repeated reads of the same index would be safe and the
- // values aree !Drop, thus won't suffer from double drops.
+ // values are !Drop, thus won't suffer from double drops.
unsafe { self.data.get_unchecked(self.alive.start + idx).assume_init_read() }
}
}
}
}
+/// The hash of an array is the same as that of the corresponding slice,
+/// as required by the `Borrow` implementation.
+///
+/// ```
+/// use std::hash::{BuildHasher, Hash, Hasher};
+///
+/// fn hash_of(x: impl Hash, b: &impl BuildHasher) -> u64 {
+/// let mut h = b.build_hasher();
+/// x.hash(&mut h);
+/// h.finish()
+/// }
+///
+/// let b = std::collections::hash_map::RandomState::new();
+/// let a: [u8; 3] = [0xa8, 0x3c, 0x09];
+/// let s: &[u8] = &[0xa8, 0x3c, 0x09];
+/// assert_eq!(hash_of(a, &b), hash_of(s, &b));
+/// ```
#[stable(feature = "rust1", since = "1.0.0")]
impl<T: Hash, const N: usize> Hash for [T; N] {
fn hash<H: hash::Hasher>(&self, state: &mut H) {
{
// SAFETY: we know for certain that this iterator will yield exactly `N`
// items.
- unsafe { collect_into_array_unchecked(&mut IntoIter::new(self).map(f)) }
+ unsafe { collect_into_array_unchecked(&mut IntoIterator::into_iter(self).map(f)) }
}
/// 'Zips up' two arrays into a single array of pairs.
/// ```
#[unstable(feature = "array_zip", issue = "80094")]
pub fn zip<U>(self, rhs: [U; N]) -> [(T, U); N] {
- let mut iter = IntoIter::new(self).zip(IntoIter::new(rhs));
+ let mut iter = IntoIterator::into_iter(self).zip(rhs);
// SAFETY: we know for certain that this iterator will yield exactly `N`
// items.
//! impl char {}
-use crate::intrinsics::likely;
use crate::slice;
use crate::str::from_utf8_unchecked_mut;
use crate::unicode::printable::is_printable;
/// ];
///
/// assert_eq!(
- /// decode_utf16(v.iter().cloned())
+ /// decode_utf16(v)
/// .map(|r| r.map_err(|e| e.unpaired_surrogate()))
/// .collect::<Vec<_>>(),
/// vec![
/// ];
///
/// assert_eq!(
- /// decode_utf16(v.iter().cloned())
+ /// decode_utf16(v)
/// .map(|r| r.unwrap_or(REPLACEMENT_CHARACTER))
/// .collect::<String>(),
/// "𝄞mus�ic�"
#[inline]
pub fn to_digit(self, radix: u32) -> Option<u32> {
assert!(radix <= 36, "to_digit: radix is too high (maximum 36)");
- // the code is split up here to improve execution speed for cases where
- // the `radix` is constant and 10 or smaller
- let val = if likely(radix <= 10) {
- // If not a digit, a number greater than radix will be created.
- (self as u32).wrapping_sub('0' as u32)
- } else {
- match self {
- '0'..='9' => self as u32 - '0' as u32,
- 'a'..='z' => self as u32 - 'a' as u32 + 10,
- 'A'..='Z' => self as u32 - 'A' as u32 + 10,
- _ => return None,
+ // If not a digit, a number greater than radix will be created.
+ let mut digit = (self as u32).wrapping_sub('0' as u32);
+ if radix > 10 {
+ if digit < 10 {
+ return Some(digit);
}
- };
-
- if val < radix { Some(val) } else { None }
+ // Force the 6th bit to be set to ensure ascii is lower case.
+ digit = (self as u32 | 0b10_0000).wrapping_sub('a' as u32).saturating_add(10);
+ }
+ (digit < radix).then_some(digit)
}
/// Returns an iterator that yields the hexadecimal Unicode escape of a
/// A common trait for the ability to explicitly duplicate an object.
///
-/// Differs from [`Copy`] in that [`Copy`] is implicit and extremely inexpensive, while
+/// Differs from [`Copy`] in that [`Copy`] is implicit and an inexpensive bit-wise copy, while
/// `Clone` is always explicit and may or may not be expensive. In order to enforce
/// these characteristics, Rust does not allow you to reimplement [`Copy`], but you
/// may reimplement `Clone` and run arbitrary code.
/// Allocate at compile time. Should not be called at runtime.
#[rustc_const_unstable(feature = "const_heap", issue = "79597")]
pub fn const_allocate(size: usize, align: usize) -> *mut u8;
-
- /// Copies `count * size_of::<T>()` bytes from `src` to `dst`. The source
- /// and destination must *not* overlap.
- ///
- /// For regions of memory which might overlap, use [`copy`] instead.
- ///
- /// `copy_nonoverlapping` is semantically equivalent to C's [`memcpy`], but
- /// with the argument order swapped.
- ///
- /// [`memcpy`]: https://en.cppreference.com/w/c/string/byte/memcpy
- ///
- /// # Safety
- ///
- /// Behavior is undefined if any of the following conditions are violated:
- ///
- /// * `src` must be [valid] for reads of `count * size_of::<T>()` bytes.
- ///
- /// * `dst` must be [valid] for writes of `count * size_of::<T>()` bytes.
- ///
- /// * Both `src` and `dst` must be properly aligned.
- ///
- /// * The region of memory beginning at `src` with a size of `count *
- /// size_of::<T>()` bytes must *not* overlap with the region of memory
- /// beginning at `dst` with the same size.
- ///
- /// Like [`read`], `copy_nonoverlapping` creates a bitwise copy of `T`, regardless of
- /// whether `T` is [`Copy`]. If `T` is not [`Copy`], using *both* the values
- /// in the region beginning at `*src` and the region beginning at `*dst` can
- /// [violate memory safety][read-ownership].
- ///
- /// Note that even if the effectively copied size (`count * size_of::<T>()`) is
- /// `0`, the pointers must be non-null and properly aligned.
- ///
- /// [`read`]: crate::ptr::read
- /// [read-ownership]: crate::ptr::read#ownership-of-the-returned-value
- /// [valid]: crate::ptr#safety
- ///
- /// # Examples
- ///
- /// Manually implement [`Vec::append`]:
- ///
- /// ```
- /// use std::ptr;
- ///
- /// /// Moves all the elements of `src` into `dst`, leaving `src` empty.
- /// fn append<T>(dst: &mut Vec<T>, src: &mut Vec<T>) {
- /// let src_len = src.len();
- /// let dst_len = dst.len();
- ///
- /// // Ensure that `dst` has enough capacity to hold all of `src`.
- /// dst.reserve(src_len);
- ///
- /// unsafe {
- /// // The call to offset is always safe because `Vec` will never
- /// // allocate more than `isize::MAX` bytes.
- /// let dst_ptr = dst.as_mut_ptr().offset(dst_len as isize);
- /// let src_ptr = src.as_ptr();
- ///
- /// // Truncate `src` without dropping its contents. We do this first,
- /// // to avoid problems in case something further down panics.
- /// src.set_len(0);
- ///
- /// // The two regions cannot overlap because mutable references do
- /// // not alias, and two different vectors cannot own the same
- /// // memory.
- /// ptr::copy_nonoverlapping(src_ptr, dst_ptr, src_len);
- ///
- /// // Notify `dst` that it now holds the contents of `src`.
- /// dst.set_len(dst_len + src_len);
- /// }
- /// }
- ///
- /// let mut a = vec!['r'];
- /// let mut b = vec!['u', 's', 't'];
- ///
- /// append(&mut a, &mut b);
- ///
- /// assert_eq!(a, &['r', 'u', 's', 't']);
- /// assert!(b.is_empty());
- /// ```
- ///
- /// [`Vec::append`]: ../../std/vec/struct.Vec.html#method.append
- #[doc(alias = "memcpy")]
- #[stable(feature = "rust1", since = "1.0.0")]
- #[rustc_const_unstable(feature = "const_intrinsic_copy", issue = "80697")]
- pub fn copy_nonoverlapping<T>(src: *const T, dst: *mut T, count: usize);
-
- /// Copies `count * size_of::<T>()` bytes from `src` to `dst`. The source
- /// and destination may overlap.
- ///
- /// If the source and destination will *never* overlap,
- /// [`copy_nonoverlapping`] can be used instead.
- ///
- /// `copy` is semantically equivalent to C's [`memmove`], but with the argument
- /// order swapped. Copying takes place as if the bytes were copied from `src`
- /// to a temporary array and then copied from the array to `dst`.
- ///
- /// [`memmove`]: https://en.cppreference.com/w/c/string/byte/memmove
- ///
- /// # Safety
- ///
- /// Behavior is undefined if any of the following conditions are violated:
- ///
- /// * `src` must be [valid] for reads of `count * size_of::<T>()` bytes.
- ///
- /// * `dst` must be [valid] for writes of `count * size_of::<T>()` bytes.
- ///
- /// * Both `src` and `dst` must be properly aligned.
- ///
- /// Like [`read`], `copy` creates a bitwise copy of `T`, regardless of
- /// whether `T` is [`Copy`]. If `T` is not [`Copy`], using both the values
- /// in the region beginning at `*src` and the region beginning at `*dst` can
- /// [violate memory safety][read-ownership].
- ///
- /// Note that even if the effectively copied size (`count * size_of::<T>()`) is
- /// `0`, the pointers must be non-null and properly aligned.
- ///
- /// [`read`]: crate::ptr::read
- /// [read-ownership]: crate::ptr::read#ownership-of-the-returned-value
- /// [valid]: crate::ptr#safety
- ///
- /// # Examples
- ///
- /// Efficiently create a Rust vector from an unsafe buffer:
- ///
- /// ```
- /// use std::ptr;
- ///
- /// /// # Safety
- /// ///
- /// /// * `ptr` must be correctly aligned for its type and non-zero.
- /// /// * `ptr` must be valid for reads of `elts` contiguous elements of type `T`.
- /// /// * Those elements must not be used after calling this function unless `T: Copy`.
- /// # #[allow(dead_code)]
- /// unsafe fn from_buf_raw<T>(ptr: *const T, elts: usize) -> Vec<T> {
- /// let mut dst = Vec::with_capacity(elts);
- ///
- /// // SAFETY: Our precondition ensures the source is aligned and valid,
- /// // and `Vec::with_capacity` ensures that we have usable space to write them.
- /// ptr::copy(ptr, dst.as_mut_ptr(), elts);
- ///
- /// // SAFETY: We created it with this much capacity earlier,
- /// // and the previous `copy` has initialized these elements.
- /// dst.set_len(elts);
- /// dst
- /// }
- /// ```
- #[doc(alias = "memmove")]
- #[stable(feature = "rust1", since = "1.0.0")]
- #[rustc_const_unstable(feature = "const_intrinsic_copy", issue = "80697")]
- pub fn copy<T>(src: *const T, dst: *mut T, count: usize);
}
// Some functions are defined here because they accidentally got made
!ptr.is_null() && ptr as usize % mem::align_of::<T>() == 0
}
+/// Copies `count * size_of::<T>()` bytes from `src` to `dst`. The source
+/// and destination must *not* overlap.
+///
+/// For regions of memory which might overlap, use [`copy`] instead.
+///
+/// `copy_nonoverlapping` is semantically equivalent to C's [`memcpy`], but
+/// with the argument order swapped.
+///
+/// [`memcpy`]: https://en.cppreference.com/w/c/string/byte/memcpy
+///
+/// # Safety
+///
+/// Behavior is undefined if any of the following conditions are violated:
+///
+/// * `src` must be [valid] for reads of `count * size_of::<T>()` bytes.
+///
+/// * `dst` must be [valid] for writes of `count * size_of::<T>()` bytes.
+///
+/// * Both `src` and `dst` must be properly aligned.
+///
+/// * The region of memory beginning at `src` with a size of `count *
+/// size_of::<T>()` bytes must *not* overlap with the region of memory
+/// beginning at `dst` with the same size.
+///
+/// Like [`read`], `copy_nonoverlapping` creates a bitwise copy of `T`, regardless of
+/// whether `T` is [`Copy`]. If `T` is not [`Copy`], using *both* the values
+/// in the region beginning at `*src` and the region beginning at `*dst` can
+/// [violate memory safety][read-ownership].
+///
+/// Note that even if the effectively copied size (`count * size_of::<T>()`) is
+/// `0`, the pointers must be non-null and properly aligned.
+///
+/// [`read`]: crate::ptr::read
+/// [read-ownership]: crate::ptr::read#ownership-of-the-returned-value
+/// [valid]: crate::ptr#safety
+///
+/// # Examples
+///
+/// Manually implement [`Vec::append`]:
+///
+/// ```
+/// use std::ptr;
+///
+/// /// Moves all the elements of `src` into `dst`, leaving `src` empty.
+/// fn append<T>(dst: &mut Vec<T>, src: &mut Vec<T>) {
+/// let src_len = src.len();
+/// let dst_len = dst.len();
+///
+/// // Ensure that `dst` has enough capacity to hold all of `src`.
+/// dst.reserve(src_len);
+///
+/// unsafe {
+/// // The call to offset is always safe because `Vec` will never
+/// // allocate more than `isize::MAX` bytes.
+/// let dst_ptr = dst.as_mut_ptr().offset(dst_len as isize);
+/// let src_ptr = src.as_ptr();
+///
+/// // Truncate `src` without dropping its contents. We do this first,
+/// // to avoid problems in case something further down panics.
+/// src.set_len(0);
+///
+/// // The two regions cannot overlap because mutable references do
+/// // not alias, and two different vectors cannot own the same
+/// // memory.
+/// ptr::copy_nonoverlapping(src_ptr, dst_ptr, src_len);
+///
+/// // Notify `dst` that it now holds the contents of `src`.
+/// dst.set_len(dst_len + src_len);
+/// }
+/// }
+///
+/// let mut a = vec!['r'];
+/// let mut b = vec!['u', 's', 't'];
+///
+/// append(&mut a, &mut b);
+///
+/// assert_eq!(a, &['r', 'u', 's', 't']);
+/// assert!(b.is_empty());
+/// ```
+///
+/// [`Vec::append`]: ../../std/vec/struct.Vec.html#method.append
+#[doc(alias = "memcpy")]
+#[stable(feature = "rust1", since = "1.0.0")]
+#[rustc_const_unstable(feature = "const_intrinsic_copy", issue = "80697")]
+#[inline]
+pub const unsafe fn copy_nonoverlapping<T>(src: *const T, dst: *mut T, count: usize) {
+ extern "rust-intrinsic" {
+ #[rustc_const_unstable(feature = "const_intrinsic_copy", issue = "80697")]
+ pub fn copy_nonoverlapping<T>(src: *const T, dst: *mut T, count: usize);
+ }
+
+ // FIXME: Perform these checks only at run time
+ /*if cfg!(debug_assertions)
+ && !(is_aligned_and_not_null(src)
+ && is_aligned_and_not_null(dst)
+ && is_nonoverlapping(src, dst, count))
+ {
+ // Not panicking to keep codegen impact smaller.
+ abort();
+ }*/
+
+ // SAFETY: the safety contract for `copy_nonoverlapping` must be
+ // upheld by the caller.
+ unsafe { copy_nonoverlapping(src, dst, count) }
+}
+
+/// Copies `count * size_of::<T>()` bytes from `src` to `dst`. The source
+/// and destination may overlap.
+///
+/// If the source and destination will *never* overlap,
+/// [`copy_nonoverlapping`] can be used instead.
+///
+/// `copy` is semantically equivalent to C's [`memmove`], but with the argument
+/// order swapped. Copying takes place as if the bytes were copied from `src`
+/// to a temporary array and then copied from the array to `dst`.
+///
+/// [`memmove`]: https://en.cppreference.com/w/c/string/byte/memmove
+///
+/// # Safety
+///
+/// Behavior is undefined if any of the following conditions are violated:
+///
+/// * `src` must be [valid] for reads of `count * size_of::<T>()` bytes.
+///
+/// * `dst` must be [valid] for writes of `count * size_of::<T>()` bytes.
+///
+/// * Both `src` and `dst` must be properly aligned.
+///
+/// Like [`read`], `copy` creates a bitwise copy of `T`, regardless of
+/// whether `T` is [`Copy`]. If `T` is not [`Copy`], using both the values
+/// in the region beginning at `*src` and the region beginning at `*dst` can
+/// [violate memory safety][read-ownership].
+///
+/// Note that even if the effectively copied size (`count * size_of::<T>()`) is
+/// `0`, the pointers must be non-null and properly aligned.
+///
+/// [`read`]: crate::ptr::read
+/// [read-ownership]: crate::ptr::read#ownership-of-the-returned-value
+/// [valid]: crate::ptr#safety
+///
+/// # Examples
+///
+/// Efficiently create a Rust vector from an unsafe buffer:
+///
+/// ```
+/// use std::ptr;
+///
+/// /// # Safety
+/// ///
+/// /// * `ptr` must be correctly aligned for its type and non-zero.
+/// /// * `ptr` must be valid for reads of `elts` contiguous elements of type `T`.
+/// /// * Those elements must not be used after calling this function unless `T: Copy`.
+/// # #[allow(dead_code)]
+/// unsafe fn from_buf_raw<T>(ptr: *const T, elts: usize) -> Vec<T> {
+/// let mut dst = Vec::with_capacity(elts);
+///
+/// // SAFETY: Our precondition ensures the source is aligned and valid,
+/// // and `Vec::with_capacity` ensures that we have usable space to write them.
+/// ptr::copy(ptr, dst.as_mut_ptr(), elts);
+///
+/// // SAFETY: We created it with this much capacity earlier,
+/// // and the previous `copy` has initialized these elements.
+/// dst.set_len(elts);
+/// dst
+/// }
+/// ```
+#[doc(alias = "memmove")]
+#[stable(feature = "rust1", since = "1.0.0")]
+#[rustc_const_unstable(feature = "const_intrinsic_copy", issue = "80697")]
+#[inline]
+pub const unsafe fn copy<T>(src: *const T, dst: *mut T, count: usize) {
+ extern "rust-intrinsic" {
+ #[rustc_const_unstable(feature = "const_intrinsic_copy", issue = "80697")]
+ fn copy<T>(src: *const T, dst: *mut T, count: usize);
+ }
+
+ // FIXME: Perform these checks only at run time
+ /*if cfg!(debug_assertions) && !(is_aligned_and_not_null(src) && is_aligned_and_not_null(dst)) {
+ // Not panicking to keep codegen impact smaller.
+ abort();
+ }*/
+
+ // SAFETY: the safety contract for `copy` must be upheld by the caller.
+ unsafe { copy(src, dst, count) }
+}
+
/// Sets `count * size_of::<T>()` bytes of memory starting at `dst` to
/// `val`.
///
use crate::cmp;
-use crate::iter::{
- adapters::zip::try_get_unchecked, adapters::SourceIter, FusedIterator, InPlaceIterable,
- TrustedLen, TrustedRandomAccess,
-};
+use crate::iter::{adapters::SourceIter, FusedIterator, InPlaceIterable, TrustedLen};
use crate::ops::{ControlFlow, Try};
/// An iterator that only iterates over the first `n` iterations of `iter`.
self.try_fold(init, ok(fold)).unwrap()
}
-
- unsafe fn __iterator_get_unchecked(&mut self, idx: usize) -> <I as Iterator>::Item
- where
- Self: TrustedRandomAccess,
- {
- // SAFETY: the caller must uphold the contract for
- // `Iterator::__iterator_get_unchecked`.
- unsafe { try_get_unchecked(&mut self.iter, idx) }
- }
}
#[unstable(issue = "none", feature = "inplace_iteration")]
#[unstable(feature = "trusted_len", issue = "37572")]
unsafe impl<I: TrustedLen> TrustedLen for Take<I> {}
-
-#[doc(hidden)]
-#[unstable(feature = "trusted_random_access", issue = "none")]
-unsafe impl<I> TrustedRandomAccess for Take<I>
-where
- I: TrustedRandomAccess,
-{
- const MAY_HAVE_SIDE_EFFECT: bool = I::MAY_HAVE_SIDE_EFFECT;
-}
/// called on `self`:
/// * `std::clone::Clone::clone()`
/// * `std::iter::Iterator::size_hint()`
-/// * `std::iter::Iterator::next_back()`
+/// * `std::iter::DoubleEndedIterator::next_back()`
/// * `std::iter::Iterator::__iterator_get_unchecked()`
/// * `std::iter::TrustedRandomAccess::size()`
///
pub use self::traits::InPlaceIterable;
#[unstable(feature = "trusted_len", issue = "37572")]
pub use self::traits::TrustedLen;
+#[unstable(feature = "trusted_step", issue = "85731")]
+pub use self::traits::TrustedStep;
#[stable(feature = "rust1", since = "1.0.0")]
pub use self::traits::{
DoubleEndedIterator, ExactSizeIterator, Extend, FromIterator, IntoIterator, Product, Sum,
use crate::mem;
use crate::ops::{self, Try};
-use super::{FusedIterator, TrustedLen, TrustedRandomAccess};
+use super::{FusedIterator, TrustedLen, TrustedRandomAccess, TrustedStep};
+
+// Safety: All invariants are upheld.
+macro_rules! unsafe_impl_trusted_step {
+ ($($type:ty)*) => {$(
+ #[unstable(feature = "trusted_step", issue = "85731")]
+ unsafe impl TrustedStep for $type {}
+ )*};
+}
+unsafe_impl_trusted_step![char i8 i16 i32 i64 i128 isize u8 u16 u32 u64 u128 usize];
/// Objects that have a notion of *successor* and *predecessor* operations.
///
/// The *successor* operation moves towards values that compare greater.
/// The *predecessor* operation moves towards values that compare lesser.
-///
-/// # Safety
-///
-/// This trait is `unsafe` because its implementation must be correct for
-/// the safety of `unsafe trait TrustedLen` implementations, and the results
-/// of using this trait can otherwise be trusted by `unsafe` code to be correct
-/// and fulfill the listed obligations.
#[unstable(feature = "step_trait", reason = "recently redesigned", issue = "42168")]
-pub unsafe trait Step: Clone + PartialOrd + Sized {
+pub trait Step: Clone + PartialOrd + Sized {
/// Returns the number of *successor* steps required to get from `start` to `end`.
///
/// Returns `None` if the number of steps would overflow `usize`
///
/// * `Step::forward_checked(a, n) == (0..n).try_fold(a, |x, _| Step::forward_checked(&x, 1))`
/// * Corollary: `Step::forward_checked(&a, 0) == Some(a)`
- #[unstable(feature = "step_trait_ext", reason = "recently added", issue = "42168")]
fn forward_checked(start: Self, count: usize) -> Option<Self>;
/// Returns the value that would be obtained by taking the *successor*
/// * Corollary: `Step::forward(a, 0) == a`
/// * `Step::forward(a, n) >= a`
/// * `Step::backward(Step::forward(a, n), n) == a`
- #[unstable(feature = "step_trait_ext", reason = "recently added", issue = "42168")]
fn forward(start: Self, count: usize) -> Self {
Step::forward_checked(start, count).expect("overflow in `Step::forward`")
}
/// For any `a` and `n`, where no overflow occurs:
///
/// * `Step::forward_unchecked(a, n)` is equivalent to `Step::forward(a, n)`
- #[unstable(feature = "step_trait_ext", reason = "recently added", issue = "42168")]
unsafe fn forward_unchecked(start: Self, count: usize) -> Self {
Step::forward(start, count)
}
///
/// * `Step::backward_checked(a, n) == (0..n).try_fold(a, |x, _| Step::backward_checked(&x, 1))`
/// * Corollary: `Step::backward_checked(&a, 0) == Some(a)`
- #[unstable(feature = "step_trait_ext", reason = "recently added", issue = "42168")]
fn backward_checked(start: Self, count: usize) -> Option<Self>;
/// Returns the value that would be obtained by taking the *predecessor*
/// * Corollary: `Step::backward(a, 0) == a`
/// * `Step::backward(a, n) <= a`
/// * `Step::forward(Step::backward(a, n), n) == a`
- #[unstable(feature = "step_trait_ext", reason = "recently added", issue = "42168")]
fn backward(start: Self, count: usize) -> Self {
Step::backward_checked(start, count).expect("overflow in `Step::backward`")
}
/// For any `a` and `n`, where no overflow occurs:
///
/// * `Step::backward_unchecked(a, n)` is equivalent to `Step::backward(a, n)`
- #[unstable(feature = "step_trait_ext", reason = "recently added", issue = "42168")]
unsafe fn backward_unchecked(start: Self, count: usize) -> Self {
Step::backward(start, count)
}
$(
#[allow(unreachable_patterns)]
#[unstable(feature = "step_trait", reason = "recently redesigned", issue = "42168")]
- unsafe impl Step for $u_narrower {
+ impl Step for $u_narrower {
step_identical_methods!();
#[inline]
#[allow(unreachable_patterns)]
#[unstable(feature = "step_trait", reason = "recently redesigned", issue = "42168")]
- unsafe impl Step for $i_narrower {
+ impl Step for $i_narrower {
step_identical_methods!();
#[inline]
$(
#[allow(unreachable_patterns)]
#[unstable(feature = "step_trait", reason = "recently redesigned", issue = "42168")]
- unsafe impl Step for $u_wider {
+ impl Step for $u_wider {
step_identical_methods!();
#[inline]
#[allow(unreachable_patterns)]
#[unstable(feature = "step_trait", reason = "recently redesigned", issue = "42168")]
- unsafe impl Step for $i_wider {
+ impl Step for $i_wider {
step_identical_methods!();
#[inline]
}
#[unstable(feature = "step_trait", reason = "recently redesigned", issue = "42168")]
-unsafe impl Step for char {
+impl Step for char {
#[inline]
fn steps_between(&start: &char, &end: &char) -> Option<usize> {
let start = start as u32;
)*)
}
-#[stable(feature = "rust1", since = "1.0.0")]
-impl<A: Step> Iterator for ops::Range<A> {
+/// Specialization implementations for `Range`.
+trait RangeIteratorImpl {
+ type Item;
+
+ // Iterator
+ fn spec_next(&mut self) -> Option<Self::Item>;
+ fn spec_nth(&mut self, n: usize) -> Option<Self::Item>;
+
+ // DoubleEndedIterator
+ fn spec_next_back(&mut self) -> Option<Self::Item>;
+ fn spec_nth_back(&mut self, n: usize) -> Option<Self::Item>;
+}
+
+impl<A: Step> RangeIteratorImpl for ops::Range<A> {
type Item = A;
#[inline]
- fn next(&mut self) -> Option<A> {
+ default fn spec_next(&mut self) -> Option<A> {
if self.start < self.end {
- // SAFETY: just checked precondition
- let n = unsafe { Step::forward_unchecked(self.start.clone(), 1) };
+ let n =
+ Step::forward_checked(self.start.clone(), 1).expect("`Step` invariants not upheld");
Some(mem::replace(&mut self.start, n))
} else {
None
}
#[inline]
- fn size_hint(&self) -> (usize, Option<usize>) {
+ default fn spec_nth(&mut self, n: usize) -> Option<A> {
+ if let Some(plus_n) = Step::forward_checked(self.start.clone(), n) {
+ if plus_n < self.end {
+ self.start =
+ Step::forward_checked(plus_n.clone(), 1).expect("`Step` invariants not upheld");
+ return Some(plus_n);
+ }
+ }
+
+ self.start = self.end.clone();
+ None
+ }
+
+ #[inline]
+ default fn spec_next_back(&mut self) -> Option<A> {
if self.start < self.end {
- let hint = Step::steps_between(&self.start, &self.end);
- (hint.unwrap_or(usize::MAX), hint)
+ self.end =
+ Step::backward_checked(self.end.clone(), 1).expect("`Step` invariants not upheld");
+ Some(self.end.clone())
} else {
- (0, Some(0))
+ None
}
}
#[inline]
- fn nth(&mut self, n: usize) -> Option<A> {
+ default fn spec_nth_back(&mut self, n: usize) -> Option<A> {
+ if let Some(minus_n) = Step::backward_checked(self.end.clone(), n) {
+ if minus_n > self.start {
+ self.end =
+ Step::backward_checked(minus_n, 1).expect("`Step` invariants not upheld");
+ return Some(self.end.clone());
+ }
+ }
+
+ self.end = self.start.clone();
+ None
+ }
+}
+
+impl<T: TrustedStep> RangeIteratorImpl for ops::Range<T> {
+ #[inline]
+ fn spec_next(&mut self) -> Option<T> {
+ if self.start < self.end {
+ // SAFETY: just checked precondition
+ let n = unsafe { Step::forward_unchecked(self.start.clone(), 1) };
+ Some(mem::replace(&mut self.start, n))
+ } else {
+ None
+ }
+ }
+
+ #[inline]
+ fn spec_nth(&mut self, n: usize) -> Option<T> {
if let Some(plus_n) = Step::forward_checked(self.start.clone(), n) {
if plus_n < self.end {
// SAFETY: just checked precondition
None
}
+ #[inline]
+ fn spec_next_back(&mut self) -> Option<T> {
+ if self.start < self.end {
+ // SAFETY: just checked precondition
+ self.end = unsafe { Step::backward_unchecked(self.end.clone(), 1) };
+ Some(self.end.clone())
+ } else {
+ None
+ }
+ }
+
+ #[inline]
+ fn spec_nth_back(&mut self, n: usize) -> Option<T> {
+ if let Some(minus_n) = Step::backward_checked(self.end.clone(), n) {
+ if minus_n > self.start {
+ // SAFETY: just checked precondition
+ self.end = unsafe { Step::backward_unchecked(minus_n, 1) };
+ return Some(self.end.clone());
+ }
+ }
+
+ self.end = self.start.clone();
+ None
+ }
+}
+
+#[stable(feature = "rust1", since = "1.0.0")]
+impl<A: Step> Iterator for ops::Range<A> {
+ type Item = A;
+
+ #[inline]
+ fn next(&mut self) -> Option<A> {
+ self.spec_next()
+ }
+
+ #[inline]
+ fn size_hint(&self) -> (usize, Option<usize>) {
+ if self.start < self.end {
+ let hint = Step::steps_between(&self.start, &self.end);
+ (hint.unwrap_or(usize::MAX), hint)
+ } else {
+ (0, Some(0))
+ }
+ }
+
+ #[inline]
+ fn nth(&mut self, n: usize) -> Option<A> {
+ self.spec_nth(n)
+ }
+
#[inline]
fn last(mut self) -> Option<A> {
self.next_back()
impl<A: Step> DoubleEndedIterator for ops::Range<A> {
#[inline]
fn next_back(&mut self) -> Option<A> {
- if self.start < self.end {
- // SAFETY: just checked precondition
- self.end = unsafe { Step::backward_unchecked(self.end.clone(), 1) };
- Some(self.end.clone())
- } else {
- None
- }
+ self.spec_next_back()
}
#[inline]
fn nth_back(&mut self, n: usize) -> Option<A> {
- if let Some(minus_n) = Step::backward_checked(self.end.clone(), n) {
- if minus_n > self.start {
- // SAFETY: just checked precondition
- self.end = unsafe { Step::backward_unchecked(minus_n, 1) };
- return Some(self.end.clone());
- }
- }
-
- self.end = self.start.clone();
- None
+ self.spec_nth_back(n)
}
}
+// Safety:
+// The following invariants for `Step::steps_between` exist:
+//
+// > * `steps_between(&a, &b) == Some(n)` only if `a <= b`
+// > * Note that `a <= b` does _not_ imply `steps_between(&a, &b) != None`;
+// > this is the case when it would require more than `usize::MAX` steps to
+// > get to `b`
+// > * `steps_between(&a, &b) == None` if `a > b`
+//
+// The first invariant is what is generally required for `TrustedLen` to be
+// sound. The note addendum satisfies an additional `TrustedLen` invariant.
+//
+// > The upper bound must only be `None` if the actual iterator length is larger
+// > than `usize::MAX`
+//
+// The second invariant logically follows the first so long as the `PartialOrd`
+// implementation is correct; regardless it is explicitly stated. If `a < b`
+// then `(0, Some(0))` is returned by `ops::Range<A: Step>::size_hint`. As such
+// the second invariant is upheld.
#[unstable(feature = "trusted_len", issue = "37572")]
-unsafe impl<A: Step> TrustedLen for ops::Range<A> {}
+unsafe impl<A: TrustedStep> TrustedLen for ops::Range<A> {}
#[stable(feature = "fused", since = "1.26.0")]
impl<A: Step> FusedIterator for ops::Range<A> {}
}
}
+// Safety: See above implementation for `ops::Range<A>`
+#[unstable(feature = "trusted_len", issue = "37572")]
+unsafe impl<A: TrustedStep> TrustedLen for ops::RangeFrom<A> {}
+
#[stable(feature = "fused", since = "1.26.0")]
impl<A: Step> FusedIterator for ops::RangeFrom<A> {}
-#[unstable(feature = "trusted_len", issue = "37572")]
-unsafe impl<A: Step> TrustedLen for ops::RangeFrom<A> {}
+trait RangeInclusiveIteratorImpl {
+ type Item;
-#[stable(feature = "inclusive_range", since = "1.26.0")]
-impl<A: Step> Iterator for ops::RangeInclusive<A> {
+ // Iterator
+ fn spec_next(&mut self) -> Option<Self::Item>;
+ fn spec_try_fold<B, F, R>(&mut self, init: B, f: F) -> R
+ where
+ Self: Sized,
+ F: FnMut(B, Self::Item) -> R,
+ R: Try<Output = B>;
+
+ // DoubleEndedIterator
+ fn spec_next_back(&mut self) -> Option<Self::Item>;
+ fn spec_try_rfold<B, F, R>(&mut self, init: B, f: F) -> R
+ where
+ Self: Sized,
+ F: FnMut(B, Self::Item) -> R,
+ R: Try<Output = B>;
+}
+
+impl<A: Step> RangeInclusiveIteratorImpl for ops::RangeInclusive<A> {
type Item = A;
#[inline]
- fn next(&mut self) -> Option<A> {
+ default fn spec_next(&mut self) -> Option<A> {
+ if self.is_empty() {
+ return None;
+ }
+ let is_iterating = self.start < self.end;
+ Some(if is_iterating {
+ let n =
+ Step::forward_checked(self.start.clone(), 1).expect("`Step` invariants not upheld");
+ mem::replace(&mut self.start, n)
+ } else {
+ self.exhausted = true;
+ self.start.clone()
+ })
+ }
+
+ #[inline]
+ default fn spec_try_fold<B, F, R>(&mut self, init: B, mut f: F) -> R
+ where
+ Self: Sized,
+ F: FnMut(B, A) -> R,
+ R: Try<Output = B>,
+ {
+ if self.is_empty() {
+ return try { init };
+ }
+
+ let mut accum = init;
+
+ while self.start < self.end {
+ let n =
+ Step::forward_checked(self.start.clone(), 1).expect("`Step` invariants not upheld");
+ let n = mem::replace(&mut self.start, n);
+ accum = f(accum, n)?;
+ }
+
+ self.exhausted = true;
+
+ if self.start == self.end {
+ accum = f(accum, self.start.clone())?;
+ }
+
+ try { accum }
+ }
+
+ #[inline]
+ default fn spec_next_back(&mut self) -> Option<A> {
+ if self.is_empty() {
+ return None;
+ }
+ let is_iterating = self.start < self.end;
+ Some(if is_iterating {
+ let n =
+ Step::backward_checked(self.end.clone(), 1).expect("`Step` invariants not upheld");
+ mem::replace(&mut self.end, n)
+ } else {
+ self.exhausted = true;
+ self.end.clone()
+ })
+ }
+
+ #[inline]
+ default fn spec_try_rfold<B, F, R>(&mut self, init: B, mut f: F) -> R
+ where
+ Self: Sized,
+ F: FnMut(B, A) -> R,
+ R: Try<Output = B>,
+ {
+ if self.is_empty() {
+ return try { init };
+ }
+
+ let mut accum = init;
+
+ while self.start < self.end {
+ let n =
+ Step::backward_checked(self.end.clone(), 1).expect("`Step` invariants not upheld");
+ let n = mem::replace(&mut self.end, n);
+ accum = f(accum, n)?;
+ }
+
+ self.exhausted = true;
+
+ if self.start == self.end {
+ accum = f(accum, self.start.clone())?;
+ }
+
+ try { accum }
+ }
+}
+
+impl<T: TrustedStep> RangeInclusiveIteratorImpl for ops::RangeInclusive<T> {
+ #[inline]
+ fn spec_next(&mut self) -> Option<T> {
if self.is_empty() {
return None;
}
})
}
+ #[inline]
+ fn spec_try_fold<B, F, R>(&mut self, init: B, mut f: F) -> R
+ where
+ Self: Sized,
+ F: FnMut(B, T) -> R,
+ R: Try<Output = B>,
+ {
+ if self.is_empty() {
+ return try { init };
+ }
+
+ let mut accum = init;
+
+ while self.start < self.end {
+ // SAFETY: just checked precondition
+ let n = unsafe { Step::forward_unchecked(self.start.clone(), 1) };
+ let n = mem::replace(&mut self.start, n);
+ accum = f(accum, n)?;
+ }
+
+ self.exhausted = true;
+
+ if self.start == self.end {
+ accum = f(accum, self.start.clone())?;
+ }
+
+ try { accum }
+ }
+
+ #[inline]
+ fn spec_next_back(&mut self) -> Option<T> {
+ if self.is_empty() {
+ return None;
+ }
+ let is_iterating = self.start < self.end;
+ Some(if is_iterating {
+ // SAFETY: just checked precondition
+ let n = unsafe { Step::backward_unchecked(self.end.clone(), 1) };
+ mem::replace(&mut self.end, n)
+ } else {
+ self.exhausted = true;
+ self.end.clone()
+ })
+ }
+
+ #[inline]
+ fn spec_try_rfold<B, F, R>(&mut self, init: B, mut f: F) -> R
+ where
+ Self: Sized,
+ F: FnMut(B, T) -> R,
+ R: Try<Output = B>,
+ {
+ if self.is_empty() {
+ return try { init };
+ }
+
+ let mut accum = init;
+
+ while self.start < self.end {
+ // SAFETY: just checked precondition
+ let n = unsafe { Step::backward_unchecked(self.end.clone(), 1) };
+ let n = mem::replace(&mut self.end, n);
+ accum = f(accum, n)?;
+ }
+
+ self.exhausted = true;
+
+ if self.start == self.end {
+ accum = f(accum, self.start.clone())?;
+ }
+
+ try { accum }
+ }
+}
+
+#[stable(feature = "inclusive_range", since = "1.26.0")]
+impl<A: Step> Iterator for ops::RangeInclusive<A> {
+ type Item = A;
+
+ #[inline]
+ fn next(&mut self) -> Option<A> {
+ self.spec_next()
+ }
+
#[inline]
fn size_hint(&self) -> (usize, Option<usize>) {
if self.is_empty() {
}
#[inline]
- fn try_fold<B, F, R>(&mut self, init: B, mut f: F) -> R
+ fn try_fold<B, F, R>(&mut self, init: B, f: F) -> R
where
Self: Sized,
F: FnMut(B, Self::Item) -> R,
R: Try<Output = B>,
{
- if self.is_empty() {
- return try { init };
- }
-
- let mut accum = init;
-
- while self.start < self.end {
- // SAFETY: just checked precondition
- let n = unsafe { Step::forward_unchecked(self.start.clone(), 1) };
- let n = mem::replace(&mut self.start, n);
- accum = f(accum, n)?;
- }
-
- self.exhausted = true;
-
- if self.start == self.end {
- accum = f(accum, self.start.clone())?;
- }
-
- try { accum }
+ self.spec_try_fold(init, f)
}
#[inline]
impl<A: Step> DoubleEndedIterator for ops::RangeInclusive<A> {
#[inline]
fn next_back(&mut self) -> Option<A> {
- if self.is_empty() {
- return None;
- }
- let is_iterating = self.start < self.end;
- Some(if is_iterating {
- // SAFETY: just checked precondition
- let n = unsafe { Step::backward_unchecked(self.end.clone(), 1) };
- mem::replace(&mut self.end, n)
- } else {
- self.exhausted = true;
- self.end.clone()
- })
+ self.spec_next_back()
}
#[inline]
}
#[inline]
- fn try_rfold<B, F, R>(&mut self, init: B, mut f: F) -> R
+ fn try_rfold<B, F, R>(&mut self, init: B, f: F) -> R
where
Self: Sized,
F: FnMut(B, Self::Item) -> R,
R: Try<Output = B>,
{
- if self.is_empty() {
- return try { init };
- }
-
- let mut accum = init;
-
- while self.start < self.end {
- // SAFETY: just checked precondition
- let n = unsafe { Step::backward_unchecked(self.end.clone(), 1) };
- let n = mem::replace(&mut self.end, n);
- accum = f(accum, n)?;
- }
-
- self.exhausted = true;
-
- if self.start == self.end {
- accum = f(accum, self.start.clone())?;
- }
-
- try { accum }
+ self.spec_try_rfold(init, f)
}
#[inline]
}
}
+// Safety: See above implementation for `ops::Range<A>`
#[unstable(feature = "trusted_len", issue = "37572")]
-unsafe impl<A: Step> TrustedLen for ops::RangeInclusive<A> {}
+unsafe impl<A: TrustedStep> TrustedLen for ops::RangeInclusive<A> {}
#[stable(feature = "fused", since = "1.26.0")]
impl<A: Step> FusedIterator for ops::RangeInclusive<A> {}
/// [impl]: crate::iter#implementing-iterator
#[stable(feature = "rust1", since = "1.0.0")]
#[rustc_on_unimplemented(
- on(
- _Self = "[std::ops::Range<Idx>; 1]",
- label = "if you meant to iterate between two values, remove the square brackets",
- note = "`[start..end]` is an array of one `Range`; you might have meant to have a `Range` \
- without the brackets: `start..end`"
- ),
- on(
- _Self = "[std::ops::RangeFrom<Idx>; 1]",
- label = "if you meant to iterate from a value onwards, remove the square brackets",
- note = "`[start..]` is an array of one `RangeFrom`; you might have meant to have a \
- `RangeFrom` without the brackets: `start..`, keeping in mind that iterating over an \
- unbounded iterator will run forever unless you `break` or `return` from within the \
- loop"
- ),
- on(
- _Self = "[std::ops::RangeTo<Idx>; 1]",
- label = "if you meant to iterate until a value, remove the square brackets and add a \
- starting value",
- note = "`[..end]` is an array of one `RangeTo`; you might have meant to have a bounded \
- `Range` without the brackets: `0..end`"
- ),
- on(
- _Self = "[std::ops::RangeInclusive<Idx>; 1]",
- label = "if you meant to iterate between two values, remove the square brackets",
- note = "`[start..=end]` is an array of one `RangeInclusive`; you might have meant to have a \
- `RangeInclusive` without the brackets: `start..=end`"
- ),
- on(
- _Self = "[std::ops::RangeToInclusive<Idx>; 1]",
- label = "if you meant to iterate until a value (including it), remove the square brackets \
- and add a starting value",
- note = "`[..=end]` is an array of one `RangeToInclusive`; you might have meant to have a \
- bounded `RangeInclusive` without the brackets: `0..=end`"
- ),
on(
_Self = "std::ops::RangeTo<Idx>",
label = "if you meant to iterate until a value, add a starting value",
_Self = "std::string::String",
label = "`{Self}` is not an iterator; try calling `.chars()` or `.bytes()`"
),
- on(
- _Self = "[]",
- label = "arrays do not yet implement `IntoIterator`; try using `std::array::IntoIter::new(arr)`",
- note = "see <https://github.com/rust-lang/rust/pull/65819> for more details"
- ),
on(
_Self = "{integral}",
note = "if you want to iterate between `start` until a value `end`, use the exclusive range \
/// A more complex example:
///
/// ```
- /// // The even numbers from zero to ten.
+ /// // The even numbers in the range of zero to nine.
/// let iter = (0..10).filter(|x| x % 2 == 0);
///
/// // We might iterate from zero to ten times. Knowing that it's five
/// assert_eq!(it.len(), 2);
/// assert_eq!(it.next(), Some(&40));
/// ```
+ ///
+ /// While you cannot `break` from a closure, the [`crate::ops::ControlFlow`]
+ /// type allows a similar idea:
+ ///
+ /// ```
+ /// use std::ops::ControlFlow;
+ ///
+ /// let triangular = (1..30).try_fold(0_i8, |prev, x| {
+ /// if let Some(next) = prev.checked_add(x) {
+ /// ControlFlow::Continue(next)
+ /// } else {
+ /// ControlFlow::Break(prev)
+ /// }
+ /// });
+ /// assert_eq!(triangular, ControlFlow::Break(120));
+ ///
+ /// let triangular = (1..30).try_fold(0_u64, |prev, x| {
+ /// if let Some(next) = prev.checked_add(x) {
+ /// ControlFlow::Continue(next)
+ /// } else {
+ /// ControlFlow::Break(prev)
+ /// }
+ /// });
+ /// assert_eq!(triangular, ControlFlow::Continue(435));
+ /// ```
#[inline]
#[stable(feature = "iterator_try_fold", since = "1.27.0")]
fn try_fold<B, F, R>(&mut self, init: B, mut f: F) -> R
/// // It short-circuited, so the remaining items are still in the iterator:
/// assert_eq!(it.next(), Some("stale_bread.json"));
/// ```
+ ///
+ /// The [`crate::ops::ControlFlow`] type can be used with this method for the
+ /// situations in which you'd use `break` and `continue` in a normal loop:
+ ///
+ /// ```
+ /// use std::ops::ControlFlow;
+ ///
+ /// let r = (2..100).try_for_each(|x| {
+ /// if 323 % x == 0 {
+ /// return ControlFlow::Break(x)
+ /// }
+ ///
+ /// ControlFlow::Continue(())
+ /// });
+ /// assert_eq!(r, ControlFlow::Break(17));
+ /// ```
#[inline]
#[stable(feature = "iterator_try_fold", since = "1.27.0")]
fn try_for_each<F, R>(&mut self, f: F) -> R
/// If several elements are equally maximum, the last element is
/// returned. If the iterator is empty, [`None`] is returned.
///
+ /// Note that [`f32`]/[`f64`] doesn't implement [`Ord`] due to NaN being
+ /// incomparable. You can work around this by using [`Iterator::reduce`]:
+ /// ```
+ /// assert_eq!(
+ /// vec![2.4, f32::NAN, 1.3]
+ /// .into_iter()
+ /// .reduce(f32::max)
+ /// .unwrap(),
+ /// 2.4
+ /// );
+ /// ```
+ ///
/// # Examples
///
/// Basic usage:
/// Returns the minimum element of an iterator.
///
- /// If several elements are equally minimum, the first element is
- /// returned. If the iterator is empty, [`None`] is returned.
+ /// If several elements are equally minimum, the first element is returned.
+ /// If the iterator is empty, [`None`] is returned.
+ ///
+ /// Note that [`f32`]/[`f64`] doesn't implement [`Ord`] due to NaN being
+ /// incomparable. You can work around this by using [`Iterator::reduce`]:
+ /// ```
+ /// assert_eq!(
+ /// vec![2.4, f32::NAN, 1.3]
+ /// .into_iter()
+ /// .reduce(f32::min)
+ /// .unwrap(),
+ /// 1.3
+ /// );
+ /// ```
///
/// # Examples
///
+use crate::iter::Step;
+
/// An iterator that always continues to yield `None` when exhausted.
///
/// Calling next on a fused iterator that has returned `None` once is guaranteed
#[unstable(issue = "none", feature = "inplace_iteration")]
#[doc(hidden)]
pub unsafe trait InPlaceIterable: Iterator {}
+
+/// A type that upholds all invariants of [`Step`].
+///
+/// The invariants of [`Step::steps_between()`] are a superset of the invariants
+/// of [`TrustedLen`]. As such, [`TrustedLen`] is implemented for all range
+/// types with the same generic type argument.
+///
+/// # Safety
+///
+/// The implementation of [`Step`] for the given type must guarantee all
+/// invariants of all methods are upheld. See the [`Step`] trait's documentation
+/// for details. Consumers are free to rely on the invariants in unsafe code.
+#[unstable(feature = "trusted_step", issue = "85731")]
+#[rustc_specialization_trait]
+pub unsafe trait TrustedStep: Step {}
pub use self::iterator::Iterator;
#[unstable(issue = "none", feature = "inplace_iteration")]
pub use self::marker::InPlaceIterable;
+#[unstable(feature = "trusted_step", issue = "85731")]
+pub use self::marker::TrustedStep;
#[stable(feature = "rust1", since = "1.0.0")]
pub use self::marker::{FusedIterator, TrustedLen};
#![cfg(not(test))]
#![stable(feature = "core", since = "1.6.0")]
#![doc(
- html_root_url = "https://doc.rust-lang.org/nightly/",
html_playground_url = "https://play.rust-lang.org/",
issue_tracker_base_url = "https://github.com/rust-lang/rust/issues/",
test(no_crate_inject, attr(deny(warnings))),
#![feature(allow_internal_unstable)]
#![feature(arbitrary_self_types)]
#![feature(asm)]
+#![feature(bool_to_option)]
#![feature(cfg_target_has_atomic)]
#![feature(const_heap)]
#![feature(const_alloc_layout)]
#![feature(const_fn_transmute)]
#![feature(abi_unadjusted)]
#![feature(adx_target_feature)]
-#![feature(external_doc)]
#![feature(associated_type_bounds)]
#![feature(const_caller_location)]
#![feature(slice_ptr_get)]
#![feature(no_niche)] // rust-lang/rust#68303
#![feature(no_coverage)] // rust-lang/rust#84605
#![feature(int_error_matching)]
+#![cfg_attr(bootstrap, feature(target_feature_11))]
#![deny(unsafe_op_in_unsafe_fn)]
+#![deny(or_patterns_back_compat)]
// allow using `core::` in intra-doc links
#[allow(unused_extern_crates)]
#[unstable(feature = "assert_matches", issue = "82775")]
#[allow_internal_unstable(core_panic)]
macro_rules! assert_matches {
- ($left:expr, $( $pattern:pat )|+ $( if $guard: expr )? $(,)?) => ({
+ ($left:expr, $( $pattern:pat_param )|+ $( if $guard: expr )? $(,)?) => ({
match $left {
$( $pattern )|+ $( if $guard )? => {}
ref left_val => {
}
}
});
- ($left:expr, $( $pattern:pat )|+ $( if $guard: expr )?, $($arg:tt)+) => ({
+ ($left:expr, $( $pattern:pat_param )|+ $( if $guard: expr )?, $($arg:tt)+) => ({
match $left {
$( $pattern )|+ $( if $guard )? => {}
ref left_val => {
#[macro_export]
#[stable(feature = "matches_macro", since = "1.42.0")]
macro_rules! matches {
- ($expression:expr, $( $pattern:pat )|+ $( if $guard: expr )? $(,)?) => {
+ ($expression:expr, $( $pattern:pat_param )|+ $( if $guard: expr )? $(,)?) => {
match $expression {
$( $pattern )|+ $( if $guard )? => true,
_ => false
/// Indicates unimplemented code by panicking with a message of "not implemented".
///
/// This allows your code to type-check, which is useful if you are prototyping or
-/// implementing a trait that requires multiple methods which you don't plan of using all of.
+/// implementing a trait that requires multiple methods which you don't plan to use all of.
///
/// The difference between `unimplemented!` and [`todo!`] is that while `todo!`
/// conveys an intent of implementing the functionality later and the message is "not yet
/// [`MaybeUninit<T>`]: crate::mem::MaybeUninit
#[stable(feature = "manually_drop", since = "1.20.0")]
#[lang = "manually_drop"]
-#[derive(Copy, Debug, Default, PartialEq, Eq, PartialOrd, Ord, Hash)]
+#[derive(Copy, Clone, Debug, Default, PartialEq, Eq, PartialOrd, Ord, Hash)]
#[repr(transparent)]
pub struct ManuallyDrop<T: ?Sized> {
value: T,
&mut self.value
}
}
-
-#[stable(feature = "manually_drop", since = "1.20.0")]
-impl<T: Clone> Clone for ManuallyDrop<T> {
- #[inline]
- fn clone(&self) -> ManuallyDrop<T> {
- ManuallyDrop { value: self.value.clone() }
- }
-
- #[inline]
- fn clone_from(&mut self, other: &Self) {
- self.value.clone_from(&other.value)
- }
-}
u
}
- /// Sets the value of the `MaybeUninit<T>`. This overwrites any previous value
- /// without dropping it, so be careful not to use this twice unless you want to
- /// skip running the destructor. For your convenience, this also returns a mutable
- /// reference to the (now safely initialized) contents of `self`.
+ /// Sets the value of the `MaybeUninit<T>`.
+ ///
+ /// This overwrites any previous value without dropping it, so be careful
+ /// not to use this twice unless you want to skip running the destructor.
+ /// For your convenience, this also returns a mutable reference to the
+ /// (now safely initialized) contents of `self`.
+ ///
+ /// As the content is stored inside a `MaybeUninit`, the destructor is not
+ /// ran for the inner data if the MaybeUninit leaves scope without a call to
+ /// [`assume_init`], [`assume_init_drop`], or similar. Code that receives
+ /// the mutable reference returned by this function needs to keep this in
+ /// mind. The safety model of Rust regards leaks as safe, but they are
+ /// usually still undesirable. This being said, the mutable reference
+ /// behaves like any other mutable reference would, so assigning a new value
+ /// to it will drop the old content.
+ ///
+ /// [`assume_init`]: Self::assume_init
+ /// [`assume_init_drop`]: Self::assume_init_drop
+ ///
+ /// # Examples
+ ///
+ /// Correct usage of this method:
+ ///
+ /// ```rust
+ /// #![feature(maybe_uninit_extra)]
+ /// use std::mem::MaybeUninit;
+ ///
+ /// let mut x = MaybeUninit::<Vec<u8>>::uninit();
+ ///
+ /// {
+ /// let hello = x.write((&b"Hello, world!").to_vec());
+ /// // Setting hello does not leak prior allocations, but drops them
+ /// *hello = (&b"Hello").to_vec();
+ /// hello[0] = 'h' as u8;
+ /// }
+ /// // x is initialized now:
+ /// let s = unsafe { x.assume_init() };
+ /// assert_eq!(b"hello", s.as_slice());
+ /// ```
+ ///
+ /// This usage of the method causes a leak:
+ ///
+ /// ```rust
+ /// #![feature(maybe_uninit_extra)]
+ /// use std::mem::MaybeUninit;
+ ///
+ /// let mut x = MaybeUninit::<String>::uninit();
+ ///
+ /// x.write("Hello".to_string());
+ /// // This leaks the contained string:
+ /// x.write("hello".to_string());
+ /// // x is initialized now:
+ /// let s = unsafe { x.assume_init() };
+ /// ```
#[unstable(feature = "maybe_uninit_extra", issue = "63567")]
#[rustc_const_unstable(feature = "maybe_uninit_extra", issue = "63567")]
#[inline(always)]
/// behavior. The [type-level documentation][inv] contains more information about
/// this initialization invariant.
///
- /// Moreover, this leaves a copy of the same data behind in the `MaybeUninit<T>`. When using
- /// multiple copies of the data (by calling `assume_init_read` multiple times, or first
- /// calling `assume_init_read` and then [`assume_init`]), it is your responsibility
+ /// Moreover, similar to the [`ptr::read`] function, this function creates a
+ /// bitwise copy of the contents, regardless whether the contained type
+ /// implements the [`Copy`] trait or not. When using multiple copies of the
+ /// data (by calling `assume_init_read` multiple times, or first calling
+ /// `assume_init_read` and then [`assume_init`]), it is your responsibility
/// to ensure that that data may indeed be duplicated.
///
/// [inv]: #initialization-invariant
/// Drops the contained value in place.
///
- /// If you have ownership of the `MaybeUninit`, you can use [`assume_init`] instead.
+ /// If you have ownership of the `MaybeUninit`, you can also use
+ /// [`assume_init`] as an alternative.
///
/// # Safety
///
///
/// On top of that, all additional invariants of the type `T` must be
/// satisfied, as the `Drop` implementation of `T` (or its members) may
- /// rely on this. For example, a `1`-initialized [`Vec<T>`] is considered
- /// initialized (under the current implementation; this does not constitute
- /// a stable guarantee) because the only requirement the compiler knows
- /// about it is that the data pointer must be non-null. Dropping such a
- /// `Vec<T>` however will cause undefined behaviour.
+ /// rely on this. For example, setting a [`Vec<T>`] to an invalid but
+ /// non-null address makes it initialized (under the current implementation;
+ /// this does not constitute a stable guarantee), because the only
+ /// requirement the compiler knows about it is that the data pointer must be
+ /// non-null. Dropping such a `Vec<T>` however will cause undefined
+ /// behaviour.
///
/// [`assume_init`]: MaybeUninit::assume_init
/// [`Vec<T>`]: ../../std/vec/struct.Vec.html
/// ### Correct usage of this method:
///
/// ```rust
- /// #![feature(maybe_uninit_ref)]
/// use std::mem::MaybeUninit;
///
/// let mut x = MaybeUninit::<Vec<u32>>::uninit();
/// ### *Incorrect* usages of this method:
///
/// ```rust,no_run
- /// #![feature(maybe_uninit_ref)]
/// use std::mem::MaybeUninit;
///
/// let x = MaybeUninit::<Vec<u32>>::uninit();
/// ```
///
/// ```rust,no_run
- /// #![feature(maybe_uninit_ref)]
/// use std::{cell::Cell, mem::MaybeUninit};
///
/// let b = MaybeUninit::<Cell<bool>>::uninit();
/// // Reference to an uninitialized `Cell<bool>`: UB!
/// }
/// ```
- #[unstable(feature = "maybe_uninit_ref", issue = "63568")]
+ #[stable(feature = "maybe_uninit_ref", since = "1.55.0")]
#[rustc_const_unstable(feature = "const_maybe_uninit_assume_init", issue = "none")]
#[inline(always)]
pub const unsafe fn assume_init_ref(&self) -> &T {
/// ### Correct usage of this method:
///
/// ```rust
- /// #![feature(maybe_uninit_ref)]
/// use std::mem::MaybeUninit;
///
/// # unsafe extern "C" fn initialize_buffer(buf: *mut [u8; 1024]) { *buf = [0; 1024] }
/// You cannot use `.assume_init_mut()` to initialize a value:
///
/// ```rust,no_run
- /// #![feature(maybe_uninit_ref)]
/// use std::mem::MaybeUninit;
///
/// let mut b = MaybeUninit::<bool>::uninit();
/// [`Read`]: https://doc.rust-lang.org/std/io/trait.Read.html
///
/// ```rust,no_run
- /// #![feature(maybe_uninit_ref)]
/// use std::{io, mem::MaybeUninit};
///
/// fn read_chunk (reader: &'_ mut dyn io::Read) -> io::Result<[u8; 64]>
/// Nor can you use direct field access to do field-by-field gradual initialization:
///
/// ```rust,no_run
- /// #![feature(maybe_uninit_ref)]
/// use std::{mem::MaybeUninit, ptr};
///
/// struct Foo {
/// foo.assume_init()
/// };
/// ```
- // FIXME(#76092): We currently rely on the above being incorrect, i.e., we have references
- // to uninitialized data (e.g., in `libcore/fmt/float.rs`). We should make
- // a final decision about the rules before stabilization.
- #[unstable(feature = "maybe_uninit_ref", issue = "63568")]
+ #[stable(feature = "maybe_uninit_ref", since = "1.55.0")]
#[rustc_const_unstable(feature = "const_maybe_uninit_assume_init", issue = "none")]
#[inline(always)]
pub const unsafe fn assume_init_mut(&mut self) -> &mut T {
/// ```
#[inline]
#[stable(feature = "rust1", since = "1.0.0")]
-#[rustc_const_unstable(feature = "const_swap", issue = "83163")]
-pub const fn swap<T>(x: &mut T, y: &mut T) {
+pub fn swap<T>(x: &mut T, y: &mut T) {
// SAFETY: the raw pointers have been created from safe mutable references satisfying all the
// constraints on `ptr::swap_nonoverlapping_one`
unsafe {
#[inline]
#[stable(feature = "rust1", since = "1.0.0")]
#[must_use = "if you don't need the old value, you can just assign the new value directly"]
-#[rustc_const_unstable(feature = "const_replace", issue = "83164")]
-pub const fn replace<T>(dest: &mut T, src: T) -> T {
+pub fn replace<T>(dest: &mut T, src: T) -> T {
// SAFETY: We read from `dest` but directly write `src` into it afterwards,
// such that the old value is not duplicated. Nothing is dropped and
// nothing here can panic.
///
/// This is currently identical to `transmute::<f32, u32>(self)` on all platforms.
///
- /// See `from_bits` for some discussion of the portability of this operation
- /// (there are almost no issues).
+ /// See [`from_bits`](Self::from_bits) for some discussion of the
+ /// portability of this operation (there are almost no issues).
///
/// Note that this function is distinct from `as` casting, which attempts to
/// preserve the *numeric* value, and not the bitwise value.
self.to_bits().to_ne_bytes()
}
- /// Return the memory representation of this floating point number as a byte array in
- /// native byte order.
- ///
- /// [`to_ne_bytes`] should be preferred over this whenever possible.
- ///
- /// [`to_ne_bytes`]: f32::to_ne_bytes
- ///
- /// # Examples
- ///
- /// ```
- /// #![feature(num_as_ne_bytes)]
- /// let num = 12.5f32;
- /// let bytes = num.as_ne_bytes();
- /// assert_eq!(
- /// bytes,
- /// if cfg!(target_endian = "big") {
- /// &[0x41, 0x48, 0x00, 0x00]
- /// } else {
- /// &[0x00, 0x00, 0x48, 0x41]
- /// }
- /// );
- /// ```
- #[unstable(feature = "num_as_ne_bytes", issue = "76976")]
- #[inline]
- pub fn as_ne_bytes(&self) -> &[u8; 4] {
- // SAFETY: `f32` is a plain old datatype so we can always transmute to it
- unsafe { &*(self as *const Self as *const _) }
- }
-
/// Create a floating point value from its representation as a byte array in big endian.
///
/// # Examples
///
/// This is currently identical to `transmute::<f64, u64>(self)` on all platforms.
///
- /// See `from_bits` for some discussion of the portability of this operation
- /// (there are almost no issues).
+ /// See [`from_bits`](Self::from_bits) for some discussion of the
+ /// portability of this operation (there are almost no issues).
///
/// Note that this function is distinct from `as` casting, which attempts to
/// preserve the *numeric* value, and not the bitwise value.
self.to_bits().to_ne_bytes()
}
- /// Return the memory representation of this floating point number as a byte array in
- /// native byte order.
- ///
- /// [`to_ne_bytes`] should be preferred over this whenever possible.
- ///
- /// [`to_ne_bytes`]: f64::to_ne_bytes
- ///
- /// # Examples
- ///
- /// ```
- /// #![feature(num_as_ne_bytes)]
- /// let num = 12.5f64;
- /// let bytes = num.as_ne_bytes();
- /// assert_eq!(
- /// bytes,
- /// if cfg!(target_endian = "big") {
- /// &[0x40, 0x29, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00]
- /// } else {
- /// &[0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x29, 0x40]
- /// }
- /// );
- /// ```
- #[unstable(feature = "num_as_ne_bytes", issue = "76976")]
- #[inline]
- pub fn as_ne_bytes(&self) -> &[u8; 8] {
- // SAFETY: `f64` is a plain old datatype so we can always transmute to it
- unsafe { &*(self as *const Self as *const _) }
- }
-
/// Create a floating point value from its representation as a byte array in big endian.
///
/// # Examples
}
/// Unchecked integer addition. Computes `self + rhs`, assuming overflow
- /// cannot occur. This results in undefined behavior when
- #[doc = concat!("`self + rhs > ", stringify!($SelfT), "::MAX` or `self + rhs < ", stringify!($SelfT), "::MIN`.")]
+ /// cannot occur.
+ ///
+ /// # Safety
+ ///
+ /// This results in undefined behavior when
+ #[doc = concat!("`self + rhs > ", stringify!($SelfT), "::MAX` or `self + rhs < ", stringify!($SelfT), "::MIN`,")]
+ /// i.e. when [`checked_add`] would return `None`.
+ ///
+ #[doc = concat!("[`checked_add`]: ", stringify!($SelfT), "::checked_add")]
#[unstable(
feature = "unchecked_math",
reason = "niche optimization path",
}
/// Unchecked integer subtraction. Computes `self - rhs`, assuming overflow
- /// cannot occur. This results in undefined behavior when
- #[doc = concat!("`self - rhs > ", stringify!($SelfT), "::MAX` or `self - rhs < ", stringify!($SelfT), "::MIN`.")]
+ /// cannot occur.
+ ///
+ /// # Safety
+ ///
+ /// This results in undefined behavior when
+ #[doc = concat!("`self - rhs > ", stringify!($SelfT), "::MAX` or `self - rhs < ", stringify!($SelfT), "::MIN`,")]
+ /// i.e. when [`checked_sub`] would return `None`.
+ ///
+ #[doc = concat!("[`checked_sub`]: ", stringify!($SelfT), "::checked_sub")]
#[unstable(
feature = "unchecked_math",
reason = "niche optimization path",
}
/// Unchecked integer multiplication. Computes `self * rhs`, assuming overflow
- /// cannot occur. This results in undefined behavior when
- #[doc = concat!("`self * rhs > ", stringify!($SelfT), "::MAX` or `self * rhs < ", stringify!($SelfT), "::MIN`.")]
+ /// cannot occur.
+ ///
+ /// # Safety
+ ///
+ /// This results in undefined behavior when
+ #[doc = concat!("`self * rhs > ", stringify!($SelfT), "::MAX` or `self * rhs < ", stringify!($SelfT), "::MIN`,")]
+ /// i.e. when [`checked_mul`] would return `None`.
+ ///
+ #[doc = concat!("[`checked_mul`]: ", stringify!($SelfT), "::checked_mul")]
#[unstable(
feature = "unchecked_math",
reason = "niche optimization path",
if unlikely!(b) {None} else {Some(a)}
}
+ /// Unchecked shift left. Computes `self << rhs`, assuming that
+ /// `rhs` is less than the number of bits in `self`.
+ ///
+ /// # Safety
+ ///
+ /// This results in undefined behavior if `rhs` is larger than
+ /// or equal to the number of bits in `self`,
+ /// i.e. when [`checked_shl`] would return `None`.
+ ///
+ #[doc = concat!("[`checked_shl`]: ", stringify!($SelfT), "::checked_shl")]
+ #[unstable(
+ feature = "unchecked_math",
+ reason = "niche optimization path",
+ issue = "85122",
+ )]
+ #[must_use = "this returns the result of the operation, \
+ without modifying the original"]
+ #[rustc_const_unstable(feature = "const_inherent_unchecked_arith", issue = "85122")]
+ #[inline(always)]
+ pub const unsafe fn unchecked_shl(self, rhs: Self) -> Self {
+ // SAFETY: the caller must uphold the safety contract for
+ // `unchecked_shl`.
+ unsafe { intrinsics::unchecked_shl(self, rhs) }
+ }
+
/// Checked shift right. Computes `self >> rhs`, returning `None` if `rhs` is
/// larger than or equal to the number of bits in `self`.
///
if unlikely!(b) {None} else {Some(a)}
}
+ /// Unchecked shift right. Computes `self >> rhs`, assuming that
+ /// `rhs` is less than the number of bits in `self`.
+ ///
+ /// # Safety
+ ///
+ /// This results in undefined behavior if `rhs` is larger than
+ /// or equal to the number of bits in `self`,
+ /// i.e. when [`checked_shr`] would return `None`.
+ ///
+ #[doc = concat!("[`checked_shr`]: ", stringify!($SelfT), "::checked_shr")]
+ #[unstable(
+ feature = "unchecked_math",
+ reason = "niche optimization path",
+ issue = "85122",
+ )]
+ #[must_use = "this returns the result of the operation, \
+ without modifying the original"]
+ #[rustc_const_unstable(feature = "const_inherent_unchecked_arith", issue = "85122")]
+ #[inline(always)]
+ pub const unsafe fn unchecked_shr(self, rhs: Self) -> Self {
+ // SAFETY: the caller must uphold the safety contract for
+ // `unchecked_shr`.
+ unsafe { intrinsics::unchecked_shr(self, rhs) }
+ }
+
/// Checked absolute value. Computes `self.abs()`, returning `None` if
/// `self == MIN`.
///
unsafe { mem::transmute(self) }
}
- /// Return the memory representation of this integer as a byte array in
- /// native byte order.
- ///
- /// [`to_ne_bytes`] should be preferred over this whenever possible.
- ///
- /// [`to_ne_bytes`]: Self::to_ne_bytes
- ///
- /// # Examples
- ///
- /// ```
- /// #![feature(num_as_ne_bytes)]
- #[doc = concat!("let num = ", $swap_op, stringify!($SelfT), ";")]
- /// let bytes = num.as_ne_bytes();
- /// assert_eq!(
- /// bytes,
- /// if cfg!(target_endian = "big") {
- #[doc = concat!(" &", $be_bytes)]
- /// } else {
- #[doc = concat!(" &", $le_bytes)]
- /// }
- /// );
- /// ```
- #[unstable(feature = "num_as_ne_bytes", issue = "76976")]
- #[inline]
- pub fn as_ne_bytes(&self) -> &[u8; mem::size_of::<Self>()] {
- // SAFETY: integers are plain old datatypes so we can always transmute them to
- // arrays of bytes
- unsafe { &*(self as *const Self as *const _) }
- }
-
/// Create an integer value from its representation as a byte array in
/// big endian.
///
pub struct $Ty($Int);
impl $Ty {
- /// Creates a non-zero without checking the value.
+ /// Creates a non-zero without checking whether the value is non-zero.
+ /// This results in undefined behaviour if the value is zero.
///
/// # Safety
///
NonZeroUsize(usize);
}
+// A bunch of methods for unsigned nonzero types only.
+macro_rules! nonzero_unsigned_operations {
+ ( $( $Ty: ident($Int: ty); )+ ) => {
+ $(
+ impl $Ty {
+ /// Add an unsigned integer to a non-zero value.
+ /// Check for overflow and return [`None`] on overflow
+ /// As a consequence, the result cannot wrap to zero.
+ ///
+ ///
+ /// # Examples
+ ///
+ /// ```
+ /// #![feature(nonzero_ops)]
+ #[doc = concat!("# use std::num::", stringify!($Ty), ";")]
+ ///
+ /// # fn main() { test().unwrap(); }
+ /// # fn test() -> Option<()> {
+ #[doc = concat!("let one = ", stringify!($Ty), "::new(1)?;")]
+ #[doc = concat!("let two = ", stringify!($Ty), "::new(2)?;")]
+ #[doc = concat!("let max = ", stringify!($Ty), "::new(",
+ stringify!($Int), "::MAX)?;")]
+ ///
+ /// assert_eq!(Some(two), one.checked_add(1));
+ /// assert_eq!(None, max.checked_add(1));
+ /// # Some(())
+ /// # }
+ /// ```
+ #[unstable(feature = "nonzero_ops", issue = "84186")]
+ #[inline]
+ pub const fn checked_add(self, other: $Int) -> Option<$Ty> {
+ if let Some(result) = self.get().checked_add(other) {
+ // SAFETY: $Int::checked_add returns None on overflow
+ // so the result cannot be zero.
+ Some(unsafe { $Ty::new_unchecked(result) })
+ } else {
+ None
+ }
+ }
+
+ /// Add an unsigned integer to a non-zero value.
+ #[doc = concat!("Return [`", stringify!($Int), "::MAX`] on overflow.")]
+ ///
+ /// # Examples
+ ///
+ /// ```
+ /// #![feature(nonzero_ops)]
+ #[doc = concat!("# use std::num::", stringify!($Ty), ";")]
+ ///
+ /// # fn main() { test().unwrap(); }
+ /// # fn test() -> Option<()> {
+ #[doc = concat!("let one = ", stringify!($Ty), "::new(1)?;")]
+ #[doc = concat!("let two = ", stringify!($Ty), "::new(2)?;")]
+ #[doc = concat!("let max = ", stringify!($Ty), "::new(",
+ stringify!($Int), "::MAX)?;")]
+ ///
+ /// assert_eq!(two, one.saturating_add(1));
+ /// assert_eq!(max, max.saturating_add(1));
+ /// # Some(())
+ /// # }
+ /// ```
+ #[unstable(feature = "nonzero_ops", issue = "84186")]
+ #[inline]
+ pub const fn saturating_add(self, other: $Int) -> $Ty {
+ // SAFETY: $Int::saturating_add returns $Int::MAX on overflow
+ // so the result cannot be zero.
+ unsafe { $Ty::new_unchecked(self.get().saturating_add(other)) }
+ }
+
+ /// Add an unsigned integer to a non-zero value,
+ /// assuming overflow cannot occur.
+ /// Overflow is unchecked, and it is undefined behaviour to overflow
+ /// *even if the result would wrap to a non-zero value*.
+ /// The behaviour is undefined as soon as
+ #[doc = concat!("`self + rhs > ", stringify!($Int), "::MAX`.")]
+ ///
+ /// # Examples
+ ///
+ /// ```
+ /// #![feature(nonzero_ops)]
+ #[doc = concat!("# use std::num::", stringify!($Ty), ";")]
+ ///
+ /// # fn main() { test().unwrap(); }
+ /// # fn test() -> Option<()> {
+ #[doc = concat!("let one = ", stringify!($Ty), "::new(1)?;")]
+ #[doc = concat!("let two = ", stringify!($Ty), "::new(2)?;")]
+ ///
+ /// assert_eq!(two, unsafe { one.unchecked_add(1) });
+ /// # Some(())
+ /// # }
+ /// ```
+ #[unstable(feature = "nonzero_ops", issue = "84186")]
+ #[inline]
+ pub unsafe fn unchecked_add(self, other: $Int) -> $Ty {
+ // SAFETY: The caller ensures there is no overflow.
+ unsafe { $Ty::new_unchecked(self.get().unchecked_add(other)) }
+ }
+
+ /// Returns the smallest power of two greater than or equal to n.
+ /// Check for overflow and return [`None`]
+ /// if the next power of two is greater than the type’s maximum value.
+ /// As a consequence, the result cannot wrap to zero.
+ ///
+ /// # Examples
+ ///
+ /// ```
+ /// #![feature(nonzero_ops)]
+ #[doc = concat!("# use std::num::", stringify!($Ty), ";")]
+ ///
+ /// # fn main() { test().unwrap(); }
+ /// # fn test() -> Option<()> {
+ #[doc = concat!("let two = ", stringify!($Ty), "::new(2)?;")]
+ #[doc = concat!("let three = ", stringify!($Ty), "::new(3)?;")]
+ #[doc = concat!("let four = ", stringify!($Ty), "::new(4)?;")]
+ #[doc = concat!("let max = ", stringify!($Ty), "::new(",
+ stringify!($Int), "::MAX)?;")]
+ ///
+ /// assert_eq!(Some(two), two.checked_next_power_of_two() );
+ /// assert_eq!(Some(four), three.checked_next_power_of_two() );
+ /// assert_eq!(None, max.checked_next_power_of_two() );
+ /// # Some(())
+ /// # }
+ /// ```
+ #[unstable(feature = "nonzero_ops", issue = "84186")]
+ #[inline]
+ pub const fn checked_next_power_of_two(self) -> Option<$Ty> {
+ if let Some(nz) = self.get().checked_next_power_of_two() {
+ // SAFETY: The next power of two is positive
+ // and overflow is checked.
+ Some(unsafe { $Ty::new_unchecked(nz) })
+ } else {
+ None
+ }
+ }
+ }
+ )+
+ }
+}
+
+nonzero_unsigned_operations! {
+ NonZeroU8(u8);
+ NonZeroU16(u16);
+ NonZeroU32(u32);
+ NonZeroU64(u64);
+ NonZeroU128(u128);
+ NonZeroUsize(usize);
+}
+
+// A bunch of methods for signed nonzero types only.
+macro_rules! nonzero_signed_operations {
+ ( $( $Ty: ident($Int: ty) -> $Uty: ident($Uint: ty); )+ ) => {
+ $(
+ impl $Ty {
+ /// Computes the absolute value of self.
+ #[doc = concat!("See [`", stringify!($Int), "::abs`]")]
+ /// for documentation on overflow behaviour.
+ ///
+ /// # Example
+ ///
+ /// ```
+ /// #![feature(nonzero_ops)]
+ #[doc = concat!("# use std::num::", stringify!($Ty), ";")]
+ ///
+ /// # fn main() { test().unwrap(); }
+ /// # fn test() -> Option<()> {
+ #[doc = concat!("let pos = ", stringify!($Ty), "::new(1)?;")]
+ #[doc = concat!("let neg = ", stringify!($Ty), "::new(-1)?;")]
+ ///
+ /// assert_eq!(pos, pos.abs());
+ /// assert_eq!(pos, neg.abs());
+ /// # Some(())
+ /// # }
+ /// ```
+ #[unstable(feature = "nonzero_ops", issue = "84186")]
+ #[inline]
+ pub const fn abs(self) -> $Ty {
+ // SAFETY: This cannot overflow to zero.
+ unsafe { $Ty::new_unchecked(self.get().abs()) }
+ }
+
+ /// Checked absolute value.
+ /// Check for overflow and returns [`None`] if
+ #[doc = concat!("`self == ", stringify!($Int), "::MIN`.")]
+ /// The result cannot be zero.
+ ///
+ /// # Example
+ ///
+ /// ```
+ /// #![feature(nonzero_ops)]
+ #[doc = concat!("# use std::num::", stringify!($Ty), ";")]
+ ///
+ /// # fn main() { test().unwrap(); }
+ /// # fn test() -> Option<()> {
+ #[doc = concat!("let pos = ", stringify!($Ty), "::new(1)?;")]
+ #[doc = concat!("let neg = ", stringify!($Ty), "::new(-1)?;")]
+ #[doc = concat!("let min = ", stringify!($Ty), "::new(",
+ stringify!($Int), "::MIN)?;")]
+ ///
+ /// assert_eq!(Some(pos), neg.checked_abs());
+ /// assert_eq!(None, min.checked_abs());
+ /// # Some(())
+ /// # }
+ /// ```
+ #[unstable(feature = "nonzero_ops", issue = "84186")]
+ #[inline]
+ pub const fn checked_abs(self) -> Option<$Ty> {
+ if let Some(nz) = self.get().checked_abs() {
+ // SAFETY: absolute value of nonzero cannot yield zero values.
+ Some(unsafe { $Ty::new_unchecked(nz) })
+ } else {
+ None
+ }
+ }
+
+ /// Computes the absolute value of self,
+ /// with overflow information, see
+ #[doc = concat!("[`", stringify!($Int), "::overflowing_abs`].")]
+ ///
+ /// # Example
+ ///
+ /// ```
+ /// #![feature(nonzero_ops)]
+ #[doc = concat!("# use std::num::", stringify!($Ty), ";")]
+ ///
+ /// # fn main() { test().unwrap(); }
+ /// # fn test() -> Option<()> {
+ #[doc = concat!("let pos = ", stringify!($Ty), "::new(1)?;")]
+ #[doc = concat!("let neg = ", stringify!($Ty), "::new(-1)?;")]
+ #[doc = concat!("let min = ", stringify!($Ty), "::new(",
+ stringify!($Int), "::MIN)?;")]
+ ///
+ /// assert_eq!((pos, false), pos.overflowing_abs());
+ /// assert_eq!((pos, false), neg.overflowing_abs());
+ /// assert_eq!((min, true), min.overflowing_abs());
+ /// # Some(())
+ /// # }
+ /// ```
+ #[unstable(feature = "nonzero_ops", issue = "84186")]
+ #[inline]
+ pub const fn overflowing_abs(self) -> ($Ty, bool) {
+ let (nz, flag) = self.get().overflowing_abs();
+ (
+ // SAFETY: absolute value of nonzero cannot yield zero values.
+ unsafe { $Ty::new_unchecked(nz) },
+ flag,
+ )
+ }
+
+ /// Saturating absolute value, see
+ #[doc = concat!("[`", stringify!($Int), "::saturating_abs`].")]
+ ///
+ /// # Example
+ ///
+ /// ```
+ /// #![feature(nonzero_ops)]
+ #[doc = concat!("# use std::num::", stringify!($Ty), ";")]
+ ///
+ /// # fn main() { test().unwrap(); }
+ /// # fn test() -> Option<()> {
+ #[doc = concat!("let pos = ", stringify!($Ty), "::new(1)?;")]
+ #[doc = concat!("let neg = ", stringify!($Ty), "::new(-1)?;")]
+ #[doc = concat!("let min = ", stringify!($Ty), "::new(",
+ stringify!($Int), "::MIN)?;")]
+ #[doc = concat!("let min_plus = ", stringify!($Ty), "::new(",
+ stringify!($Int), "::MIN + 1)?;")]
+ #[doc = concat!("let max = ", stringify!($Ty), "::new(",
+ stringify!($Int), "::MAX)?;")]
+ ///
+ /// assert_eq!(pos, pos.saturating_abs());
+ /// assert_eq!(pos, neg.saturating_abs());
+ /// assert_eq!(max, min.saturating_abs());
+ /// assert_eq!(max, min_plus.saturating_abs());
+ /// # Some(())
+ /// # }
+ /// ```
+ #[unstable(feature = "nonzero_ops", issue = "84186")]
+ #[inline]
+ pub const fn saturating_abs(self) -> $Ty {
+ // SAFETY: absolute value of nonzero cannot yield zero values.
+ unsafe { $Ty::new_unchecked(self.get().saturating_abs()) }
+ }
+
+ /// Wrapping absolute value, see
+ #[doc = concat!("[`", stringify!($Int), "::wrapping_abs`].")]
+ ///
+ /// # Example
+ ///
+ /// ```
+ /// #![feature(nonzero_ops)]
+ #[doc = concat!("# use std::num::", stringify!($Ty), ";")]
+ ///
+ /// # fn main() { test().unwrap(); }
+ /// # fn test() -> Option<()> {
+ #[doc = concat!("let pos = ", stringify!($Ty), "::new(1)?;")]
+ #[doc = concat!("let neg = ", stringify!($Ty), "::new(-1)?;")]
+ #[doc = concat!("let min = ", stringify!($Ty), "::new(",
+ stringify!($Int), "::MIN)?;")]
+ #[doc = concat!("let max = ", stringify!($Ty), "::new(",
+ stringify!($Int), "::MAX)?;")]
+ ///
+ /// assert_eq!(pos, pos.wrapping_abs());
+ /// assert_eq!(pos, neg.wrapping_abs());
+ /// assert_eq!(min, min.wrapping_abs());
+ /// # // FIXME: add once Neg is implemented?
+ /// # // assert_eq!(max, (-max).wrapping_abs());
+ /// # Some(())
+ /// # }
+ /// ```
+ #[unstable(feature = "nonzero_ops", issue = "84186")]
+ #[inline]
+ pub const fn wrapping_abs(self) -> $Ty {
+ // SAFETY: absolute value of nonzero cannot yield zero values.
+ unsafe { $Ty::new_unchecked(self.get().wrapping_abs()) }
+ }
+
+ /// Computes the absolute value of self
+ /// without any wrapping or panicking.
+ ///
+ /// # Example
+ ///
+ /// ```
+ /// #![feature(nonzero_ops)]
+ #[doc = concat!("# use std::num::", stringify!($Ty), ";")]
+ #[doc = concat!("# use std::num::", stringify!($Uty), ";")]
+ ///
+ /// # fn main() { test().unwrap(); }
+ /// # fn test() -> Option<()> {
+ #[doc = concat!("let u_pos = ", stringify!($Uty), "::new(1)?;")]
+ #[doc = concat!("let i_pos = ", stringify!($Ty), "::new(1)?;")]
+ #[doc = concat!("let i_neg = ", stringify!($Ty), "::new(-1)?;")]
+ #[doc = concat!("let i_min = ", stringify!($Ty), "::new(",
+ stringify!($Int), "::MIN)?;")]
+ #[doc = concat!("let u_max = ", stringify!($Uty), "::new(",
+ stringify!($Uint), "::MAX / 2 + 1)?;")]
+ ///
+ /// assert_eq!(u_pos, i_pos.unsigned_abs());
+ /// assert_eq!(u_pos, i_neg.unsigned_abs());
+ /// assert_eq!(u_max, i_min.unsigned_abs());
+ /// # Some(())
+ /// # }
+ /// ```
+ #[unstable(feature = "nonzero_ops", issue = "84186")]
+ #[inline]
+ pub const fn unsigned_abs(self) -> $Uty {
+ // SAFETY: absolute value of nonzero cannot yield zero values.
+ unsafe { $Uty::new_unchecked(self.get().unsigned_abs()) }
+ }
+ }
+ )+
+ }
+}
+
+nonzero_signed_operations! {
+ NonZeroI8(i8) -> NonZeroU8(u8);
+ NonZeroI16(i16) -> NonZeroU16(u16);
+ NonZeroI32(i32) -> NonZeroU32(u32);
+ NonZeroI64(i64) -> NonZeroU64(u64);
+ NonZeroI128(i128) -> NonZeroU128(u128);
+ NonZeroIsize(isize) -> NonZeroUsize(usize);
+}
+
+// A bunch of methods for both signed and unsigned nonzero types.
+macro_rules! nonzero_unsigned_signed_operations {
+ ( $( $signedness:ident $Ty: ident($Int: ty); )+ ) => {
+ $(
+ impl $Ty {
+ /// Multiply two non-zero integers together.
+ /// Check for overflow and return [`None`] on overflow.
+ /// As a consequence, the result cannot wrap to zero.
+ ///
+ /// # Examples
+ ///
+ /// ```
+ /// #![feature(nonzero_ops)]
+ #[doc = concat!("# use std::num::", stringify!($Ty), ";")]
+ ///
+ /// # fn main() { test().unwrap(); }
+ /// # fn test() -> Option<()> {
+ #[doc = concat!("let two = ", stringify!($Ty), "::new(2)?;")]
+ #[doc = concat!("let four = ", stringify!($Ty), "::new(4)?;")]
+ #[doc = concat!("let max = ", stringify!($Ty), "::new(",
+ stringify!($Int), "::MAX)?;")]
+ ///
+ /// assert_eq!(Some(four), two.checked_mul(two));
+ /// assert_eq!(None, max.checked_mul(two));
+ /// # Some(())
+ /// # }
+ /// ```
+ #[unstable(feature = "nonzero_ops", issue = "84186")]
+ #[inline]
+ pub const fn checked_mul(self, other: $Ty) -> Option<$Ty> {
+ if let Some(result) = self.get().checked_mul(other.get()) {
+ // SAFETY: checked_mul returns None on overflow
+ // and `other` is also non-null
+ // so the result cannot be zero.
+ Some(unsafe { $Ty::new_unchecked(result) })
+ } else {
+ None
+ }
+ }
+
+ /// Multiply two non-zero integers together.
+ #[doc = concat!("Return [`", stringify!($Int), "::MAX`] on overflow.")]
+ ///
+ /// # Examples
+ ///
+ /// ```
+ /// #![feature(nonzero_ops)]
+ #[doc = concat!("# use std::num::", stringify!($Ty), ";")]
+ ///
+ /// # fn main() { test().unwrap(); }
+ /// # fn test() -> Option<()> {
+ #[doc = concat!("let two = ", stringify!($Ty), "::new(2)?;")]
+ #[doc = concat!("let four = ", stringify!($Ty), "::new(4)?;")]
+ #[doc = concat!("let max = ", stringify!($Ty), "::new(",
+ stringify!($Int), "::MAX)?;")]
+ ///
+ /// assert_eq!(four, two.saturating_mul(two));
+ /// assert_eq!(max, four.saturating_mul(max));
+ /// # Some(())
+ /// # }
+ /// ```
+ #[unstable(feature = "nonzero_ops", issue = "84186")]
+ #[inline]
+ pub const fn saturating_mul(self, other: $Ty) -> $Ty {
+ // SAFETY: saturating_mul returns u*::MAX on overflow
+ // and `other` is also non-null
+ // so the result cannot be zero.
+ unsafe { $Ty::new_unchecked(self.get().saturating_mul(other.get())) }
+ }
+
+ /// Multiply two non-zero integers together,
+ /// assuming overflow cannot occur.
+ /// Overflow is unchecked, and it is undefined behaviour to overflow
+ /// *even if the result would wrap to a non-zero value*.
+ /// The behaviour is undefined as soon as
+ #[doc = sign_dependent_expr!{
+ $signedness ?
+ if signed {
+ concat!("`self * rhs > ", stringify!($Int), "::MAX`, ",
+ "or `self * rhs < ", stringify!($Int), "::MIN`.")
+ }
+ if unsigned {
+ concat!("`self * rhs > ", stringify!($Int), "::MAX`.")
+ }
+ }]
+ ///
+ /// # Examples
+ ///
+ /// ```
+ /// #![feature(nonzero_ops)]
+ #[doc = concat!("# use std::num::", stringify!($Ty), ";")]
+ ///
+ /// # fn main() { test().unwrap(); }
+ /// # fn test() -> Option<()> {
+ #[doc = concat!("let two = ", stringify!($Ty), "::new(2)?;")]
+ #[doc = concat!("let four = ", stringify!($Ty), "::new(4)?;")]
+ ///
+ /// assert_eq!(four, unsafe { two.unchecked_mul(two) });
+ /// # Some(())
+ /// # }
+ /// ```
+ #[unstable(feature = "nonzero_ops", issue = "84186")]
+ #[inline]
+ pub unsafe fn unchecked_mul(self, other: $Ty) -> $Ty {
+ // SAFETY: The caller ensures there is no overflow.
+ unsafe { $Ty::new_unchecked(self.get().unchecked_mul(other.get())) }
+ }
+
+ /// Raise non-zero value to an integer power.
+ /// Check for overflow and return [`None`] on overflow.
+ /// As a consequence, the result cannot wrap to zero.
+ ///
+ /// # Examples
+ ///
+ /// ```
+ /// #![feature(nonzero_ops)]
+ #[doc = concat!("# use std::num::", stringify!($Ty), ";")]
+ ///
+ /// # fn main() { test().unwrap(); }
+ /// # fn test() -> Option<()> {
+ #[doc = concat!("let three = ", stringify!($Ty), "::new(3)?;")]
+ #[doc = concat!("let twenty_seven = ", stringify!($Ty), "::new(27)?;")]
+ #[doc = concat!("let half_max = ", stringify!($Ty), "::new(",
+ stringify!($Int), "::MAX / 2)?;")]
+ ///
+ /// assert_eq!(Some(twenty_seven), three.checked_pow(3));
+ /// assert_eq!(None, half_max.checked_pow(3));
+ /// # Some(())
+ /// # }
+ /// ```
+ #[unstable(feature = "nonzero_ops", issue = "84186")]
+ #[inline]
+ pub const fn checked_pow(self, other: u32) -> Option<$Ty> {
+ if let Some(result) = self.get().checked_pow(other) {
+ // SAFETY: checked_pow returns None on overflow
+ // so the result cannot be zero.
+ Some(unsafe { $Ty::new_unchecked(result) })
+ } else {
+ None
+ }
+ }
+
+ /// Raise non-zero value to an integer power.
+ #[doc = sign_dependent_expr!{
+ $signedness ?
+ if signed {
+ concat!("Return [`", stringify!($Int), "::MIN`] ",
+ "or [`", stringify!($Int), "::MAX`] on overflow.")
+ }
+ if unsigned {
+ concat!("Return [`", stringify!($Int), "::MAX`] on overflow.")
+ }
+ }]
+ ///
+ /// # Examples
+ ///
+ /// ```
+ /// #![feature(nonzero_ops)]
+ #[doc = concat!("# use std::num::", stringify!($Ty), ";")]
+ ///
+ /// # fn main() { test().unwrap(); }
+ /// # fn test() -> Option<()> {
+ #[doc = concat!("let three = ", stringify!($Ty), "::new(3)?;")]
+ #[doc = concat!("let twenty_seven = ", stringify!($Ty), "::new(27)?;")]
+ #[doc = concat!("let max = ", stringify!($Ty), "::new(",
+ stringify!($Int), "::MAX)?;")]
+ ///
+ /// assert_eq!(twenty_seven, three.saturating_pow(3));
+ /// assert_eq!(max, max.saturating_pow(3));
+ /// # Some(())
+ /// # }
+ /// ```
+ #[unstable(feature = "nonzero_ops", issue = "84186")]
+ #[inline]
+ pub const fn saturating_pow(self, other: u32) -> $Ty {
+ // SAFETY: saturating_pow returns u*::MAX on overflow
+ // so the result cannot be zero.
+ unsafe { $Ty::new_unchecked(self.get().saturating_pow(other)) }
+ }
+ }
+ )+
+ }
+}
+
+// Use this when the generated code should differ between signed and unsigned types.
+macro_rules! sign_dependent_expr {
+ (signed ? if signed { $signed_case:expr } if unsigned { $unsigned_case:expr } ) => {
+ $signed_case
+ };
+ (unsigned ? if signed { $signed_case:expr } if unsigned { $unsigned_case:expr } ) => {
+ $unsigned_case
+ };
+}
+
+nonzero_unsigned_signed_operations! {
+ unsigned NonZeroU8(u8);
+ unsigned NonZeroU16(u16);
+ unsigned NonZeroU32(u32);
+ unsigned NonZeroU64(u64);
+ unsigned NonZeroU128(u128);
+ unsigned NonZeroUsize(usize);
+ signed NonZeroI8(i8);
+ signed NonZeroI16(i16);
+ signed NonZeroI32(i32);
+ signed NonZeroI64(i64);
+ signed NonZeroI128(i128);
+ signed NonZeroIsize(isize);
+}
+
macro_rules! nonzero_unsigned_is_power_of_two {
( $( $Ty: ident )+ ) => {
$(
}
/// Unchecked integer addition. Computes `self + rhs`, assuming overflow
- /// cannot occur. This results in undefined behavior when
- #[doc = concat!("`self + rhs > ", stringify!($SelfT), "::MAX` or `self + rhs < ", stringify!($SelfT), "::MIN`.")]
+ /// cannot occur.
+ ///
+ /// # Safety
+ ///
+ /// This results in undefined behavior when
+ #[doc = concat!("`self + rhs > ", stringify!($SelfT), "::MAX` or `self + rhs < ", stringify!($SelfT), "::MIN`,")]
+ /// i.e. when [`checked_add`] would return `None`.
+ ///
+ #[doc = concat!("[`checked_add`]: ", stringify!($SelfT), "::checked_add")]
#[unstable(
feature = "unchecked_math",
reason = "niche optimization path",
}
/// Unchecked integer subtraction. Computes `self - rhs`, assuming overflow
- /// cannot occur. This results in undefined behavior when
- #[doc = concat!("`self - rhs > ", stringify!($SelfT), "::MAX` or `self - rhs < ", stringify!($SelfT), "::MIN`.")]
+ /// cannot occur.
+ ///
+ /// # Safety
+ ///
+ /// This results in undefined behavior when
+ #[doc = concat!("`self - rhs > ", stringify!($SelfT), "::MAX` or `self - rhs < ", stringify!($SelfT), "::MIN`,")]
+ /// i.e. when [`checked_sub`] would return `None`.
+ ///
+ #[doc = concat!("[`checked_sub`]: ", stringify!($SelfT), "::checked_sub")]
#[unstable(
feature = "unchecked_math",
reason = "niche optimization path",
}
/// Unchecked integer multiplication. Computes `self * rhs`, assuming overflow
- /// cannot occur. This results in undefined behavior when
- #[doc = concat!("`self * rhs > ", stringify!($SelfT), "::MAX` or `self * rhs < ", stringify!($SelfT), "::MIN`.")]
+ /// cannot occur.
+ ///
+ /// # Safety
+ ///
+ /// This results in undefined behavior when
+ #[doc = concat!("`self * rhs > ", stringify!($SelfT), "::MAX` or `self * rhs < ", stringify!($SelfT), "::MIN`,")]
+ /// i.e. when [`checked_mul`] would return `None`.
+ ///
+ #[doc = concat!("[`checked_mul`]: ", stringify!($SelfT), "::checked_mul")]
#[unstable(
feature = "unchecked_math",
reason = "niche optimization path",
if unlikely!(b) {None} else {Some(a)}
}
+ /// Unchecked shift left. Computes `self << rhs`, assuming that
+ /// `rhs` is less than the number of bits in `self`.
+ ///
+ /// # Safety
+ ///
+ /// This results in undefined behavior if `rhs` is larger than
+ /// or equal to the number of bits in `self`,
+ /// i.e. when [`checked_shl`] would return `None`.
+ ///
+ #[doc = concat!("[`checked_shl`]: ", stringify!($SelfT), "::checked_shl")]
+ #[unstable(
+ feature = "unchecked_math",
+ reason = "niche optimization path",
+ issue = "85122",
+ )]
+ #[must_use = "this returns the result of the operation, \
+ without modifying the original"]
+ #[rustc_const_unstable(feature = "const_inherent_unchecked_arith", issue = "85122")]
+ #[inline(always)]
+ pub const unsafe fn unchecked_shl(self, rhs: Self) -> Self {
+ // SAFETY: the caller must uphold the safety contract for
+ // `unchecked_shl`.
+ unsafe { intrinsics::unchecked_shl(self, rhs) }
+ }
+
/// Checked shift right. Computes `self >> rhs`, returning `None`
/// if `rhs` is larger than or equal to the number of bits in `self`.
///
if unlikely!(b) {None} else {Some(a)}
}
+ /// Unchecked shift right. Computes `self >> rhs`, assuming that
+ /// `rhs` is less than the number of bits in `self`.
+ ///
+ /// # Safety
+ ///
+ /// This results in undefined behavior if `rhs` is larger than
+ /// or equal to the number of bits in `self`,
+ /// i.e. when [`checked_shr`] would return `None`.
+ ///
+ #[doc = concat!("[`checked_shr`]: ", stringify!($SelfT), "::checked_shr")]
+ #[unstable(
+ feature = "unchecked_math",
+ reason = "niche optimization path",
+ issue = "85122",
+ )]
+ #[must_use = "this returns the result of the operation, \
+ without modifying the original"]
+ #[rustc_const_unstable(feature = "const_inherent_unchecked_arith", issue = "85122")]
+ #[inline(always)]
+ pub const unsafe fn unchecked_shr(self, rhs: Self) -> Self {
+ // SAFETY: the caller must uphold the safety contract for
+ // `unchecked_shr`.
+ unsafe { intrinsics::unchecked_shr(self, rhs) }
+ }
+
/// Checked exponentiation. Computes `self.pow(exp)`, returning `None` if
/// overflow occurred.
///
unsafe { mem::transmute(self) }
}
- /// Return the memory representation of this integer as a byte array in
- /// native byte order.
- ///
- /// [`to_ne_bytes`] should be preferred over this whenever possible.
- ///
- /// [`to_ne_bytes`]: Self::to_ne_bytes
- ///
- /// # Examples
- ///
- /// ```
- /// #![feature(num_as_ne_bytes)]
- #[doc = concat!("let num = ", $swap_op, stringify!($SelfT), ";")]
- /// let bytes = num.as_ne_bytes();
- /// assert_eq!(
- /// bytes,
- /// if cfg!(target_endian = "big") {
- #[doc = concat!(" &", $be_bytes)]
- /// } else {
- #[doc = concat!(" &", $le_bytes)]
- /// }
- /// );
- /// ```
- #[unstable(feature = "num_as_ne_bytes", issue = "76976")]
- #[inline]
- pub fn as_ne_bytes(&self) -> &[u8; mem::size_of::<Self>()] {
- // SAFETY: integers are plain old datatypes so we can always transmute them to
- // arrays of bytes
- unsafe { &*(self as *const Self as *const _) }
- }
-
/// Create a native endian integer value from its representation
/// as a byte array in big endian.
///
///
/// Early-exiting from [`Iterator::try_for_each`]:
/// ```
-/// #![feature(control_flow_enum)]
/// use std::ops::ControlFlow;
///
/// let r = (2..100).try_for_each(|x| {
///
/// A basic tree traversal:
/// ```no_run
-/// #![feature(control_flow_enum)]
/// use std::ops::ControlFlow;
///
/// pub struct TreeNode<T> {
/// }
/// }
/// ```
-#[unstable(feature = "control_flow_enum", reason = "new API", issue = "75744")]
+#[stable(feature = "control_flow_enum_type", since = "1.55.0")]
#[derive(Debug, Clone, Copy, PartialEq)]
pub enum ControlFlow<B, C = ()> {
/// Move on to the next phase of the operation as normal.
+ #[stable(feature = "control_flow_enum_type", since = "1.55.0")]
#[cfg_attr(not(bootstrap), lang = "Continue")]
Continue(C),
/// Exit the operation without running subsequent phases.
+ #[stable(feature = "control_flow_enum_type", since = "1.55.0")]
#[cfg_attr(not(bootstrap), lang = "Break")]
Break(B),
// Yes, the order of the variants doesn't match the type parameters.
#[cfg(bootstrap)]
impl<R: ops::TryV1> ControlFlow<R, R::Output> {
/// Create a `ControlFlow` from any type implementing `Try`.
- #[unstable(feature = "control_flow_enum", reason = "new API", issue = "75744")]
#[inline]
- pub fn from_try(r: R) -> Self {
+ pub(crate) fn from_try(r: R) -> Self {
match R::into_result(r) {
Ok(v) => ControlFlow::Continue(v),
Err(v) => ControlFlow::Break(R::from_error(v)),
}
/// Convert a `ControlFlow` into any type implementing `Try`;
- #[unstable(feature = "control_flow_enum", reason = "new API", issue = "75744")]
#[inline]
- pub fn into_try(self) -> R {
+ pub(crate) fn into_try(self) -> R {
match self {
ControlFlow::Continue(v) => R::from_ok(v),
ControlFlow::Break(v) => v,
}
}
+/// These are used only as part of implementing the iterator adapters.
+/// They have mediocre names and non-obvious semantics, so aren't
+/// currently on a path to potential stabilization.
#[cfg(not(bootstrap))]
impl<R: ops::TryV2> ControlFlow<R, R::Output> {
/// Create a `ControlFlow` from any type implementing `Try`.
- #[unstable(feature = "control_flow_enum", reason = "new API", issue = "75744")]
#[inline]
- pub fn from_try(r: R) -> Self {
+ pub(crate) fn from_try(r: R) -> Self {
match R::branch(r) {
ControlFlow::Continue(v) => ControlFlow::Continue(v),
ControlFlow::Break(v) => ControlFlow::Break(R::from_residual(v)),
}
/// Convert a `ControlFlow` into any type implementing `Try`;
- #[unstable(feature = "control_flow_enum", reason = "new API", issue = "75744")]
#[inline]
- pub fn into_try(self) -> R {
+ pub(crate) fn into_try(self) -> R {
match self {
ControlFlow::Continue(v) => R::from_output(v),
ControlFlow::Break(v) => v,
Unbounded,
}
-#[unstable(feature = "bound_as_ref", issue = "80996")]
impl<T> Bound<T> {
/// Converts from `&Bound<T>` to `Bound<&T>`.
#[inline]
+ #[unstable(feature = "bound_as_ref", issue = "80996")]
pub fn as_ref(&self) -> Bound<&T> {
match *self {
Included(ref x) => Included(x),
}
}
- /// Converts from `&mut Bound<T>` to `Bound<&T>`.
+ /// Converts from `&mut Bound<T>` to `Bound<&mut T>`.
#[inline]
+ #[unstable(feature = "bound_as_ref", issue = "80996")]
pub fn as_mut(&mut self) -> Bound<&mut T> {
match *self {
Included(ref mut x) => Included(x),
Unbounded => Unbounded,
}
}
+
+ /// Maps a `Bound<T>` to a `Bound<U>` by applying a function to the contained value (including
+ /// both `Included` and `Excluded`), returning a `Bound` of the same kind.
+ ///
+ /// # Examples
+ ///
+ /// ```
+ /// #![feature(bound_map)]
+ /// use std::ops::Bound::*;
+ ///
+ /// let bound_string = Included("Hello, World!");
+ ///
+ /// assert_eq!(bound_string.map(|s| s.len()), Included(13));
+ /// ```
+ ///
+ /// ```
+ /// #![feature(bound_map)]
+ /// use std::ops::Bound;
+ /// use Bound::*;
+ ///
+ /// let unbounded_string: Bound<String> = Unbounded;
+ ///
+ /// assert_eq!(unbounded_string.map(|s| s.len()), Unbounded);
+ /// ```
+ #[inline]
+ #[unstable(feature = "bound_map", issue = "86026")]
+ pub fn map<U, F: FnOnce(T) -> U>(self, f: F) -> Bound<U> {
+ match self {
+ Unbounded => Unbounded,
+ Included(x) => Included(f(x)),
+ Excluded(x) => Excluded(f(x)),
+ }
+ }
}
impl<T: Clone> Bound<&T> {
/// into the return type using [`Try::from_output`]:
/// ```
/// # #![feature(try_trait_v2)]
-/// # #![feature(control_flow_enum)]
/// # use std::ops::{ControlFlow, Try};
/// fn simple_try_fold_2<A, T, R: Try<Output = A>>(
/// iter: impl Iterator<Item = T>,
/// recreated from their corresponding residual, so we'll just call it:
/// ```
/// # #![feature(try_trait_v2)]
-/// # #![feature(control_flow_enum)]
/// # use std::ops::{ControlFlow, Try};
/// pub fn simple_try_fold_3<A, T, R: Try<Output = A>>(
/// iter: impl Iterator<Item = T>,
///
/// ```
/// #![feature(try_trait_v2)]
- /// #![feature(control_flow_enum)]
/// use std::ops::Try;
///
/// assert_eq!(<Result<_, String> as Try>::from_output(3), Ok(3));
///
/// ```
/// #![feature(try_trait_v2)]
- /// #![feature(control_flow_enum)]
/// use std::ops::{ControlFlow, Try};
///
/// assert_eq!(Ok::<_, String>(3).branch(), ControlFlow::Continue(3));
///
/// ```
/// #![feature(try_trait_v2)]
- /// #![feature(control_flow_enum)]
/// use std::ops::{ControlFlow, FromResidual};
///
/// assert_eq!(Result::<String, i64>::from_residual(Err(3_u8)), Err(3));
//! the optional owned box, [`Option`]`<`[`Box<T>`]`>`.
//!
//! The following example uses [`Option`] to create an optional box of
-//! [`i32`]. Notice that in order to use the inner [`i32`] value first, the
-//! `check_optional` function needs to use pattern matching to
+//! [`i32`]. Notice that in order to use the inner [`i32`] value, the
+//! `check_optional` function first needs to use pattern matching to
//! determine whether the box has a value (i.e., it is [`Some(...)`][`Some`]) or
//! not ([`None`]).
//!
//! * [`ptr::NonNull<U>`]
//! * `#[repr(transparent)]` struct around one of the types in this list.
//!
+//! This is called the "null pointer optimization" or NPO.
+//!
//! It is further guaranteed that, for the cases above, one can
//! [`mem::transmute`] from all valid values of `T` to `Option<T>` and
//! from `Some::<T>(_)` to `T` (but transmuting `None::<T>` to `T`
///
/// Converts an `Option<`[`String`]`>` into an `Option<`[`usize`]`>`, preserving the original.
/// The [`map`] method takes the `self` argument by value, consuming the original,
- /// so this technique uses `as_ref` to first take an `Option` to a reference
+ /// so this technique uses `from` to first take an `Option` to a reference
/// to the value inside the original.
///
/// [`map`]: Option::map
/// The 2015 version of the core prelude.
///
/// See the [module-level documentation](self) for more.
-#[unstable(feature = "prelude_2015", issue = "none")]
+#[stable(feature = "prelude_2015", since = "1.55.0")]
pub mod rust_2015 {
- #[unstable(feature = "prelude_2015", issue = "none")]
+ #[stable(feature = "prelude_2015", since = "1.55.0")]
#[doc(no_inline)]
pub use super::v1::*;
}
/// The 2018 version of the core prelude.
///
/// See the [module-level documentation](self) for more.
-#[unstable(feature = "prelude_2018", issue = "none")]
+#[stable(feature = "prelude_2018", since = "1.55.0")]
pub mod rust_2018 {
- #[unstable(feature = "prelude_2018", issue = "none")]
+ #[stable(feature = "prelude_2018", since = "1.55.0")]
#[doc(no_inline)]
pub use super::v1::*;
}
/// The 2021 version of the core prelude.
///
/// See the [module-level documentation](self) for more.
-#[unstable(feature = "prelude_2021", issue = "none")]
+#[stable(feature = "prelude_2021", since = "1.55.0")]
pub mod rust_2021 {
- #[unstable(feature = "prelude_2021", issue = "none")]
+ #[stable(feature = "prelude_2021", since = "1.55.0")]
#[doc(no_inline)]
pub use super::v1::*;
- // FIXME: Add more things.
+ #[stable(feature = "prelude_2021", since = "1.55.0")]
+ #[doc(no_inline)]
+ pub use crate::iter::FromIterator;
+
+ #[stable(feature = "prelude_2021", since = "1.55.0")]
+ #[doc(no_inline)]
+ pub use crate::convert::{TryFrom, TryInto};
}
}
#[inline]
-#[rustc_const_unstable(feature = "const_swap", issue = "83163")]
-pub(crate) const unsafe fn swap_nonoverlapping_one<T>(x: *mut T, y: *mut T) {
+pub(crate) unsafe fn swap_nonoverlapping_one<T>(x: *mut T, y: *mut T) {
// NOTE(eddyb) SPIR-V's Logical addressing model doesn't allow for arbitrary
// reinterpretation of values as (chunkable) byte arrays, and the loop in the
// block optimization in `swap_nonoverlapping_bytes` is hard to rewrite back
/// ```
#[inline]
#[stable(feature = "rust1", since = "1.0.0")]
-#[rustc_const_unstable(feature = "const_replace", issue = "83164")]
-pub const unsafe fn replace<T>(dst: *mut T, mut src: T) -> T {
+pub unsafe fn replace<T>(dst: *mut T, mut src: T) -> T {
// SAFETY: the caller must guarantee that `dst` is valid to be
// cast to a mutable reference (valid for writes, aligned, initialized),
// and cannot overlap `src` since `dst` must point to a distinct
/// ```
#[inline]
#[stable(feature = "rust1", since = "1.0.0")]
-#[rustc_const_unstable(feature = "const_ptr_write", issue = "none")]
-pub const unsafe fn write<T>(dst: *mut T, src: T) {
+pub unsafe fn write<T>(dst: *mut T, src: T) {
+ // We are calling the intrinsics directly to avoid function calls in the generated code
+ // as `intrinsics::copy_nonoverlapping` is a wrapper function.
+ extern "rust-intrinsic" {
+ fn copy_nonoverlapping<T>(src: *const T, dst: *mut T, count: usize);
+ }
+
// SAFETY: the caller must guarantee that `dst` is valid for writes.
// `dst` cannot overlap `src` because the caller has mutable access
// to `dst` while `src` is owned by this function.
unsafe {
copy_nonoverlapping(&src as *const T, dst, 1);
- // We are calling the intrinsic directly to avoid function calls in the generated code.
intrinsics::forget(src);
}
}
///
/// [`ptr::write`]: crate::ptr::write()
#[stable(feature = "pointer_methods", since = "1.26.0")]
- #[rustc_const_unstable(feature = "const_ptr_write", issue = "none")]
#[inline(always)]
- pub const unsafe fn write(self, val: T)
+ pub unsafe fn write(self, val: T)
where
T: Sized,
{
}
}
- /// Decompose a (possibly wide) pointer into is address and metadata components.
+ /// Decompose a (possibly wide) pointer into its address and metadata components.
///
/// The pointer can be later reconstructed with [`NonNull::from_raw_parts`].
#[unstable(feature = "ptr_metadata", issue = "81513")]
///
/// If the value is found then [`Result::Ok`] is returned, containing the
/// index of the matching element. If there are multiple matches, then any
- /// one of the matches could be returned. If the value is not found then
- /// [`Result::Err`] is returned, containing the index where a matching
- /// element could be inserted while maintaining sorted order.
+ /// one of the matches could be returned. The index is chosen
+ /// deterministically, but is subject to change in future versions of Rust.
+ /// If the value is not found then [`Result::Err`] is returned, containing
+ /// the index where a matching element could be inserted while maintaining
+ /// sorted order.
///
/// See also [`binary_search_by`], [`binary_search_by_key`], and [`partition_point`].
///
///
/// If the value is found then [`Result::Ok`] is returned, containing the
/// index of the matching element. If there are multiple matches, then any
- /// one of the matches could be returned. If the value is not found then
- /// [`Result::Err`] is returned, containing the index where a matching
- /// element could be inserted while maintaining sorted order.
+ /// one of the matches could be returned. The index is chosen
+ /// deterministically, but is subject to change in future versions of Rust.
+ /// If the value is not found then [`Result::Err`] is returned, containing
+ /// the index where a matching element could be inserted while maintaining
+ /// sorted order.
///
/// See also [`binary_search`], [`binary_search_by_key`], and [`partition_point`].
///
///
/// If the value is found then [`Result::Ok`] is returned, containing the
/// index of the matching element. If there are multiple matches, then any
- /// one of the matches could be returned. If the value is not found then
- /// [`Result::Err`] is returned, containing the index where a matching
- /// element could be inserted while maintaining sorted order.
+ /// one of the matches could be returned. The index is chosen
+ /// deterministically, but is subject to change in future versions of Rust.
+ /// If the value is not found then [`Result::Err`] is returned, containing
+ /// the index where a matching element could be inserted while maintaining
+ /// sorted order.
///
/// See also [`binary_search`], [`binary_search_by`], and [`partition_point`].
///
// SAFETY: the conditions for `ptr::copy` have all been checked above,
// as have those for `ptr::add`.
unsafe {
- ptr::copy(self.as_ptr().add(src_start), self.as_mut_ptr().add(dest), count);
+ // Derive both `src_ptr` and `dest_ptr` from the same loan
+ let ptr = self.as_mut_ptr();
+ let src_ptr = ptr.add(src_start);
+ let dest_ptr = ptr.add(dest);
+ ptr::copy(src_ptr, dest_ptr, count);
}
}
where
P: FnMut(&T) -> bool,
{
- let mut left = 0;
- let mut right = self.len();
-
- while left != right {
- let mid = left + (right - left) / 2;
- // SAFETY: When `left < right`, `left <= mid < right`.
- // Therefore `left` always increases and `right` always decreases,
- // and either of them is selected. In both cases `left <= right` is
- // satisfied. Therefore if `left < right` in a step, `left <= right`
- // is satisfied in the next step. Therefore as long as `left != right`,
- // `0 <= left < right <= len` is satisfied and if this case
- // `0 <= mid < len` is satisfied too.
- let value = unsafe { self.get_unchecked(mid) };
- if pred(value) {
- left = mid + 1;
- } else {
- right = mid;
- }
- }
-
- left
+ self.binary_search_by(|x| if pred(x) { Less } else { Greater }).unwrap_or_else(|i| i)
}
}
#[inline]
#[rustc_const_unstable(feature = "duration_consts_2", issue = "72440")]
pub const fn from_secs_f64(secs: f64) -> Duration {
+ match Duration::try_from_secs_f64(secs) {
+ Ok(v) => v,
+ Err(e) => crate::panicking::panic(e.description()),
+ }
+ }
+
+ /// The checked version of [`from_secs_f64`].
+ ///
+ /// [`from_secs_f64`]: Duration::from_secs_f64
+ ///
+ /// This constructor will return an `Err` if `secs` is not finite, negative or overflows `Duration`.
+ ///
+ /// # Examples
+ /// ```
+ /// #![feature(duration_checked_float)]
+ ///
+ /// use std::time::Duration;
+ ///
+ /// let dur = Duration::try_from_secs_f64(2.7);
+ /// assert_eq!(dur, Ok(Duration::new(2, 700_000_000)));
+ ///
+ /// let negative = Duration::try_from_secs_f64(-5.0);
+ /// assert!(negative.is_err());
+ /// ```
+ #[unstable(feature = "duration_checked_float", issue = "83400")]
+ #[inline]
+ pub const fn try_from_secs_f64(secs: f64) -> Result<Duration, FromSecsError> {
const MAX_NANOS_F64: f64 = ((u64::MAX as u128 + 1) * (NANOS_PER_SEC as u128)) as f64;
let nanos = secs * (NANOS_PER_SEC as f64);
if !nanos.is_finite() {
- panic!("got non-finite value when converting float to duration");
- }
- if nanos >= MAX_NANOS_F64 {
- panic!("overflow when converting float to duration");
- }
- if nanos < 0.0 {
- panic!("underflow when converting float to duration");
- }
- let nanos = nanos as u128;
- Duration {
- secs: (nanos / (NANOS_PER_SEC as u128)) as u64,
- nanos: (nanos % (NANOS_PER_SEC as u128)) as u32,
+ Err(FromSecsError { kind: FromSecsErrorKind::NonFinite })
+ } else if nanos >= MAX_NANOS_F64 {
+ Err(FromSecsError { kind: FromSecsErrorKind::Overflow })
+ } else if nanos < 0.0 {
+ Err(FromSecsError { kind: FromSecsErrorKind::Underflow })
+ } else {
+ let nanos = nanos as u128;
+ Ok(Duration {
+ secs: (nanos / (NANOS_PER_SEC as u128)) as u64,
+ nanos: (nanos % (NANOS_PER_SEC as u128)) as u32,
+ })
}
}
#[inline]
#[rustc_const_unstable(feature = "duration_consts_2", issue = "72440")]
pub const fn from_secs_f32(secs: f32) -> Duration {
+ match Duration::try_from_secs_f32(secs) {
+ Ok(v) => v,
+ Err(e) => crate::panicking::panic(e.description()),
+ }
+ }
+
+ /// The checked version of [`from_secs_f32`].
+ ///
+ /// [`from_secs_f32`]: Duration::from_secs_f32
+ ///
+ /// This constructor will return an `Err` if `secs` is not finite, negative or overflows `Duration`.
+ ///
+ /// # Examples
+ /// ```
+ /// #![feature(duration_checked_float)]
+ ///
+ /// use std::time::Duration;
+ ///
+ /// let dur = Duration::try_from_secs_f32(2.7);
+ /// assert_eq!(dur, Ok(Duration::new(2, 700_000_000)));
+ ///
+ /// let negative = Duration::try_from_secs_f32(-5.0);
+ /// assert!(negative.is_err());
+ /// ```
+ #[unstable(feature = "duration_checked_float", issue = "83400")]
+ #[inline]
+ pub const fn try_from_secs_f32(secs: f32) -> Result<Duration, FromSecsError> {
const MAX_NANOS_F32: f32 = ((u64::MAX as u128 + 1) * (NANOS_PER_SEC as u128)) as f32;
let nanos = secs * (NANOS_PER_SEC as f32);
if !nanos.is_finite() {
- panic!("got non-finite value when converting float to duration");
- }
- if nanos >= MAX_NANOS_F32 {
- panic!("overflow when converting float to duration");
- }
- if nanos < 0.0 {
- panic!("underflow when converting float to duration");
- }
- let nanos = nanos as u128;
- Duration {
- secs: (nanos / (NANOS_PER_SEC as u128)) as u64,
- nanos: (nanos % (NANOS_PER_SEC as u128)) as u32,
+ Err(FromSecsError { kind: FromSecsErrorKind::NonFinite })
+ } else if nanos >= MAX_NANOS_F32 {
+ Err(FromSecsError { kind: FromSecsErrorKind::Overflow })
+ } else if nanos < 0.0 {
+ Err(FromSecsError { kind: FromSecsErrorKind::Underflow })
+ } else {
+ let nanos = nanos as u128;
+ Ok(Duration {
+ secs: (nanos / (NANOS_PER_SEC as u128)) as u64,
+ nanos: (nanos % (NANOS_PER_SEC as u128)) as u32,
+ })
}
}
}
}
}
+
+/// An error which can be returned when converting a floating-point value of seconds
+/// into a [`Duration`].
+///
+/// This error is used as the error type for [`Duration::try_from_secs_f32`] and
+/// [`Duration::try_from_secs_f64`].
+///
+/// # Example
+///
+/// ```
+/// #![feature(duration_checked_float)]
+///
+/// use std::time::Duration;
+///
+/// if let Err(e) = Duration::try_from_secs_f32(-1.0) {
+/// println!("Failed conversion to Duration: {}", e);
+/// }
+/// ```
+#[derive(Debug, Clone, PartialEq, Eq)]
+#[unstable(feature = "duration_checked_float", issue = "83400")]
+pub struct FromSecsError {
+ kind: FromSecsErrorKind,
+}
+
+impl FromSecsError {
+ const fn description(&self) -> &'static str {
+ match self.kind {
+ FromSecsErrorKind::NonFinite => {
+ "got non-finite value when converting float to duration"
+ }
+ FromSecsErrorKind::Overflow => "overflow when converting float to duration",
+ FromSecsErrorKind::Underflow => "underflow when converting float to duration",
+ }
+ }
+}
+
+#[unstable(feature = "duration_checked_float", issue = "83400")]
+impl fmt::Display for FromSecsError {
+ fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
+ fmt::Display::fmt(self.description(), f)
+ }
+}
+
+#[derive(Debug, Clone, PartialEq, Eq)]
+enum FromSecsErrorKind {
+ // Value is not a finite value (either infinity or NaN).
+ NonFinite,
+ // Value is too large to store in a `Duration`.
+ Overflow,
+ // Value is less than `0.0`.
+ Underflow,
+}
fn is_any<T: Any + ?Sized>() {}
is_any::<[i32]>();
}
+
+#[test]
+fn distinct_type_names() {
+ // https://github.com/rust-lang/rust/issues/84666
+
+ struct Velocity(f32, f32);
+
+ fn type_name_of_val<T>(_: T) -> &'static str {
+ type_name::<T>()
+ }
+
+ assert_ne!(type_name_of_val(Velocity), type_name_of_val(Velocity(0.0, -9.8)),);
+}
-use core::array::{self, IntoIter};
+use core::array;
use core::convert::TryFrom;
#[test]
#[test]
fn iterator_collect() {
let arr = [0, 1, 2, 5, 9];
- let v: Vec<_> = IntoIter::new(arr.clone()).collect();
+ let v: Vec<_> = IntoIterator::into_iter(arr.clone()).collect();
assert_eq!(&arr[..], &v[..]);
}
#[test]
fn iterator_rev_collect() {
let arr = [0, 1, 2, 5, 9];
- let v: Vec<_> = IntoIter::new(arr.clone()).rev().collect();
+ let v: Vec<_> = IntoIterator::into_iter(arr.clone()).rev().collect();
assert_eq!(&v[..], &[9, 5, 2, 1, 0]);
}
fn iterator_nth() {
let v = [0, 1, 2, 3, 4];
for i in 0..v.len() {
- assert_eq!(IntoIter::new(v.clone()).nth(i).unwrap(), v[i]);
+ assert_eq!(IntoIterator::into_iter(v.clone()).nth(i).unwrap(), v[i]);
}
- assert_eq!(IntoIter::new(v.clone()).nth(v.len()), None);
+ assert_eq!(IntoIterator::into_iter(v.clone()).nth(v.len()), None);
- let mut iter = IntoIter::new(v);
+ let mut iter = IntoIterator::into_iter(v);
assert_eq!(iter.nth(2).unwrap(), v[2]);
assert_eq!(iter.nth(1).unwrap(), v[4]);
}
#[test]
fn iterator_last() {
let v = [0, 1, 2, 3, 4];
- assert_eq!(IntoIter::new(v).last().unwrap(), 4);
- assert_eq!(IntoIter::new([0]).last().unwrap(), 0);
+ assert_eq!(IntoIterator::into_iter(v).last().unwrap(), 4);
+ assert_eq!(IntoIterator::into_iter([0]).last().unwrap(), 0);
- let mut it = IntoIter::new([0, 9, 2, 4]);
+ let mut it = IntoIterator::into_iter([0, 9, 2, 4]);
assert_eq!(it.next_back(), Some(4));
assert_eq!(it.last(), Some(2));
}
#[test]
fn iterator_clone() {
- let mut it = IntoIter::new([0, 2, 4, 6, 8]);
+ let mut it = IntoIterator::into_iter([0, 2, 4, 6, 8]);
assert_eq!(it.next(), Some(0));
assert_eq!(it.next_back(), Some(8));
let mut clone = it.clone();
#[test]
fn iterator_fused() {
- let mut it = IntoIter::new([0, 9, 2]);
+ let mut it = IntoIterator::into_iter([0, 9, 2]);
assert_eq!(it.next(), Some(0));
assert_eq!(it.next(), Some(9));
assert_eq!(it.next(), Some(2));
#[test]
fn iterator_len() {
- let mut it = IntoIter::new([0, 1, 2, 5, 9]);
+ let mut it = IntoIterator::into_iter([0, 1, 2, 5, 9]);
assert_eq!(it.size_hint(), (5, Some(5)));
assert_eq!(it.len(), 5);
assert_eq!(it.is_empty(), false);
assert_eq!(it.is_empty(), false);
// Empty
- let it = IntoIter::new([] as [String; 0]);
+ let it = IntoIterator::into_iter([] as [String; 0]);
assert_eq!(it.size_hint(), (0, Some(0)));
assert_eq!(it.len(), 0);
assert_eq!(it.is_empty(), true);
#[test]
fn iterator_count() {
let v = [0, 1, 2, 3, 4];
- assert_eq!(IntoIter::new(v.clone()).count(), 5);
+ assert_eq!(IntoIterator::into_iter(v.clone()).count(), 5);
- let mut iter2 = IntoIter::new(v);
+ let mut iter2 = IntoIterator::into_iter(v);
iter2.next();
iter2.next();
assert_eq!(iter2.count(), 3);
#[test]
fn iterator_flat_map() {
- assert!((0..5).flat_map(|i| IntoIter::new([2 * i, 2 * i + 1])).eq(0..10));
+ assert!((0..5).flat_map(|i| IntoIterator::into_iter([2 * i, 2 * i + 1])).eq(0..10));
}
#[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!("{:?}", IntoIterator::into_iter(arr)), "IntoIter([0, 1, 2, 5, 9])",);
}
#[test]
// Simple: drop new iterator.
let i = Cell::new(0);
{
- IntoIter::new(five(&i));
+ IntoIterator::into_iter(five(&i));
}
assert_eq!(i.get(), 5);
// Call `next()` once.
let i = Cell::new(0);
{
- let mut iter = IntoIter::new(five(&i));
+ let mut iter = IntoIterator::into_iter(five(&i));
let _x = iter.next();
assert_eq!(i.get(), 0);
assert_eq!(iter.count(), 4);
// Check `clone` and calling `next`/`next_back`.
let i = Cell::new(0);
{
- let mut iter = IntoIter::new(five(&i));
+ let mut iter = IntoIterator::into_iter(five(&i));
iter.next();
assert_eq!(i.get(), 1);
iter.next_back();
// Check via `nth`.
let i = Cell::new(0);
{
- let mut iter = IntoIter::new(five(&i));
+ let mut iter = IntoIterator::into_iter(five(&i));
let _x = iter.nth(2);
assert_eq!(i.get(), 2);
let _y = iter.last();
// Check every element.
let i = Cell::new(0);
- for (index, _x) in IntoIter::new(five(&i)).enumerate() {
+ for (index, _x) in IntoIterator::into_iter(five(&i)).enumerate() {
assert_eq!(i.get(), index);
}
assert_eq!(i.get(), 5);
let i = Cell::new(0);
- for (index, _x) in IntoIter::new(five(&i)).rev().enumerate() {
+ for (index, _x) in IntoIterator::into_iter(five(&i)).rev().enumerate() {
assert_eq!(i.get(), index);
}
assert_eq!(i.get(), 5);
assert_eq!('A'.to_digit(16), Some(10));
assert_eq!('b'.to_digit(16), Some(11));
assert_eq!('B'.to_digit(16), Some(11));
+ assert_eq!('A'.to_digit(36), Some(10));
assert_eq!('z'.to_digit(36), Some(35));
assert_eq!('Z'.to_digit(36), Some(35));
- assert_eq!(' '.to_digit(10), None);
+ assert_eq!('['.to_digit(36), None);
+ assert_eq!('`'.to_digit(36), None);
+ assert_eq!('{'.to_digit(36), None);
assert_eq!('$'.to_digit(36), None);
+ assert_eq!('@'.to_digit(16), None);
+ assert_eq!('G'.to_digit(16), None);
+ assert_eq!('g'.to_digit(16), None);
+ assert_eq!(' '.to_digit(10), None);
+ assert_eq!('/'.to_digit(10), None);
+ assert_eq!(':'.to_digit(10), None);
+ assert_eq!(':'.to_digit(11), None);
}
#[test]
const UNALIGNED: u16 = unsafe { UNALIGNED_PTR.read_unaligned() };
assert_eq!(UNALIGNED, u16::from_ne_bytes([0x23, 0x45]));
}
-
-#[test]
-fn write() {
- use core::ptr;
-
- const fn write_aligned() -> i32 {
- let mut res = 0;
- unsafe {
- ptr::write(&mut res as *mut _, 42);
- }
- res
- }
- const ALIGNED: i32 = write_aligned();
- assert_eq!(ALIGNED, 42);
-
- const fn write_unaligned() -> [u16; 2] {
- let mut two_aligned = [0u16; 2];
- unsafe {
- let unaligned_ptr = (two_aligned.as_mut_ptr() as *mut u8).add(1) as *mut u16;
- ptr::write_unaligned(unaligned_ptr, u16::from_ne_bytes([0x23, 0x45]));
- }
- two_aligned
- }
- const UNALIGNED: [u16; 2] = write_unaligned();
- assert_eq!(UNALIGNED, [u16::from_ne_bytes([0x00, 0x23]), u16::from_ne_bytes([0x45, 0x00])]);
-}
-
-#[test]
-fn mut_ptr_write() {
- const fn aligned() -> i32 {
- let mut res = 0;
- unsafe {
- (&mut res as *mut i32).write(42);
- }
- res
- }
- const ALIGNED: i32 = aligned();
- assert_eq!(ALIGNED, 42);
-
- const fn write_unaligned() -> [u16; 2] {
- let mut two_aligned = [0u16; 2];
- unsafe {
- let unaligned_ptr = (two_aligned.as_mut_ptr() as *mut u8).add(1) as *mut u16;
- unaligned_ptr.write_unaligned(u16::from_ne_bytes([0x23, 0x45]));
- }
- two_aligned
- }
- const UNALIGNED: [u16; 2] = write_unaligned();
- assert_eq!(UNALIGNED, [u16::from_ne_bytes([0x00, 0x23]), u16::from_ne_bytes([0x45, 0x00])]);
-}
fn test_double_ended_zip() {
let xs = [1, 2, 3, 4, 5, 6];
let ys = [1, 2, 3, 7];
- let a = xs.iter().cloned();
- let b = ys.iter().cloned();
- let mut it = a.zip(b);
+ let mut it = xs.iter().cloned().zip(ys);
assert_eq!(it.next(), Some((1, 1)));
assert_eq!(it.next(), Some((2, 2)));
assert_eq!(it.next_back(), Some((4, 7)));
#![feature(const_ptr_read)]
#![feature(const_ptr_write)]
#![feature(const_ptr_offset)]
-#![feature(control_flow_enum)]
#![feature(core_intrinsics)]
#![feature(core_private_bignum)]
#![feature(core_private_diy_float)]
#![feature(maybe_uninit_write_slice)]
#![feature(min_specialization)]
#![feature(step_trait)]
-#![feature(step_trait_ext)]
#![feature(str_internals)]
#![feature(test)]
#![feature(trusted_len)]
#![no_std]
#![unstable(feature = "panic_abort", issue = "32837")]
-#![doc(
- html_root_url = "https://doc.rust-lang.org/nightly/",
- issue_tracker_base_url = "https://github.com/rust-lang/rust/issues/"
-)]
+#![doc(issue_tracker_base_url = "https://github.com/rust-lang/rust/issues/")]
#![panic_runtime]
#![allow(unused_features)]
#![feature(core_intrinsics)]
#![no_std]
#![unstable(feature = "panic_unwind", issue = "32837")]
-#![doc(
- html_root_url = "https://doc.rust-lang.org/nightly/",
- issue_tracker_base_url = "https://github.com/rust-lang/rust/issues/"
-)]
+#![doc(issue_tracker_base_url = "https://github.com/rust-lang/rust/issues/")]
#![feature(core_intrinsics)]
#![feature(lang_items)]
#![feature(nll)]
data: *mut T,
len: usize,
capacity: usize,
- extend_from_slice: extern "C" fn(Buffer<T>, Slice<'_, T>) -> Buffer<T>,
+ reserve: extern "C" fn(Buffer<T>, usize) -> Buffer<T>,
drop: extern "C" fn(Buffer<T>),
}
mem::take(self)
}
+ // We have the array method separate from extending from a slice. This is
+ // because in the case of small arrays, codegen can be more efficient
+ // (avoiding a memmove call). With extend_from_slice, LLVM at least
+ // currently is not able to make that optimization.
+ pub(super) fn extend_from_array<const N: usize>(&mut self, xs: &[T; N]) {
+ if xs.len() > (self.capacity - self.len) {
+ let b = self.take();
+ *self = (b.reserve)(b, xs.len());
+ }
+ unsafe {
+ xs.as_ptr().copy_to_nonoverlapping(self.data.add(self.len), xs.len());
+ self.len += xs.len();
+ }
+ }
+
pub(super) fn extend_from_slice(&mut self, xs: &[T]) {
- // Fast path to avoid going through an FFI call.
- if let Some(final_len) = self.len.checked_add(xs.len()) {
- if final_len <= self.capacity {
- let dst = unsafe { slice::from_raw_parts_mut(self.data, self.capacity) };
- dst[self.len..][..xs.len()].copy_from_slice(xs);
- self.len = final_len;
- return;
- }
+ if xs.len() > (self.capacity - self.len) {
+ let b = self.take();
+ *self = (b.reserve)(b, xs.len());
+ }
+ unsafe {
+ xs.as_ptr().copy_to_nonoverlapping(self.data.add(self.len), xs.len());
+ self.len += xs.len();
+ }
+ }
+
+ pub(super) fn push(&mut self, v: T) {
+ // The code here is taken from Vec::push, and we know that reserve()
+ // will panic if we're exceeding isize::MAX bytes and so there's no need
+ // to check for overflow.
+ if self.len == self.capacity {
+ let b = self.take();
+ *self = (b.reserve)(b, 1);
+ }
+ unsafe {
+ *self.data.add(self.len) = v;
+ self.len += 1;
}
- let b = self.take();
- *self = (b.extend_from_slice)(b, Slice::from(xs));
}
}
}
}
- extern "C" fn extend_from_slice<T: Copy>(b: Buffer<T>, xs: Slice<'_, T>) -> Buffer<T> {
+ extern "C" fn reserve<T: Copy>(b: Buffer<T>, additional: usize) -> Buffer<T> {
let mut v = to_vec(b);
- v.extend_from_slice(&xs);
+ v.reserve(additional);
Buffer::from(v)
}
mem::drop(to_vec(b));
}
- Buffer { data, len, capacity, extend_from_slice, drop }
+ Buffer { data, len, capacity, reserve, drop }
}
}
(le $ty:ty) => {
impl<S> Encode<S> for $ty {
fn encode(self, w: &mut Writer, _: &mut S) {
- w.write_all(&self.to_le_bytes()).unwrap();
+ w.extend_from_array(&self.to_le_bytes());
}
}
impl<S> Encode<S> for u8 {
fn encode(self, w: &mut Writer, _: &mut S) {
- w.write_all(&[self]).unwrap();
+ w.push(self);
}
}
#![stable(feature = "proc_macro_lib", since = "1.15.0")]
#![deny(missing_docs)]
#![doc(
- html_root_url = "https://doc.rust-lang.org/nightly/",
html_playground_url = "https://play.rust-lang.org/",
issue_tracker_base_url = "https://github.com/rust-lang/rust/issues/",
test(no_crate_inject, attr(deny(warnings))),
#![feature(restricted_std)]
#![feature(rustc_attrs)]
#![feature(min_specialization)]
+#![feature(bound_cloned)]
#![recursion_limit = "256"]
#[unstable(feature = "proc_macro_internals", issue = "27812")]
pub use diagnostic::{Diagnostic, Level, MultiSpan};
use std::cmp::Ordering;
-use std::ops::{Bound, RangeBounds};
+use std::ops::RangeBounds;
use std::path::PathBuf;
use std::str::FromStr;
use std::{error, fmt, iter, mem};
// was 'c' or whether it was '\u{63}'.
#[unstable(feature = "proc_macro_span", issue = "54725")]
pub fn subspan<R: RangeBounds<usize>>(&self, range: R) -> Option<Span> {
- // HACK(eddyb) something akin to `Option::cloned`, but for `Bound<&T>`.
- fn cloned_bound<T: Clone>(bound: Bound<&T>) -> Bound<T> {
- match bound {
- Bound::Included(x) => Bound::Included(x.clone()),
- Bound::Excluded(x) => Bound::Excluded(x.clone()),
- Bound::Unbounded => Bound::Unbounded,
- }
- }
-
- self.0.subspan(cloned_bound(range.start_bound()), cloned_bound(range.end_bound())).map(Span)
+ self.0.subspan(range.start_bound().cloned(), range.end_bound().cloned()).map(Span)
}
}
compiler_builtins = { version = "0.1.0", features = ['rustc-dep-of-std'] }
[build-dependencies]
-cc = "1.0.67"
+cc = "1.0.68"
panic_abort = { path = "../panic_abort" }
core = { path = "../core" }
libc = { version = "0.2.93", default-features = false, features = ['rustc-dep-of-std'] }
-compiler_builtins = { version = "0.1.43" }
+compiler_builtins = { version = "0.1.44" }
profiler_builtins = { path = "../profiler_builtins", optional = true }
unwind = { path = "../unwind" }
hashbrown = { version = "0.11", default-features = false, features = ['rustc-dep-of-std'] }
#[unstable(feature = "try_reserve", reason = "new API", issue = "48043")]
impl Error for alloc::collections::TryReserveError {}
+#[unstable(feature = "duration_checked_float", issue = "83400")]
+impl Error for core::time::FromSecsError {}
+
// Copied from `any.rs`.
impl dyn Error + 'static {
/// Returns `true` if the boxed type is the same as `T`
}
/// Bypass "move out of struct which implements [`Drop`] trait" restriction.
+ #[inline]
fn into_inner(self) -> Box<[u8]> {
// Rationale: `mem::forget(self)` invalidates the previous call to `ptr::read(&self.inner)`
// so we use `ManuallyDrop` to ensure `self` is not dropped.
fn seek(&mut self, pos: SeekFrom) -> io::Result<u64> {
(**self).seek(pos)
}
+
+ #[inline]
+ fn stream_position(&mut self) -> io::Result<u64> {
+ (**self).stream_position()
+ }
}
#[stable(feature = "rust1", since = "1.0.0")]
impl<B: BufRead + ?Sized> BufRead for &mut B {
fn seek(&mut self, pos: SeekFrom) -> io::Result<u64> {
(**self).seek(pos)
}
+
+ #[inline]
+ fn stream_position(&mut self) -> io::Result<u64> {
+ (**self).stream_position()
+ }
}
#[stable(feature = "rust1", since = "1.0.0")]
impl<B: BufRead + ?Sized> BufRead for Box<B> {
/// Capture a [closure]'s environment by value.
///
/// `move` converts any variables captured by reference or mutable reference
-/// to owned by value variables.
+/// to variables captured by value.
///
/// ```rust
-/// let capture = "hello";
-/// let closure = move || {
-/// println!("rust says {}", capture);
-/// };
+/// let data = vec![1, 2, 3];
+/// let closure = move || println!("captured {:?} by value", data);
+///
+/// // data is no longer available, it is owned by the closure
/// ```
///
/// Note: `move` closures may still implement [`Fn`] or [`FnMut`], even though
/// ```rust
/// fn create_fn() -> impl Fn() {
/// let text = "Fn".to_owned();
-///
/// move || println!("This is a: {}", text)
/// }
///
/// let fn_plain = create_fn();
-///
/// fn_plain();
/// ```
///
/// `move` is often used when [threads] are involved.
///
/// ```rust
-/// let x = 5;
+/// let data = vec![1, 2, 3];
///
/// std::thread::spawn(move || {
-/// println!("captured {} by value", x)
+/// println!("captured {:?} by value", data)
/// }).join().unwrap();
///
-/// // x is no longer available
+/// // data was moved to the spawned thread, so we cannot use it here
/// ```
///
/// `move` is also valid before an async block.
///
/// ```rust
-/// let capture = "hello";
+/// let capture = "hello".to_owned();
/// let block = async move {
/// println!("rust says {} from async block", capture);
/// };
/// Mutable raw pointers work much like mutable references, with the added
/// possibility of not pointing to a valid object. The syntax is `*mut Type`.
///
-/// More information on mutable references and pointers can be found in```
-/// [Reference].
+/// More information on mutable references and pointers can be found in the [Reference].
///
/// [Reference]: ../reference/types/pointer.html#mutable-references-mut
mod mut_keyword {}
/// At run-time, when a method needs to be called on the `dyn Trait`, the vtable is consulted to get
/// the function pointer and then that function pointer is called.
///
+/// See the Reference for more information on [trait objects][ref-trait-obj]
+/// and [object safety][ref-obj-safety].
+///
/// ## Trade-offs
///
/// The above indirection is the additional runtime cost of calling a function on a `dyn Trait`.
/// However, `dyn Trait` is likely to produce smaller code than `impl Trait` / generic parameters as
/// the method won't be duplicated for each concrete type.
///
-/// Read more about `object safety` and [trait object]s.
-///
/// [trait object]: ../book/ch17-02-trait-objects.html
+/// [ref-trait-obj]: ../reference/types/trait-object.html
+/// [ref-obj-safety]: ../reference/items/traits.html#object-safety
/// [erased]: https://en.wikipedia.org/wiki/Type_erasure
mod dyn_keyword {}
#![cfg_attr(not(feature = "restricted-std"), stable(feature = "rust1", since = "1.0.0"))]
#![cfg_attr(feature = "restricted-std", unstable(feature = "restricted_std", issue = "none"))]
#![doc(
- html_root_url = "https://doc.rust-lang.org/nightly/",
html_playground_url = "https://play.rust-lang.org/",
issue_tracker_base_url = "https://github.com/rust-lang/rust/issues/",
test(no_crate_inject, attr(deny(warnings))),
#![feature(doc_masked)]
#![feature(doc_notable_trait)]
#![feature(dropck_eyepatch)]
+#![feature(duration_checked_float)]
#![feature(duration_constants)]
#![feature(edition_panic)]
#![feature(exact_size_is_empty)]
#![feature(log_syntax)]
#![feature(map_try_insert)]
#![feature(maybe_uninit_extra)]
-#![feature(maybe_uninit_ref)]
#![feature(maybe_uninit_slice)]
#![feature(maybe_uninit_uninit_array)]
#![feature(min_specialization)]
#![feature(panic_internals)]
#![feature(panic_unwind)]
#![feature(pin_static_ref)]
-#![feature(prelude_2021)]
#![feature(prelude_import)]
#![feature(ptr_internals)]
#![feature(raw)]
-#![unstable(
- feature = "ip",
- reason = "extra functionality has not been \
- scrutinized to the level that it should \
- be to be stable",
- issue = "27709"
-)]
-
// Tests for this module
#[cfg(all(test, not(target_os = "emscripten")))]
mod tests;
#[allow(missing_docs)]
#[derive(Copy, PartialEq, Eq, Clone, Hash, Debug)]
+#[unstable(feature = "ip", issue = "27709")]
pub enum Ipv6MulticastScope {
InterfaceLocal,
LinkLocal,
/// assert_eq!(IpAddr::V6(Ipv6Addr::new(0, 0, 0x1c9, 0, 0, 0xafc8, 0, 0x1)).is_global(), true);
/// ```
#[rustc_const_unstable(feature = "const_ip", issue = "76205")]
+ #[unstable(feature = "ip", issue = "27709")]
#[inline]
pub const fn is_global(&self) -> bool {
match self {
/// );
/// ```
#[rustc_const_unstable(feature = "const_ip", issue = "76205")]
+ #[unstable(feature = "ip", issue = "27709")]
#[inline]
pub const fn is_documentation(&self) -> bool {
match self {
Ipv4Addr { inner: c::in_addr { s_addr: u32::from_ne_bytes([a, b, c, d]) } }
}
- /// An IPv4 address with the address pointing to localhost: 127.0.0.1.
+ /// An IPv4 address with the address pointing to localhost: `127.0.0.1`
///
/// # Examples
///
#[stable(feature = "ip_constructors", since = "1.30.0")]
pub const LOCALHOST: Self = Ipv4Addr::new(127, 0, 0, 1);
- /// An IPv4 address representing an unspecified address: 0.0.0.0
+ /// An IPv4 address representing an unspecified address: `0.0.0.0`
///
/// This corresponds to the constant `INADDR_ANY` in other languages.
///
#[stable(feature = "ip_constructors", since = "1.30.0")]
pub const UNSPECIFIED: Self = Ipv4Addr::new(0, 0, 0, 0);
- /// An IPv4 address representing the broadcast address: 255.255.255.255
+ /// An IPv4 address representing the broadcast address: `255.255.255.255`
///
/// # Examples
///
self.inner.s_addr.to_ne_bytes()
}
- /// Returns [`true`] for the special 'unspecified' address (0.0.0.0).
+ /// Returns [`true`] for the special 'unspecified' address (`0.0.0.0`).
///
/// This property is defined in _UNIX Network Programming, Second Edition_,
/// W. Richard Stevens, p. 891; see also [ip7].
self.inner.s_addr == 0
}
- /// Returns [`true`] if this is a loopback address (127.0.0.0/8).
+ /// Returns [`true`] if this is a loopback address (`127.0.0.0/8`).
///
/// This property is defined by [IETF RFC 1122].
///
///
/// The private address ranges are defined in [IETF RFC 1918] and include:
///
- /// - 10.0.0.0/8
- /// - 172.16.0.0/12
- /// - 192.168.0.0/16
+ /// - `10.0.0.0/8`
+ /// - `172.16.0.0/12`
+ /// - `192.168.0.0/16`
///
/// [IETF RFC 1918]: https://tools.ietf.org/html/rfc1918
///
}
}
- /// Returns [`true`] if the address is link-local (169.254.0.0/16).
+ /// Returns [`true`] if the address is link-local (`169.254.0.0/16`).
///
/// This property is defined by [IETF RFC 3927].
///
/// - the broadcast address (see [`Ipv4Addr::is_broadcast()`])
/// - addresses used for documentation (see [`Ipv4Addr::is_documentation()`])
/// - the unspecified address (see [`Ipv4Addr::is_unspecified()`]), and the whole
- /// 0.0.0.0/8 block
+ /// `0.0.0.0/8` block
/// - addresses reserved for future protocols (see
/// [`Ipv4Addr::is_ietf_protocol_assignment()`], except
/// `192.0.0.9/32` and `192.0.0.10/32` which are globally routable
/// assert_eq!(Ipv4Addr::new(80, 9, 12, 3).is_global(), true);
/// ```
#[rustc_const_unstable(feature = "const_ipv4", issue = "76205")]
+ #[unstable(feature = "ip", issue = "27709")]
#[inline]
pub const fn is_global(&self) -> bool {
// check if this address is 192.0.0.9 or 192.0.0.10. These addresses are the only two
/// assert_eq!(Ipv4Addr::new(100, 128, 0, 0).is_shared(), false);
/// ```
#[rustc_const_unstable(feature = "const_ipv4", issue = "76205")]
+ #[unstable(feature = "ip", issue = "27709")]
#[inline]
pub const fn is_shared(&self) -> bool {
self.octets()[0] == 100 && (self.octets()[1] & 0b1100_0000 == 0b0100_0000)
/// assert_eq!(Ipv4Addr::new(191, 255, 255, 255).is_ietf_protocol_assignment(), false);
/// ```
#[rustc_const_unstable(feature = "const_ipv4", issue = "76205")]
+ #[unstable(feature = "ip", issue = "27709")]
#[inline]
pub const fn is_ietf_protocol_assignment(&self) -> bool {
self.octets()[0] == 192 && self.octets()[1] == 0 && self.octets()[2] == 0
/// assert_eq!(Ipv4Addr::new(198, 20, 0, 0).is_benchmarking(), false);
/// ```
#[rustc_const_unstable(feature = "const_ipv4", issue = "76205")]
+ #[unstable(feature = "ip", issue = "27709")]
#[inline]
pub const fn is_benchmarking(&self) -> bool {
self.octets()[0] == 198 && (self.octets()[1] & 0xfe) == 18
/// assert_eq!(Ipv4Addr::new(255, 255, 255, 255).is_reserved(), false);
/// ```
#[rustc_const_unstable(feature = "const_ipv4", issue = "76205")]
+ #[unstable(feature = "ip", issue = "27709")]
#[inline]
pub const fn is_reserved(&self) -> bool {
self.octets()[0] & 240 == 240 && !self.is_broadcast()
}
- /// Returns [`true`] if this is a multicast address (224.0.0.0/4).
+ /// Returns [`true`] if this is a multicast address (`224.0.0.0/4`).
///
- /// Multicast addresses have a most significant octet between 224 and 239,
+ /// Multicast addresses have a most significant octet between `224` and `239`,
/// and is defined by [IETF RFC 5771].
///
/// [IETF RFC 5771]: https://tools.ietf.org/html/rfc5771
self.octets()[0] >= 224 && self.octets()[0] <= 239
}
- /// Returns [`true`] if this is a broadcast address (255.255.255.255).
+ /// Returns [`true`] if this is a broadcast address (`255.255.255.255`).
///
- /// A broadcast address has all octets set to 255 as defined in [IETF RFC 919].
+ /// A broadcast address has all octets set to `255` as defined in [IETF RFC 919].
///
/// [IETF RFC 919]: https://tools.ietf.org/html/rfc919
///
///
/// This is defined in [IETF RFC 5737]:
///
- /// - 192.0.2.0/24 (TEST-NET-1)
- /// - 198.51.100.0/24 (TEST-NET-2)
- /// - 203.0.113.0/24 (TEST-NET-3)
+ /// - `192.0.2.0/24` (TEST-NET-1)
+ /// - `198.51.100.0/24` (TEST-NET-2)
+ /// - `203.0.113.0/24` (TEST-NET-3)
///
/// [IETF RFC 5737]: https://tools.ietf.org/html/rfc5737
///
/// Converts this address to an IPv4-compatible [`IPv6` address].
///
- /// a.b.c.d becomes ::a.b.c.d
+ /// `a.b.c.d` becomes `::a.b.c.d`
///
/// This isn't typically the method you want; these addresses don't typically
/// function on modern systems. Use `to_ipv6_mapped` instead.
///
/// assert_eq!(
/// Ipv4Addr::new(192, 0, 2, 255).to_ipv6_compatible(),
- /// Ipv6Addr::new(0, 0, 0, 0, 0, 0, 49152, 767)
+ /// Ipv6Addr::new(0, 0, 0, 0, 0, 0, 0xc000, 0x2ff)
/// );
/// ```
#[rustc_const_stable(feature = "const_ipv4", since = "1.50.0")]
/// Converts this address to an IPv4-mapped [`IPv6` address].
///
- /// a.b.c.d becomes ::ffff:a.b.c.d
+ /// `a.b.c.d` becomes `::ffff:a.b.c.d`
///
/// [`IPv6` address]: Ipv6Addr
///
/// use std::net::{Ipv4Addr, Ipv6Addr};
///
/// assert_eq!(Ipv4Addr::new(192, 0, 2, 255).to_ipv6_mapped(),
- /// Ipv6Addr::new(0, 0, 0, 0, 0, 65535, 49152, 767));
+ /// Ipv6Addr::new(0, 0, 0, 0, 0, 0xffff, 0xc000, 0x2ff));
/// ```
#[rustc_const_stable(feature = "const_ipv4", since = "1.50.0")]
#[stable(feature = "rust1", since = "1.0.0")]
]
}
- /// Returns [`true`] for the special 'unspecified' address (::).
+ /// Returns [`true`] for the special 'unspecified' address (`::`).
///
/// This property is defined in [IETF RFC 4291].
///
/// assert_eq!(Ipv6Addr::new(0, 0, 0x1c9, 0, 0, 0xafc8, 0, 0x1).is_global(), true);
/// ```
#[rustc_const_unstable(feature = "const_ipv6", issue = "76205")]
+ #[unstable(feature = "ip", issue = "27709")]
#[inline]
pub const fn is_global(&self) -> bool {
match self.multicast_scope() {
/// assert_eq!(Ipv6Addr::new(0xfc02, 0, 0, 0, 0, 0, 0, 0).is_unique_local(), true);
/// ```
#[rustc_const_unstable(feature = "const_ipv6", issue = "76205")]
+ #[unstable(feature = "ip", issue = "27709")]
#[inline]
pub const fn is_unique_local(&self) -> bool {
(self.segments()[0] & 0xfe00) == 0xfc00
}
- /// Returns [`true`] if the address is a unicast link-local address (`fe80::/64`).
- ///
- /// A common misconception is to think that "unicast link-local addresses start with
- /// `fe80::`", but [IETF RFC 4291] actually defines a stricter format for these addresses:
+ /// Returns [`true`] if this is a unicast address, as defined by [IETF RFC 4291].
+ /// Any address that is not a [multicast address] (`ff00::/8`) is unicast.
///
- /// ```no_rust
- /// | 10 |
- /// | bits | 54 bits | 64 bits |
- /// +----------+-------------------------+----------------------------+
- /// |1111111010| 0 | interface ID |
- /// +----------+-------------------------+----------------------------+
- /// ```
- ///
- /// This method validates the format defined in the RFC and won't recognize addresses
- /// like `fe80:0:0:1::` or `fe81::` as unicast link-local addresses.
- /// If you need a less strict validation, use [`Ipv6Addr::is_unicast_link_local()`] instead.
+ /// [IETF RFC 4291]: https://tools.ietf.org/html/rfc4291
+ /// [multicast address]: Ipv6Addr::is_multicast
///
/// # Examples
///
///
/// use std::net::Ipv6Addr;
///
- /// let ip = Ipv6Addr::new(0xfe80, 0, 0, 0, 0, 0, 0, 0);
- /// assert!(ip.is_unicast_link_local_strict());
- ///
- /// let ip = Ipv6Addr::new(0xfe80, 0, 0, 0, 0xffff, 0xffff, 0xffff, 0xffff);
- /// assert!(ip.is_unicast_link_local_strict());
+ /// // The unspecified and loopback addresses are unicast.
+ /// assert_eq!(Ipv6Addr::UNSPECIFIED.is_unicast(), true);
+ /// assert_eq!(Ipv6Addr::LOCALHOST.is_unicast(), true);
///
- /// let ip = Ipv6Addr::new(0xfe80, 0, 0, 1, 0, 0, 0, 0);
- /// assert!(!ip.is_unicast_link_local_strict());
- /// assert!(ip.is_unicast_link_local());
- ///
- /// let ip = Ipv6Addr::new(0xfe81, 0, 0, 0, 0, 0, 0, 0);
- /// assert!(!ip.is_unicast_link_local_strict());
- /// assert!(ip.is_unicast_link_local());
+ /// // Any address that is not a multicast address (`ff00::/8`) is unicast.
+ /// assert_eq!(Ipv6Addr::new(0x2001, 0xdb8, 0, 0, 0, 0, 0, 0).is_unicast(), true);
+ /// assert_eq!(Ipv6Addr::new(0xff00, 0, 0, 0, 0, 0, 0, 0).is_unicast(), false);
/// ```
- ///
- /// # See also
- ///
- /// - [IETF RFC 4291 section 2.5.6]
- /// - [RFC 4291 errata 4406] (which has been rejected but provides useful
- /// insight)
- /// - [`Ipv6Addr::is_unicast_link_local()`]
- ///
- /// [IETF RFC 4291]: https://tools.ietf.org/html/rfc4291
- /// [IETF RFC 4291 section 2.5.6]: https://tools.ietf.org/html/rfc4291#section-2.5.6
- /// [RFC 4291 errata 4406]: https://www.rfc-editor.org/errata/eid4406
#[rustc_const_unstable(feature = "const_ipv6", issue = "76205")]
+ #[unstable(feature = "ip", issue = "27709")]
#[inline]
- pub const fn is_unicast_link_local_strict(&self) -> bool {
- matches!(self.segments(), [0xfe80, 0, 0, 0, ..])
+ pub const fn is_unicast(&self) -> bool {
+ !self.is_multicast()
}
- /// Returns [`true`] if the address is a unicast link-local address (`fe80::/10`).
+ /// Returns `true` if the address is a unicast address with link-local scope,
+ /// as defined in [RFC 4291].
///
- /// This method returns [`true`] for addresses in the range reserved by [RFC 4291 section 2.4],
- /// i.e. addresses with the following format:
+ /// A unicast address has link-local scope if it has the prefix `fe80::/10`, as per [RFC 4291 section 2.4].
+ /// Note that this encompasses more addresses than those defined in [RFC 4291 section 2.5.6],
+ /// which describes "Link-Local IPv6 Unicast Addresses" as having the following stricter format:
///
- /// ```no_rust
- /// | 10 |
- /// | bits | 54 bits | 64 bits |
+ /// ```text
+ /// | 10 bits | 54 bits | 64 bits |
/// +----------+-------------------------+----------------------------+
- /// |1111111010| arbitratry value | interface ID |
+ /// |1111111010| 0 | interface ID |
/// +----------+-------------------------+----------------------------+
/// ```
+ /// So while currently the only addresses with link-local scope an application will encounter are all in `fe80::/64`,
+ /// this might change in the future with the publication of new standards. More addresses in `fe80::/10` could be allocated,
+ /// and those addresses will have link-local scope.
+ ///
+ /// Also note that while [RFC 4291 section 2.5.3] mentions about the [loopback address] (`::1`) that "it is treated as having Link-Local scope",
+ /// this does not mean that the loopback address actually has link-local scope and this method will return `false` on it.
///
- /// As a result, this method considers addresses such as `fe80:0:0:1::` or `fe81::` to be
- /// unicast link-local addresses, whereas [`Ipv6Addr::is_unicast_link_local_strict()`] does not.
- /// If you need a strict validation fully compliant with the RFC, use
- /// [`Ipv6Addr::is_unicast_link_local_strict()`] instead.
+ /// [RFC 4291]: https://tools.ietf.org/html/rfc4291
+ /// [RFC 4291 section 2.4]: https://tools.ietf.org/html/rfc4291#section-2.4
+ /// [RFC 4291 section 2.5.3]: https://tools.ietf.org/html/rfc4291#section-2.5.3
+ /// [RFC 4291 section 2.5.6]: https://tools.ietf.org/html/rfc4291#section-2.5.6
+ /// [loopback address]: Ipv6Addr::LOCALHOST
///
/// # Examples
///
///
/// use std::net::Ipv6Addr;
///
- /// let ip = Ipv6Addr::new(0xfe80, 0, 0, 0, 0, 0, 0, 0);
- /// assert!(ip.is_unicast_link_local());
+ /// // The loopback address (`::1`) does not actually have link-local scope.
+ /// assert_eq!(Ipv6Addr::LOCALHOST.is_unicast_link_local(), false);
///
- /// let ip = Ipv6Addr::new(0xfe80, 0, 0, 0, 0xffff, 0xffff, 0xffff, 0xffff);
- /// assert!(ip.is_unicast_link_local());
+ /// // Only addresses in `fe80::/10` have link-local scope.
+ /// assert_eq!(Ipv6Addr::new(0x2001, 0xdb8, 0, 0, 0, 0, 0, 0).is_unicast_link_local(), false);
+ /// assert_eq!(Ipv6Addr::new(0xfe80, 0, 0, 0, 0, 0, 0, 0).is_unicast_link_local(), true);
///
- /// let ip = Ipv6Addr::new(0xfe80, 0, 0, 1, 0, 0, 0, 0);
- /// assert!(ip.is_unicast_link_local());
- /// assert!(!ip.is_unicast_link_local_strict());
- ///
- /// let ip = Ipv6Addr::new(0xfe81, 0, 0, 0, 0, 0, 0, 0);
- /// assert!(ip.is_unicast_link_local());
- /// assert!(!ip.is_unicast_link_local_strict());
+ /// // Addresses outside the stricter `fe80::/64` also have link-local scope.
+ /// assert_eq!(Ipv6Addr::new(0xfe80, 0, 0, 1, 0, 0, 0, 0).is_unicast_link_local(), true);
+ /// assert_eq!(Ipv6Addr::new(0xfe81, 0, 0, 0, 0, 0, 0, 0).is_unicast_link_local(), true);
/// ```
- ///
- /// # See also
- ///
- /// - [IETF RFC 4291 section 2.4]
- /// - [RFC 4291 errata 4406] (which has been rejected but provides useful
- /// insight)
- ///
- /// [IETF RFC 4291 section 2.4]: https://tools.ietf.org/html/rfc4291#section-2.4
- /// [RFC 4291 errata 4406]: https://www.rfc-editor.org/errata/eid4406
#[rustc_const_unstable(feature = "const_ipv6", issue = "76205")]
+ #[unstable(feature = "ip", issue = "27709")]
#[inline]
pub const fn is_unicast_link_local(&self) -> bool {
(self.segments()[0] & 0xffc0) == 0xfe80
}
- /// Returns [`true`] if this is a deprecated unicast site-local address (fec0::/10). The
- /// unicast site-local address format is defined in [RFC 4291 section 2.5.7] as:
- ///
- /// ```no_rust
- /// | 10 |
- /// | bits | 54 bits | 64 bits |
- /// +----------+-------------------------+----------------------------+
- /// |1111111011| subnet ID | interface ID |
- /// +----------+-------------------------+----------------------------+
- /// ```
- ///
- /// [RFC 4291 section 2.5.7]: https://tools.ietf.org/html/rfc4291#section-2.5.7
- ///
- /// # Examples
- ///
- /// ```
- /// #![feature(ip)]
- ///
- /// use std::net::Ipv6Addr;
- ///
- /// assert_eq!(
- /// Ipv6Addr::new(0, 0, 0, 0, 0, 0xffff, 0xc00a, 0x2ff).is_unicast_site_local(),
- /// false
- /// );
- /// assert_eq!(Ipv6Addr::new(0xfec2, 0, 0, 0, 0, 0, 0, 0).is_unicast_site_local(), true);
- /// ```
- ///
- /// # Warning
- ///
- /// As per [RFC 3879], the whole `FEC0::/10` prefix is
- /// deprecated. New software must not support site-local
- /// addresses.
- ///
- /// [RFC 3879]: https://tools.ietf.org/html/rfc3879
- #[rustc_const_unstable(feature = "const_ipv6", issue = "76205")]
- #[inline]
- pub const fn is_unicast_site_local(&self) -> bool {
- (self.segments()[0] & 0xffc0) == 0xfec0
- }
-
/// Returns [`true`] if this is an address reserved for documentation
/// (`2001:db8::/32`).
///
/// assert_eq!(Ipv6Addr::new(0x2001, 0xdb8, 0, 0, 0, 0, 0, 0).is_documentation(), true);
/// ```
#[rustc_const_unstable(feature = "const_ipv6", issue = "76205")]
+ #[unstable(feature = "ip", issue = "27709")]
#[inline]
pub const fn is_documentation(&self) -> bool {
(self.segments()[0] == 0x2001) && (self.segments()[1] == 0xdb8)
/// assert_eq!(Ipv6Addr::new(0, 0, 0, 0, 0, 0xffff, 0xc00a, 0x2ff).is_unicast_global(), true);
/// ```
#[rustc_const_unstable(feature = "const_ipv6", issue = "76205")]
+ #[unstable(feature = "ip", issue = "27709")]
#[inline]
pub const fn is_unicast_global(&self) -> bool {
- !self.is_multicast()
+ self.is_unicast()
&& !self.is_loopback()
&& !self.is_unicast_link_local()
&& !self.is_unique_local()
/// assert_eq!(Ipv6Addr::new(0, 0, 0, 0, 0, 0xffff, 0xc00a, 0x2ff).multicast_scope(), None);
/// ```
#[rustc_const_unstable(feature = "const_ipv6", issue = "76205")]
+ #[unstable(feature = "ip", issue = "27709")]
#[inline]
pub const fn multicast_scope(&self) -> Option<Ipv6MulticastScope> {
if self.is_multicast() {
}
}
- /// Returns [`true`] if this is a multicast address (ff00::/8).
+ /// Returns [`true`] if this is a multicast address (`ff00::/8`).
///
/// This property is defined by [IETF RFC 4291].
///
/// assert_eq!(Ipv6Addr::new(0, 0, 0, 0, 0, 0, 0, 1).to_ipv4_mapped(), None);
/// ```
#[rustc_const_unstable(feature = "const_ipv6", issue = "76205")]
+ #[unstable(feature = "ip", issue = "27709")]
#[inline]
pub const fn to_ipv4_mapped(&self) -> Option<Ipv4Addr> {
match self.octets() {
/// Converts this address to an [`IPv4` address]. Returns [`None`] if this address is
/// neither IPv4-compatible or IPv4-mapped.
///
- /// ::a.b.c.d and ::ffff:a.b.c.d become a.b.c.d
+ /// `::a.b.c.d` and `::ffff:a.b.c.d` become `a.b.c.d`
///
/// [`IPv4` address]: Ipv4Addr
///
let unique_local: u16 = 1 << 2;
let global: u16 = 1 << 3;
let unicast_link_local: u16 = 1 << 4;
- let unicast_link_local_strict: u16 = 1 << 5;
- let unicast_site_local: u16 = 1 << 6;
let unicast_global: u16 = 1 << 7;
let documentation: u16 = 1 << 8;
let multicast_interface_local: u16 = 1 << 9;
} else {
assert!(!ip!($s).is_unicast_link_local());
}
- if ($mask & unicast_link_local_strict) == unicast_link_local_strict {
- assert!(ip!($s).is_unicast_link_local_strict());
- } else {
- assert!(!ip!($s).is_unicast_link_local_strict());
- }
- if ($mask & unicast_site_local) == unicast_site_local {
- assert!(ip!($s).is_unicast_site_local());
- } else {
- assert!(!ip!($s).is_unicast_site_local());
- }
if ($mask & unicast_global) == unicast_global {
assert!(ip!($s).is_unicast_global());
} else {
let unique_local: u16 = 1 << 2;
let global: u16 = 1 << 3;
let unicast_link_local: u16 = 1 << 4;
- let unicast_link_local_strict: u16 = 1 << 5;
- let unicast_site_local: u16 = 1 << 6;
let unicast_global: u16 = 1 << 7;
let documentation: u16 = 1 << 8;
let multicast_interface_local: u16 = 1 << 9;
unicast_link_local
);
- check!(
- "fe80::",
- &[0xfe, 0x80, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
- unicast_link_local | unicast_link_local_strict
- );
+ check!("fe80::", &[0xfe, 0x80, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], unicast_link_local);
check!(
"febf:ffff::",
0xfe, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
0xff, 0xff
],
- unicast_link_local | unicast_link_local_strict
+ unicast_link_local
);
check!(
check!(
"fec0::",
&[0xfe, 0xc0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
- unicast_site_local | unicast_global | global
+ unicast_global | global
);
check!(
const IS_UNIQUE_LOCAL: bool = IP_ADDRESS.is_unique_local();
assert!(!IS_UNIQUE_LOCAL);
- const IS_UNICAST_LINK_LOCAL_STRICT: bool = IP_ADDRESS.is_unicast_link_local_strict();
- assert!(!IS_UNICAST_LINK_LOCAL_STRICT);
-
const IS_UNICAST_LINK_LOCAL: bool = IP_ADDRESS.is_unicast_link_local();
assert!(!IS_UNICAST_LINK_LOCAL);
- const IS_UNICAST_SITE_LOCAL: bool = IP_ADDRESS.is_unicast_site_local();
- assert!(!IS_UNICAST_SITE_LOCAL);
-
const IS_DOCUMENTATION: bool = IP_ADDRESS.is_documentation();
assert!(!IS_DOCUMENTATION);
/// See the [`panic!`] macro for more information about panicking.
#[stable(feature = "panic_any", since = "1.51.0")]
#[inline]
+#[track_caller]
pub fn panic_any<M: 'static + Any + Send>(msg: M) -> ! {
crate::panicking::begin_panic(msg);
}
use crate::sync::atomic::{AtomicBool, Ordering};
use crate::sys::stdio::panic_output;
use crate::sys_common::backtrace::{self, RustBacktrace};
-use crate::sys_common::rwlock::RWLock;
+use crate::sys_common::rwlock::StaticRWLock;
use crate::sys_common::thread_info;
use crate::thread;
Custom(*mut (dyn Fn(&PanicInfo<'_>) + 'static + Sync + Send)),
}
-static HOOK_LOCK: RWLock = RWLock::new();
+static HOOK_LOCK: StaticRWLock = StaticRWLock::new();
static mut HOOK: Hook = Hook::Default;
/// Registers a custom panic hook, replacing any that was previously registered.
}
unsafe {
- HOOK_LOCK.write();
+ let guard = HOOK_LOCK.write();
let old_hook = HOOK;
HOOK = Hook::Custom(Box::into_raw(hook));
- HOOK_LOCK.write_unlock();
+ drop(guard);
if let Hook::Custom(ptr) = old_hook {
#[allow(unused_must_use)]
}
unsafe {
- HOOK_LOCK.write();
+ let guard = HOOK_LOCK.write();
let hook = HOOK;
HOOK = Hook::Default;
- HOOK_LOCK.write_unlock();
+ drop(guard);
match hook {
Hook::Default => Box::new(default_hook),
Some(s) => *s,
None => match info.payload().downcast_ref::<String>() {
Some(s) => &s[..],
- None => "Box<Any>",
+ None => "Box<dyn Any>",
},
};
let thread = thread_info::current_thread();
unsafe {
let mut info = PanicInfo::internal_constructor(message, location);
- HOOK_LOCK.read();
+ let _guard = HOOK_LOCK.read();
match HOOK {
// Some platforms (like wasm) know that printing to stderr won't ever actually
// print anything, and if that's the case we can skip the default
(*ptr)(&info);
}
};
- HOOK_LOCK.read_unlock();
}
if panics > 1 {
impl<'a> cmp::PartialEq for Components<'a> {
#[inline]
fn eq(&self, other: &Components<'a>) -> bool {
- Iterator::eq(self.clone(), other.clone())
+ Iterator::eq(self.clone().rev(), other.clone().rev())
}
}
#[stable(feature = "box_from_path", since = "1.17.0")]
impl From<&Path> for Box<Path> {
+ /// Creates a boxed [`Path`] from a reference.
+ ///
+ /// This will allocate and clone `path` to it.
fn from(path: &Path) -> Box<Path> {
let boxed: Box<OsStr> = path.inner.into();
let rw = Box::into_raw(boxed) as *mut Path;
#[stable(feature = "box_from_cow", since = "1.45.0")]
impl From<Cow<'_, Path>> for Box<Path> {
+ /// Creates a boxed [`Path`] from a clone-on-write pointer.
+ ///
+ /// Converting from a `Cow::Owned` does not clone or allocate.
#[inline]
fn from(cow: Cow<'_, Path>) -> Box<Path> {
match cow {
#[stable(feature = "rust1", since = "1.0.0")]
impl<T: ?Sized + AsRef<OsStr>> From<&T> for PathBuf {
+ /// Converts a borrowed `OsStr` to a `PathBuf`.
+ ///
+ /// Allocates a [`PathBuf`] and copies the data into it.
#[inline]
fn from(s: &T) -> PathBuf {
PathBuf::from(s.as_ref().to_os_string())
#[stable(feature = "cow_from_path", since = "1.6.0")]
impl<'a> From<&'a Path> for Cow<'a, Path> {
+ /// Creates a clone-on-write pointer from a reference to
+ /// [`Path`].
+ ///
+ /// This conversion does not clone or allocate.
#[inline]
fn from(s: &'a Path) -> Cow<'a, Path> {
Cow::Borrowed(s)
#[stable(feature = "cow_from_path", since = "1.6.0")]
impl<'a> From<PathBuf> for Cow<'a, Path> {
+ /// Creates a clone-on-write pointer from an owned
+ /// instance of [`PathBuf`].
+ ///
+ /// This conversion does not clone or allocate.
#[inline]
fn from(s: PathBuf) -> Cow<'a, Path> {
Cow::Owned(s)
#[stable(feature = "cow_from_pathbuf_ref", since = "1.28.0")]
impl<'a> From<&'a PathBuf> for Cow<'a, Path> {
+ /// Creates a clone-on-write pointer from a reference to
+ /// [`PathBuf`].
+ ///
+ /// This conversion does not clone or allocate.
#[inline]
fn from(p: &'a PathBuf) -> Cow<'a, Path> {
Cow::Borrowed(p.as_path())
#[stable(feature = "pathbuf_from_cow_path", since = "1.28.0")]
impl<'a> From<Cow<'a, Path>> for PathBuf {
+ /// Converts a clone-on-write pointer to an owned path.
+ ///
+ /// Converting from a `Cow::Owned` does not clone or allocate.
#[inline]
fn from(p: Cow<'a, Path>) -> Self {
p.into_owned()
/// Returns `true` if the path points at an existing entity.
///
/// This function will traverse symbolic links to query information about the
- /// destination file. In case of broken symbolic links this will return `false`.
+ /// destination file.
///
- /// If you cannot access the directory containing the file, e.g., because of a
- /// permission error, this will return `false`.
+ /// If you cannot access the metadata of the file, e.g. because of a
+ /// permission error or broken symbolic links, this will return `false`.
///
/// # Examples
///
/// Returns `true` if the path exists on disk and is pointing at a regular file.
///
/// This function will traverse symbolic links to query information about the
- /// destination file. In case of broken symbolic links this will return `false`.
+ /// destination file.
///
- /// If you cannot access the directory containing the file, e.g., because of a
- /// permission error, this will return `false`.
+ /// If you cannot access the metadata of the file, e.g. because of a
+ /// permission error or broken symbolic links, this will return `false`.
///
/// # Examples
///
/// Returns `true` if the path exists on disk and is pointing at a directory.
///
/// This function will traverse symbolic links to query information about the
- /// destination file. In case of broken symbolic links this will return `false`.
+ /// destination file.
///
- /// If you cannot access the directory containing the file, e.g., because of a
- /// permission error, this will return `false`.
+ /// If you cannot access the metadata of the file, e.g. because of a
+ /// permission error or broken symbolic links, this will return `false`.
///
/// # Examples
///
//!
//! # Prelude contents
//!
-//! The current version of the prelude (version 1) lives in
-//! [`std::prelude::v1`], and re-exports the following:
+//! The first version of the prelude is used in Rust 2015 and Rust 2018,
+//! and lives in [`std::prelude::v1`].
+//! [`std::prelude::rust_2015`] and [`std::prelude::rust_2018`] re-export this prelude.
+//! It re-exports the following:
//!
//! * <code>[std::marker]::{[Copy], [Send], [Sized], [Sync], [Unpin]}</code>,
//! marker traits that indicate fundamental properties of types.
//! * <code>[std::string]::{[String], [ToString]}</code>, heap-allocated strings.
//! * <code>[std::vec]::[Vec]</code>, a growable, heap-allocated vector.
//!
+//! The prelude used in Rust 2021, [`std::prelude::rust_2021`], includes all of the above,
+//! and in addition re-exports:
+//!
+//! * <code>[std::convert]::{[TryFrom], [TryInto]}</code>,
+//! * <code>[std::iter]::[FromIterator]</code>.
+//!
//! [mem::drop]: crate::mem::drop
//! [std::borrow]: crate::borrow
//! [std::boxed]: crate::boxed
//! [std::ops]: crate::ops
//! [std::option]: crate::option
//! [`std::prelude::v1`]: v1
+//! [`std::prelude::rust_2015`]: rust_2015
+//! [`std::prelude::rust_2018`]: rust_2018
+//! [`std::prelude::rust_2021`]: rust_2021
//! [std::result]: crate::result
//! [std::slice]: crate::slice
//! [std::string]: crate::string
//! [std::vec]: mod@crate::vec
+//! [TryFrom]: crate::convert::TryFrom
+//! [TryInto]: crate::convert::TryInto
+//! [FromIterator]: crate::iter::FromIterator
//! [`to_owned`]: crate::borrow::ToOwned::to_owned
//! [book-closures]: ../../book/ch13-01-closures.html
//! [book-dtor]: ../../book/ch15-03-drop.html
/// The 2015 version of the prelude of The Rust Standard Library.
///
/// See the [module-level documentation](self) for more.
-#[unstable(feature = "prelude_2015", issue = "none")]
+#[stable(feature = "prelude_2015", since = "1.55.0")]
pub mod rust_2015 {
- #[unstable(feature = "prelude_2015", issue = "none")]
+ #[stable(feature = "prelude_2015", since = "1.55.0")]
#[doc(no_inline)]
pub use super::v1::*;
}
/// The 2018 version of the prelude of The Rust Standard Library.
///
/// See the [module-level documentation](self) for more.
-#[unstable(feature = "prelude_2018", issue = "none")]
+#[stable(feature = "prelude_2018", since = "1.55.0")]
pub mod rust_2018 {
- #[unstable(feature = "prelude_2018", issue = "none")]
+ #[stable(feature = "prelude_2018", since = "1.55.0")]
#[doc(no_inline)]
pub use super::v1::*;
}
/// The 2021 version of the prelude of The Rust Standard Library.
///
/// See the [module-level documentation](self) for more.
-#[unstable(feature = "prelude_2021", issue = "none")]
+#[stable(feature = "prelude_2021", since = "1.55.0")]
pub mod rust_2021 {
- #[unstable(feature = "prelude_2021", issue = "none")]
+ #[stable(feature = "prelude_2021", since = "1.55.0")]
#[doc(no_inline)]
pub use super::v1::*;
- #[unstable(feature = "prelude_2021", issue = "none")]
+ #[stable(feature = "prelude_2021", since = "1.55.0")]
#[doc(no_inline)]
pub use core::prelude::rust_2021::*;
}
//! });
//! rx.recv().unwrap();
//! ```
+//!
+//! Unbounded receive loop:
+//!
+//! ```
+//! use std::sync::mpsc::sync_channel;
+//! use std::thread;
+//!
+//! let (tx, rx) = sync_channel(3);
+//!
+//! for _ in 0..3 {
+//! // It would be the same without thread and clone here
+//! // since there will still be one `tx` left.
+//! let tx = tx.clone();
+//! // cloned tx dropped within thread
+//! thread::spawn(move || tx.send("ok").unwrap());
+//! }
+//!
+//! // Drop the last sender to stop `rx` waiting for message.
+//! // The program will not complete if we comment this out.
+//! // **All** `tx` needs to be dropped for `rx` to have `Err`.
+//! drop(tx);
+//!
+//! // Unbounded receiver waiting for all senders to complete.
+//! while let Ok(msg) = rx.recv() {
+//! println!("{}", msg);
+//! }
+//!
+//! println!("completed");
+//! ```
#![stable(feature = "rust1", since = "1.0.0")]
///
/// Messages can be sent through this channel with [`send`].
///
+/// Note: all senders (the original and the clones) need to be dropped for the receiver
+/// to stop blocking to receive messages with [`Receiver::recv`].
+///
/// [`send`]: Sender::send
///
/// # Examples
/// the same order as it was sent, and no [`send`] will block the calling thread
/// (this channel has an "infinite buffer", unlike [`sync_channel`], which will
/// block after its buffer limit is reached). [`recv`] will block until a message
-/// is available.
+/// is available while there is at least one [`Sender`] alive (including clones).
///
/// The [`Sender`] can be cloned to [`send`] to the same channel multiple times, but
/// only one [`Receiver`] is supported.
#[stable(feature = "rust1", since = "1.0.0")]
impl<T> Clone for Sender<T> {
+ /// Clone a sender to send to other threads.
+ ///
+ /// Note, be aware of the lifetime of the sender because all senders
+ /// (including the original) need to be dropped in order for
+ /// [`Receiver::recv`] to stop blocking.
fn clone(&self) -> Sender<T> {
let packet = match *unsafe { self.inner() } {
Flavor::Oneshot(ref p) => {
/// corresponding channel has hung up.
///
/// This function will always block the current thread if there is no data
- /// available and it's possible for more data to be sent. Once a message is
- /// sent to the corresponding [`Sender`] (or [`SyncSender`]), then this
- /// receiver will wake up and return that message.
+ /// available and it's possible for more data to be sent (at least one sender
+ /// still exists). Once a message is sent to the corresponding [`Sender`]
+ /// (or [`SyncSender`]), this receiver will wake up and return that
+ /// message.
///
/// If the corresponding [`Sender`] has disconnected, or it disconnects while
/// this call is blocking, this call will wake up and return [`Err`] to
/// corresponding channel has hung up, or if it waits more than `timeout`.
///
/// This function will always block the current thread if there is no data
- /// available and it's possible for more data to be sent. Once a message is
- /// sent to the corresponding [`Sender`] (or [`SyncSender`]), then this
- /// receiver will wake up and return that message.
+ /// available and it's possible for more data to be sent (at least one sender
+ /// still exists). Once a message is sent to the corresponding [`Sender`]
+ /// (or [`SyncSender`]), this receiver will wake up and return that
+ /// message.
///
/// If the corresponding [`Sender`] has disconnected, or it disconnects while
/// this call is blocking, this call will wake up and return [`Err`] to
/// # Errors
///
/// If another user of this mutex panicked while holding the mutex, then
- /// this call will return an error if the mutex would otherwise be
- /// acquired.
+ /// this call will return the [`Poisoned`] error if the mutex would
+ /// otherwise be acquired.
+ ///
+ /// If the mutex could not be acquired because it is already locked, then
+ /// this call will return the [`WouldBlock`] error.
+ ///
+ /// [`Poisoned`]: TryLockError::Poisoned
+ /// [`WouldBlock`]: TryLockError::WouldBlock
///
/// # Examples
///
use crate::cell::UnsafeCell;
use crate::fmt;
-use crate::mem;
use crate::ops::{Deref, DerefMut};
-use crate::ptr;
use crate::sync::{poison, LockResult, TryLockError, TryLockResult};
use crate::sys_common::rwlock as sys;
/// [`Mutex`]: super::Mutex
#[stable(feature = "rust1", since = "1.0.0")]
pub struct RwLock<T: ?Sized> {
- inner: Box<sys::RWLock>,
+ inner: sys::MovableRWLock,
poison: poison::Flag,
data: UnsafeCell<T>,
}
#[stable(feature = "rust1", since = "1.0.0")]
pub fn new(t: T) -> RwLock<T> {
RwLock {
- inner: box sys::RWLock::new(),
+ inner: sys::MovableRWLock::new(),
poison: poison::Flag::new(),
data: UnsafeCell::new(t),
}
///
/// # Errors
///
- /// This function will return an error if the RwLock is poisoned. An RwLock
- /// is poisoned whenever a writer panics while holding an exclusive lock. An
- /// error will only be returned if the lock would have otherwise been
+ /// This function will return the [`Poisoned`] error if the RwLock is poisoned.
+ /// An RwLock is poisoned whenever a writer panics while holding an exclusive
+ /// lock. `Poisoned` will only be returned if the lock would have otherwise been
/// acquired.
///
+ /// This function will return the [`WouldBlock`] error if the RwLock could not
+ /// be acquired because it was already locked exclusively.
+ ///
+ /// [`Poisoned`]: TryLockError::Poisoned
+ /// [`WouldBlock`]: TryLockError::WouldBlock
+ ///
/// # Examples
///
/// ```
///
/// # Errors
///
- /// This function will return an error if the RwLock is poisoned. An RwLock
- /// is poisoned whenever a writer panics while holding an exclusive lock. An
- /// error will only be returned if the lock would have otherwise been
- /// acquired.
+ /// This function will return the [`Poisoned`] error if the RwLock is
+ /// poisoned. An RwLock is poisoned whenever a writer panics while holding
+ /// an exclusive lock. `Poisoned` will only be returned if the lock would have
+ /// otherwise been acquired.
+ ///
+ /// This function will return the [`WouldBlock`] error if the RwLock could not
+ /// be acquired because it was already locked exclusively.
+ ///
+ /// [`Poisoned`]: TryLockError::Poisoned
+ /// [`WouldBlock`]: TryLockError::WouldBlock
+ ///
///
/// # Examples
///
where
T: Sized,
{
- // We know statically that there are no outstanding references to
- // `self` so there's no need to lock the inner lock.
- //
- // To get the inner value, we'd like to call `data.into_inner()`,
- // but because `RwLock` impl-s `Drop`, we can't move out of it, so
- // we'll have to destructure it manually instead.
- unsafe {
- // Like `let RwLock { inner, poison, data } = self`.
- let (inner, poison, data) = {
- let RwLock { ref inner, ref poison, ref data } = self;
- (ptr::read(inner), ptr::read(poison), ptr::read(data))
- };
- mem::forget(self);
- inner.destroy(); // Keep in sync with the `Drop` impl.
- drop(inner);
-
- poison::map_result(poison.borrow(), |_| data.into_inner())
- }
+ let data = self.data.into_inner();
+ poison::map_result(self.poison.borrow(), |_| data)
}
/// Returns a mutable reference to the underlying data.
}
}
-#[stable(feature = "rust1", since = "1.0.0")]
-unsafe impl<#[may_dangle] T: ?Sized> Drop for RwLock<T> {
- fn drop(&mut self) {
- // IMPORTANT: This code needs to be kept in sync with `RwLock::into_inner`.
- unsafe { self.inner.destroy() }
- }
-}
-
#[stable(feature = "rust1", since = "1.0.0")]
impl<T: ?Sized + fmt::Debug> fmt::Debug for RwLock<T> {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
state: UnsafeCell<State>,
}
+pub type MovableRWLock = Box<RWLock>;
+
enum State {
Unlocked,
Reading(usize),
writer: SpinMutex<WaitVariable<bool>>,
}
+pub type MovableRWLock = Box<RWLock>;
+
// Check at compile time that RWLock size matches C definition (see test_c_rwlock_initializer below)
//
// # Safety
if #[cfg(target_os = "android")] {
#[link(name = "dl")]
#[link(name = "log")]
- #[link(name = "gcc")]
extern "C" {}
} else if #[cfg(target_os = "freebsd")] {
#[link(name = "execinfo")]
target_os = "illumos",
target_os = "linux",
target_os = "netbsd",
- target_os = "opensbd",
+ target_os = "openbsd",
))] {
// On platforms that support it we pass the SOCK_CLOEXEC
// flag to atomically create the socket and set it as
target_os = "illumos",
target_os = "linux",
target_os = "netbsd",
- target_os = "opensbd",
+ target_os = "openbsd",
))] {
// Like above, set cloexec atomically
cvt(libc::socketpair(fam, ty | libc::SOCK_CLOEXEC, 0, fds.as_mut_ptr()))?;
target_os = "illumos",
target_os = "linux",
target_os = "netbsd",
- target_os = "opensbd",
+ target_os = "openbsd",
))] {
let fd = cvt_r(|| unsafe {
libc::accept4(self.0.raw(), storage, len, libc::SOCK_CLOEXEC)
use crate::sys::cvt;
use crate::sys::fd;
use crate::sys::memchr;
-use crate::sys::rwlock::{RWLockReadGuard, StaticRWLock};
-use crate::sys_common::mutex::{StaticMutex, StaticMutexGuard};
+use crate::sys_common::rwlock::{StaticRWLock, StaticRWLockReadGuard};
use crate::vec;
use libc::{c_char, c_int, c_void};
static ENV_LOCK: StaticRWLock = StaticRWLock::new();
-pub fn env_read_lock() -> RWLockReadGuard {
- ENV_LOCK.read_with_guard()
+pub fn env_read_lock() -> StaticRWLockReadGuard {
+ ENV_LOCK.read()
}
/// Returns a vector of (variable, value) byte-vector pairs for all the
let v = CString::new(v.as_bytes())?;
unsafe {
- let _guard = ENV_LOCK.write_with_guard();
+ let _guard = ENV_LOCK.write();
cvt(libc::setenv(k.as_ptr(), v.as_ptr(), 1)).map(drop)
}
}
let nbuf = CString::new(n.as_bytes())?;
unsafe {
- let _guard = ENV_LOCK.write_with_guard();
+ let _guard = ENV_LOCK.write();
cvt(libc::unsetenv(nbuf.as_ptr())).map(drop)
}
}
num_readers: AtomicUsize,
}
+pub type MovableRWLock = Box<RWLock>;
+
unsafe impl Send for RWLock {}
unsafe impl Sync for RWLock {}
}
}
}
-
-pub struct StaticRWLock(RWLock);
-
-impl StaticRWLock {
- pub const fn new() -> StaticRWLock {
- StaticRWLock(RWLock::new())
- }
-
- /// Acquires shared access to the underlying lock, blocking the current
- /// thread to do so.
- ///
- /// The lock is automatically unlocked when the returned guard is dropped.
- #[inline]
- pub fn read_with_guard(&'static self) -> RWLockReadGuard {
- // SAFETY: All methods require static references, therefore self
- // cannot be moved between invocations.
- unsafe {
- self.0.read();
- }
- RWLockReadGuard(&self.0)
- }
-
- /// Acquires write access to the underlying lock, blocking the current thread
- /// to do so.
- ///
- /// The lock is automatically unlocked when the returned guard is dropped.
- #[inline]
- pub fn write_with_guard(&'static self) -> RWLockWriteGuard {
- // SAFETY: All methods require static references, therefore self
- // cannot be moved between invocations.
- unsafe {
- self.0.write();
- }
- RWLockWriteGuard(&self.0)
- }
-}
-
-pub struct RWLockReadGuard(&'static RWLock);
-
-impl Drop for RWLockReadGuard {
- fn drop(&mut self) {
- unsafe { self.0.read_unlock() }
- }
-}
-
-pub struct RWLockWriteGuard(&'static RWLock);
-
-impl Drop for RWLockWriteGuard {
- fn drop(&mut self) {
- unsafe { self.0.write_unlock() }
- }
-}
mode: Cell<isize>,
}
+pub type MovableRWLock = RWLock;
+
unsafe impl Send for RWLock {}
unsafe impl Sync for RWLock {} // no threads on this platform
state: UnsafeCell<State>,
}
+pub type MovableRWLock = RWLock;
+
enum State {
Unlocked,
Reading(usize),
pub const SD_SEND: c_int = 1;
pub const SOCK_DGRAM: c_int = 2;
pub const SOCK_STREAM: c_int = 1;
+pub const SOCKET_ERROR: c_int = -1;
pub const SOL_SOCKET: c_int = 0xffff;
pub const SO_RCVTIMEO: c_int = 0x1006;
pub const SO_SNDTIMEO: c_int = 0x1005;
use crate::sys_common::{AsInner, FromInner, IntoInner};
use crate::time::Duration;
-use libc::{c_int, c_long, c_ulong, c_void};
+use libc::{c_int, c_long, c_ulong};
pub type wrlen_t = i32;
impl Socket {
pub fn new(addr: &SocketAddr, ty: c_int) -> io::Result<Socket> {
- let fam = match *addr {
+ let family = match *addr {
SocketAddr::V4(..) => c::AF_INET,
SocketAddr::V6(..) => c::AF_INET6,
};
let socket = unsafe {
- match c::WSASocketW(
- fam,
+ c::WSASocketW(
+ family,
ty,
0,
ptr::null_mut(),
0,
c::WSA_FLAG_OVERLAPPED | c::WSA_FLAG_NO_HANDLE_INHERIT,
- ) {
- c::INVALID_SOCKET => match c::WSAGetLastError() {
- c::WSAEPROTOTYPE | c::WSAEINVAL => {
- match c::WSASocketW(fam, ty, 0, ptr::null_mut(), 0, c::WSA_FLAG_OVERLAPPED)
- {
- c::INVALID_SOCKET => Err(last_error()),
- n => {
- let s = Socket(n);
- s.set_no_inherit()?;
- Ok(s)
- }
- }
- }
- n => Err(io::Error::from_raw_os_error(n)),
- },
- n => Ok(Socket(n)),
+ )
+ };
+
+ if socket != c::INVALID_SOCKET {
+ Ok(Self(socket))
+ } else {
+ let error = unsafe { c::WSAGetLastError() };
+
+ if error != c::WSAEPROTOTYPE && error != c::WSAEINVAL {
+ return Err(io::Error::from_raw_os_error(error));
+ }
+
+ let socket =
+ unsafe { c::WSASocketW(family, ty, 0, ptr::null_mut(), 0, c::WSA_FLAG_OVERLAPPED) };
+
+ if socket == c::INVALID_SOCKET {
+ return Err(last_error());
}
- }?;
- Ok(socket)
+
+ let socket = Self(socket);
+ socket.set_no_inherit()?;
+ Ok(socket)
+ }
}
pub fn connect_timeout(&self, addr: &SocketAddr, timeout: Duration) -> io::Result<()> {
self.set_nonblocking(true)?;
- let r = unsafe {
+ let result = {
let (addrp, len) = addr.into_inner();
- cvt(c::connect(self.0, addrp, len))
+ let result = unsafe { c::connect(self.0, addrp, len) };
+ cvt(result).map(drop)
};
self.set_nonblocking(false)?;
- match r {
- Ok(_) => return Ok(()),
- Err(ref e) if e.kind() == io::ErrorKind::WouldBlock => {}
- Err(e) => return Err(e),
- }
-
- if timeout.as_secs() == 0 && timeout.subsec_nanos() == 0 {
- return Err(io::Error::new_const(
- io::ErrorKind::InvalidInput,
- &"cannot set a 0 duration timeout",
- ));
- }
-
- let mut timeout = c::timeval {
- tv_sec: timeout.as_secs() as c_long,
- tv_usec: (timeout.subsec_nanos() / 1000) as c_long,
- };
- if timeout.tv_sec == 0 && timeout.tv_usec == 0 {
- timeout.tv_usec = 1;
- }
+ match result {
+ Err(ref error) if error.kind() == io::ErrorKind::WouldBlock => {
+ if timeout.as_secs() == 0 && timeout.subsec_nanos() == 0 {
+ return Err(io::Error::new_const(
+ io::ErrorKind::InvalidInput,
+ &"cannot set a 0 duration timeout",
+ ));
+ }
- let fds = unsafe {
- let mut fds = mem::zeroed::<c::fd_set>();
- fds.fd_count = 1;
- fds.fd_array[0] = self.0;
- fds
- };
+ let mut timeout = c::timeval {
+ tv_sec: timeout.as_secs() as c_long,
+ tv_usec: (timeout.subsec_nanos() / 1000) as c_long,
+ };
- let mut writefds = fds;
- let mut errorfds = fds;
+ if timeout.tv_sec == 0 && timeout.tv_usec == 0 {
+ timeout.tv_usec = 1;
+ }
- let n =
- unsafe { cvt(c::select(1, ptr::null_mut(), &mut writefds, &mut errorfds, &timeout))? };
+ let fds = {
+ let mut fds = unsafe { mem::zeroed::<c::fd_set>() };
+ fds.fd_count = 1;
+ fds.fd_array[0] = self.0;
+ fds
+ };
+
+ let mut writefds = fds;
+ let mut errorfds = fds;
+
+ let count = {
+ let result = unsafe {
+ c::select(1, ptr::null_mut(), &mut writefds, &mut errorfds, &timeout)
+ };
+ cvt(result)?
+ };
+
+ match count {
+ 0 => {
+ Err(io::Error::new_const(io::ErrorKind::TimedOut, &"connection timed out"))
+ }
+ _ => {
+ if writefds.fd_count != 1 {
+ if let Some(e) = self.take_error()? {
+ return Err(e);
+ }
+ }
- match n {
- 0 => Err(io::Error::new_const(io::ErrorKind::TimedOut, &"connection timed out")),
- _ => {
- if writefds.fd_count != 1 {
- if let Some(e) = self.take_error()? {
- return Err(e);
+ Ok(())
}
}
- Ok(())
}
+ _ => result,
}
}
pub fn accept(&self, storage: *mut c::SOCKADDR, len: *mut c_int) -> io::Result<Socket> {
- let socket = unsafe {
- match c::accept(self.0, storage, len) {
- c::INVALID_SOCKET => Err(last_error()),
- n => Ok(Socket(n)),
- }
- }?;
- Ok(socket)
+ let socket = unsafe { c::accept(self.0, storage, len) };
+
+ match socket {
+ c::INVALID_SOCKET => Err(last_error()),
+ _ => Ok(Self(socket)),
+ }
}
pub fn duplicate(&self) -> io::Result<Socket> {
+ let mut info = unsafe { mem::zeroed::<c::WSAPROTOCOL_INFO>() };
+ let result = unsafe { c::WSADuplicateSocketW(self.0, c::GetCurrentProcessId(), &mut info) };
+ cvt(result)?;
let socket = unsafe {
- let mut info: c::WSAPROTOCOL_INFO = mem::zeroed();
- cvt(c::WSADuplicateSocketW(self.0, c::GetCurrentProcessId(), &mut info))?;
-
- match c::WSASocketW(
+ c::WSASocketW(
info.iAddressFamily,
info.iSocketType,
info.iProtocol,
&mut info,
0,
c::WSA_FLAG_OVERLAPPED | c::WSA_FLAG_NO_HANDLE_INHERIT,
- ) {
- c::INVALID_SOCKET => match c::WSAGetLastError() {
- c::WSAEPROTOTYPE | c::WSAEINVAL => {
- match c::WSASocketW(
- info.iAddressFamily,
- info.iSocketType,
- info.iProtocol,
- &mut info,
- 0,
- c::WSA_FLAG_OVERLAPPED,
- ) {
- c::INVALID_SOCKET => Err(last_error()),
- n => {
- let s = Socket(n);
- s.set_no_inherit()?;
- Ok(s)
- }
- }
- }
- n => Err(io::Error::from_raw_os_error(n)),
- },
- n => Ok(Socket(n)),
+ )
+ };
+
+ if socket != c::INVALID_SOCKET {
+ Ok(Self(socket))
+ } else {
+ let error = unsafe { c::WSAGetLastError() };
+
+ if error != c::WSAEPROTOTYPE && error != c::WSAEINVAL {
+ return Err(io::Error::from_raw_os_error(error));
+ }
+
+ let socket = unsafe {
+ c::WSASocketW(
+ info.iAddressFamily,
+ info.iSocketType,
+ info.iProtocol,
+ &mut info,
+ 0,
+ c::WSA_FLAG_OVERLAPPED,
+ )
+ };
+
+ if socket == c::INVALID_SOCKET {
+ return Err(last_error());
}
- }?;
- Ok(socket)
+
+ let socket = Self(socket);
+ socket.set_no_inherit()?;
+ Ok(socket)
+ }
}
fn recv_with_flags(&self, buf: &mut [u8], flags: c_int) -> io::Result<usize> {
// On unix when a socket is shut down all further reads return 0, so we
// do the same on windows to map a shut down socket to returning EOF.
- let len = cmp::min(buf.len(), i32::MAX as usize) as i32;
- unsafe {
- match c::recv(self.0, buf.as_mut_ptr() as *mut c_void, len, flags) {
- -1 if c::WSAGetLastError() == c::WSAESHUTDOWN => Ok(0),
- -1 => Err(last_error()),
- n => Ok(n as usize),
+ let length = cmp::min(buf.len(), i32::MAX as usize) as i32;
+ let result = unsafe { c::recv(self.0, buf.as_mut_ptr() as *mut _, length, flags) };
+
+ match result {
+ c::SOCKET_ERROR => {
+ let error = unsafe { c::WSAGetLastError() };
+
+ if error == c::WSAESHUTDOWN {
+ Ok(0)
+ } else {
+ Err(io::Error::from_raw_os_error(error))
+ }
}
+ _ => Ok(result as usize),
}
}
pub fn read_vectored(&self, bufs: &mut [IoSliceMut<'_>]) -> io::Result<usize> {
// On unix when a socket is shut down all further reads return 0, so we
// do the same on windows to map a shut down socket to returning EOF.
- let len = cmp::min(bufs.len(), c::DWORD::MAX as usize) as c::DWORD;
+ let length = cmp::min(bufs.len(), c::DWORD::MAX as usize) as c::DWORD;
let mut nread = 0;
let mut flags = 0;
- unsafe {
- let ret = c::WSARecv(
+ let result = unsafe {
+ c::WSARecv(
self.0,
bufs.as_mut_ptr() as *mut c::WSABUF,
- len,
+ length,
&mut nread,
&mut flags,
ptr::null_mut(),
ptr::null_mut(),
- );
- match ret {
- 0 => Ok(nread as usize),
- _ if c::WSAGetLastError() == c::WSAESHUTDOWN => Ok(0),
- _ => Err(last_error()),
+ )
+ };
+
+ match result {
+ 0 => Ok(nread as usize),
+ _ => {
+ let error = unsafe { c::WSAGetLastError() };
+
+ if error == c::WSAESHUTDOWN {
+ Ok(0)
+ } else {
+ Err(io::Error::from_raw_os_error(error))
+ }
}
}
}
buf: &mut [u8],
flags: c_int,
) -> io::Result<(usize, SocketAddr)> {
- let mut storage: c::SOCKADDR_STORAGE_LH = unsafe { mem::zeroed() };
+ let mut storage = unsafe { mem::zeroed::<c::SOCKADDR_STORAGE_LH>() };
let mut addrlen = mem::size_of_val(&storage) as c::socklen_t;
- let len = cmp::min(buf.len(), <wrlen_t>::MAX as usize) as wrlen_t;
+ let length = cmp::min(buf.len(), <wrlen_t>::MAX as usize) as wrlen_t;
// On unix when a socket is shut down all further reads return 0, so we
// do the same on windows to map a shut down socket to returning EOF.
- unsafe {
- match c::recvfrom(
+ let result = unsafe {
+ c::recvfrom(
self.0,
- buf.as_mut_ptr() as *mut c_void,
- len,
+ buf.as_mut_ptr() as *mut _,
+ length,
flags,
&mut storage as *mut _ as *mut _,
&mut addrlen,
- ) {
- -1 if c::WSAGetLastError() == c::WSAESHUTDOWN => {
+ )
+ };
+
+ match result {
+ c::SOCKET_ERROR => {
+ let error = unsafe { c::WSAGetLastError() };
+
+ if error == c::WSAESHUTDOWN {
Ok((0, net::sockaddr_to_addr(&storage, addrlen as usize)?))
+ } else {
+ Err(io::Error::from_raw_os_error(error))
}
- -1 => Err(last_error()),
- n => Ok((n as usize, net::sockaddr_to_addr(&storage, addrlen as usize)?)),
}
+ _ => Ok((result as usize, net::sockaddr_to_addr(&storage, addrlen as usize)?)),
}
}
}
pub fn write_vectored(&self, bufs: &[IoSlice<'_>]) -> io::Result<usize> {
- let len = cmp::min(bufs.len(), c::DWORD::MAX as usize) as c::DWORD;
+ let length = cmp::min(bufs.len(), c::DWORD::MAX as usize) as c::DWORD;
let mut nwritten = 0;
- unsafe {
- cvt(c::WSASend(
+ let result = unsafe {
+ c::WSASend(
self.0,
- bufs.as_ptr() as *const c::WSABUF as *mut c::WSABUF,
- len,
+ bufs.as_ptr() as *const c::WSABUF as *mut _,
+ length,
&mut nwritten,
0,
ptr::null_mut(),
ptr::null_mut(),
- ))?;
- }
- Ok(nwritten as usize)
+ )
+ };
+ cvt(result).map(|_| nwritten as usize)
}
#[inline]
Shutdown::Read => c::SD_RECEIVE,
Shutdown::Both => c::SD_BOTH,
};
- cvt(unsafe { c::shutdown(self.0, how) })?;
- Ok(())
+ let result = unsafe { c::shutdown(self.0, how) };
+ cvt(result).map(drop)
}
pub fn set_nonblocking(&self, nonblocking: bool) -> io::Result<()> {
let mut nonblocking = nonblocking as c_ulong;
- let r = unsafe { c::ioctlsocket(self.0, c::FIONBIO as c_int, &mut nonblocking) };
- if r == 0 { Ok(()) } else { Err(io::Error::last_os_error()) }
+ let result = unsafe { c::ioctlsocket(self.0, c::FIONBIO as c_int, &mut nonblocking) };
+ cvt(result).map(drop)
}
pub fn set_nodelay(&self, nodelay: bool) -> io::Result<()> {
inner: UnsafeCell<c::SRWLOCK>,
}
+pub type MovableRWLock = RWLock;
+
unsafe impl Send for RWLock {}
unsafe impl Sync for RWLock {}
use crate::sys::rwlock as imp;
+/// An OS-based reader-writer lock, meant for use in static variables.
+///
+/// This rwlock does not implement poisoning.
+///
+/// This rwlock has a const constructor ([`StaticRWLock::new`]), does not
+/// implement `Drop` to cleanup resources.
+pub struct StaticRWLock(imp::RWLock);
+
+impl StaticRWLock {
+ /// Creates a new rwlock for use.
+ pub const fn new() -> Self {
+ Self(imp::RWLock::new())
+ }
+
+ /// Acquires shared access to the underlying lock, blocking the current
+ /// thread to do so.
+ ///
+ /// The lock is automatically unlocked when the returned guard is dropped.
+ #[inline]
+ pub fn read(&'static self) -> StaticRWLockReadGuard {
+ unsafe { self.0.read() };
+ StaticRWLockReadGuard(&self.0)
+ }
+
+ /// Acquires write access to the underlying lock, blocking the current thread
+ /// to do so.
+ ///
+ /// The lock is automatically unlocked when the returned guard is dropped.
+ #[inline]
+ pub fn write(&'static self) -> StaticRWLockWriteGuard {
+ unsafe { self.0.write() };
+ StaticRWLockWriteGuard(&self.0)
+ }
+}
+
+#[must_use]
+pub struct StaticRWLockReadGuard(&'static imp::RWLock);
+
+impl Drop for StaticRWLockReadGuard {
+ #[inline]
+ fn drop(&mut self) {
+ unsafe {
+ self.0.read_unlock();
+ }
+ }
+}
+
+#[must_use]
+pub struct StaticRWLockWriteGuard(&'static imp::RWLock);
+
+impl Drop for StaticRWLockWriteGuard {
+ #[inline]
+ fn drop(&mut self) {
+ unsafe {
+ self.0.write_unlock();
+ }
+ }
+}
+
/// An OS-based reader-writer lock.
///
-/// This structure is entirely unsafe and serves as the lowest layer of a
-/// cross-platform binding of system rwlocks. It is recommended to use the
-/// safer types at the top level of this crate instead of this type.
-pub struct RWLock(imp::RWLock);
+/// This rwlock does *not* have a const constructor, cleans up its resources in
+/// its `Drop` implementation and may safely be moved (when not borrowed).
+///
+/// This rwlock does not implement poisoning.
+///
+/// This is either a wrapper around `Box<imp::RWLock>` or `imp::RWLock`,
+/// depending on the platform. It is boxed on platforms where `imp::RWLock` may
+/// not be moved.
+pub struct MovableRWLock(imp::MovableRWLock);
-impl RWLock {
+impl MovableRWLock {
/// Creates a new reader-writer lock for use.
- ///
- /// Behavior is undefined if the reader-writer lock is moved after it is
- /// first used with any of the functions below.
- pub const fn new() -> RWLock {
- RWLock(imp::RWLock::new())
+ pub fn new() -> Self {
+ Self(imp::MovableRWLock::from(imp::RWLock::new()))
}
/// Acquires shared access to the underlying lock, blocking the current
/// thread to do so.
- ///
- /// Behavior is undefined if the rwlock has been moved between this and any
- /// previous method call.
#[inline]
- pub unsafe fn read(&self) {
- self.0.read()
+ pub fn read(&self) {
+ unsafe { self.0.read() }
}
/// Attempts to acquire shared access to this lock, returning whether it
/// succeeded or not.
///
/// This function does not block the current thread.
- ///
- /// Behavior is undefined if the rwlock has been moved between this and any
- /// previous method call.
#[inline]
- pub unsafe fn try_read(&self) -> bool {
- self.0.try_read()
+ pub fn try_read(&self) -> bool {
+ unsafe { self.0.try_read() }
}
/// Acquires write access to the underlying lock, blocking the current thread
/// to do so.
- ///
- /// Behavior is undefined if the rwlock has been moved between this and any
- /// previous method call.
#[inline]
- pub unsafe fn write(&self) {
- self.0.write()
+ pub fn write(&self) {
+ unsafe { self.0.write() }
}
/// Attempts to acquire exclusive access to this lock, returning whether it
/// succeeded or not.
///
/// This function does not block the current thread.
- ///
- /// Behavior is undefined if the rwlock has been moved between this and any
- /// previous method call.
#[inline]
- pub unsafe fn try_write(&self) -> bool {
- self.0.try_write()
+ pub fn try_write(&self) -> bool {
+ unsafe { self.0.try_write() }
}
/// Unlocks previously acquired shared access to this lock.
pub unsafe fn write_unlock(&self) {
self.0.write_unlock()
}
+}
- /// Destroys OS-related resources with this RWLock.
- ///
- /// Behavior is undefined if there are any currently active users of this
- /// lock.
- #[inline]
- pub unsafe fn destroy(&self) {
- self.0.destroy()
+impl Drop for MovableRWLock {
+ fn drop(&mut self) {
+ unsafe { self.0.destroy() };
}
}
/// Currently, the following system calls are being used to get the current time using `now()`:
///
/// | Platform | System call |
-/// |:---------:|:--------------------------------------------------------------------:|
+/// |-----------|----------------------------------------------------------------------|
/// | SGX | [`insecure_time` usercall]. More information on [timekeeping in SGX] |
/// | UNIX | [clock_gettime (Monotonic Clock)] |
/// | Darwin | [mach_absolute_time] |
/// Currently, the following system calls are being used to get the current time using `now()`:
///
/// | Platform | System call |
-/// |:---------:|:--------------------------------------------------------------------:|
+/// |-----------|----------------------------------------------------------------------|
/// | SGX | [`insecure_time` usercall]. More information on [timekeeping in SGX] |
/// | UNIX | [clock_gettime (Realtime Clock)] |
/// | Darwin | [gettimeofday] |
-Subproject commit 37d6e1886369ea0176356286dc7fbd42ee5aa79c
+Subproject commit 3001c75a1d2a81d2a76bef139c69387cb2ebb820
//! [win]: https://docs.microsoft.com/en-us/windows/console/character-mode-applications
//! [ti]: https://en.wikipedia.org/wiki/Terminfo
-#![doc(
- html_root_url = "https://doc.rust-lang.org/nightly/",
- html_playground_url = "https://play.rust-lang.org/",
- test(attr(deny(warnings)))
-)]
+#![doc(html_playground_url = "https://play.rust-lang.org/", test(attr(deny(warnings))))]
#![deny(missing_docs)]
#![cfg_attr(windows, feature(libc))]
"Configure formatting of output:
pretty = Print verbose output;
terse = Display one character per test;
- json = Output a json document",
- "pretty|terse|json",
+ json = Output a json document;
+ junit = Output a JUnit document",
+ "pretty|terse|json|junit",
)
.optflag("", "show-output", "Show captured stdout of successful tests")
.optopt(
}
OutputFormat::Json
}
-
+ Some("junit") => {
+ if !allow_unstable {
+ return Err("The \"junit\" format is only accepted on the nightly compiler".into());
+ }
+ OutputFormat::Junit
+ }
Some(v) => {
return Err(format!(
- "argument for --format must be pretty, terse, or json (was \
+ "argument for --format must be pretty, terse, json or junit (was \
{})",
v
));
cli::TestOpts,
event::{CompletedTest, TestEvent},
filter_tests,
- formatters::{JsonFormatter, OutputFormatter, PrettyFormatter, TerseFormatter},
+ formatters::{JsonFormatter, JunitFormatter, OutputFormatter, PrettyFormatter, TerseFormatter},
helpers::{concurrency::get_concurrency, metrics::MetricMap},
options::{Options, OutputFormat},
run_tests,
Box::new(TerseFormatter::new(output, opts.use_color(), max_name_len, is_multithreaded))
}
OutputFormat::Json => Box::new(JsonFormatter::new(output)),
+ OutputFormat::Junit => Box::new(JunitFormatter::new(output)),
};
let mut st = ConsoleTestState::new(opts)?;
--- /dev/null
+use std::io::{self, prelude::Write};
+use std::time::Duration;
+
+use super::OutputFormatter;
+use crate::{
+ console::{ConsoleTestState, OutputLocation},
+ test_result::TestResult,
+ time,
+ types::{TestDesc, TestType},
+};
+
+pub struct JunitFormatter<T> {
+ out: OutputLocation<T>,
+ results: Vec<(TestDesc, TestResult, Duration)>,
+}
+
+impl<T: Write> JunitFormatter<T> {
+ pub fn new(out: OutputLocation<T>) -> Self {
+ Self { out, results: Vec::new() }
+ }
+
+ fn write_message(&mut self, s: &str) -> io::Result<()> {
+ assert!(!s.contains('\n'));
+
+ self.out.write_all(s.as_ref())
+ }
+}
+
+impl<T: Write> OutputFormatter for JunitFormatter<T> {
+ fn write_run_start(&mut self, _test_count: usize) -> io::Result<()> {
+ // We write xml header on run start
+ self.write_message(&"<?xml version=\"1.0\" encoding=\"UTF-8\"?>")
+ }
+
+ fn write_test_start(&mut self, _desc: &TestDesc) -> io::Result<()> {
+ // We do not output anything on test start.
+ Ok(())
+ }
+
+ fn write_timeout(&mut self, _desc: &TestDesc) -> io::Result<()> {
+ // We do not output anything on test timeout.
+ Ok(())
+ }
+
+ fn write_result(
+ &mut self,
+ desc: &TestDesc,
+ result: &TestResult,
+ exec_time: Option<&time::TestExecTime>,
+ _stdout: &[u8],
+ _state: &ConsoleTestState,
+ ) -> io::Result<()> {
+ // Because the testsuit node holds some of the information as attributes, we can't write it
+ // until all of the tests has ran. Instead of writting every result as they come in, we add
+ // them to a Vec and write them all at once when run is complete.
+ let duration = exec_time.map(|t| t.0.clone()).unwrap_or_default();
+ self.results.push((desc.clone(), result.clone(), duration));
+ Ok(())
+ }
+ fn write_run_finish(&mut self, state: &ConsoleTestState) -> io::Result<bool> {
+ self.write_message("<testsuites>")?;
+
+ self.write_message(&*format!(
+ "<testsuite name=\"test\" package=\"test\" id=\"0\" \
+ errors=\"0\" \
+ failures=\"{}\" \
+ tests=\"{}\" \
+ skipped=\"{}\" \
+ >",
+ state.failed, state.total, state.ignored
+ ))?;
+ for (desc, result, duration) in std::mem::replace(&mut self.results, Vec::new()) {
+ let (class_name, test_name) = parse_class_name(&desc);
+ match result {
+ TestResult::TrIgnored => { /* no-op */ }
+ TestResult::TrFailed => {
+ self.write_message(&*format!(
+ "<testcase classname=\"{}\" \
+ name=\"{}\" time=\"{}\">",
+ class_name,
+ test_name,
+ duration.as_secs()
+ ))?;
+ self.write_message("<failure type=\"assert\"/>")?;
+ self.write_message("</testcase>")?;
+ }
+
+ TestResult::TrFailedMsg(ref m) => {
+ self.write_message(&*format!(
+ "<testcase classname=\"{}\" \
+ name=\"{}\" time=\"{}\">",
+ class_name,
+ test_name,
+ duration.as_secs()
+ ))?;
+ self.write_message(&*format!("<failure message=\"{}\" type=\"assert\"/>", m))?;
+ self.write_message("</testcase>")?;
+ }
+
+ TestResult::TrTimedFail => {
+ self.write_message(&*format!(
+ "<testcase classname=\"{}\" \
+ name=\"{}\" time=\"{}\">",
+ class_name,
+ test_name,
+ duration.as_secs()
+ ))?;
+ self.write_message("<failure type=\"timeout\"/>")?;
+ self.write_message("</testcase>")?;
+ }
+
+ TestResult::TrBench(ref b) => {
+ self.write_message(&*format!(
+ "<testcase classname=\"benchmark::{}\" \
+ name=\"{}\" time=\"{}\" />",
+ class_name, test_name, b.ns_iter_summ.sum
+ ))?;
+ }
+
+ TestResult::TrOk | TestResult::TrAllowedFail => {
+ self.write_message(&*format!(
+ "<testcase classname=\"{}\" \
+ name=\"{}\" time=\"{}\"/>",
+ class_name,
+ test_name,
+ duration.as_secs()
+ ))?;
+ }
+ }
+ }
+ self.write_message("<system-out/>")?;
+ self.write_message("<system-err/>")?;
+ self.write_message("</testsuite>")?;
+ self.write_message("</testsuites>")?;
+
+ Ok(state.failed == 0)
+ }
+}
+
+fn parse_class_name(desc: &TestDesc) -> (String, String) {
+ match desc.test_type {
+ TestType::UnitTest => parse_class_name_unit(desc),
+ TestType::DocTest => parse_class_name_doc(desc),
+ TestType::IntegrationTest => parse_class_name_integration(desc),
+ TestType::Unknown => (String::from("unknown"), String::from(desc.name.as_slice())),
+ }
+}
+
+fn parse_class_name_unit(desc: &TestDesc) -> (String, String) {
+ // Module path => classname
+ // Function name => name
+ let module_segments: Vec<&str> = desc.name.as_slice().split("::").collect();
+ let (class_name, test_name) = match module_segments[..] {
+ [test] => (String::from("crate"), String::from(test)),
+ [ref path @ .., test] => (path.join("::"), String::from(test)),
+ [..] => unreachable!(),
+ };
+ (class_name, test_name)
+}
+
+fn parse_class_name_doc(desc: &TestDesc) -> (String, String) {
+ // File path => classname
+ // Line # => test name
+ let segments: Vec<&str> = desc.name.as_slice().split(" - ").collect();
+ let (class_name, test_name) = match segments[..] {
+ [file, line] => (String::from(file.trim()), String::from(line.trim())),
+ [..] => unreachable!(),
+ };
+ (class_name, test_name)
+}
+
+fn parse_class_name_integration(desc: &TestDesc) -> (String, String) {
+ (String::from("integration"), String::from(desc.name.as_slice()))
+}
};
mod json;
+mod junit;
mod pretty;
mod terse;
pub(crate) use self::json::JsonFormatter;
+pub(crate) use self::junit::JunitFormatter;
pub(crate) use self::pretty::PrettyFormatter;
pub(crate) use self::terse::TerseFormatter;
fn write_test_name(&mut self, desc: &TestDesc) -> io::Result<()> {
let name = desc.padded_name(self.max_name_len, desc.name.padding());
- self.write_plain(&format!("test {} ... ", name))?;
+ if let Some(test_mode) = desc.test_mode() {
+ self.write_plain(&format!("test {} - {} ... ", name, test_mode))?;
+ } else {
+ self.write_plain(&format!("test {} ... ", name))?;
+ }
Ok(())
}
fn write_test_name(&mut self, desc: &TestDesc) -> io::Result<()> {
let name = desc.padded_name(self.max_name_len, desc.name.padding());
- self.write_plain(&format!("test {} ... ", name))?;
+ if let Some(test_mode) = desc.test_mode() {
+ self.write_plain(&format!("test {} - {} ... ", name, test_mode))?;
+ } else {
+ self.write_plain(&format!("test {} ... ", name))?;
+ }
Ok(())
}
#![crate_name = "test"]
#![unstable(feature = "test", issue = "50297")]
-#![doc(html_root_url = "https://doc.rust-lang.org/nightly/", test(attr(deny(warnings))))]
+#![doc(test(attr(deny(warnings))))]
#![cfg_attr(unix, feature(libc))]
#![feature(rustc_private)]
#![feature(nll)]
Terse,
/// JSON output
Json,
+ /// JUnit output
+ Junit,
}
/// Whether ignored test should be run or not
ignore: true,
should_panic: ShouldPanic::No,
allow_fail: false,
+ #[cfg(not(bootstrap))]
+ compile_fail: false,
+ #[cfg(not(bootstrap))]
+ no_run: false,
test_type: TestType::Unknown,
},
testfn: DynTestFn(Box::new(move || {})),
ignore: false,
should_panic: ShouldPanic::No,
allow_fail: false,
+ #[cfg(not(bootstrap))]
+ compile_fail: false,
+ #[cfg(not(bootstrap))]
+ no_run: false,
test_type: TestType::Unknown,
},
testfn: DynTestFn(Box::new(move || {})),
ignore: true,
should_panic: ShouldPanic::No,
allow_fail: false,
+ #[cfg(not(bootstrap))]
+ compile_fail: false,
+ #[cfg(not(bootstrap))]
+ no_run: false,
test_type: TestType::Unknown,
},
testfn: DynTestFn(Box::new(f)),
ignore: true,
should_panic: ShouldPanic::No,
allow_fail: false,
+ #[cfg(not(bootstrap))]
+ compile_fail: false,
+ #[cfg(not(bootstrap))]
+ no_run: false,
test_type: TestType::Unknown,
},
testfn: DynTestFn(Box::new(f)),
ignore: false,
should_panic: ShouldPanic::Yes,
allow_fail: false,
+ #[cfg(not(bootstrap))]
+ compile_fail: false,
+ #[cfg(not(bootstrap))]
+ no_run: false,
test_type: TestType::Unknown,
},
testfn: DynTestFn(Box::new(f)),
ignore: false,
should_panic: ShouldPanic::YesWithMessage("error message"),
allow_fail: false,
+ #[cfg(not(bootstrap))]
+ compile_fail: false,
+ #[cfg(not(bootstrap))]
+ no_run: false,
test_type: TestType::Unknown,
},
testfn: DynTestFn(Box::new(f)),
ignore: false,
should_panic: ShouldPanic::YesWithMessage(expected),
allow_fail: false,
+ #[cfg(not(bootstrap))]
+ compile_fail: false,
+ #[cfg(not(bootstrap))]
+ no_run: false,
test_type: TestType::Unknown,
},
testfn: DynTestFn(Box::new(f)),
ignore: false,
should_panic: ShouldPanic::YesWithMessage(expected),
allow_fail: false,
+ #[cfg(not(bootstrap))]
+ compile_fail: false,
+ #[cfg(not(bootstrap))]
+ no_run: false,
test_type: TestType::Unknown,
},
testfn: DynTestFn(Box::new(f)),
ignore: false,
should_panic,
allow_fail: false,
+ #[cfg(not(bootstrap))]
+ compile_fail: false,
+ #[cfg(not(bootstrap))]
+ no_run: false,
test_type: TestType::Unknown,
},
testfn: DynTestFn(Box::new(f)),
ignore: false,
should_panic: ShouldPanic::No,
allow_fail: false,
+ #[cfg(not(bootstrap))]
+ compile_fail: false,
+ #[cfg(not(bootstrap))]
+ no_run: false,
test_type: TestType::Unknown,
},
testfn: DynTestFn(Box::new(f)),
ignore: false,
should_panic: ShouldPanic::No,
allow_fail: false,
+ #[cfg(not(bootstrap))]
+ compile_fail: false,
+ #[cfg(not(bootstrap))]
+ no_run: false,
test_type,
},
testfn: DynTestFn(Box::new(f)),
ignore: false,
should_panic: ShouldPanic::No,
allow_fail: false,
+ #[cfg(not(bootstrap))]
+ compile_fail: false,
+ #[cfg(not(bootstrap))]
+ no_run: false,
test_type,
}
}
ignore: false,
should_panic: ShouldPanic::Yes,
allow_fail: false,
+ #[cfg(not(bootstrap))]
+ compile_fail: false,
+ #[cfg(not(bootstrap))]
+ no_run: false,
test_type: TestType::Unknown,
},
testfn: DynTestFn(Box::new(move || {})),
ignore: false,
should_panic: ShouldPanic::No,
allow_fail: false,
+ #[cfg(not(bootstrap))]
+ compile_fail: false,
+ #[cfg(not(bootstrap))]
+ no_run: false,
test_type: TestType::Unknown,
},
testfn: DynTestFn(Box::new(move || {})),
ignore: false,
should_panic: ShouldPanic::No,
allow_fail: false,
+ #[cfg(not(bootstrap))]
+ compile_fail: false,
+ #[cfg(not(bootstrap))]
+ no_run: false,
test_type: TestType::Unknown,
},
testfn: DynTestFn(Box::new(testfn)),
ignore: false,
should_panic: ShouldPanic::No,
allow_fail: false,
+ #[cfg(not(bootstrap))]
+ compile_fail: false,
+ #[cfg(not(bootstrap))]
+ no_run: false,
test_type: TestType::Unknown,
};
ignore: false,
should_panic: ShouldPanic::No,
allow_fail: false,
+ #[cfg(not(bootstrap))]
+ compile_fail: false,
+ #[cfg(not(bootstrap))]
+ no_run: false,
test_type: TestType::Unknown,
};
ignore: false,
should_panic: ShouldPanic::No,
allow_fail: false,
+ #[cfg(not(bootstrap))]
+ compile_fail: false,
+ #[cfg(not(bootstrap))]
+ no_run: false,
test_type: TestType::Unknown,
};
ignore: false,
should_panic: ShouldPanic::No,
allow_fail: false,
+ #[cfg(not(bootstrap))]
+ compile_fail: false,
+ #[cfg(not(bootstrap))]
+ no_run: false,
test_type: TestType::Unknown,
};
pub ignore: bool,
pub should_panic: options::ShouldPanic,
pub allow_fail: bool,
+ #[cfg(not(bootstrap))]
+ pub compile_fail: bool,
+ #[cfg(not(bootstrap))]
+ pub no_run: bool,
pub test_type: TestType,
}
}
}
}
+
+ /// Returns None for ignored test or that that are just run, otherwise give a description of the type of test.
+ /// Descriptions include "should panic", "compile fail" and "compile".
+ #[cfg(not(bootstrap))]
+ pub fn test_mode(&self) -> Option<&'static str> {
+ if self.ignore {
+ return None;
+ }
+ match self.should_panic {
+ options::ShouldPanic::Yes | options::ShouldPanic::YesWithMessage(_) => {
+ return Some("should panic");
+ }
+ options::ShouldPanic::No => {}
+ }
+ if self.allow_fail {
+ return Some("allow fail");
+ }
+ if self.compile_fail {
+ return Some("compile fail");
+ }
+ if self.no_run {
+ return Some("compile");
+ }
+ None
+ }
+
+ #[cfg(bootstrap)]
+ pub fn test_mode(&self) -> Option<&'static str> {
+ None
+ }
}
#[derive(Debug)]
cfg-if = "0.1.8"
[build-dependencies]
-cc = "1.0.67"
+cc = "1.0.68"
[features]
+
+# Only applies for Linux and Fuchsia targets
+# Static link to the in-tree build of llvm libunwind
llvm-libunwind = []
+
+# Only applies for Linux and Fuchsia targets
+# If crt-static is enabled, static link to `libunwind.a` provided by system
+# If crt-static is disabled, dynamic link to `libunwind.so` provided by system
system-llvm-libunwind = []
println!("cargo:rerun-if-changed=build.rs");
let target = env::var("TARGET").expect("TARGET was not set");
- if cfg!(feature = "system-llvm-libunwind") {
+ if cfg!(target_os = "linux") && cfg!(feature = "system-llvm-libunwind") {
+ // linking for Linux is handled in lib.rs
return;
}
// linking for Linux is handled in lib.rs
if target.contains("musl") {
llvm_libunwind::compile();
+ } else if target.contains("android") {
+ let build = cc::Build::new();
+
+ // Since ndk r23 beta 3 `libgcc` was replaced with `libunwind` thus
+ // check if we have `libunwind` available and if so use it. Otherwise
+ // fall back to `libgcc` to support older ndk versions.
+ let has_unwind =
+ build.is_flag_supported("-lunwind").expect("Unable to invoke compiler");
+
+ if has_unwind {
+ println!("cargo:rustc-link-lib=unwind");
+ } else {
+ println!("cargo:rustc-link-lib=gcc");
+ }
}
} else if target.contains("freebsd") {
println!("cargo:rustc-link-lib=gcc_s");
pub fn compile() {
let target = env::var("TARGET").expect("TARGET was not set");
let target_env = env::var("CARGO_CFG_TARGET_ENV").unwrap();
- let target_vendor = env::var("CARGO_CFG_TARGET_VENDOR").unwrap();
- let target_endian_little = env::var("CARGO_CFG_TARGET_ENDIAN").unwrap() != "big";
- let cfg = &mut cc::Build::new();
-
- cfg.cpp(true);
- cfg.cpp_set_stdlib(None);
- cfg.warnings(false);
+ let mut cc_cfg = cc::Build::new();
+ let mut cpp_cfg = cc::Build::new();
+ let root = Path::new("../../src/llvm-project/libunwind");
- // libunwind expects a __LITTLE_ENDIAN__ macro to be set for LE archs, cf. #65765
- if target_endian_little {
- cfg.define("__LITTLE_ENDIAN__", Some("1"));
+ cpp_cfg.cpp(true);
+ cpp_cfg.cpp_set_stdlib(None);
+ cpp_cfg.flag("-nostdinc++");
+ cpp_cfg.flag("-fno-exceptions");
+ cpp_cfg.flag("-fno-rtti");
+ cpp_cfg.flag_if_supported("-fvisibility-global-new-delete-hidden");
+
+ // Don't set this for clang
+ // By default, Clang builds C code in GNU C17 mode.
+ // By default, Clang builds C++ code according to the C++98 standard,
+ // with many C++11 features accepted as extensions.
+ if cpp_cfg.get_compiler().is_like_gnu() {
+ cpp_cfg.flag("-std=c++11");
+ cc_cfg.flag("-std=c99");
}
- if target_env == "msvc" {
- // Don't pull in extra libraries on MSVC
- cfg.flag("/Zl");
- cfg.flag("/EHsc");
- cfg.define("_CRT_SECURE_NO_WARNINGS", None);
- cfg.define("_LIBUNWIND_DISABLE_VISIBILITY_ANNOTATIONS", None);
- } else if target.contains("x86_64-fortanix-unknown-sgx") {
- cfg.cpp(false);
-
- cfg.static_flag(true);
- cfg.opt_level(3);
-
- cfg.flag("-nostdinc++");
- cfg.flag("-fno-exceptions");
- cfg.flag("-fno-rtti");
- cfg.flag("-fstrict-aliasing");
- cfg.flag("-funwind-tables");
- cfg.flag("-fvisibility=hidden");
- cfg.flag("-fno-stack-protector");
- cfg.flag("-ffreestanding");
- cfg.flag("-fexceptions");
-
- // easiest way to undefine since no API available in cc::Build to undefine
- cfg.flag("-U_FORTIFY_SOURCE");
- cfg.define("_FORTIFY_SOURCE", "0");
-
- cfg.flag_if_supported("-fvisibility-global-new-delete-hidden");
+ if target.contains("x86_64-fortanix-unknown-sgx") || target_env == "musl" {
+ // use the same GCC C compiler command to compile C++ code so we do not need to setup the
+ // C++ compiler env variables on the builders.
+ // Don't set this for clang++, as clang++ is able to compile this without libc++.
+ if cpp_cfg.get_compiler().is_like_gnu() {
+ cpp_cfg.cpp(false);
+ }
+ }
- cfg.define("_LIBUNWIND_DISABLE_VISIBILITY_ANNOTATIONS", None);
- cfg.define("RUST_SGX", "1");
- cfg.define("__NO_STRING_INLINES", None);
- cfg.define("__NO_MATH_INLINES", None);
- cfg.define("_LIBUNWIND_IS_BAREMETAL", None);
- cfg.define("__LIBUNWIND_IS_NATIVE_ONLY", None);
- cfg.define("NDEBUG", None);
- } else {
- cfg.flag("-std=c99");
- cfg.flag("-std=c++11");
- cfg.flag("-nostdinc++");
- cfg.flag("-fno-exceptions");
- cfg.flag("-fno-rtti");
+ for cfg in [&mut cc_cfg, &mut cpp_cfg].iter_mut() {
+ cfg.warnings(false);
cfg.flag("-fstrict-aliasing");
cfg.flag("-funwind-tables");
cfg.flag("-fvisibility=hidden");
- cfg.flag_if_supported("-fvisibility-global-new-delete-hidden");
cfg.define("_LIBUNWIND_DISABLE_VISIBILITY_ANNOTATIONS", None);
+ cfg.include(root.join("include"));
+ cfg.cargo_metadata(false);
+
+ if target.contains("x86_64-fortanix-unknown-sgx") {
+ cfg.static_flag(true);
+ cfg.opt_level(3);
+ cfg.flag("-fno-stack-protector");
+ cfg.flag("-ffreestanding");
+ cfg.flag("-fexceptions");
+
+ // easiest way to undefine since no API available in cc::Build to undefine
+ cfg.flag("-U_FORTIFY_SOURCE");
+ cfg.define("_FORTIFY_SOURCE", "0");
+ cfg.define("RUST_SGX", "1");
+ cfg.define("__NO_STRING_INLINES", None);
+ cfg.define("__NO_MATH_INLINES", None);
+ cfg.define("_LIBUNWIND_IS_BAREMETAL", None);
+ cfg.define("__LIBUNWIND_IS_NATIVE_ONLY", None);
+ cfg.define("NDEBUG", None);
+ }
}
- let mut unwind_sources = vec![
- "Unwind-EHABI.cpp",
- "Unwind-seh.cpp",
+ let mut c_sources = vec![
"Unwind-sjlj.c",
"UnwindLevel1-gcc-ext.c",
"UnwindLevel1.c",
"UnwindRegistersRestore.S",
"UnwindRegistersSave.S",
- "libunwind.cpp",
];
- if target_vendor == "apple" {
- unwind_sources.push("Unwind_AppleExtras.cpp");
- }
+ let cpp_sources = vec!["Unwind-EHABI.cpp", "Unwind-seh.cpp", "libunwind.cpp"];
+ let cpp_len = cpp_sources.len();
if target.contains("x86_64-fortanix-unknown-sgx") {
- unwind_sources.push("UnwindRustSgx.c");
+ c_sources.push("UnwindRustSgx.c");
}
- let root = Path::new("../../src/llvm-project/libunwind");
- cfg.include(root.join("include"));
- for src in unwind_sources {
- cfg.file(root.join("src").join(src));
+ for src in c_sources {
+ cc_cfg.file(root.join("src").join(src).canonicalize().unwrap());
}
- if target_env == "musl" {
- // use the same C compiler command to compile C++ code so we do not need to setup the
- // C++ compiler env variables on the builders
- cfg.cpp(false);
- // linking for musl is handled in lib.rs
- cfg.cargo_metadata(false);
- println!("cargo:rustc-link-search=native={}", env::var("OUT_DIR").unwrap());
+ for src in cpp_sources {
+ cpp_cfg.file(root.join("src").join(src).canonicalize().unwrap());
}
- cfg.compile("unwind");
+ let out_dir = env::var("OUT_DIR").unwrap();
+ println!("cargo:rustc-link-search=native={}", &out_dir);
+
+ cpp_cfg.compile("unwind-cpp");
+
+ let mut count = 0;
+ for entry in std::fs::read_dir(&out_dir).unwrap() {
+ let obj = entry.unwrap().path().canonicalize().unwrap();
+ if let Some(ext) = obj.extension() {
+ if ext == "o" {
+ cc_cfg.object(&obj);
+ count += 1;
+ }
+ }
+ }
+ assert_eq!(cpp_len, count, "Can't get object files from {:?}", &out_dir);
+ cc_cfg.compile("unwind");
}
}
}
#[cfg(target_env = "musl")]
-#[link(name = "unwind", kind = "static", cfg(target_feature = "crt-static"))]
-#[link(name = "gcc_s", cfg(not(target_feature = "crt-static")))]
-extern "C" {}
+cfg_if::cfg_if! {
+ if #[cfg(all(feature = "llvm-libunwind", feature = "system-llvm-libunwind"))] {
+ compile_error!("`llvm-libunwind` and `system-llvm-libunwind` cannot be enabled at the same time");
+ } else if #[cfg(feature = "llvm-libunwind")] {
+ #[link(name = "unwind", kind = "static")]
+ extern "C" {}
+ } else if #[cfg(feature = "system-llvm-libunwind")] {
+ #[link(name = "unwind", kind = "static-nobundle", cfg(target_feature = "crt-static"))]
+ #[link(name = "unwind", cfg(not(target_feature = "crt-static")))]
+ extern "C" {}
+ } else {
+ #[link(name = "unwind", kind = "static", cfg(target_feature = "crt-static"))]
+ #[link(name = "gcc_s", cfg(not(target_feature = "crt-static")))]
+ extern "C" {}
+ }
+}
// When building with crt-static, we get `gcc_eh` from the `libc` crate, since
// glibc needs it, and needs it listed later on the linker command line. We
extern "C" {}
#[cfg(all(target_vendor = "fortanix", target_env = "sgx"))]
-#[link(name = "unwind", kind = "static-nobundle")]
+#[link(name = "unwind", kind = "static")]
extern "C" {}
filetime = "0.2"
num_cpus = "1.0"
getopts = "0.2.19"
-cc = "1.0.67"
+cc = "1.0.68"
libc = "0.2"
serde = { version = "1.0.8", features = ["derive"] }
serde_json = "1.0.2"
cmd.arg("-C").arg("target-feature=-crt-static");
}
}
+
+ if stage == "0" {
+ // Cargo doesn't pass RUSTFLAGS to proc_macros:
+ // https://github.com/rust-lang/cargo/issues/4423
+ // Set `--cfg=bootstrap` explicitly instead.
+ cmd.arg("--cfg=bootstrap");
+ }
}
if let Ok(map) = env::var("RUSTC_DEBUGINFO_MAP") {
cmd.arg(arg);
}
if env::var_os("RUSTDOC_FUSE_LD_LLD").is_some() {
- cmd.arg("-Clink-args=-fuse-ld=lld");
+ cmd.arg("-Clink-arg=-fuse-ld=lld");
+ if cfg!(windows) {
+ cmd.arg("-Clink-arg=-Wl,/threads:1");
+ } else {
+ cmd.arg("-Clink-arg=-Wl,--threads=1");
+ }
}
// Needed to be able to run all rustdoc tests.
rev_parse = ["git", "rev-parse", "--show-toplevel"]
top_level = subprocess.check_output(rev_parse, universal_newlines=True).strip()
compiler = "{}/compiler/".format(top_level)
+ library = "{}/library/".format(top_level)
# Look for a version to compare to based on the current commit.
# Only commits merged by bors will have CI artifacts.
merge_base = ["git", "log", "--author=bors", "--pretty=%H", "-n1"]
commit = subprocess.check_output(merge_base, universal_newlines=True).strip()
- # Warn if there were changes to the compiler since the ancestor commit.
- status = subprocess.call(["git", "diff-index", "--quiet", commit, "--", compiler])
+ # Warn if there were changes to the compiler or standard library since the ancestor commit.
+ status = subprocess.call(["git", "diff-index", "--quiet", commit, "--", compiler, library])
if status != 0:
if download_rustc == "if-unchanged":
return None
- print("warning: `download-rustc` is enabled, but there are changes to compiler/")
+ print("warning: `download-rustc` is enabled, but there are changes to \
+ compiler/ or library/")
if self.verbose:
print("using downloaded stage1 artifacts from CI (commit {})".format(commit))
).decode(default_encoding).splitlines()]
filtered_submodules = []
submodules_names = []
+ llvm_checked_out = os.path.exists(os.path.join(self.rust_root, "src/llvm-project/.git"))
+ external_llvm_provided = self.get_toml('llvm-config') or self.downloading_llvm()
+ llvm_needed = not self.get_toml('codegen-backends', 'rust') \
+ or "llvm" in self.get_toml('codegen-backends', 'rust')
for module in submodules:
- # This is handled by native::Llvm in rustbuild, not here
if module.endswith("llvm-project"):
- continue
+ # Don't sync the llvm-project submodule if an external LLVM was
+ # provided, if we are downloading LLVM or if the LLVM backend is
+ # not being built. Also, if the submodule has been initialized
+ # already, sync it anyways so that it doesn't mess up contributor
+ # pull requests.
+ if external_llvm_provided or not llvm_needed:
+ if self.get_toml('lld') != 'true' and not llvm_checked_out:
+ continue
check = self.check_submodule(module, slow_submodules)
filtered_submodules.append((module, check))
submodules_names.append(module)
recorded = subprocess.Popen(["git", "ls-tree", "HEAD"] + submodules_names,
cwd=self.rust_root, stdout=subprocess.PIPE)
recorded = recorded.communicate()[0].decode(default_encoding).strip().splitlines()
- # { filename: hash }
recorded_submodules = {}
for data in recorded:
- # [mode, kind, hash, filename]
data = data.split()
recorded_submodules[data[3]] = data[2]
for module in filtered_submodules:
tool::Rustfmt,
tool::Miri,
tool::CargoMiri,
- native::Lld
+ native::Lld,
+ native::CrtBeginEnd
),
Kind::Check | Kind::Clippy { .. } | Kind::Fix | Kind::Format => describe!(
check::Std,
self.run_step_descriptions(&Builder::get_step_descriptions(Kind::Doc), paths);
}
+ /// NOTE: keep this in sync with `rustdoc::clean::utils::doc_rust_lang_org_channel`, or tests will fail on beta/stable.
+ pub fn doc_rust_lang_org_channel(&self) -> String {
+ let channel = match &*self.config.channel {
+ "stable" => &self.version,
+ "beta" => "beta",
+ "nightly" | "dev" => "nightly",
+ // custom build of rustdoc maybe? link to the latest stable docs just in case
+ _ => "stable",
+ };
+ "https://doc.rust-lang.org/".to_owned() + channel
+ }
+
fn run_step_descriptions(&self, v: &[StepDescription], paths: &[PathBuf]) {
StepDescription::run(v, self, paths);
}
return;
}
- add_dylib_path(vec![self.rustc_libdir(compiler)], cmd);
+ let mut dylib_dirs = vec![self.rustc_libdir(compiler)];
+
+ // Ensure that the downloaded LLVM libraries can be found.
+ if self.config.llvm_from_ci {
+ let ci_llvm_lib = self.out.join(&*compiler.host.triple).join("ci-llvm").join("lib");
+ dylib_dirs.push(ci_llvm_lib);
+ }
+
+ add_dylib_path(dylib_dirs, cmd);
}
/// Gets a path to the compiler specified.
}
if self.is_fuse_ld_lld(compiler.host) {
cargo.env("RUSTC_HOST_FUSE_LD_LLD", "1");
+ cargo.env("RUSTDOC_FUSE_LD_LLD", "1");
}
if let Some(target_linker) = self.linker(target) {
if self.is_fuse_ld_lld(target) {
rustflags.arg("-Clink-args=-fuse-ld=lld");
}
+ self.lld_flags(target).for_each(|flag| {
+ rustdocflags.arg(&flag);
+ });
if !(["build", "check", "clippy", "fix", "rustc"].contains(&cmd)) && want_rustdoc {
cargo.env("RUSTDOC_LIBDIR", self.rustc_libdir(compiler));
DependencyType::TargetSelfContained,
);
}
+ let crt_path = builder.ensure(native::CrtBeginEnd { target });
for &obj in &["crtbegin.o", "crtbeginS.o", "crtend.o", "crtendS.o"] {
- let src = compiler_file(builder, builder.cc(target), target, obj);
+ let src = crt_path.join(obj);
let target = libdir_self_contained.join(obj);
builder.copy(&src, &target);
target_deps.push((target, DependencyType::TargetSelfContained));
if builder.no_std(target) == Some(true) {
let mut features = "compiler-builtins-mem".to_string();
- features.push_str(compiler_builtins_c_feature);
+ if !target.starts_with("bpf") {
+ features.push_str(compiler_builtins_c_feature);
+ }
// for no-std targets we only compile a few no_std crates
cargo
if target.contains("riscv") {
cargo.rustflag("-Cforce-unwind-tables=yes");
}
+
+ let html_root =
+ format!("-Zcrate-attr=doc(html_root_url=\"{}/\")", builder.doc_rust_lang_org_channel(),);
+ cargo.rustflag(&html_root);
+ cargo.rustdocflag(&html_root);
}
#[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)]
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_VERSION", builder.rust_version());
let libdir_relative = builder.config.libdir_relative().unwrap_or_else(|| Path::new("lib"));
cargo.env("CFG_LIBDIR_RELATIVE", libdir_relative);
let src_exe = exe("lld", target_compiler.host);
let dst_exe = exe("rust-lld", target_compiler.host);
builder.copy(&lld_install.join("bin").join(&src_exe), &libdir_bin.join(&dst_exe));
+ // for `-Z gcc-ld=lld`
+ let gcc_ld_dir = libdir_bin.join("gcc-ld");
+ t!(fs::create_dir(&gcc_ld_dir));
+ builder.copy(
+ &lld_install.join("bin").join(&src_exe),
+ &gcc_ld_dir.join(exe("ld", target_compiler.host)),
+ );
}
// Similarly, copy `llvm-dwp` into libdir for Split DWARF. Only copy it when the LLVM
if builder.config.lld_enabled {
let exe = exe("rust-lld", compiler.host);
builder.copy(&src_dir.join(&exe), &dst_dir.join(&exe));
+ // for `-Z gcc-ld=lld`
+ let gcc_lld_dir = dst_dir.join("gcc-ld");
+ t!(fs::create_dir(&gcc_lld_dir));
+ builder.copy(&src_dir.join(&exe), &gcc_lld_dir.join(&exe));
}
// Copy over llvm-dwp if it's there
build.verbose("finding compilers");
cc_detect::find(&mut build);
- build.verbose("running sanity check");
- sanity::check(&mut build);
+ // When running `setup`, the profile is about to change, so any requirements we have now may
+ // be different on the next invocation. Don't check for them until the next time x.py is
+ // run. This is ok because `setup` never runs any build commands, so it won't fail if commands are missing.
+ if !matches!(build.config.cmd, Subcommand::Setup { .. }) {
+ build.verbose("running sanity check");
+ sanity::check(&mut build);
+ }
// If local-rust is the same major.minor as the current version, then force a
// local-rebuild
slice::from_ref(&self.build.triple)
}
- /// If the LLVM submodule has been initialized already, sync it unconditionally. This avoids
- /// contributors checking in a submodule change by accident.
- pub fn maybe_update_llvm_submodule(&self) {
- if self.in_tree_llvm_info.is_git() {
- native::update_llvm_submodule(self);
- }
- }
-
/// Executes the entire build, as configured by the flags and configuration.
pub fn build(&mut self) {
unsafe {
job::setup(self);
}
- self.maybe_update_llvm_submodule();
-
if let Subcommand::Format { check, paths } = &self.config.cmd {
return format::format(self, *check, &paths);
}
self.config.use_lld && !target.contains("msvc")
}
+ fn lld_flags(&self, target: TargetSelection) -> impl Iterator<Item = String> {
+ let mut options = [None, None];
+
+ if self.config.use_lld {
+ if self.is_fuse_ld_lld(target) {
+ options[0] = Some("-Clink-arg=-fuse-ld=lld".to_string());
+ }
+
+ let threads = if target.contains("windows") { "/threads:1" } else { "--threads=1" };
+ options[1] = Some(format!("-Clink-arg=-Wl,{}", threads));
+ }
+
+ std::array::IntoIter::new(options).flatten()
+ }
+
/// Returns if this target should statically link the C runtime, if specified
fn crt_static(&self, target: TargetSelection) -> Option<bool> {
if target.contains("pc-windows-msvc") {
eprintln!(
"
Couldn't find required command: ninja
-You should install ninja, or set ninja=false in config.toml
+You should install ninja, or set `ninja=false` in config.toml in the `[llvm]` section.
"
);
std::process::exit(1);
src/tools/cargo \
src/tools/cargotest \
$(BOOTSTRAP_ARGS)
-check-aux-and-gui: check-aux
- $(Q)$(BOOTSTRAP) test --stage 2 \
- src/test/rustdoc-gui \
- $(BOOTSTRAP_ARGS)
check-bootstrap:
$(Q)$(CFG_PYTHON) $(CFG_SRC_DIR)src/bootstrap/bootstrap_test.py
dist:
use crate::builder::{Builder, RunConfig, ShouldRun, Step};
use crate::config::TargetSelection;
use crate::util::{self, exe};
-use crate::{Build, GitRepo};
+use crate::GitRepo;
use build_helper::up_to_date;
pub struct Meta {
Err(Meta { stamp, build_llvm_config, out_dir, root: root.into() })
}
-// modified from `check_submodule` and `update_submodule` in bootstrap.py
-pub(crate) fn update_llvm_submodule(build: &Build) {
- let llvm_project = &Path::new("src").join("llvm-project");
-
- fn dir_is_empty(dir: &Path) -> bool {
- t!(std::fs::read_dir(dir)).next().is_none()
- }
-
- // NOTE: The check for the empty directory is here because when running x.py
- // the first time, the llvm submodule won't be checked out. Check it out
- // now so we can build it.
- if !build.in_tree_llvm_info.is_git() && !dir_is_empty(&build.config.src.join(llvm_project)) {
- return;
- }
-
- // check_submodule
- let checked_out = if build.config.fast_submodules {
- Some(output(
- Command::new("git")
- .args(&["rev-parse", "HEAD"])
- .current_dir(build.config.src.join(llvm_project)),
- ))
- } else {
- None
- };
-
- // update_submodules
- let recorded = output(
- Command::new("git")
- .args(&["ls-tree", "HEAD"])
- .arg(llvm_project)
- .current_dir(&build.config.src),
- );
- let hash =
- recorded.split(' ').nth(2).unwrap_or_else(|| panic!("unexpected output `{}`", recorded));
-
- // update_submodule
- if let Some(llvm_hash) = checked_out {
- if hash == llvm_hash {
- // already checked out
- return;
- }
- }
-
- println!("Updating submodule {}", llvm_project.display());
- build.run(
- Command::new("git")
- .args(&["submodule", "-q", "sync"])
- .arg(llvm_project)
- .current_dir(&build.config.src),
- );
-
- // Try passing `--progress` to start, then run git again without if that fails.
- let update = |progress: bool| {
- let mut git = Command::new("git");
- git.args(&["submodule", "update", "--init", "--recursive"]);
- if progress {
- git.arg("--progress");
- }
- git.arg(llvm_project).current_dir(&build.config.src);
- git
- };
- // NOTE: doesn't use `try_run` because this shouldn't print an error if it fails.
- if !update(true).status().map_or(false, |status| status.success()) {
- build.run(&mut update(false));
- }
-
- build.run(
- Command::new("git")
- .args(&["reset", "-q", "--hard"])
- .current_dir(build.config.src.join(llvm_project)),
- );
- build.run(
- Command::new("git")
- .args(&["clean", "-qdfx"])
- .current_dir(build.config.src.join(llvm_project)),
- );
-}
-
#[derive(Debug, Copy, Clone, Hash, PartialEq, Eq)]
pub struct Llvm {
pub target: TargetSelection,
Err(m) => m,
};
- if !builder.config.dry_run {
- update_llvm_submodule(builder);
- }
if builder.config.llvm_link_shared
&& (target.contains("windows") || target.contains("apple-darwin"))
{
let llvm_targets = match &builder.config.llvm_targets {
Some(s) => s,
None => {
- "AArch64;ARM;Hexagon;MSP430;Mips;NVPTX;PowerPC;RISCV;\
+ "AArch64;ARM;BPF;Hexagon;MSP430;Mips;NVPTX;PowerPC;RISCV;\
Sparc;SystemZ;WebAssembly;X86"
}
};
.define("LLVM_TARGET_ARCH", target_native.split('-').next().unwrap())
.define("LLVM_DEFAULT_TARGET_TRIPLE", target_native);
- if target != "aarch64-apple-darwin" {
+ if target != "aarch64-apple-darwin" && !target.contains("windows") {
cfg.define("LLVM_ENABLE_ZLIB", "ON");
} else {
cfg.define("LLVM_ENABLE_ZLIB", "OFF");
fs::write(&self.path, self.hash.as_deref().unwrap_or(b""))
}
}
+
+#[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)]
+pub struct CrtBeginEnd {
+ pub target: TargetSelection,
+}
+
+impl Step for CrtBeginEnd {
+ type Output = PathBuf;
+
+ fn should_run(run: ShouldRun<'_>) -> ShouldRun<'_> {
+ run.path("src/llvm-project/compiler-rt/lib/crt")
+ }
+
+ fn make_run(run: RunConfig<'_>) {
+ run.builder.ensure(CrtBeginEnd { target: run.target });
+ }
+
+ /// Build crtbegin.o/crtend.o for musl target.
+ fn run(self, builder: &Builder<'_>) -> Self::Output {
+ let out_dir = builder.native_dir(self.target).join("crt");
+
+ if builder.config.dry_run {
+ return out_dir;
+ }
+
+ let crtbegin_src = builder.src.join("src/llvm-project/compiler-rt/lib/crt/crtbegin.c");
+ let crtend_src = builder.src.join("src/llvm-project/compiler-rt/lib/crt/crtend.c");
+ if up_to_date(&crtbegin_src, &out_dir.join("crtbegin.o"))
+ && up_to_date(&crtend_src, &out_dir.join("crtendS.o"))
+ {
+ return out_dir;
+ }
+
+ builder.info("Building crtbegin.o and crtend.o");
+ t!(fs::create_dir_all(&out_dir));
+
+ let mut cfg = cc::Build::new();
+
+ if let Some(ar) = builder.ar(self.target) {
+ cfg.archiver(ar);
+ }
+ cfg.compiler(builder.cc(self.target));
+ cfg.cargo_metadata(false)
+ .out_dir(&out_dir)
+ .target(&self.target.triple)
+ .host(&builder.config.build.triple)
+ .warnings(false)
+ .debug(false)
+ .opt_level(3)
+ .file(crtbegin_src)
+ .file(crtend_src);
+
+ // Those flags are defined in src/llvm-project/compiler-rt/lib/crt/CMakeLists.txt
+ // Currently only consumer of those objects is musl, which use .init_array/.fini_array
+ // instead of .ctors/.dtors
+ cfg.flag("-std=c11")
+ .define("CRT_HAS_INITFINI_ARRAY", None)
+ .define("EH_USE_FRAME_REGISTRY", None);
+
+ cfg.compile("crt");
+
+ t!(fs::copy(out_dir.join("crtbegin.o"), out_dir.join("crtbeginS.o")));
+ t!(fs::copy(out_dir.join("crtend.o"), out_dir.join("crtendS.o")));
+ out_dir
+ }
+}
SourceType::Submodule,
&[],
);
+ cargo.add_rustc_lib_path(builder, compiler);
cargo.arg("--").arg("miri").arg("setup");
// Tell `cargo miri setup` where to find the sources.
SourceType::Submodule,
&[],
);
+ cargo.add_rustc_lib_path(builder, compiler);
// miri tests need to know about the stage sysroot
cargo.env("MIRI_SYSROOT", miri_sysroot);
cargo.arg("--").args(builder.config.cmd.test_args());
- cargo.add_rustc_lib_path(builder, compiler);
-
let mut cargo = Command::from(cargo);
if !try_run(builder, &mut cargo) {
return;
}
}
+fn check_if_browser_ui_test_is_installed_global(npm: &Path, global: bool) -> bool {
+ let mut command = Command::new(&npm);
+ command.arg("list").arg("--depth=0");
+ if global {
+ command.arg("--global");
+ }
+ let lines = command
+ .output()
+ .map(|output| String::from_utf8_lossy(&output.stdout).into_owned())
+ .unwrap_or(String::new());
+ lines.contains(&" browser-ui-test@")
+}
+
+fn check_if_browser_ui_test_is_installed(npm: &Path) -> bool {
+ check_if_browser_ui_test_is_installed_global(npm, false)
+ || check_if_browser_ui_test_is_installed_global(npm, true)
+}
+
#[derive(Debug, Copy, Clone, Hash, PartialEq, Eq)]
pub struct RustdocGUI {
pub target: TargetSelection,
const ONLY_HOSTS: bool = true;
fn should_run(run: ShouldRun<'_>) -> ShouldRun<'_> {
- run.path("src/test/rustdoc-gui")
+ let builder = run.builder;
+ let run = run.suite_path("src/test/rustdoc-gui");
+ run.default_condition(
+ builder.config.nodejs.is_some()
+ && builder
+ .config
+ .npm
+ .as_ref()
+ .map(|p| check_if_browser_ui_test_is_installed(p))
+ .unwrap_or(false),
+ )
}
fn make_run(run: RunConfig<'_>) {
}
fn run(self, builder: &Builder<'_>) {
- if let (Some(nodejs), Some(npm)) = (&builder.config.nodejs, &builder.config.npm) {
- builder.ensure(compile::Std { compiler: self.compiler, target: self.target });
-
- // The goal here is to check if the necessary packages are installed, and if not, we
- // display a warning and move on.
- let mut command = Command::new(&npm);
- command.arg("list").arg("--depth=0");
- let lines = command
- .output()
- .map(|output| String::from_utf8_lossy(&output.stdout).to_string())
- .unwrap_or(String::new());
- if !lines.contains(&" browser-ui-test@") {
- println!(
- "warning: rustdoc-gui test suite cannot be run because npm `browser-ui-test` \
- dependency is missing",
- );
- println!(
- "If you want to install the `{0}` dependency, run `npm install {0}`",
- "browser-ui-test",
- );
- return;
- }
+ let nodejs = builder.config.nodejs.as_ref().expect("nodejs isn't available");
+ let npm = builder.config.npm.as_ref().expect("npm isn't available");
- let out_dir = builder.test_out(self.target).join("rustdoc-gui");
+ builder.ensure(compile::Std { compiler: self.compiler, target: self.target });
- // We remove existing folder to be sure there won't be artifacts remaining.
- let _ = fs::remove_dir_all(&out_dir);
+ // The goal here is to check if the necessary packages are installed, and if not, we
+ // panic.
+ if !check_if_browser_ui_test_is_installed(&npm) {
+ eprintln!(
+ "error: rustdoc-gui test suite cannot be run because npm `browser-ui-test` \
+ dependency is missing",
+ );
+ eprintln!(
+ "If you want to install the `{0}` dependency, run `npm install {0}`",
+ "browser-ui-test",
+ );
+ panic!("Cannot run rustdoc-gui tests");
+ }
- // We generate docs for the libraries present in the rustdoc-gui's src folder.
- let libs_dir = builder.build.src.join("src/test/rustdoc-gui/src");
- for entry in libs_dir.read_dir().expect("read_dir call failed") {
- let entry = entry.expect("invalid entry");
- let path = entry.path();
- if path.extension().map(|e| e == "rs").unwrap_or(false) {
- let mut command = builder.rustdoc_cmd(self.compiler);
- command.arg(path).arg("-o").arg(&out_dir);
- builder.run(&mut command);
+ let out_dir = builder.test_out(self.target).join("rustdoc-gui");
+
+ // We remove existing folder to be sure there won't be artifacts remaining.
+ let _ = fs::remove_dir_all(&out_dir);
+
+ let mut nb_generated = 0;
+ // We generate docs for the libraries present in the rustdoc-gui's src folder.
+ let libs_dir = builder.build.src.join("src/test/rustdoc-gui/src");
+ for entry in libs_dir.read_dir().expect("read_dir call failed") {
+ let entry = entry.expect("invalid entry");
+ let path = entry.path();
+ if path.extension().map(|e| e == "rs").unwrap_or(false) {
+ let mut command = builder.rustdoc_cmd(self.compiler);
+ command.arg(path).arg("-o").arg(&out_dir);
+ builder.run(&mut command);
+ nb_generated += 1;
+ }
+ }
+ assert!(nb_generated > 0, "no documentation was generated...");
+
+ // We now run GUI tests.
+ let mut command = Command::new(&nodejs);
+ command
+ .arg(builder.build.src.join("src/tools/rustdoc-gui/tester.js"))
+ .arg("--doc-folder")
+ .arg(out_dir)
+ .arg("--tests-folder")
+ .arg(builder.build.src.join("src/test/rustdoc-gui"));
+ for path in &builder.paths {
+ if let Some(name) = path.file_name().and_then(|f| f.to_str()) {
+ if name.ends_with(".goml") {
+ command.arg("--file").arg(name);
}
}
-
- // We now run GUI tests.
- let mut command = Command::new(&nodejs);
- command
- .arg(builder.build.src.join("src/tools/rustdoc-gui/tester.js"))
- .arg("--doc-folder")
- .arg(out_dir)
- .arg("--tests-folder")
- .arg(builder.build.src.join("src/test/rustdoc-gui"));
- builder.run(&mut command);
- } else {
- builder.info("No nodejs found, skipping \"src/test/rustdoc-gui\" tests");
}
+ builder.run(&mut command);
}
}
compare_mode: Option<&'static str>,
}
-impl Compiletest {
- fn add_lld_flags(builder: &Builder<'_>, target: TargetSelection, flags: &mut Vec<String>) {
- if builder.config.use_lld {
- if builder.is_fuse_ld_lld(target) {
- flags.push("-Clink-arg=-fuse-ld=lld".to_string());
- }
-
- let threads = if target.contains("windows") { "/threads:1" } else { "--threads=1" };
- flags.push(format!("-Clink-arg=-Wl,{}", threads));
- }
- }
-}
-
impl Step for Compiletest {
type Output = ();
}
}
flags.push(format!("-Cdebuginfo={}", builder.config.rust_debuginfo_level_tests));
- flags.push("-Zunstable-options".to_string());
flags.push(builder.config.cmd.rustc_args().join(" "));
if let Some(linker) = builder.linker(target) {
let mut hostflags = flags.clone();
hostflags.push(format!("-Lnative={}", builder.test_helpers_out(compiler.host).display()));
- Self::add_lld_flags(builder, compiler.host, &mut hostflags);
+ hostflags.extend(builder.lld_flags(compiler.host));
cmd.arg("--host-rustcflags").arg(hostflags.join(" "));
let mut targetflags = flags;
targetflags.push(format!("-Lnative={}", builder.test_helpers_out(target).display()));
- Self::add_lld_flags(builder, target, &mut targetflags);
+ targetflags.extend(builder.lld_flags(target));
cmd.arg("--target-rustcflags").arg(targetflags.join(" "));
cmd.arg("--docck-python").arg(builder.python());
}
}
cmd.env("RUSTC_BOOTSTRAP", "1");
+ cmd.env("DOC_RUST_LANG_ORG_CHANNEL", builder.doc_rust_lang_org_channel());
builder.add_rust_test_threads(&mut cmd);
if builder.config.sanitizers_enabled(target) {
cmd.env("BOOTSTRAP_CARGO", &builder.initial_cargo);
+ cmd.arg("--channel").arg(&builder.config.channel);
+
builder.ci_env.force_coloring_in_ci(&mut cmd);
builder.info(&format!(
if tool == "tidy" {
tool = "rust-tidy";
}
- let cargo_out =
- builder.cargo_out(compiler, self.mode, target).join(exe(tool, compiler.host));
- let bin = builder.tools_dir(compiler).join(exe(tool, compiler.host));
+ let cargo_out = builder.cargo_out(compiler, self.mode, target).join(exe(tool, target));
+ let bin = builder.tools_dir(compiler).join(exe(tool, target));
builder.copy(&cargo_out, &bin);
Some(bin)
}
cargo.env("CFG_RELEASE_CHANNEL", &builder.config.channel);
cargo.env("CFG_VERSION", builder.rust_version());
cargo.env("CFG_RELEASE_NUM", &builder.version);
+ cargo.env("DOC_RUST_LANG_ORG_CHANNEL", builder.doc_rust_lang_org_channel());
let info = GitInfo::new(builder.config.ignore_git, &dir);
if let Some(sha) = info.sha() {
}
/// Adds a list of lookup paths to `cmd`'s dynamic library lookup path.
+/// If The dylib_path_par is already set for this cmd, the old value will be overwritten!
pub fn add_dylib_path(path: Vec<PathBuf>, cmd: &mut Command) {
let mut list = dylib_path();
for path in path {
|| target.contains("wasm32")
|| target.contains("nvptx")
|| target.contains("fortanix")
- || target.contains("fuchsia"))
+ || target.contains("fuchsia")
+ || target.contains("bpf"))
}
}
}
-#[track_caller]
pub fn output(cmd: &mut Command) -> String {
let output = match cmd.stderr(Stdio::inherit()).output() {
Ok(status) => status,
# riscv targets currently do not need a C compiler, as compiler_builtins
# doesn't currently have it enabled, and the riscv gcc compiler is not
# installed.
-ENV CC_mipsel_unknown_linux_musl=mipsel-openwrt-linux-gcc \
+ENV CFLAGS_armv5te_unknown_linux_musleabi="-march=armv5te -marm -mfloat-abi=soft" \
+ CFLAGS_arm_unknown_linux_musleabi="-march=armv6 -marm" \
+ CFLAGS_arm_unknown_linux_musleabihf="-march=armv6 -marm -mfpu=vfp" \
+ CFLAGS_armv7_unknown_linux_musleabihf="-march=armv7-a" \
+ CC_mipsel_unknown_linux_musl=mipsel-openwrt-linux-gcc \
CC_mips_unknown_linux_musl=mips-openwrt-linux-gcc \
CC_mips64el_unknown_linux_muslabi64=mips64el-linux-gnuabi64-gcc \
CC_mips64_unknown_linux_muslabi64=mips64-linux-gnuabi64-gcc \
AR_x86_64_pc_solaris=x86_64-pc-solaris2.10-ar \
CC_x86_64_pc_solaris=x86_64-pc-solaris2.10-gcc \
CXX_x86_64_pc_solaris=x86_64-pc-solaris2.10-g++ \
+ AR_x86_64_sun_solaris=x86_64-sun-solaris2.10-ar \
+ CC_x86_64_sun_solaris=x86_64-sun-solaris2.10-gcc \
+ CXX_x86_64_sun_solaris=x86_64-sun-solaris2.10-g++ \
CC_armv7_unknown_linux_gnueabi=arm-linux-gnueabi-gcc-8 \
CXX_armv7_unknown_linux_gnueabi=arm-linux-gnueabi-g++-8 \
AR_x86_64_fortanix_unknown_sgx=ar \
COPY host-x86_64/dist-various-2/build-fuchsia-toolchain.sh /tmp/
RUN /tmp/build-fuchsia-toolchain.sh
COPY host-x86_64/dist-various-2/build-solaris-toolchain.sh /tmp/
-RUN /tmp/build-solaris-toolchain.sh x86_64 amd64 solaris-i386
-RUN /tmp/build-solaris-toolchain.sh sparcv9 sparcv9 solaris-sparc
+RUN /tmp/build-solaris-toolchain.sh x86_64 amd64 solaris-i386 pc
+# Build deprecated target 'x86_64-sun-solaris2.10' until removed
+RUN /tmp/build-solaris-toolchain.sh x86_64 amd64 solaris-i386 sun
+RUN /tmp/build-solaris-toolchain.sh sparcv9 sparcv9 solaris-sparc sun
COPY host-x86_64/dist-various-2/build-x86_64-fortanix-unknown-sgx-toolchain.sh /tmp/
RUN /tmp/build-x86_64-fortanix-unknown-sgx-toolchain.sh
ENV TARGETS=$TARGETS,wasm32-wasi
ENV TARGETS=$TARGETS,sparcv9-sun-solaris
ENV TARGETS=$TARGETS,x86_64-pc-solaris
+ENV TARGETS=$TARGETS,x86_64-sun-solaris
ENV TARGETS=$TARGETS,x86_64-unknown-linux-gnux32
ENV TARGETS=$TARGETS,x86_64-fortanix-unknown-sgx
ENV TARGETS=$TARGETS,nvptx64-nvidia-cuda
ARCH=$1
LIB_ARCH=$2
APT_ARCH=$3
+MANUFACTURER=$4
BINUTILS=2.28.1
GCC=6.5.0
-# Choose correct target based on the $ARCH
-case "$ARCH" in
-x86_64)
- TARGET=x86_64-pc-solaris2.10
- ;;
-sparcv9)
- TARGET=sparcv9-sun-solaris2.10
- ;;
-*)
- printf 'ERROR: unknown architecture: %s\n' "$ARCH"
- exit 1
-esac
+TARGET=${ARCH}-${MANUFACTURER}-solaris2.10
# First up, build binutils
mkdir binutils
# Install es-check
# Pin its version to prevent unrelated CI failures due to future es-check versions.
RUN npm install es-check@5.2.3 -g
+RUN npm install eslint@7.20.0 -g
COPY scripts/sccache.sh /scripts/
RUN sh /scripts/sccache.sh
python3 ../x.py doc --stage 0 library/test && \
/scripts/validate-toolstate.sh && \
# Runs checks to ensure that there are no ES5 issues in our JS code.
- es-check es5 ../src/librustdoc/html/static/*.js
+ es-check es5 ../src/librustdoc/html/static/*.js && \
+ eslint ../src/librustdoc/html/static/*.js
libgl1-mesa-dev \
llvm-dev \
libfreetype6-dev \
- libexpat1-dev \
- libexpat1-dev \
- gnupg \
- apt-utils \
- wget \
- fonts-ipafont-gothic \
- fonts-wqy-zenhei \
- fonts-thai-tlwg \
- fonts-kacst \
- fonts-freefont-ttf \
- libxss1 \
- libxtst6
-
-RUN curl -sL https://nodejs.org/dist/v14.4.0/node-v14.4.0-linux-x64.tar.xz | tar -xJ
-ENV PATH="/node-v14.4.0-linux-x64/bin:${PATH}"
-
-# Install required dependencies from browser-UI-test framework
-# For now, we need to use `--unsafe-perm=true` to go around an issue when npm tries
-# to create a new folder. For reference:
-# https://github.com/puppeteer/puppeteer/issues/375
-RUN npm install browser-ui-test -g --unsafe-perm=true
+ libexpat1-dev
COPY scripts/sccache.sh /scripts/
RUN sh /scripts/sccache.sh
RUN /scripts/cmake.sh
ENV RUST_CONFIGURE_ARGS --build=x86_64-unknown-linux-gnu
-ENV RUST_CHECK_TARGET check-aux-and-gui
+ENV RUST_CHECK_TARGET check-aux
cmake \
libssl-dev \
sudo \
- xz-utils \
- pkg-config
+ xz-utils
+
+# Install dependencies for chromium browser
+RUN apt-get install -y \
+ gconf-service \
+ libasound2 \
+ libatk1.0-0 \
+ libatk-bridge2.0-0 \
+ libc6 \
+ libcairo2 \
+ libcups2 \
+ libdbus-1-3 \
+ libexpat1 \
+ libfontconfig1 \
+ libgcc1 \
+ libgconf-2-4 \
+ libgdk-pixbuf2.0-0 \
+ libglib2.0-0 \
+ libgtk-3-0 \
+ libnspr4 \
+ libpango-1.0-0 \
+ libpangocairo-1.0-0 \
+ libstdc++6 \
+ libx11-6 \
+ libx11-xcb1 \
+ libxcb1 \
+ libxcomposite1 \
+ libxcursor1 \
+ libxdamage1 \
+ libxext6 \
+ libxfixes3 \
+ libxi6 \
+ libxrandr2 \
+ libxrender1 \
+ libxss1 \
+ libxtst6 \
+ fonts-liberation \
+ libappindicator1 \
+ libnss3 \
+ lsb-release \
+ xdg-utils \
+ wget
COPY scripts/sccache.sh /scripts/
RUN sh /scripts/sccache.sh
COPY host-x86_64/x86_64-gnu-tools/checktools.sh /tmp/
+RUN curl -sL https://nodejs.org/dist/v14.4.0/node-v14.4.0-linux-x64.tar.xz | tar -xJ
+ENV PATH="/node-v14.4.0-linux-x64/bin:${PATH}"
+
+# For now, we need to use `--unsafe-perm=true` to go around an issue when npm tries
+# to create a new folder. For reference:
+# https://github.com/puppeteer/puppeteer/issues/375
+#
+# We also specify the version in case we need to update it to go around cache limitations.
+RUN npm install -g browser-ui-test@0.2.14 --unsafe-perm=true
+
ENV RUST_CONFIGURE_ARGS \
--build=x86_64-unknown-linux-gnu \
--save-toolstates=/tmp/toolstate/toolstates.json
-ENV SCRIPT /tmp/checktools.sh ../x.py
+
+ENV SCRIPT /tmp/checktools.sh ../x.py && \
+ NODE_PATH=`npm root -g` python3 ../x.py test src/test/rustdoc-gui --stage 2
--env TOOLSTATE_REPO_ACCESS_TOKEN \
--env TOOLSTATE_REPO \
--env TOOLSTATE_PUBLISH \
+ --env RUST_CI_OVERRIDE_RELEASE_CHANNEL \
--env CI_JOB_NAME="${CI_JOB_NAME-$IMAGE}" \
--init \
--rm \
- name: x86_64-gnu
<<: *job-linux-xl
+ # This job ensures commits landing on nightly still pass the full
+ # test suite on the stable channel. There are some UI tests that
+ # depend on the channel being built (for example if they include the
+ # channel name on the output), and this builder prevents landing
+ # changes that would result in broken builds after a promotion.
+ - name: x86_64-gnu-stable
+ env:
+ IMAGE: x86_64-gnu
+ RUST_CI_OVERRIDE_RELEASE_CHANNEL: stable
+ <<: *job-linux-xl
+
- name: x86_64-gnu-aux
<<: *job-linux-xl
# Always set the release channel for bootstrap; this is normally not important (i.e., only dist
# builds would seem to matter) but in practice bootstrap wants to know whether we're targeting
# master, beta, or stable with a build to determine whether to run some checks (notably toolstate).
-export RUST_RELEASE_CHANNEL="$(cat "${ci_dir}/channel")"
+if [[ -z "${RUST_CI_OVERRIDE_RELEASE_CHANNEL+x}" ]]; then
+ export RUST_RELEASE_CHANNEL="$(cat "${ci_dir}/channel")"
+else
+ export RUST_RELEASE_CHANNEL="${RUST_CI_OVERRIDE_RELEASE_CHANNEL}"
+fi
RUST_CONFIGURE_ARGS="$RUST_CONFIGURE_ARGS --release-channel=$RUST_RELEASE_CHANNEL"
if [ "$DEPLOY$DEPLOY_ALT" = "1" ]; then
# There is not an easy blanket search for subtrees. For now, manually list
# the subtrees.
echo "Executing the job since clippy or rustfmt subtree was updated"
+elif ! (git diff --quiet "$BASE_COMMIT" -- \
+ src/test/rustdoc-gui \
+ src/librustdoc \
+ src/tools/rustdoc-gui); then
+ # There was a change in either rustdoc or in its GUI tests.
+ echo "Executing the job since rustdoc was updated"
else
echo "Not executing this job since no submodules nor subtrees were updated"
ciCommandSetEnv SKIP_JOB 1
-Subproject commit 1da3c411f17adb1ba5de1683bb6acee83362b54a
+Subproject commit 302a115e8f71876dfc884aebb0ca5ccb02b8a962
-Subproject commit 569c3391f5c0cc43433bc77831d17f8ff4d76602
+Subproject commit 7349d173fa28a0bb834cf0264a05286620ef0923
-Subproject commit 5aa457bf1b54bd2cd5d4cf49797f29299bdf89a7
+Subproject commit 8f598e2af6c25b4a7ee88ef6a8196d9b8ea50ca8
-Subproject commit 5f8c6da200ada77760a2fe1096938ef58151c9a6
+Subproject commit 805e016c5792ad2adabb66e348233067d5ea9f10
-Subproject commit 1e6c7fbda4c45e85adf63ff3f82fa9c870b1447f
+Subproject commit c8da5bfd1c7c71d90ef1646f5e0a9f6609d5c78a
- [JSON Output](json.md)
- [Tests](tests/index.md)
- [Platform Support](platform-support.md)
+ - [aarch64-apple-ios-sim](platform-support/aarch64-apple-ios-sim.md)
- [Target Tier Policy](target-tier-policy.md)
- [Targets](targets/index.md)
- [Built-in Targets](targets/built-in.md)
* `y`, `yes`, `on`, or no value: Unwind tables are forced to be generated.
* `n`, `no`, or `off`: Unwind tables are not forced to be generated. If unwind
- tables are required by the target or `-C panic=unwind`, an error will be
- emitted.
+ tables are required by the target an error will be emitted.
The default if not specified depends on the target.
* `ptx-linker`: use
[`rust-ptx-linker`](https://github.com/denzp/rust-ptx-linker) for Nvidia
NVPTX GPGPU support.
+* `bpf-linker`: use
+ [`bpf-linker`](https://github.com/alessandrod/bpf-linker) for eBPF support.
* `wasm-ld`: use the [`wasm-ld`](https://lld.llvm.org/WebAssembly.html)
executable, a port of LLVM `lld` for WebAssembly.
* `ld64.lld`: use the LLVM `lld` executable with the [`-flavor darwin`
`mips64-unknown-linux-muslabi64` | ✓ | MIPS64 Linux, n64 ABI, MUSL
`mips64el-unknown-linux-muslabi64` | ✓ | MIPS64 (LE) Linux, n64 ABI, MUSL
`mipsel-unknown-linux-musl` | ✓ | MIPS (LE) Linux with MUSL
-`nvptx64-nvidia-cuda` | ✓ | --emit=asm generates PTX code that [runs on NVIDIA GPUs]
+`nvptx64-nvidia-cuda` | * | --emit=asm generates PTX code that [runs on NVIDIA GPUs]
`riscv32i-unknown-none-elf` | * | Bare RISC-V (RV32I ISA)
`riscv32imac-unknown-none-elf` | * | Bare RISC-V (RV32IMAC ISA)
`riscv32imc-unknown-none-elf` | * | Bare RISC-V (RV32IMC ISA)
target | std | host | notes
-------|:---:|:----:|-------
`aarch64-apple-ios-macabi` | ? | | Apple Catalyst on ARM64
-`aarch64-apple-ios-sim` | ? | | Apple iOS Simulator on ARM64
+[`aarch64-apple-ios-sim`](platform-support/aarch64-apple-ios-sim.md) | ✓ | | Apple iOS Simulator on ARM64
`aarch64-apple-tvos` | * | | ARM64 tvOS
`aarch64-unknown-freebsd` | ✓ | ✓ | ARM64 FreeBSD
`aarch64-unknown-hermit` | ? | |
`armv7a-none-eabihf` | * | | ARM Cortex-A, hardfloat
`armv7s-apple-ios` | ✓ | |
`avr-unknown-gnu-atmega328` | * | | AVR. Requires `-Z build-std=core`
+`bpfeb-unknown-none` | * | | BPF (big endian)
+`bpfel-unknown-none` | * | | BPF (little endian)
`hexagon-unknown-linux-musl` | ? | |
`i386-apple-ios` | ✓ | | 32-bit x86 iOS
`i686-apple-darwin` | ✓ | ✓ | 32-bit macOS (10.7+, Lion+)
--- /dev/null
+# aarch64-apple-ios-sim
+
+**Tier: 3**
+
+Apple iOS Simulator on ARM64.
+
+## Designated Developers
+
+* [@badboy](https://github.com/badboy)
+* [@deg4uss3r](https://github.com/deg4uss3r)
+
+## Requirements
+
+This target is cross-compiled.
+To build this target Xcode 12 or higher on macOS is required.
+
+## Building
+
+The target can be built by enabling it for a `rustc` build:
+
+```toml
+[build]
+build-stage = 1
+target = ["aarch64-apple-ios-sim"]
+```
+
+## Cross-compilation
+
+This target can be cross-compiled from `x86_64` or `aarch64` macOS hosts.
+
+Other hosts are not supported for cross-compilation, but might work when also providing the required Xcode SDK.
+
+## Testing
+
+Currently there is no support to run the rustc test suite for this target.
+
+
+## Building Rust programs
+
+*Note: Building for this target requires the corresponding iOS SDK, as provided by Xcode 12+.*
+
+If `rustc` has support for that target and the library artifacts are available,
+then Rust programs can be built for that target:
+
+```text
+rustc --target aarch64-apple-ios-sim your-code.rs
+```
+
+On Rust Nightly it is possible to build without the target artifacts available:
+
+```text
+cargo build -Z build-std --target aarch64-apple-ios-sim
+```
+
+There is no easy way to run simple programs in the iOS simulator.
+Static library builds can be embedded into iOS applications.
`lib.rs` to test your README as part of your doctests:
```rust,no_run
-#![feature(external_doc)]
-
-#[doc(include = "../README.md")]
+#[doc = include_str!("../README.md")]
#[cfg(doctest)]
pub struct ReadmeDoctests;
```
```md
- [x] Complete task
-- [ ] IncComplete task
+- [ ] Incomplete task
```
-This will render as
+This will render as:
-<ul>
- <li><input type="checkbox"></li>
- <li><input type="checkbox" checked></li>
-</ul>
+> - [x] Complete task
+> - [ ] Incomplete task
See the specification for the [task list extension] for more details.
[unstable-masked]: ../unstable-book/language-features/doc-masked.html
[issue-masked]: https://github.com/rust-lang/rust/issues/44027
-### Include external files as API documentation
-
-As designed in [RFC 1990], Rustdoc can read an external file to use as a type's documentation. This
-is useful if certain documentation is so long that it would break the flow of reading the source.
-Instead of writing it all inline, writing `#[doc(include = "sometype.md")]` will ask Rustdoc to
-instead read that file and use it as if it were written inline.
-
-[RFC 1990]: https://github.com/rust-lang/rfcs/pull/1990
-
-`#[doc(include = "...")]` currently requires the `#![feature(external_doc)]` feature gate. For more
-information, see [its chapter in the Unstable Book][unstable-include] and [its tracking
-issue][issue-include].
-
-[unstable-include]: ../unstable-book/language-features/external-doc.html
-[issue-include]: https://github.com/rust-lang/rust/issues/44732
-
## Unstable command-line arguments
These features are enabled by passing a command-line flag to Rustdoc, but the flags in question are
--- /dev/null
+# `force-warns`
+
+The tracking issue for this feature is: [#85512](https://github.com/rust-lang/rust/issues/85512).
+
+------------------------
+
+This feature allows you to cause any lint to produce a warning even if the lint has a different level by default or another level is set somewhere else. For instance, the `force-warns` option can be used to make a lint (e.g., `dead_code`) produce a warning even if that lint is allowed in code with `#![allow(dead_code)]`.
+
+## Example
+
+```rust,ignore (partial-example)
+#![allow(dead_code)]
+
+fn dead_function() {}
+// This would normally not produce a warning even though the
+// function is not used, because dead code is being allowed
+
+fn main() {}
+```
+
+We can force a warning to be produced by providing `--force-warns dead_code` to rustc.
+++ /dev/null
-# `external_doc`
-
-The tracking issue for this feature is: [#44732]
-
-The `external_doc` feature allows the use of the `include` parameter to the `#[doc]` attribute, to
-include external files in documentation. Use the attribute in place of, or in addition to, regular
-doc comments and `#[doc]` attributes, and `rustdoc` will load the given file when it renders
-documentation for your crate.
-
-With the following files in the same directory:
-
-`external-doc.md`:
-
-```markdown
-# My Awesome Type
-
-This is the documentation for this spectacular type.
-```
-
-`lib.rs`:
-
-```no_run (needs-external-files)
-#![feature(external_doc)]
-
-#[doc(include = "external-doc.md")]
-pub struct MyAwesomeType;
-```
-
-`rustdoc` will load the file `external-doc.md` and use it as the documentation for the `MyAwesomeType`
-struct.
-
-When locating files, `rustdoc` will base paths in the `src/` directory, as if they were alongside the
-`lib.rs` for your crate. So if you want a `docs/` folder to live alongside the `src/` directory,
-start your paths with `../docs/` for `rustdoc` to properly find the file.
-
-This feature was proposed in [RFC #1990] and initially implemented in PR [#44781].
-
-[#44732]: https://github.com/rust-lang/rust/issues/44732
-[RFC #1990]: https://github.com/rust-lang/rfcs/pull/1990
-[#44781]: https://github.com/rust-lang/rust/pull/44781
+++ /dev/null
-# `member_constraints`
-
-The tracking issue for this feature is: [#61997]
-
-[#61997]: https://github.com/rust-lang/rust/issues/61997
-
-------------------------
-
-The `member_constraints` feature gate lets you use `impl Trait` syntax with
-multiple unrelated lifetime parameters.
-
-A simple example is:
-
-```rust
-#![feature(member_constraints)]
-
-trait Trait<'a, 'b> { }
-impl<T> Trait<'_, '_> for T {}
-
-fn foo<'a, 'b>(x: &'a u32, y: &'b u32) -> impl Trait<'a, 'b> {
- (x, y)
-}
-
-fn main() { }
-```
-
-Without the `member_constraints` feature gate, the above example is an
-error because both `'a` and `'b` appear in the impl Trait bounds, but
-neither outlives the other.
--- /dev/null
+# `more_qualified_paths`
+
+The `more_qualified_paths` feature can be used in order to enable the
+use of qualified paths in patterns.
+
+## Example
+
+```rust
+#![feature(more_qualified_paths)]
+
+fn main() {
+ // destructure through a qualified path
+ let <Foo as A>::Assoc { br } = StructStruct { br: 2 };
+}
+
+struct StructStruct {
+ br: i8,
+}
+
+struct Foo;
+
+trait A {
+ type Assoc;
+}
+
+impl A for Foo {
+ type Assoc = StructStruct;
+}
+```
- Hexagon
- MIPS32r2 and MIPS64r2
- wasm32
+- BPF
## Basic usage
| PowerPC | `reg_nonzero` | | `r[1-31]` | `b` |
| PowerPC | `freg` | `f[0-31]` | `f` |
| wasm32 | `local` | None\* | `r` |
+| BPF | `reg` | `r[0-10]` | `r` |
+| BPF | `wreg` | `w[0-10]` | `w` |
> **Note**: On x86 we treat `reg_byte` differently from `reg` because the compiler can allocate `al` and `ah` separately whereas `reg` reserves the whole register.
>
| PowerPC | `reg_nonzero` | None | `i8`, `i16`, `i32` |
| PowerPC | `freg` | None | `f32`, `f64` |
| wasm32 | `local` | None | `i8` `i16` `i32` `i64` `f32` `f64` |
+| BPF | `reg` | None | `i8` `i16` `i32` `i64` |
+| BPF | `wreg` | `alu32` | `i8` `i16` `i32` |
> **Note**: For the purposes of the above table pointers, function pointers and `isize`/`usize` are treated as the equivalent integer type (`i16`/`i32`/`i64` depending on the target).
| Hexagon | `r29` | `sp` |
| Hexagon | `r30` | `fr` |
| Hexagon | `r31` | `lr` |
+| BPF | `r[0-10]` | `w[0-10]` |
Some registers cannot be used for input or output operands:
unichr = chr
+channel = os.environ["DOC_RUST_LANG_ORG_CHANNEL"]
+
class CustomHTMLParser(HTMLParser):
"""simplified HTML parser.
def normalize_xpath(path):
+ path = path.replace("{{channel}}", channel)
if path.startswith('//'):
return '.' + path # avoid warnings
elif path.startswith('.//'):
def check_string(data, pat, regexp):
+ pat = pat.replace("{{channel}}", channel)
if not pat:
return True # special case a presence testing
elif regexp:
<Synthetic Name="[...]"><DisplayString>...</DisplayString></Synthetic>
</Expand>
</Type>
+ <Type Name="enum$<*>">
+ <Intrinsic Name="tag" Expression="variant0.variant$" />
+ <DisplayString Condition="tag() == 0">{tag(),en}</DisplayString>
+ <DisplayString Condition="tag() == 1" Optional="true">{tag(),en}</DisplayString>
+ <DisplayString Condition="tag() == 2" Optional="true">{tag(),en}</DisplayString>
+ <DisplayString Condition="tag() == 3" Optional="true">{tag(),en}</DisplayString>
+ <DisplayString Condition="tag() == 4" Optional="true">{tag(),en}</DisplayString>
+ <DisplayString Condition="tag() == 5" Optional="true">{tag(),en}</DisplayString>
+ <DisplayString Condition="tag() == 6" Optional="true">{tag(),en}</DisplayString>
+ <DisplayString Condition="tag() == 7" Optional="true">{tag(),en}</DisplayString>
+ <DisplayString Condition="tag() == 8" Optional="true">{tag(),en}</DisplayString>
+ <DisplayString Condition="tag() == 9" Optional="true">{tag(),en}</DisplayString>
+ <DisplayString Condition="tag() == 10" Optional="true">{tag(),en}</DisplayString>
+ <DisplayString Condition="tag() == 11" Optional="true">{tag(),en}</DisplayString>
+ <DisplayString Condition="tag() == 12" Optional="true">{tag(),en}</DisplayString>
+ <DisplayString Condition="tag() == 13" Optional="true">{tag(),en}</DisplayString>
+ <DisplayString Condition="tag() == 14" Optional="true">{tag(),en}</DisplayString>
+ <DisplayString Condition="tag() == 15" Optional="true">{tag(),en}</DisplayString>
+
+ <Expand>
+ <ExpandedItem Condition="tag() == 0">variant0</ExpandedItem>
+ <ExpandedItem Condition="tag() == 1" Optional="true">variant1</ExpandedItem>
+ <ExpandedItem Condition="tag() == 2" Optional="true">variant2</ExpandedItem>
+ <ExpandedItem Condition="tag() == 3" Optional="true">variant3</ExpandedItem>
+ <ExpandedItem Condition="tag() == 4" Optional="true">variant4</ExpandedItem>
+ <ExpandedItem Condition="tag() == 5" Optional="true">variant5</ExpandedItem>
+ <ExpandedItem Condition="tag() == 6" Optional="true">variant6</ExpandedItem>
+ <ExpandedItem Condition="tag() == 7" Optional="true">variant7</ExpandedItem>
+ <ExpandedItem Condition="tag() == 8" Optional="true">variant8</ExpandedItem>
+ <ExpandedItem Condition="tag() == 9" Optional="true">variant9</ExpandedItem>
+ <ExpandedItem Condition="tag() == 10" Optional="true">variant10</ExpandedItem>
+ <ExpandedItem Condition="tag() == 11" Optional="true">variant11</ExpandedItem>
+ <ExpandedItem Condition="tag() == 12" Optional="true">variant12</ExpandedItem>
+ <ExpandedItem Condition="tag() == 13" Optional="true">variant13</ExpandedItem>
+ <ExpandedItem Condition="tag() == 14" Optional="true">variant14</ExpandedItem>
+ <ExpandedItem Condition="tag() == 15" Optional="true">variant15</ExpandedItem>
+ </Expand>
+ </Type>
+
+ <!-- $T1 is the name of the enum, $T2 is the low value of the dataful variant tag,
+ $T3 is the high value of the dataful variant tag, $T4 is the name of the dataful variant -->
+ <Type Name="enum$<*, *, *, *>">
+ <Intrinsic Name="tag" Expression="discriminant" />
+ <Intrinsic Name="is_dataful" Expression="tag() >= $T2 && tag() <= $T3" />
+ <DisplayString Condition="is_dataful()">{"$T4",sb}({dataful_variant})</DisplayString>
+ <DisplayString Condition="!is_dataful()">{discriminant,en}</DisplayString>
+ <Expand>
+ <ExpandedItem Condition="is_dataful()">dataful_variant</ExpandedItem>
+ <Synthetic Condition="is_dataful()" Name="[variant]">
+ <DisplayString>{"$T4",sb}</DisplayString>
+ </Synthetic>
+ </Expand>
+ </Type>
</AutoVisualizer>
</Expand>
</Type>
- <Type Name="core::option::Option<*>">
- <DisplayString Condition="RUST$ENUM$DISR == 0x0">None</DisplayString>
- <DisplayString Condition="RUST$ENUM$DISR == 0x1">Some({__0})</DisplayString>
- <Expand>
- <Item Name="[value]" ExcludeView="simple" Condition="RUST$ENUM$DISR == 1">__0</Item>
- </Expand>
- </Type>
-
<Type Name="core::option::Option<*>" Priority="MediumLow">
<DisplayString Condition="*(void**)this == nullptr">None</DisplayString>
<DisplayString>Some({($T1 *)this})</DisplayString>
</Expand>
</Type>
- <Type Name="core::result::Result<*>">
- <DisplayString Condition="RUST$ENUM$DISR == 0x0">Ok({__0})</DisplayString>
- <DisplayString Condition="RUST$ENUM$DISR == 0x1">Err({(*($T2*) &__0)})</DisplayString>
- <Expand>
- <Item Name="[value]" Condition="RUST$ENUM$DISR == 0x0">__0</Item>
- <Item Name="[value]" Condition="RUST$ENUM$DISR == 0x1">(*($T2*) &__0)</Item>
- </Expand>
- </Type>
-
<Type Name="core::ptr::non_null::NonNull<*>">
<DisplayString>{(void*) pointer}</DisplayString>
<Expand>
}
}
GenericParamDefKind::Lifetime => {}
- GenericParamDefKind::Const { .. } => {}
+ GenericParamDefKind::Const { ref mut default, .. } => {
+ // We never want something like `impl<const N: usize = 10>`
+ default.take();
+ }
}
}
}
fn build_macro(cx: &mut DocContext<'_>, did: DefId, name: Symbol) -> clean::ItemKind {
- let imported_from = cx.tcx.original_crate_name(did.krate);
+ let imported_from = cx.tcx.crate_name(did.krate);
match cx.enter_resolver(|r| r.cstore().load_macro_untracked(did, cx.sess())) {
LoadedMacro::MacroDef(def, _) => {
let matchers: Vec<Span> = if let ast::ItemKind::MacroDef(ref def) = def.kind {
use rustc_span::hygiene::{AstPass, MacroKind};
use rustc_span::symbol::{kw, sym, Ident, Symbol};
use rustc_span::{self, ExpnKind};
+use rustc_target::spec::abi::Abi;
+use rustc_typeck::check::intrinsic::intrinsic_operation_unsafety;
use rustc_typeck::hir_ty_to_ty;
use std::collections::hash_map::Entry;
ty::PredicateKind::RegionOutlives(pred) => pred.clean(cx),
ty::PredicateKind::TypeOutlives(pred) => pred.clean(cx),
ty::PredicateKind::Projection(pred) => Some(pred.clean(cx)),
+ ty::PredicateKind::ConstEvaluatable(..) => None,
ty::PredicateKind::Subtype(..)
| ty::PredicateKind::WellFormed(..)
| ty::PredicateKind::ObjectSafe(..)
| ty::PredicateKind::ClosureKind(..)
- | ty::PredicateKind::ConstEvaluatable(..)
| ty::PredicateKind::ConstEquate(..)
| ty::PredicateKind::TypeWellFormedFromEnv(..) => panic!("not user writable"),
}
},
)
}
- ty::GenericParamDefKind::Const { .. } => (
+ ty::GenericParamDefKind::Const { has_default, .. } => (
self.name,
GenericParamDefKind::Const {
did: self.def_id,
ty: cx.tcx.type_of(self.def_id).clean(cx),
+ default: match has_default {
+ true => Some(cx.tcx.const_param_default(self.def_id).to_string()),
+ false => None,
+ },
},
),
};
synthetic,
},
),
- hir::GenericParamKind::Const { ref ty, default: _ } => (
+ hir::GenericParamKind::Const { ref ty, default } => (
self.name.ident().name,
GenericParamDefKind::Const {
did: cx.tcx.hir().local_def_id(self.hir_id).to_def_id(),
ty: ty.clean(cx),
- // FIXME(const_generics_defaults): add `default` field here for docs
+ default: default.map(|ct| {
+ let def_id = cx.tcx.hir().local_def_id(ct.hir_id);
+ ty::Const::from_anon_const(cx.tcx, def_id).to_string()
+ }),
},
),
};
decl,
generics,
header: hir::FnHeader {
- unsafety: hir::Unsafety::Unsafe,
+ unsafety: if abi == Abi::RustIntrinsic {
+ intrinsic_operation_unsafety(item.ident.name)
+ } else {
+ hir::Unsafety::Unsafe
+ },
abi,
constness: hir::Constness::NotConst,
asyncness: hir::IsAsync::NotAsync,
format!("{}/std/", s.trim_end_matches('/'))
}
Some(ExternalLocation::Unknown) | None => {
- "https://doc.rust-lang.org/nightly/std/".to_string()
+ format!("{}/std/", crate::DOC_RUST_LANG_ORG_CHANNEL)
}
};
// This is a primitive so the url is done "by hand".
crate fn is_crate(&self) -> bool {
self.is_mod() && self.def_id.as_real().map_or(false, |did| did.index == CRATE_DEF_INDEX)
}
-
crate fn is_mod(&self) -> bool {
self.type_() == ItemType::Module
}
// #[doc(...)]
if let Some(list) = attr.meta().as_ref().and_then(|mi| mi.meta_item_list()) {
for item in list {
- // #[doc(include)]
+ // #[doc(hidden)]
if !item.has_name(sym::cfg) {
continue;
}
SugaredDoc,
/// A doc fragment created from a "raw" `#[doc=""]` attribute.
RawDoc,
- /// A doc fragment created from a `#[doc(include="filename")]` attribute. Contains both the
- /// given filename and the file contents.
- Include { filename: Symbol },
}
// The goal of this function is to apply the `DocFragment` transformations that are required when
where
T: IntoIterator<Item = &'a DocFragment>,
{
- let mut prev_kind: Option<DocFragmentKind> = None;
iter.into_iter().fold(String::new(), |mut acc, frag| {
- if !acc.is_empty()
- && prev_kind
- .take()
- .map(|p| matches!(p, DocFragmentKind::Include { .. }) && p != frag.kind)
- .unwrap_or(false)
- {
- acc.push('\n');
- }
add_doc_fragment(&mut acc, &frag);
- prev_kind = Some(frag.kind);
acc
})
}
self.other_attrs.lists(name)
}
- /// 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.
- crate fn extract_include(mi: &ast::MetaItem) -> Option<(Symbol, Symbol)> {
- mi.meta_item_list().and_then(|list| {
- for meta in list {
- if meta.has_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<Symbol> = None;
- let mut contents: Option<Symbol> = None;
-
- for it in list {
- if it.has_name(sym::file) {
- if let Some(name) = it.value_str() {
- filename = Some(name);
- }
- } else if it.has_name(sym::contents) {
- if let Some(docs) = it.value_str() {
- contents = Some(docs);
- }
- }
- }
-
- if let (Some(filename), Some(contents)) = (filename, contents) {
- Some((filename, contents))
- } else {
- None
- }
- });
- }
- }
-
- None
- })
- }
-
crate fn has_doc_flag(&self, flag: Symbol) -> bool {
for attr in &self.other_attrs {
if !attr.has_name(sym::doc) {
let mut doc_strings: Vec<DocFragment> = vec![];
let mut doc_line = 0;
- fn update_need_backline(doc_strings: &mut Vec<DocFragment>, frag: &DocFragment) {
+ fn update_need_backline(doc_strings: &mut Vec<DocFragment>) {
if let Some(prev) = doc_strings.last_mut() {
- if matches!(prev.kind, DocFragmentKind::Include { .. })
- || prev.kind != frag.kind
- || prev.parent_module != frag.parent_module
- {
- // add a newline for extra padding between segments
- prev.need_backline = prev.kind == DocFragmentKind::SugaredDoc
- || prev.kind == DocFragmentKind::RawDoc
- } else {
- prev.need_backline = true;
- }
+ prev.need_backline = true;
}
}
indent: 0,
};
- update_need_backline(&mut doc_strings, &frag);
+ update_need_backline(&mut doc_strings);
doc_strings.push(frag);
None
} else {
- if attr.has_name(sym::doc) {
- if let Some(mi) = attr.meta() {
- if let Some((filename, contents)) = Attributes::extract_include(&mi) {
- let line = doc_line;
- doc_line += contents.as_str().lines().count();
- let frag = DocFragment {
- line,
- span: attr.span,
- doc: contents,
- kind: DocFragmentKind::Include { filename },
- parent_module,
- need_backline: false,
- indent: 0,
- };
- update_need_backline(&mut doc_strings, &frag);
- doc_strings.push(frag);
- }
- }
- }
Some(attr.clone())
}
};
let mut out = String::new();
add_doc_fragment(&mut out, &ori);
while let Some(new_frag) = iter.next() {
- if matches!(ori.kind, DocFragmentKind::Include { .. })
- || new_frag.kind != ori.kind
- || new_frag.parent_module != ori.parent_module
- {
+ if new_frag.kind != ori.kind || new_frag.parent_module != ori.parent_module {
break;
}
add_doc_fragment(&mut out, &new_frag);
Const {
did: DefId,
ty: Type,
+ default: Option<String>,
},
}
}
}
- crate 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",
- }
- }
-
crate fn impls(&self, tcx: TyCtxt<'_>) -> &'static ArrayVec<DefId, 4> {
Self::all_impls(tcx).get(self).expect("missing impl for primitive type")
}
})
}
- crate fn to_url_str(&self) -> &'static str {
- self.as_str()
- }
-
crate fn as_sym(&self) -> Symbol {
use PrimitiveType::*;
match self {
use crate::clean::blanket_impl::BlanketImplFinder;
use crate::clean::{
inline, Clean, Crate, Generic, GenericArg, GenericArgs, ImportSource, Item, ItemKind, Lifetime,
- MacroKind, Path, PathSegment, Primitive, PrimitiveType, ResolvedPath, Type, TypeBinding,
+ Path, PathSegment, Primitive, PrimitiveType, ResolvedPath, Type, TypeBinding,
};
use crate::core::DocContext;
use crate::formats::item_type::ItemType;
auto_impls.into_iter().chain(blanket_impls)
}
+/// If `res` has a documentation page associated, store it in the cache.
+///
+/// This is later used by [`href()`] to determine the HTML link for the item.
+///
+/// [`href()`]: crate::html::format::href
crate fn register_res(cx: &mut DocContext<'_>, res: Res) -> DefId {
+ use DefKind::*;
debug!("register_res({:?})", res);
let (did, kind) = match res {
- Res::Def(DefKind::Fn, i) => (i, ItemType::Function),
- Res::Def(DefKind::TyAlias, i) => (i, ItemType::Typedef),
- Res::Def(DefKind::Enum, i) => (i, ItemType::Enum),
- Res::Def(DefKind::Trait, i) => (i, ItemType::Trait),
Res::Def(DefKind::AssocTy | DefKind::AssocFn | DefKind::AssocConst, i) => {
+ // associated items are documented, but on the page of their parent
(cx.tcx.parent(i).unwrap(), ItemType::Trait)
}
- Res::Def(DefKind::Struct, i) => (i, ItemType::Struct),
- Res::Def(DefKind::Union, i) => (i, ItemType::Union),
- Res::Def(DefKind::Mod, i) => (i, ItemType::Module),
- Res::Def(DefKind::ForeignTy, i) => (i, ItemType::ForeignType),
- Res::Def(DefKind::Const, i) => (i, ItemType::Constant),
- Res::Def(DefKind::Static, i) => (i, ItemType::Static),
Res::Def(DefKind::Variant, i) => {
+ // variant items are documented, but on the page of their parent
(cx.tcx.parent(i).expect("cannot get parent def id"), ItemType::Enum)
}
- Res::Def(DefKind::Macro(mac_kind), i) => match mac_kind {
- MacroKind::Bang => (i, ItemType::Macro),
- MacroKind::Attr => (i, ItemType::ProcAttribute),
- MacroKind::Derive => (i, ItemType::ProcDerive),
- },
- Res::Def(DefKind::TraitAlias, i) => (i, ItemType::TraitAlias),
- Res::SelfTy(Some(def_id), _) => (def_id, ItemType::Trait),
- Res::SelfTy(_, Some((impl_def_id, _))) => return impl_def_id,
- _ => return res.def_id(),
+ // Each of these have their own page.
+ Res::Def(
+ kind
+ @
+ (Fn | TyAlias | Enum | Trait | Struct | Union | Mod | ForeignTy | Const | Static
+ | Macro(..) | TraitAlias),
+ i,
+ ) => (i, kind.into()),
+ // This is part of a trait definition; document the trait.
+ Res::SelfTy(Some(trait_def_id), _) => (trait_def_id, ItemType::Trait),
+ // This is an inherent impl; it doesn't have its own page.
+ Res::SelfTy(None, Some((impl_def_id, _))) => return impl_def_id,
+ Res::SelfTy(None, None)
+ | Res::PrimTy(_)
+ | Res::ToolMod
+ | Res::SelfCtor(_)
+ | Res::Local(_)
+ | Res::NonMacroAttr(_)
+ | Res::Err => return res.def_id(),
+ Res::Def(
+ TyParam | ConstParam | Ctor(..) | ExternCrate | Use | ForeignMod | AnonConst | OpaqueTy
+ | Field | LifetimeParam | GlobalAsm | Impl | Closure | Generator,
+ id,
+ ) => return id,
};
if did.is_local() {
return did;
&& attr.meta_item_list().map_or(false, |l| rustc_attr::list_contains_name(&l, flag))
})
}
+
+/// A link to `doc.rust-lang.org` that includes the channel name. Use this instead of manual links
+/// so that the channel is consistent.
+///
+/// Set by `bootstrap::Builder::doc_rust_lang_org_channel` in order to keep tests passing on beta/stable.
+crate const DOC_RUST_LANG_ORG_CHANNEL: &'static str = env!("DOC_RUST_LANG_ORG_CHANNEL");
use std::str::FromStr;
use rustc_data_structures::fx::FxHashMap;
-use rustc_session::config::{self, parse_crate_types_from_list, parse_externs, CrateType};
-use rustc_session::config::{get_cmd_lint_options, host_triple, nightly_options};
+use rustc_session::config::{
+ self, parse_crate_types_from_list, parse_externs, parse_target_triple, CrateType,
+};
+use rustc_session::config::{get_cmd_lint_options, nightly_options};
use rustc_session::config::{CodegenOptions, DebuggingOptions, ErrorOutputType, Externs};
use rustc_session::getopts;
use rustc_session::lint::Level;
return Err(0);
}
- if matches.opt_strs("print").iter().any(|opt| opt == "unversioned-files") {
- for file in crate::html::render::FILES_UNVERSIONED.keys() {
- println!("{}", file);
- }
- return Err(0);
- }
-
let color = config::parse_color(&matches);
let config::JsonConfig { json_rendered, json_unused_externs, .. } =
config::parse_json(&matches);
}
}
- let target =
- matches.opt_str("target").map_or(TargetTriple::from_triple(host_triple()), |target| {
- if target.ends_with(".json") {
- TargetTriple::TargetPath(PathBuf::from(target))
- } else {
- TargetTriple::TargetTriple(target)
- }
- });
+ let target = parse_target_triple(matches, error_format);
let show_coverage = matches.opt_present("show-coverage");
let generate_redirect_map = matches.opt_present("generate-redirect-map");
let show_type_layout = matches.opt_present("show-type-layout");
- let (lint_opts, describe_lints, lint_cap) = get_cmd_lint_options(matches, error_format);
+ let (lint_opts, describe_lints, lint_cap, _) =
+ get_cmd_lint_options(matches, error_format, &debugging_opts);
Ok(Options {
input,
// By default, rustdoc ignores all lints.
// Specifically unblock lints relevant to documentation or the lint machinery itself.
let mut lints_to_show = vec![
- // it's unclear whether this should be part of rustdoc directly (#77364)
+ // it's unclear whether these should be part of rustdoc directly (#77364)
rustc_lint::builtin::MISSING_DOCS.name.to_string(),
+ rustc_lint::builtin::INVALID_DOC_ATTRIBUTES.name.to_string(),
// these are definitely not part of rustdoc, but we want to warn on them anyway.
rustc_lint::builtin::RENAMED_AND_REMOVED_LINTS.name.to_string(),
rustc_lint::builtin::UNKNOWN_LINTS.name.to_string(),
let mut krate = tcx.sess.time("clean_crate", || clean::krate(&mut ctxt));
if krate.module.doc_value().map(|d| d.is_empty()).unwrap_or(true) {
- let help = "The following guide may be of use:\n\
- https://doc.rust-lang.org/nightly/rustdoc/how-to-write-documentation.html";
+ let help = format!(
+ "The following guide may be of use:\n\
+ {}/rustdoc/how-to-write-documentation.html",
+ crate::DOC_RUST_LANG_ORG_CHANNEL
+ );
tcx.struct_lint_node(
crate::lint::MISSING_CRATE_LEVEL_DOCS,
DocContext::as_local_hir_id(tcx, krate.module.def_id).unwrap(),
|lint| {
let mut diag =
lint.build("no documentation found for this crate's top-level module");
- diag.help(help);
+ diag.help(&help);
diag.emit();
},
);
let target = self.options.target.clone();
let target_str = target.to_string();
let unused_externs = self.unused_extern_reports.clone();
+ let no_run = config.no_run || options.no_run;
if !config.compile_fail {
self.compiling_test_count.fetch_add(1, Ordering::SeqCst);
}
// compiler failures are test failures
should_panic: testing::ShouldPanic::No,
allow_fail: config.allow_fail,
+ #[cfg(not(bootstrap))]
+ compile_fail: config.compile_fail,
+ #[cfg(not(bootstrap))]
+ no_run,
test_type: testing::TestType::DocTest,
},
testfn: testing::DynTestFn(box move || {
let report_unused_externs = |uext| {
unused_externs.lock().unwrap().push(uext);
};
- let no_run = config.no_run || options.no_run;
let res = run_test(
&test,
&cratename,
Ok(())
}
- clean::GenericParamDefKind::Const { ref ty, .. } => {
+ clean::GenericParamDefKind::Const { ref ty, ref default, .. } => {
if f.alternate() {
- write!(f, "const {}: {:#}", self.name, ty.print(cx))
+ write!(f, "const {}: {:#}", self.name, ty.print(cx))?;
} else {
- write!(f, "const {}: {}", self.name, ty.print(cx))
+ write!(f, "const {}: {}", self.name, ty.print(cx))?;
}
+
+ if let Some(default) = default {
+ if f.alternate() {
+ write!(f, " = {:#}", default)?;
+ } else {
+ write!(f, " = {}", default)?;
+ }
+ }
+
+ Ok(())
}
})
}
f,
"<a class=\"primitive\" href=\"{}primitive.{}.html\">",
"../".repeat(len),
- prim.to_url_str()
+ prim.as_sym()
)?;
needs_termination = true;
}
f,
"<a class=\"primitive\" href=\"{}/primitive.{}.html\">",
loc.join("/"),
- prim.to_url_str()
+ prim.as_sym()
)?;
needs_termination = true;
}
fmt::Display::fmt(&tybounds(param_names, cx), f)
}
clean::Infer => write!(f, "_"),
- clean::Primitive(prim) => primitive_link(f, prim, prim.as_str(), cx),
+ clean::Primitive(prim) => primitive_link(f, prim, &*prim.as_sym().as_str(), cx),
clean::BareFunction(ref decl) => {
if f.alternate() {
write!(
{sidebar}\
</nav>\
<div class=\"theme-picker\">\
- <button id=\"theme-picker\" aria-label=\"Pick another theme!\" aria-haspopup=\"menu\">\
+ <button id=\"theme-picker\" aria-label=\"Pick another theme!\" aria-haspopup=\"menu\" title=\"themes\">\
<img src=\"{static_root_path}brush{suffix}.svg\" \
width=\"18\" height=\"18\" \
alt=\"Pick another theme!\">\
placeholder=\"Click or press ‘S’ to search, ‘?’ for more options…\" \
type=\"search\">\
</div>\
- <button type=\"button\" id=\"help-button\">?</button>
- <a id=\"settings-menu\" href=\"{root_path}settings.html\">\
+ <button type=\"button\" id=\"help-button\" title=\"help\">?</button>\
+ <a id=\"settings-menu\" href=\"{root_path}settings.html\" title=\"settings\">\
<img src=\"{static_root_path}wheel{suffix}.svg\" \
width=\"18\" height=\"18\" \
alt=\"Change settings\">\
{after_content}\
<div id=\"rustdoc-vars\" data-root-path=\"{root_path}\" data-current-crate=\"{krate}\" \
data-search-index-js=\"{root_path}search-index{suffix}.js\" \
- data-search-js=\"{static_root_path}search{suffix}.js\"></div>
+ data-search-js=\"{static_root_path}search{suffix}.js\"></div>\
<script src=\"{static_root_path}main{suffix}.js\"></script>\
{extra_scripts}\
</body>\
}
},
title = page.title,
- description = page.description,
+ description = Escape(page.description),
keywords = page.keywords,
favicon = if layout.favicon.is_empty() {
format!(
<html lang="en">
<head>
<meta http-equiv="refresh" content="0;URL={url}">
+ <title>Redirection</title>
</head>
<body>
<p>Redirecting to <a href="{url}">{url}</a>...</p>
use std::sync::mpsc::{channel, Receiver};
use rustc_data_structures::fx::{FxHashMap, FxHashSet};
-use rustc_hir::def_id::{DefId, LOCAL_CRATE};
+use rustc_hir::def_id::LOCAL_CRATE;
use rustc_middle::ty::TyCtxt;
use rustc_session::Session;
use rustc_span::edition::Edition;
pub(super) render_redirect_pages: bool,
/// The map used to ensure all generated 'id=' attributes are unique.
pub(super) id_map: RefCell<IdMap>,
- /// Tracks section IDs for `Deref` targets so they match in both the main
- /// body and the sidebar.
- pub(super) deref_id_map: RefCell<FxHashMap<DefId, String>>,
/// Shared mutable state.
///
/// Issue for improving the situation: [#82381][]
// `Context` is cloned a lot, so we don't want the size to grow unexpectedly.
#[cfg(target_arch = "x86_64")]
-rustc_data_structures::static_assert_size!(Context<'_>, 152);
+rustc_data_structures::static_assert_size!(Context<'_>, 112);
/// Shared mutable state used in [`Context`] and elsewhere.
crate struct SharedContext<'tcx> {
)
};
let keywords = make_item_keywords(it);
+ let name;
+ let tyname_s = if it.is_crate() {
+ name = format!("{} crate", tyname);
+ name.as_str()
+ } else {
+ tyname.as_str()
+ };
let page = layout::Page {
- css_class: tyname.as_str(),
+ css_class: tyname_s,
root_path: &self.root_path(),
static_root_path: self.shared.static_root_path.as_deref(),
title: &title,
dst,
render_redirect_pages: false,
id_map: RefCell::new(id_map),
- deref_id_map: RefCell::new(FxHashMap::default()),
shared: Rc::new(scx),
cache: Rc::new(cache),
};
dst: self.dst.clone(),
render_redirect_pages: self.render_redirect_pages,
id_map: RefCell::new(IdMap::new()),
- deref_id_map: RefCell::new(FxHashMap::default()),
shared: Rc::clone(&self.shared),
cache: Rc::clone(&self.cache),
}
mod write_shared;
crate use context::*;
-crate use write_shared::FILES_UNVERSIONED;
use std::collections::VecDeque;
use std::default::Default;
if !e.is_empty() {
let mut e: Vec<&ItemEntry> = e.iter().collect();
e.sort();
- write!(f, "<h3 id=\"{}\">{}</h3><ul class=\"{} docblock\">", title, title, class);
+ write!(
+ f,
+ "<h3 id=\"{}\">{}</h3><ul class=\"{} docblock\">",
+ title.replace(' ', "-"), // IDs cannot contain whitespaces.
+ title,
+ class
+ );
for s in e.iter() {
write!(f, "<li>{}</li>", s.print());
</h1>",
);
// Note: print_entries does not escape the title, because we know the current set of titles
- // don't require escaping.
+ // doesn't require escaping.
print_entries(f, &self.structs, "Structs", "structs");
print_entries(f, &self.enums, "Enums", "enums");
print_entries(f, &self.unions, "Unions", "unions");
.into(),
("auto-hide-large-items", "Auto-hide item contents for large items.", true).into(),
("auto-hide-method-docs", "Auto-hide item methods' documentation", false).into(),
- ("auto-hide-trait-implementations", "Auto-hide trait implementation documentation", true)
+ ("auto-hide-trait-implementations", "Auto-hide trait implementation documentation", false)
.into(),
("auto-collapse-implementors", "Auto-hide implementors of a trait", true).into(),
("go-to-only-result", "Directly go to item in search if there is only one result", false)
}
}
-const ALLOWED_ATTRIBUTES: &[Symbol] = &[
- sym::export_name,
- sym::link_section,
- sym::must_use,
- sym::no_mangle,
- sym::repr,
- sym::non_exhaustive,
-];
+const ALLOWED_ATTRIBUTES: &[Symbol] =
+ &[sym::export_name, sym::link_section, sym::no_mangle, sym::repr, sym::non_exhaustive];
fn attributes(it: &clean::Item) -> Vec<String> {
it.attrs
RenderMode::Normal
}
AssocItemRender::DerefFor { trait_, type_, deref_mut_ } => {
- let id =
- cx.derive_id(small_url_encode(format!("deref-methods-{:#}", type_.print(cx))));
- debug!("Adding {} to deref id map", type_.print(cx));
- cx.deref_id_map.borrow_mut().insert(type_.def_id_full(cache).unwrap(), id.clone());
write!(
w,
- "<h2 id=\"{id}\" class=\"small-section-header\">\
+ "<h2 id=\"deref-methods\" class=\"small-section-header\">\
Methods from {trait_}<Target = {type_}>\
- <a href=\"#{id}\" class=\"anchor\"></a>\
+ <a href=\"#deref-methods\" class=\"anchor\"></a>\
</h2>",
- id = id,
trait_ = trait_.print(cx),
type_ = type_.print(cx),
);
);
}
}
+ if let AssocItemRender::DerefFor { .. } = what {
+ return;
+ }
if !traits.is_empty() {
let deref_impl = traits
.iter()
.any(|t| t.inner_impl().trait_.def_id_full(cache) == cx.cache.deref_mut_trait_did);
render_deref_methods(w, cx, impl_, containing_item, has_deref_mut);
}
-
- // If we were already one level into rendering deref methods, we don't want to render
- // anything after recursing into any further deref methods above.
- if let AssocItemRender::DerefFor { .. } = what {
- return;
- }
-
let (synthetic, concrete): (Vec<&&Impl>, Vec<&&Impl>) =
traits.iter().partition(|t| t.inner_impl().synthetic);
let (blanket_impl, concrete): (Vec<&&Impl>, _) =
// in documentation pages for trait with automatic implementations like "Send" and "Sync".
aliases: &[String],
) {
- let tcx = cx.tcx();
let cache = cx.cache();
let traits = &cache.traits;
let trait_ = i.trait_did_full(cache).map(|did| &traits[&did]);
})
})
.map(|item| format!("{}.{}", item.type_(), name));
- write!(w, "<h4 id=\"{}\" class=\"{}{}\">", id, item_type, in_trait_class,);
+ write!(
+ w,
+ "<div id=\"{}\" class=\"{}{} has-srclink\">",
+ id, item_type, in_trait_class,
+ );
w.write_str("<code>");
render_assoc_item(
w,
);
write!(w, "<a href=\"#{}\" class=\"anchor\"></a>", id);
write_srclink(cx, item, w);
- w.write_str("</h4>");
+ w.write_str("</div>");
}
}
clean::TypedefItem(ref tydef, _) => {
let source_id = format!("{}.{}", ItemType::AssocType, name);
let id = cx.derive_id(source_id.clone());
- write!(w, "<h4 id=\"{}\" class=\"{}{}\"><code>", id, item_type, in_trait_class);
+ write!(
+ w,
+ "<div id=\"{}\" class=\"{}{} has-srclink\"><code>",
+ id, item_type, in_trait_class
+ );
assoc_type(
w,
item,
);
w.write_str("</code>");
write!(w, "<a href=\"#{}\" class=\"anchor\"></a>", id);
- w.write_str("</h4>");
+ w.write_str("</div>");
}
clean::AssocConstItem(ref ty, ref default) => {
let source_id = format!("{}.{}", item_type, name);
let id = cx.derive_id(source_id.clone());
- write!(w, "<h4 id=\"{}\" class=\"{}{}\"><code>", id, item_type, in_trait_class);
+ write!(
+ w,
+ "<div id=\"{}\" class=\"{}{} has-srclink\"><code>",
+ id, item_type, in_trait_class
+ );
assoc_const(
w,
item,
);
write!(w, "<a href=\"#{}\" class=\"anchor\"></a>", id);
write_srclink(cx, item, w);
- w.write_str("</h4>");
+ w.write_str("</div>");
}
clean::AssocTypeItem(ref bounds, ref default) => {
let source_id = format!("{}.{}", item_type, name);
let id = cx.derive_id(source_id.clone());
- write!(w, "<h4 id=\"{}\" class=\"{}{}\"><code>", id, item_type, in_trait_class);
+ write!(w, "<div id=\"{}\" class=\"{}{}\"><code>", id, item_type, in_trait_class,);
assoc_type(
w,
item,
);
w.write_str("</code>");
write!(w, "<a href=\"#{}\" class=\"anchor\"></a>", id);
- w.write_str("</h4>");
+ w.write_str("</div>");
}
clean::StrippedItem(..) => return,
_ => panic!("can't make docs for trait item with name {:?}", item.name),
);
}
}
- let toggled = !impl_items.is_empty() || !default_impl_items.is_empty();
- let open_details = |close_tags: &mut String, is_collapsed: bool| {
+ if render_mode == RenderMode::Normal {
+ let toggled = !impl_items.is_empty() || !default_impl_items.is_empty();
if toggled {
close_tags.insert_str(0, "</details>");
- if is_collapsed {
- "<details class=\"rustdoc-toggle implementors-toggle\"><summary>"
- } else {
- "<details class=\"rustdoc-toggle implementors-toggle\" open><summary>"
- }
- } else {
- ""
+ write!(w, "<details class=\"rustdoc-toggle implementors-toggle\" open>");
}
- };
- if render_mode == RenderMode::Normal {
- let is_implementing_trait;
- let id = cx.derive_id(match i.inner_impl().trait_ {
- Some(ref t) => {
- is_implementing_trait = true;
- if is_on_foreign_type {
- get_id_for_impl_on_foreign_type(&i.inner_impl().for_, t, cx)
- } else {
- format!("impl-{}", small_url_encode(format!("{:#}", t.print(cx))))
- }
- }
- None => {
- is_implementing_trait = false;
- "impl".to_string()
- }
- });
- let aliases = if aliases.is_empty() {
- String::new()
- } else {
- format!(" data-aliases=\"{}\"", aliases.join(","))
- };
- if let Some(use_absolute) = use_absolute {
- write!(
- w,
- "{}<h3 id=\"{}\" class=\"impl\"{}><code class=\"in-band\">",
- open_details(&mut close_tags, is_implementing_trait),
- id,
- aliases
- );
- write!(w, "{}", i.inner_impl().print(use_absolute, cx));
- if show_def_docs {
- for it in &i.inner_impl().items {
- if let clean::TypedefItem(ref tydef, _) = *it.kind {
- w.write_str("<span class=\"where fmt-newline\"> ");
- assoc_type(
- w,
- it,
- &[],
- Some(&tydef.type_),
- AssocItemLink::Anchor(None),
- "",
- cx,
- );
- w.write_str(";</span>");
- }
- }
- }
- w.write_str("</code>");
- } else {
- write!(
- w,
- "{}<h3 id=\"{}\" class=\"impl\"{}><code class=\"in-band\">{}</code>",
- open_details(&mut close_tags, is_implementing_trait),
- id,
- aliases,
- i.inner_impl().print(false, cx)
- );
+ if toggled {
+ write!(w, "<summary>")
}
- write!(w, "<a href=\"#{}\" class=\"anchor\"></a>", id);
- render_stability_since_raw(
+ render_impl_summary(
w,
- i.impl_item.stable_since(tcx).as_deref(),
- i.impl_item.const_stable_since(tcx).as_deref(),
+ cx,
+ i,
outer_version,
outer_const_version,
+ show_def_docs,
+ use_absolute,
+ is_on_foreign_type,
+ aliases,
);
- write_srclink(cx, &i.impl_item, w);
- if !toggled {
- w.write_str("</h3>");
- } else {
- w.write_str("</h3></summary>");
+ if toggled {
+ write!(w, "</summary>")
}
-
if trait_.is_some() {
if let Some(portability) = portability(&i.impl_item, Some(parent)) {
write!(w, "<div class=\"item-info\">{}</div>", portability);
);
}
}
- if toggled {
+ if !default_impl_items.is_empty() || !impl_items.is_empty() {
w.write_str("<div class=\"impl-items\">");
w.push_buffer(default_impl_items);
- if trait_.is_some() && !impl_items.is_empty() {
- w.write_str("<details class=\"undocumented\"><summary></summary>");
- close_tags.insert_str(0, "</details>");
- }
w.push_buffer(impl_items);
close_tags.insert_str(0, "</div>");
}
w.write_str(&close_tags);
}
+fn render_impl_summary(
+ w: &mut Buffer,
+ cx: &Context<'_>,
+ i: &Impl,
+ outer_version: Option<&str>,
+ outer_const_version: Option<&str>,
+ show_def_docs: bool,
+ use_absolute: Option<bool>,
+ is_on_foreign_type: bool,
+ // This argument is used to reference same type with different paths to avoid duplication
+ // in documentation pages for trait with automatic implementations like "Send" and "Sync".
+ aliases: &[String],
+) {
+ let tcx = cx.tcx();
+ let id = cx.derive_id(match i.inner_impl().trait_ {
+ Some(ref t) => {
+ if is_on_foreign_type {
+ get_id_for_impl_on_foreign_type(&i.inner_impl().for_, t, cx)
+ } else {
+ format!("impl-{}", small_url_encode(format!("{:#}", t.print(cx))))
+ }
+ }
+ None => "impl".to_string(),
+ });
+ let aliases = if aliases.is_empty() {
+ String::new()
+ } else {
+ format!(" data-aliases=\"{}\"", aliases.join(","))
+ };
+ if let Some(use_absolute) = use_absolute {
+ write!(
+ w,
+ "<div id=\"{}\" class=\"impl has-srclink\"{}>\
+ <code class=\"in-band\">",
+ id, aliases
+ );
+ write!(w, "{}", i.inner_impl().print(use_absolute, cx));
+ if show_def_docs {
+ for it in &i.inner_impl().items {
+ if let clean::TypedefItem(ref tydef, _) = *it.kind {
+ w.write_str("<span class=\"where fmt-newline\"> ");
+ assoc_type(w, it, &[], Some(&tydef.type_), AssocItemLink::Anchor(None), "", cx);
+ w.write_str(";</span>");
+ }
+ }
+ }
+ w.write_str("</code>");
+ } else {
+ write!(
+ w,
+ "<div id=\"{}\" class=\"impl has-srclink\"{}>\
+ <code class=\"in-band\">{}</code>",
+ id,
+ aliases,
+ i.inner_impl().print(false, cx)
+ );
+ }
+ write!(w, "<a href=\"#{}\" class=\"anchor\"></a>", id);
+ render_stability_since_raw(
+ w,
+ i.impl_item.stable_since(tcx).as_deref(),
+ i.impl_item.const_stable_since(tcx).as_deref(),
+ outer_version,
+ outer_const_version,
+ );
+ write_srclink(cx, &i.impl_item, w);
+ w.write_str("</div>");
+}
+
fn print_sidebar(cx: &Context<'_>, it: &clean::Item, buffer: &mut Buffer) {
let parentlen = cx.current.len() - if it.is_mod() { 1 } else { 0 };
"<div class=\"block version\">\
<p>Version {}</p>\
</div>",
- Escape(version)
+ Escape(version),
);
}
}
write!(
buffer,
"<a id=\"all-types\" href=\"all.html\"><p>See all {}'s items</p></a>",
- it.name.as_ref().expect("crates always have a name")
+ it.name.as_ref().expect("crates always have a name"),
);
}
+
match *it.kind {
clean::StructItem(ref s) => sidebar_struct(cx, buffer, it, s),
clean::TraitItem(ref t) => sidebar_trait(cx, buffer, it, t),
clean::TypedefItem(_, _) => sidebar_typedef(cx, buffer, it),
clean::ModuleItem(ref m) => sidebar_module(buffer, &m.items),
clean::ForeignTypeItem => sidebar_foreign_type(cx, buffer, it),
- _ => (),
+ _ => {}
}
// The sidebar is designed to display sibling functions, modules and
// as much HTML as possible in order to allow non-JS-enabled browsers
// to navigate the documentation (though slightly inefficiently).
- buffer.write_str("<p class=\"location\">");
- for (i, name) in cx.current.iter().take(parentlen).enumerate() {
- if i > 0 {
- buffer.write_str("::<wbr>");
+ if !it.is_mod() {
+ buffer.write_str("<p class=\"location\">Other items in<br>");
+ for (i, name) in cx.current.iter().take(parentlen).enumerate() {
+ if i > 0 {
+ buffer.write_str("::<wbr>");
+ }
+ write!(
+ buffer,
+ "<a href=\"{}index.html\">{}</a>",
+ &cx.root_path()[..(cx.current.len() - i - 1) * 3],
+ *name
+ );
}
- write!(
- buffer,
- "<a href=\"{}index.html\">{}</a>",
- &cx.root_path()[..(cx.current.len() - i - 1) * 3],
- *name
- );
+ buffer.write_str("</p>");
}
- buffer.write_str("</p>");
// Sidebar refers to the enclosing module, not this module.
- let relpath = if it.is_mod() { "../" } else { "" };
+ let relpath = if it.is_mod() && parentlen != 0 { "./" } else { "" };
write!(
buffer,
"<div id=\"sidebar-vars\" data-name=\"{name}\" data-ty=\"{ty}\" data-relpath=\"{path}\">\
ty = it.type_(),
path = relpath
);
-
- if parentlen == 0 {
- write!(
- buffer,
- "<script defer src=\"{}sidebar-items{}.js\"></script>",
- relpath, cx.shared.resource_suffix
- );
- } else {
- write!(buffer, "<script defer src=\"{}sidebar-items.js\"></script>", relpath);
- }
-
+ write!(buffer, "<script defer src=\"{}sidebar-items.js\"></script>", relpath);
// Closes sidebar-elems div.
buffer.write_str("</div>");
}
.flat_map(|i| get_methods(i.inner_impl(), true, &mut used_links, deref_mut, c))
.collect::<Vec<_>>();
if !ret.is_empty() {
- let deref_id_map = cx.deref_id_map.borrow();
- let id = deref_id_map
- .get(&real_target.def_id_full(c).unwrap())
- .expect("Deref section without derived id");
write!(
out,
- "<a class=\"sidebar-title\" href=\"#{}\">Methods from {}<Target={}></a>",
- id,
+ "<a class=\"sidebar-title\" href=\"#deref-methods\">Methods from {}<Target={}></a>",
Escape(&format!("{:#}", impl_.inner_impl().trait_.as_ref().unwrap().print(cx))),
Escape(&format!("{:#}", real_target.print(cx))),
);
}
}
-fn item_ty_to_strs(ty: &ItemType) -> (&'static str, &'static str) {
- match *ty {
+fn item_ty_to_strs(ty: ItemType) -> (&'static str, &'static str) {
+ match ty {
ItemType::ExternCrate | ItemType::Import => ("reexports", "Re-exports"),
ItemType::Module => ("modules", "Modules"),
ItemType::Struct => ("structs", "Structs"),
fn sidebar_module(buf: &mut Buffer, items: &[clean::Item]) {
let mut sidebar = String::new();
+ // Re-exports are handled a bit differently because they can be extern crates or imports.
if items.iter().any(|it| {
- it.type_() == ItemType::ExternCrate || (it.type_() == ItemType::Import && !it.is_stripped())
+ it.name.is_some()
+ && (it.type_() == ItemType::ExternCrate
+ || (it.type_() == ItemType::Import && !it.is_stripped()))
}) {
- sidebar.push_str("<li><a href=\"#reexports\">Re-exports</a></li>");
+ let (id, name) = item_ty_to_strs(ItemType::Import);
+ sidebar.push_str(&format!("<li><a href=\"#{}\">{}</a></li>", id, name));
}
// ordering taken from item_module, reorder, where it prioritized elements in a certain order
ItemType::ForeignType,
ItemType::Keyword,
] {
- if items.iter().any(|it| !it.is_stripped() && it.type_() == myty) {
- let (short, name) = item_ty_to_strs(&myty);
- sidebar.push_str(&format!(
- "<li><a href=\"#{id}\">{name}</a></li>",
- id = short,
- name = name
- ));
+ if items.iter().any(|it| !it.is_stripped() && it.type_() == myty && it.name.is_some()) {
+ let (id, name) = item_ty_to_strs(myty);
+ sidebar.push_str(&format!("<li><a href=\"#{}\">{}</a></li>", id, name));
}
}
);
}
}
- write!(buf, "<a class=\"{}\" href=\"\">{}</a>", item.type_(), item.name.as_ref().unwrap());
+ write!(buf, "<a class=\"{}\" href=\"#\">{}</a>", item.type_(), item.name.as_ref().unwrap());
write!(
buf,
- "<button id=\"copy-path\" onclick=\"copy_path(this)\">\
+ "<button id=\"copy-path\" onclick=\"copy_path(this)\" title=\"copy path\">\
<img src=\"{static_root_path}clipboard{suffix}.svg\" \
width=\"19\" height=\"18\" \
- alt=\"Copy item import\">\
+ alt=\"Copy item import\" \
+ title=\"Copy item import to clipboard\">\
</button>",
static_root_path = page.get_static_root_path(),
suffix = page.resource_suffix,
w.write_str("</table>");
}
curty = myty;
- let (short, name) = item_ty_to_strs(&myty.unwrap());
+ let (short, name) = item_ty_to_strs(myty.unwrap());
write!(
w,
"<h2 id=\"{id}\" class=\"section-header\">\
info!("Documenting {} on {:?}", name, t.name);
let item_type = m.type_();
let id = cx.derive_id(format!("{}.{}", item_type, name));
- write!(w, "<details class=\"rustdoc-toggle\" open><summary>");
- write!(w, "<h3 id=\"{id}\" class=\"method\"><code>", id = id,);
+ let mut content = Buffer::empty_from(w);
+ document(&mut content, cx, m, Some(t));
+ let toggled = !content.is_empty();
+ if toggled {
+ write!(w, "<details class=\"rustdoc-toggle\" open><summary>");
+ }
+ write!(w, "<div id=\"{}\" class=\"method has-srclink\"><code>", id);
render_assoc_item(w, m, AssocItemLink::Anchor(Some(&id)), ItemType::Impl, cx);
w.write_str("</code>");
render_stability_since(w, m, t, cx.tcx());
write_srclink(cx, m, w);
- w.write_str("</h3></summary>");
- document(w, cx, m, Some(t));
+ w.write_str("</div>");
+ if toggled {
+ write!(w, "</summary>");
+ w.push_buffer(content);
+ write!(w, "</details>");
+ }
}
if !types.is_empty() {
if fields.peek().is_some() {
write!(
w,
- "<h2 id=\"fields\" class=\"fields small-section-header\">
+ "<h2 id=\"fields\" class=\"fields small-section-header\">\
Fields<a href=\"#fields\" class=\"anchor\"></a></h2>"
);
for (field, ty) in fields {
if !e.variants.is_empty() {
write!(
w,
- "<h2 id=\"variants\" class=\"variants small-section-header\">
- Variants{}<a href=\"#variants\" class=\"anchor\"></a></h2>\n",
+ "<h2 id=\"variants\" class=\"variants small-section-header\">\
+ Variants{}<a href=\"#variants\" class=\"anchor\"></a></h2>",
document_non_exhaustive_header(it)
);
document_non_exhaustive(w, it);
if fields.peek().is_some() {
write!(
w,
- "<h2 id=\"fields\" class=\"fields small-section-header\">
+ "<h2 id=\"fields\" class=\"fields small-section-header\">\
Fields{}<a href=\"#fields\" class=\"anchor\"></a></h2>",
document_non_exhaustive_header(it)
);
w.write_str(
"Non-exhaustive structs could have additional fields added in future. \
Therefore, non-exhaustive structs cannot be constructed in external crates \
- using the traditional <code>Struct {{ .. }}</code> syntax; cannot be \
+ using the traditional <code>Struct { .. }</code> syntax; cannot be \
matched against without a wildcard <code>..</code>; and \
struct update syntax will not work.",
);
use crate::error::Error;
use crate::html::{layout, static_files};
-crate static FILES_UNVERSIONED: Lazy<FxHashMap<&str, &[u8]>> = Lazy::new(|| {
+static FILES_UNVERSIONED: Lazy<FxHashMap<&str, &[u8]>> = Lazy::new(|| {
map! {
"FiraSans-Regular.woff2" => static_files::fira_sans::REGULAR2,
"FiraSans-Medium.woff2" => static_files::fira_sans::MEDIUM2,
"SourceCodePro-Semibold.ttf.woff" => static_files::source_code_pro::SEMIBOLD,
"SourceCodePro-It.ttf.woff" => static_files::source_code_pro::ITALIC,
"SourceCodePro-LICENSE.txt" => static_files::source_code_pro::LICENSE,
+ "noto-sans-kr-v13-korean-regular.woff" => static_files::noto_sans_kr::REGULAR,
+ "noto-sans-kr-v13-korean-regular-LICENSE.txt" => static_files::noto_sans_kr::LICENSE,
"LICENSE-MIT.txt" => static_files::LICENSE_MIT,
"LICENSE-APACHE.txt" => static_files::LICENSE_APACHE,
"COPYRIGHT.txt" => static_files::COPYRIGHT,
)?;
write_minify("search.js", static_files::SEARCH_JS)?;
write_minify("settings.js", static_files::SETTINGS_JS)?;
- write_minify("sidebar-items.js", static_files::sidebar::ITEMS)?;
if cx.shared.include_sources {
write_minify("source-script.js", static_files::sidebar::SOURCE_SCRIPT)?;
}
}());
- function addSidebarCrates(crates) {
- // Draw a convenient sidebar of known crates if we have a listing
- if (window.rootPath === "../" || window.rootPath === "./") {
- var sidebar = document.getElementsByClassName("sidebar-elems")[0];
- if (sidebar) {
- var div = document.createElement("div");
- div.className = "block crate";
- div.innerHTML = "<h3>Crates</h3>";
- var ul = document.createElement("ul");
- div.appendChild(ul);
-
- for (var i = 0; i < crates.length; ++i) {
- var klass = "crate";
- if (window.rootPath !== "./" && crates[i] === window.currentCrate) {
- klass += " current";
- }
- var link = document.createElement("a");
- link.href = window.rootPath + crates[i] + "/index.html";
- link.className = klass;
- link.textContent = crates[i];
-
- var li = document.createElement("li");
- li.appendChild(link);
- ul.appendChild(li);
- }
- sidebar.appendChild(div);
- }
- }
- }
-
// delayed sidebar rendering.
window.initSidebarItems = function(items) {
var sidebar = document.getElementsByClassName("sidebar-elems")[0];
var current = window.sidebarCurrent;
+ function addSidebarCrates(crates) {
+ if (!hasClass(document.body, "crate")) {
+ // We only want to list crates on the crate page.
+ return;
+ }
+ // Draw a convenient sidebar of known crates if we have a listing
+ var div = document.createElement("div");
+ div.className = "block crate";
+ div.innerHTML = "<h3>Crates</h3>";
+ var ul = document.createElement("ul");
+ div.appendChild(ul);
+
+ for (var i = 0; i < crates.length; ++i) {
+ var klass = "crate";
+ if (window.rootPath !== "./" && crates[i] === window.currentCrate) {
+ klass += " current";
+ }
+ var link = document.createElement("a");
+ link.href = window.rootPath + crates[i] + "/index.html";
+ link.className = klass;
+ link.textContent = crates[i];
+
+ var li = document.createElement("li");
+ li.appendChild(link);
+ ul.appendChild(li);
+ }
+ sidebar.appendChild(div);
+ }
+
function block(shortty, longty) {
var filtered = items[shortty];
if (!filtered) {
ul.appendChild(li);
}
div.appendChild(ul);
- if (sidebar) {
- sidebar.appendChild(div);
- }
+ sidebar.appendChild(div);
}
- block("primitive", "Primitive Types");
- block("mod", "Modules");
- block("macro", "Macros");
- block("struct", "Structs");
- block("enum", "Enums");
- block("union", "Unions");
- block("constant", "Constants");
- block("static", "Statics");
- block("trait", "Traits");
- block("fn", "Functions");
- block("type", "Type Definitions");
- block("foreigntype", "Foreign Types");
- block("keyword", "Keywords");
- block("traitalias", "Trait Aliases");
-
- // `crates{version}.js` should always be loaded before this script, so we can use it safely.
- addSidebarCrates(window.ALL_CRATES);
+ if (sidebar) {
+ var isModule = hasClass(document.body, "mod");
+ if (!isModule) {
+ block("primitive", "Primitive Types");
+ block("mod", "Modules");
+ block("macro", "Macros");
+ block("struct", "Structs");
+ block("enum", "Enums");
+ block("union", "Unions");
+ block("constant", "Constants");
+ block("static", "Statics");
+ block("trait", "Traits");
+ block("fn", "Functions");
+ block("type", "Type Definitions");
+ block("foreigntype", "Foreign Types");
+ block("keyword", "Keywords");
+ block("traitalias", "Trait Aliases");
+ }
+
+ // `crates{version}.js` should always be loaded before this script, so we can use
+ // it safely.
+ addSidebarCrates(window.ALL_CRATES);
+ }
};
window.register_implementors = function(imp) {
var hideMethodDocs = getSettingValue("auto-hide-method-docs") === "true";
var hideImplementors = getSettingValue("auto-collapse-implementors") !== "false";
- var hideImplementations = getSettingValue("auto-hide-trait-implementations") !== "false";
+ var hideImplementations = getSettingValue("auto-hide-trait-implementations") === "true";
var hideLargeItemContents = getSettingValue("auto-hide-large-items") !== "false";
- function openImplementors(id) {
+ function setImplementorsTogglesOpen(id, open) {
var list = document.getElementById(id);
if (list !== null) {
onEachLazy(list.getElementsByClassName("implementors-toggle"), function(e) {
- e.open = true;
+ e.open = open;
});
}
}
- if (!hideImplementations) {
- openImplementors("trait-implementations-list");
- openImplementors("blanket-implementations-list");
+ if (hideImplementations) {
+ setImplementorsTogglesOpen("trait-implementations-list", false);
+ setImplementorsTogglesOpen("blanket-implementations-list", false);
}
if (!hideImplementors) {
- openImplementors("implementors-list");
+ setImplementorsTogglesOpen("implementors-list", true);
}
onEachLazy(document.getElementsByClassName("rustdoc-toggle"), function (e) {
--- /dev/null
+Copyright 2014, 2015 Adobe Systems Incorporated (http://www.adobe.com/), with Reserved Font Name 'Source'. All Rights Reserved. Source is a trademark of Adobe Systems Incorporated in the United States and/or other countries.
+
+This Font Software is licensed under the SIL Open Font License, Version 1.1.
+
+This license is copied below, and is also available with a FAQ at: http://scripts.sil.org/OFL
+
+
+-----------------------------------------------------------
+SIL OPEN FONT LICENSE Version 1.1 - 26 February 2007
+-----------------------------------------------------------
+
+PREAMBLE
+The goals of the Open Font License (OFL) are to stimulate worldwide
+development of collaborative font projects, to support the font creation
+efforts of academic and linguistic communities, and to provide a free and
+open framework in which fonts may be shared and improved in partnership
+with others.
+
+The OFL allows the licensed fonts to be used, studied, modified and
+redistributed freely as long as they are not sold by themselves. The
+fonts, including any derivative works, can be bundled, embedded,
+redistributed and/or sold with any software provided that any reserved
+names are not used by derivative works. The fonts and derivatives,
+however, cannot be released under any other type of license. The
+requirement for fonts to remain under this license does not apply
+to any document created using the fonts or their derivatives.
+
+DEFINITIONS
+"Font Software" refers to the set of files released by the Copyright
+Holder(s) under this license and clearly marked as such. This may
+include source files, build scripts and documentation.
+
+"Reserved Font Name" refers to any names specified as such after the
+copyright statement(s).
+
+"Original Version" refers to the collection of Font Software components as
+distributed by the Copyright Holder(s).
+
+"Modified Version" refers to any derivative made by adding to, deleting,
+or substituting -- in part or in whole -- any of the components of the
+Original Version, by changing formats or by porting the Font Software to a
+new environment.
+
+"Author" refers to any designer, engineer, programmer, technical
+writer or other person who contributed to the Font Software.
+
+PERMISSION & CONDITIONS
+Permission is hereby granted, free of charge, to any person obtaining
+a copy of the Font Software, to use, study, copy, merge, embed, modify,
+redistribute, and sell modified and unmodified copies of the Font
+Software, subject to the following conditions:
+
+1) Neither the Font Software nor any of its individual components,
+in Original or Modified Versions, may be sold by itself.
+
+2) Original or Modified Versions of the Font Software may be bundled,
+redistributed and/or sold with any software, provided that each copy
+contains the above copyright notice and this license. These can be
+included either as stand-alone text files, human-readable headers or
+in the appropriate machine-readable metadata fields within text or
+binary files as long as those fields can be easily viewed by the user.
+
+3) No Modified Version of the Font Software may use the Reserved Font
+Name(s) unless explicit written permission is granted by the corresponding
+Copyright Holder. This restriction only applies to the primary font name as
+presented to the users.
+
+4) The name(s) of the Copyright Holder(s) or the Author(s) of the Font
+Software shall not be used to promote, endorse or advertise any
+Modified Version, except to acknowledge the contribution(s) of the
+Copyright Holder(s) and the Author(s) or with their explicit written
+permission.
+
+5) The Font Software, modified or unmodified, in part or in whole,
+must be distributed entirely under this license, and must not be
+distributed under any other license. The requirement for fonts to
+remain under this license does not apply to any document created
+using the Font Software.
+
+TERMINATION
+This license becomes null and void if any of the above conditions are
+not met.
+
+DISCLAIMER
+THE FONT SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO ANY WARRANTIES OF
+MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT
+OF COPYRIGHT, PATENT, TRADEMARK, OR OTHER RIGHT. IN NO EVENT SHALL THE
+COPYRIGHT HOLDER BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+INCLUDING ANY GENERAL, SPECIAL, INDIRECT, INCIDENTAL, OR CONSEQUENTIAL
+DAMAGES, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+FROM, OUT OF THE USE OR INABILITY TO USE THE FONT SOFTWARE OR FROM
+OTHER DEALINGS IN THE FONT SOFTWARE.
font-display: swap;
}
+/* Avoid using legacy CJK serif fonts in Windows like Batang */
+@font-face {
+ font-family: 'Noto Sans KR';
+ src: url("noto-sans-kr-v13-korean-regular.woff") format("woff");
+ font-display: swap;
+ unicode-range: U+A960-A97F, U+AC00-D7AF, U+D7B0-D7FF;
+}
+
* {
-webkit-box-sizing: border-box;
-moz-box-sizing: border-box;
/* General structure and fonts */
body {
- font: 16px/1.4 "Source Serif 4", serif;
+ font: 16px/1.4 "Source Serif 4", "Noto Sans KR", serif;
margin: 0;
position: relative;
padding: 10px 15px 20px 15px;
h3 {
font-size: 1.3em;
}
-h1, h2, h3:not(.impl):not(.method):not(.type):not(.tymethod):not(.notable),
-h4:not(.method):not(.type):not(.tymethod):not(.associatedconstant):not(.associatedtype) {
+h1, h2, h3, h4 {
font-weight: 500;
margin: 20px 0 15px 0;
padding-bottom: 6px;
h1.fqn > .in-band > a:hover {
text-decoration: underline;
}
-h2, h3:not(.impl):not(.method):not(.type):not(.tymethod),
-h4:not(.method):not(.type):not(.tymethod):not(.associatedconstant):not(.associatedtype) {
+h2, h3, h4 {
border-bottom: 1px solid;
}
-h3.impl, h3.method, h4.method, h3.type, h4.type, h4.associatedconstant, h4.associatedtype {
+.impl, .impl-items .method,
+.impl-items .type, .impl-items .associatedconstant,
+.impl-items .associatedtype {
flex-basis: 100%;
font-weight: 600;
margin-top: 16px;
margin-bottom: 10px;
position: relative;
}
-h3.impl, h3.method, h4.method.trait-impl, h3.type,
-h4.type.trait-impl, h4.associatedconstant.trait-impl, h4.associatedtype.trait-impl {
+.impl, .method.trait-impl,
+.type.trait-impl,
+.associatedconstant.trait-impl,
+.associatedtype.trait-impl {
padding-left: 15px;
}
+div.impl-items > div {
+ padding-left: 0;
+}
+
h1, h2, h3, h4,
.sidebar, a.source, .search-input, .search-results .result-name,
.content table td:first-child > a,
-div.item-list .out-of-band,
+div.item-list .out-of-band, span.since,
#source-sidebar, #sidebar-toggle,
details.rustdoc-toggle > summary::before,
details.undocumented > summary::before,
-.content ul.crate a.crate,
+div.impl-items > div:not(.docblock):not(.item-info),
+.content ul.crate a.crate, a.srclink,
/* This selector is for the items listed in the "all items" page. */
#main > ul.docblock > li > a {
font-family: "Fira Sans", Arial, sans-serif;
border: none;
}
-.location a:first-child {
+.location a:first-of-type {
font-weight: 500;
}
+.location a:hover {
+ text-decoration: underline;
+}
.block {
padding: 0;
margin-bottom: 14px;
}
.block h2, .block h3 {
- margin-top: 0;
- margin-bottom: 8px;
text-align: center;
}
.block ul, .block li {
font-weight: normal;
}
-h3.impl > .out-of-band {
- font-size: 21px;
-}
-
-h4.method > .out-of-band {
- font-size: 19px;
-}
-
-h4 > code, h3 > code, .invisible > code {
+.method > code, .trait-impl > code, .invisible > code {
max-width: calc(100% - 41px);
display: block;
}
}
.content .multi-column li { width: 100%; display: inline-block; }
-.content .method {
+.content > .methods > .method {
font-size: 1em;
position: relative;
}
font-size: 0.8em;
}
-.content .methods > div:not(.notable-traits):not(.methods) {
+.content .methods > div:not(.notable-traits):not(.method) {
margin-left: 40px;
margin-bottom: 15px;
}
margin-left: 20px;
margin-top: -34px;
}
-.content .docblock > .impl-items > h4 {
- border-bottom: 0;
-}
.content .docblock >.impl-items .table-display {
margin: 0;
}
text-decoration: underline;
}
-.invisible > .srclink, h4 > code + .srclink, h3 > code + .srclink {
+.invisible > .srclink,
+.method > code + .srclink {
position: absolute;
top: 0;
right: 0;
.search-results .result-name > span {
display: inline-block;
-}
-
-.result-name span.primitive::after {
- content: ' (primitive type)';
- font-style: italic;
-}
-
-.result-name span.keyword::after {
- content: ' (keyword)';
- font-style: italic;
+ margin: 0;
+ font-weight: normal;
}
body.blur > :not(#help) {
flex-grow: 1;
}
-.impl-items h4, h4.impl, h3.impl, .methods h3 {
+.has-srclink {
display: flex;
flex-basis: 100%;
font-size: 16px;
margin: 0;
}
+.notable-traits .notable {
+ margin: 0;
+ margin-bottom: 13px;
+ font-size: 19px;
+ font-weight: 600;
+}
+
.notable-traits .docblock code.content{
margin: 0;
padding: 0;
margin-left: 5px;
}
-h4 > .notable-traits {
- position: absolute;
- left: -44px;
- top: 2px;
-}
-
#all-types {
text-align: center;
border: 1px solid;
border-top: 1px solid;
}
-
-
-h3.notable {
- margin: 0;
- margin-bottom: 13px;
- font-size: 19px;
-}
-
kbd {
display: inline-block;
padding: 3px 5px;
details.rustdoc-toggle > summary:not(.hideme)::before {
position: absolute;
left: -23px;
- top: initial;
+ top: 3px;
}
.impl-items > details.rustdoc-toggle > summary:not(.hideme)::before,
.undocumented > details.rustdoc-toggle > summary:not(.hideme)::before {
position: absolute;
- top: 3px;
left: -2px;
}
padding: 0;
}
- .content h4 > .out-of-band {
- position: inherit;
- }
-
#search {
margin-left: 0;
}
z-index: 1;
}
- h4 > .notable-traits {
+ .notable-traits {
position: absolute;
left: -22px;
top: 24px;
extraClass = " active";
}
- var output = "";
+ var output = document.createElement("div");
var duplicates = {};
var length = 0;
if (array.length > 0) {
- output = "<div class=\"search-results " + extraClass + "\">";
+ output.className = "search-results " + extraClass;
array.forEach(function(item) {
- var name, type;
-
- name = item.name;
- type = itemTypes[item.ty];
-
if (item.is_alias !== true) {
if (duplicates[item.fullPath]) {
return;
}
duplicates[item.fullPath] = true;
}
+
+ var name = item.name;
+ var type = itemTypes[item.ty];
+
length += 1;
- output += "<a class=\"result-" + type + "\" href=\"" + item.href + "\">" +
- "<div><div class=\"result-name\">" +
- (item.is_alias === true ?
- ("<span class=\"alias\"><b>" + item.alias + " </b></span><span " +
- "class=\"grey\"><i> - see </i></span>") : "") +
- item.displayPath + "<span class=\"" + type + "\">" +
- name + "</span></div><div class=\"desc\">" +
- "<span>" + item.desc +
- " </span></div></div></a>";
+ var extra = "";
+ if (type === "primitive") {
+ extra = " <i>(primitive type)</i>";
+ } else if (type === "keyword") {
+ extra = " <i>(keyword)</i>";
+ }
+
+ var link = document.createElement("a");
+ link.className = "result-" + type;
+ link.href = item.href;
+
+ var wrapper = document.createElement("div");
+ var resultName = document.createElement("div");
+ resultName.className = "result-name";
+
+ if (item.is_alias) {
+ var alias = document.createElement("span");
+ alias.className = "alias";
+
+ var bold = document.createElement("b");
+ bold.innerText = item.alias;
+ alias.appendChild(bold);
+
+ alias.insertAdjacentHTML(
+ "beforeend",
+ "<span class=\"grey\"><i> - see </i></span>");
+
+ resultName.appendChild(alias);
+ }
+ resultName.insertAdjacentHTML(
+ "beforeend",
+ item.displayPath + "<span class=\"" + type + "\">" + name + extra + "</span>");
+ wrapper.appendChild(resultName);
+
+ var description = document.createElement("div");
+ description.className = "desc";
+ var spanDesc = document.createElement("span");
+ spanDesc.insertAdjacentHTML("beforeend", item.desc);
+
+ description.appendChild(spanDesc);
+ wrapper.appendChild(description);
+ link.appendChild(wrapper);
+ output.appendChild(link);
});
- output += "</div>";
} else {
- output = "<div class=\"search-failed\"" + extraClass + ">No results :(<br/>" +
+ output.className = "search-failed" + extraClass;
+ output.innerHTML = "No results :(<br/>" +
"Try on <a href=\"https://duckduckgo.com/?q=" +
encodeURIComponent("rust " + query.query) +
"\">DuckDuckGo</a>?<br/><br/>" +
"href=\"https://doc.rust-lang.org/book/index.html\">Rust Book</a> for " +
"introductions to language features and the language itself.</li><li><a " +
"href=\"https://docs.rs\">Docs.rs</a> for documentation of crates released on" +
- " <a href=\"https://crates.io/\">crates.io</a>.</li></ul></div>";
+ " <a href=\"https://crates.io/\">crates.io</a>.</li></ul>";
}
return [output, length];
}
makeTabHeader(0, "In Names", ret_others[1]) +
makeTabHeader(1, "In Parameters", ret_in_args[1]) +
makeTabHeader(2, "In Return Types", ret_returned[1]) +
- "</div><div id=\"results\">" +
- ret_others[0] + ret_in_args[0] + ret_returned[0] + "</div>";
+ "</div>";
+
+ var resultsElem = document.createElement("div");
+ resultsElem.id = "results";
+ resultsElem.appendChild(ret_others[0]);
+ resultsElem.appendChild(ret_in_args[0]);
+ resultsElem.appendChild(ret_returned[0]);
search.innerHTML = output;
+ search.appendChild(resultsElem);
// Reset focused elements.
searchState.focusedByTab = [null, null, null];
searchState.showResults(search);
+++ /dev/null
-initSidebarItems({});
color: #c5c5c5;
}
-h1, h2, h3:not(.impl):not(.method):not(.type):not(.tymethod),
-h4:not(.method):not(.type):not(.tymethod) {
+h1, h2, h3, h4 {
color: white;
}
h1.fqn {
h1.fqn a {
color: #fff;
}
-h2, h3:not(.impl):not(.method):not(.type):not(.tymethod) {
+h2, h3, h4 {
border-bottom-color: #5c6773;
}
-h4:not(.method):not(.type):not(.tymethod):not(.associatedconstant) {
+h4 {
border: none;
}
border-color: #5c6773;
}
+.notable-traits-tooltiptext .notable {
+ border-bottom-color: #5c6773;
+}
+
#titles > button.selected {
background-color: #141920 !important;
border-bottom: 1px solid #ffb44c !important;
background-color: rgba(70, 70, 70, 0.33);
}
-.search-results td span.alias {
+.search-results .result-name span.alias {
color: #c5c5c5;
}
-.search-results td span.grey {
+.search-results .result-name span.grey {
color: #999;
}
color: #ddd;
}
-h1, h2, h3:not(.impl):not(.method):not(.type):not(.tymethod),
-h4:not(.method):not(.type):not(.tymethod) {
+h1, h2, h3, h4 {
color: #ddd;
}
h1.fqn {
border-bottom-color: #d2d2d2;
}
-h2, h3:not(.impl):not(.method):not(.type):not(.tymethod),
-h4:not(.method):not(.type):not(.tymethod) {
+h2, h3, h4 {
border-bottom-color: #d2d2d2;
}
border-color: #777;
}
+.notable-traits-tooltiptext .notable {
+ border-bottom-color: #d2d2d2;
+}
+
#titles > button:not(.selected) {
background-color: #252525;
border-top-color: #252525;
background-color: #606060;
}
-.search-results td span.alias {
+.search-results .result-name span.alias {
color: #fff;
}
-.search-results td span.grey {
+.search-results .result-name span.grey {
color: #ccc;
}
color: black;
}
-h1, h2, h3:not(.impl):not(.method):not(.type):not(.tymethod),
-h4:not(.method):not(.type):not(.tymethod) {
+h1, h2, h3, h4 {
color: black;
}
h1.fqn {
border-bottom-color: #D5D5D5;
}
-h2, h3:not(.impl):not(.method):not(.type):not(.tymethod),
-h4:not(.method):not(.type):not(.tymethod) {
+h2, h3, h4 {
border-bottom-color: #DDDDDD;
}
border-color: #999;
}
+.notable-traits-tooltiptext .notable {
+ border-bottom-color: #DDDDDD;
+}
+
#titles > button:not(.selected) {
background-color: #e6e6e6;
border-top-color: #e6e6e6;
background-color: #f9f9f9;
}
-.search-results td span.alias {
+.search-results .result-name span.alias {
color: #000;
}
-.search-results td span.grey {
+.search-results .result-name span.grey {
color: #999;
}
crate static LICENSE: &[u8] = include_bytes!("static/SourceCodePro-LICENSE.txt");
}
+crate mod noto_sans_kr {
+ /// The file `noto-sans-kr-v13-korean-regular.woff`, the Regular variant of the Noto Sans KR
+ /// font.
+ crate static REGULAR: &[u8] = include_bytes!("static/noto-sans-kr-v13-korean-regular.woff");
+
+ /// The file `noto-sans-kr-v13-korean-regular-LICENSE.txt`, the license text of the Noto Sans KR
+ /// font.
+ crate static LICENSE: &[u8] =
+ include_bytes!("static/noto-sans-kr-v13-korean-regular-LICENSE.txt");
+}
+
/// Files related to the sidebar in rustdoc sources.
crate mod sidebar {
/// File script to handle sidebar.
crate static SOURCE_SCRIPT: &str = include_str!("static/source-script.js");
-
- /// Top Level sidebar items script which will load a sidebar without items.
- crate static ITEMS: &str = include_str!("static/sidebar-items.js");
}
bounds: bounds.into_iter().map(|x| x.into_tcx(tcx)).collect(),
default: default.map(|x| x.into_tcx(tcx)),
},
- Const { did: _, ty } => GenericParamDefKind::Const(ty.into_tcx(tcx)),
+ Const { did: _, ty, default } => {
+ GenericParamDefKind::Const { ty: ty.into_tcx(tcx), default }
+ }
}
}
}
.unwrap_or_default(),
},
Generic(s) => Type::Generic(s.to_string()),
- Primitive(p) => Type::Primitive(p.as_str().to_string()),
+ Primitive(p) => Type::Primitive(p.as_sym().to_string()),
BareFunction(f) => Type::FunctionPointer(Box::new((*f).into_tcx(tcx))),
Tuple(t) => Type::Tuple(t.into_iter().map(|x| x.into_tcx(tcx)).collect()),
Slice(t) => Type::Slice(Box::new((*t).into_tcx(tcx))),
)
})
.collect(),
- format_version: 5,
+ format_version: 6,
};
let mut p = self.out_path.clone();
p.push(output.index.get(&output.root).unwrap().name.clone().unwrap());
use rustc_session::getopts;
use rustc_session::{early_error, early_warn};
+use crate::clean::utils::DOC_RUST_LANG_ORG_CHANNEL;
+
/// A macro to create a FxHashMap.
///
/// Example:
"LEVEL",
)
}),
+ unstable("force-warns", |o| {
+ o.optopt(
+ "",
+ "force-warns",
+ "Lints that will warn even if allowed somewhere else",
+ "LINTS",
+ )
+ }),
unstable("index-page", |o| {
o.optopt("", "index-page", "Markdown file to be used as index page", "PATH")
}),
"Generate JSON file at the top level instead of generating HTML redirection files",
)
}),
- unstable("print", |o| {
- o.optmulti("", "print", "Rustdoc information to print on stdout", "[unversioned-files]")
- }),
unstable("emit", |o| {
o.optmulti(
"",
}
println!("{}", options.usage(&format!("{} [options] <input>", argv0)));
println!(" @path Read newline separated options from `path`\n");
- println!("More information available at https://doc.rust-lang.org/rustdoc/what-is-rustdoc.html")
+ println!(
+ "More information available at {}/rustdoc/what-is-rustdoc.html",
+ DOC_RUST_LANG_ORG_CHANNEL
+ );
}
/// A result type used by several functions under `main()`.
}
}
- fn name(self, tcx: TyCtxt<'_>) -> String {
+ fn name(self, tcx: TyCtxt<'_>) -> Symbol {
match self {
- Res::Def(_, id) => tcx.item_name(id).to_string(),
- Res::Primitive(prim) => prim.as_str().to_string(),
+ Res::Def(_, id) => tcx.item_name(id),
+ Res::Primitive(prim) => prim.as_sym(),
}
}
ty::AssocKind::Const => "associatedconstant",
ty::AssocKind::Type => "associatedtype",
};
- let fragment = format!("{}#{}.{}", prim_ty.as_str(), out, item_name);
+ let fragment = format!("{}#{}.{}", prim_ty.as_sym(), out, item_name);
(Res::Primitive(prim_ty), fragment, Some((kind.as_def_kind(), item.def_id)))
})
})
AnchorFailure::RustdocAnchorConflict(res),
));
}
- return Ok((res, Some(ty.as_str().to_owned())));
+ return Ok((res, Some(ty.as_sym().to_string())));
}
_ => return Ok((res, extra_fragment.clone())),
}
return None;
}
res = prim;
- fragment = Some(prim.name(self.cx.tcx));
+ fragment = Some(prim.name(self.cx.tcx).to_string());
} else {
// `[char]` when a `char` module is in scope
let candidates = vec![res, prim];
let other_ns = if expected_ns == ValueNS { TypeNS } else { ValueNS };
// FIXME: really it should be `resolution_failure` that does this, not `resolve_with_disambiguator`
// See https://github.com/rust-lang/rust/pull/76955#discussion_r493953382 for a good approach
- for &new_ns in &[other_ns, MacroNS] {
+ for new_ns in [other_ns, MacroNS] {
if let Some(res) =
self.check_full_res(new_ns, path_str, base_node, extra_fragment)
{
Ok(res) => Some((res, extra_fragment.clone())),
Err(mut kind) => {
// `resolve_macro` only looks in the macro namespace. Try to give a better error if possible.
- for &ns in &[TypeNS, ValueNS] {
+ for ns in [TypeNS, ValueNS] {
if let Some(res) =
self.check_full_res(ns, path_str, base_node, extra_fragment)
{
("()", DefKind::Fn),
("!", DefKind::Macro(MacroKind::Bang)),
];
- for &(suffix, kind) in &suffixes {
+ for (suffix, kind) in suffixes {
if let Some(link) = link.strip_suffix(suffix) {
// Avoid turning `!` or `()` into an empty string
if !link.is_empty() {
break;
};
name = start;
- for &ns in &[TypeNS, ValueNS, MacroNS] {
+ for ns in [TypeNS, ValueNS, MacroNS] {
if let Some(res) =
collector.check_full_res(ns, &start, module_id.into(), &None)
{
) {
diag_info.link_range = disambiguator_range;
report_diagnostic(cx.tcx, BROKEN_INTRA_DOC_LINKS, msg, &diag_info, |diag, _sp| {
- let msg = "see https://doc.rust-lang.org/nightly/rustdoc/linking-to-items-by-name.html#namespaces-and-disambiguators for more info about disambiguators";
- diag.note(msg);
+ let msg = format!(
+ "see {}/rustdoc/linking-to-items-by-name.html#namespaces-and-disambiguators for more info about disambiguators",
+ crate::DOC_RUST_LANG_ORG_CHANNEL
+ );
+ diag.note(&msg);
});
}
use crate::core::DocContext;
use crate::fold::DocFolder;
-use rustc_data_structures::fx::{FxHashMap, FxHashSet};
-use rustc_hir::def_id::DefId;
+use rustc_data_structures::fx::FxHashSet;
use rustc_middle::ty::DefIdTree;
use rustc_span::symbol::sym;
}
}
+ let mut cleaner = BadImplStripper { prims, items: crate_items };
+
+ // scan through included items ahead of time to splice in Deref targets to the "valid" sets
+ for it in &new_items {
+ if let ImplItem(Impl { ref for_, ref trait_, ref items, .. }) = *it.kind {
+ if cleaner.keep_impl(for_) && trait_.def_id() == cx.tcx.lang_items().deref_trait() {
+ let target = items
+ .iter()
+ .find_map(|item| match *item.kind {
+ TypedefItem(ref t, true) => Some(&t.type_),
+ _ => None,
+ })
+ .expect("Deref impl without Target type");
+
+ if let Some(prim) = target.primitive_type() {
+ cleaner.prims.insert(prim);
+ } else if let Some(did) = target.def_id() {
+ cleaner.items.insert(did.into());
+ }
+ }
+ }
+ }
+
+ new_items.retain(|it| {
+ if let ImplItem(Impl { ref for_, ref trait_, ref blanket_impl, .. }) = *it.kind {
+ cleaner.keep_impl(for_)
+ || trait_.as_ref().map_or(false, |t| cleaner.keep_impl(t))
+ || blanket_impl.is_some()
+ } else {
+ true
+ }
+ });
+
// `tcx.crates()` doesn't include the local crate, and `tcx.all_trait_implementations`
// doesn't work with it anyway, so pull them from the HIR map instead
let mut extra_attrs = Vec::new();
}
}
- let mut cleaner = BadImplStripper { prims, items: crate_items };
-
- let mut type_did_to_deref_target: FxHashMap<DefId, &Type> = FxHashMap::default();
- // Gather all type to `Deref` target edges.
- for it in &new_items {
- if let ImplItem(Impl { ref for_, ref trait_, ref items, .. }) = *it.kind {
- if trait_.def_id() == cx.tcx.lang_items().deref_trait() {
- let target = items.iter().find_map(|item| match *item.kind {
- TypedefItem(ref t, true) => Some(&t.type_),
- _ => None,
- });
- if let (Some(for_did), Some(target)) = (for_.def_id(), target) {
- type_did_to_deref_target.insert(for_did, target);
- }
- }
- }
- }
- // Follow all `Deref` targets of included items and recursively add them as valid
- fn add_deref_target(
- map: &FxHashMap<DefId, &Type>,
- cleaner: &mut BadImplStripper,
- type_did: &DefId,
- ) {
- if let Some(target) = map.get(type_did) {
- debug!("add_deref_target: type {:?}, target {:?}", type_did, target);
- if let Some(target_prim) = target.primitive_type() {
- cleaner.prims.insert(target_prim);
- } else if let Some(target_did) = target.def_id() {
- // `impl Deref<Target = S> for S`
- if target_did == *type_did {
- // Avoid infinite cycles
- return;
- }
- cleaner.items.insert(target_did.into());
- add_deref_target(map, cleaner, &target_did.into());
- }
- }
- }
- for type_did in type_did_to_deref_target.keys() {
- // Since only the `DefId` portion of the `Type` instances is known to be same for both the
- // `Deref` target type and the impl for type positions, this map of types is keyed by
- // `DefId` and for convenience uses a special cleaner that accepts `DefId`s directly.
- if cleaner.keep_impl_with_def_id(FakeDefId::Real(*type_did)) {
- add_deref_target(&type_did_to_deref_target, &mut cleaner, type_did);
- }
- }
-
let items = if let ModuleItem(Module { ref mut items, .. }) = *krate.module.kind {
items
} else {
};
items.extend(synth_impls);
- for it in new_items.drain(..) {
- if let ImplItem(Impl { ref for_, ref trait_, ref blanket_impl, .. }) = *it.kind {
- if !(cleaner.keep_impl(for_)
- || trait_.as_ref().map_or(false, |t| cleaner.keep_impl(t))
- || blanket_impl.is_some())
- {
- continue;
- }
- }
-
- items.push(it);
- }
-
+ items.extend(new_items);
krate
}
use rustc_middle::middle::privacy::AccessLevel;
use rustc_middle::ty::TyCtxt;
use rustc_span;
+use rustc_span::def_id::LOCAL_CRATE;
use rustc_span::source_map::Spanned;
use rustc_span::symbol::{kw, sym, Symbol};
&Spanned { span, node: hir::VisibilityKind::Public },
hir::CRATE_HIR_ID,
&krate.item,
- self.cx.tcx.crate_name,
+ self.cx.tcx.crate_name(LOCAL_CRATE),
);
// Attach the crate's exported macros to the top-level module.
// In the case of macros 2.0 (`pub macro`), and for built-in `derive`s or attributes as
-Subproject commit 5f67a5715771b7d29e4713e8d68338602d216dcf
+Subproject commit 39c5555872cc5d379cc3535a31dc0cdac969466f
pub enum GenericParamDefKind {
Lifetime,
Type { bounds: Vec<GenericBound>, default: Option<Type> },
- Const(Type),
+ Const { ty: Type, default: Option<String> },
}
#[derive(Clone, Debug, Serialize, Deserialize, PartialEq)]
--- /dev/null
+// min-llvm-version: 10.0.1
+// assembly-output: emit-asm
+// compile-flags: --target bpfel-unknown-none -C target_feature=+alu32
+// needs-llvm-components: bpf
+
+#![feature(no_core, lang_items, rustc_attrs, repr_simd)]
+#![crate_type = "rlib"]
+#![no_core]
+#![allow(asm_sub_register, non_camel_case_types)]
+
+#[rustc_builtin_macro]
+macro_rules! asm {
+ () => {};
+}
+#[rustc_builtin_macro]
+macro_rules! concat {
+ () => {};
+}
+#[rustc_builtin_macro]
+macro_rules! stringify {
+ () => {};
+}
+
+#[lang = "sized"]
+trait Sized {}
+#[lang = "copy"]
+trait Copy {}
+
+type ptr = *const u64;
+
+impl Copy for i8 {}
+impl Copy for i16 {}
+impl Copy for i32 {}
+impl Copy for i64 {}
+impl Copy for ptr {}
+
+macro_rules! check {
+ ($func:ident $ty:ident $class:ident) => {
+ #[no_mangle]
+ pub unsafe fn $func(x: $ty) -> $ty {
+ let y;
+ asm!("{} = {}", out($class) y, in($class) x);
+ y
+ }
+ };
+}
+
+macro_rules! check_reg {
+ ($func:ident $ty:ident $reg:tt) => {
+ #[no_mangle]
+ pub unsafe fn $func(x: $ty) -> $ty {
+ let y;
+ asm!(concat!($reg, " = ", $reg), lateout($reg) y, in($reg) x);
+ y
+ }
+ };
+}
+
+extern "C" {
+ fn extern_func();
+}
+
+// CHECK-LABEL: sym_fn
+// CHECK: #APP
+// CHECK: call extern_func
+// CHECK: #NO_APP
+#[no_mangle]
+pub unsafe fn sym_fn() {
+ asm!("call {}", sym extern_func);
+}
+
+// CHECK-LABEL: reg_i8:
+// CHECK: #APP
+// CHECK: r{{[0-9]+}} = r{{[0-9]+}}
+// CHECK: #NO_APP
+check!(reg_i8 i8 reg);
+
+// CHECK-LABEL: reg_i16:
+// CHECK: #APP
+// CHECK: r{{[0-9]+}} = r{{[0-9]+}}
+// CHECK: #NO_APP
+check!(reg_i16 i16 reg);
+
+// CHECK-LABEL: reg_i32:
+// CHECK: #APP
+// CHECK: r{{[0-9]+}} = r{{[0-9]+}}
+// CHECK: #NO_APP
+check!(reg_i32 i32 reg);
+
+// CHECK-LABEL: reg_i64:
+// CHECK: #APP
+// CHECK: r{{[0-9]+}} = r{{[0-9]+}}
+// CHECK: #NO_APP
+check!(reg_i64 i64 reg);
+
+// CHECK-LABEL: wreg_i8:
+// CHECK: #APP
+// CHECK: w{{[0-9]+}} = w{{[0-9]+}}
+// CHECK: #NO_APP
+check!(wreg_i8 i8 wreg);
+
+// CHECK-LABEL: wreg_i16:
+// CHECK: #APP
+// CHECK: w{{[0-9]+}} = w{{[0-9]+}}
+// CHECK: #NO_APP
+check!(wreg_i16 i16 wreg);
+
+// CHECK-LABEL: wreg_i32:
+// CHECK: #APP
+// CHECK: w{{[0-9]+}} = w{{[0-9]+}}
+// CHECK: #NO_APP
+check!(wreg_i32 i32 wreg);
+
+// CHECK-LABEL: r0_i8:
+// CHECK: #APP
+// CHECK: r0 = r0
+// CHECK: #NO_APP
+check_reg!(r0_i8 i8 "r0");
+
+// CHECK-LABEL: r0_i16:
+// CHECK: #APP
+// CHECK: r0 = r0
+// CHECK: #NO_APP
+check_reg!(r0_i16 i16 "r0");
+
+// CHECK-LABEL: r0_i32:
+// CHECK: #APP
+// CHECK: r0 = r0
+// CHECK: #NO_APP
+check_reg!(r0_i32 i32 "r0");
+
+// CHECK-LABEL: r0_i64:
+// CHECK: #APP
+// CHECK: r0 = r0
+// CHECK: #NO_APP
+check_reg!(r0_i64 i64 "r0");
+
+// CHECK-LABEL: w0_i8:
+// CHECK: #APP
+// CHECK: w0 = w0
+// CHECK: #NO_APP
+check_reg!(w0_i8 i8 "w0");
+
+// CHECK-LABEL: w0_i16:
+// CHECK: #APP
+// CHECK: w0 = w0
+// CHECK: #NO_APP
+check_reg!(w0_i16 i16 "w0");
+
+// CHECK-LABEL: w0_i32:
+// CHECK: #APP
+// CHECK: w0 = w0
+// CHECK: #NO_APP
+check_reg!(w0_i32 i32 "w0");
// min-llvm-version: 12.0.0
-// needs-llvm-components: aarch64 x86
-// revisions:x64 A64
+// needs-llvm-components: aarch64 x86 powerpc
+// revisions: x64 A64 ppc64le
// assembly-output: emit-asm
// [x64] compile-flags: --target x86_64-unknown-linux-gnu -Crelocation-model=static
// [A64] compile-flags: --target aarch64-unknown-linux-gnu -Crelocation-model=static
+// [ppc64le] compile-flags: --target powerpc64le-unknown-linux-gnu -Crelocation-model=static
#![feature(no_core, lang_items)]
#![no_core]
pub fn orange() -> &'static u8 {
&PIERIS
}
+
+// For ppc64 we need to make sure to generate TOC entries even with the static relocation model
+// ppc64le: .tc chaenomeles[TC],chaenomeles
+// ppc64le: .tc banana[TC],banana
+// ppc64le: .tc EXOCHORDA[TC],EXOCHORDA
+// ppc64le: .tc PIERIS[TC],PIERIS
// FIXME: No way to reliably check the filename.
// CHECK-DAG: [[ASYNC_FN:!.*]] = !DINamespace(name: "async_fn_test"
-// CHECK-DAG: [[GEN:!.*]] = !DICompositeType(tag: DW_TAG_union_type, name: "generator-0", scope: [[ASYNC_FN]]
-// CHECK: {{!.*}} = !DIDerivedType(tag: DW_TAG_member, scope: [[GEN]],
+// CHECK-DAG: [[GEN:!.*]] = !DICompositeType(tag: DW_TAG_union_type, name: "generator-0"
+// CHECK: {{!.*}} = !DIDerivedType(tag: DW_TAG_member, name: "variant0", scope: [[GEN]],
// For brevity, we only check the struct name and members of the last variant.
// CHECK-SAME: file: [[FILE:![0-9]*]], line: 11,
// CHECK-NOT: flags: DIFlagArtificial
// CHECK-SAME: )
-// CHECK: {{!.*}} = !DIDerivedType(tag: DW_TAG_member, scope: [[GEN]],
+// CHECK: {{!.*}} = !DIDerivedType(tag: DW_TAG_member, name: "variant1", scope: [[GEN]],
// CHECK-SAME: file: [[FILE]], line: 15,
// CHECK-NOT: flags: DIFlagArtificial
// CHECK-SAME: )
-// CHECK: {{!.*}} = !DIDerivedType(tag: DW_TAG_member, scope: [[GEN]],
+// CHECK: {{!.*}} = !DIDerivedType(tag: DW_TAG_member, name: "variant2", scope: [[GEN]],
// CHECK-SAME: file: [[FILE]], line: 15,
// CHECK-NOT: flags: DIFlagArtificial
// CHECK-SAME: )
-// CHECK: {{!.*}} = !DIDerivedType(tag: DW_TAG_member, scope: [[GEN]],
+// CHECK: {{!.*}} = !DIDerivedType(tag: DW_TAG_member, name: "variant3", scope: [[GEN]],
// CHECK-SAME: file: [[FILE]], line: 12,
// CHECK-NOT: flags: DIFlagArtificial
// CHECK-SAME: )
-// CHECK: {{!.*}} = !DIDerivedType(tag: DW_TAG_member, scope: [[GEN]],
+// CHECK: {{!.*}} = !DIDerivedType(tag: DW_TAG_member, name: "variant4", scope: [[GEN]],
// CHECK-SAME: file: [[FILE]], line: 14,
// CHECK-SAME: baseType: [[VARIANT:![0-9]*]]
// CHECK-NOT: flags: DIFlagArtificial
// CHECK-SAME: )
-// CHECK: [[S1:!.*]] = !DICompositeType(tag: DW_TAG_structure_type, name: "Suspend1", scope: [[ASYNC_FN]],
+// CHECK: [[S1:!.*]] = !DICompositeType(tag: DW_TAG_structure_type, name: "Suspend1", scope: [[GEN]],
// CHECK-NOT: flags: DIFlagArtificial
// CHECK-SAME: )
-// CHECK: {{!.*}} = !DIDerivedType(tag: DW_TAG_member, name: "RUST$ENUM$DISR", scope: [[S1]],
+// CHECK: {{!.*}} = !DIDerivedType(tag: DW_TAG_member, name: "variant$", scope: [[S1]],
// CHECK-SAME: flags: DIFlagArtificial
// CHECK: {{!.*}} = !DIDerivedType(tag: DW_TAG_member, name: "s", scope: [[S1]]
// CHECK-NOT: flags: DIFlagArtificial
--- /dev/null
+// only-bpf
+#![crate_type = "lib"]
+#![feature(bpf_target_feature)]
+#![no_std]
+
+#[no_mangle]
+#[target_feature(enable = "alu32")]
+// CHECK: define i8 @foo(i8 returned %arg) unnamed_addr #0 {
+pub unsafe fn foo(arg: u8) -> u8 {
+ arg
+}
// FIXME: No way to reliably check the filename.
// CHECK-DAG: [[GEN_FN:!.*]] = !DINamespace(name: "generator_test"
-// CHECK-DAG: [[GEN:!.*]] = !DICompositeType(tag: DW_TAG_union_type, name: "generator-0", scope: [[GEN_FN]]
-// CHECK: {{!.*}} = !DIDerivedType(tag: DW_TAG_member, scope: [[GEN]],
+// CHECK-DAG: [[GEN:!.*]] = !DICompositeType(tag: DW_TAG_union_type, name: "generator-0"
+// CHECK: {{!.*}} = !DIDerivedType(tag: DW_TAG_member, name: "variant0", scope: [[GEN]],
// For brevity, we only check the struct name and members of the last variant.
// CHECK-SAME: file: [[FILE:![0-9]*]], line: 14,
// CHECK-NOT: flags: DIFlagArtificial
// CHECK-SAME: )
-// CHECK: {{!.*}} = !DIDerivedType(tag: DW_TAG_member, scope: [[GEN]],
+// CHECK: {{!.*}} = !DIDerivedType(tag: DW_TAG_member, name: "variant1", scope: [[GEN]],
// CHECK-SAME: file: [[FILE]], line: 18,
// CHECK-NOT: flags: DIFlagArtificial
// CHECK-SAME: )
-// CHECK: {{!.*}} = !DIDerivedType(tag: DW_TAG_member, scope: [[GEN]],
+// CHECK: {{!.*}} = !DIDerivedType(tag: DW_TAG_member, name: "variant2", scope: [[GEN]],
// CHECK-SAME: file: [[FILE]], line: 18,
// CHECK-NOT: flags: DIFlagArtificial
// CHECK-SAME: )
-// CHECK: {{!.*}} = !DIDerivedType(tag: DW_TAG_member, scope: [[GEN]],
+// CHECK: {{!.*}} = !DIDerivedType(tag: DW_TAG_member, name: "variant3", scope: [[GEN]],
// CHECK-SAME: file: [[FILE]], line: 15,
// CHECK-NOT: flags: DIFlagArtificial
// CHECK-SAME: )
-// CHECK: {{!.*}} = !DIDerivedType(tag: DW_TAG_member, scope: [[GEN]],
+// CHECK: {{!.*}} = !DIDerivedType(tag: DW_TAG_member, name: "variant4", scope: [[GEN]],
// CHECK-SAME: file: [[FILE]], line: 17,
// CHECK-SAME: baseType: [[VARIANT:![0-9]*]]
// CHECK-NOT: flags: DIFlagArtificial
// CHECK-SAME: )
-// CHECK: [[S1:!.*]] = !DICompositeType(tag: DW_TAG_structure_type, name: "Suspend1", scope: [[GEN_FN]],
+// CHECK: [[S1:!.*]] = !DICompositeType(tag: DW_TAG_structure_type, name: "Suspend1", scope: [[GEN]],
// CHECK-NOT: flags: DIFlagArtificial
// CHECK-SAME: )
-// CHECK: {{!.*}} = !DIDerivedType(tag: DW_TAG_member, name: "RUST$ENUM$DISR", scope: [[S1]],
+// CHECK: {{!.*}} = !DIDerivedType(tag: DW_TAG_member, name: "variant$", scope: [[S1]],
// CHECK-SAME: flags: DIFlagArtificial
// CHECK: {{!.*}} = !DIDerivedType(tag: DW_TAG_member, name: "s", scope: [[S1]]
// CHECK-NOT: flags: DIFlagArtificial
--- /dev/null
+// only-cdb
+// ignore-tidy-linelength
+// compile-flags:-g
+
+// cdb-command: g
+
+// Note: The natvis used to visualize niche-layout enums don't work correctly in cdb
+// so the best we can do is to make sure we are generating the right debuginfo
+
+// cdb-command: dx -r2 a,!
+// cdb-check:a,! [Type: enum$<core::option::Option<enum$<msvc_pretty_enums::CStyleEnum>>, 2, 16, Some>]
+// cdb-check: [+0x000] dataful_variant [Type: enum$<core::option::Option<enum$<msvc_pretty_enums::CStyleEnum>>, 2, 16, Some>::Some]
+// cdb-check: [+0x000] __0 : Low (0x2) [Type: msvc_pretty_enums::CStyleEnum]
+// cdb-check: [+0x000] discriminant : 0x2 [Type: enum$<core::option::Option<enum$<msvc_pretty_enums::CStyleEnum>>, 2, 16, Some>::Discriminant$]
+
+// cdb-command: dx -r2 b,!
+// cdb-check:b,! [Type: enum$<core::option::Option<enum$<msvc_pretty_enums::CStyleEnum>>, 2, 16, Some>]
+// cdb-check: [+0x000] dataful_variant [Type: enum$<core::option::Option<enum$<msvc_pretty_enums::CStyleEnum>>, 2, 16, Some>::Some]
+// cdb-check: [+0x000] __0 : 0x11 [Type: msvc_pretty_enums::CStyleEnum]
+// cdb-check: [+0x000] discriminant : None (0x11) [Type: enum$<core::option::Option<enum$<msvc_pretty_enums::CStyleEnum>>, 2, 16, Some>::Discriminant$]
+
+// cdb-command: dx -r2 c,!
+// cdb-check:c,! [Type: enum$<msvc_pretty_enums::NicheLayoutEnum, 2, 16, Data>]
+// cdb-check: [+0x000] dataful_variant [Type: enum$<msvc_pretty_enums::NicheLayoutEnum, 2, 16, Data>::Data]
+// cdb-check: [+0x000] my_data : 0x11 [Type: msvc_pretty_enums::CStyleEnum]
+// cdb-check: [+0x000] discriminant : Tag1 (0x11) [Type: enum$<msvc_pretty_enums::NicheLayoutEnum, 2, 16, Data>::Discriminant$]
+
+// cdb-command: dx -r2 d,!
+// cdb-check:d,! [Type: enum$<msvc_pretty_enums::NicheLayoutEnum, 2, 16, Data>]
+// cdb-check: [+0x000] dataful_variant [Type: enum$<msvc_pretty_enums::NicheLayoutEnum, 2, 16, Data>::Data]
+// cdb-check: [+0x000] my_data : High (0x10) [Type: msvc_pretty_enums::CStyleEnum]
+// cdb-check: [+0x000] discriminant : 0x10 [Type: enum$<msvc_pretty_enums::NicheLayoutEnum, 2, 16, Data>::Discriminant$]
+
+// cdb-command: dx -r2 e,!
+// cdb-check:e,! [Type: enum$<msvc_pretty_enums::NicheLayoutEnum, 2, 16, Data>]
+// cdb-check: [+0x000] dataful_variant [Type: enum$<msvc_pretty_enums::NicheLayoutEnum, 2, 16, Data>::Data]
+// cdb-check: [+0x000] my_data : 0x13 [Type: msvc_pretty_enums::CStyleEnum]
+// cdb-check: [+0x000] discriminant : Tag2 (0x13) [Type: enum$<msvc_pretty_enums::NicheLayoutEnum, 2, 16, Data>::Discriminant$]
+
+// cdb-command: dx -r2 f,!
+// cdb-check:f,! [Type: enum$<core::option::Option<u32*>, 1, [...], Some>]
+// cdb-check: [+0x000] dataful_variant [Type: enum$<core::option::Option<u32*>, 1, [...], Some>::Some]
+// cdb-check: [+0x000] __0 : 0x[...] : 0x1 [Type: unsigned int *]
+// cdb-check: [+0x000] discriminant : 0x[...] [Type: enum$<core::option::Option<u32*>, 1, [...], Some>::Discriminant$]
+
+// cdb-command: dx -r2 g,!
+// cdb-check:g,! [Type: enum$<core::option::Option<u32*>, 1, [...], Some>]
+// cdb-check: [+0x000] dataful_variant [Type: enum$<core::option::Option<u32*>, 1, [...], Some>::Some]
+// cdb-check: [+0x000] __0 : 0x0 [Type: unsigned int *]
+// cdb-check: [+0x000] discriminant : None (0x0) [Type: enum$<core::option::Option<u32*>, 1, [...], Some>::Discriminant$]
+
+// cdb-command: dx h
+// cdb-check:h : Some [Type: enum$<core::option::Option<u32>>]
+// cdb-check: [+0x000] variant$ : Some (0x1) [Type: core::option::Option]
+// cdb-check: [+0x004] __0 : 0xc [Type: unsigned int]
+
+// cdb-command: dx i
+// cdb-check:i : None [Type: enum$<core::option::Option<u32>>]
+// cdb-check: [+0x000] variant$ : None (0x0) [Type: core::option::Option]
+
+// cdb-command: dx j
+// cdb-check:j : High (0x10) [Type: msvc_pretty_enums::CStyleEnum]
+
+// cdb-command: dx -r2 k,!
+// cdb-check:k,! [Type: enum$<core::option::Option<alloc::string::String>, 1, [...], Some>]
+// cdb-check: [+0x000] dataful_variant [Type: enum$<core::option::Option<alloc::string::String>, 1, [...], Some>::Some]
+// cdb-check: [+0x000] __0 [Type: alloc::string::String]
+// cdb-check: [+0x000] discriminant : 0x[...] [Type: enum$<core::option::Option<alloc::string::String>, 1, [...], Some>::Discriminant$]
+
+pub enum CStyleEnum {
+ Low = 2,
+ High = 16,
+}
+
+pub enum NicheLayoutEnum {
+ Tag1,
+ Data { my_data: CStyleEnum },
+ Tag2,
+}
+
+fn main() {
+ let a = Some(CStyleEnum::Low);
+ let b = Option::<CStyleEnum>::None;
+ let c = NicheLayoutEnum::Tag1;
+ let d = NicheLayoutEnum::Data { my_data: CStyleEnum::High };
+ let e = NicheLayoutEnum::Tag2;
+ let f = Some(&1u32);
+ let g = Option::<&'static u32>::None;
+ let h = Some(12u32);
+ let i = Option::<u32>::None;
+ let j = CStyleEnum::High;
+ let k = Some("IAMA optional string!".to_string());
+
+ zzz(); // #break
+}
+
+fn zzz() { () }
// ignore-freebsd: gdb package too new
// only-cdb // "Temporarily" ignored on GDB/LLDB due to debuginfo tests being disabled, see PR 47155
// ignore-android: FIXME(#10381)
+// ignore-tidy-linelength
// compile-flags:-g
// min-gdb-version: 7.7
// min-lldb-version: 310
// NOTE: OsString doesn't have a .natvis entry yet.
// cdb-command: dx some
-// cdb-check:some : Some(8) [Type: [...]::Option<i16>]
+// cdb-check:some : Some [Type: enum$<core::option::Option<i16>>]
// cdb-command: dx none
-// cdb-check:none : None [Type: [...]::Option<i64>]
+// cdb-check:none : None [Type: enum$<core::option::Option<i64>>]
// cdb-command: dx some_string
-// cdb-check:some_string : Some("IAMA optional string!") [[...]::Option<[...]::String>]
+// cdb-check:some_string [Type: enum$<core::option::Option<alloc::string::String>, 1, [...], Some>]
#![allow(unused_variables)]
use std::ffi::OsString;
pub mod fn_calls_methods_in_same_impl {
use point::Point;
- #[rustc_clean(label="typeck", cfg="cfail2")]
+ #[rustc_clean(cfg="cfail2")]
pub fn check() {
let x = Point { x: 2.0, y: 2.0 };
x.distance_from_origin();
pub mod fn_calls_free_fn {
use point::{self, Point};
- #[rustc_clean(label="typeck", cfg="cfail2")]
+ #[rustc_clean(cfg="cfail2")]
pub fn check() {
let x = Point { x: 2.0, y: 2.0 };
point::distance_squared(&x);
pub mod fn_make_struct {
use point::Point;
- #[rustc_clean(label="typeck", cfg="cfail2")]
+ #[rustc_clean(cfg="cfail2")]
pub fn make_origin() -> Point {
Point { x: 2.0, y: 2.0 }
}
pub mod fn_read_field {
use point::Point;
- #[rustc_clean(label="typeck", cfg="cfail2")]
+ #[rustc_clean(cfg="cfail2")]
pub fn get_x(p: Point) -> f32 {
p.x
}
pub mod fn_write_field {
use point::Point;
- #[rustc_clean(label="typeck", cfg="cfail2")]
+ #[rustc_clean(cfg="cfail2")]
pub fn inc_x(p: &mut Point) {
p.x += 1.0;
}
extern crate a;
-#[rustc_dirty(label="typeck", cfg="rpass2")]
+#[rustc_clean(except="typeck", cfg="rpass2")]
pub fn call_function0() {
a::function0(77);
}
-#[rustc_clean(label="typeck", cfg="rpass2")]
+#[rustc_clean(cfg="rpass2")]
pub fn call_function1() {
a::function1(77);
}
pub mod fn_with_type_in_sig {
use point::Point;
- #[rustc_dirty(label="typeck", cfg="cfail2")]
+ #[rustc_clean(except="typeck,fn_sig,optimized_mir", cfg="cfail2")]
pub fn boop(p: Option<&Point>) -> f32 {
p.map(|p| p.total()).unwrap_or(0.0)
}
pub mod call_fn_with_type_in_sig {
use fn_with_type_in_sig;
- #[rustc_dirty(label="typeck", cfg="cfail2")]
+ #[rustc_clean(except="typeck,optimized_mir", cfg="cfail2")]
pub fn bip() -> f32 {
fn_with_type_in_sig::boop(None)
}
pub mod fn_with_type_in_body {
use point::Point;
- #[rustc_dirty(label="typeck", cfg="cfail2")]
+ #[rustc_clean(except="typeck,optimized_mir", cfg="cfail2")]
pub fn boop() -> f32 {
Point::origin().total()
}
pub mod call_fn_with_type_in_body {
use fn_with_type_in_body;
- #[rustc_clean(label="typeck", cfg="cfail2")]
+ #[rustc_clean(cfg="cfail2")]
pub fn bip() -> f32 {
fn_with_type_in_body::boop()
}
pub mod fn_make_struct {
use point::Point;
- #[rustc_dirty(label="typeck", cfg="cfail2")]
+ #[rustc_clean(except="typeck,fn_sig,optimized_mir", cfg="cfail2")]
pub fn make_origin(p: Point) -> Point {
Point { ..p }
}
pub mod fn_read_field {
use point::Point;
- #[rustc_dirty(label="typeck", cfg="cfail2")]
+ #[rustc_clean(except="typeck,fn_sig,optimized_mir", cfg="cfail2")]
pub fn get_x(p: Point) -> f32 {
p.x
}
pub mod fn_write_field {
use point::Point;
- #[rustc_dirty(label="typeck", cfg="cfail2")]
+ #[rustc_clean(except="typeck,fn_sig,optimized_mir", cfg="cfail2")]
pub fn inc_x(p: &mut Point) {
p.x += 1.0;
}
pub mod fn_calls_methods_in_same_impl {
use point::Point;
- #[rustc_clean(label="typeck", cfg="cfail2")]
+ #[rustc_clean(cfg="cfail2")]
pub fn check() {
let x = Point { x: 2.0, y: 2.0 };
x.distance_from_origin();
pub mod fn_calls_methods_in_another_impl {
use point::Point;
- #[rustc_clean(label="typeck", cfg="cfail2")]
+ #[rustc_clean(cfg="cfail2")]
pub fn check() {
let mut x = Point { x: 2.0, y: 2.0 };
x.translate(3.0, 3.0);
pub mod fn_make_struct {
use point::Point;
- #[rustc_clean(label="typeck", cfg="cfail2")]
+ #[rustc_clean(cfg="cfail2")]
pub fn make_origin() -> Point {
Point { x: 2.0, y: 2.0 }
}
pub mod fn_read_field {
use point::Point;
- #[rustc_clean(label="typeck", cfg="cfail2")]
+ #[rustc_clean(cfg="cfail2")]
pub fn get_x(p: Point) -> f32 {
p.x
}
pub mod fn_write_field {
use point::Point;
- #[rustc_clean(label="typeck", cfg="cfail2")]
+ #[rustc_clean(cfg="cfail2")]
pub fn inc_x(p: &mut Point) {
p.x += 1.0;
}
pub mod fn_calls_methods_in_same_impl {
use point::Point;
- #[rustc_clean(label="typeck", cfg="cfail2")]
+ #[rustc_clean(cfg="cfail2")]
pub fn check() {
let x = Point { x: 2.0, y: 2.0 };
x.distance_from_origin();
pub mod fn_calls_methods_in_another_impl {
use point::Point;
- #[rustc_clean(label="typeck", cfg="cfail2")]
+ #[rustc_clean(cfg="cfail2")]
pub fn check() {
let mut x = Point { x: 2.0, y: 2.0 };
x.translate(3.0, 3.0);
pub mod fn_make_struct {
use point::Point;
- #[rustc_clean(label="typeck", cfg="cfail2")]
+ #[rustc_clean(cfg="cfail2")]
pub fn make_origin() -> Point {
Point { x: 2.0, y: 2.0 }
}
pub mod fn_read_field {
use point::Point;
- #[rustc_clean(label="typeck", cfg="cfail2")]
+ #[rustc_clean(cfg="cfail2")]
pub fn get_x(p: Point) -> f32 {
p.x
}
pub mod fn_write_field {
use point::Point;
- #[rustc_clean(label="typeck", cfg="cfail2")]
+ #[rustc_clean(cfg="cfail2")]
pub fn inc_x(p: &mut Point) {
p.x += 1.0;
}
pub mod fn_calls_methods_in_same_impl {
use point::Point;
- #[rustc_clean(label="typeck", cfg="cfail2")]
+ #[rustc_clean(cfg="cfail2")]
pub fn check() {
let x = Point { x: 2.0, y: 2.0 };
x.distance_from_origin();
pub mod fn_calls_methods_in_another_impl {
use point::Point;
- #[rustc_clean(label="typeck", cfg="cfail2")]
+ #[rustc_clean(cfg="cfail2")]
pub fn check() {
let mut x = Point { x: 2.0, y: 2.0 };
x.translate(3.0, 3.0);
pub mod fn_make_struct {
use point::Point;
- #[rustc_clean(label="typeck", cfg="cfail2")]
+ #[rustc_clean(cfg="cfail2")]
pub fn make_origin() -> Point {
Point { x: 2.0, y: 2.0 }
}
pub mod fn_read_field {
use point::Point;
- #[rustc_clean(label="typeck", cfg="cfail2")]
+ #[rustc_clean(cfg="cfail2")]
pub fn get_x(p: Point) -> f32 {
p.x
}
pub mod fn_write_field {
use point::Point;
- #[rustc_clean(label="typeck", cfg="cfail2")]
+ #[rustc_clean(cfg="cfail2")]
pub fn inc_x(p: &mut Point) {
p.x += 1.0;
}
pub mod fn_calls_methods_in_same_impl {
use point::Point;
- #[rustc_clean(label="typeck", cfg="cfail2")]
+ #[rustc_clean(cfg="cfail2")]
pub fn check() {
let x = Point { x: 2.0, y: 2.0 };
x.distance_from_origin();
pub mod fn_calls_methods_in_another_impl {
use point::Point;
- #[rustc_clean(label="typeck", cfg="cfail2")]
+ #[rustc_clean(cfg="cfail2")]
pub fn dirty() {
let mut x = Point { x: 2.0, y: 2.0 };
x.translate(3.0, 3.0);
pub mod fn_make_struct {
use point::Point;
- #[rustc_clean(label="typeck", cfg="cfail2")]
+ #[rustc_clean(cfg="cfail2")]
pub fn make_origin() -> Point {
Point { x: 2.0, y: 2.0 }
}
pub mod fn_read_field {
use point::Point;
- #[rustc_clean(label="typeck", cfg="cfail2")]
+ #[rustc_clean(cfg="cfail2")]
pub fn get_x(p: Point) -> f32 {
p.x
}
pub mod fn_write_field {
use point::Point;
- #[rustc_clean(label="typeck", cfg="cfail2")]
+ #[rustc_clean(cfg="cfail2")]
pub fn inc_x(p: &mut Point) {
p.x += 1.0;
}
pub mod fn_calls_changed_method {
use point::Point;
- #[rustc_clean(label="typeck", cfg="cfail2")]
+ #[rustc_clean(cfg="cfail2")]
pub fn check() {
let p = Point { x: 2.0, y: 2.0 };
p.distance_from_origin();
pub mod fn_calls_another_method {
use point::Point;
- #[rustc_clean(label="typeck", cfg="cfail2")]
+ #[rustc_clean(cfg="cfail2")]
pub fn check() {
let p = Point { x: 2.0, y: 2.0 };
p.x();
pub mod fn_make_struct {
use point::Point;
- #[rustc_clean(label="typeck", cfg="cfail2")]
+ #[rustc_clean(cfg="cfail2")]
pub fn make_origin() -> Point {
Point { x: 2.0, y: 2.0 }
}
pub mod fn_read_field {
use point::Point;
- #[rustc_clean(label="typeck", cfg="cfail2")]
+ #[rustc_clean(cfg="cfail2")]
pub fn get_x(p: Point) -> f32 {
p.x
}
pub mod fn_write_field {
use point::Point;
- #[rustc_clean(label="typeck", cfg="cfail2")]
+ #[rustc_clean(cfg="cfail2")]
pub fn inc_x(p: &mut Point) {
p.x += 1.0;
}
pub mod fn_calls_changed_method {
use point::Point;
- #[rustc_dirty(label="typeck", cfg="cfail2")]
+ #[rustc_clean(except="typeck,optimized_mir", cfg="cfail2")]
pub fn check() {
let p = Point { x: 2.0, y: 2.0 };
p.distance_from_point(None);
pub mod fn_calls_another_method {
use point::Point;
- #[rustc_clean(label="typeck", cfg="cfail2")]
+ #[rustc_clean(cfg="cfail2")]
pub fn check() {
let p = Point { x: 2.0, y: 2.0 };
p.x();
pub mod fn_make_struct {
use point::Point;
- #[rustc_clean(label="typeck", cfg="cfail2")]
+ #[rustc_clean(cfg="cfail2")]
pub fn make_origin() -> Point {
Point { x: 2.0, y: 2.0 }
}
pub mod fn_read_field {
use point::Point;
- #[rustc_clean(label="typeck", cfg="cfail2")]
+ #[rustc_clean(cfg="cfail2")]
pub fn get_x(p: Point) -> f32 {
p.x
}
pub mod fn_write_field {
use point::Point;
- #[rustc_clean(label="typeck", cfg="cfail2")]
+ #[rustc_clean(cfg="cfail2")]
pub fn inc_x(p: &mut Point) {
p.x += 1.0;
}
// Check that reordering otherwise identical items is not considered a
// change at all.
-#[rustc_clean(label = "hir_crate", cfg = "rpass2")]
+#[rustc_clean(cfg = "rpass2")]
// But removing an item, naturally, is.
-#[rustc_dirty(label = "hir_crate", cfg = "rpass3")]
+#[rustc_clean(except="hir_crate", cfg = "rpass3")]
#[cfg(rpass1)]
pub struct X {
pub x: u32,
mod y {
use x;
- #[rustc_clean(label="typeck", cfg="cfail2")]
+ #[rustc_clean(
+ except="hir_owner,hir_owner_nodes,generics_of,predicates_of,type_of,fn_sig",
+ cfg="cfail2",
+ )]
pub fn y() {
- //[cfail2]~^ ERROR `typeck(y)` should be clean but is not
+ //[cfail2]~^ ERROR `hir_owner(y)` should be dirty but is not
+ //[cfail2]~| ERROR `hir_owner_nodes(y)` should be dirty but is not
+ //[cfail2]~| ERROR `generics_of(y)` should be dirty but is not
+ //[cfail2]~| ERROR `predicates_of(y)` should be dirty but is not
+ //[cfail2]~| ERROR `type_of(y)` should be dirty but is not
+ //[cfail2]~| ERROR `fn_sig(y)` should be dirty but is not
+ //[cfail2]~| ERROR `typeck(y)` should be clean but is not
x::x();
}
}
mod z {
- #[rustc_dirty(label="typeck", cfg="cfail2")]
+ #[rustc_clean(except="typeck", cfg="cfail2")]
pub fn z() {
//[cfail2]~^ ERROR `typeck(z)` should be dirty but is not
}
#[cfg(not(cfail1))]
use super::callee2 as callee;
- #[rustc_clean(label="hir_owner", cfg="cfail2")]
- #[rustc_clean(label="hir_owner", cfg="cfail3")]
- #[rustc_dirty(label="hir_owner_nodes", cfg="cfail2")]
- #[rustc_clean(label="hir_owner_nodes", cfg="cfail3")]
-
-
+ #[rustc_clean(except="hir_owner_nodes,typeck", cfg="cfail2")]
+ #[rustc_clean(cfg="cfail3")]
pub fn change_callee_indirectly_function() {
callee(1, 2)
}
}
#[cfg(not(cfail1))]
-#[rustc_dirty(cfg="cfail2")]
+#[rustc_clean(cfg="cfail2", except="hir_owner,hir_owner_nodes,generics_of,predicates_of,type_of")]
#[rustc_clean(cfg="cfail3")]
enum EnumChangeNameOfTypeParameter<T> {
Variant1(T),
}
#[cfg(not(cfail1))]
-#[rustc_dirty(cfg="cfail2")]
+#[rustc_clean(cfg="cfail2", except="hir_owner,hir_owner_nodes,generics_of,predicates_of,type_of")]
#[rustc_clean(cfg="cfail3")]
enum EnumAddTypeParameter<S, T> {
Variant1(S),
}
#[cfg(not(cfail1))]
-#[rustc_dirty(cfg="cfail2", except="predicates_of")]
+#[rustc_clean(cfg="cfail2", except="hir_owner,hir_owner_nodes,generics_of,type_of")]
#[rustc_clean(cfg="cfail3")]
enum EnumChangeNameOfLifetimeParameter<'b> {
Variant1(&'b u32),
}
#[cfg(not(cfail1))]
-#[rustc_dirty(cfg="cfail2", except="predicates_of")]
+#[rustc_clean(cfg="cfail2", except="hir_owner,hir_owner_nodes,generics_of,type_of")]
#[rustc_clean(cfg="cfail3")]
enum EnumAddLifetimeParameter<'a, 'b> {
Variant1(&'a u32),
}
#[cfg(not(cfail1))]
-#[rustc_dirty(cfg="cfail2", except="generics_of,type_of")]
+#[rustc_clean(cfg="cfail2", except="hir_owner,hir_owner_nodes,predicates_of")]
#[rustc_clean(cfg="cfail3")]
enum EnumAddLifetimeParameterBound<'a, 'b: 'a> {
Variant1(&'a u32),
}
#[cfg(not(cfail1))]
-#[rustc_dirty(cfg="cfail2", except="type_of")]
+#[rustc_clean(cfg="cfail2", except="hir_owner,hir_owner_nodes,generics_of,predicates_of")]
#[rustc_clean(cfg="cfail3")]
enum EnumAddLifetimeBoundToParameter<'a, T: 'a> {
Variant1(T),
}
#[cfg(not(cfail1))]
-#[rustc_dirty(cfg="cfail2")]
+#[rustc_clean(cfg="cfail2", except="hir_owner,hir_owner_nodes,generics_of,predicates_of,type_of")]
#[rustc_clean(cfg="cfail3")]
enum EnumAddTraitBound<T: Sync> {
Variant1(T),
}
#[cfg(not(cfail1))]
-#[rustc_dirty(cfg="cfail2", except="generics_of,type_of")]
+#[rustc_clean(cfg="cfail2", except="hir_owner,hir_owner_nodes,predicates_of")]
#[rustc_clean(cfg="cfail3")]
enum EnumAddLifetimeParameterBoundWhere<'a, 'b> where 'b: 'a {
Variant1(&'a u32),
}
#[cfg(not(cfail1))]
-#[rustc_dirty(cfg="cfail2", except="type_of")]
+#[rustc_clean(cfg="cfail2", except="hir_owner,hir_owner_nodes,generics_of,predicates_of")]
#[rustc_clean(cfg="cfail3")]
enum EnumAddLifetimeBoundToParameterWhere<'a, T> where T: 'a {
Variant1(T),
}
#[cfg(not(cfail1))]
-#[rustc_dirty(cfg="cfail2")]
+#[rustc_clean(cfg="cfail2", except="hir_owner,hir_owner_nodes,generics_of,predicates_of,type_of")]
#[rustc_clean(cfg="cfail3")]
enum EnumAddTraitBoundWhere<T> where T: Sync {
Variant1(T),
}
#[cfg(not(cfail1))]
-#[rustc_dirty(cfg = "cfail2", except = "hir_owner_nodes")]
+#[rustc_clean(cfg = "cfail2", except = "hir_owner")]
#[rustc_clean(cfg = "cfail3")]
extern "C" {
pub fn change_function_name2(c: i64) -> i32;
}
#[cfg(not(cfail1))]
-#[rustc_dirty(cfg = "cfail2", except = "hir_owner,hir_owner_nodes")]
+#[rustc_clean(cfg = "cfail2")]
#[rustc_clean(cfg = "cfail3")]
extern "C" {
pub fn change_parameter_name(d: i64) -> i32;
}
#[cfg(not(cfail1))]
-#[rustc_dirty(cfg = "cfail2", except = "hir_owner,hir_owner_nodes")]
+#[rustc_clean(cfg = "cfail2")]
#[rustc_clean(cfg = "cfail3")]
extern "C" {
pub fn change_parameter_type(c: i32) -> i32;
}
#[cfg(not(cfail1))]
-#[rustc_dirty(cfg = "cfail2", except = "hir_owner,hir_owner_nodes")]
+#[rustc_clean(cfg = "cfail2")]
#[rustc_clean(cfg = "cfail3")]
extern "C" {
pub fn change_return_type(c: i32) -> i8;
}
#[cfg(not(cfail1))]
-#[rustc_dirty(cfg = "cfail2", except = "hir_owner,hir_owner_nodes")]
+#[rustc_clean(cfg = "cfail2")]
#[rustc_clean(cfg = "cfail3")]
extern "C" {
pub fn add_parameter(c: i32, d: i32) -> i32;
}
#[cfg(not(cfail1))]
-#[rustc_dirty(cfg = "cfail2", except = "hir_owner,hir_owner_nodes")]
+#[rustc_clean(cfg = "cfail2")]
#[rustc_clean(cfg = "cfail3")]
extern "C" {
pub fn add_return_type(c: i32) -> i32;
}
#[cfg(not(cfail1))]
-#[rustc_dirty(cfg = "cfail2", except = "hir_owner,hir_owner_nodes")]
+#[rustc_clean(cfg = "cfail2")]
#[rustc_clean(cfg = "cfail3")]
extern "C" {
pub fn make_function_variadic(c: i32, ...);
}
#[cfg(not(cfail1))]
-#[rustc_dirty(cfg = "cfail2", except = "hir_owner_nodes")]
+#[rustc_clean(cfg = "cfail2", except = "hir_owner")]
#[rustc_clean(cfg = "cfail3")]
extern "rust-call" {
pub fn change_calling_convention(c: i32);
}
#[cfg(not(cfail1))]
-#[rustc_dirty(cfg = "cfail2", except = "hir_owner_nodes")]
+#[rustc_clean(cfg = "cfail2", except = "hir_owner")]
#[rustc_clean(cfg = "cfail3")]
extern "C" {
pub fn make_function_public(c: i32);
}
#[cfg(not(cfail1))]
-#[rustc_dirty(cfg = "cfail2", except = "hir_owner_nodes")]
+#[rustc_clean(cfg = "cfail2", except = "hir_owner")]
#[rustc_clean(cfg = "cfail3")]
extern "C" {
pub fn add_function1(c: i32);
}
#[cfg(not(cfail1))]
-#[rustc_dirty(cfg = "cfail2", except = "hir_owner,hir_owner_nodes")]
+#[rustc_clean(cfg = "cfail2")]
#[rustc_clean(cfg = "cfail3")]
#[link(name = "bar")]
extern "C" {
#[cfg(not(cfail1))]
use super::c_i64 as c_int;
- #[rustc_dirty(cfg = "cfail2", except = "hir_owner,hir_owner_nodes")]
+ #[rustc_clean(cfg = "cfail2")]
#[rustc_clean(cfg = "cfail3")]
extern "C" {
pub fn indirectly_change_parameter_type(c: c_int);
#[cfg(not(cfail1))]
use super::c_i64 as c_int;
- #[rustc_dirty(cfg = "cfail2", except = "hir_owner,hir_owner_nodes")]
+ #[rustc_clean(cfg = "cfail2")]
#[rustc_clean(cfg = "cfail3")]
extern "C" {
pub fn indirectly_change_return_type() -> c_int;
}
#[cfg(not(cfail1))]
-#[rustc_clean(label="hir_owner", cfg="cfail2")]
-#[rustc_clean(label="hir_owner", cfg="cfail3")]
-#[rustc_dirty(label="hir_owner_nodes", cfg="cfail2")]
-#[rustc_clean(label="hir_owner_nodes", cfg="cfail3")]
+#[rustc_clean(except="hir_owner_nodes", cfg="cfail2")]
+#[rustc_clean(cfg="cfail3")]
fn change_simple_index(slice: &[u32]) -> u32 {
slice[4]
}
}
#[cfg(not(cfail1))]
-#[rustc_clean(label="hir_owner", cfg="cfail2")]
-#[rustc_clean(label="hir_owner", cfg="cfail3")]
-#[rustc_dirty(label="hir_owner_nodes", cfg="cfail2")]
-#[rustc_clean(label="hir_owner_nodes", cfg="cfail3")]
+#[rustc_clean(except="hir_owner_nodes", cfg="cfail2")]
+#[rustc_clean(cfg="cfail3")]
fn change_lower_bound(slice: &[u32]) -> &[u32] {
&slice[2..5]
}
}
#[cfg(not(cfail1))]
-#[rustc_clean(label="hir_owner", cfg="cfail2")]
-#[rustc_clean(label="hir_owner", cfg="cfail3")]
-#[rustc_dirty(label="hir_owner_nodes", cfg="cfail2")]
-#[rustc_clean(label="hir_owner_nodes", cfg="cfail3")]
+#[rustc_clean(except="hir_owner_nodes", cfg="cfail2")]
+#[rustc_clean(cfg="cfail3")]
fn change_upper_bound(slice: &[u32]) -> &[u32] {
&slice[3..7]
}
}
#[cfg(not(cfail1))]
-#[rustc_clean(label="hir_owner", cfg="cfail2")]
-#[rustc_clean(label="hir_owner", cfg="cfail3")]
-#[rustc_dirty(label="hir_owner_nodes", cfg="cfail2")]
-#[rustc_clean(label="hir_owner_nodes", cfg="cfail3")]
+#[rustc_clean(except="hir_owner_nodes,typeck", cfg="cfail2")]
+#[rustc_clean(cfg="cfail3")]
fn add_lower_bound(slice: &[u32]) -> &[u32] {
&slice[3..4]
}
}
#[cfg(not(cfail1))]
-#[rustc_clean(label="hir_owner", cfg="cfail2")]
-#[rustc_clean(label="hir_owner", cfg="cfail3")]
-#[rustc_dirty(label="hir_owner_nodes", cfg="cfail2")]
-#[rustc_clean(label="hir_owner_nodes", cfg="cfail3")]
+#[rustc_clean(except="hir_owner_nodes,typeck", cfg="cfail2")]
+#[rustc_clean(cfg="cfail3")]
fn add_upper_bound(slice: &[u32]) -> &[u32] {
&slice[3..7]
}
}
#[cfg(not(cfail1))]
-#[rustc_clean(label="hir_owner", cfg="cfail2")]
-#[rustc_clean(label="hir_owner", cfg="cfail3")]
-#[rustc_dirty(label="hir_owner_nodes", cfg="cfail2")]
-#[rustc_clean(label="hir_owner_nodes", cfg="cfail3")]
+#[rustc_clean(except="hir_owner_nodes,typeck", cfg="cfail2")]
+#[rustc_clean(cfg="cfail3")]
fn change_mutability(slice: &mut [u32]) -> u32 {
(&slice[3..5])[0]
}
}
#[cfg(not(cfail1))]
-#[rustc_clean(label="hir_owner", cfg="cfail2")]
-#[rustc_clean(label="hir_owner", cfg="cfail3")]
-#[rustc_dirty(label="hir_owner_nodes", cfg="cfail2")]
-#[rustc_clean(label="hir_owner_nodes", cfg="cfail3")]
+#[rustc_clean(except="hir_owner_nodes,typeck", cfg="cfail2")]
+#[rustc_clean(cfg="cfail3")]
fn exclusive_to_inclusive_range(slice: &[u32]) -> &[u32] {
&slice[3..=7]
}
#[rustc_clean(cfg="cfail2", except="hir_owner")]
#[rustc_clean(cfg="cfail3")]
impl Foo {
- #[rustc_dirty(cfg="cfail2", except="type_of,predicates_of,promoted_mir")]
+ #[rustc_clean(
+ cfg="cfail2",
+ except="hir_owner,hir_owner_nodes,fn_sig,generics_of,typeck,associated_item,optimized_mir",
+ )]
#[rustc_clean(cfg="cfail3")]
pub fn method_selfness(&self) { }
}
pub struct LayoutPacked;
#[cfg(not(cfail1))]
-#[rustc_clean(label="hir_owner", cfg="cfail2")]
-#[rustc_clean(label="hir_owner_nodes", cfg="cfail2")]
-#[rustc_dirty(label="type_of", cfg="cfail2")]
-#[rustc_clean(label="generics_of", cfg="cfail2")]
-#[rustc_clean(label="predicates_of", cfg="cfail2")]
-#[rustc_clean(label="hir_owner", cfg="cfail3")]
-#[rustc_clean(label="hir_owner_nodes", cfg="cfail3")]
-#[rustc_clean(label="type_of", cfg="cfail3")]
-#[rustc_clean(label="generics_of", cfg="cfail3")]
-#[rustc_clean(label="predicates_of", cfg="cfail3")]
+#[rustc_clean(except="type_of", cfg="cfail2")]
+#[rustc_clean(cfg="cfail3")]
#[repr(packed)]
pub struct LayoutPacked;
struct LayoutC;
#[cfg(not(cfail1))]
-#[rustc_clean(label="hir_owner", cfg="cfail2")]
-#[rustc_clean(label="hir_owner_nodes", cfg="cfail2")]
-#[rustc_dirty(label="type_of", cfg="cfail2")]
-#[rustc_clean(label="generics_of", cfg="cfail2")]
-#[rustc_clean(label="predicates_of", cfg="cfail2")]
-#[rustc_clean(label="hir_owner", cfg="cfail3")]
-#[rustc_clean(label="hir_owner_nodes", cfg="cfail3")]
-#[rustc_clean(label="type_of", cfg="cfail3")]
-#[rustc_clean(label="generics_of", cfg="cfail3")]
-#[rustc_clean(label="predicates_of", cfg="cfail3")]
+#[rustc_clean(except="type_of", cfg="cfail2")]
+#[rustc_clean(cfg="cfail3")]
#[repr(C)]
struct LayoutC;
struct TupleStructFieldType(i32);
#[cfg(not(cfail1))]
-#[rustc_dirty(label="hir_owner", cfg="cfail2")]
-#[rustc_dirty(label="hir_owner_nodes", cfg="cfail2")]
-#[rustc_clean(label="type_of", cfg="cfail2")]
-#[rustc_clean(label="generics_of", cfg="cfail2")]
-#[rustc_clean(label="predicates_of", cfg="cfail2")]
-#[rustc_clean(label="hir_owner", cfg="cfail3")]
-#[rustc_clean(label="hir_owner_nodes", cfg="cfail3")]
-#[rustc_clean(label="type_of", cfg="cfail3")]
-#[rustc_clean(label="generics_of", cfg="cfail3")]
-#[rustc_clean(label="predicates_of", cfg="cfail3")]
+#[rustc_clean(except="hir_owner,hir_owner_nodes", cfg="cfail2")]
+#[rustc_clean(cfg="cfail3")]
// Note that changing the type of a field does not change the type of the struct or enum, but
// adding/removing fields or changing a fields name or visibility does.
struct TupleStructFieldType(
struct TupleStructAddField(i32);
#[cfg(not(cfail1))]
-#[rustc_dirty(label="hir_owner", cfg="cfail2")]
-#[rustc_dirty(label="hir_owner_nodes", cfg="cfail2")]
-#[rustc_dirty(label="type_of", cfg="cfail2")]
-#[rustc_clean(label="generics_of", cfg="cfail2")]
-#[rustc_clean(label="predicates_of", cfg="cfail2")]
-#[rustc_clean(label="hir_owner", cfg="cfail3")]
-#[rustc_clean(label="hir_owner_nodes", cfg="cfail3")]
-#[rustc_clean(label="type_of", cfg="cfail3")]
-#[rustc_clean(label="generics_of", cfg="cfail3")]
-#[rustc_clean(label="predicates_of", cfg="cfail3")]
+#[rustc_clean(except="hir_owner,hir_owner_nodes,type_of", cfg="cfail2")]
+#[rustc_clean(cfg="cfail3")]
struct TupleStructAddField(
i32,
u32
struct TupleStructFieldVisibility(char);
#[cfg(not(cfail1))]
-#[rustc_dirty(label="hir_owner", cfg="cfail2")]
-#[rustc_dirty(label="hir_owner_nodes", cfg="cfail2")]
-#[rustc_dirty(label="type_of", cfg="cfail2")]
-#[rustc_clean(label="generics_of", cfg="cfail2")]
-#[rustc_clean(label="predicates_of", cfg="cfail2")]
-#[rustc_clean(label="hir_owner", cfg="cfail3")]
-#[rustc_clean(label="hir_owner_nodes", cfg="cfail3")]
-#[rustc_clean(label="type_of", cfg="cfail3")]
-#[rustc_clean(label="generics_of", cfg="cfail3")]
-#[rustc_clean(label="predicates_of", cfg="cfail3")]
+#[rustc_clean(except="hir_owner,hir_owner_nodes,type_of", cfg="cfail2")]
+#[rustc_clean(cfg="cfail3")]
struct TupleStructFieldVisibility(pub char);
struct RecordStructFieldType { x: f32 }
#[cfg(not(cfail1))]
-#[rustc_dirty(label="hir_owner", cfg="cfail2")]
-#[rustc_dirty(label="hir_owner_nodes", cfg="cfail2")]
-#[rustc_clean(label="type_of", cfg="cfail2")]
-#[rustc_clean(label="generics_of", cfg="cfail2")]
-#[rustc_clean(label="predicates_of", cfg="cfail2")]
-#[rustc_clean(label="hir_owner", cfg="cfail3")]
-#[rustc_clean(label="hir_owner_nodes", cfg="cfail3")]
-#[rustc_clean(label="type_of", cfg="cfail3")]
-#[rustc_clean(label="generics_of", cfg="cfail3")]
-#[rustc_clean(label="predicates_of", cfg="cfail3")]
+#[rustc_clean(except="hir_owner,hir_owner_nodes", cfg="cfail2")]
+#[rustc_clean(cfg="cfail3")]
// Note that changing the type of a field does not change the type of the struct or enum, but
// adding/removing fields or changing a fields name or visibility does.
struct RecordStructFieldType {
struct RecordStructFieldName { x: f32 }
#[cfg(not(cfail1))]
-#[rustc_dirty(label="hir_owner", cfg="cfail2")]
-#[rustc_dirty(label="hir_owner_nodes", cfg="cfail2")]
-#[rustc_dirty(label="type_of", cfg="cfail2")]
-#[rustc_clean(label="generics_of", cfg="cfail2")]
-#[rustc_clean(label="predicates_of", cfg="cfail2")]
-#[rustc_clean(label="hir_owner", cfg="cfail3")]
-#[rustc_clean(label="hir_owner_nodes", cfg="cfail3")]
-#[rustc_clean(label="type_of", cfg="cfail3")]
-#[rustc_clean(label="generics_of", cfg="cfail3")]
-#[rustc_clean(label="predicates_of", cfg="cfail3")]
+#[rustc_clean(except="hir_owner,hir_owner_nodes,type_of", cfg="cfail2")]
+#[rustc_clean(cfg="cfail3")]
struct RecordStructFieldName { y: f32 }
struct RecordStructAddField { x: f32 }
#[cfg(not(cfail1))]
-#[rustc_dirty(label="hir_owner", cfg="cfail2")]
-#[rustc_dirty(label="hir_owner_nodes", cfg="cfail2")]
-#[rustc_dirty(label="type_of", cfg="cfail2")]
-#[rustc_clean(label="generics_of", cfg="cfail2")]
-#[rustc_clean(label="predicates_of", cfg="cfail2")]
-#[rustc_clean(label="hir_owner", cfg="cfail3")]
-#[rustc_clean(label="hir_owner_nodes", cfg="cfail3")]
-#[rustc_clean(label="type_of", cfg="cfail3")]
-#[rustc_clean(label="generics_of", cfg="cfail3")]
-#[rustc_clean(label="predicates_of", cfg="cfail3")]
+#[rustc_clean(except="hir_owner,hir_owner_nodes,type_of", cfg="cfail2")]
+#[rustc_clean(cfg="cfail3")]
struct RecordStructAddField {
x: f32,
y: () }
struct RecordStructFieldVisibility { x: f32 }
#[cfg(not(cfail1))]
-#[rustc_dirty(label="hir_owner", cfg="cfail2")]
-#[rustc_dirty(label="hir_owner_nodes", cfg="cfail2")]
-#[rustc_dirty(label="type_of", cfg="cfail2")]
-#[rustc_clean(label="generics_of", cfg="cfail2")]
-#[rustc_clean(label="predicates_of", cfg="cfail2")]
-#[rustc_clean(label="hir_owner", cfg="cfail3")]
-#[rustc_clean(label="hir_owner_nodes", cfg="cfail3")]
-#[rustc_clean(label="type_of", cfg="cfail3")]
-#[rustc_clean(label="generics_of", cfg="cfail3")]
-#[rustc_clean(label="predicates_of", cfg="cfail3")]
+#[rustc_clean(except="hir_owner,hir_owner_nodes,type_of", cfg="cfail2")]
+#[rustc_clean(cfg="cfail3")]
struct RecordStructFieldVisibility {
pub x: f32
}
struct AddLifetimeParameter<'a>(&'a f32, &'a f64);
#[cfg(not(cfail1))]
-#[rustc_dirty(label="hir_owner", cfg="cfail2")]
-#[rustc_dirty(label="hir_owner_nodes", cfg="cfail2")]
-#[rustc_dirty(label="type_of", cfg="cfail2")]
-#[rustc_dirty(label="generics_of", cfg="cfail2")]
-#[rustc_clean(label="predicates_of", cfg="cfail2")]
-#[rustc_clean(label="hir_owner", cfg="cfail3")]
-#[rustc_clean(label="hir_owner_nodes", cfg="cfail3")]
-#[rustc_clean(label="type_of", cfg="cfail3")]
-#[rustc_clean(label="generics_of", cfg="cfail3")]
-#[rustc_clean(label="predicates_of", cfg="cfail3")]
+#[rustc_clean(except="hir_owner,hir_owner_nodes,type_of,generics_of", cfg="cfail2")]
+#[rustc_clean(cfg="cfail3")]
struct AddLifetimeParameter<'a, 'b>(&'a f32, &'b f64);
struct AddLifetimeParameterBound<'a, 'b>(&'a f32, &'b f64);
#[cfg(not(cfail1))]
-#[rustc_dirty(label="hir_owner", cfg="cfail2")]
-#[rustc_dirty(label="hir_owner_nodes", cfg="cfail2")]
-#[rustc_clean(label="type_of", cfg="cfail2")]
-#[rustc_clean(label="generics_of", cfg="cfail2")]
-#[rustc_dirty(label="predicates_of", cfg="cfail2")]
-#[rustc_clean(label="hir_owner", cfg="cfail3")]
-#[rustc_clean(label="hir_owner_nodes", cfg="cfail3")]
-#[rustc_clean(label="type_of", cfg="cfail3")]
-#[rustc_clean(label="generics_of", cfg="cfail3")]
-#[rustc_clean(label="predicates_of", cfg="cfail3")]
+#[rustc_clean(except="hir_owner,hir_owner_nodes,predicates_of", cfg="cfail2")]
+#[rustc_clean(cfg="cfail3")]
struct AddLifetimeParameterBound<'a, 'b: 'a>(
&'a f32,
&'b f64
struct AddLifetimeParameterBoundWhereClause<'a, 'b>(&'a f32, &'b f64);
#[cfg(not(cfail1))]
-#[rustc_dirty(label="hir_owner", cfg="cfail2")]
-#[rustc_dirty(label="hir_owner_nodes", cfg="cfail2")]
-#[rustc_clean(label="type_of", cfg="cfail2")]
-#[rustc_clean(label="generics_of", cfg="cfail2")]
-#[rustc_dirty(label="predicates_of", cfg="cfail2")]
-#[rustc_clean(label="hir_owner", cfg="cfail3")]
-#[rustc_clean(label="hir_owner_nodes", cfg="cfail3")]
-#[rustc_clean(label="type_of", cfg="cfail3")]
-#[rustc_clean(label="generics_of", cfg="cfail3")]
-#[rustc_clean(label="predicates_of", cfg="cfail3")]
+#[rustc_clean(except="hir_owner,hir_owner_nodes,predicates_of", cfg="cfail2")]
+#[rustc_clean(cfg="cfail3")]
struct AddLifetimeParameterBoundWhereClause<'a, 'b>(
&'a f32,
&'b f64)
struct AddTypeParameter<T1>(T1, T1);
#[cfg(not(cfail1))]
-#[rustc_dirty(label="hir_owner", cfg="cfail2")]
-#[rustc_dirty(label="hir_owner_nodes", cfg="cfail2")]
-#[rustc_dirty(label="type_of", cfg="cfail2")]
-#[rustc_dirty(label="generics_of", cfg="cfail2")]
-#[rustc_dirty(label="predicates_of", cfg="cfail2")]
-#[rustc_clean(label="hir_owner", cfg="cfail3")]
-#[rustc_clean(label="hir_owner_nodes", cfg="cfail3")]
-#[rustc_clean(label="type_of", cfg="cfail3")]
-#[rustc_clean(label="generics_of", cfg="cfail3")]
-#[rustc_clean(label="predicates_of", cfg="cfail3")]
+#[rustc_clean(except="hir_owner,hir_owner_nodes,type_of,generics_of,predicates_of", cfg="cfail2")]
+#[rustc_clean(cfg="cfail3")]
struct AddTypeParameter<T1, T2>(
// The field contains the parent's Generics, so it's dirty even though its
// type hasn't changed.
struct AddTypeParameterBound<T>(T);
#[cfg(not(cfail1))]
-#[rustc_dirty(label="hir_owner", cfg="cfail2")]
-#[rustc_dirty(label="hir_owner_nodes", cfg="cfail2")]
-#[rustc_clean(label="type_of", cfg="cfail2")]
-#[rustc_clean(label="generics_of", cfg="cfail2")]
-#[rustc_dirty(label="predicates_of", cfg="cfail2")]
-#[rustc_clean(label="hir_owner", cfg="cfail3")]
-#[rustc_clean(label="hir_owner_nodes", cfg="cfail3")]
-#[rustc_clean(label="type_of", cfg="cfail3")]
-#[rustc_clean(label="generics_of", cfg="cfail3")]
-#[rustc_clean(label="predicates_of", cfg="cfail3")]
+#[rustc_clean(except="hir_owner,hir_owner_nodes,predicates_of", cfg="cfail2")]
+#[rustc_clean(cfg="cfail3")]
struct AddTypeParameterBound<T: Send>(
T
);
struct AddTypeParameterBoundWhereClause<T>(T);
#[cfg(not(cfail1))]
-#[rustc_dirty(label="hir_owner", cfg="cfail2")]
-#[rustc_dirty(label="hir_owner_nodes", cfg="cfail2")]
-#[rustc_clean(label="type_of", cfg="cfail2")]
-#[rustc_clean(label="generics_of", cfg="cfail2")]
-#[rustc_dirty(label="predicates_of", cfg="cfail2")]
-#[rustc_clean(label="hir_owner", cfg="cfail3")]
-#[rustc_clean(label="hir_owner_nodes", cfg="cfail3")]
-#[rustc_clean(label="type_of", cfg="cfail3")]
-#[rustc_clean(label="generics_of", cfg="cfail3")]
-#[rustc_clean(label="predicates_of", cfg="cfail3")]
+#[rustc_clean(except="hir_owner,hir_owner_nodes,predicates_of", cfg="cfail2")]
+#[rustc_clean(cfg="cfail3")]
struct AddTypeParameterBoundWhereClause<T>(
T
) where T: Sync;
// fingerprint is stable (i.e., that there are no random influences like memory
// addresses taken into account by the hashing algorithm).
// Note: there is no #[cfg(...)], so this is ALWAYS compiled
-#[rustc_clean(label="hir_owner", cfg="cfail2")]
-#[rustc_clean(label="hir_owner_nodes", cfg="cfail2")]
-#[rustc_clean(label="type_of", cfg="cfail2")]
-#[rustc_clean(label="generics_of", cfg="cfail2")]
-#[rustc_clean(label="predicates_of", cfg="cfail2")]
-#[rustc_clean(label="hir_owner", cfg="cfail3")]
-#[rustc_clean(label="hir_owner_nodes", cfg="cfail3")]
-#[rustc_clean(label="type_of", cfg="cfail3")]
-#[rustc_clean(label="generics_of", cfg="cfail3")]
-#[rustc_clean(label="predicates_of", cfg="cfail3")]
+#[rustc_clean(cfg="cfail2")]
+#[rustc_clean(cfg="cfail3")]
pub struct EmptyStruct;
struct Visibility;
#[cfg(not(cfail1))]
-#[rustc_dirty(label="hir_owner", cfg="cfail2")]
-#[rustc_dirty(label="hir_owner_nodes", cfg="cfail2")]
-#[rustc_clean(label="type_of", cfg="cfail2")]
-#[rustc_clean(label="generics_of", cfg="cfail2")]
-#[rustc_clean(label="predicates_of", cfg="cfail2")]
-#[rustc_clean(label="hir_owner", cfg="cfail3")]
-#[rustc_clean(label="hir_owner_nodes", cfg="cfail3")]
-#[rustc_clean(label="type_of", cfg="cfail3")]
-#[rustc_clean(label="generics_of", cfg="cfail3")]
-#[rustc_clean(label="predicates_of", cfg="cfail3")]
+#[rustc_clean(except="hir_owner,hir_owner_nodes", cfg="cfail2")]
+#[rustc_clean(cfg="cfail3")]
pub struct Visibility;
struct ReferencedType1;
#[cfg(not(cfail1))]
use super::ReferencedType2 as FieldType;
- #[rustc_dirty(label="hir_owner", cfg="cfail2")]
- #[rustc_dirty(label="hir_owner_nodes", cfg="cfail2")]
- #[rustc_clean(label="type_of", cfg="cfail2")]
- #[rustc_clean(label="generics_of", cfg="cfail2")]
- #[rustc_clean(label="predicates_of", cfg="cfail2")]
- #[rustc_clean(label="hir_owner", cfg="cfail3")]
- #[rustc_clean(label="hir_owner_nodes", cfg="cfail3")]
- #[rustc_clean(label="type_of", cfg="cfail3")]
- #[rustc_clean(label="generics_of", cfg="cfail3")]
- #[rustc_clean(label="predicates_of", cfg="cfail3")]
+ #[rustc_clean(except="hir_owner,hir_owner_nodes", cfg="cfail2")]
+ #[rustc_clean(cfg="cfail3")]
struct TupleStruct(
FieldType
);
#[cfg(not(cfail1))]
use super::ReferencedType2 as FieldType;
- #[rustc_dirty(label="hir_owner", cfg="cfail2")]
- #[rustc_dirty(label="hir_owner_nodes", cfg="cfail2")]
- #[rustc_clean(label="type_of", cfg="cfail2")]
- #[rustc_clean(label="generics_of", cfg="cfail2")]
- #[rustc_clean(label="predicates_of", cfg="cfail2")]
- #[rustc_clean(label="hir_owner", cfg="cfail3")]
- #[rustc_clean(label="hir_owner_nodes", cfg="cfail3")]
- #[rustc_clean(label="type_of", cfg="cfail3")]
- #[rustc_clean(label="generics_of", cfg="cfail3")]
- #[rustc_clean(label="predicates_of", cfg="cfail3")]
+ #[rustc_clean(except="hir_owner,hir_owner_nodes", cfg="cfail2")]
+ #[rustc_clean(cfg="cfail3")]
struct RecordStruct {
_x: FieldType
}
#[cfg(not(cfail1))]
use super::ReferencedTrait2 as Trait;
- #[rustc_dirty(label="hir_owner", cfg="cfail2")]
- #[rustc_dirty(label="hir_owner_nodes", cfg="cfail2")]
- #[rustc_clean(label="type_of", cfg="cfail2")]
- #[rustc_clean(label="generics_of", cfg="cfail2")]
- #[rustc_dirty(label="predicates_of", cfg="cfail2")]
- #[rustc_clean(label="hir_owner", cfg="cfail3")]
- #[rustc_clean(label="hir_owner_nodes", cfg="cfail3")]
- #[rustc_clean(label="type_of", cfg="cfail3")]
- #[rustc_clean(label="generics_of", cfg="cfail3")]
- #[rustc_clean(label="predicates_of", cfg="cfail3")]
+ #[rustc_clean(except="hir_owner,hir_owner_nodes,predicates_of", cfg="cfail2")]
+ #[rustc_clean(cfg="cfail3")]
struct Struct<T: Trait>(T);
}
#[cfg(not(cfail1))]
use super::ReferencedTrait2 as Trait;
- #[rustc_dirty(label="hir_owner", cfg="cfail2")]
- #[rustc_dirty(label="hir_owner_nodes", cfg="cfail2")]
- #[rustc_clean(label="type_of", cfg="cfail2")]
- #[rustc_clean(label="generics_of", cfg="cfail2")]
- #[rustc_dirty(label="predicates_of", cfg="cfail2")]
- #[rustc_clean(label="hir_owner", cfg="cfail3")]
- #[rustc_clean(label="hir_owner_nodes", cfg="cfail3")]
- #[rustc_clean(label="type_of", cfg="cfail3")]
- #[rustc_clean(label="generics_of", cfg="cfail3")]
- #[rustc_clean(label="predicates_of", cfg="cfail3")]
+ #[rustc_clean(except="hir_owner,hir_owner_nodes,predicates_of", cfg="cfail2")]
+ #[rustc_clean(cfg="cfail3")]
struct Struct<T>(T) where T : Trait;
}
trait TraitVisibility { }
#[cfg(not(cfail1))]
-#[rustc_dirty(label="hir_owner", cfg="cfail2")]
-#[rustc_clean(label="hir_owner", cfg="cfail3")]
+#[rustc_clean(except="hir_owner", cfg="cfail2")]
+#[rustc_clean(cfg="cfail3")]
pub trait TraitVisibility { }
trait TraitUnsafety { }
#[cfg(not(cfail1))]
-#[rustc_dirty(label="hir_owner", cfg="cfail2")]
-#[rustc_clean(label="hir_owner", cfg="cfail3")]
+#[rustc_clean(except="hir_owner", cfg="cfail2")]
+#[rustc_clean(cfg="cfail3")]
unsafe trait TraitUnsafety { }
}
#[cfg(not(cfail1))]
-#[rustc_dirty(label="hir_owner", cfg="cfail2")]
-#[rustc_clean(label="hir_owner", cfg="cfail3")]
+#[rustc_clean(except="hir_owner,associated_item_def_ids", cfg="cfail2")]
+#[rustc_clean(cfg="cfail3")]
pub trait TraitAddMethod {
fn method();
}
}
#[cfg(not(cfail1))]
-#[rustc_dirty(label="hir_owner", cfg="cfail2")]
-#[rustc_clean(label="hir_owner", cfg="cfail3")]
+#[rustc_clean(except="hir_owner,associated_item_def_ids", cfg="cfail2")]
+#[rustc_clean(cfg="cfail3")]
trait TraitChangeMethodName {
fn methodChanged();
}
}
#[cfg(not(cfail1))]
-#[rustc_clean(label="hir_owner", cfg="cfail2")]
-#[rustc_clean(label="hir_owner", cfg="cfail3")]
+#[rustc_clean(cfg="cfail2")]
+#[rustc_clean(cfg="cfail3")]
trait TraitAddReturnType {
- #[rustc_dirty(label="hir_owner", cfg="cfail2")]
- #[rustc_clean(label="hir_owner", cfg="cfail3")]
+ #[rustc_clean(except="hir_owner,fn_sig", cfg="cfail2")]
+ #[rustc_clean(cfg="cfail3")]
fn method() -> u32;
}
}
#[cfg(not(cfail1))]
-#[rustc_clean(label="hir_owner", cfg="cfail2")]
-#[rustc_clean(label="hir_owner", cfg="cfail3")]
+#[rustc_clean(cfg="cfail2")]
+#[rustc_clean(cfg="cfail3")]
trait TraitChangeReturnType {
- #[rustc_dirty(label="hir_owner", cfg="cfail2")]
- #[rustc_clean(label="hir_owner", cfg="cfail3")]
+ #[rustc_clean(except="hir_owner,hir_owner_nodes,fn_sig", cfg="cfail2")]
+ #[rustc_clean(cfg="cfail3")]
fn method() -> u64;
}
}
#[cfg(not(cfail1))]
-#[rustc_clean(label="hir_owner", cfg="cfail2")]
-#[rustc_clean(label="hir_owner", cfg="cfail3")]
+#[rustc_clean(cfg="cfail2")]
+#[rustc_clean(cfg="cfail3")]
trait TraitAddParameterToMethod {
- #[rustc_dirty(label="hir_owner", cfg="cfail2")]
- #[rustc_clean(label="hir_owner", cfg="cfail3")]
+ #[rustc_clean(except="hir_owner,fn_sig", cfg="cfail2")]
+ #[rustc_clean(cfg="cfail3")]
fn method(a: u32);
}
}
#[cfg(not(cfail1))]
-#[rustc_clean(label="hir_owner", cfg="cfail2")]
-#[rustc_clean(label="hir_owner", cfg="cfail3")]
+#[rustc_clean(cfg="cfail2")]
+#[rustc_clean(cfg="cfail3")]
trait TraitChangeMethodParameterName {
// FIXME(#38501) This should preferably always be clean.
- #[rustc_dirty(label="hir_owner", cfg="cfail2")]
- #[rustc_clean(label="hir_owner", cfg="cfail3")]
+ #[rustc_clean(except="hir_owner", cfg="cfail2")]
+ #[rustc_clean(cfg="cfail3")]
fn method(b: u32);
- #[rustc_clean(label="hir_owner", cfg="cfail2")]
- #[rustc_clean(label="hir_owner", cfg="cfail3")]
- #[rustc_dirty(label="hir_owner_nodes", cfg="cfail2")]
- #[rustc_clean(label="hir_owner_nodes", cfg="cfail3")]
+ #[rustc_clean(except="hir_owner_nodes,optimized_mir", cfg="cfail2")]
+ #[rustc_clean(cfg="cfail3")]
fn with_default(y: i32) {}
}
}
#[cfg(not(cfail1))]
-#[rustc_clean(label="hir_owner", cfg="cfail2")]
-#[rustc_clean(label="hir_owner", cfg="cfail3")]
+#[rustc_clean(cfg="cfail2")]
+#[rustc_clean(cfg="cfail3")]
trait TraitChangeMethodParameterType {
- #[rustc_dirty(label="hir_owner", cfg="cfail2")]
- #[rustc_clean(label="hir_owner", cfg="cfail3")]
+ #[rustc_clean(except="hir_owner,fn_sig", cfg="cfail2")]
+ #[rustc_clean(cfg="cfail3")]
fn method(a: i64);
}
}
#[cfg(not(cfail1))]
-#[rustc_clean(label="hir_owner", cfg="cfail2")]
-#[rustc_clean(label="hir_owner", cfg="cfail3")]
+#[rustc_clean(cfg="cfail2")]
+#[rustc_clean(cfg="cfail3")]
trait TraitChangeMethodParameterTypeRef {
- #[rustc_dirty(label="hir_owner", cfg="cfail2")]
- #[rustc_clean(label="hir_owner", cfg="cfail3")]
+ #[rustc_clean(except="hir_owner,fn_sig", cfg="cfail2")]
+ #[rustc_clean(cfg="cfail3")]
fn method(a: &mut i32);
}
}
#[cfg(not(cfail1))]
-#[rustc_clean(label="hir_owner", cfg="cfail2")]
-#[rustc_clean(label="hir_owner", cfg="cfail3")]
+#[rustc_clean(cfg="cfail2")]
+#[rustc_clean(cfg="cfail3")]
trait TraitChangeMethodParametersOrder {
- #[rustc_dirty(label="hir_owner", cfg="cfail2")]
- #[rustc_clean(label="hir_owner", cfg="cfail3")]
+ #[rustc_clean(except="hir_owner,fn_sig", cfg="cfail2")]
+ #[rustc_clean(cfg="cfail3")]
fn method(b: i64, a: i32);
}
}
#[cfg(not(cfail1))]
-#[rustc_dirty(label="hir_owner", cfg="cfail2")]
-#[rustc_clean(label="hir_owner", cfg="cfail3")]
+#[rustc_clean(except="hir_owner", cfg="cfail2")]
+#[rustc_clean(cfg="cfail3")]
trait TraitAddMethodAutoImplementation {
- #[rustc_dirty(label="hir_owner", cfg="cfail2")]
- #[rustc_clean(label="hir_owner", cfg="cfail3")]
+ #[rustc_clean(except="hir_owner,associated_item", cfg="cfail2")]
+ #[rustc_clean(cfg="cfail3")]
fn method() { }
}
}
#[cfg(not(cfail1))]
-#[rustc_dirty(label="hir_owner", cfg="cfail2")]
-#[rustc_clean(label="hir_owner", cfg="cfail3")]
+#[rustc_clean(except="hir_owner,associated_item_def_ids", cfg="cfail2")]
+#[rustc_clean(cfg="cfail3")]
trait TraitChangeOrderOfMethods {
fn method1();
fn method0();
}
#[cfg(not(cfail1))]
-#[rustc_clean(label="hir_owner", cfg="cfail2")]
-#[rustc_clean(label="hir_owner", cfg="cfail3")]
+#[rustc_clean(cfg="cfail2")]
+#[rustc_clean(cfg="cfail3")]
trait TraitChangeModeSelfRefToMut {
- #[rustc_dirty(label="hir_owner", cfg="cfail2")]
- #[rustc_clean(label="hir_owner", cfg="cfail3")]
+ #[rustc_clean(except="hir_owner,fn_sig", cfg="cfail2")]
+ #[rustc_clean(cfg="cfail3")]
fn method(&mut self);
}
}
#[cfg(not(cfail1))]
-#[rustc_clean(label="hir_owner", cfg="cfail2")]
-#[rustc_clean(label="hir_owner", cfg="cfail3")]
+#[rustc_clean(cfg="cfail2")]
+#[rustc_clean(cfg="cfail3")]
trait TraitChangeModeSelfOwnToMut: Sized {
- #[rustc_dirty(label="hir_owner", cfg="cfail2")]
- #[rustc_clean(label="hir_owner", cfg="cfail3")]
- #[rustc_dirty(label="hir_owner_nodes", cfg="cfail2")]
- #[rustc_clean(label="hir_owner_nodes", cfg="cfail3")]
+ #[rustc_clean(except="hir_owner,hir_owner_nodes,typeck,optimized_mir", cfg="cfail2")]
+ #[rustc_clean(cfg="cfail3")]
fn method(mut self) {}
}
}
#[cfg(not(cfail1))]
-#[rustc_clean(label="hir_owner", cfg="cfail2")]
-#[rustc_clean(label="hir_owner", cfg="cfail3")]
+#[rustc_clean(cfg="cfail2")]
+#[rustc_clean(cfg="cfail3")]
trait TraitChangeModeSelfOwnToRef {
- #[rustc_dirty(label="hir_owner", cfg="cfail2")]
- #[rustc_clean(label="hir_owner", cfg="cfail3")]
+ #[rustc_clean(except="hir_owner,fn_sig,generics_of", cfg="cfail2")]
+ #[rustc_clean(cfg="cfail3")]
fn method(&self);
}
}
#[cfg(not(cfail1))]
-#[rustc_clean(label="hir_owner", cfg="cfail2")]
-#[rustc_clean(label="hir_owner", cfg="cfail3")]
+#[rustc_clean(cfg="cfail2")]
+#[rustc_clean(cfg="cfail3")]
trait TraitAddUnsafeModifier {
- #[rustc_dirty(label="hir_owner", cfg="cfail2")]
- #[rustc_clean(label="hir_owner", cfg="cfail3")]
+ #[rustc_clean(except="hir_owner,fn_sig", cfg="cfail2")]
+ #[rustc_clean(cfg="cfail3")]
unsafe fn method();
}
}
#[cfg(not(cfail1))]
-#[rustc_clean(label="hir_owner", cfg="cfail2")]
-#[rustc_clean(label="hir_owner", cfg="cfail3")]
+#[rustc_clean(cfg="cfail2")]
+#[rustc_clean(cfg="cfail3")]
trait TraitAddExternModifier {
- #[rustc_dirty(label="hir_owner", cfg="cfail2")]
- #[rustc_clean(label="hir_owner", cfg="cfail3")]
+ #[rustc_clean(except="hir_owner,fn_sig", cfg="cfail2")]
+ #[rustc_clean(cfg="cfail3")]
extern "C" fn method();
}
}
#[cfg(not(cfail1))]
-#[rustc_clean(label="hir_owner", cfg="cfail2")]
-#[rustc_clean(label="hir_owner", cfg="cfail3")]
+#[rustc_clean(cfg="cfail2")]
+#[rustc_clean(cfg="cfail3")]
trait TraitChangeExternCToRustIntrinsic {
- #[rustc_dirty(label="hir_owner", cfg="cfail2")]
- #[rustc_clean(label="hir_owner", cfg="cfail3")]
+ #[rustc_clean(except="hir_owner,fn_sig", cfg="cfail2")]
+ #[rustc_clean(cfg="cfail3")]
extern "stdcall" fn method();
}
}
#[cfg(not(cfail1))]
-#[rustc_clean(label="hir_owner", cfg="cfail2")]
-#[rustc_clean(label="hir_owner", cfg="cfail3")]
+#[rustc_clean(cfg="cfail2")]
+#[rustc_clean(cfg="cfail3")]
trait TraitAddTypeParameterToMethod {
- #[rustc_dirty(label="hir_owner", cfg="cfail2")]
- #[rustc_clean(label="hir_owner", cfg="cfail3")]
+ #[rustc_clean(except="hir_owner,generics_of,predicates_of,type_of", cfg="cfail2")]
+ #[rustc_clean(cfg="cfail3")]
fn method<T>();
}
}
#[cfg(not(cfail1))]
-#[rustc_clean(label="hir_owner", cfg="cfail2")]
-#[rustc_clean(label="hir_owner", cfg="cfail3")]
+#[rustc_clean(cfg="cfail2")]
+#[rustc_clean(cfg="cfail3")]
trait TraitAddLifetimeParameterToMethod {
- #[rustc_dirty(label="hir_owner", cfg="cfail2")]
- #[rustc_clean(label="hir_owner", cfg="cfail3")]
+ #[rustc_clean(except="hir_owner,fn_sig,generics_of", cfg="cfail2")]
+ #[rustc_clean(cfg="cfail3")]
fn method<'a>();
}
}
#[cfg(not(cfail1))]
-#[rustc_clean(label="hir_owner", cfg="cfail2")]
-#[rustc_clean(label="hir_owner", cfg="cfail3")]
+#[rustc_clean(cfg="cfail2")]
+#[rustc_clean(cfg="cfail3")]
trait TraitAddTraitBoundToMethodTypeParameter {
- #[rustc_dirty(label="hir_owner", cfg="cfail2")]
- #[rustc_clean(label="hir_owner", cfg="cfail3")]
+ #[rustc_clean(except="hir_owner,hir_owner_nodes,predicates_of", cfg="cfail2")]
+ #[rustc_clean(cfg="cfail3")]
fn method<T: ReferencedTrait0>();
}
}
#[cfg(not(cfail1))]
-#[rustc_clean(label="hir_owner", cfg="cfail2")]
-#[rustc_clean(label="hir_owner", cfg="cfail3")]
+#[rustc_clean(cfg="cfail2")]
+#[rustc_clean(cfg="cfail3")]
trait TraitAddBuiltinBoundToMethodTypeParameter {
- #[rustc_dirty(label="hir_owner", cfg="cfail2")]
- #[rustc_clean(label="hir_owner", cfg="cfail3")]
+ #[rustc_clean(except="hir_owner,hir_owner_nodes,predicates_of", cfg="cfail2")]
+ #[rustc_clean(cfg="cfail3")]
fn method<T: Sized>();
}
}
#[cfg(not(cfail1))]
-#[rustc_clean(label="hir_owner", cfg="cfail2")]
-#[rustc_clean(label="hir_owner", cfg="cfail3")]
+#[rustc_clean(cfg="cfail2")]
+#[rustc_clean(cfg="cfail3")]
trait TraitAddLifetimeBoundToMethodLifetimeParameter {
- #[rustc_dirty(label="hir_owner", cfg="cfail2")]
- #[rustc_clean(label="hir_owner", cfg="cfail3")]
+ #[rustc_clean(
+ except="hir_owner,hir_owner_nodes,generics_of,predicates_of,fn_sig,type_of",
+ cfg="cfail2",
+ )]
+ #[rustc_clean(cfg="cfail3")]
fn method<'a, 'b: 'a>(a: &'a u32, b: &'b u32);
}
}
#[cfg(not(cfail1))]
-#[rustc_clean(label="hir_owner", cfg="cfail2")]
-#[rustc_clean(label="hir_owner", cfg="cfail3")]
+#[rustc_clean(cfg="cfail2")]
+#[rustc_clean(cfg="cfail3")]
trait TraitAddSecondTraitBoundToMethodTypeParameter {
- #[rustc_dirty(label="hir_owner", cfg="cfail2")]
- #[rustc_clean(label="hir_owner", cfg="cfail3")]
+ #[rustc_clean(except="hir_owner,hir_owner_nodes,predicates_of", cfg="cfail2")]
+ #[rustc_clean(cfg="cfail3")]
fn method<T: ReferencedTrait0 + ReferencedTrait1>();
}
}
#[cfg(not(cfail1))]
-#[rustc_clean(label="hir_owner", cfg="cfail2")]
-#[rustc_clean(label="hir_owner", cfg="cfail3")]
+#[rustc_clean(cfg="cfail2")]
+#[rustc_clean(cfg="cfail3")]
trait TraitAddSecondBuiltinBoundToMethodTypeParameter {
- #[rustc_dirty(label="hir_owner", cfg="cfail2")]
- #[rustc_clean(label="hir_owner", cfg="cfail3")]
+ #[rustc_clean(except="hir_owner,hir_owner_nodes,predicates_of", cfg="cfail2")]
+ #[rustc_clean(cfg="cfail3")]
fn method<T: Sized + Sync>();
}
}
#[cfg(not(cfail1))]
-#[rustc_clean(label="hir_owner", cfg="cfail2")]
-#[rustc_clean(label="hir_owner", cfg="cfail3")]
+#[rustc_clean(cfg="cfail2")]
+#[rustc_clean(cfg="cfail3")]
trait TraitAddSecondLifetimeBoundToMethodLifetimeParameter {
- #[rustc_dirty(label="hir_owner", cfg="cfail2")]
- #[rustc_clean(label="hir_owner", cfg="cfail3")]
+ #[rustc_clean(
+ except="hir_owner,hir_owner_nodes,generics_of,predicates_of,fn_sig,type_of",
+ cfg="cfail2",
+ )]
+ #[rustc_clean(cfg="cfail3")]
fn method<'a, 'b, 'c: 'a + 'b>(a: &'a u32, b: &'b u32, c: &'c u32);
}
#[cfg(cfail1)]
trait TraitAddAssociatedType {
- #[rustc_dirty(label="hir_owner", cfg="cfail2")]
- #[rustc_clean(label="hir_owner", cfg="cfail3")]
+ #[rustc_clean(except="hir_owner", cfg="cfail2")]
+ #[rustc_clean(cfg="cfail3")]
fn method();
}
#[cfg(not(cfail1))]
-#[rustc_dirty(label="hir_owner", cfg="cfail2")]
-#[rustc_clean(label="hir_owner", cfg="cfail3")]
+#[rustc_clean(except="hir_owner,associated_item_def_ids", cfg="cfail2")]
+#[rustc_clean(cfg="cfail3")]
trait TraitAddAssociatedType {
type Associated;
// Apparently the type bound contributes to the predicates of the trait, but
// does not change the associated item itself.
#[cfg(not(cfail1))]
-#[rustc_clean(label="hir_owner", cfg="cfail2")]
-#[rustc_clean(label="hir_owner", cfg="cfail3")]
+#[rustc_clean(cfg="cfail2")]
+#[rustc_clean(cfg="cfail3")]
trait TraitAddTraitBoundToAssociatedType {
- #[rustc_dirty(label="hir_owner", cfg="cfail2")]
- #[rustc_clean(label="hir_owner", cfg="cfail3")]
+ #[rustc_clean(except="hir_owner", cfg="cfail2")]
+ #[rustc_clean(cfg="cfail3")]
type Associated: ReferencedTrait0;
fn method();
}
#[cfg(not(cfail1))]
-#[rustc_clean(label="hir_owner", cfg="cfail2")]
-#[rustc_clean(label="hir_owner", cfg="cfail3")]
+#[rustc_clean(cfg="cfail2")]
+#[rustc_clean(cfg="cfail3")]
trait TraitAddLifetimeBoundToAssociatedType<'a> {
- #[rustc_dirty(label="hir_owner", cfg="cfail2")]
- #[rustc_clean(label="hir_owner", cfg="cfail3")]
+ #[rustc_clean(except="hir_owner", cfg="cfail2")]
+ #[rustc_clean(cfg="cfail3")]
type Associated: 'a;
fn method();
}
#[cfg(not(cfail1))]
-#[rustc_dirty(label="hir_owner", cfg="cfail2")]
-#[rustc_clean(label="hir_owner", cfg="cfail3")]
+#[rustc_clean(except="hir_owner", cfg="cfail2")]
+#[rustc_clean(cfg="cfail3")]
trait TraitAddDefaultToAssociatedType {
- #[rustc_dirty(label="hir_owner", cfg="cfail2")]
- #[rustc_clean(label="hir_owner", cfg="cfail3")]
+ #[rustc_clean(except="hir_owner,associated_item", cfg="cfail2")]
+ #[rustc_clean(cfg="cfail3")]
type Associated = ReferenceType0;
fn method();
}
#[cfg(not(cfail1))]
-#[rustc_dirty(label="hir_owner", cfg="cfail2")]
-#[rustc_clean(label="hir_owner", cfg="cfail3")]
+#[rustc_clean(except="hir_owner,associated_item_def_ids", cfg="cfail2")]
+#[rustc_clean(cfg="cfail3")]
trait TraitAddAssociatedConstant {
const Value: u32;
}
#[cfg(not(cfail1))]
-#[rustc_dirty(label="hir_owner", cfg="cfail2")]
-#[rustc_clean(label="hir_owner", cfg="cfail3")]
+#[rustc_clean(except="hir_owner", cfg="cfail2")]
+#[rustc_clean(cfg="cfail3")]
trait TraitAddInitializerToAssociatedConstant {
- #[rustc_dirty(label="hir_owner", cfg="cfail2")]
- #[rustc_clean(label="hir_owner", cfg="cfail3")]
+ #[rustc_clean(except="hir_owner,associated_item", cfg="cfail2")]
+ #[rustc_clean(cfg="cfail3")]
const Value: u32 = 1;
- #[rustc_clean(label="hir_owner", cfg="cfail2")]
- #[rustc_clean(label="hir_owner", cfg="cfail3")]
+ #[rustc_clean(cfg="cfail2")]
+ #[rustc_clean(cfg="cfail3")]
fn method();
}
}
#[cfg(not(cfail1))]
-#[rustc_clean(label="hir_owner", cfg="cfail2")]
-#[rustc_clean(label="hir_owner", cfg="cfail3")]
+#[rustc_clean(cfg="cfail2")]
+#[rustc_clean(cfg="cfail3")]
trait TraitChangeTypeOfAssociatedConstant {
- #[rustc_dirty(label="hir_owner", cfg="cfail2")]
- #[rustc_clean(label="hir_owner", cfg="cfail3")]
+ #[rustc_clean(except="hir_owner,type_of", cfg="cfail2")]
+ #[rustc_clean(cfg="cfail3")]
const Value: f64;
- #[rustc_clean(label="hir_owner", cfg="cfail2")]
- #[rustc_clean(label="hir_owner", cfg="cfail3")]
+ #[rustc_clean(cfg="cfail2")]
+ #[rustc_clean(cfg="cfail3")]
fn method();
}
trait TraitAddSuperTrait { }
#[cfg(not(cfail1))]
-#[rustc_dirty(label="hir_owner", cfg="cfail2")]
-#[rustc_clean(label="hir_owner", cfg="cfail3")]
+#[rustc_clean(except="hir_owner,predicates_of", cfg="cfail2")]
+#[rustc_clean(cfg="cfail3")]
trait TraitAddSuperTrait : ReferencedTrait0 { }
trait TraitAddBuiltiBound { }
#[cfg(not(cfail1))]
-#[rustc_dirty(label="hir_owner", cfg="cfail2")]
-#[rustc_clean(label="hir_owner", cfg="cfail3")]
+#[rustc_clean(except="hir_owner,predicates_of", cfg="cfail2")]
+#[rustc_clean(cfg="cfail3")]
trait TraitAddBuiltiBound : Send { }
trait TraitAddStaticLifetimeBound { }
#[cfg(not(cfail1))]
-#[rustc_dirty(label="hir_owner", cfg="cfail2")]
-#[rustc_clean(label="hir_owner", cfg="cfail3")]
+#[rustc_clean(except="hir_owner,predicates_of", cfg="cfail2")]
+#[rustc_clean(cfg="cfail3")]
trait TraitAddStaticLifetimeBound : 'static { }
trait TraitAddTraitAsSecondBound : ReferencedTrait0 { }
#[cfg(not(cfail1))]
-#[rustc_dirty(label="hir_owner", cfg="cfail2")]
-#[rustc_clean(label="hir_owner", cfg="cfail3")]
+#[rustc_clean(except="hir_owner,predicates_of", cfg="cfail2")]
+#[rustc_clean(cfg="cfail3")]
trait TraitAddTraitAsSecondBound : ReferencedTrait0 + ReferencedTrait1 { }
#[cfg(cfail1)]
trait TraitAddTraitAsSecondBoundFromBuiltin : Send { }
#[cfg(not(cfail1))]
-#[rustc_dirty(label="hir_owner", cfg="cfail2")]
-#[rustc_clean(label="hir_owner", cfg="cfail3")]
+#[rustc_clean(except="hir_owner,predicates_of", cfg="cfail2")]
+#[rustc_clean(cfg="cfail3")]
trait TraitAddTraitAsSecondBoundFromBuiltin : Send + ReferencedTrait0 { }
trait TraitAddBuiltinBoundAsSecondBound : ReferencedTrait0 { }
#[cfg(not(cfail1))]
-#[rustc_dirty(label="hir_owner", cfg="cfail2")]
-#[rustc_clean(label="hir_owner", cfg="cfail3")]
+#[rustc_clean(except="hir_owner,predicates_of", cfg="cfail2")]
+#[rustc_clean(cfg="cfail3")]
trait TraitAddBuiltinBoundAsSecondBound : ReferencedTrait0 + Send { }
#[cfg(cfail1)]
trait TraitAddBuiltinBoundAsSecondBoundFromBuiltin : Send { }
#[cfg(not(cfail1))]
-#[rustc_dirty(label="hir_owner", cfg="cfail2")]
-#[rustc_clean(label="hir_owner", cfg="cfail3")]
+#[rustc_clean(except="hir_owner,predicates_of", cfg="cfail2")]
+#[rustc_clean(cfg="cfail3")]
trait TraitAddBuiltinBoundAsSecondBoundFromBuiltin: Send + Copy { }
trait TraitAddStaticBoundAsSecondBound : ReferencedTrait0 { }
#[cfg(not(cfail1))]
-#[rustc_dirty(label="hir_owner", cfg="cfail2")]
-#[rustc_clean(label="hir_owner", cfg="cfail3")]
+#[rustc_clean(except="hir_owner,predicates_of", cfg="cfail2")]
+#[rustc_clean(cfg="cfail3")]
trait TraitAddStaticBoundAsSecondBound : ReferencedTrait0 + 'static { }
#[cfg(cfail1)]
trait TraitAddStaticBoundAsSecondBoundFromBuiltin : Send { }
#[cfg(not(cfail1))]
-#[rustc_dirty(label="hir_owner", cfg="cfail2")]
-#[rustc_clean(label="hir_owner", cfg="cfail3")]
+#[rustc_clean(except="hir_owner,predicates_of", cfg="cfail2")]
+#[rustc_clean(cfg="cfail3")]
trait TraitAddStaticBoundAsSecondBoundFromBuiltin : Send + 'static { }
trait TraitAddTypeParameterToTrait { }
#[cfg(not(cfail1))]
-#[rustc_dirty(label="hir_owner", cfg="cfail2")]
-#[rustc_clean(label="hir_owner", cfg="cfail3")]
+#[rustc_clean(except="hir_owner,generics_of,predicates_of", cfg="cfail2")]
+#[rustc_clean(cfg="cfail3")]
trait TraitAddTypeParameterToTrait<T> { }
trait TraitAddLifetimeParameterToTrait { }
#[cfg(not(cfail1))]
-#[rustc_dirty(label="hir_owner", cfg="cfail2")]
-#[rustc_clean(label="hir_owner", cfg="cfail3")]
+#[rustc_clean(except="hir_owner,generics_of,predicates_of", cfg="cfail2")]
+#[rustc_clean(cfg="cfail3")]
trait TraitAddLifetimeParameterToTrait<'a> { }
trait TraitAddTraitBoundToTypeParameterOfTrait<T> { }
#[cfg(not(cfail1))]
-#[rustc_dirty(label="hir_owner", cfg="cfail2")]
-#[rustc_clean(label="hir_owner", cfg="cfail3")]
+#[rustc_clean(except="hir_owner,hir_owner_nodes,predicates_of", cfg="cfail2")]
+#[rustc_clean(cfg="cfail3")]
trait TraitAddTraitBoundToTypeParameterOfTrait<T: ReferencedTrait0> { }
trait TraitAddLifetimeBoundToTypeParameterOfTrait<'a, T> { }
#[cfg(not(cfail1))]
-#[rustc_dirty(label="hir_owner", cfg="cfail2")]
-#[rustc_clean(label="hir_owner", cfg="cfail3")]
+#[rustc_clean(except="hir_owner,hir_owner_nodes,generics_of,predicates_of", cfg="cfail2")]
+#[rustc_clean(cfg="cfail3")]
trait TraitAddLifetimeBoundToTypeParameterOfTrait<'a, T: 'a> { }
trait TraitAddLifetimeBoundToLifetimeParameterOfTrait<'a, 'b> { }
#[cfg(not(cfail1))]
-#[rustc_dirty(label="hir_owner", cfg="cfail2")]
-#[rustc_clean(label="hir_owner", cfg="cfail3")]
+#[rustc_clean(except="hir_owner,hir_owner_nodes,predicates_of", cfg="cfail2")]
+#[rustc_clean(cfg="cfail3")]
trait TraitAddLifetimeBoundToLifetimeParameterOfTrait<'a: 'b, 'b> { }
trait TraitAddBuiltinBoundToTypeParameterOfTrait<T> { }
#[cfg(not(cfail1))]
-#[rustc_dirty(label="hir_owner", cfg="cfail2")]
-#[rustc_clean(label="hir_owner", cfg="cfail3")]
+#[rustc_clean(except="hir_owner,hir_owner_nodes,predicates_of", cfg="cfail2")]
+#[rustc_clean(cfg="cfail3")]
trait TraitAddBuiltinBoundToTypeParameterOfTrait<T: Send> { }
trait TraitAddSecondTypeParameterToTrait<T> { }
#[cfg(not(cfail1))]
-#[rustc_dirty(label="hir_owner", cfg="cfail2")]
-#[rustc_clean(label="hir_owner", cfg="cfail3")]
+#[rustc_clean(except="hir_owner,hir_owner_nodes,generics_of,predicates_of", cfg="cfail2")]
+#[rustc_clean(cfg="cfail3")]
trait TraitAddSecondTypeParameterToTrait<T, S> { }
trait TraitAddSecondLifetimeParameterToTrait<'a> { }
#[cfg(not(cfail1))]
-#[rustc_dirty(label="hir_owner", cfg="cfail2")]
-#[rustc_clean(label="hir_owner", cfg="cfail3")]
+#[rustc_clean(except="hir_owner,hir_owner_nodes,generics_of,predicates_of", cfg="cfail2")]
+#[rustc_clean(cfg="cfail3")]
trait TraitAddSecondLifetimeParameterToTrait<'a, 'b> { }
trait TraitAddSecondTraitBoundToTypeParameterOfTrait<T: ReferencedTrait0> { }
#[cfg(not(cfail1))]
-#[rustc_dirty(label="hir_owner", cfg="cfail2")]
-#[rustc_clean(label="hir_owner", cfg="cfail3")]
+#[rustc_clean(except="hir_owner,hir_owner_nodes,predicates_of", cfg="cfail2")]
+#[rustc_clean(cfg="cfail3")]
trait TraitAddSecondTraitBoundToTypeParameterOfTrait<T: ReferencedTrait0 + ReferencedTrait1> { }
trait TraitAddSecondLifetimeBoundToTypeParameterOfTrait<'a, 'b, T: 'a> { }
#[cfg(not(cfail1))]
-#[rustc_dirty(label="hir_owner", cfg="cfail2")]
-#[rustc_clean(label="hir_owner", cfg="cfail3")]
+#[rustc_clean(except="hir_owner,hir_owner_nodes,generics_of,predicates_of", cfg="cfail2")]
+#[rustc_clean(cfg="cfail3")]
trait TraitAddSecondLifetimeBoundToTypeParameterOfTrait<'a, 'b, T: 'a + 'b> { }
trait TraitAddSecondLifetimeBoundToLifetimeParameterOfTrait<'a: 'b, 'b, 'c> { }
#[cfg(not(cfail1))]
-#[rustc_dirty(label="hir_owner", cfg="cfail2")]
-#[rustc_clean(label="hir_owner", cfg="cfail3")]
+#[rustc_clean(except="hir_owner,hir_owner_nodes,predicates_of", cfg="cfail2")]
+#[rustc_clean(cfg="cfail3")]
trait TraitAddSecondLifetimeBoundToLifetimeParameterOfTrait<'a: 'b + 'c, 'b, 'c> { }
trait TraitAddSecondBuiltinBoundToTypeParameterOfTrait<T: Send> { }
#[cfg(not(cfail1))]
-#[rustc_dirty(label="hir_owner", cfg="cfail2")]
-#[rustc_clean(label="hir_owner", cfg="cfail3")]
+#[rustc_clean(except="hir_owner,hir_owner_nodes,predicates_of", cfg="cfail2")]
+#[rustc_clean(cfg="cfail3")]
trait TraitAddSecondBuiltinBoundToTypeParameterOfTrait<T: Send + Sync> { }
trait TraitAddTraitBoundToTypeParameterOfTraitWhere<T> { }
#[cfg(not(cfail1))]
-#[rustc_dirty(label="hir_owner", cfg="cfail2")]
-#[rustc_clean(label="hir_owner", cfg="cfail3")]
+#[rustc_clean(except="hir_owner,hir_owner_nodes,predicates_of", cfg="cfail2")]
+#[rustc_clean(cfg="cfail3")]
trait TraitAddTraitBoundToTypeParameterOfTraitWhere<T> where T: ReferencedTrait0 { }
trait TraitAddLifetimeBoundToTypeParameterOfTraitWhere<'a, T> { }
#[cfg(not(cfail1))]
-#[rustc_dirty(label="hir_owner", cfg="cfail2")]
-#[rustc_clean(label="hir_owner", cfg="cfail3")]
+#[rustc_clean(except="hir_owner,hir_owner_nodes,generics_of,predicates_of", cfg="cfail2")]
+#[rustc_clean(cfg="cfail3")]
trait TraitAddLifetimeBoundToTypeParameterOfTraitWhere<'a, T> where T: 'a { }
trait TraitAddLifetimeBoundToLifetimeParameterOfTraitWhere<'a, 'b> { }
#[cfg(not(cfail1))]
-#[rustc_dirty(label="hir_owner", cfg="cfail2")]
-#[rustc_clean(label="hir_owner", cfg="cfail3")]
+#[rustc_clean(except="hir_owner,hir_owner_nodes,predicates_of", cfg="cfail2")]
+#[rustc_clean(cfg="cfail3")]
trait TraitAddLifetimeBoundToLifetimeParameterOfTraitWhere<'a, 'b> where 'a: 'b { }
trait TraitAddBuiltinBoundToTypeParameterOfTraitWhere<T> { }
#[cfg(not(cfail1))]
-#[rustc_dirty(label="hir_owner", cfg="cfail2")]
-#[rustc_clean(label="hir_owner", cfg="cfail3")]
+#[rustc_clean(except="hir_owner,hir_owner_nodes,predicates_of", cfg="cfail2")]
+#[rustc_clean(cfg="cfail3")]
trait TraitAddBuiltinBoundToTypeParameterOfTraitWhere<T> where T: Send { }
trait TraitAddSecondTraitBoundToTypeParameterOfTraitWhere<T> where T: ReferencedTrait0 { }
#[cfg(not(cfail1))]
-#[rustc_dirty(label="hir_owner", cfg="cfail2")]
-#[rustc_clean(label="hir_owner", cfg="cfail3")]
+#[rustc_clean(except="hir_owner,hir_owner_nodes,predicates_of", cfg="cfail2")]
+#[rustc_clean(cfg="cfail3")]
trait TraitAddSecondTraitBoundToTypeParameterOfTraitWhere<T>
where T: ReferencedTrait0 + ReferencedTrait1 { }
trait TraitAddSecondLifetimeBoundToTypeParameterOfTraitWhere<'a, 'b, T> where T: 'a { }
#[cfg(not(cfail1))]
-#[rustc_dirty(label="hir_owner", cfg="cfail2")]
-#[rustc_clean(label="hir_owner", cfg="cfail3")]
+#[rustc_clean(except="hir_owner,hir_owner_nodes,generics_of,predicates_of", cfg="cfail2")]
+#[rustc_clean(cfg="cfail3")]
trait TraitAddSecondLifetimeBoundToTypeParameterOfTraitWhere<'a, 'b, T> where T: 'a + 'b { }
trait TraitAddSecondLifetimeBoundToLifetimeParameterOfTraitWhere<'a, 'b, 'c> where 'a: 'b { }
#[cfg(not(cfail1))]
-#[rustc_dirty(label="hir_owner", cfg="cfail2")]
-#[rustc_clean(label="hir_owner", cfg="cfail3")]
+#[rustc_clean(except="hir_owner,hir_owner_nodes,predicates_of", cfg="cfail2")]
+#[rustc_clean(cfg="cfail3")]
trait TraitAddSecondLifetimeBoundToLifetimeParameterOfTraitWhere<'a, 'b, 'c> where 'a: 'b + 'c { }
trait TraitAddSecondBuiltinBoundToTypeParameterOfTraitWhere<T> where T: Send { }
#[cfg(not(cfail1))]
-#[rustc_dirty(label="hir_owner", cfg="cfail2")]
-#[rustc_clean(label="hir_owner", cfg="cfail3")]
+#[rustc_clean(except="hir_owner,hir_owner_nodes,predicates_of", cfg="cfail2")]
+#[rustc_clean(cfg="cfail3")]
trait TraitAddSecondBuiltinBoundToTypeParameterOfTraitWhere<T> where T: Send + Sync { }
#[cfg(not(cfail1))]
use super::ReferenceType1 as ReturnType;
- #[rustc_clean(label="hir_owner", cfg="cfail2")]
- #[rustc_clean(label="hir_owner", cfg="cfail3")]
+ #[rustc_clean(cfg="cfail2")]
+ #[rustc_clean(cfg="cfail3")]
trait TraitChangeReturnType {
- #[rustc_dirty(label="hir_owner", cfg="cfail2")]
- #[rustc_clean(label="hir_owner", cfg="cfail3")]
+ #[rustc_clean(except="hir_owner,hir_owner_nodes,fn_sig", cfg="cfail2")]
+ #[rustc_clean(cfg="cfail3")]
fn method() -> ReturnType;
}
}
#[cfg(not(cfail1))]
use super::ReferenceType1 as ArgType;
- #[rustc_clean(label="hir_owner", cfg="cfail2")]
- #[rustc_clean(label="hir_owner", cfg="cfail3")]
+ #[rustc_clean(cfg="cfail2")]
+ #[rustc_clean(cfg="cfail3")]
trait TraitChangeArgType {
- #[rustc_dirty(label="hir_owner", cfg="cfail2")]
- #[rustc_clean(label="hir_owner", cfg="cfail3")]
+ #[rustc_clean(except="hir_owner,fn_sig", cfg="cfail2")]
+ #[rustc_clean(cfg="cfail3")]
fn method(a: ArgType);
}
}
#[cfg(not(cfail1))]
use super::ReferencedTrait1 as Bound;
- #[rustc_clean(label="hir_owner", cfg="cfail2")]
- #[rustc_clean(label="hir_owner", cfg="cfail3")]
+ #[rustc_clean(cfg="cfail2")]
+ #[rustc_clean(cfg="cfail3")]
trait TraitChangeBoundOfMethodTypeParameter {
- #[rustc_dirty(label="hir_owner", cfg="cfail2")]
- #[rustc_clean(label="hir_owner", cfg="cfail3")]
+ #[rustc_clean(except="hir_owner,hir_owner_nodes,predicates_of", cfg="cfail2")]
+ #[rustc_clean(cfg="cfail3")]
fn method<T: Bound>(a: T);
}
}
#[cfg(not(cfail1))]
use super::ReferencedTrait1 as Bound;
- #[rustc_clean(label="hir_owner", cfg="cfail2")]
- #[rustc_clean(label="hir_owner", cfg="cfail3")]
+ #[rustc_clean(cfg="cfail2")]
+ #[rustc_clean(cfg="cfail3")]
trait TraitChangeBoundOfMethodTypeParameterWhere {
- #[rustc_dirty(label="hir_owner", cfg="cfail2")]
- #[rustc_clean(label="hir_owner", cfg="cfail3")]
+ #[rustc_clean(except="hir_owner,hir_owner_nodes,predicates_of", cfg="cfail2")]
+ #[rustc_clean(cfg="cfail3")]
fn method<T>(a: T) where T: Bound;
}
}
#[cfg(not(cfail1))]
use super::ReferencedTrait1 as Bound;
- #[rustc_dirty(label="hir_owner", cfg="cfail2")]
- #[rustc_clean(label="hir_owner", cfg="cfail3")]
+ #[rustc_clean(except="hir_owner,hir_owner_nodes,predicates_of", cfg="cfail2")]
+ #[rustc_clean(cfg="cfail3")]
trait TraitChangeTraitBound<T: Bound> {
fn method(a: T);
}
#[cfg(not(cfail1))]
use super::ReferencedTrait1 as Bound;
- #[rustc_dirty(label="hir_owner", cfg="cfail2")]
- #[rustc_clean(label="hir_owner", cfg="cfail3")]
+ #[rustc_clean(except="hir_owner,hir_owner_nodes,predicates_of", cfg="cfail2")]
+ #[rustc_clean(cfg="cfail3")]
trait TraitChangeTraitBoundWhere<T> where T: Bound {
fn method(a: T);
}
}
#[cfg(not(cfail1))]
-#[rustc_dirty(label="hir_owner", cfg="cfail2")]
-#[rustc_clean(label="hir_owner", cfg="cfail3")]
+#[rustc_clean(except="hir_owner,associated_item_def_ids", cfg="cfail2")]
+#[rustc_clean(cfg="cfail3")]
pub trait ChangeMethodNameTrait {
- #[rustc_clean(label="hir_owner", cfg="cfail3")]
+ #[rustc_clean(cfg="cfail3")]
fn method_name2();
}
#[cfg(not(cfail1))]
-#[rustc_dirty(label="hir_owner", cfg="cfail2")]
-#[rustc_clean(label="hir_owner", cfg="cfail3")]
+#[rustc_clean(except="hir_owner,associated_item_def_ids", cfg="cfail2")]
+#[rustc_clean(cfg="cfail3")]
impl ChangeMethodNameTrait for Foo {
- #[rustc_clean(label="hir_owner", cfg="cfail3")]
+ #[rustc_clean(cfg="cfail3")]
fn method_name2() { }
}
}
#[cfg(not(cfail1))]
-#[rustc_clean(label="hir_owner", cfg="cfail2")]
-#[rustc_clean(label="hir_owner", cfg="cfail3")]
+#[rustc_clean(cfg="cfail2")]
+#[rustc_clean(cfg="cfail3")]
impl ChangeMethodBodyTrait for Foo {
- #[rustc_clean(label="hir_owner", cfg="cfail2")]
- #[rustc_clean(label="hir_owner", cfg="cfail3")]
- #[rustc_dirty(label="hir_owner_nodes", cfg="cfail2")]
- #[rustc_clean(label="hir_owner_nodes", cfg="cfail3")]
+ #[rustc_clean(except="hir_owner_nodes,typeck,optimized_mir", cfg="cfail2")]
+ #[rustc_clean(cfg="cfail3")]
fn method_name() {
()
}
}
#[cfg(not(cfail1))]
-#[rustc_clean(label="hir_owner", cfg="cfail2")]
-#[rustc_clean(label="hir_owner", cfg="cfail3")]
+#[rustc_clean(cfg="cfail2")]
+#[rustc_clean(cfg="cfail3")]
impl ChangeMethodBodyTraitInlined for Foo {
- #[rustc_clean(label="hir_owner", cfg="cfail2")]
- #[rustc_clean(label="hir_owner", cfg="cfail3")]
- #[rustc_dirty(label="hir_owner_nodes", cfg="cfail2")]
- #[rustc_clean(label="hir_owner_nodes", cfg="cfail3")]
+ #[rustc_clean(except="hir_owner_nodes,typeck,optimized_mir", cfg="cfail2")]
+ #[rustc_clean(cfg="cfail3")]
#[inline]
fn method_name() {
panic!()
}
#[cfg(not(cfail1))]
-#[rustc_dirty(label="hir_owner", cfg="cfail2")]
-#[rustc_clean(label="hir_owner", cfg="cfail3")]
+#[rustc_clean(except="hir_owner", cfg="cfail2")]
+#[rustc_clean(cfg="cfail3")]
impl ChangeMethodSelfnessTrait for Foo {
- #[rustc_dirty(label="hir_owner", cfg="cfail2")]
- #[rustc_clean(label="hir_owner", cfg="cfail3")]
+ #[rustc_clean(
+ except="hir_owner,hir_owner_nodes,associated_item,generics_of,fn_sig,typeck,optimized_mir",
+ cfg="cfail2",
+ )]
+ #[rustc_clean(cfg="cfail3")]
fn method_name(&self) {
()
}
}
#[cfg(not(cfail1))]
-#[rustc_dirty(label="hir_owner", cfg="cfail2")]
-#[rustc_clean(label="hir_owner", cfg="cfail3")]
+#[rustc_clean(except="hir_owner", cfg="cfail2")]
+#[rustc_clean(cfg="cfail3")]
impl RemoveMethodSelfnessTrait for Foo {
- #[rustc_dirty(label="hir_owner", cfg="cfail2")]
- #[rustc_clean(label="hir_owner", cfg="cfail3")]
+ #[rustc_clean(
+ except="hir_owner,hir_owner_nodes,associated_item,generics_of,fn_sig,typeck,optimized_mir",
+ cfg="cfail2",
+ )]
+ #[rustc_clean(cfg="cfail3")]
fn method_name() {}
}
}
#[cfg(not(cfail1))]
-#[rustc_clean(label="hir_owner", cfg="cfail2")]
-#[rustc_clean(label="hir_owner", cfg="cfail3")]
+#[rustc_clean(cfg="cfail2")]
+#[rustc_clean(cfg="cfail3")]
impl ChangeMethodSelfmutnessTrait for Foo {
- #[rustc_dirty(label="hir_owner", cfg="cfail2")]
- #[rustc_clean(label="hir_owner", cfg="cfail3")]
+ #[rustc_clean(except="hir_owner,hir_owner_nodes,fn_sig,typeck,optimized_mir", cfg="cfail2")]
+ #[rustc_clean(cfg="cfail3")]
fn method_name(&mut self) {}
}
}
#[cfg(not(cfail1))]
-#[rustc_dirty(label="hir_owner", cfg="cfail2")]
-#[rustc_clean(label="hir_owner", cfg="cfail3")]
+#[rustc_clean(except="hir_owner,associated_item_def_ids", cfg="cfail2")]
+#[rustc_clean(cfg="cfail3")]
impl ChangeItemKindTrait for Foo {
type name = ();
}
}
#[cfg(not(cfail1))]
-#[rustc_dirty(label="hir_owner", cfg="cfail2")]
-#[rustc_clean(label="hir_owner", cfg="cfail3")]
+#[rustc_clean(except="hir_owner,associated_item_def_ids", cfg="cfail2")]
+#[rustc_clean(cfg="cfail3")]
impl RemoveItemTrait for Foo {
type TypeName = ();
}
}
#[cfg(not(cfail1))]
-#[rustc_dirty(label="hir_owner", cfg="cfail2")]
-#[rustc_clean(label="hir_owner", cfg="cfail3")]
+#[rustc_clean(except="hir_owner,associated_item_def_ids", cfg="cfail2")]
+#[rustc_clean(cfg="cfail3")]
impl AddItemTrait for Foo {
type TypeName = ();
fn method_name() { }
}
#[cfg(not(cfail1))]
-#[rustc_dirty(label="hir_owner", cfg="cfail2")]
-#[rustc_clean(label="hir_owner", cfg="cfail3")]
+#[rustc_clean(except="hir_owner", cfg="cfail2")]
+#[rustc_clean(cfg="cfail3")]
pub trait ChangeHasValueTrait {
- #[rustc_dirty(label="hir_owner", cfg="cfail2")]
- #[rustc_clean(label="hir_owner", cfg="cfail3")]
+ #[rustc_clean(except="hir_owner,associated_item", cfg="cfail2")]
+ #[rustc_clean(cfg="cfail3")]
fn method_name() { }
}
#[cfg(not(cfail1))]
-#[rustc_clean(label="hir_owner", cfg="cfail2")]
-#[rustc_clean(label="hir_owner", cfg="cfail3")]
+#[rustc_clean(cfg="cfail2")]
+#[rustc_clean(cfg="cfail3")]
impl ChangeHasValueTrait for Foo {
fn method_name() { }
}
}
#[cfg(not(cfail1))]
-#[rustc_dirty(label="hir_owner", cfg="cfail2")]
-#[rustc_clean(label="hir_owner", cfg="cfail3")]
+#[rustc_clean(except="hir_owner", cfg="cfail2")]
+#[rustc_clean(cfg="cfail3")]
impl AddDefaultTrait for Foo {
- #[rustc_dirty(label="hir_owner", cfg="cfail2")]
- #[rustc_clean(label="hir_owner", cfg="cfail3")]
+ #[rustc_clean(except="hir_owner,hir_owner_nodes,associated_item", cfg="cfail2")]
+ #[rustc_clean(cfg="cfail3")]
default fn method_name() { }
}
}
#[cfg(not(cfail1))]
-#[rustc_clean(label="hir_owner", cfg="cfail2")]
-#[rustc_clean(label="hir_owner", cfg="cfail3")]
+#[rustc_clean(cfg="cfail2")]
+#[rustc_clean(cfg="cfail3")]
impl AddArgumentTrait for Foo {
- #[rustc_dirty(label="hir_owner", cfg="cfail2")]
- #[rustc_clean(label="hir_owner", cfg="cfail3")]
+ #[rustc_clean(except="hir_owner,hir_owner_nodes,fn_sig,typeck,optimized_mir", cfg="cfail2")]
+ #[rustc_clean(cfg="cfail3")]
fn method_name(&self, _x: u32) { }
}
}
#[cfg(not(cfail1))]
-#[rustc_clean(label="hir_owner", cfg="cfail2")]
-#[rustc_clean(label="hir_owner", cfg="cfail3")]
+#[rustc_clean(cfg="cfail2")]
+#[rustc_clean(cfg="cfail3")]
impl ChangeArgumentTypeTrait for Foo {
- #[rustc_dirty(label="hir_owner", cfg="cfail2")]
- #[rustc_clean(label="hir_owner", cfg="cfail3")]
+ #[rustc_clean(except="hir_owner,hir_owner_nodes,fn_sig,typeck,optimized_mir", cfg="cfail2")]
+ #[rustc_clean(cfg="cfail3")]
fn method_name(&self, _x: char) { }
}
}
#[cfg(not(cfail1))]
-#[rustc_dirty(label="hir_owner", cfg="cfail2")]
-#[rustc_clean(label="hir_owner", cfg="cfail3")]
+#[rustc_clean(except="hir_owner,generics_of,impl_trait_ref", cfg="cfail2")]
+#[rustc_clean(cfg="cfail3")]
impl<T> AddTypeParameterToImpl<T> for Bar<T> {
- #[rustc_dirty(label="hir_owner", cfg="cfail2")]
- #[rustc_clean(label="hir_owner", cfg="cfail3")]
+ #[rustc_clean(
+ except="hir_owner,hir_owner_nodes,generics_of,fn_sig,type_of,typeck,optimized_mir",
+ cfg="cfail2",
+ )]
+ #[rustc_clean(cfg="cfail3")]
fn id(t: T) -> T { t }
}
}
#[cfg(not(cfail1))]
-#[rustc_dirty(label="hir_owner", cfg="cfail2")]
-#[rustc_clean(label="hir_owner", cfg="cfail3")]
+#[rustc_clean(except="hir_owner,impl_trait_ref", cfg="cfail2")]
+#[rustc_clean(cfg="cfail3")]
impl ChangeSelfTypeOfImpl for u64 {
- #[rustc_clean(label="hir_owner", cfg="cfail2")]
- #[rustc_clean(label="hir_owner", cfg="cfail3")]
+ #[rustc_clean(except="fn_sig,typeck,optimized_mir", cfg="cfail2")]
+ #[rustc_clean(cfg="cfail3")]
fn id(self) -> Self { self }
}
}
#[cfg(not(cfail1))]
-#[rustc_dirty(label="hir_owner", cfg="cfail2")]
-#[rustc_clean(label="hir_owner", cfg="cfail3")]
+#[rustc_clean(except="hir_owner,hir_owner_nodes", cfg="cfail2")]
+#[rustc_clean(cfg="cfail3")]
impl<T: 'static> AddLifetimeBoundToImplParameter for T {
- #[rustc_clean(label="hir_owner", cfg="cfail2")]
- #[rustc_clean(label="hir_owner", cfg="cfail3")]
+ #[rustc_clean(cfg="cfail2")]
+ #[rustc_clean(cfg="cfail3")]
fn id(self) -> Self { self }
}
}
#[cfg(not(cfail1))]
-#[rustc_dirty(label="hir_owner", cfg="cfail2")]
-#[rustc_clean(label="hir_owner", cfg="cfail3")]
+#[rustc_clean(except="hir_owner,hir_owner_nodes", cfg="cfail2")]
+#[rustc_clean(cfg="cfail3")]
impl<T: Clone> AddTraitBoundToImplParameter for T {
- #[rustc_clean(label="hir_owner", cfg="cfail2")]
- #[rustc_clean(label="hir_owner", cfg="cfail3")]
+ #[rustc_clean(cfg="cfail2")]
+ #[rustc_clean(cfg="cfail3")]
fn id(self) -> Self { self }
}
}
#[cfg(not(cfail1))]
-#[rustc_clean(label="hir_owner", cfg="cfail2")]
-#[rustc_clean(label="hir_owner", cfg="cfail3")]
+#[rustc_clean(cfg="cfail2")]
+#[rustc_clean(cfg="cfail3")]
impl AddNoMangleToMethod for Foo {
- #[rustc_clean(label="hir_owner", cfg="cfail2")]
- #[rustc_clean(label="hir_owner", cfg="cfail3")]
+ #[rustc_clean(cfg="cfail2")]
+ #[rustc_clean(cfg="cfail3")]
#[no_mangle]
fn add_no_mangle_to_method(&self) { }
}
}
#[cfg(not(cfail1))]
-#[rustc_clean(label="hir_owner", cfg="cfail2")]
-#[rustc_clean(label="hir_owner", cfg="cfail3")]
+#[rustc_clean(cfg="cfail2")]
+#[rustc_clean(cfg="cfail3")]
impl MakeMethodInline for Foo {
- #[rustc_clean(label="hir_owner", cfg="cfail2")]
- #[rustc_clean(label="hir_owner", cfg="cfail3")]
+ #[rustc_clean(cfg="cfail2")]
+ #[rustc_clean(cfg="cfail3")]
#[inline]
fn make_method_inline(&self) -> u8 { 0 }
}
mod y {
use x;
- #[rustc_clean(label="typeck", cfg="rpass2")]
+ #[rustc_clean(cfg="rpass2")]
pub fn yyyy() {
x::xxxx();
}
mod z {
use y;
- #[rustc_clean(label="typeck", cfg="rpass2")]
+ #[rustc_clean(cfg="rpass2")]
pub fn z() {
y::yyyy();
}
}
}
-#[rustc_dirty(label="typeck", cfg="rpass2")]
+#[rustc_clean(except="hir_owner_nodes,typeck,optimized_mir,promoted_mir", cfg="rpass2")]
#[inline(always)]
pub fn changed_fn() {
// This will cause additional hygiene to be generate,
#[cfg(rpass2)]
use Trait2;
- #[rustc_clean(label="hir_owner", cfg="rpass2")]
- #[rustc_clean(label="hir_owner_nodes", cfg="rpass2")]
- #[rustc_dirty(label="typeck", cfg="rpass2")]
+ #[rustc_clean(except="typeck", cfg="rpass2")]
fn bar() {
().method();
}
- #[rustc_clean(label="hir_owner", cfg="rpass2")]
- #[rustc_clean(label="hir_owner_nodes", cfg="rpass2")]
- #[rustc_clean(label="typeck", cfg="rpass2")]
+ #[rustc_clean(cfg="rpass2")]
fn baz() {
22; // no method call, traits in scope don't matter
}
#![crate_type = "rlib"]
#![feature(rustc_attrs)]
-#[rustc_clean(label = "hir_owner", cfg = "cfail2")]
-#[rustc_dirty(label = "hir_owner_nodes", cfg = "cfail2")]
+#[rustc_clean(except = "hir_owner_nodes", cfg = "cfail2")]
pub fn foo() {
#[cfg(cfail1)]
pub fn baz() {} // order is different...
- #[rustc_clean(label = "hir_owner", cfg = "cfail2")]
- #[rustc_clean(label = "hir_owner_nodes", cfg = "cfail2")]
+ #[rustc_clean(cfg = "cfail2")]
pub fn bar() {} // but that doesn't matter.
#[cfg(cfail2)]
#[cfg(rpass3)]
use mod2::Foo;
- #[rustc_clean(label="hir_owner", cfg="rpass2")]
- #[rustc_clean(label="hir_owner_nodes", cfg="rpass2")]
- #[rustc_clean(label="hir_owner", cfg="rpass3")]
- #[rustc_dirty(label="hir_owner_nodes", cfg="rpass3")]
+ #[rustc_clean(cfg="rpass2")]
+ #[rustc_clean(except="hir_owner_nodes,typeck", cfg="rpass3")]
fn in_expr() {
Foo(0);
}
- #[rustc_clean(label="hir_owner", cfg="rpass2")]
- #[rustc_clean(label="hir_owner_nodes", cfg="rpass2")]
- #[rustc_clean(label="hir_owner", cfg="rpass3")]
- #[rustc_dirty(label="hir_owner_nodes", cfg="rpass3")]
+ #[rustc_clean(cfg="rpass2")]
+ #[rustc_clean(except="hir_owner_nodes,typeck", cfg="rpass3")]
fn in_type() {
test::<Foo>();
}
--- /dev/null
+// no-prefer-dynamic
+//[cfail1] compile-flags: -lbar -lfoo --crate-type lib
+//[cfail2] compile-flags: -lfoo -lbar --crate-type lib
--- /dev/null
+// aux-build:my_lib.rs
+// error-pattern: error: linking with
+// revisions:cfail1 cfail2
+// compile-flags:-Z query-dep-graph
+
+// Tests that re-ordering the `-l` arguments used
+// when compiling an external dependency does not lead to
+// an 'unstable fingerprint' error.
+
+extern crate my_lib;
+
+fn main() {}
extern crate a;
-#[rustc_dirty(label="typeck", cfg="rpass2")]
-#[rustc_clean(label="typeck", cfg="rpass3")]
+#[rustc_clean(except="typeck,optimized_mir", cfg="rpass2")]
+#[rustc_clean(cfg="rpass3")]
pub fn use_X() -> u32 {
let x: a::X = 22;
x as u32
}
-#[rustc_clean(label="typeck", cfg="rpass2")]
-#[rustc_clean(label="typeck", cfg="rpass3")]
+#[rustc_clean(cfg="rpass2")]
+#[rustc_clean(cfg="rpass3")]
pub fn use_Y() {
let x: a::Y = 'c';
}
#![feature(rustc_attrs)]
-#[rustc_clean(label="hir_owner", cfg="rpass2")]
-#[rustc_clean(label="hir_owner_nodes", cfg="rpass2")]
+#[rustc_clean(cfg="rpass2")]
fn line_same() {
let _ = line!();
}
-#[rustc_clean(label="hir_owner", cfg="rpass2")]
-#[rustc_clean(label="hir_owner_nodes", cfg="rpass2")]
+#[rustc_clean(cfg="rpass2")]
fn col_same() {
let _ = column!();
}
-#[rustc_clean(label="hir_owner", cfg="rpass2")]
-#[rustc_clean(label="hir_owner_nodes", cfg="rpass2")]
+#[rustc_clean(cfg="rpass2")]
fn file_same() {
let _ = file!();
}
-#[rustc_clean(label="hir_owner", cfg="rpass2")]
-#[rustc_dirty(label="hir_owner_nodes", cfg="rpass2")]
+#[rustc_clean(except="hir_owner_nodes,optimized_mir", cfg="rpass2")]
fn line_different() {
#[cfg(rpass1)]
{
}
}
-#[rustc_clean(label="hir_owner", cfg="rpass2")]
-#[rustc_dirty(label="hir_owner_nodes", cfg="rpass2")]
+#[rustc_clean(except="hir_owner_nodes,optimized_mir", cfg="rpass2")]
fn col_different() {
#[cfg(rpass1)]
{
-#[rustc_clean(label="hir_owner", cfg="rpass2")]
+#[rustc_clean(cfg="rpass2")]
pub struct SomeType {
pub x: u32,
pub y: i64,
-#[rustc_clean(label="hir_owner", cfg="rpass2")]
+#[rustc_clean(cfg="rpass2")]
pub struct SomeOtherType {
pub a: i32,
pub b: u64,
pub fn main() {}
#[cfg(rpass2)]
-#[rustc_dirty(label="hir_owner", cfg="rpass2")]
-#[rustc_dirty(label="hir_owner_nodes", cfg="rpass2")]
+#[rustc_clean(except="hir_owner,hir_owner_nodes,optimized_mir", cfg="rpass2")]
pub fn main() {}
}
#[cfg(rpass2)]
-#[rustc_dirty(label="optimized_mir", cfg="rpass2")]
+#[rustc_clean(except="hir_owner,hir_owner_nodes,optimized_mir", cfg="rpass2")]
pub fn main() {
let _ = 0u8 + 1;
}
}
#[cfg(cfail2)]
- #[rustc_dirty(label="hir_owner_nodes", cfg="cfail2")]
- #[rustc_dirty(label="optimized_mir", cfg="cfail2")]
+ #[rustc_clean(except="hir_owner,hir_owner_nodes,optimized_mir,promoted_mir", cfg="cfail2")]
pub fn x() {
println!("{}", "2");
}
pub mod y {
use x;
- #[rustc_clean(label="typeck", cfg="cfail2")]
- #[rustc_clean(label="optimized_mir", cfg="cfail2")]
+ #[rustc_clean(cfg="cfail2")]
pub fn y() {
x::x();
}
pub mod z {
use y;
- #[rustc_clean(label="typeck", cfg="cfail2")]
- #[rustc_clean(label="optimized_mir", cfg="cfail2")]
+ #[rustc_clean(cfg="cfail2")]
pub fn z() {
y::y();
}
pub y: char
}
-#[rustc_dirty(label="typeck", cfg="rpass2")]
+#[rustc_clean(except="fn_sig,typeck", cfg="rpass2")]
pub fn use_X(x: X) -> u32 {
x.x as u32
}
-#[rustc_dirty(label="typeck", cfg="rpass2")]
+#[rustc_clean(except="typeck", cfg="rpass2")]
pub fn use_EmbedX(embed: EmbedX) -> u32 {
embed.x.x as u32
}
-#[rustc_clean(label="typeck", cfg="rpass2")]
+#[rustc_clean(cfg="rpass2")]
pub fn use_Y() {
let x: Y = Y { y: 'c' };
}
pub y: char
}
-#[rustc_dirty(label="typeck", cfg="cfail2")]
+#[rustc_clean(except="typeck", cfg="cfail2")]
pub fn use_X() -> u32 {
let x: X = X { x: 22 };
//[cfail2]~^ ERROR struct `X` has no field named `x`
//[cfail2]~^ ERROR no field `x` on type `X`
}
-#[rustc_dirty(label="typeck", cfg="cfail2")]
+#[rustc_clean(except="typeck", cfg="cfail2")]
pub fn use_EmbedX(embed: EmbedX) -> u32 {
embed.x.x as u32
//[cfail2]~^ ERROR no field `x` on type `X`
}
-#[rustc_clean(label="typeck", cfg="cfail2")]
+#[rustc_clean(cfg="cfail2")]
pub fn use_Y() {
let x: Y = Y { y: 'c' };
}
pub y: char
}
-#[rustc_dirty(label="typeck", cfg="rpass2")]
+#[rustc_clean(except="typeck", cfg="rpass2")]
pub fn use_X() -> u32 {
let x: X = X { x: 22 };
x.x as u32
}
-#[rustc_dirty(label="typeck", cfg="rpass2")]
+#[rustc_clean(except="typeck", cfg="rpass2")]
pub fn use_EmbedX(x: EmbedX) -> u32 {
let x: X = X { x: 22 };
x.x as u32
}
-#[rustc_clean(label="typeck", cfg="rpass2")]
+#[rustc_clean(cfg="rpass2")]
pub fn use_Y() {
let x: Y = Y { y: 'c' };
}
use a::*;
-#[rustc_dirty(label="typeck", cfg="rpass2")]
+#[rustc_clean(except="typeck", cfg="rpass2")]
pub fn use_X() -> u32 {
let x: X = X { x: 22 };
x.x as u32
}
-#[rustc_dirty(label="typeck", cfg="rpass2")]
+#[rustc_clean(except="typeck", cfg="rpass2")]
pub fn use_EmbedX(embed: EmbedX) -> u32 {
embed.x.x as u32
}
-#[rustc_clean(label="typeck", cfg="rpass2")]
+#[rustc_clean(cfg="rpass2")]
pub fn use_Y() {
let x: Y = Y { y: 'c' };
}
pub y: char
}
-#[rustc_clean(label="typeck", cfg="rpass2")]
+#[rustc_clean(cfg="rpass2")]
pub fn use_X() -> u32 {
let x: X = X { x: 22 };
x.x as u32
}
-#[rustc_clean(label="typeck", cfg="rpass2")]
+#[rustc_clean(cfg="rpass2")]
pub fn use_EmbedX(x: EmbedX) -> u32 {
let x: X = X { x: 22 };
x.x as u32
}
-#[rustc_clean(label="typeck", cfg="rpass2")]
+#[rustc_clean(cfg="rpass2")]
pub fn use_Y() {
let x: Y = Y { y: 'c' };
}
pub y: char
}
-#[rustc_dirty(label="typeck", cfg="rpass2")]
+#[rustc_clean(except="typeck,fn_sig", cfg="rpass2")]
pub fn use_X(x: X) -> u32 {
x.x as u32
}
-#[rustc_dirty(label="typeck", cfg="rpass2")]
+#[rustc_clean(except="typeck", cfg="rpass2")]
pub fn use_EmbedX(embed: EmbedX) -> u32 {
embed.x.x as u32
}
-#[rustc_clean(label="typeck", cfg="rpass2")]
+#[rustc_clean(cfg="rpass2")]
pub fn use_Y() {
let x: Y = Y { y: 'c' };
}
extern crate a;
-#[rustc_dirty(label="typeck", cfg="rpass2")]
-#[rustc_clean(label="typeck", cfg="rpass3")]
+#[rustc_clean(except="typeck", cfg="rpass2")]
+#[rustc_clean(cfg="rpass3")]
pub fn use_X() -> u32 {
let x: a::X = 22;
x as u32
}
-#[rustc_clean(label="typeck", cfg="rpass2")]
-#[rustc_clean(label="typeck", cfg="rpass3")]
+#[rustc_clean(cfg="rpass2")]
+#[rustc_clean(cfg="rpass3")]
pub fn use_Y() {
let x: a::Y = 'c';
}
#![allow(warnings)]
#![feature(rustc_attrs)]
-// Sanity check for the dirty-clean system. We add #[rustc_dirty]/#[rustc_clean]
+// Sanity check for the dirty-clean system. We add #[rustc_clean]
// attributes in places that are not checked and make sure that this causes an
// error.
fn main() {
- #[rustc_dirty(label="hir_owner", cfg="cfail2")]
- //[cfail2]~^ ERROR found unchecked `#[rustc_dirty]` / `#[rustc_clean]` attribute
+ #[rustc_clean(except="hir_owner", cfg="cfail2")]
+ //[cfail2]~^ ERROR found unchecked `#[rustc_clean]` attribute
{
// empty block
}
- #[rustc_clean(label="hir_owner", cfg="cfail2")]
- //[cfail2]~^ ERROR found unchecked `#[rustc_dirty]` / `#[rustc_clean]` attribute
+ #[rustc_clean(cfg="cfail2")]
+ //[cfail2]~^ ERROR found unchecked `#[rustc_clean]` attribute
{
// empty block
}
}
struct _Struct {
- #[rustc_dirty(label="hir_owner", cfg="cfail2")]
- //[cfail2]~^ ERROR found unchecked `#[rustc_dirty]` / `#[rustc_clean]` attribute
+ #[rustc_clean(except="hir_owner", cfg="cfail2")]
+ //[cfail2]~^ ERROR found unchecked `#[rustc_clean]` attribute
_field1: i32,
- #[rustc_clean(label="hir_owner", cfg="cfail2")]
- //[cfail2]~^ ERROR found unchecked `#[rustc_dirty]` / `#[rustc_clean]` attribute
+ #[rustc_clean(cfg="cfail2")]
+ //[cfail2]~^ ERROR found unchecked `#[rustc_clean]` attribute
_field2: i32,
}
--- /dev/null
+- // MIR for `opt1` before InstCombine
++ // MIR for `opt1` after InstCombine
+
+ fn opt1(_1: bool) -> u32 {
+ debug x => _1; // in scope 0 at $DIR/bool_compare.rs:2:9: 2:10
+ let mut _0: u32; // return place in scope 0 at $DIR/bool_compare.rs:2:21: 2:24
+ let mut _2: bool; // in scope 0 at $DIR/bool_compare.rs:3:8: 3:17
+ let mut _3: bool; // in scope 0 at $DIR/bool_compare.rs:3:8: 3:9
+
+ bb0: {
+ StorageLive(_2); // scope 0 at $DIR/bool_compare.rs:3:8: 3:17
+ StorageLive(_3); // scope 0 at $DIR/bool_compare.rs:3:8: 3:9
+ _3 = _1; // scope 0 at $DIR/bool_compare.rs:3:8: 3:9
+- _2 = Ne(move _3, const true); // scope 0 at $DIR/bool_compare.rs:3:8: 3:17
++ _2 = Not(move _3); // scope 0 at $DIR/bool_compare.rs:3:8: 3:17
+ StorageDead(_3); // scope 0 at $DIR/bool_compare.rs:3:16: 3:17
+ switchInt(move _2) -> [false: bb2, otherwise: bb1]; // scope 0 at $DIR/bool_compare.rs:3:5: 3:34
+ }
+
+ bb1: {
+ _0 = const 0_u32; // scope 0 at $DIR/bool_compare.rs:3:20: 3:21
+ goto -> bb3; // scope 0 at $DIR/bool_compare.rs:3:5: 3:34
+ }
+
+ bb2: {
+ _0 = const 1_u32; // scope 0 at $DIR/bool_compare.rs:3:31: 3:32
+ goto -> bb3; // scope 0 at $DIR/bool_compare.rs:3:5: 3:34
+ }
+
+ bb3: {
+ StorageDead(_2); // scope 0 at $DIR/bool_compare.rs:3:33: 3:34
+ return; // scope 0 at $DIR/bool_compare.rs:4:2: 4:2
+ }
+ }
+
--- /dev/null
+- // MIR for `opt2` before InstCombine
++ // MIR for `opt2` after InstCombine
+
+ fn opt2(_1: bool) -> u32 {
+ debug x => _1; // in scope 0 at $DIR/bool_compare.rs:7:9: 7:10
+ let mut _0: u32; // return place in scope 0 at $DIR/bool_compare.rs:7:21: 7:24
+ let mut _2: bool; // in scope 0 at $DIR/bool_compare.rs:8:8: 8:17
+ let mut _3: bool; // in scope 0 at $DIR/bool_compare.rs:8:16: 8:17
+
+ bb0: {
+ StorageLive(_2); // scope 0 at $DIR/bool_compare.rs:8:8: 8:17
+ StorageLive(_3); // scope 0 at $DIR/bool_compare.rs:8:16: 8:17
+ _3 = _1; // scope 0 at $DIR/bool_compare.rs:8:16: 8:17
+- _2 = Ne(const true, move _3); // scope 0 at $DIR/bool_compare.rs:8:8: 8:17
++ _2 = Not(move _3); // scope 0 at $DIR/bool_compare.rs:8:8: 8:17
+ StorageDead(_3); // scope 0 at $DIR/bool_compare.rs:8:16: 8:17
+ switchInt(move _2) -> [false: bb2, otherwise: bb1]; // scope 0 at $DIR/bool_compare.rs:8:5: 8:34
+ }
+
+ bb1: {
+ _0 = const 0_u32; // scope 0 at $DIR/bool_compare.rs:8:20: 8:21
+ goto -> bb3; // scope 0 at $DIR/bool_compare.rs:8:5: 8:34
+ }
+
+ bb2: {
+ _0 = const 1_u32; // scope 0 at $DIR/bool_compare.rs:8:31: 8:32
+ goto -> bb3; // scope 0 at $DIR/bool_compare.rs:8:5: 8:34
+ }
+
+ bb3: {
+ StorageDead(_2); // scope 0 at $DIR/bool_compare.rs:8:33: 8:34
+ return; // scope 0 at $DIR/bool_compare.rs:9:2: 9:2
+ }
+ }
+
--- /dev/null
+- // MIR for `opt3` before InstCombine
++ // MIR for `opt3` after InstCombine
+
+ fn opt3(_1: bool) -> u32 {
+ debug x => _1; // in scope 0 at $DIR/bool_compare.rs:12:9: 12:10
+ let mut _0: u32; // return place in scope 0 at $DIR/bool_compare.rs:12:21: 12:24
+ let mut _2: bool; // in scope 0 at $DIR/bool_compare.rs:13:8: 13:18
+ let mut _3: bool; // in scope 0 at $DIR/bool_compare.rs:13:8: 13:9
+
+ bb0: {
+ StorageLive(_2); // scope 0 at $DIR/bool_compare.rs:13:8: 13:18
+ StorageLive(_3); // scope 0 at $DIR/bool_compare.rs:13:8: 13:9
+ _3 = _1; // scope 0 at $DIR/bool_compare.rs:13:8: 13:9
+- _2 = Eq(move _3, const false); // scope 0 at $DIR/bool_compare.rs:13:8: 13:18
++ _2 = Not(move _3); // scope 0 at $DIR/bool_compare.rs:13:8: 13:18
+ StorageDead(_3); // scope 0 at $DIR/bool_compare.rs:13:17: 13:18
+ switchInt(move _2) -> [false: bb2, otherwise: bb1]; // scope 0 at $DIR/bool_compare.rs:13:5: 13:35
+ }
+
+ bb1: {
+ _0 = const 0_u32; // scope 0 at $DIR/bool_compare.rs:13:21: 13:22
+ goto -> bb3; // scope 0 at $DIR/bool_compare.rs:13:5: 13:35
+ }
+
+ bb2: {
+ _0 = const 1_u32; // scope 0 at $DIR/bool_compare.rs:13:32: 13:33
+ goto -> bb3; // scope 0 at $DIR/bool_compare.rs:13:5: 13:35
+ }
+
+ bb3: {
+ StorageDead(_2); // scope 0 at $DIR/bool_compare.rs:13:34: 13:35
+ return; // scope 0 at $DIR/bool_compare.rs:14:2: 14:2
+ }
+ }
+
--- /dev/null
+- // MIR for `opt4` before InstCombine
++ // MIR for `opt4` after InstCombine
+
+ fn opt4(_1: bool) -> u32 {
+ debug x => _1; // in scope 0 at $DIR/bool_compare.rs:17:9: 17:10
+ let mut _0: u32; // return place in scope 0 at $DIR/bool_compare.rs:17:21: 17:24
+ let mut _2: bool; // in scope 0 at $DIR/bool_compare.rs:18:8: 18:18
+ let mut _3: bool; // in scope 0 at $DIR/bool_compare.rs:18:17: 18:18
+
+ bb0: {
+ StorageLive(_2); // scope 0 at $DIR/bool_compare.rs:18:8: 18:18
+ StorageLive(_3); // scope 0 at $DIR/bool_compare.rs:18:17: 18:18
+ _3 = _1; // scope 0 at $DIR/bool_compare.rs:18:17: 18:18
+- _2 = Eq(const false, move _3); // scope 0 at $DIR/bool_compare.rs:18:8: 18:18
++ _2 = Not(move _3); // scope 0 at $DIR/bool_compare.rs:18:8: 18:18
+ StorageDead(_3); // scope 0 at $DIR/bool_compare.rs:18:17: 18:18
+ switchInt(move _2) -> [false: bb2, otherwise: bb1]; // scope 0 at $DIR/bool_compare.rs:18:5: 18:35
+ }
+
+ bb1: {
+ _0 = const 0_u32; // scope 0 at $DIR/bool_compare.rs:18:21: 18:22
+ goto -> bb3; // scope 0 at $DIR/bool_compare.rs:18:5: 18:35
+ }
+
+ bb2: {
+ _0 = const 1_u32; // scope 0 at $DIR/bool_compare.rs:18:32: 18:33
+ goto -> bb3; // scope 0 at $DIR/bool_compare.rs:18:5: 18:35
+ }
+
+ bb3: {
+ StorageDead(_2); // scope 0 at $DIR/bool_compare.rs:18:34: 18:35
+ return; // scope 0 at $DIR/bool_compare.rs:19:2: 19:2
+ }
+ }
+
--- /dev/null
+// EMIT_MIR bool_compare.opt1.InstCombine.diff
+fn opt1(x: bool) -> u32 {
+ if x != true { 0 } else { 1 }
+}
+
+// EMIT_MIR bool_compare.opt2.InstCombine.diff
+fn opt2(x: bool) -> u32 {
+ if true != x { 0 } else { 1 }
+}
+
+// EMIT_MIR bool_compare.opt3.InstCombine.diff
+fn opt3(x: bool) -> u32 {
+ if x == false { 0 } else { 1 }
+}
+
+// EMIT_MIR bool_compare.opt4.InstCombine.diff
+fn opt4(x: bool) -> u32 {
+ if false == x { 0 } else { 1 }
+}
+
+fn main() {
+ opt1(false);
+ opt2(false);
+ opt3(false);
+ opt4(false);
+}
},
} */
-fn main::{closure#0}(_1: *mut [generator@$DIR/generator-drop-cleanup.rs:10:15: 13:6 {String, ()}]) -> () {
+fn main::{closure#0}(_1: *mut [generator@$DIR/generator-drop-cleanup.rs:10:15: 13:6]) -> () {
let mut _0: (); // return place in scope 0 at $DIR/generator-drop-cleanup.rs:10:15: 13:6
let mut _2: (); // in scope 0 at $DIR/generator-drop-cleanup.rs:10:15: 13:6
let _3: std::string::String; // in scope 0 at $DIR/generator-drop-cleanup.rs:11:13: 11:15
// MIR for `main::{closure#0}` before StateTransform
-fn main::{closure#0}(_1: [generator@$DIR/generator-storage-dead-unwind.rs:22:16: 28:6 {Foo, Bar, ()}], _2: ()) -> ()
+fn main::{closure#0}(_1: [generator@$DIR/generator-storage-dead-unwind.rs:22:16: 28:6], _2: ()) -> ()
yields ()
{
let mut _0: (); // return place in scope 0 at $DIR/generator-storage-dead-unwind.rs:22:19: 22:19
bb8 (cleanup): {
StorageDead(_10); // scope 2 at $DIR/generator-storage-dead-unwind.rs:27:15: 27:16
StorageDead(_9); // scope 2 at $DIR/generator-storage-dead-unwind.rs:27:16: 27:17
- goto -> bb10; // scope 2 at $DIR/generator-storage-dead-unwind.rs:1:1: 1:1
+ goto -> bb10; // scope 2 at no-location
}
bb9 (cleanup): {
StorageDead(_8); // scope 2 at $DIR/generator-storage-dead-unwind.rs:26:15: 26:16
StorageDead(_7); // scope 2 at $DIR/generator-storage-dead-unwind.rs:26:16: 26:17
- goto -> bb10; // scope 2 at $DIR/generator-storage-dead-unwind.rs:1:1: 1:1
+ goto -> bb10; // scope 2 at no-location
}
bb10 (cleanup): {
storage_conflicts: BitMatrix(0x0) {},
} */
-fn main::{closure#0}(_1: Pin<&mut [generator@$DIR/generator-tiny.rs:19:16: 25:6 {u8, HasDrop, ()}]>, _2: u8) -> GeneratorState<(), ()> {
+fn main::{closure#0}(_1: Pin<&mut [generator@$DIR/generator-tiny.rs:19:16: 25:6]>, _2: u8) -> GeneratorState<(), ()> {
debug _x => _10; // in scope 0 at $DIR/generator-tiny.rs:19:17: 19:19
let mut _0: std::ops::GeneratorState<(), ()>; // return place in scope 0 at $DIR/generator-tiny.rs:19:16: 25:6
let _3: HasDrop; // in scope 0 at $DIR/generator-tiny.rs:20:13: 20:15
}
bb0: {
- _11 = discriminant((*(_1.0: &mut [generator@$DIR/generator-tiny.rs:19:16: 25:6 {u8, HasDrop, ()}]))); // scope 0 at $DIR/generator-tiny.rs:19:16: 25:6
+ _11 = discriminant((*(_1.0: &mut [generator@$DIR/generator-tiny.rs:19:16: 25:6]))); // scope 0 at $DIR/generator-tiny.rs:19:16: 25:6
switchInt(move _11) -> [0_u32: bb1, 3_u32: bb5, otherwise: bb6]; // scope 0 at $DIR/generator-tiny.rs:19:16: 25:6
}
StorageLive(_7); // scope 1 at $DIR/generator-tiny.rs:22:13: 22:18
((_0 as Yielded).0: ()) = move _7; // scope 1 at $DIR/generator-tiny.rs:22:13: 22:18
discriminant(_0) = 0; // scope 1 at $DIR/generator-tiny.rs:22:13: 22:18
- discriminant((*(_1.0: &mut [generator@$DIR/generator-tiny.rs:19:16: 25:6 {u8, HasDrop, ()}]))) = 3; // scope 1 at $DIR/generator-tiny.rs:22:13: 22:18
+ discriminant((*(_1.0: &mut [generator@$DIR/generator-tiny.rs:19:16: 25:6]))) = 3; // scope 1 at $DIR/generator-tiny.rs:22:13: 22:18
return; // scope 1 at $DIR/generator-tiny.rs:22:13: 22:18
}
}
+ scope 2 (inlined g) { // at $DIR/inline-generator.rs:9:28: 9:31
+ }
-+ scope 3 (inlined Pin::<&mut [generator@$DIR/inline-generator.rs:15:5: 15:41 {bool, i32}]>::new) { // at $DIR/inline-generator.rs:9:14: 9:32
++ scope 3 (inlined Pin::<&mut [generator@$DIR/inline-generator.rs:15:5: 15:41]>::new) { // at $DIR/inline-generator.rs:9:14: 9:32
+ debug pointer => _3; // in scope 3 at $DIR/inline-generator.rs:9:14: 9:32
-+ let mut _5: &mut [generator@$DIR/inline-generator.rs:15:5: 15:41 {bool, i32}]; // in scope 3 at $DIR/inline-generator.rs:9:14: 9:32
++ let mut _5: &mut [generator@$DIR/inline-generator.rs:15:5: 15:41]; // in scope 3 at $DIR/inline-generator.rs:9:14: 9:32
+ scope 4 {
-+ scope 5 (inlined Pin::<&mut [generator@$DIR/inline-generator.rs:15:5: 15:41 {bool, i32}]>::new_unchecked) { // at $DIR/inline-generator.rs:9:14: 9:32
++ scope 5 (inlined Pin::<&mut [generator@$DIR/inline-generator.rs:15:5: 15:41]>::new_unchecked) { // at $DIR/inline-generator.rs:9:14: 9:32
+ debug pointer => _5; // in scope 5 at $DIR/inline-generator.rs:9:14: 9:32
-+ let mut _6: &mut [generator@$DIR/inline-generator.rs:15:5: 15:41 {bool, i32}]; // in scope 5 at $DIR/inline-generator.rs:9:14: 9:32
++ let mut _6: &mut [generator@$DIR/inline-generator.rs:15:5: 15:41]; // in scope 5 at $DIR/inline-generator.rs:9:14: 9:32
+ }
+ }
+ }
+ _5 = move _3; // scope 4 at $DIR/inline-generator.rs:9:14: 9:32
+ StorageLive(_6); // scope 5 at $DIR/inline-generator.rs:9:14: 9:32
+ _6 = move _5; // scope 5 at $DIR/inline-generator.rs:9:14: 9:32
-+ (_2.0: &mut [generator@$DIR/inline-generator.rs:15:5: 15:41 {bool, i32}]) = move _6; // scope 5 at $DIR/inline-generator.rs:9:14: 9:32
++ (_2.0: &mut [generator@$DIR/inline-generator.rs:15:5: 15:41]) = move _6; // scope 5 at $DIR/inline-generator.rs:9:14: 9:32
+ StorageDead(_6); // scope 5 at $DIR/inline-generator.rs:9:14: 9:32
+ StorageDead(_5); // scope 4 at $DIR/inline-generator.rs:9:14: 9:32
StorageDead(_3); // scope 0 at $DIR/inline-generator.rs:9:31: 9:32
+ StorageLive(_10); // scope 0 at $DIR/inline-generator.rs:9:14: 9:46
+ StorageLive(_11); // scope 0 at $DIR/inline-generator.rs:9:14: 9:46
+ StorageLive(_12); // scope 0 at $DIR/inline-generator.rs:9:14: 9:46
-+ _12 = discriminant((*(_2.0: &mut [generator@$DIR/inline-generator.rs:15:5: 15:41 {bool, i32}]))); // scope 6 at $DIR/inline-generator.rs:9:14: 9:46
++ _12 = discriminant((*(_2.0: &mut [generator@$DIR/inline-generator.rs:15:5: 15:41]))); // scope 6 at $DIR/inline-generator.rs:9:14: 9:46
+ switchInt(move _12) -> [0_u32: bb3, 1_u32: bb8, 3_u32: bb7, otherwise: bb9]; // scope 6 at $DIR/inline-generator.rs:9:14: 9:46
}
+ StorageDead(_9); // scope 6 at $DIR/inline-generator.rs:9:14: 9:46
+ ((_1 as Yielded).0: i32) = move _8; // scope 6 at $DIR/inline-generator.rs:9:14: 9:46
+ discriminant(_1) = 0; // scope 6 at $DIR/inline-generator.rs:9:14: 9:46
-+ discriminant((*(_2.0: &mut [generator@$DIR/inline-generator.rs:15:5: 15:41 {bool, i32}]))) = 3; // scope 6 at $DIR/inline-generator.rs:9:14: 9:46
++ discriminant((*(_2.0: &mut [generator@$DIR/inline-generator.rs:15:5: 15:41]))) = 3; // scope 6 at $DIR/inline-generator.rs:9:14: 9:46
+ goto -> bb1; // scope 0 at $DIR/inline-generator.rs:15:11: 15:39
+ }
+
+ StorageDead(_8); // scope 6 at $DIR/inline-generator.rs:9:14: 9:46
+ ((_1 as Complete).0: bool) = move _10; // scope 6 at $DIR/inline-generator.rs:9:14: 9:46
+ discriminant(_1) = 1; // scope 6 at $DIR/inline-generator.rs:9:14: 9:46
-+ discriminant((*(_2.0: &mut [generator@$DIR/inline-generator.rs:15:5: 15:41 {bool, i32}]))) = 1; // scope 6 at $DIR/inline-generator.rs:9:14: 9:46
++ discriminant((*(_2.0: &mut [generator@$DIR/inline-generator.rs:15:5: 15:41]))) = 1; // scope 6 at $DIR/inline-generator.rs:9:14: 9:46
+ goto -> bb1; // scope 0 at $DIR/inline-generator.rs:15:41: 15:41
+ }
+
_6 = const 1_i32; // scope 0 at $DIR/loop_test.rs:14:17: 14:18
FakeRead(ForLet(None), _6); // scope 0 at $DIR/loop_test.rs:14:13: 14:14
StorageDead(_6); // scope 0 at $DIR/loop_test.rs:16:5: 16:6
- goto -> bb3; // scope 0 at $DIR/loop_test.rs:1:1: 1:1
+ goto -> bb3; // scope 0 at no-location
}
bb5 (cleanup): {
_0 = const 3_i32; // scope 0 at $DIR/match-arm-scopes.rs:15:59: 15:60
StorageDead(_10); // scope 0 at $DIR/match-arm-scopes.rs:15:72: 15:73
StorageDead(_9); // scope 0 at $DIR/match-arm-scopes.rs:15:77: 15:78
-- goto -> bb23; // scope 0 at $DIR/match-arm-scopes.rs:1:1: 1:1
-+ goto -> bb20; // scope 0 at $DIR/match-arm-scopes.rs:1:1: 1:1
+- goto -> bb23; // scope 0 at no-location
++ goto -> bb20; // scope 0 at no-location
}
- bb10: {
_0 = const 3_i32; // scope 0 at $DIR/match-arm-scopes.rs:15:59: 15:60
StorageDead(_13); // scope 0 at $DIR/match-arm-scopes.rs:15:72: 15:73
StorageDead(_12); // scope 0 at $DIR/match-arm-scopes.rs:15:77: 15:78
-- goto -> bb23; // scope 0 at $DIR/match-arm-scopes.rs:1:1: 1:1
-+ goto -> bb20; // scope 0 at $DIR/match-arm-scopes.rs:1:1: 1:1
+- goto -> bb23; // scope 0 at no-location
++ goto -> bb20; // scope 0 at no-location
}
- bb15: {
scope 5 {
debug i => _15; // in scope 5 at $DIR/remove_storage_markers.rs:8:9: 8:10
}
+ scope 7 (inlined iter::range::<impl Iterator for std::ops::Range<i32>>::next) { // at $DIR/remove_storage_markers.rs:8:14: 8:19
+ debug self => _9; // in scope 7 at $DIR/remove_storage_markers.rs:8:14: 8:19
+ let mut _18: &mut std::ops::Range<i32>; // in scope 7 at $DIR/remove_storage_markers.rs:8:14: 8:19
+ }
}
}
scope 6 (inlined <std::ops::Range<i32> as IntoIterator>::into_iter) { // at $DIR/remove_storage_markers.rs:8:14: 8:19
- StorageLive(_10); // scope 3 at $DIR/remove_storage_markers.rs:8:14: 8:19
_10 = &mut _4; // scope 3 at $DIR/remove_storage_markers.rs:8:14: 8:19
_9 = &mut (*_10); // scope 3 at $DIR/remove_storage_markers.rs:8:14: 8:19
- _8 = <std::ops::Range<i32> as Iterator>::next(move _9) -> bb2; // scope 3 at $DIR/remove_storage_markers.rs:8:14: 8:19
+- StorageLive(_18); // scope 7 at $DIR/remove_storage_markers.rs:8:14: 8:19
+ _18 = &mut (*_9); // scope 7 at $DIR/remove_storage_markers.rs:8:14: 8:19
+ _8 = <std::ops::Range<i32> as iter::range::RangeIteratorImpl>::spec_next(move _18) -> bb4; // scope 7 at $DIR/remove_storage_markers.rs:8:14: 8:19
// mir::Constant
// + span: $DIR/remove_storage_markers.rs:8:14: 8:19
- // + literal: Const { ty: for<'r> fn(&'r mut std::ops::Range<i32>) -> std::option::Option<<std::ops::Range<i32> as std::iter::Iterator>::Item> {<std::ops::Range<i32> as std::iter::Iterator>::next}, val: Value(Scalar(<ZST>)) }
+ // + literal: Const { ty: for<'r> fn(&'r mut std::ops::Range<i32>) -> std::option::Option<<std::ops::Range<i32> as std::iter::range::RangeIteratorImpl>::Item> {<std::ops::Range<i32> as std::iter::range::RangeIteratorImpl>::spec_next}, val: Value(Scalar(<ZST>)) }
}
bb2: {
-- StorageDead(_9); // scope 3 at $DIR/remove_storage_markers.rs:8:18: 8:19
- _11 = discriminant(_8); // scope 3 at $DIR/remove_storage_markers.rs:8:9: 8:10
- switchInt(move _11) -> [0_isize: bb3, otherwise: bb4]; // scope 3 at $DIR/remove_storage_markers.rs:8:9: 8:10
- }
-
- bb3: {
_0 = const (); // scope 3 at $DIR/remove_storage_markers.rs:8:5: 10:6
- StorageDead(_10); // scope 3 at $DIR/remove_storage_markers.rs:8:18: 8:19
- StorageDead(_8); // scope 3 at $DIR/remove_storage_markers.rs:8:18: 8:19
return; // scope 0 at $DIR/remove_storage_markers.rs:11:2: 11:2
}
- bb4: {
+ bb3: {
- StorageLive(_12); // scope 3 at $DIR/remove_storage_markers.rs:8:9: 8:10
_12 = ((_8 as Some).0: i32); // scope 3 at $DIR/remove_storage_markers.rs:8:9: 8:10
- StorageLive(_13); // scope 4 at $DIR/remove_storage_markers.rs:8:9: 8:10
- StorageDead(_6); // scope 2 at $DIR/remove_storage_markers.rs:10:5: 10:6
goto -> bb1; // scope 2 at $DIR/remove_storage_markers.rs:8:5: 10:6
}
+
+ bb4: {
+- StorageDead(_18); // scope 7 at $DIR/remove_storage_markers.rs:8:14: 8:19
+- StorageDead(_9); // scope 3 at $DIR/remove_storage_markers.rs:8:18: 8:19
+ _11 = discriminant(_8); // scope 3 at $DIR/remove_storage_markers.rs:8:9: 8:10
+ switchInt(move _11) -> [0_isize: bb2, otherwise: bb3]; // scope 3 at $DIR/remove_storage_markers.rs:8:9: 8:10
+ }
}
bb4: {
StorageDead(_4); // scope 0 at $DIR/while-storage.rs:13:9: 13:10
- goto -> bb6; // scope 0 at $DIR/while-storage.rs:1:1: 1:1
+ goto -> bb6; // scope 0 at no-location
}
bb5: {
# Run it in order to generate some profiling data,
# with `LLVM_PROFILE_FILE=<profdata_file>` environment variable set to
# output the coverage stats for this run.
- LLVM_PROFILE_FILE="$(TMPDIR)"/$@-%p.profraw \
+ LLVM_PROFILE_FILE="$(TMPDIR)"/$@.profraw \
$(call RUN,$@) || \
( \
status=$$?; \
) \
)
- # Run it through rustdoc as well to cover doctests
- LLVM_PROFILE_FILE="$(TMPDIR)"/$@-%p.profraw \
+ # Run it through rustdoc as well to cover doctests.
+ # `%p` is the pid, and `%m` the binary signature. We suspect that the pid alone
+ # might result in overwritten files and failed tests, as rustdoc spawns each
+ # doctest as its own process, so make sure the filename is as unique as possible.
+ LLVM_PROFILE_FILE="$(TMPDIR)"/$@-%p-%m.profraw \
$(RUSTDOC) --crate-name workaround_for_79771 --test $(SOURCEDIR)/$@.rs \
$$( sed -n 's/^\/\/ compile-flags: \([^#]*\).*/\1/p' $(SOURCEDIR)/$@.rs ) \
-L "$(TMPDIR)" -Zinstrument-coverage \
# Postprocess the profiling data so it can be used by the llvm-cov tool
"$(LLVM_BIN_DIR)"/llvm-profdata merge --sparse \
- "$(TMPDIR)"/$@-*.profraw \
+ "$(TMPDIR)"/$@*.profraw \
-o "$(TMPDIR)"/$@.profdata
# Generate a coverage report using `llvm-cov show`.
--instr-profile="$(TMPDIR)"/$@.profdata \
$(call BIN,"$(TMPDIR)"/$@) \
$$( \
- for file in $(TMPDIR)/rustdoc-$@/*/rust_out; \
- do \
+ for file in $(TMPDIR)/rustdoc-$@/*/rust_out; do \
[ -x "$$file" ] && printf "%s %s " -object $$file; \
done \
) \
12| 1| if b {
13| 1| println!("non_async_func println in block");
14| 1| }
+ ^0
15| 1|}
16| |
17| |
5| 1| if true {
6| 1| countdown = 10;
7| 1| }
+ ^0
8| |
9| | const B: u32 = 100;
10| 1| let x = if countdown > 7 {
24| 1| if true {
25| 1| countdown = 10;
26| 1| }
+ ^0
27| |
28| 1| if countdown > 7 {
29| 1| countdown -= 4;
41| 1| if true {
42| 1| countdown = 10;
43| 1| }
+ ^0
44| |
45| 1| if countdown > 7 {
46| 1| countdown -= 4;
53| | } else {
54| 0| return;
55| | }
- 56| | } // Note: closing brace shows uncovered (vs. `0` for implicit else) because condition literal
- 57| | // `true` was const-evaluated. The compiler knows the `if` block will be executed.
+ 56| 0| }
+ 57| |
58| |
59| 1| let mut countdown = 0;
60| 1| if true {
61| 1| countdown = 1;
62| 1| }
+ ^0
63| |
64| 1| let z = if countdown > 7 {
^0
8| 1|//! assert_eq!(1, 1);
9| |//! } else {
10| |//! // this is not!
- 11| |//! assert_eq!(1, 2);
+ 11| 0|//! assert_eq!(1, 2);
12| |//! }
13| 1|//! ```
14| |//!
74| 1| if true {
75| 1| assert_eq!(1, 1);
76| | } else {
- 77| | assert_eq!(1, 2);
+ 77| 0| assert_eq!(1, 2);
78| | }
79| 1|}
80| |
19| 1| if true {
20| 1| println!("Exiting with error...");
21| 1| return Err(1);
- 22| | }
- 23| |
- 24| | let _ = Firework { strength: 1000 };
- 25| |
- 26| | Ok(())
+ 22| 0| }
+ 23| 0|
+ 24| 0| let _ = Firework { strength: 1000 };
+ 25| 0|
+ 26| 0| Ok(())
27| 1|}
28| |
29| |// Expected program output:
--- /dev/null
+ 1| |#![feature(generators, generator_trait)]
+ 2| |
+ 3| |use std::ops::{Generator, GeneratorState};
+ 4| |use std::pin::Pin;
+ 5| |
+ 6| |// The following implementation of a function called from a `yield` statement
+ 7| |// (apparently requiring the Result and the `String` type or constructor)
+ 8| |// creates conditions where the `generator::StateTransform` MIR transform will
+ 9| |// drop all `Counter` `Coverage` statements from a MIR. `simplify.rs` has logic
+ 10| |// to handle this condition, and still report dead block coverage.
+ 11| 1|fn get_u32(val: bool) -> Result<u32, String> {
+ 12| 1| if val { Ok(1) } else { Err(String::from("some error")) }
+ ^0
+ 13| 1|}
+ 14| |
+ 15| 1|fn main() {
+ 16| 1| let is_true = std::env::args().len() == 1;
+ 17| 1| let mut generator = || {
+ 18| 1| yield get_u32(is_true);
+ 19| 1| return "foo";
+ 20| 1| };
+ 21| |
+ 22| 1| match Pin::new(&mut generator).resume(()) {
+ 23| 1| GeneratorState::Yielded(Ok(1)) => {}
+ 24| 0| _ => panic!("unexpected return from resume"),
+ 25| | }
+ 26| 1| match Pin::new(&mut generator).resume(()) {
+ 27| 1| GeneratorState::Complete("foo") => {}
+ 28| 0| _ => panic!("unexpected return from resume"),
+ 29| | }
+ 30| 1|}
+
11| 3| self.strength = new_strength;
12| 3| }
------------------
- | <generics::Firework<f64>>::set_strength:
- | 10| 2| fn set_strength(&mut self, new_strength: T) {
- | 11| 2| self.strength = new_strength;
- | 12| 2| }
- ------------------
| <generics::Firework<i32>>::set_strength:
| 10| 1| fn set_strength(&mut self, new_strength: T) {
| 11| 1| self.strength = new_strength;
| 12| 1| }
+ ------------------
+ | <generics::Firework<f64>>::set_strength:
+ | 10| 2| fn set_strength(&mut self, new_strength: T) {
+ | 11| 2| self.strength = new_strength;
+ | 12| 2| }
------------------
13| |}
14| |
30| 1| if true {
31| 1| println!("Exiting with error...");
32| 1| return Err(1);
- 33| | } // The remaining lines below have no coverage because `if true` (with the constant literal
- 34| | // `true`) is guaranteed to execute the `then` block, which is also guaranteed to `return`.
- 35| | // Thankfully, in the normal case, conditions are not guaranteed ahead of time, and as shown
- 36| | // in other tests, the lines below would have coverage (which would show they had `0`
- 37| | // executions, assuming the condition still evaluated to `true`).
- 38| |
- 39| | let _ = Firework { strength: 1000 };
- 40| |
- 41| | Ok(())
+ 33| 0| }
+ 34| 0|
+ 35| 0|
+ 36| 0|
+ 37| 0|
+ 38| 0|
+ 39| 0| let _ = Firework { strength: 1000 };
+ 40| 0|
+ 41| 0| Ok(())
42| 1|}
43| |
44| |// Expected program output:
9| 1| fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
10| 1| if true {
11| 1| if false {
- 12| | while true {
- 13| | }
+ 12| 0| while true {
+ 13| 0| }
14| 1| }
- 15| 1| write!(f, "error")?;
- ^0
- 16| | } else {
- 17| | }
+ 15| 1| write!(f, "cool")?;
+ ^0
+ 16| 0| } else {
+ 17| 0| }
18| |
19| 10| for i in 0..10 {
20| 10| if true {
21| 10| if false {
- 22| | while true {}
+ 22| 0| while true {}
23| 10| }
- 24| 10| write!(f, "error")?;
- ^0
- 25| | } else {
- 26| | }
+ 24| 10| write!(f, "cool")?;
+ ^0
+ 25| 0| } else {
+ 26| 0| }
27| | }
28| 1| Ok(())
29| 1| }
34| |impl std::fmt::Display for DisplayTest {
35| 1| fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
36| 1| if false {
- 37| | } else {
+ 37| 0| } else {
38| 1| if false {
- 39| | while true {}
+ 39| 0| while true {}
40| 1| }
- 41| 1| write!(f, "error")?;
- ^0
+ 41| 1| write!(f, "cool")?;
+ ^0
42| | }
43| 10| for i in 0..10 {
44| 10| if false {
- 45| | } else {
+ 45| 0| } else {
46| 10| if false {
- 47| | while true {}
+ 47| 0| while true {}
48| 10| }
- 49| 10| write!(f, "error")?;
- ^0
+ 49| 10| write!(f, "cool")?;
+ ^0
50| | }
51| | }
52| 1| Ok(())
1| 1|fn main() {
2| 1| if false {
- 3| | loop {}
+ 3| 0| loop {}
4| 1| }
5| 1|}
} else {
return;
}
- } // Note: closing brace shows uncovered (vs. `0` for implicit else) because condition literal
- // `true` was const-evaluated. The compiler knows the `if` block will be executed.
+ }
+
let mut countdown = 0;
if true {
--- /dev/null
+#![feature(generators, generator_trait)]
+
+use std::ops::{Generator, GeneratorState};
+use std::pin::Pin;
+
+// The following implementation of a function called from a `yield` statement
+// (apparently requiring the Result and the `String` type or constructor)
+// creates conditions where the `generator::StateTransform` MIR transform will
+// drop all `Counter` `Coverage` statements from a MIR. `simplify.rs` has logic
+// to handle this condition, and still report dead block coverage.
+fn get_u32(val: bool) -> Result<u32, String> {
+ if val { Ok(1) } else { Err(String::from("some error")) }
+}
+
+fn main() {
+ let is_true = std::env::args().len() == 1;
+ let mut generator = || {
+ yield get_u32(is_true);
+ return "foo";
+ };
+
+ match Pin::new(&mut generator).resume(()) {
+ GeneratorState::Yielded(Ok(1)) => {}
+ _ => panic!("unexpected return from resume"),
+ }
+ match Pin::new(&mut generator).resume(()) {
+ GeneratorState::Complete("foo") => {}
+ _ => panic!("unexpected return from resume"),
+ }
+}
if true {
println!("Exiting with error...");
return Err(1);
- } // The remaining lines below have no coverage because `if true` (with the constant literal
- // `true`) is guaranteed to execute the `then` block, which is also guaranteed to `return`.
- // Thankfully, in the normal case, conditions are not guaranteed ahead of time, and as shown
- // in other tests, the lines below would have coverage (which would show they had `0`
- // executions, assuming the condition still evaluated to `true`).
+ }
+
+
+
+
let _ = Firework { strength: 1000 };
while true {
}
}
- write!(f, "error")?;
+ write!(f, "cool")?;
} else {
}
if false {
while true {}
}
- write!(f, "error")?;
+ write!(f, "cool")?;
} else {
}
}
if false {
while true {}
}
- write!(f, "error")?;
+ write!(f, "cool")?;
}
for i in 0..10 {
if false {
if false {
while true {}
}
- write!(f, "error")?;
+ write!(f, "cool")?;
}
}
Ok(())
#![feature(rustc_private)]
+#![deny(warnings)]
extern crate rustc_codegen_ssa;
extern crate rustc_errors;
use rustc_codegen_ssa::traits::CodegenBackend;
use rustc_codegen_ssa::{CodegenResults, CrateInfo};
use rustc_data_structures::fx::FxHashMap;
-use rustc_data_structures::sync::MetadataRef;
use rustc_errors::ErrorReported;
-use rustc_middle::dep_graph::DepGraph;
use rustc_middle::dep_graph::{WorkProduct, WorkProductId};
-use rustc_middle::middle::cstore::{EncodedMetadata, MetadataLoader, MetadataLoaderDyn};
-use rustc_middle::ty::query::Providers;
+use rustc_middle::middle::cstore::EncodedMetadata;
use rustc_middle::ty::TyCtxt;
use rustc_session::config::OutputFilenames;
use rustc_session::Session;
-use rustc_target::spec::Target;
use std::any::Any;
-use std::path::Path;
struct TheBackend;
impl CodegenBackend for TheBackend {
- fn metadata_loader(&self) -> Box<MetadataLoaderDyn> {
- Box::new(rustc_codegen_ssa::back::metadata::DefaultMetadataLoader)
- }
-
- fn provide(&self, providers: &mut Providers) {}
- fn provide_extern(&self, providers: &mut Providers) {}
-
fn codegen_crate<'a, 'tcx>(
&self,
tcx: TyCtxt<'tcx>,
metadata: EncodedMetadata,
_need_metadata_module: bool,
) -> Box<dyn Any> {
- use rustc_hir::def_id::LOCAL_CRATE;
-
Box::new(CodegenResults {
- crate_name: tcx.crate_name(LOCAL_CRATE),
modules: vec![],
allocator_module: None,
metadata_module: None,
metadata,
- windows_subsystem: None,
linker_info: LinkerInfo::new(tcx, "fake_target_cpu".to_string()),
crate_info: CrateInfo::new(tcx),
})
) -> Result<(), ErrorReported> {
use rustc_session::{config::CrateType, output::out_filename};
use std::io::Write;
- let crate_name = codegen_results.crate_name;
+ let crate_name = codegen_results.crate_info.local_crate_name;
for &crate_type in sess.opts.crate_types.iter() {
if crate_type != CrateType::Rlib {
sess.fatal(&format!("Crate type is {:?}", crate_type));
-#![feature(external_doc)]
-
-#[doc(include="input.md")]
+#[doc = include_str!("input.md")]
pub struct SomeStruct;
pub fn main() {
--- /dev/null
+# only-linux
+# ignore-32bit
+
+-include ../tools.mk
+
+all:
+ $(RUSTC) eh_frame-terminator.rs
+ $(call RUN,eh_frame-terminator) | $(CGREP) '1122334455667788'
+ objdump --dwarf=frames $(TMPDIR)/eh_frame-terminator | $(CGREP) 'ZERO terminator'
--- /dev/null
+// run-pass
+
+#![feature(backtrace)]
+#[derive(Clone, Copy)]
+struct Foo {
+ array: [u64; 10240],
+}
+
+impl Foo {
+ const fn new() -> Self {
+ Self {
+ array: [0x1122_3344_5566_7788; 10240]
+ }
+ }
+}
+
+static BAR: [Foo; 10240] = [Foo::new(); 10240];
+
+fn main() {
+ let bt = std::backtrace::Backtrace::force_capture();
+ println!("Hello, world! {:?}", bt);
+ println!("{:x}", BAR[0].array[0]);
+}
+++ /dev/null
--include ../tools.mk
-
-all:
- $(RUSTDOC) -Z unstable-options --print unversioned-files | sort | diff - unversioned-files.txt
+++ /dev/null
-COPYRIGHT.txt
-FiraSans-LICENSE.txt
-FiraSans-Medium.woff
-FiraSans-Medium.woff2
-FiraSans-Regular.woff
-FiraSans-Regular.woff2
-LICENSE-APACHE.txt
-LICENSE-MIT.txt
-SourceCodePro-It.ttf.woff
-SourceCodePro-LICENSE.txt
-SourceCodePro-Regular.ttf.woff
-SourceCodePro-Semibold.ttf.woff
-SourceSerif4-Bold.ttf.woff
-SourceSerif4-It.ttf.woff
-SourceSerif4-LICENSE.md
-SourceSerif4-Regular.ttf.woff
--- /dev/null
+include ../tools.mk
+
+# Test that rustdoc will properly canonicalize the target spec json path just like rustc
+
+OUTPUT_DIR := "$(TMPDIR)/rustdoc-target-spec-json-path"
+
+all:
+ $(RUSTC) --crate-type lib dummy_core.rs --target target.json
+ $(RUSTDOC) -o $(OUTPUT_DIR) -L $(TMPDIR) my_crate.rs --target target.json
--- /dev/null
+#![feature(no_core)]
+#![no_core]
--- /dev/null
+#![feature(no_core)]
+#![no_core]
+extern crate dummy_core;
--- /dev/null
+{
+ "arch": "x86_64",
+ "cpu": "x86-64",
+ "crt-static-respected": true,
+ "data-layout": "e-m:e-p270:32:32-p271:32:32-p272:64:64-i64:64-f80:128-n8:16:32:64-S128",
+ "dynamic-linking": true,
+ "env": "gnu",
+ "executables": true,
+ "has-elf-tls": true,
+ "has-rpath": true,
+ "is-builtin": true,
+ "linker-is-gnu": true,
+ "llvm-target": "x86_64-unknown-linux-gnu",
+ "max-atomic-width": 64,
+ "os": "linux",
+ "position-independent-executables": true,
+ "pre-link-args": {
+ "gcc": [
+ "-m64"
+ ]
+ },
+ "relro-level": "full",
+ "stack-probes": {
+ "kind": "inline-or-call",
+ "min-llvm-version-for-inline": [
+ 11,
+ 0,
+ 1
+ ]
+ },
+ "supported-sanitizers": [
+ "address",
+ "leak",
+ "memory",
+ "thread"
+ ],
+ "target-family": "unix",
+ "target-pointer-width": "64"
+}
#![feature(box_syntax)]
#![feature(rustc_private)]
#![feature(associated_type_defaults)]
-#![feature(external_doc)]
extern crate rustc_graphviz;
// A simple rust project
}
}
+#[doc = include_str!("extra-docs.md")]
+struct StructWithDocs;
+
trait Foo {
type Bar = FrameBuffer;
}
-
-#[doc(include = "extra-docs.md")]
-struct StructWithDocs;
--- /dev/null
+-include ../../run-make-fulldeps/tools.mk
+
+OUT=$(TMPDIR)/emit
+
+all: asm llvm-bc llvm-ir obj metadata link dep-info mir
+
+asm: $(OUT)
+ $(RUSTC) --emit asm=$(OUT)/libfoo.s foo.rs
+ test -f $(OUT)/libfoo.s
+llvm-bc: $(OUT)
+ $(RUSTC) --emit llvm-bc=$(OUT)/libfoo.bc foo.rs
+ test -f $(OUT)/libfoo.bc
+llvm-ir: $(OUT)
+ $(RUSTC) --emit llvm-ir=$(OUT)/libfoo.ll foo.rs
+ test -f $(OUT)/libfoo.ll
+obj: $(OUT)
+ $(RUSTC) --emit obj=$(OUT)/libfoo.o foo.rs
+ test -f $(OUT)/libfoo.o
+metadata: $(OUT)
+ $(RUSTC) --emit metadata=$(OUT)/libfoo.rmeta foo.rs
+ test -f $(OUT)/libfoo.rmeta
+link: $(OUT)
+ $(RUSTC) --emit link=$(OUT)/libfoo.rlib foo.rs
+ test -f $(OUT)/libfoo.rlib
+dep-info: $(OUT)
+ $(RUSTC) --emit dep-info=$(OUT)/libfoo.d foo.rs
+ test -f $(OUT)/libfoo.d
+mir: $(OUT)
+ $(RUSTC) --emit mir=$(OUT)/libfoo.mir foo.rs
+ test -f $(OUT)/libfoo.mir
+
+$(OUT):
+ mkdir -p $(OUT)
--- /dev/null
+#![crate_type = "rlib"]
--- /dev/null
+include ../../run-make-fulldeps/tools.mk
+
+SESSION_DIR := $(TMPDIR)/session
+OUTPUT_FILE := $(TMPDIR)/build-output
+
+all:
+ echo $(TMPDIR)
+ # Make it so that rustc will fail to create a session directory.
+ touch $(SESSION_DIR)
+ # Check exit code is 1 for an error, and not 101 for ICE.
+ $(RUSTC) foo.rs --crate-type=rlib -C incremental=$(SESSION_DIR) > $(OUTPUT_FILE) 2>&1; [ $$? -eq 1 ]
+ $(CGREP) "Could not create incremental compilation crate directory" < $(OUTPUT_FILE)
+ # -v tests are fragile, hopefully this text won't change
+ $(CGREP) -v "internal compiler error" < $(OUTPUT_FILE)
--- /dev/null
+// intentionally empty
--- /dev/null
+-include ../../run-make-fulldeps/tools.mk
+
+# needs-rust-lld
+all:
+ RUSTC_LOG=rustc_codegen_ssa::back::link=info $(RUSTC) -Z gcc-ld=lld -C link-args=-Wl,-v main.rs 2> $(TMPDIR)/output.txt
+ $(CGREP) -e "^LLD [0-9]+\.[0-9]+\.[0-9]+" < $(TMPDIR)/output.txt
--- /dev/null
+// test linking using cc with rust-lld injected into search path as ld
+// see rust-lang/rust#71519 for more info
+
+fn main() {}
--- /dev/null
+# Test the behavior of #[link(.., kind = "raw-dylib")] on windows-msvc
+
+# only-windows
+# only-msvc
+
+-include ../../run-make-fulldeps/tools.mk
+
+all:
+ $(call COMPILE_OBJ,"$(TMPDIR)"/extern_1.obj,extern_1.c)
+ $(call COMPILE_OBJ,"$(TMPDIR)"/extern_2.obj,extern_2.c)
+ $(CC) "$(TMPDIR)"/extern_1.obj -link -dll -out:"$(TMPDIR)"/extern_1.dll
+ $(CC) "$(TMPDIR)"/extern_2.obj -link -dll -out:"$(TMPDIR)"/extern_2.dll
+ $(RUSTC) --crate-type lib --crate-name raw_dylib_test lib.rs
+ $(RUSTC) --crate-type bin driver.rs -L "$(TMPDIR)"
+ "$(TMPDIR)"/driver > "$(TMPDIR)"/output.txt
+
+ifdef RUSTC_BLESS_TEST
+ cp "$(TMPDIR)"/output.txt output.txt
+else
+ $(DIFF) output.txt "$(TMPDIR)"/output.txt
+endif
--- /dev/null
+extern crate raw_dylib_test;
+
+fn main() {
+ raw_dylib_test::library_function();
+}
--- /dev/null
+#include <stdio.h>
+
+__declspec(dllexport) void extern_fn_1() {
+ printf("extern_fn_1\n");
+ fflush(stdout);
+}
+
+__declspec(dllexport) void extern_fn_2() {
+ printf("extern_fn_2; didn't get the rename\n");
+ fflush(stdout);
+}
+
+__declspec(dllexport) void extern_fn_with_long_name() {
+ printf("extern_fn_with_long_name; got the rename\n");
+ fflush(stdout);
+}
--- /dev/null
+#include <stdio.h>
+
+__declspec(dllexport) void extern_fn_3() {
+ printf("extern_fn_3\n");
+ fflush(stdout);
+}
--- /dev/null
+#![feature(raw_dylib, native_link_modifiers, native_link_modifiers_verbatim)]
+
+#[link(name = "extern_1.dll", kind = "raw-dylib", modifiers = "+verbatim")]
+extern {
+ fn extern_fn_1();
+}
+
+#[link(name = "extern_2", kind = "raw-dylib")]
+extern {
+ fn extern_fn_3();
+}
+
+pub fn library_function() {
+ #[link(name = "extern_1", kind = "raw-dylib")]
+ extern { fn extern_fn_2(); }
+
+ unsafe {
+ extern_fn_1();
+ extern_fn_2();
+ extern_fn_3();
+ }
+}
--- /dev/null
+extern_fn_1
+extern_fn_2; didn't get the rename
+extern_fn_3
all:
$(RUSTDOC) --output-format=json x.html 2>&1 | diff - output-format-json.stderr
+ $(RUSTC) --force-warns dead_code x.rs 2>&1 | diff - force-warns.stderr
--- /dev/null
+error: the `-Z unstable-options` flag must also be passed to enable the flag `--force-warns=lints`
+
--- /dev/null
+goto: file://|DOC_PATH|/lib2/struct.Foo.html
+// This test checks that the font weight is correctly applied.
+assert: ("//*[@class='docblock type-decl']//a[text()='Alias']", {"font-weight": "400"})
+assert: ("//*[@class='structfield small-section-header']//a[text()='Alias']", {"font-weight": "400"})
+assert: ("#method\.a_method > code", {"font-weight": "600"})
+assert: ("#associatedtype\.X > code", {"font-weight": "600"})
+assert: ("#associatedconstant\.Y > code", {"font-weight": "600"})
--- /dev/null
+goto: file://|DOC_PATH|/test_docs/index.html
+// We set the theme so we're sure that the corect values will be used, whatever the computer
+// this test is running on.
+local-storage: {"rustdoc-theme": "dark", "rustdoc-preferred-dark-theme": "dark", "rustdoc-use-system-theme": "false"}
+// If the text isn't displayed, the browser doesn't compute color style correctly...
+show-text: true
+// We reload the page so the local storage settings are being used.
+reload:
+write: (".search-input", "thisisanalias")
+// Waiting for the search results to appear...
+wait-for: "#titles"
+// Checking that the colors for the alias element are the ones expected.
+assert: (".result-name > .alias", {"color": "rgb(255, 255, 255)"})
+assert: (".result-name > .alias > .grey", {"color": "rgb(204, 204, 204)"})
--- /dev/null
+// This test is to ensure that the codeblocks are correctly rendered in the search results.
+goto: file://|DOC_PATH|/test_docs/index.html?search=some_more_function
+// Waiting for the search results to appear...
+wait-for: "#titles"
+assert: (".search-results .desc code", "format!")
// Note: The two next assert commands could be merged as one but readability would be
// less good.
//
-// Checking that the CSS is displaying " (keyword)"...
-assert: (".result-name span.keyword::after", {"content": '" (keyword)"'})
-// ... in italic.
-assert: (".result-name span.keyword::after", {"font-style": "italic"})
+// Checking that the CSS is displaying " (keyword)" in italic.
+assert: (".result-name span.keyword > i", "(keyword)")
+assert: (".result-name span.keyword", "CookieMonster (keyword)")
--- /dev/null
+goto: file://|DOC_PATH|/test_docs/index.html
+assert: (".sidebar > .location", "Crate test_docs")
+// In modules, we only have one "location" element.
+assert: (".sidebar .location", 1)
+assert: (".sidebar-elems > #all-types", "See all test_docs's items")
+// We check that we have the crates list and that the "current" on is "test_docs".
+assert: (".sidebar-elems > .crate > ul > li > a.current", "test_docs")
+// And we're also supposed to have the list of items in the current module.
+assert: (".sidebar-elems > .items > ul > li:nth-child(1)", "Modules")
+assert: (".sidebar-elems > .items > ul > li:nth-child(2)", "Structs")
+assert: (".sidebar-elems > .items > ul > li:nth-child(3)", "Enums")
+assert: (".sidebar-elems > .items > ul > li:nth-child(4)", "Traits")
+assert: (".sidebar-elems > .items > ul > li:nth-child(5)", "Functions")
+assert: (".sidebar-elems > .items > ul > li:nth-child(6)", "Type Definitions")
+assert: (".sidebar-elems > .items > ul > li:nth-child(7)", "Keywords")
+assert: ("#structs + table td > a", "Foo")
+click: "#structs + table td > a"
+
+// PAGE: struct.Foo.html
+assert: (".sidebar .location", 2)
+// We check that there is no crate listed outside of the top level.
+assert-false: ".sidebar-elems > .crate"
+// We now go back to the crate page to click on the "lib2" crate link.
+goto: file://|DOC_PATH|/test_docs/index.html
+click: ".sidebar-elems > .crate > ul > li:first-child > a"
+
+// PAGE: lib2/index.html
+goto: file://|DOC_PATH|/lib2/index.html
+assert: (".sidebar > .location", "Crate lib2")
+// We check that we have the crates list and that the "current" on is now "lib2".
+assert: (".sidebar-elems > .crate > ul > li > a.current", "lib2")
+// We now go to the "foobar" function page.
+assert: (".sidebar-elems > .items > ul > li:nth-child(1)", "Modules")
+assert: (".sidebar-elems > .items > ul > li:nth-child(2)", "Structs")
+assert: (".sidebar-elems > .items > ul > li:nth-child(3)", "Traits")
+assert: (".sidebar-elems > .items > ul > li:nth-child(4)", "Functions")
+assert: (".sidebar-elems > .items > ul > li:nth-child(5)", "Type Definitions")
+assert: ("#functions + table td > a", "foobar")
+click: "#functions + table td > a"
+
+// PAGE: fn.foobar.html
+// In items containing no items (like functions or constants) and in modules, we have one
+// "location" elements.
+assert: (".sidebar .location", 1)
+// There is a "<br>" tag between "in" and "lib2", but it doesn't count as a space.
+assert: (".sidebar .sidebar-elems .location", "Other items inlib2")
+// We check that we don't have the crate list.
+assert-false: ".sidebar-elems > .crate"
+
+goto: ./module/index.html
+assert: (".sidebar > .location", "Module module")
+// We check that we don't have the crate list.
+assert-false: ".sidebar-elems > .crate"
+
+goto: ./sub_module/sub_sub_module/index.html
+assert: (".sidebar > .location", "Module sub_sub_module")
+// We check that we don't have the crate list.
+assert-false: ".sidebar-elems > .crate"
+assert: (".sidebar-elems > .items > ul > li:nth-child(1)", "Functions")
+assert: ("#functions + table td > a", "foo")
}
/// Just a normal enum.
+#[doc(alias = "ThisIsAnAlias")]
pub enum WhoLetTheDogOut {
/// Woof!
Woof,
#[doc(keyword = "CookieMonster")]
pub mod keyword {}
+
+/// Just some type alias.
+pub type SomeType = u32;
--- /dev/null
+pub mod module {
+ pub mod sub_module {
+ pub mod sub_sub_module {
+ pub fn foo() {}
+ }
+ pub fn bar() {}
+ }
+ pub fn whatever() {}
+}
+
+pub fn foobar() {}
+
+pub type Alias = u32;
+
+pub struct Foo {
+ pub x: Alias,
+}
+
+impl Foo {
+ pub fn a_method(&self) {}
+}
+
+pub trait Trait {
+ type X;
+ const Y: u32;
+}
+
+impl Trait for Foo {
+ type X = u32;
+ const Y: u32 = 0;
+}
--- /dev/null
+// This tests that the "implementations" section on struct/enum pages
+// has all the implementations toggled open by default, so users can
+// find method names in those implementations with Ctrl-F.
+goto: file://|DOC_PATH|/test_docs/struct.Foo.html
+assert: (".rustdoc-toggle.implementors-toggle", "open", "")
--- /dev/null
+goto: file://|DOC_PATH|/test_docs/type.SomeType.html
+assert-all: (".top-block .docblock p", {"font-weight": "400"})
// check-pass
// compile-flags: -Z unstable-options --check
+// normalize-stderr-test: "nightly|beta|1\.[0-9][0-9]\.[0-9]" -> "$$CHANNEL"
#![warn(missing_docs)]
//~^ WARN
warning: missing documentation for the crate
- --> $DIR/check.rs:4:1
+ --> $DIR/check.rs:5:1
|
LL | / #![warn(missing_docs)]
LL | |
| |_______________^
|
note: the lint level is defined here
- --> $DIR/check.rs:4:9
+ --> $DIR/check.rs:5:9
|
LL | #![warn(missing_docs)]
| ^^^^^^^^^^^^
warning: missing documentation for a function
- --> $DIR/check.rs:9:1
+ --> $DIR/check.rs:10:1
|
LL | pub fn foo() {}
| ^^^^^^^^^^^^
warning: no documentation found for this crate's top-level module
|
note: the lint level is defined here
- --> $DIR/check.rs:7:9
+ --> $DIR/check.rs:8:9
|
LL | #![warn(rustdoc::all)]
| ^^^^^^^^^^^^
= note: `#[warn(rustdoc::missing_crate_level_docs)]` implied by `#[warn(rustdoc::all)]`
= help: The following guide may be of use:
- https://doc.rust-lang.org/nightly/rustdoc/how-to-write-documentation.html
+ https://doc.rust-lang.org/$CHANNEL/rustdoc/how-to-write-documentation.html
warning: missing code example in this documentation
- --> $DIR/check.rs:4:1
+ --> $DIR/check.rs:5:1
|
LL | / #![warn(missing_docs)]
LL | |
| |_______________^
|
note: the lint level is defined here
- --> $DIR/check.rs:7:9
+ --> $DIR/check.rs:8:9
|
LL | #![warn(rustdoc::all)]
| ^^^^^^^^^^^^
= note: `#[warn(rustdoc::missing_doc_code_examples)]` implied by `#[warn(rustdoc::all)]`
warning: missing code example in this documentation
- --> $DIR/check.rs:9:1
+ --> $DIR/check.rs:10:1
|
LL | pub fn foo() {}
| ^^^^^^^^^^^^^^^
+++ /dev/null
-// check-pass
-// #26207: Ensure `Deref` cycles are properly handled without errors.
-
-#[derive(Copy, Clone)]
-struct S;
-
-impl std::ops::Deref for S {
- type Target = S;
-
- fn deref(&self) -> &S {
- self
- }
-}
-
-fn main() {
- let s: S = *******S;
-}
--- /dev/null
+// check-pass
+
+#[doc(include = "external-cross-doc.md")]
+//~^ WARNING unknown `doc` attribute `include`
+//~| HELP use `doc = include_str!` instead
+// FIXME(#85497): make this a deny instead so it's more clear what's happening
+//~| NOTE on by default
+//~| WARNING previously accepted
+//~| NOTE see issue #82730
+pub struct NeedMoreDocs;
--- /dev/null
+warning: unknown `doc` attribute `include`
+ --> $DIR/doc-include-suggestion.rs:3:7
+ |
+LL | #[doc(include = "external-cross-doc.md")]
+ | ------^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^-- help: use `doc = include_str!` instead: `#[doc = include_str!("external-cross-doc.md")]`
+ |
+ = note: `#[warn(invalid_doc_attributes)]` on by default
+ = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
+ = note: for more information, see issue #82730 <https://github.com/rust-lang/rust/issues/82730>
+
+warning: 1 warning emitted
+
-// check-pass
// run-rustfix
-
+#![deny(warnings)]
#![feature(doc_notable_trait)]
#[doc(notable_trait)]
-//~^ WARN unknown `doc` attribute `spotlight`
+//~^ ERROR unknown `doc` attribute `spotlight`
//~| WARN this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
trait MyTrait {}
-// check-pass
// run-rustfix
-
+#![deny(warnings)]
#![feature(doc_notable_trait)]
#[doc(spotlight)]
-//~^ WARN unknown `doc` attribute `spotlight`
+//~^ ERROR unknown `doc` attribute `spotlight`
//~| WARN this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
trait MyTrait {}
-warning: unknown `doc` attribute `spotlight`
- --> $DIR/doc-spotlight.rs:6:7
+error: unknown `doc` attribute `spotlight`
+ --> $DIR/doc-spotlight.rs:5:7
|
LL | #[doc(spotlight)]
| ^^^^^^^^^ help: use `notable_trait` instead
|
- = note: `#[warn(invalid_doc_attributes)]` on by default
+note: the lint level is defined here
+ --> $DIR/doc-spotlight.rs:2:9
+ |
+LL | #![deny(warnings)]
+ | ^^^^^^^^
+ = note: `#[deny(invalid_doc_attributes)]` implied by `#[deny(warnings)]`
= warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
= note: for more information, see issue #82730 <https://github.com/rust-lang/rust/issues/82730>
= note: `doc(spotlight)` was renamed to `doc(notable_trait)`
= note: `doc(spotlight)` is now a no-op
-warning: 1 warning emitted
+error: aborting due to previous error
running 1 test
-test $DIR/failed-doctest-compile-fail.rs - Foo (line 9) ... FAILED
+test $DIR/failed-doctest-compile-fail.rs - Foo (line 9) - compile fail ... FAILED
failures:
running 1 test
-test $DIR/failed-doctest-missing-codes.rs - Foo (line 9) ... FAILED
+test $DIR/failed-doctest-missing-codes.rs - Foo (line 9) - compile fail ... FAILED
failures:
+// normalize-stderr-test: "nightly|beta|1\.[0-9][0-9]\.[0-9]" -> "$$CHANNEL"
#![deny(warnings)]
//! Email me at <hello@localhost>.
error: unknown disambiguator `hello`
- --> $DIR/email-address-localhost.rs:3:18
+ --> $DIR/email-address-localhost.rs:4:18
|
LL | //! Email me at <hello@localhost>.
| ^^^^^
|
note: the lint level is defined here
- --> $DIR/email-address-localhost.rs:1:9
+ --> $DIR/email-address-localhost.rs:2:9
|
LL | #![deny(warnings)]
| ^^^^^^^^
= note: `#[deny(rustdoc::broken_intra_doc_links)]` implied by `#[deny(warnings)]`
- = note: see https://doc.rust-lang.org/nightly/rustdoc/linking-to-items-by-name.html#namespaces-and-disambiguators for more info about disambiguators
+ = note: see https://doc.rust-lang.org/$CHANNEL/rustdoc/linking-to-items-by-name.html#namespaces-and-disambiguators for more info about disambiguators
error: aborting due to previous error
+// normalize-stderr-test: "nightly|beta|1\.[0-9][0-9]\.[0-9]" -> "$$CHANNEL"
#![deny(warnings)]
//! Linking to [foo@banana] and [`bar@banana!()`].
error: unknown disambiguator `foo`
- --> $DIR/unknown-disambiguator.rs:3:17
+ --> $DIR/unknown-disambiguator.rs:4:17
|
LL | //! Linking to [foo@banana] and [`bar@banana!()`].
| ^^^
|
note: the lint level is defined here
- --> $DIR/unknown-disambiguator.rs:1:9
+ --> $DIR/unknown-disambiguator.rs:2:9
|
LL | #![deny(warnings)]
| ^^^^^^^^
= note: `#[deny(rustdoc::broken_intra_doc_links)]` implied by `#[deny(warnings)]`
- = note: see https://doc.rust-lang.org/nightly/rustdoc/linking-to-items-by-name.html#namespaces-and-disambiguators for more info about disambiguators
+ = note: see https://doc.rust-lang.org/$CHANNEL/rustdoc/linking-to-items-by-name.html#namespaces-and-disambiguators for more info about disambiguators
error: unknown disambiguator `bar`
- --> $DIR/unknown-disambiguator.rs:3:35
+ --> $DIR/unknown-disambiguator.rs:4:35
|
LL | //! Linking to [foo@banana] and [`bar@banana!()`].
| ^^^
|
- = note: see https://doc.rust-lang.org/nightly/rustdoc/linking-to-items-by-name.html#namespaces-and-disambiguators for more info about disambiguators
+ = note: see https://doc.rust-lang.org/$CHANNEL/rustdoc/linking-to-items-by-name.html#namespaces-and-disambiguators for more info about disambiguators
error: unknown disambiguator `foo`
- --> $DIR/unknown-disambiguator.rs:9:34
+ --> $DIR/unknown-disambiguator.rs:10:34
|
LL | //! And with weird backticks: [``foo@hello``] [foo`@`hello].
| ^^^
|
- = note: see https://doc.rust-lang.org/nightly/rustdoc/linking-to-items-by-name.html#namespaces-and-disambiguators for more info about disambiguators
+ = note: see https://doc.rust-lang.org/$CHANNEL/rustdoc/linking-to-items-by-name.html#namespaces-and-disambiguators for more info about disambiguators
error: unknown disambiguator `foo`
- --> $DIR/unknown-disambiguator.rs:9:48
+ --> $DIR/unknown-disambiguator.rs:10:48
|
LL | //! And with weird backticks: [``foo@hello``] [foo`@`hello].
| ^^^
|
- = note: see https://doc.rust-lang.org/nightly/rustdoc/linking-to-items-by-name.html#namespaces-and-disambiguators for more info about disambiguators
+ = note: see https://doc.rust-lang.org/$CHANNEL/rustdoc/linking-to-items-by-name.html#namespaces-and-disambiguators for more info about disambiguators
error: unknown disambiguator ``
- --> $DIR/unknown-disambiguator.rs:6:31
+ --> $DIR/unknown-disambiguator.rs:7:31
|
LL | //! And to [no disambiguator](@nectarine) and [another](@apricot!()).
| ^
|
- = note: see https://doc.rust-lang.org/nightly/rustdoc/linking-to-items-by-name.html#namespaces-and-disambiguators for more info about disambiguators
+ = note: see https://doc.rust-lang.org/$CHANNEL/rustdoc/linking-to-items-by-name.html#namespaces-and-disambiguators for more info about disambiguators
error: unknown disambiguator ``
- --> $DIR/unknown-disambiguator.rs:6:57
+ --> $DIR/unknown-disambiguator.rs:7:57
|
LL | //! And to [no disambiguator](@nectarine) and [another](@apricot!()).
| ^
|
- = note: see https://doc.rust-lang.org/nightly/rustdoc/linking-to-items-by-name.html#namespaces-and-disambiguators for more info about disambiguators
+ = note: see https://doc.rust-lang.org/$CHANNEL/rustdoc/linking-to-items-by-name.html#namespaces-and-disambiguators for more info about disambiguators
error: aborting due to 6 previous errors
running 1 test
-test $DIR/issue-80992.rs - test (line 7) ... ok
+test $DIR/issue-80992.rs - test (line 7) - compile fail ... ok
test result: ok. 1 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished in $TIME
// error-pattern: no documentation found
+// normalize-stderr-test: "nightly|beta|1\.[0-9][0-9]\.[0-9]" -> "$$CHANNEL"
#![deny(rustdoc::missing_crate_level_docs)]
//^~ NOTE defined here
error: no documentation found for this crate's top-level module
|
note: the lint level is defined here
- --> $DIR/no-crate-level-doc-lint.rs:2:9
+ --> $DIR/no-crate-level-doc-lint.rs:3:9
|
LL | #![deny(rustdoc::missing_crate_level_docs)]
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
= help: The following guide may be of use:
- https://doc.rust-lang.org/nightly/rustdoc/how-to-write-documentation.html
+ https://doc.rust-lang.org/$CHANNEL/rustdoc/how-to-write-documentation.html
error: aborting due to previous error
running 7 tests
-test $DIR/no-run-flag.rs - f (line 11) ... ok
+test $DIR/no-run-flag.rs - f (line 11) - compile ... ok
test $DIR/no-run-flag.rs - f (line 14) ... ignored
-test $DIR/no-run-flag.rs - f (line 17) ... ok
-test $DIR/no-run-flag.rs - f (line 23) ... ok
-test $DIR/no-run-flag.rs - f (line 28) ... ok
-test $DIR/no-run-flag.rs - f (line 32) ... ok
-test $DIR/no-run-flag.rs - f (line 8) ... ok
+test $DIR/no-run-flag.rs - f (line 17) - compile ... ok
+test $DIR/no-run-flag.rs - f (line 23) - compile fail ... ok
+test $DIR/no-run-flag.rs - f (line 28) - compile ... ok
+test $DIR/no-run-flag.rs - f (line 32) - compile ... ok
+test $DIR/no-run-flag.rs - f (line 8) - compile ... ok
test result: ok. 6 passed; 0 failed; 1 ignored; 0 measured; 0 filtered out; finished in $TIME
// revisions: correct incorrect
// check-pass
-// [correct]compile-flags:--test --test-run-directory={{src-base}}
-// [incorrect]compile-flags:--test --test-run-directory={{src-base}}/coverage
+// [correct]compile-flags:--test --test-run-directory={{src-base}} -Zunstable-options
+// [incorrect]compile-flags:--test --test-run-directory={{src-base}}/coverage -Zunstable-options
// normalize-stdout-test: "src/test/rustdoc-ui" -> "$$DIR"
// normalize-stdout-test "finished in \d+\.\d+s" -> "finished in $$TIME"
--- /dev/null
+// compile-flags: --test --test-args=--test-threads=1
+// check-pass
+// normalize-stdout-test: "src/test/rustdoc-ui" -> "$$DIR"
+// normalize-stdout-test "finished in \d+\.\d+s" -> "finished in $$TIME"
+
+/// ```
+/// let a = true;
+/// ```
+/// ```should_panic
+/// panic!()
+/// ```
+/// ```ignore (incomplete-code)
+/// fn foo() {
+/// ```
+/// ```no_run
+/// loop {
+/// println!("Hello, world");
+/// }
+/// ```
+/// fails to compile
+/// ```compile_fail
+/// let x = 5;
+/// x += 2; // shouldn't compile!
+/// ```
+
+pub fn f() {}
--- /dev/null
+
+running 5 tests
+test $DIR/test-type.rs - f (line 12) ... ignored
+test $DIR/test-type.rs - f (line 15) - compile ... ok
+test $DIR/test-type.rs - f (line 21) - compile fail ... ok
+test $DIR/test-type.rs - f (line 6) ... ok
+test $DIR/test-type.rs - f (line 9) ... ok
+
+test result: ok. 4 passed; 0 failed; 1 ignored; 0 measured; 0 filtered out; finished in $TIME
+
--- /dev/null
+// check-pass
+
+#[cfg(any(target_arch = "wasm32", doc))]
+#[target_feature(enable = "simd128")]
+pub fn foo() {}
/// Docs for QUX1 in impl.
const QUX1: i8 = 5;
// @has - '//*[@id="associatedconstant.QUX_DEFAULT0"]' 'const QUX_DEFAULT0: u16'
- // @!has - '//div[@class="impl-items"]/details[@open=""]//*[@class="docblock"]' "Docs for QUX_DEFAULT12 in trait."
- // @has - '//div[@class="impl-items"]/details//*[@class="docblock"]' "Docs for QUX_DEFAULT12 in trait."
+ // @has - '//div[@class="impl-items"]//*[@class="docblock"]' "Docs for QUX_DEFAULT12 in trait."
const QUX_DEFAULT0: u16 = 6;
// @has - '//*[@id="associatedconstant.QUX_DEFAULT1"]' 'const QUX_DEFAULT1: i16'
// @has - '//*[@class="docblock"]' "Docs for QUX_DEFAULT1 in impl."
/// Docs for QUX_DEFAULT1 in impl.
const QUX_DEFAULT1: i16 = 7;
// @has - '//*[@id="associatedconstant.QUX_DEFAULT2"]' 'const QUX_DEFAULT2: u32'
- // @!has - '//div[@class="impl-items"]/details[@open=""]//*[@class="docblock"]' "Docs for QUX_DEFAULT2 in trait."
- // @has - '//div[@class="impl-items"]/details//*[@class="docblock"]' "Docs for QUX_DEFAULT2 in trait."
+ // @has - '//div[@class="impl-items"]//*[@class="docblock"]' "Docs for QUX_DEFAULT2 in trait."
}
impl Foo {
// @has async_fn/struct.Foo.html
- // @has - '//h4[@class="method"]' 'pub async fn complicated_lifetimes( &self, context: &impl Bar) -> impl Iterator<Item = &usize>'
+ // @has - '//div[@class="method has-srclink"]' 'pub async fn complicated_lifetimes( &self, context: &impl Bar) -> impl Iterator<Item = &usize>'
pub async fn complicated_lifetimes(&self, context: &impl Bar) -> impl Iterator<Item = &usize> {}
// taken from `tokio` as an example of a method that was particularly bad before
- // @has - '//h4[@class="method"]' "pub async fn readable<T>(&self) -> Result<AsyncFdReadyGuard<'_, T>, ()>"
+ // @has - '//div[@class="method has-srclink"]' "pub async fn readable<T>(&self) -> Result<AsyncFdReadyGuard<'_, T>, ()>"
pub async fn readable<T>(&self) -> Result<AsyncFdReadyGuard<'_, T>, ()> {}
- // @has - '//h4[@class="method"]' "pub async fn mut_self(&mut self)"
+ // @has - '//div[@class="method has-srclink"]' "pub async fn mut_self(&mut self)"
pub async fn mut_self(&mut self) {}
}
#[export_name = "bar"]
pub extern "C" fn g() {}
-// @matches foo/enum.Foo.html '//*[@class="rust enum"]' \
-// '#\[repr\(i64\)\]\n#\[must_use\]'
-#[repr(i64)]
-#[must_use]
-pub enum Foo {
- Bar,
-}
-
// @has foo/struct.Repr.html '//*[@class="docblock type-decl"]' '#[repr(C, align(8))]'
#[repr(C, align(8))]
pub struct Repr;
#![feature(auto_traits)]
-// @has auto_aliases/trait.Bar.html '//h3[@data-aliases="auto_aliases::Foo"]' 'impl Bar for Foo'
+// @has auto_aliases/trait.Bar.html '//div[@data-aliases="auto_aliases::Foo"]' 'impl Bar for Foo'
pub struct Foo;
pub auto trait Bar {}
# Cross-crate imported docs
-This file is to make sure `#[doc(include="file.md")]` works when you re-export an item with included
+This file is to make sure `#[doc = include_str!("file.md")]` works when you re-export an item with included
docs.
-#![feature(external_doc)]
-#![deny(missing_doc)]
-
-#[doc(include="external-cross-doc.md")]
+#[deny(missing_docs)]
+#[doc = include_str!("external-cross-doc.md")]
pub struct NeedMoreDocs;
# External Docs
-This file is here to test the `#[doc(include="file")]` attribute.
+This file is here to test the `#[doc = include_str!("file")]` attribute.
#![crate_name = "foo"]
-// @has foo/struct.S.html '//h3[@id="impl-Into%3CU%3E"]//code' 'impl<T, U> Into<U> for T'
+// @has foo/struct.S.html '//div[@id="impl-Into%3CU%3E"]//code' 'impl<T, U> Into<U> for T'
pub struct S2 {}
mod m {
pub struct S {}
// therefore should not concern itself with the lints.
#[deny(warnings)]
-// @has cap_lints/struct.Foo.html //pre '#[must_use]'
-#[must_use]
+// @has cap_lints/struct.Foo.html //* 'Struct Foo'
pub struct Foo {
field: i32,
}
pub struct Foo;
impl Foo {
- // @has 'foo/struct.Foo.html' '//h4[@id="method.gated"]/code' 'pub unsafe fn gated() -> u32'
+ // @has 'foo/struct.Foo.html' '//div[@id="method.gated"]/code' 'pub unsafe fn gated() -> u32'
#[stable(feature = "rust1", since = "1.0.0")]
#[rustc_const_unstable(feature="foo", issue = "none")]
pub const unsafe fn gated() -> u32 { 42 }
- // @has 'foo/struct.Foo.html' '//h4[@id="method.stable_impl"]/code' 'pub const fn stable_impl() -> u32'
+ // @has 'foo/struct.Foo.html' '//div[@id="method.stable_impl"]/code' 'pub const fn stable_impl() -> u32'
// @has - '//span[@class="since"]' '1.0.0 (const: 1.2.0)'
#[stable(feature = "rust1", since = "1.0.0")]
#[rustc_const_stable(feature = "rust1", since = "1.2.0")]
}
// @has foo/struct.Foo.html
-// @has - '//*[@class="method"]' 'const fn new()'
+// @has - '//*[@class="method has-srclink"]' 'const fn new()'
pub struct Foo(usize);
impl Foo {
inner: T,
}
-// @has foo/struct.Simd.html '//div[@id="trait-implementations-list"]//h3/code' 'impl Add<Simd<u8, 16_usize>> for Simd<u8, 16>'
+// @has foo/struct.Simd.html '//div[@id="trait-implementations-list"]//div/code' 'impl Add<Simd<u8, 16_usize>> for Simd<u8, 16>'
impl Add for Simd<u8, 16> {
type Output = Self;
--- /dev/null
+#![crate_name = "foo"]
+#![feature(const_evaluatable_checked, const_generics)]
+#![allow(incomplete_features)]
+// make sure that `ConstEvaluatable` predicates dont cause rustdoc to ICE #77647
+// @has foo/struct.Ice.html '//pre[@class="rust struct"]' \
+// 'pub struct Ice<const N: usize> where [(); N + 1]: ;'
+pub struct Ice<const N: usize> where [(); N + 1]:;
--- /dev/null
+#![crate_name = "foo"]
+#![feature(const_generics_defaults)]
+
+// @has foo/struct.Foo.html '//pre[@class="rust struct"]' \
+// 'pub struct Foo<const M: usize = 10_usize, const N: usize = M, T = i32>(_);'
+pub struct Foo<const M: usize = 10, const N: usize = M, T = i32>(T);
}
// @has foo/trait.Array.html
-// @has - '//h3[@class="impl"]' 'impl<T, const N: usize> Array for [T; N]'
+// @has - '//div[@class="impl has-srclink"]' 'impl<T, const N: usize> Array for [T; N]'
impl <T, const N: usize> Array for [T; N] {
type Item = T;
}
// @has foo/struct.Bar.html '//pre[@class="rust struct"]' 'pub struct Bar<T, const N: usize>(_)'
pub struct Bar<T, const N: usize>([T; N]);
-// @has foo/struct.Foo.html '//h3[@id="impl"]/code' 'impl<const M: usize> Foo<M> where u8: Trait<M>'
+// @has foo/struct.Foo.html '//div[@id="impl"]/code' 'impl<const M: usize> Foo<M> where u8: Trait<M>'
impl<const M: usize> Foo<M> where u8: Trait<M> {
// @has - '//*[@id="associatedconstant.FOO_ASSOC"]' 'pub const FOO_ASSOC: usize'
pub const FOO_ASSOC: usize = M + 13;
}
}
-// @has foo/struct.Bar.html '//h3[@id="impl"]/code' 'impl<const M: usize> Bar<u8, M>'
+// @has foo/struct.Bar.html '//div[@id="impl"]/code' 'impl<const M: usize> Bar<u8, M>'
impl<const M: usize> Bar<u8, M> {
// @has - '//*[@id="method.hey"]' \
// 'pub fn hey<const N: usize>(&self) -> Foo<N> where u8: Trait<N>'
}
// @has foo/struct.VSet.html '//pre[@class="rust struct"]' 'pub struct VSet<T, const ORDER: Order>'
-// @has foo/struct.VSet.html '//h3[@id="impl-Send"]/code' 'impl<T, const ORDER: Order> Send for VSet<T, ORDER>'
-// @has foo/struct.VSet.html '//h3[@id="impl-Sync"]/code' 'impl<T, const ORDER: Order> Sync for VSet<T, ORDER>'
+// @has foo/struct.VSet.html '//div[@id="impl-Send"]/code' 'impl<T, const ORDER: Order> Send for VSet<T, ORDER>'
+// @has foo/struct.VSet.html '//div[@id="impl-Sync"]/code' 'impl<T, const ORDER: Order> Sync for VSet<T, ORDER>'
pub struct VSet<T, const ORDER: Order> {
inner: Vec<T>,
}
-// @has foo/struct.VSet.html '//h3[@id="impl"]/code' 'impl<T> VSet<T, {Order::Sorted}>'
+// @has foo/struct.VSet.html '//div[@id="impl"]/code' 'impl<T> VSet<T, {Order::Sorted}>'
impl <T> VSet<T, {Order::Sorted}> {
pub fn new() -> Self {
Self { inner: Vec::new() }
}
}
-// @has foo/struct.VSet.html '//h3[@id="impl-1"]/code' 'impl<T> VSet<T, {Order::Unsorted}>'
+// @has foo/struct.VSet.html '//div[@id="impl-1"]/code' 'impl<T> VSet<T, {Order::Unsorted}>'
impl <T> VSet<T, {Order::Unsorted}> {
pub fn new() -> Self {
Self { inner: Vec::new() }
pub struct Escape<const S: &'static str>;
-// @has foo/struct.Escape.html '//h3[@id="impl"]/code' 'impl Escape<{ r#"<script>alert("Escape");</script>"# }>'
+// @has foo/struct.Escape.html '//div[@id="impl"]/code' 'impl Escape<{ r#"<script>alert("Escape");</script>"# }>'
impl Escape<{ r#"<script>alert("Escape");</script>"# }> {
pub fn f() {}
}
+++ /dev/null
-// #26207: Show all methods reachable via Deref impls, recursing through multiple dereferencing
-// levels and across multiple crates.
-
-// @has 'foo/struct.Foo.html'
-// @has '-' '//*[@id="deref-methods-PathBuf"]' 'Methods from Deref<Target = PathBuf>'
-// @has '-' '//*[@class="impl-items"]//*[@id="method.as_path"]' 'pub fn as_path(&self)'
-// @has '-' '//*[@id="deref-methods-Path"]' 'Methods from Deref<Target = Path>'
-// @has '-' '//*[@class="impl-items"]//*[@id="method.exists"]' 'pub fn exists(&self)'
-// @has '-' '//*[@class="sidebar-title"][@href="#deref-methods-PathBuf"]' 'Methods from Deref<Target=PathBuf>'
-// @has '-' '//*[@class="sidebar-links"]/a[@href="#method.as_path"]' 'as_path'
-// @has '-' '//*[@class="sidebar-title"][@href="#deref-methods-Path"]' 'Methods from Deref<Target=Path>'
-// @has '-' '//*[@class="sidebar-links"]/a[@href="#method.exists"]' 'exists'
-
-#![crate_name = "foo"]
-
-use std::ops::Deref;
-use std::path::PathBuf;
-
-pub struct Foo(PathBuf);
-
-impl Deref for Foo {
- type Target = PathBuf;
- fn deref(&self) -> &PathBuf { &self.0 }
-}
+++ /dev/null
-// #26207: Show all methods reachable via Deref impls, recursing through multiple dereferencing
-// levels if needed.
-
-// @has 'foo/struct.Foo.html'
-// @has '-' '//*[@id="deref-methods-Bar"]' 'Methods from Deref<Target = Bar>'
-// @has '-' '//*[@class="impl-items"]//*[@id="method.bar"]' 'pub fn bar(&self)'
-// @has '-' '//*[@id="deref-methods-Baz"]' 'Methods from Deref<Target = Baz>'
-// @has '-' '//*[@class="impl-items"]//*[@id="method.baz"]' 'pub fn baz(&self)'
-// @has '-' '//*[@class="sidebar-title"][@href="#deref-methods-Bar"]' 'Methods from Deref<Target=Bar>'
-// @has '-' '//*[@class="sidebar-links"]/a[@href="#method.bar"]' 'bar'
-// @has '-' '//*[@class="sidebar-title"][@href="#deref-methods-Baz"]' 'Methods from Deref<Target=Baz>'
-// @has '-' '//*[@class="sidebar-links"]/a[@href="#method.baz"]' 'baz'
-
-#![crate_name = "foo"]
-
-use std::ops::Deref;
-
-pub struct Foo(Bar);
-pub struct Bar(Baz);
-pub struct Baz;
-
-impl Deref for Foo {
- type Target = Bar;
- fn deref(&self) -> &Bar { &self.0 }
-}
-
-impl Deref for Bar {
- type Target = Baz;
- fn deref(&self) -> &Baz { &self.0 }
-}
-
-impl Bar {
- /// This appears under `Foo` methods
- pub fn bar(&self) {}
-}
-
-impl Baz {
- /// This should also appear in `Foo` methods when recursing
- pub fn baz(&self) {}
-}
#![crate_name = "foo"]
// @has 'foo/struct.Bar.html'
-// @has '-' '//*[@id="deref-methods-FooJ"]' 'Methods from Deref<Target = FooJ>'
+// @has '-' '//*[@id="deref-methods"]' 'Methods from Deref<Target = FooJ>'
// @has '-' '//*[@class="impl-items"]//*[@id="method.foo_a"]' 'pub fn foo_a(&self)'
// @has '-' '//*[@class="impl-items"]//*[@id="method.foo_b"]' 'pub fn foo_b(&self)'
// @has '-' '//*[@class="impl-items"]//*[@id="method.foo_c"]' 'pub fn foo_c(&self)'
// @has '-' '//*[@class="impl-items"]//*[@id="method.foo_j"]' 'pub fn foo_j(&self)'
-// @has '-' '//*[@class="sidebar-title"][@href="#deref-methods-FooJ"]' 'Methods from Deref<Target=FooJ>'
+// @has '-' '//*[@class="sidebar-title"][@href="#deref-methods"]' 'Methods from Deref<Target=FooJ>'
// @has '-' '//*[@class="sidebar-links"]/a[@href="#method.foo_a"]' 'foo_a'
// @has '-' '//*[@class="sidebar-links"]/a[@href="#method.foo_b"]' 'foo_b'
// @has '-' '//*[@class="sidebar-links"]/a[@href="#method.foo_c"]' 'foo_c'
fn foo(foo: Self::Fuu);
}
-// @has doc_assoc_item/struct.Foo.html '//*[@class="impl"]' 'impl<T: Bar<Fuu = u32>> Foo<T>'
+// @has doc_assoc_item/struct.Foo.html '//*[@class="impl has-srclink"]' 'impl<T: Bar<Fuu = u32>> Foo<T>'
impl<T: Bar<Fuu = u32>> Foo<T> {
pub fn new(t: T) -> Foo<T> {
Foo {
// @has issue_33054/impls/struct.Foo.html
// @has - '//code' 'impl Foo'
// @has - '//code' 'impl Bar for Foo'
-// @count - '//*[@id="trait-implementations-list"]//*[@class="impl"]' 1
-// @count - '//*[@id="main"]/details/summary/*[@class="impl"]' 1
+// @count - '//*[@id="trait-implementations-list"]//*[@class="impl has-srclink"]' 1
+// @count - '//*[@id="main"]/details/summary/*[@class="impl has-srclink"]' 1
// @has issue_33054/impls/bar/trait.Bar.html
// @has - '//code' 'impl Bar for Foo'
// @count - '//*[@class="struct"]' 1
#![crate_name = "foo"]
// @has foo/struct.Foo.html
-// @has - '//div[@id="synthetic-implementations-list"]/h3[@id="impl-Send"]' 'impl Send for Foo'
+// @has - '//div[@id="synthetic-implementations-list"]/div[@id="impl-Send"]' 'impl Send for Foo'
pub struct Foo;
pub trait EmptyTrait {}
-// @has - '//div[@id="trait-implementations-list"]/h3[@id="impl-EmptyTrait"]' 'impl EmptyTrait for Foo'
+// @has - '//div[@id="trait-implementations-list"]/div[@id="impl-EmptyTrait"]' 'impl EmptyTrait for Foo'
impl EmptyTrait for Foo {}
pub trait NotEmpty {
fn foo(&self);
}
-// @has - '//div[@id="trait-implementations-list"]/details/summary/h3[@id="impl-NotEmpty"]' 'impl NotEmpty for Foo'
+// @has - '//div[@id="trait-implementations-list"]/details/summary/div[@id="impl-NotEmpty"]' 'impl NotEmpty for Foo'
impl NotEmpty for Foo {
fn foo(&self) {}
}
// This test ensures that the [src] link is present on traits items.
-// @has foo/trait.Iterator.html '//h3[@id="method.zip"]/a[@class="srclink"]' "[src]"
+// @has foo/trait.Iterator.html '//div[@id="method.zip"]/a[@class="srclink"]' "[src]"
pub use std::iter::Iterator;
-#![feature(external_doc)]
-
-// @has external_doc/struct.CanHasDocs.html
-// @has - '//h1' 'External Docs'
-// @has - '//h2' 'Inline Docs'
-#[doc(include = "auxiliary/external-doc.md")]
-/// ## Inline Docs
-pub struct CanHasDocs;
-
// @has external_doc/struct.IncludeStrDocs.html
// @has - '//h1' 'External Docs'
// @has - '//h2' 'Inline Docs'
use std::fmt;
-// @!has foo/struct.Bar.html '//h3[@id="impl-ToString"]//code' 'impl<T> ToString for T'
+// @!has foo/struct.Bar.html '//div[@id="impl-ToString"]//code' 'impl<T> ToString for T'
pub struct Bar;
-// @has foo/struct.Foo.html '//h3[@id="impl-ToString"]//code' 'impl<T> ToString for T'
+// @has foo/struct.Foo.html '//div[@id="impl-ToString"]//code' 'impl<T> ToString for T'
pub struct Foo;
// @has foo/struct.Foo.html '//div[@class="sidebar-links"]/a[@href="#impl-ToString"]' 'ToString'
pub struct Foo<T> { field: T }
-// @has impl_parts/struct.Foo.html '//*[@class="impl"]//code' \
+// @has impl_parts/struct.Foo.html '//*[@class="impl has-srclink"]//code' \
// "impl<T: Clone> !AnAutoTrait for Foo<T> where T: Sync,"
// @has impl_parts/trait.AnAutoTrait.html '//*[@class="item-list"]//code' \
// "impl<T: Clone> !AnAutoTrait for Foo<T> where T: Sync,"
// @has - '//*[@id="associatedconstant.ConstNoDefault"]' 'const ConstNoDefault: i16'
// @has - '//*[@class="docblock"]' 'dox for ConstNoDefault'
// @has - '//*[@id="associatedconstant.ConstWithDefault"]' 'const ConstWithDefault: u16'
-// @!has - '//details[@open=""]/details/div[@class="docblock"]' 'docs for ConstWithDefault'
-// @has - '//details/details/div[@class="docblock"]' 'docs for ConstWithDefault'
+// @has - '//div[@class="docblock"]' 'docs for ConstWithDefault'
// @has - '//*[@id="associatedtype.TypeNoDefault"]' 'type TypeNoDefault = i32'
// @has - '//*[@class="docblock"]' 'dox for TypeNoDefault'
// @has - '//*[@id="associatedtype.TypeWithDefault"]' 'type TypeWithDefault = u32'
-// @!has - '//details[@open=""]/details/div[@class="docblock"]' 'docs for TypeWithDefault'
-// @has - '//details/details/div[@class="docblock"]' 'docs for TypeWithDefault'
+// @has - '//div[@class="docblock"]' 'docs for TypeWithDefault'
// @has - '//*[@id="method.method_no_default"]' 'fn method_no_default()'
// @has - '//*[@class="docblock"]' 'dox for method_no_default'
// @has - '//*[@id="method.method_with_default"]' 'fn method_with_default()'
-// @!has - '//details[@open=""]/details/div[@class="docblock"]' 'docs for method_with_default'
-// @has - '//details/details/div[@class="docblock"]' 'docs for method_with_default'
+// @has - '//div[@class="docblock"]' 'docs for method_with_default'
pub use assoc_items::MyStruct;
// @has foo/trait.MyTrait.html
// @has 'foo/struct.MyStruct.html'
// @has - '//*[@id="method.my_trait_method"]' 'fn my_trait_method()'
-// @!has - '//details[@open=""]/details/div[@class="docblock"]' 'docs for my_trait_method'
-// @has - '//details/details/div[@class="docblock"]' 'docs for my_trait_method'
+// @has - '//div[@class="docblock"]' 'docs for my_trait_method'
pub use impl_inline_without_trait::MyStruct;
extern crate rustdoc_nonreachable_impls;
// @has issue_31948_1/struct.Wobble.html
-// @has - '//*[@class="impl"]//code' 'Bark for'
-// @has - '//*[@class="impl"]//code' 'Woof for'
+// @has - '//*[@class="impl has-srclink"]//code' 'Bark for'
+// @has - '//*[@class="impl has-srclink"]//code' 'Woof for'
// @!has - '//*[@class="impl"]//code' 'Bar for'
// @!has - '//*[@class="impl"]//code' 'Qux for'
pub use rustdoc_nonreachable_impls::hidden::Wobble;
extern crate rustdoc_nonreachable_impls;
// @has issue_31948_2/struct.Wobble.html
-// @has - '//*[@class="impl"]//code' 'Qux for'
-// @has - '//*[@class="impl"]//code' 'Bark for'
-// @has - '//*[@class="impl"]//code' 'Woof for'
+// @has - '//*[@class="impl has-srclink"]//code' 'Qux for'
+// @has - '//*[@class="impl has-srclink"]//code' 'Bark for'
+// @has - '//*[@class="impl has-srclink"]//code' 'Woof for'
// @!has - '//*[@class="impl"]//code' 'Bar for'
pub use rustdoc_nonreachable_impls::hidden::Wobble;
extern crate rustdoc_nonreachable_impls;
// @has issue_31948/struct.Foo.html
-// @has - '//*[@class="impl"]//code' 'Bark for'
-// @has - '//*[@class="impl"]//code' 'Woof for'
-// @!has - '//*[@class="impl"]//code' 'Bar for'
+// @has - '//*[@class="impl has-srclink"]//code' 'Bark for'
+// @has - '//*[@class="impl has-srclink"]//code' 'Woof for'
+// @!has - '//*[@class="impl has-srclink"]//code' 'Bar for'
// @!has - '//*[@class="impl"]//code' 'Qux for'
pub use rustdoc_nonreachable_impls::Foo;
/// [`std::collections::BTreeMap::into_iter`]
/// [`String::from`] is ambiguous as to which `From` impl
/// [Vec::into_iter()] uses a disambiguator
-// @has 'associated_items/fn.foo.html' '//a[@href="https://doc.rust-lang.org/nightly/alloc/collections/btree/map/struct.BTreeMap.html#method.into_iter"]' 'std::collections::BTreeMap::into_iter'
-// @has 'associated_items/fn.foo.html' '//a[@href="https://doc.rust-lang.org/nightly/alloc/string/struct.String.html#method.from"]' 'String::from'
-// @has 'associated_items/fn.foo.html' '//a[@href="https://doc.rust-lang.org/nightly/alloc/vec/struct.Vec.html#method.into_iter"]' 'Vec::into_iter'
+// @has 'associated_items/fn.foo.html' '//a[@href="{{channel}}/alloc/collections/btree/map/struct.BTreeMap.html#method.into_iter"]' 'std::collections::BTreeMap::into_iter'
+// @has 'associated_items/fn.foo.html' '//a[@href="{{channel}}/alloc/string/struct.String.html#method.from"]' 'String::from'
+// @has 'associated_items/fn.foo.html' '//a[@href="{{channel}}/alloc/vec/struct.Vec.html#method.into_iter"]' 'Vec::into_iter'
pub fn foo() {}
/// Link to [MyStruct], [link from struct][MyStruct::method], [MyStruct::clone], [MyStruct::Input]
// @has builtin_macros/index.html
-// @has - '//a/@href' 'https://doc.rust-lang.org/nightly/core/macro.cfg.html'
+// @has - '//a/@href' '{{channel}}/core/macro.cfg.html'
//! [cfg]
--- /dev/null
+// @has field/index.html '//a[@href="{{channel}}/core/ops/range/struct.Range.html#structfield.start"]' 'start'
+// @has field/index.html '//a[@href="{{channel}}/std/io/error/enum.ErrorKind.html#variant.NotFound"]' 'not_found'
+//! [start][std::ops::Range::start]
+//! [not_found][std::io::ErrorKind::NotFound]
//! Here's a link to [`Vec<T>`] and one to [`Box<Vec<Option<T>>>`].
//! Here's a link to [`Iterator<Box<T>>::Item`].
//!
-// @has foo/index.html '//a[@href="https://doc.rust-lang.org/nightly/alloc/vec/struct.Vec.html"]' 'Vec<T>'
-// @has foo/index.html '//a[@href="https://doc.rust-lang.org/nightly/alloc/boxed/struct.Box.html"]' 'Box<Vec<Option<T>>>'
-// @has foo/index.html '//a[@href="https://doc.rust-lang.org/nightly/core/iter/traits/iterator/trait.Iterator.html#associatedtype.Item"]' 'Iterator<Box<T>>::Item'
+// @has foo/index.html '//a[@href="{{channel}}/alloc/vec/struct.Vec.html"]' 'Vec<T>'
+// @has foo/index.html '//a[@href="{{channel}}/alloc/boxed/struct.Box.html"]' 'Box<Vec<Option<T>>>'
+// @has foo/index.html '//a[@href="{{channel}}/core/iter/traits/iterator/trait.Iterator.html#associatedtype.Item"]' 'Iterator<Box<T>>::Item'
//! And what about a link to [just `Option`](Option) and, [with the generic, `Option<T>`](Option<T>)?
//!
-// @has foo/index.html '//a[@href="https://doc.rust-lang.org/nightly/core/option/enum.Option.html"]' 'just Option'
-// @has foo/index.html '//a[@href="https://doc.rust-lang.org/nightly/core/option/enum.Option.html"]' 'with the generic, Option<T>'
+// @has foo/index.html '//a[@href="{{channel}}/core/option/enum.Option.html"]' 'just Option'
+// @has foo/index.html '//a[@href="{{channel}}/core/option/enum.Option.html"]' 'with the generic, Option<T>'
//! We should also try linking to [`Result<T, E>`]; it has *two* generics!
//! And [`Result<T, !>`] and [`Result<!, E>`].
//!
-// @has foo/index.html '//a[@href="https://doc.rust-lang.org/nightly/core/result/enum.Result.html"]' 'Result<T, E>'
-// @has foo/index.html '//a[@href="https://doc.rust-lang.org/nightly/core/result/enum.Result.html"]' 'Result<T, !>'
-// @has foo/index.html '//a[@href="https://doc.rust-lang.org/nightly/core/result/enum.Result.html"]' 'Result<!, E>'
+// @has foo/index.html '//a[@href="{{channel}}/core/result/enum.Result.html"]' 'Result<T, E>'
+// @has foo/index.html '//a[@href="{{channel}}/core/result/enum.Result.html"]' 'Result<T, !>'
+// @has foo/index.html '//a[@href="{{channel}}/core/result/enum.Result.html"]' 'Result<!, E>'
//! Now let's test a trickier case: [`Vec::<T>::new`], or you could write it
//! [with parentheses as `Vec::<T>::new()`][Vec::<T>::new()].
//! And what about something even harder? That would be [`Vec::<Box<T>>::new()`].
//!
-// @has foo/index.html '//a[@href="https://doc.rust-lang.org/nightly/alloc/vec/struct.Vec.html#method.new"]' 'Vec::<T>::new'
-// @has foo/index.html '//a[@href="https://doc.rust-lang.org/nightly/alloc/vec/struct.Vec.html#method.new"]' 'with parentheses as Vec::<T>::new()'
-// @has foo/index.html '//a[@href="https://doc.rust-lang.org/nightly/alloc/vec/struct.Vec.html#method.new"]' 'Vec::<Box<T>>::new()'
+// @has foo/index.html '//a[@href="{{channel}}/alloc/vec/struct.Vec.html#method.new"]' 'Vec::<T>::new'
+// @has foo/index.html '//a[@href="{{channel}}/alloc/vec/struct.Vec.html#method.new"]' 'with parentheses as Vec::<T>::new()'
+// @has foo/index.html '//a[@href="{{channel}}/alloc/vec/struct.Vec.html#method.new"]' 'Vec::<Box<T>>::new()'
//! This is also pretty tricky: [`TypeId::of::<String>()`].
//! And this too: [`Vec::<std::error::Error>::len`].
//!
-// @has foo/index.html '//a[@href="https://doc.rust-lang.org/nightly/core/any/struct.TypeId.html#method.of"]' 'TypeId::of::<String>()'
-// @has foo/index.html '//a[@href="https://doc.rust-lang.org/nightly/alloc/vec/struct.Vec.html#method.len"]' 'Vec::<std::error::Error>::len'
+// @has foo/index.html '//a[@href="{{channel}}/core/any/struct.TypeId.html#method.of"]' 'TypeId::of::<String>()'
+// @has foo/index.html '//a[@href="{{channel}}/alloc/vec/struct.Vec.html#method.len"]' 'Vec::<std::error::Error>::len'
//! We unofficially and implicitly support things that aren't valid in the actual Rust syntax, like
//! [`Box::<T>new()`]. We may not support them in the future!
//!
-// @has foo/index.html '//a[@href="https://doc.rust-lang.org/nightly/alloc/boxed/struct.Box.html#method.new"]' 'Box::<T>new()'
+// @has foo/index.html '//a[@href="{{channel}}/alloc/boxed/struct.Box.html#method.new"]' 'Box::<T>new()'
//! These will be resolved as regular links:
//! - [`this is <invalid syntax> first`](https://www.rust-lang.org)
#![feature(intra_doc_pointers)]
#![deny(rustdoc::broken_intra_doc_links)]
-// @has foo/index.html '//a[@href="https://doc.rust-lang.org/nightly/std/primitive.slice.html#method.rotate_left"]' 'slice::rotate_left'
+// @has foo/index.html '//a[@href="{{channel}}/std/primitive.slice.html#method.rotate_left"]' 'slice::rotate_left'
//! [slice::rotate_left]
-// @has - '//a[@href="https://doc.rust-lang.org/nightly/std/primitive.array.html#method.map"]' 'array::map'
+// @has - '//a[@href="{{channel}}/std/primitive.array.html#method.map"]' 'array::map'
//! [array::map]
-// @has - '//a[@href="https://doc.rust-lang.org/nightly/std/primitive.str.html"]' 'owned str'
-// @has - '//a[@href="https://doc.rust-lang.org/nightly/std/primitive.str.html"]' 'str ref'
-// @has - '//a[@href="https://doc.rust-lang.org/nightly/std/primitive.str.html#method.is_empty"]' 'str::is_empty'
-// @has - '//a[@href="https://doc.rust-lang.org/nightly/std/primitive.str.html#method.len"]' '&str::len'
+// @has - '//a[@href="{{channel}}/std/primitive.str.html"]' 'owned str'
+// @has - '//a[@href="{{channel}}/std/primitive.str.html"]' 'str ref'
+// @has - '//a[@href="{{channel}}/std/primitive.str.html#method.is_empty"]' 'str::is_empty'
+// @has - '//a[@href="{{channel}}/std/primitive.str.html#method.len"]' '&str::len'
//! [owned str][str]
//! [str ref][&str]
//! [str::is_empty]
//! [&str::len]
-// @has - '//a[@href="https://doc.rust-lang.org/nightly/std/primitive.pointer.html#method.is_null"]' 'pointer::is_null'
-// @has - '//a[@href="https://doc.rust-lang.org/nightly/std/primitive.pointer.html#method.is_null"]' '*const::is_null'
-// @has - '//a[@href="https://doc.rust-lang.org/nightly/std/primitive.pointer.html#method.is_null"]' '*mut::is_null'
+// @has - '//a[@href="{{channel}}/std/primitive.pointer.html#method.is_null"]' 'pointer::is_null'
+// @has - '//a[@href="{{channel}}/std/primitive.pointer.html#method.is_null"]' '*const::is_null'
+// @has - '//a[@href="{{channel}}/std/primitive.pointer.html#method.is_null"]' '*mut::is_null'
//! [pointer::is_null]
//! [*const::is_null]
//! [*mut::is_null]
-// @has - '//a[@href="https://doc.rust-lang.org/nightly/std/primitive.unit.html"]' 'unit'
+// @has - '//a[@href="{{channel}}/std/primitive.unit.html"]' 'unit'
//! [unit]
-// @has - '//a[@href="https://doc.rust-lang.org/nightly/std/primitive.tuple.html"]' 'tuple'
+// @has - '//a[@href="{{channel}}/std/primitive.tuple.html"]' 'tuple'
//! [tuple]
-// @has - '//a[@href="https://doc.rust-lang.org/nightly/std/primitive.reference.html"]' 'reference'
-// @has - '//a[@href="https://doc.rust-lang.org/nightly/std/primitive.reference.html"]' '&'
-// @has - '//a[@href="https://doc.rust-lang.org/nightly/std/primitive.reference.html"]' '&mut'
+// @has - '//a[@href="{{channel}}/std/primitive.reference.html"]' 'reference'
+// @has - '//a[@href="{{channel}}/std/primitive.reference.html"]' '&'
+// @has - '//a[@href="{{channel}}/std/primitive.reference.html"]' '&mut'
//! [reference]
//! [&]
//! [&mut]
-// @has - '//a[@href="https://doc.rust-lang.org/nightly/std/primitive.fn.html"]' 'fn'
+// @has - '//a[@href="{{channel}}/std/primitive.fn.html"]' 'fn'
//! [fn]
-// @has - '//a[@href="https://doc.rust-lang.org/nightly/std/primitive.never.html"]' 'never'
-// @has - '//a[@href="https://doc.rust-lang.org/nightly/std/primitive.never.html"]' '!'
+// @has - '//a[@href="{{channel}}/std/primitive.never.html"]' 'never'
+// @has - '//a[@href="{{channel}}/std/primitive.never.html"]' '!'
//! [never]
//! [!]
#![deny(broken_intra_doc_links)]
//! [i32::MAX]
-// @has prim_assoc/index.html '//a[@href="https://doc.rust-lang.org/nightly/std/primitive.i32.html#associatedconstant.MAX"]' "i32::MAX"
+// @has prim_assoc/index.html '//a[@href="{{channel}}/std/primitive.i32.html#associatedconstant.MAX"]' "i32::MAX"
#![crate_type = "rlib"]
// @has prim_methods_external_core/index.html
-// @has - '//*[@id="main"]//a[@href="https://doc.rust-lang.org/nightly/std/primitive.char.html"]' 'char'
-// @has - '//*[@id="main"]//a[@href="https://doc.rust-lang.org/nightly/std/primitive.char.html#method.len_utf8"]' 'char::len_utf8'
+// @has - '//*[@id="main"]//a[@href="{{channel}}/std/primitive.char.html"]' 'char'
+// @has - '//*[@id="main"]//a[@href="{{channel}}/std/primitive.char.html#method.len_utf8"]' 'char::len_utf8'
//! A [`char`] and its [`char::len_utf8`].
// @has prim_methods_local/index.html
-// @has - '//*[@id="main"]//a[@href="https://doc.rust-lang.org/nightly/std/primitive.char.html"]' 'char'
-// @has - '//*[@id="main"]//a[@href="https://doc.rust-lang.org/nightly/std/primitive.char.html#method.len_utf8"]' 'char::len_utf8'
+// @has - '//*[@id="main"]//a[@href="{{channel}}/std/primitive.char.html"]' 'char'
+// @has - '//*[@id="main"]//a[@href="{{channel}}/std/primitive.char.html#method.len_utf8"]' 'char::len_utf8'
//! A [`char`] and its [`char::len_utf8`].
// @has prim_methods/index.html
-// @has - '//*[@id="main"]//a[@href="https://doc.rust-lang.org/nightly/std/primitive.char.html"]' 'char'
-// @has - '//*[@id="main"]//a[@href="https://doc.rust-lang.org/nightly/std/primitive.char.html#method.len_utf8"]' 'char::len_utf8'
+// @has - '//*[@id="main"]//a[@href="{{channel}}/std/primitive.char.html"]' 'char'
+// @has - '//*[@id="main"]//a[@href="{{channel}}/std/primitive.char.html#method.len_utf8"]' 'char::len_utf8'
//! A [`char`] and its [`char::len_utf8`].
pub mod char {
/// [char]
- // @has prim_precedence/char/struct.Inner.html '//a/@href' 'https://doc.rust-lang.org/nightly/std/primitive.char.html'
+ // @has prim_precedence/char/struct.Inner.html '//a/@href' '{{channel}}/std/primitive.char.html'
pub struct Inner;
}
/// See [prim@char]
-// @has prim_precedence/struct.MyString.html '//a/@href' 'https://doc.rust-lang.org/nightly/std/primitive.char.html'
+// @has prim_precedence/struct.MyString.html '//a/@href' '{{channel}}/std/primitive.char.html'
pub struct MyString;
/// See also [crate::char] and [mod@char]
#![deny(broken_intra_doc_links)]
// @has primitive_disambiguators/index.html
-// @has - '//a/@href' 'https://doc.rust-lang.org/nightly/std/primitive.str.html#method.trim'
+// @has - '//a/@href' '{{channel}}/std/primitive.str.html#method.trim'
//! [str::trim()]
// @has primitive_non_default_impl/fn.str_methods.html
/// [`str::trim`]
-// @has - '//*[@href="https://doc.rust-lang.org/nightly/std/primitive.str.html#method.trim"]' 'str::trim'
+// @has - '//*[@href="{{channel}}/std/primitive.str.html#method.trim"]' 'str::trim'
/// [`str::to_lowercase`]
-// @has - '//*[@href="https://doc.rust-lang.org/nightly/std/primitive.str.html#method.to_lowercase"]' 'str::to_lowercase'
+// @has - '//*[@href="{{channel}}/std/primitive.str.html#method.to_lowercase"]' 'str::to_lowercase'
/// [`str::into_boxed_bytes`]
-// @has - '//*[@href="https://doc.rust-lang.org/nightly/std/primitive.str.html#method.into_boxed_bytes"]' 'str::into_boxed_bytes'
+// @has - '//*[@href="{{channel}}/std/primitive.str.html#method.into_boxed_bytes"]' 'str::into_boxed_bytes'
/// [`str::replace`]
-// @has - '//*[@href="https://doc.rust-lang.org/nightly/std/primitive.str.html#method.replace"]' 'str::replace'
+// @has - '//*[@href="{{channel}}/std/primitive.str.html#method.replace"]' 'str::replace'
pub fn str_methods() {}
// @has primitive_non_default_impl/fn.f32_methods.html
/// [f32::powi]
-// @has - '//*[@href="https://doc.rust-lang.org/nightly/std/primitive.f32.html#method.powi"]' 'f32::powi'
+// @has - '//*[@href="{{channel}}/std/primitive.f32.html#method.powi"]' 'f32::powi'
/// [f32::sqrt]
-// @has - '//*[@href="https://doc.rust-lang.org/nightly/std/primitive.f32.html#method.sqrt"]' 'f32::sqrt'
+// @has - '//*[@href="{{channel}}/std/primitive.f32.html#method.sqrt"]' 'f32::sqrt'
/// [f32::mul_add]
-// @has - '//*[@href="https://doc.rust-lang.org/nightly/std/primitive.f32.html#method.mul_add"]' 'f32::mul_add'
+// @has - '//*[@href="{{channel}}/std/primitive.f32.html#method.mul_add"]' 'f32::mul_add'
pub fn f32_methods() {}
// @has primitive_non_default_impl/fn.f64_methods.html
/// [`f64::powi`]
-// @has - '//*[@href="https://doc.rust-lang.org/nightly/std/primitive.f64.html#method.powi"]' 'f64::powi'
+// @has - '//*[@href="{{channel}}/std/primitive.f64.html#method.powi"]' 'f64::powi'
/// [`f64::sqrt`]
-// @has - '//*[@href="https://doc.rust-lang.org/nightly/std/primitive.f64.html#method.sqrt"]' 'f64::sqrt'
+// @has - '//*[@href="{{channel}}/std/primitive.f64.html#method.sqrt"]' 'f64::sqrt'
/// [`f64::mul_add`]
-// @has - '//*[@href="https://doc.rust-lang.org/nightly/std/primitive.f64.html#method.mul_add"]' 'f64::mul_add'
+// @has - '//*[@href="{{channel}}/std/primitive.f64.html#method.mul_add"]' 'f64::mul_add'
pub fn f64_methods() {}
// documenting the re-export.
// @has outer/index.html
-// @ has - '//a[@href="https://doc.rust-lang.org/nightly/std/env/fn.var.html"]' "std::env"
+// @ has - '//a[@href="{{channel}}/std/env/fn.var.html"]' "std::env"
// @ has - '//a[@href="fn.f.html"]' "g"
pub use f as g;
// Make sure the documentation is actually correct by documenting an inlined re-export
/// [mod@std::env]
// @has outer/fn.f.html
-// @has - '//a[@href="https://doc.rust-lang.org/nightly/std/env/index.html"]' "std::env"
+// @has - '//a[@href="{{channel}}/std/env/index.html"]' "std::env"
pub use inner::f;
/// Link to [S::assoc_fn()]
/// Link to [Default::default()]
// @has trait_item/struct.S.html '//*[@href="struct.S.html#method.assoc_fn"]' 'S::assoc_fn()'
-// @has - '//*[@href="https://doc.rust-lang.org/nightly/core/default/trait.Default.html#tymethod.default"]' 'Default::default()'
+// @has - '//*[@href="{{channel}}/core/default/trait.Default.html#tymethod.default"]' 'Default::default()'
pub struct S;
impl S {
// @has foo/index.html
-// @has - '//*[@id="main"]//a[@href="https://doc.rust-lang.org/nightly/std/primitive.bool.html"]' 'true'
-// @has - '//*[@id="main"]//a[@href="https://doc.rust-lang.org/nightly/std/primitive.bool.html"]' 'false'
+// @has - '//*[@id="main"]//a[@href="{{channel}}/std/primitive.bool.html"]' 'true'
+// @has - '//*[@id="main"]//a[@href="{{channel}}/std/primitive.bool.html"]' 'false'
//! A `bool` is either [`true`] or [`false`].
-// ignore-tidy-linelength
#![deny(broken_intra_doc_links)]
#![feature(lang_items)]
#![feature(no_core)]
/// [Self::f]
/// [Self::MAX]
// @has intra_link_prim_self/primitive.usize.html
-// @has - '//a[@href="https://doc.rust-lang.org/nightly/std/primitive.usize.html#method.f"]' 'Self::f'
-// @has - '//a[@href="https://doc.rust-lang.org/nightly/std/primitive.usize.html#associatedconstant.MAX"]' 'Self::MAX'
+// @has - '//a[@href="{{channel}}/std/primitive.usize.html#method.f"]' 'Self::f'
+// @has - '//a[@href="{{channel}}/std/primitive.usize.html#associatedconstant.MAX"]' 'Self::MAX'
impl usize {
/// Some docs
pub fn f() {}
pub const MAX: usize = 10;
// FIXME(#8995) uncomment this when associated types in inherent impls are supported
- // @ has - '//a[@href="https://doc.rust-lang.org/nightly/std/primitive.usize.html#associatedtype.ME"]' 'Self::ME'
+ // @ has - '//a[@href="{{channel}}/std/primitive.usize.html#associatedtype.ME"]' 'Self::ME'
// / [Self::ME]
//pub type ME = usize;
}
pub trait Blah { }
// @count issue_21474/struct.What.html \
-// '//*[@id="trait-implementations-list"]//*[@class="impl"]' 1
+// '//*[@id="trait-implementations-list"]//*[@class="impl has-srclink"]' 1
pub struct What;
fn my_string(&self) -> String;
}
-// @has - "//div[@id='implementors-list']//h3[@id='impl-MyTrait']//code" "impl<T> MyTrait for T where T: Debug"
+// @has - "//div[@id='implementors-list']//div[@id='impl-MyTrait']//code" "impl<T> MyTrait for T where T: Debug"
impl<T> MyTrait for T where T: fmt::Debug {
fn my_string(&self) -> String {
format!("{:?}", self)
}
// @has issue_33302/struct.S.html \
- // '//h3[@class="impl"]' 'impl T<[i32; 16]> for S'
+ // '//div[@class="impl has-srclink"]' 'impl T<[i32; 16]> for S'
// @has - '//*[@id="associatedconstant.C"]' 'const C: [i32; 16]'
// @has - '//*[@id="associatedconstant.D"]' 'const D: i32'
impl T<[i32; ($n * $n)]> for S {
}
// @has issue_33302/struct.S.html \
- // '//h3[@class="impl"]' 'impl T<[i32; 16]> for S'
+ // '//div[@class="impl has-srclink"]' 'impl T<[i32; 16]> for S'
// @has - '//*[@id="associatedconstant.C-1"]' 'const C: (i32,)'
// @has - '//*[@id="associatedconstant.D-1"]' 'const D: i32'
impl T<(i32,)> for S {
}
// @has issue_33302/struct.S.html \
- // '//h3[@class="impl"]' 'impl T<(i32, i32)> for S'
+ // '//div[@class="impl has-srclink"]' 'impl T<(i32, i32)> for S'
// @has - '//*[@id="associatedconstant.C-2"]' 'const C: (i32, i32)'
// @has - '//*[@id="associatedconstant.D-2"]' 'const D: i32'
impl T<(i32, i32)> for S {
// @has 'foo/struct.Foo1.html'
pub struct Foo1;
-// @count - '//*[@id="trait-implementations-list"]//*[@class="impl"]' 1
-// @has - '//*[@class="impl"]' "impl Bar<Foo1, &'static Foo1> for Foo1"
+// @count - '//*[@id="trait-implementations-list"]//*[@class="impl has-srclink"]' 1
+// @has - '//*[@class="impl has-srclink"]' "impl Bar<Foo1, &'static Foo1> for Foo1"
impl Bar<Foo1, &'static Foo1> for Foo1 {}
// @has 'foo/struct.Foo2.html'
pub struct Foo2;
-// @count - '//*[@id="trait-implementations-list"]//*[@class="impl"]' 1
-// @has - '//*[@class="impl"]' "impl Bar<&'static Foo2, Foo2> for u8"
+// @count - '//*[@id="trait-implementations-list"]//*[@class="impl has-srclink"]' 1
+// @has - '//*[@class="impl has-srclink"]' "impl Bar<&'static Foo2, Foo2> for u8"
impl Bar<&'static Foo2, Foo2> for u8 {}
// @has - '//code' 'impl<B> Send for Switch<B> where <B as Signal>::Item: Send'
// @has - '//code' 'impl<B> Sync for Switch<B> where <B as Signal>::Item: Sync'
// @count - '//*[@id="implementations-list"]//*[@class="impl"]' 0
-// @count - '//*[@id="synthetic-implementations-list"]//*[@class="impl"]' 5
+// @count - '//*[@id="synthetic-implementations-list"]//*[@class="impl has-srclink"]' 5
pub struct Switch<B: Signal> {
pub inner: <B as Signal2>::Item2,
}
}
// @has issue_51236/struct.Owned.html
-// @has - '//*[@id="synthetic-implementations-list"]//*[@class="impl"]//code' "impl<T> Send for \
-// Owned<T> where <T as Owned<'static>>::Reader: Send"
+// @has - '//*[@id="synthetic-implementations-list"]//*[@class="impl has-srclink"]//code' \
+// "impl<T> Send for Owned<T> where <T as Owned<'static>>::Reader: Send"
pub struct Owned<T> where T: for<'a> ::traits::Owned<'a> {
marker: PhantomData<<T as ::traits::Owned<'static>>::Reader>,
}
}
}
-// @has issue_53812/trait.MyIterator.html '//*[@id="implementors-list"]/h3[1]' 'MyStruct<[T; 0]>'
-// @has - '//*[@id="implementors-list"]/h3[2]' 'MyStruct<[T; 1]>'
-// @has - '//*[@id="implementors-list"]/h3[3]' 'MyStruct<[T; 2]>'
-// @has - '//*[@id="implementors-list"]/h3[4]' 'MyStruct<[T; 3]>'
-// @has - '//*[@id="implementors-list"]/h3[5]' 'MyStruct<[T; 10]>'
+// @has issue_53812/trait.MyIterator.html
+// @has - '//*[@id="implementors-list"]/div[@class="impl has-srclink"][1]' 'MyStruct<[T; 0]>'
+// @has - '//*[@id="implementors-list"]/div[@class="impl has-srclink"][2]' 'MyStruct<[T; 1]>'
+// @has - '//*[@id="implementors-list"]/div[@class="impl has-srclink"][3]' 'MyStruct<[T; 2]>'
+// @has - '//*[@id="implementors-list"]/div[@class="impl has-srclink"][4]' 'MyStruct<[T; 3]>'
+// @has - '//*[@id="implementors-list"]/div[@class="impl has-srclink"][5]' 'MyStruct<[T; 10]>'
array_impls! { 10 3 2 1 0 }
// @has issue_54705/struct.ScopeFutureContents.html
-// @has - '//*[@id="synthetic-implementations-list"]//*[@class="impl"]//code' "impl<'scope, S> \
-// Send for ScopeFutureContents<'scope, S> where S: Sync"
+// @has - '//*[@id="synthetic-implementations-list"]//*[@class="impl has-srclink"]//code' \
+// "impl<'scope, S> Send for ScopeFutureContents<'scope, S> where S: Sync"
//
-// @has - '//*[@id="synthetic-implementations-list"]//*[@class="impl"]//code' "impl<'scope, S> \
-// Sync for ScopeFutureContents<'scope, S> where S: Sync"
+// @has - '//*[@id="synthetic-implementations-list"]//*[@class="impl has-srclink"]//code' \
+// "impl<'scope, S> Sync for ScopeFutureContents<'scope, S> where S: Sync"
pub struct ScopeFutureContents<'scope, S>
where S: ScopeHandle<'scope>,
{
#![feature(negative_impls)]
// @has issue_55321/struct.A.html
-// @has - '//*[@id="trait-implementations-list"]//*[@class="impl"]//code' "impl !Send for A"
-// @has - '//*[@id="trait-implementations-list"]//*[@class="impl"]//code' "impl !Sync for A"
+// @has - '//*[@id="trait-implementations-list"]//*[@class="impl has-srclink"]//code' \
+// "impl !Send for A"
+// @has - '//*[@id="trait-implementations-list"]//*[@class="impl has-srclink"]//code' \
+// "impl !Sync for A"
pub struct A();
impl !Send for A {}
impl !Sync for A {}
// @has issue_55321/struct.B.html
-// @has - '//*[@id="synthetic-implementations-list"]//*[@class="impl"]//code' "impl<T> !Send for \
-// B<T>"
-// @has - '//*[@id="synthetic-implementations-list"]//*[@class="impl"]//code' "impl<T> !Sync for \
-// B<T>"
+// @has - '//*[@id="synthetic-implementations-list"]//*[@class="impl has-srclink"]//code' \
+// "impl<T> !Send for B<T>"
+// @has - '//*[@id="synthetic-implementations-list"]//*[@class="impl has-srclink"]//code' \
+// "impl<T> !Sync for B<T>"
pub struct B<T: ?Sized>(A, Box<T>);
}
// @has issue_56822/struct.Parser.html
-// @has - '//*[@id="synthetic-implementations-list"]//*[@class="impl"]//code' "impl<'a> Send for \
-// Parser<'a>"
+// @has - '//*[@id="synthetic-implementations-list"]//*[@class="impl has-srclink"]//code' \
+// "impl<'a> Send for Parser<'a>"
pub struct Parser<'a> {
field: <Wrapper<Inner<'a, u8>> as MyTrait>::Output
}
{}
// @has issue_60726/struct.IntoIter.html
-// @has - '//*[@id="synthetic-implementations-list"]//*[@class="impl"]//code' "impl<T> !Send for \
-// IntoIter<T>"
-// @has - '//*[@id="synthetic-implementations-list"]//*[@class="impl"]//code' "impl<T> !Sync for \
-// IntoIter<T>"
+// @has - '//*[@id="synthetic-implementations-list"]//*[@class="impl has-srclink"]//code' \
+// "impl<T> !Send for IntoIter<T>"
+// @has - '//*[@id="synthetic-implementations-list"]//*[@class="impl has-srclink"]//code' \
+// "impl<T> !Sync for IntoIter<T>"
pub struct IntoIter<T>{
hello:DynTrait<FooInterface<T>>,
}
pub struct Struct {}
impl Struct {
- // @has 'issue_76501/struct.Struct.html' '//*[@class="method"]' 'pub const fn blurp() -> i32'
+ // @has 'issue_76501/struct.Struct.html' '//*[@class="method has-srclink"]' \
+ // 'pub const fn blurp() -> i32'
/// A useless function that always returns 1.
pub const fn blurp() -> i32 {
1
impl<T: Something> AnAmazingTrait for T {}
// @has 'issue_78673/struct.MyStruct.html'
-// @has - '//*[@class="impl"]' 'AnAmazingTrait for MyStruct'
-// @!has - '//*[@class="impl"]' 'AnAmazingTrait for T'
+// @has - '//*[@class="impl has-srclink"]' 'AnAmazingTrait for MyStruct'
+// @!has - '//*[@class="impl has-srclink"]' 'AnAmazingTrait for T'
pub struct MyStruct;
impl AnAmazingTrait for MyStruct {}
// generic structs may have _both_ specific and blanket impls that apply
// @has 'issue_78673/struct.AnotherStruct.html'
-// @has - '//*[@class="impl"]' 'AnAmazingTrait for AnotherStruct<()>'
-// @has - '//*[@class="impl"]' 'AnAmazingTrait for T'
+// @has - '//*[@class="impl has-srclink"]' 'AnAmazingTrait for AnotherStruct<()>'
+// @has - '//*[@class="impl has-srclink"]' 'AnAmazingTrait for T'
pub struct AnotherStruct<T>(T);
impl<T: Something> Something for AnotherStruct<T> {}
--- /dev/null
+use std::convert::AsRef;
+pub struct Local;
+
+// @has issue_82465_asref_for_and_of_local/struct.Local.html '//code' 'impl AsRef<str> for Local'
+impl AsRef<str> for Local {
+ fn as_ref(&self) -> &str {
+ todo!()
+ }
+}
+
+// @has - '//code' 'impl AsRef<Local> for str'
+impl AsRef<Local> for str {
+ fn as_ref(&self) -> &Local {
+ todo!()
+ }
+}
+++ /dev/null
-#![allow(unused)]
-
-// @has 'item_hide_threshold/struct.PubStruct.html'
-// @count - '//details[@class="rustdoc-toggle type-contents-toggle"]' 0
-pub struct PubStruct {
- pub a: usize,
- pub b: usize,
-}
-
-// @has 'item_hide_threshold/struct.BigPubStruct.html'
-// @count - '//details[@class="rustdoc-toggle type-contents-toggle"]' 1
-// @has - '//details[@class="rustdoc-toggle type-contents-toggle"]' 'Show fields'
-pub struct BigPubStruct {
- pub a: usize,
- pub b: usize,
- pub c: usize,
- pub d: usize,
- pub e: usize,
- pub f: usize,
- pub g: usize,
- pub h: usize,
- pub i: usize,
- pub j: usize,
- pub k: usize,
- pub l: usize,
- pub m: usize,
-}
-
-// @has 'item_hide_threshold/union.BigUnion.html'
-// @count - '//details[@class="rustdoc-toggle type-contents-toggle"]' 1
-// @has - '//details[@class="rustdoc-toggle type-contents-toggle"]' 'Show fields'
-pub union BigUnion {
- pub a: usize,
- pub b: usize,
- pub c: usize,
- pub d: usize,
- pub e: usize,
- pub f: usize,
- pub g: usize,
- pub h: usize,
- pub i: usize,
- pub j: usize,
- pub k: usize,
- pub l: usize,
- pub m: usize,
-}
-
-// @has 'item_hide_threshold/union.Union.html'
-// @count - '//details[@class="rustdoc-toggle type-contents-toggle"]' 0
-pub union Union {
- pub a: usize,
- pub b: usize,
- pub c: usize,
-}
-
-// @has 'item_hide_threshold/struct.PrivStruct.html'
-// @count - '//details[@class="rustdoc-toggle type-contents-toggle"]' 0
-// @has - '//div[@class="docblock type-decl"]' 'fields omitted'
-pub struct PrivStruct {
- a: usize,
- b: usize,
-}
-
-// @has 'item_hide_threshold/enum.Enum.html'
-// @count - '//details[@class="rustdoc-toggle type-contents-toggle"]' 1
-// @has - '//details[@class="rustdoc-toggle type-contents-toggle"]' 'Show fields'
-pub enum Enum {
- A, B, C,
- D {
- a: u8,
- b: u8
- }
-}
-
-// @has 'item_hide_threshold/enum.LargeEnum.html'
-// @count - '//details[@class="rustdoc-toggle type-contents-toggle"]' 1
-// @has - '//details[@class="rustdoc-toggle type-contents-toggle"]' 'Show variants'
-pub enum LargeEnum {
- A, B, C, D, E, F(u8), G, H, I, J, K, L, M
-}
-
-// @has 'item_hide_threshold/trait.Trait.html'
-// @count - '//details[@class="rustdoc-toggle type-contents-toggle"]' 0
-pub trait Trait {
- type A;
- #[must_use]
- fn foo();
- fn bar();
-}
-
-// @has 'item_hide_threshold/trait.GinormousTrait.html'
-// @count - '//details[@class="rustdoc-toggle type-contents-toggle"]' 1
-// @has - '//details[@class="rustdoc-toggle type-contents-toggle"]' 'Show associated items'
-pub trait GinormousTrait {
- type A;
- type B;
- type C;
- type D;
- type E;
- type F;
- type G;
- type H;
- type I;
- type J;
- type K;
- type L;
- type M;
- const N: usize = 1;
- #[must_use]
- fn foo();
- fn bar();
-}
-
-// @has 'item_hide_threshold/trait.HugeTrait.html'
-// @count - '//details[@class="rustdoc-toggle type-contents-toggle"]' 1
-// @has - '//details[@class="rustdoc-toggle type-contents-toggle"]' 'Show associated constants and methods'
-pub trait HugeTrait {
- type A;
- const M: usize = 1;
- const N: usize = 1;
- const O: usize = 1;
- const P: usize = 1;
- const Q: usize = 1;
- const R: usize = 1;
- const S: usize = 1;
- const T: usize = 1;
- const U: usize = 1;
- const V: usize = 1;
- const W: usize = 1;
- const X: usize = 1;
- #[must_use]
- fn foo();
- fn bar();
-}
-
-// @has 'item_hide_threshold/trait.BigTrait.html'
-// @count - '//details[@class="rustdoc-toggle type-contents-toggle"]' 1
-// @has - '//details[@class="rustdoc-toggle type-contents-toggle"]' 'Show methods'
-pub trait BigTrait {
- type A;
- #[must_use]
- fn foo();
- fn bar();
- fn baz();
- fn quux();
- fn frob();
- fn greeble();
- fn blap();
- fn whoop();
- fn pow();
- fn bang();
- fn oomph();
- fn argh();
- fn wap();
- fn ouch();
-}
// @has foo/index.html '//h2[@id="keywords"]' 'Keywords'
// @has foo/index.html '//a[@href="keyword.match.html"]' 'match'
-// @has foo/index.html '//div[@class="block items"]//a/@href' '#keywords'
+// @has foo/index.html '//div[@class="sidebar-elems"]//li/a' 'Keywords'
+// @has foo/index.html '//div[@class="sidebar-elems"]//li/a/@href' '#keywords'
// @has foo/keyword.match.html '//a[@class="keyword"]' 'match'
// @has foo/keyword.match.html '//span[@class="in-band"]' 'Keyword match'
// @has foo/keyword.match.html '//section[@id="main"]//div[@class="docblock"]//p' 'this is a test!'
// @has - '//*[@class="docblock"]' 'Docs associated with the S1 trait implementation.'
// @has - '//*[@class="docblock"]' 'Docs associated with the S1 trait a_method implementation.'
// @!has - '//*[@class="docblock"]' 'Docs associated with the trait a_method definition.'
-// @!has - '//div[@class="impl-items"]/details[@open=""]//div[@class="docblock"]' 'Docs associated with the trait b_method definition.'
-// @has - '//div[@class="impl-items"]/details//div[@class="docblock"]' 'Docs associated with the trait b_method definition.'
-// @!has - '//div[@class="impl-items"]/details[@open=""]//div[@class="docblock"]' 'Docs associated with the trait c_method definition.'
-// @has - '//div[@class="impl-items"]/details//div[@class="docblock"]' 'Docs associated with the trait c_method definition.'
+// @has - '//div[@class="impl-items"]//div[@class="docblock"]' 'Docs associated with the trait b_method definition.'
+// @has - '//div[@class="impl-items"]//div[@class="docblock"]' 'Docs associated with the trait c_method definition.'
// @!has - '//*[@class="docblock"]' 'There is another line'
-// @!has - '//div[@class="impl-items"]/details[@open=""]//div[@class="docblock"]' 'Read more'
-// @has - '//div[@class="impl-items"]/details//div[@class="docblock"]' 'Read more'
+// @has - '//div[@class="impl-items"]//div[@class="docblock"]' 'Read more'
pub struct S1(usize);
/// Docs associated with the S1 trait implementation.
// @has - '//*[@class="docblock"]' 'Docs associated with the S2 trait implementation.'
// @has - '//*[@class="docblock"]' 'Docs associated with the S2 trait a_method implementation.'
// @has - '//*[@class="docblock"]' 'Docs associated with the S2 trait c_method implementation.'
-// @!has - '//details[open=""]/div[@class="docblock"]' 'Docs associated with the trait a_method definition.'
-// @!has - '//details[open=""]/div[@class="docblock"]' 'Docs associated with the trait c_method definition.'
-// @!has - '//div[@class="impl-items"]/details[@open=""]//div[@class="docblock"]' 'Docs associated with the trait b_method definition.'
-// @has - '//div[@class="impl-items"]/details//div[@class="docblock"]' 'Docs associated with the trait b_method definition.'
+// @has - '//div[@class="impl-items"]//div[@class="docblock"]' 'Docs associated with the trait b_method definition.'
pub struct S2(usize);
/// Docs associated with the S2 trait implementation.
}
// @has manual_impl/struct.S3.html '//*[@class="trait"]' 'T'
-// @has - '//details/div[@class="docblock"]' 'Docs associated with the S3 trait implementation.'
-// @!has - '//details[@open=""]/div[@class="docblock"]' 'Docs associated with the S3 trait implementation.'
-// @has - '//details[@open=""]/div[@class="docblock"]' 'Docs associated with the S3 trait b_method implementation.'
-// @!has - '//div[@class="impl-items"]/details[@open=""]//div[@class="docblock"]' 'Docs associated with the trait a_method definition.'
-// @has - '//div[@class="impl-items"]/details//div[@class="docblock"]' 'Docs associated with the trait a_method definition.'
+// @has - '//div[@class="docblock"]' 'Docs associated with the S3 trait implementation.'
+// @has - '//div[@class="docblock"]' 'Docs associated with the S3 trait b_method implementation.'
+// @has - '//div[@class="impl-items"]//div[@class="docblock"]' 'Docs associated with the trait a_method definition.'
pub struct S3(usize);
/// Docs associated with the S3 trait implementation.
+++ /dev/null
-// @has must_use/struct.Struct.html //pre '#[must_use]'
-#[must_use]
-pub struct Struct {
- field: i32,
-}
-
-// @has must_use/enum.Enum.html //pre '#[must_use = "message"]'
-#[must_use = "message"]
-pub enum Enum {
- Variant(i32),
-}
pub struct Foo;
-// @count foo/struct.Foo.html '//*[@class="impl-items"]//*[@class="method"]' 2
+// @count foo/struct.Foo.html '//*[@class="impl-items"]//*[@class="method has-srclink"]' 2
// @!has - '//*[@class="impl-items"]//*[@class="method"]' 'mut'
impl Foo {
pub fn foo(mut self) {}
// @matches negative_impl/struct.Bravo.html '//pre' "pub struct Bravo<B>"
pub struct Bravo<B>(B);
-// @matches negative_impl/struct.Alpha.html '//*[@class="impl"]//code' "impl !Send for Alpha"
+// @matches negative_impl/struct.Alpha.html '//*[@class="impl has-srclink"]//code' \
+// "impl !Send for Alpha"
impl !Send for Alpha {}
-// @matches negative_impl/struct.Bravo.html '//*[@class="impl"]//code' "impl<B> !Send for Bravo<B>"
+// @matches negative_impl/struct.Bravo.html '//*[@class="impl has-srclink"]//code' "\
+// impl<B> !Send for Bravo<B>"
impl<B> !Send for Bravo<B> {}
include!("primitive/primitive-generic-impl.rs");
-// @has foo/primitive.i32.html '//h3[@id="impl-ToString"]//code' 'impl<T> ToString for T'
+// @has foo/primitive.i32.html '//div[@id="impl-ToString"]//code' 'impl<T> ToString for T'
#![crate_name = "foo"]
-// @has foo/struct.Foo.html '//*[@class="docblock"]/p/a[@href="https://doc.rust-lang.org/nightly/std/primitive.u32.html"]' 'u32'
-// @has foo/struct.Foo.html '//*[@class="docblock"]/p/a[@href="https://doc.rust-lang.org/nightly/std/primitive.i64.html"]' 'i64'
-// @has foo/struct.Foo.html '//*[@class="docblock"]/p/a[@href="https://doc.rust-lang.org/nightly/std/primitive.i32.html"]' 'std::primitive::i32'
-// @has foo/struct.Foo.html '//*[@class="docblock"]/p/a[@href="https://doc.rust-lang.org/nightly/std/primitive.str.html"]' 'std::primitive::str'
+// @has foo/struct.Foo.html '//*[@class="docblock"]/p/a[@href="{{channel}}/std/primitive.u32.html"]' 'u32'
+// @has foo/struct.Foo.html '//*[@class="docblock"]/p/a[@href="{{channel}}/std/primitive.i64.html"]' 'i64'
+// @has foo/struct.Foo.html '//*[@class="docblock"]/p/a[@href="{{channel}}/std/primitive.i32.html"]' 'std::primitive::i32'
+// @has foo/struct.Foo.html '//*[@class="docblock"]/p/a[@href="{{channel}}/std/primitive.str.html"]' 'std::primitive::str'
-// @has foo/struct.Foo.html '//*[@class="docblock"]/p/a[@href="https://doc.rust-lang.org/nightly/std/primitive.i32.html#associatedconstant.MAX"]' 'std::primitive::i32::MAX'
+// @has foo/struct.Foo.html '//*[@class="docblock"]/p/a[@href="{{channel}}/std/primitive.i32.html#associatedconstant.MAX"]' 'std::primitive::i32::MAX'
/// It contains [`u32`] and [i64].
/// It also links to [std::primitive::i32], [std::primitive::str],
// @has bar/p/index.html
// @has - '//code' 'pub use bool;'
-// @has - '//code/a[@href="https://doc.rust-lang.org/nightly/std/primitive.bool.html"]' 'bool'
+// @has - '//code/a[@href="{{channel}}/std/primitive.bool.html"]' 'bool'
// @has - '//code' 'pub use char as my_char;'
-// @has - '//code/a[@href="https://doc.rust-lang.org/nightly/std/primitive.char.html"]' 'char'
+// @has - '//code/a[@href="{{channel}}/std/primitive.char.html"]' 'char'
pub mod p {
pub use foo::bar::*;
}
// @has bar/baz/index.html
// @has - '//code' 'pub use bool;'
-// @has - '//code/a[@href="https://doc.rust-lang.org/nightly/std/primitive.bool.html"]' 'bool'
+// @has - '//code/a[@href="{{channel}}/std/primitive.bool.html"]' 'bool'
// @has - '//code' 'pub use char as my_char;'
-// @has - '//code/a[@href="https://doc.rust-lang.org/nightly/std/primitive.char.html"]' 'char'
+// @has - '//code/a[@href="{{channel}}/std/primitive.char.html"]' 'char'
pub use foo::bar as baz;
// @has bar/index.html
// @has - '//code' 'pub use str;'
-// @has - '//code/a[@href="https://doc.rust-lang.org/nightly/std/primitive.str.html"]' 'str'
+// @has - '//code/a[@href="{{channel}}/std/primitive.str.html"]' 'str'
// @has - '//code' 'pub use i32 as my_i32;'
-// @has - '//code/a[@href="https://doc.rust-lang.org/nightly/std/primitive.i32.html"]' 'i32'
+// @has - '//code/a[@href="{{channel}}/std/primitive.i32.html"]' 'i32'
pub use str;
pub use i32 as my_i32;
}
// @has foo/struct.Foo.html
-// @has - '//*[@class="method"]' 'pub fn new()'
-// @has - '//*[@class="method"]' 'fn not_pub()'
+// @has - '//*[@class="method has-srclink"]' 'pub fn new()'
+// @has - '//*[@class="method has-srclink"]' 'fn not_pub()'
pub struct Foo(usize);
impl Foo {
--- /dev/null
+#![feature(intrinsics)]
+#![feature(no_core)]
+
+#![no_core]
+#![crate_name = "foo"]
+
+extern "rust-intrinsic" {
+ // @has 'foo/fn.abort.html'
+ // @has - '//pre[@class="rust fn"]' 'pub extern "rust-intrinsic" fn abort() -> !'
+ pub fn abort() -> !;
+ // @has 'foo/fn.unreachable.html'
+ // @has - '//pre[@class="rust fn"]' 'pub unsafe extern "rust-intrinsic" fn unreachable() -> !'
+ pub fn unreachable() -> !;
+}
+
+extern "C" {
+ // @has 'foo/fn.needs_drop.html'
+ // @has - '//pre[@class="rust fn"]' 'pub unsafe extern "C" fn needs_drop() -> !'
+ pub fn needs_drop() -> !;
+}
// @has - '//*[@class="sidebar-title"][@href="#foreign-impls"]' 'Implementations on Foreign Types'
// @has - '//h2[@id="foreign-impls"]' 'Implementations on Foreign Types'
// @has - '//*[@class="sidebar-links"]/a[@href="#impl-Foo-for-u32"]' 'u32'
-// @has - '//h3[@id="impl-Foo-for-u32"]//code' 'impl Foo for u32'
+// @has - '//div[@id="impl-Foo-for-u32"]//code' 'impl Foo for u32'
// @has - '//*[@class="sidebar-links"]/a[@href="#impl-Foo-for-%26%27a%20str"]' "&'a str"
-// @has - '//h3[@id="impl-Foo-for-%26%27a%20str"]//code' "impl<'a> Foo for &'a str"
+// @has - '//div[@id="impl-Foo-for-%26%27a%20str"]//code' "impl<'a> Foo for &'a str"
pub trait Foo {}
impl Foo for u32 {}
#![crate_name = "foo"]
// @has foo/struct.Bar.html
-// @!has - '//h3[@id="impl-Sized"]'
+// @!has - '//div[@id="impl-Sized"]'
pub struct Bar {
a: u16,
}
// @has foo/struct.Foo.html
-// @!has - '//h3[@id="impl-Sized"]'
+// @!has - '//div[@id="impl-Sized"]'
pub struct Foo<T: ?Sized>(T);
// @has foo/struct.Unsized.html
-// @has - '//h3[@id="impl-Sized"]/code' 'impl !Sized for Unsized'
+// @has - '//div[@id="impl-Sized"]/code' 'impl !Sized for Unsized'
pub struct Unsized {
data: [u8],
}
use std::iter::Iterator;
// @has foo/struct.Odd.html
-// @has - '//h4[@id="method.new"]//span[@class="notable-traits"]//code/span' 'impl Iterator for Odd'
+// @has - '//div[@id="method.new"]//span[@class="notable-traits"]//code/span' 'impl Iterator for Odd'
pub struct Odd {
current: usize,
}
#![crate_name = "foo"]
// @has foo/struct.Unsized.html
-// @has - '//h3[@id="impl-Sized"]/code' 'impl !Sized for Unsized'
-// @!has - '//h3[@id="impl-Sized"]/a[@class="srclink"]' '[src]'
-// @has - '//h3[@id="impl-Sync"]/code' 'impl Sync for Unsized'
-// @!has - '//h3[@id="impl-Sync"]/a[@class="srclink"]' '[src]'
-// @has - '//h3[@id="impl-Any"]/code' 'impl<T> Any for T'
-// @has - '//h3[@id="impl-Any"]/a[@class="srclink"]' '[src]'
+// @has - '//div[@id="impl-Sized"]/code' 'impl !Sized for Unsized'
+// @!has - '//div[@id="impl-Sized"]/a[@class="srclink"]' '[src]'
+// @has - '//div[@id="impl-Sync"]/code' 'impl Sync for Unsized'
+// @!has - '//div[@id="impl-Sync"]/a[@class="srclink"]' '[src]'
+// @has - '//div[@id="impl-Any"]/code' 'impl<T> Any for T'
+// @has - '//div[@id="impl-Any"]/a[@class="srclink"]' '[src]'
pub struct Unsized {
data: [u8],
}
// @has basic/struct.Foo.html
// @has - '//code' 'impl<T> Send for Foo<T> where T: Send'
// @has - '//code' 'impl<T> Sync for Foo<T> where T: Sync'
-// @count - '//*[@id="implementations-list"]//*[@class="impl"]' 0
-// @count - '//*[@id="synthetic-implementations-list"]//*[@class="impl"]' 5
+// @count - '//*[@id="implementations-list"]//*[@class="impl has-srclink"]' 0
+// @count - '//*[@id="synthetic-implementations-list"]//*[@class="impl has-srclink"]' 5
pub struct Foo<T> {
field: T,
}
}
// @has complex/struct.NotOuter.html
-// @has - '//*[@id="synthetic-implementations-list"]//*[@class="impl"]//code' "impl<'a, T, K: \
-// ?Sized> Send for Outer<'a, T, K> where K: for<'b> Fn((&'b bool, &'a u8)) \
+// @has - '//*[@id="synthetic-implementations-list"]//*[@class="impl has-srclink"]//code' \
+// "impl<'a, T, K: ?Sized> Send for Outer<'a, T, K> where K: for<'b> Fn((&'b bool, &'a u8)) \
// -> &'b i8, T: MyTrait<'a>, <T as MyTrait<'a>>::MyItem: Copy, 'a: 'static"
pub use foo::{Foo, Inner as NotInner, MyTrait as NotMyTrait, Outer as NotOuter};
{}
// @has lifetimes/struct.Foo.html
-// @has - '//*[@id="synthetic-implementations-list"]//*[@class="impl"]//code' "impl<'c, K> Send \
-// for Foo<'c, K> where K: for<'b> Fn(&'b bool) -> &'c u8, 'c: 'static"
+// @has - '//*[@id="synthetic-implementations-list"]//*[@class="impl has-srclink"]//code' \
+// "impl<'c, K> Send for Foo<'c, K> where K: for<'b> Fn(&'b bool) -> &'c u8, 'c: 'static"
//
-// @has - '//*[@id="synthetic-implementations-list"]//*[@class="impl"]//code' "impl<'c, K> Sync \
-// for Foo<'c, K> where K: Sync"
+// @has - '//*[@id="synthetic-implementations-list"]//*[@class="impl has-srclink"]//code' \
+// "impl<'c, K> Sync for Foo<'c, K> where K: Sync"
pub struct Foo<'c, K: 'c> {
inner_field: Inner<'c, K>,
}
// @has manual/struct.Foo.html
-// @has - '//*[@id="synthetic-implementations-list"]//*[@class="impl"]//code' 'impl<T> Sync for \
-// Foo<T> where T: Sync'
+// @has - '//*[@id="synthetic-implementations-list"]//*[@class="impl has-srclink"]//code' \
+// 'impl<T> Sync for Foo<T> where T: Sync'
//
-// @has - '//*[@id="trait-implementations-list"]//*[@class="impl"]//code' \
+// @has - '//*[@id="trait-implementations-list"]//*[@class="impl has-srclink"]//code' \
// 'impl<T> Send for Foo<T>'
//
-// @count - '//*[@id="trait-implementations-list"]//*[@class="impl"]' 1
-// @count - '//*[@id="synthetic-implementations-list"]//*[@class="impl"]' 4
+// @count - '//*[@id="trait-implementations-list"]//*[@class="impl has-srclink"]' 1
+// @count - '//*[@id="synthetic-implementations-list"]//*[@class="impl has-srclink"]' 4
pub struct Foo<T> {
field: T,
}
}
// @has negative/struct.Outer.html
-// @has - '//*[@id="synthetic-implementations-list"]//*[@class="impl"]//code' "impl<T> !Send for \
-// Outer<T>"
+// @has - '//*[@id="synthetic-implementations-list"]//*[@class="impl has-srclink"]//code' \
+// "impl<T> !Send for Outer<T>"
//
-// @has - '//*[@id="synthetic-implementations-list"]//*[@class="impl"]//code' "impl<T> \
-// !Sync for Outer<T>"
+// @has - '//*[@id="synthetic-implementations-list"]//*[@class="impl has-srclink"]//code' \
+// "impl<T> !Sync for Outer<T>"
pub struct Outer<T: Copy> {
inner_field: Inner<T>,
}
}
// @has nested/struct.Foo.html
-// @has - '//*[@id="synthetic-implementations-list"]//*[@class="impl"]//code' 'impl<T> Send for \
-// Foo<T> where T: Copy'
+// @has - '//*[@id="synthetic-implementations-list"]//*[@class="impl has-srclink"]//code' \
+// 'impl<T> Send for Foo<T> where T: Copy'
//
-// @has - '//*[@id="synthetic-implementations-list"]//*[@class="impl"]//code' \
+// @has - '//*[@id="synthetic-implementations-list"]//*[@class="impl has-srclink"]//code' \
// 'impl<T> Sync for Foo<T> where T: Sync'
pub struct Foo<T> {
inner_field: Inner<T>,
}
// @has no_redundancy/struct.Outer.html
-// @has - '//*[@id="synthetic-implementations-list"]//*[@class="impl"]//code' "impl<T> Send for \
-// Outer<T> where T: Copy + Send"
+// @has - '//*[@id="synthetic-implementations-list"]//*[@class="impl has-srclink"]//code' \
+// "impl<T> Send for Outer<T> where T: Copy + Send"
pub struct Outer<T> {
inner_field: Inner<T>,
}
}
// @has project/struct.Foo.html
-// @has - '//*[@id="synthetic-implementations-list"]//*[@class="impl"]//code' "impl<'c, K> Send \
-// for Foo<'c, K> where K: MyTrait<MyItem = bool>, 'c: 'static"
+// @has - '//*[@id="synthetic-implementations-list"]//*[@class="impl has-srclink"]//code' \
+// "impl<'c, K> Send for Foo<'c, K> where K: MyTrait<MyItem = bool>, 'c: 'static"
//
-// @has - '//*[@id="synthetic-implementations-list"]//*[@class="impl"]//code' "impl<'c, K> Sync \
-// for Foo<'c, K> where K: MyTrait, <K as MyTrait>::MyItem: OtherTrait, 'c: 'static,"
+// @has - '//*[@id="synthetic-implementations-list"]//*[@class="impl has-srclink"]//code' \
+// "impl<'c, K> Sync for Foo<'c, K> where K: MyTrait, <K as MyTrait>::MyItem: OtherTrait, \
+// 'c: 'static,"
pub struct Foo<'c, K: 'c> {
inner_field: Inner<'c, K>,
}
// @has self_referential/struct.WriteAndThen.html
-// @has - '//*[@id="synthetic-implementations-list"]//*[@class="impl"]//code' "impl<P1> Send for \
-// WriteAndThen<P1> where <P1 as Pattern>::Value: Send"
+// @has - '//*[@id="synthetic-implementations-list"]//*[@class="impl has-srclink"]//code' \
+// "impl<P1> Send for WriteAndThen<P1> where <P1 as Pattern>::Value: Send"
pub struct WriteAndThen<P1>(pub P1::Value,pub <Constrain<P1, Wrapper<P1::Value>> as Pattern>::Value)
where P1: Pattern;
}
// @has static_region/struct.Owned.html
-// @has - '//*[@id="synthetic-implementations-list"]//*[@class="impl"]//code' "impl<T> Send for \
-// Owned<T> where <T as OwnedTrait<'static>>::Reader: Send"
+// @has - '//*[@id="synthetic-implementations-list"]//*[@class="impl has-srclink"]//code' \
+// "impl<T> Send for Owned<T> where <T as OwnedTrait<'static>>::Reader: Send"
pub struct Owned<T> where T: OwnedTrait<'static> {
marker: <T as OwnedTrait<'static>>::Reader,
}
--- /dev/null
+#![allow(unused)]
+
+// @has 'toggle_item_contents/struct.PubStruct.html'
+// @count - '//details[@class="rustdoc-toggle type-contents-toggle"]' 0
+pub struct PubStruct {
+ pub a: usize,
+ pub b: usize,
+}
+
+// @has 'toggle_item_contents/struct.BigPubStruct.html'
+// @count - '//details[@class="rustdoc-toggle type-contents-toggle"]' 1
+// @has - '//details[@class="rustdoc-toggle type-contents-toggle"]' 'Show fields'
+pub struct BigPubStruct {
+ pub a: usize,
+ pub b: usize,
+ pub c: usize,
+ pub d: usize,
+ pub e: usize,
+ pub f: usize,
+ pub g: usize,
+ pub h: usize,
+ pub i: usize,
+ pub j: usize,
+ pub k: usize,
+ pub l: usize,
+ pub m: usize,
+}
+
+// @has 'toggle_item_contents/union.BigUnion.html'
+// @count - '//details[@class="rustdoc-toggle type-contents-toggle"]' 1
+// @has - '//details[@class="rustdoc-toggle type-contents-toggle"]' 'Show fields'
+pub union BigUnion {
+ pub a: usize,
+ pub b: usize,
+ pub c: usize,
+ pub d: usize,
+ pub e: usize,
+ pub f: usize,
+ pub g: usize,
+ pub h: usize,
+ pub i: usize,
+ pub j: usize,
+ pub k: usize,
+ pub l: usize,
+ pub m: usize,
+}
+
+// @has 'toggle_item_contents/union.Union.html'
+// @count - '//details[@class="rustdoc-toggle type-contents-toggle"]' 0
+pub union Union {
+ pub a: usize,
+ pub b: usize,
+ pub c: usize,
+}
+
+// @has 'toggle_item_contents/struct.PrivStruct.html'
+// @count - '//details[@class="rustdoc-toggle type-contents-toggle"]' 0
+// @has - '//div[@class="docblock type-decl"]' 'fields omitted'
+pub struct PrivStruct {
+ a: usize,
+ b: usize,
+}
+
+// @has 'toggle_item_contents/enum.Enum.html'
+// @count - '//details[@class="rustdoc-toggle type-contents-toggle"]' 1
+// @has - '//details[@class="rustdoc-toggle type-contents-toggle"]' 'Show fields'
+pub enum Enum {
+ A, B, C,
+ D {
+ a: u8,
+ b: u8
+ }
+}
+
+// @has 'toggle_item_contents/enum.LargeEnum.html'
+// @count - '//details[@class="rustdoc-toggle type-contents-toggle"]' 1
+// @has - '//details[@class="rustdoc-toggle type-contents-toggle"]' 'Show variants'
+pub enum LargeEnum {
+ A, B, C, D, E, F(u8), G, H, I, J, K, L, M
+}
+
+// @has 'toggle_item_contents/trait.Trait.html'
+// @count - '//details[@class="rustdoc-toggle type-contents-toggle"]' 0
+pub trait Trait {
+ type A;
+ #[must_use]
+ fn foo();
+ fn bar();
+}
+
+// @has 'toggle_item_contents/trait.GinormousTrait.html'
+// @count - '//details[@class="rustdoc-toggle type-contents-toggle"]' 1
+// @has - '//details[@class="rustdoc-toggle type-contents-toggle"]' 'Show associated items'
+pub trait GinormousTrait {
+ type A;
+ type B;
+ type C;
+ type D;
+ type E;
+ type F;
+ type G;
+ type H;
+ type I;
+ type J;
+ type K;
+ type L;
+ type M;
+ const N: usize = 1;
+ #[must_use]
+ fn foo();
+ fn bar();
+}
+
+// @has 'toggle_item_contents/trait.HugeTrait.html'
+// @count - '//details[@class="rustdoc-toggle type-contents-toggle"]' 1
+// @has - '//details[@class="rustdoc-toggle type-contents-toggle"]' 'Show associated constants and methods'
+pub trait HugeTrait {
+ type A;
+ const M: usize = 1;
+ const N: usize = 1;
+ const O: usize = 1;
+ const P: usize = 1;
+ const Q: usize = 1;
+ const R: usize = 1;
+ const S: usize = 1;
+ const T: usize = 1;
+ const U: usize = 1;
+ const V: usize = 1;
+ const W: usize = 1;
+ const X: usize = 1;
+ #[must_use]
+ fn foo();
+ fn bar();
+}
+
+// @has 'toggle_item_contents/trait.BigTrait.html'
+// @count - '//details[@class="rustdoc-toggle type-contents-toggle"]' 1
+// @has - '//details[@class="rustdoc-toggle type-contents-toggle"]' 'Show methods'
+pub trait BigTrait {
+ type A;
+ #[must_use]
+ fn foo();
+ fn bar();
+ fn baz();
+ fn quux();
+ fn frob();
+ fn greeble();
+ fn blap();
+ fn whoop();
+ fn pow();
+ fn bang();
+ fn oomph();
+ fn argh();
+ fn wap();
+ fn ouch();
+}
--- /dev/null
+#![crate_name = "foo"]
+
+// Struct methods with documentation should be wrapped in a <details> toggle with an appropriate
+// summary. Struct methods with no documentation should not be wrapped.
+//
+// @has foo/struct.Foo.html
+// @has - '//details[@class="rustdoc-toggle method-toggle"]//summary//code' 'is_documented()'
+// @has - '//details[@class="rustdoc-toggle method-toggle"]//*[@class="docblock"]' 'is_documented is documented'
+// @!has - '//details[@class="rustdoc-toggle method-toggle"]//summary//code' 'not_documented()'
+pub struct Foo {
+}
+
+impl Foo {
+ pub fn not_documented() {}
+
+ /// is_documented is documented
+ pub fn is_documented() {}
+}
#![crate_name = "foo"]
+// Trait methods with documentation should be wrapped in a <details> toggle with an appropriate
+// summary. Trait methods with no documentation should not be wrapped.
+//
// @has foo/trait.Foo.html
-// @has - '//details[@class="rustdoc-toggle"]//code' 'bar'
+// @has - '//details[@class="rustdoc-toggle"]//summary//code' 'is_documented()'
+// @!has - '//details[@class="rustdoc-toggle"]//summary//code' 'not_documented()'
+// @has - '//details[@class="rustdoc-toggle"]//*[@class="docblock"]' 'is_documented is documented'
+// @has - '//details[@class="rustdoc-toggle"]//summary//code' 'is_documented_optional()'
+// @!has - '//details[@class="rustdoc-toggle"]//summary//code' 'not_documented_optional()'
+// @has - '//details[@class="rustdoc-toggle"]//*[@class="docblock"]' 'is_documented_optional is documented'
pub trait Foo {
- fn bar() -> ();
+ fn not_documented();
+
+ /// is_documented is documented
+ fn is_documented();
+
+ fn not_documented_optional() {}
+
+ /// is_documented_optional is documented
+ fn is_documented_optional() {}
}
+++ /dev/null
-#![crate_name = "foo"]
-
-
-pub trait Foo {
- // @has foo/trait.Foo.html '//h3[@id="tymethod.foo"]//div[@class="code-attribute"]' '#[must_use]'
- #[must_use]
- fn foo();
-}
-
-#[must_use]
-pub struct Bar;
-
-impl Bar {
- // @has foo/struct.Bar.html '//h4[@id="method.bar"]//div[@class="code-attribute"]' '#[must_use]'
- #[must_use]
- pub fn bar() {}
-
- // @has foo/struct.Bar.html '//h4[@id="method.bar2"]//div[@class="code-attribute"]' '#[must_use]'
- #[must_use]
- pub fn bar2() {}
-}
impl MyTrait for String {
- // @has trait_impl_items_links_and_anchors/trait.MyTrait.html '//h4[@id="associatedtype.Assoc-1"]//a[@class="type"]/@href' #associatedtype.Assoc
- // @has trait_impl_items_links_and_anchors/trait.MyTrait.html '//h4[@id="associatedtype.Assoc-1"]//a[@class="anchor"]/@href' #associatedtype.Assoc-1
+ // @has trait_impl_items_links_and_anchors/trait.MyTrait.html '//div[@id="associatedtype.Assoc-1"]//a[@class="type"]/@href' #associatedtype.Assoc
+ // @has trait_impl_items_links_and_anchors/trait.MyTrait.html '//div[@id="associatedtype.Assoc-1"]//a[@class="anchor"]/@href' #associatedtype.Assoc-1
type Assoc = ();
- // @has trait_impl_items_links_and_anchors/trait.MyTrait.html '//h4[@id="associatedconstant.VALUE-1"]//a[@class="constant"]/@href' #associatedconstant.VALUE
- // @has trait_impl_items_links_and_anchors/trait.MyTrait.html '//h4[@id="associatedconstant.VALUE-1"]//a[@class="anchor"]/@href' #associatedconstant.VALUE-1
+ // @has trait_impl_items_links_and_anchors/trait.MyTrait.html '//div[@id="associatedconstant.VALUE-1"]//a[@class="constant"]/@href' #associatedconstant.VALUE
+ // @has trait_impl_items_links_and_anchors/trait.MyTrait.html '//div[@id="associatedconstant.VALUE-1"]//a[@class="anchor"]/@href' #associatedconstant.VALUE-1
const VALUE: u32 = 5;
- // @has trait_impl_items_links_and_anchors/trait.MyTrait.html '//h4[@id="method.trait_function"]//a[@class="fnname"]/@href' #tymethod.trait_function
- // @has trait_impl_items_links_and_anchors/trait.MyTrait.html '//h4[@id="method.trait_function"]//a[@class="anchor"]/@href' #method.trait_function
+ // @has trait_impl_items_links_and_anchors/trait.MyTrait.html '//div[@id="method.trait_function"]//a[@class="fnname"]/@href' #tymethod.trait_function
+ // @has trait_impl_items_links_and_anchors/trait.MyTrait.html '//div[@id="method.trait_function"]//a[@class="anchor"]/@href' #method.trait_function
fn trait_function(&self) {}
- // @has trait_impl_items_links_and_anchors/trait.MyTrait.html '//h4[@id="method.defaulted_override-1"]//a[@class="fnname"]/@href' #method.defaulted_override
- // @has trait_impl_items_links_and_anchors/trait.MyTrait.html '//h4[@id="method.defaulted_override-1"]//a[@class="anchor"]/@href' #method.defaulted_override-1
+ // @has trait_impl_items_links_and_anchors/trait.MyTrait.html '//div[@id="method.defaulted_override-1"]//a[@class="fnname"]/@href' #method.defaulted_override
+ // @has trait_impl_items_links_and_anchors/trait.MyTrait.html '//div[@id="method.defaulted_override-1"]//a[@class="anchor"]/@href' #method.defaulted_override-1
fn defaulted_override(&self) {}
}
impl MyTrait for Vec<u8> {
- // @has trait_impl_items_links_and_anchors/trait.MyTrait.html '//h4[@id="associatedtype.Assoc-2"]//a[@class="type"]/@href' #associatedtype.Assoc
- // @has trait_impl_items_links_and_anchors/trait.MyTrait.html '//h4[@id="associatedtype.Assoc-2"]//a[@class="anchor"]/@href' #associatedtype.Assoc-2
+ // @has trait_impl_items_links_and_anchors/trait.MyTrait.html '//div[@id="associatedtype.Assoc-2"]//a[@class="type"]/@href' #associatedtype.Assoc
+ // @has trait_impl_items_links_and_anchors/trait.MyTrait.html '//div[@id="associatedtype.Assoc-2"]//a[@class="anchor"]/@href' #associatedtype.Assoc-2
type Assoc = ();
- // @has trait_impl_items_links_and_anchors/trait.MyTrait.html '//h4[@id="associatedconstant.VALUE-2"]//a[@class="constant"]/@href' #associatedconstant.VALUE
- // @has trait_impl_items_links_and_anchors/trait.MyTrait.html '//h4[@id="associatedconstant.VALUE-2"]//a[@class="anchor"]/@href' #associatedconstant.VALUE-2
+ // @has trait_impl_items_links_and_anchors/trait.MyTrait.html '//div[@id="associatedconstant.VALUE-2"]//a[@class="constant"]/@href' #associatedconstant.VALUE
+ // @has trait_impl_items_links_and_anchors/trait.MyTrait.html '//div[@id="associatedconstant.VALUE-2"]//a[@class="anchor"]/@href' #associatedconstant.VALUE-2
const VALUE: u32 = 5;
- // @has trait_impl_items_links_and_anchors/trait.MyTrait.html '//h4[@id="method.trait_function"]//a[@class="fnname"]/@href' #tymethod.trait_function
- // @has trait_impl_items_links_and_anchors/trait.MyTrait.html '//h4[@id="method.trait_function-1"]//a[@class="anchor"]/@href' #method.trait_function-1
+ // @has trait_impl_items_links_and_anchors/trait.MyTrait.html '//div[@id="method.trait_function"]//a[@class="fnname"]/@href' #tymethod.trait_function
+ // @has trait_impl_items_links_and_anchors/trait.MyTrait.html '//div[@id="method.trait_function-1"]//a[@class="anchor"]/@href' #method.trait_function-1
fn trait_function(&self) {}
- // @has trait_impl_items_links_and_anchors/trait.MyTrait.html '//h4[@id="method.defaulted_override-2"]//a[@class="fnname"]/@href' #method.defaulted_override
- // @has trait_impl_items_links_and_anchors/trait.MyTrait.html '//h4[@id="method.defaulted_override-2"]//a[@class="anchor"]/@href' #method.defaulted_override-2
+ // @has trait_impl_items_links_and_anchors/trait.MyTrait.html '//div[@id="method.defaulted_override-2"]//a[@class="fnname"]/@href' #method.defaulted_override
+ // @has trait_impl_items_links_and_anchors/trait.MyTrait.html '//div[@id="method.defaulted_override-2"]//a[@class="anchor"]/@href' #method.defaulted_override-2
fn defaulted_override(&self) {}
}
impl MyTrait for MyStruct {
- // @has trait_impl_items_links_and_anchors/trait.MyTrait.html '//h4[@id="associatedtype.Assoc-3"]//a[@class="type"]/@href' #associatedtype.Assoc
- // @has trait_impl_items_links_and_anchors/trait.MyTrait.html '//h4[@id="associatedtype.Assoc-3"]//a[@class="anchor"]/@href' #associatedtype.Assoc-3
- // @has trait_impl_items_links_and_anchors/struct.MyStruct.html '//h4[@id="associatedtype.Assoc"]//a[@class="type"]/@href' trait.MyTrait.html#associatedtype.Assoc
- // @has trait_impl_items_links_and_anchors/struct.MyStruct.html '//h4[@id="associatedtype.Assoc"]//a[@class="anchor"]/@href' #associatedtype.Assoc
+ // @has trait_impl_items_links_and_anchors/trait.MyTrait.html '//div[@id="associatedtype.Assoc-3"]//a[@class="type"]/@href' #associatedtype.Assoc
+ // @has trait_impl_items_links_and_anchors/trait.MyTrait.html '//div[@id="associatedtype.Assoc-3"]//a[@class="anchor"]/@href' #associatedtype.Assoc-3
+ // @has trait_impl_items_links_and_anchors/struct.MyStruct.html '//div[@id="associatedtype.Assoc"]//a[@class="type"]/@href' trait.MyTrait.html#associatedtype.Assoc
+ // @has trait_impl_items_links_and_anchors/struct.MyStruct.html '//div[@id="associatedtype.Assoc"]//a[@class="anchor"]/@href' #associatedtype.Assoc
type Assoc = bool;
- // @has trait_impl_items_links_and_anchors/trait.MyTrait.html '//h4[@id="associatedconstant.VALUE-3"]//a[@class="constant"]/@href' #associatedconstant.VALUE
- // @has trait_impl_items_links_and_anchors/trait.MyTrait.html '//h4[@id="associatedconstant.VALUE-3"]//a[@class="anchor"]/@href' #associatedconstant.VALUE-3
- // @has trait_impl_items_links_and_anchors/struct.MyStruct.html '//h4[@id="associatedconstant.VALUE"]//a[@class="constant"]/@href' trait.MyTrait.html#associatedconstant.VALUE
- // @has trait_impl_items_links_and_anchors/struct.MyStruct.html '//h4[@id="associatedconstant.VALUE"]//a[@class="anchor"]/@href' #associatedconstant.VALUE
+ // @has trait_impl_items_links_and_anchors/trait.MyTrait.html '//div[@id="associatedconstant.VALUE-3"]//a[@class="constant"]/@href' #associatedconstant.VALUE
+ // @has trait_impl_items_links_and_anchors/trait.MyTrait.html '//div[@id="associatedconstant.VALUE-3"]//a[@class="anchor"]/@href' #associatedconstant.VALUE-3
+ // @has trait_impl_items_links_and_anchors/struct.MyStruct.html '//div[@id="associatedconstant.VALUE"]//a[@class="constant"]/@href' trait.MyTrait.html#associatedconstant.VALUE
+ // @has trait_impl_items_links_and_anchors/struct.MyStruct.html '//div[@id="associatedconstant.VALUE"]//a[@class="anchor"]/@href' #associatedconstant.VALUE
const VALUE: u32 = 20;
- // @has trait_impl_items_links_and_anchors/trait.MyTrait.html '//h4[@id="method.trait_function-2"]//a[@class="fnname"]/@href' #tymethod.trait_function
- // @has trait_impl_items_links_and_anchors/trait.MyTrait.html '//h4[@id="method.trait_function-2"]//a[@class="anchor"]/@href' #method.trait_function-2
- // @has trait_impl_items_links_and_anchors/struct.MyStruct.html '//h4[@id="method.trait_function"]//a[@class="fnname"]/@href' trait.MyTrait.html#tymethod.trait_function
- // @has trait_impl_items_links_and_anchors/struct.MyStruct.html '//h4[@id="method.trait_function"]//a[@class="anchor"]/@href' #method.trait_function
+ // @has trait_impl_items_links_and_anchors/trait.MyTrait.html '//div[@id="method.trait_function-2"]//a[@class="fnname"]/@href' #tymethod.trait_function
+ // @has trait_impl_items_links_and_anchors/trait.MyTrait.html '//div[@id="method.trait_function-2"]//a[@class="anchor"]/@href' #method.trait_function-2
+ // @has trait_impl_items_links_and_anchors/struct.MyStruct.html '//div[@id="method.trait_function"]//a[@class="fnname"]/@href' trait.MyTrait.html#tymethod.trait_function
+ // @has trait_impl_items_links_and_anchors/struct.MyStruct.html '//div[@id="method.trait_function"]//a[@class="anchor"]/@href' #method.trait_function
fn trait_function(&self) {}
- // @has trait_impl_items_links_and_anchors/trait.MyTrait.html '//h4[@id="method.defaulted_override-3"]//a[@class="fnname"]/@href' #method.defaulted_override
- // @has trait_impl_items_links_and_anchors/trait.MyTrait.html '//h4[@id="method.defaulted_override-3"]//a[@class="anchor"]/@href' #method.defaulted_override-3
- // @has trait_impl_items_links_and_anchors/struct.MyStruct.html '//h4[@id="method.defaulted_override"]//a[@class="fnname"]/@href' trait.MyTrait.html#method.defaulted_override
- // @has trait_impl_items_links_and_anchors/struct.MyStruct.html '//h4[@id="method.defaulted_override"]//a[@class="anchor"]/@href' #method.defaulted_override
+ // @has trait_impl_items_links_and_anchors/trait.MyTrait.html '//div[@id="method.defaulted_override-3"]//a[@class="fnname"]/@href' #method.defaulted_override
+ // @has trait_impl_items_links_and_anchors/trait.MyTrait.html '//div[@id="method.defaulted_override-3"]//a[@class="anchor"]/@href' #method.defaulted_override-3
+ // @has trait_impl_items_links_and_anchors/struct.MyStruct.html '//div[@id="method.defaulted_override"]//a[@class="fnname"]/@href' trait.MyTrait.html#method.defaulted_override
+ // @has trait_impl_items_links_and_anchors/struct.MyStruct.html '//div[@id="method.defaulted_override"]//a[@class="anchor"]/@href' #method.defaulted_override
fn defaulted_override(&self) {}
- // @has trait_impl_items_links_and_anchors/struct.MyStruct.html '//h4[@id="method.defaulted"]//a[@class="fnname"]/@href' trait.MyTrait.html#method.defaulted
- // @has trait_impl_items_links_and_anchors/struct.MyStruct.html '//h4[@id="method.defaulted"]//a[@class="anchor"]/@href' #method.defaulted
+ // @has trait_impl_items_links_and_anchors/struct.MyStruct.html '//div[@id="method.defaulted"]//a[@class="fnname"]/@href' trait.MyTrait.html#method.defaulted
+ // @has trait_impl_items_links_and_anchors/struct.MyStruct.html '//div[@id="method.defaulted"]//a[@class="anchor"]/@href' #method.defaulted
}
pub struct MyStruct;
}
// @has typedef/type.MyAlias.html
-// @has - '//*[@class="impl"]//code' 'impl MyAlias'
-// @has - '//*[@class="impl"]//code' 'impl MyTrait for MyAlias'
+// @has - '//*[@class="impl has-srclink"]//code' 'impl MyAlias'
+// @has - '//*[@class="impl has-srclink"]//code' 'impl MyTrait for MyAlias'
// @has - 'Alias docstring'
// @has - '//*[@class="sidebar"]//p[@class="location"]' 'Type Definition MyAlias'
// @has - '//*[@class="sidebar"]//a[@href="#implementations"]' 'Methods'
-#![feature(external_doc)]
-
#![crate_name = "foo"]
// @has foo/struct.Example.html
// @matches - '//div[@class="docblock"]/p' '(?m)a\nno whitespace\nJust some text.\Z'
///a
///no whitespace
-#[doc(include = "unindent.md")]
+#[doc = include_str!("unindent.md")]
pub struct J;
// @has foo/struct.K.html
///
/// 4 whitespaces!
///
-#[doc(include = "unindent.md")]
+#[doc = include_str!("unindent.md")]
pub struct K;
pub struct Delta<D>(D);
-// @has foo/struct.Delta.html '//*[@class="impl"]//code' \
+// @has foo/struct.Delta.html '//*[@class="impl has-srclink"]//code' \
// "impl<D> Delta<D> where D: MyTrait"
impl<D> Delta<D> where D: MyTrait {
pub fn delta() {}
pub struct Echo<E>(E);
-// @has foo/struct.Echo.html '//*[@class="impl"]//code' \
+// @has foo/struct.Echo.html '//*[@class="impl has-srclink"]//code' \
// "impl<E> MyTrait for Echo<E> where E: MyTrait"
// @has foo/trait.MyTrait.html '//*[@id="implementors-list"]//code' \
// "impl<E> MyTrait for Echo<E> where E: MyTrait"
pub enum Foxtrot<F> { Foxtrot1(F) }
-// @has foo/enum.Foxtrot.html '//*[@class="impl"]//code' \
+// @has foo/enum.Foxtrot.html '//*[@class="impl has-srclink"]//code' \
// "impl<F> MyTrait for Foxtrot<F> where F: MyTrait"
// @has foo/trait.MyTrait.html '//*[@id="implementors-list"]//code' \
// "impl<F> MyTrait for Foxtrot<F> where F: MyTrait"
+// compile-flags: -Z unstable-options
// NOTE: This test doesn't actually require `fulldeps`
// so we could instead use it as an `ui` test.
//
error: passing `TyCtxt<'tcx>` by reference
- --> $DIR/pass_ty_by_ref_self.rs:17:15
+ --> $DIR/pass_ty_by_ref_self.rs:18:15
|
LL | fn by_ref(&self) {}
| ^^^^^ help: try passing by value: `TyCtxt<'tcx>`
|
note: the lint level is defined here
- --> $DIR/pass_ty_by_ref_self.rs:7:9
+ --> $DIR/pass_ty_by_ref_self.rs:8:9
|
LL | #![deny(rustc::ty_pass_by_reference)]
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^
error: passing `Ty<'tcx>` by reference
- --> $DIR/pass_ty_by_ref_self.rs:30:21
+ --> $DIR/pass_ty_by_ref_self.rs:31:21
|
LL | fn by_ref(self: &Ty<'tcx>) {}
| ^^^^^^^^^ help: try passing by value: `Ty<'tcx>`
#![feature(rustc_private)]
+extern crate rustc_ast;
extern crate rustc_ast_pretty;
extern crate rustc_data_structures;
-extern crate rustc_ast;
extern crate rustc_parse;
extern crate rustc_session;
extern crate rustc_span;
+use rustc_ast::mut_visit::{self, visit_clobber, MutVisitor};
+use rustc_ast::ptr::P;
+use rustc_ast::*;
use rustc_ast_pretty::pprust;
use rustc_data_structures::thin_vec::ThinVec;
use rustc_parse::new_parser_from_source_str;
use rustc_session::parse::ParseSess;
-use rustc_span::source_map::{Spanned, DUMMY_SP, FileName};
use rustc_span::source_map::FilePathMapping;
+use rustc_span::source_map::{FileName, Spanned, DUMMY_SP};
use rustc_span::symbol::Ident;
-use rustc_ast::*;
-use rustc_ast::mut_visit::{self, MutVisitor, visit_clobber};
-use rustc_ast::ptr::P;
fn parse_expr(ps: &ParseSess, src: &str) -> Option<P<Expr>> {
let src_as_string = src.to_string();
- let mut p = new_parser_from_source_str(
- ps,
- FileName::Custom(src_as_string.clone()),
- src_as_string,
- );
+ let mut p =
+ new_parser_from_source_str(ps, FileName::Custom(src_as_string.clone()), src_as_string);
p.parse_expr().map_err(|mut e| e.cancel()).ok()
}
-
// Helper functions for building exprs
fn expr(kind: ExprKind) -> P<Expr> {
- P(Expr {
- id: DUMMY_NODE_ID,
- kind,
- span: DUMMY_SP,
- attrs: ThinVec::new(),
- tokens: None
- })
+ P(Expr { id: DUMMY_NODE_ID, kind, span: DUMMY_SP, attrs: ThinVec::new(), tokens: None })
}
fn make_x() -> P<Expr> {
1 => iter_exprs(depth - 1, &mut |e| g(ExprKind::Call(e, vec![]))),
2 => {
let seg = PathSegment::from_ident(Ident::from_str("x"));
- iter_exprs(depth - 1, &mut |e| g(ExprKind::MethodCall(
- seg.clone(), vec![e, make_x()], DUMMY_SP)));
- iter_exprs(depth - 1, &mut |e| g(ExprKind::MethodCall(
- seg.clone(), vec![make_x(), e], DUMMY_SP)));
- },
+ iter_exprs(depth - 1, &mut |e| {
+ g(ExprKind::MethodCall(seg.clone(), vec![e, make_x()], DUMMY_SP))
+ });
+ iter_exprs(depth - 1, &mut |e| {
+ g(ExprKind::MethodCall(seg.clone(), vec![make_x(), e], DUMMY_SP))
+ });
+ }
3..=8 => {
let op = Spanned {
span: DUMMY_SP,
7 => BinOpKind::Or,
8 => BinOpKind::Lt,
_ => unreachable!(),
- }
+ },
};
iter_exprs(depth - 1, &mut |e| g(ExprKind::Binary(op, e, make_x())));
iter_exprs(depth - 1, &mut |e| g(ExprKind::Binary(op, make_x(), e)));
- },
+ }
9 => {
iter_exprs(depth - 1, &mut |e| g(ExprKind::Unary(UnOp::Deref, e)));
- },
+ }
10 => {
let block = P(Block {
stmts: Vec::new(),
tokens: None,
});
iter_exprs(depth - 1, &mut |e| g(ExprKind::If(e, block.clone(), None)));
- },
+ }
11 => {
- let decl = P(FnDecl {
- inputs: vec![],
- output: FnRetTy::Default(DUMMY_SP),
+ let decl = P(FnDecl { inputs: vec![], output: FnRetTy::Default(DUMMY_SP) });
+ iter_exprs(depth - 1, &mut |e| {
+ g(ExprKind::Closure(
+ CaptureBy::Value,
+ Async::No,
+ Movability::Movable,
+ decl.clone(),
+ e,
+ DUMMY_SP,
+ ))
});
- iter_exprs(depth - 1, &mut |e| g(
- ExprKind::Closure(CaptureBy::Value,
- Async::No,
- Movability::Movable,
- decl.clone(),
- e,
- DUMMY_SP)));
- },
+ }
12 => {
iter_exprs(depth - 1, &mut |e| g(ExprKind::Assign(e, make_x(), DUMMY_SP)));
iter_exprs(depth - 1, &mut |e| g(ExprKind::Assign(make_x(), e, DUMMY_SP)));
- },
+ }
13 => {
iter_exprs(depth - 1, &mut |e| g(ExprKind::Field(e, Ident::from_str("f"))));
- },
+ }
14 => {
- iter_exprs(depth - 1, &mut |e| g(ExprKind::Range(
- Some(e), Some(make_x()), RangeLimits::HalfOpen)));
- iter_exprs(depth - 1, &mut |e| g(ExprKind::Range(
- Some(make_x()), Some(e), RangeLimits::HalfOpen)));
- },
+ iter_exprs(depth - 1, &mut |e| {
+ g(ExprKind::Range(Some(e), Some(make_x()), RangeLimits::HalfOpen))
+ });
+ iter_exprs(depth - 1, &mut |e| {
+ g(ExprKind::Range(Some(make_x()), Some(e), RangeLimits::HalfOpen))
+ });
+ }
15 => {
- iter_exprs(
- depth - 1,
- &mut |e| g(ExprKind::AddrOf(BorrowKind::Ref, Mutability::Not, e)),
- );
- },
+ iter_exprs(depth - 1, &mut |e| {
+ g(ExprKind::AddrOf(BorrowKind::Ref, Mutability::Not, e))
+ });
+ }
16 => {
g(ExprKind::Ret(None));
iter_exprs(depth - 1, &mut |e| g(ExprKind::Ret(Some(e))));
- },
+ }
17 => {
let path = Path::from_ident(Ident::from_str("S"));
g(ExprKind::Struct(P(StructExpr {
- path, fields: vec![], rest: StructRest::Base(make_x())
+ qself: None,
+ path,
+ fields: vec![],
+ rest: StructRest::Base(make_x()),
})));
- },
+ }
18 => {
iter_exprs(depth - 1, &mut |e| g(ExprKind::Try(e)));
- },
+ }
19 => {
- let pat = P(Pat {
- id: DUMMY_NODE_ID,
- kind: PatKind::Wild,
- span: DUMMY_SP,
- tokens: None,
- });
+ let pat =
+ P(Pat { id: DUMMY_NODE_ID, kind: PatKind::Wild, span: DUMMY_SP, tokens: None });
iter_exprs(depth - 1, &mut |e| g(ExprKind::Let(pat.clone(), e)))
- },
+ }
_ => panic!("bad counter value in iter_exprs"),
}
}
}
-
// Folders for manipulating the placement of `Paren` nodes. See below for why this is needed.
/// `MutVisitor` that removes all `ExprKind::Paren` nodes.
}
}
-
/// `MutVisitor` that inserts `ExprKind::Paren` nodes around every `Expr`.
struct AddParens;
kind: ExprKind::Paren(e),
span: DUMMY_SP,
attrs: ThinVec::new(),
- tokens: None
+ tokens: None,
})
});
}
RemoveParens.visit_expr(&mut parsed);
AddParens.visit_expr(&mut parsed);
let text2 = pprust::expr_to_string(&parsed);
- assert!(text1 == text2,
- "exprs are not equal:\n e = {:?}\n parsed = {:?}",
- text1, text2);
+ assert!(
+ text1 == text2,
+ "exprs are not equal:\n e = {:?}\n parsed = {:?}",
+ text1,
+ text2
+ );
}
});
}
// check-fail
// Tests error conditions for specifying diagnostics using #[derive(SessionDiagnostic)]
+// The proc_macro2 crate handles spans differently when on beta/stable release rather than nightly,
+// changing the output of this test. Since SessionDiagnostic is strictly internal to the compiler
+// the test is just ignored on stable and beta:
+// ignore-beta
+// ignore-stable
+
#![feature(rustc_private)]
#![crate_type = "lib"]
error: `#[derive(SessionDiagnostic)]` can only be used on structs
- --> $DIR/session-derive-errors.rs:28:1
+ --> $DIR/session-derive-errors.rs:34:1
|
LL | / #[error = "E0123"]
LL | |
| |_^
error: `#[label = ...]` is not a valid SessionDiagnostic struct attribute
- --> $DIR/session-derive-errors.rs:37:1
+ --> $DIR/session-derive-errors.rs:43:1
|
LL | #[label = "This is in the wrong place"]
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
error: `#[suggestion = ...]` is not a valid SessionDiagnostic field attribute
- --> $DIR/session-derive-errors.rs:44:5
+ --> $DIR/session-derive-errors.rs:50:5
|
LL | #[suggestion = "this is the wrong kind of attribute"]
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
error: `error` specified multiple times
- --> $DIR/session-derive-errors.rs:52:11
+ --> $DIR/session-derive-errors.rs:58:11
|
LL | #[error = "E0456"]
| ^^^^^^^
error: `lint` specified when `error` was already specified
- --> $DIR/session-derive-errors.rs:58:10
+ --> $DIR/session-derive-errors.rs:64:10
|
LL | #[lint = "some_useful_lint"]
| ^^^^^^^^^^^^^^^^^^
error: `code` not specified
- --> $DIR/session-derive-errors.rs:67:1
+ --> $DIR/session-derive-errors.rs:73:1
|
LL | struct ErrorCodeNotProvided {}
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
= help: use the [code = "..."] attribute to set this diagnostic's error code
error: the `#[message = "..."]` attribute can only be applied to fields of type Span
- --> $DIR/session-derive-errors.rs:95:5
+ --> $DIR/session-derive-errors.rs:101:5
|
LL | #[message = "this message is applied to a String field"]
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
error: `name` doesn't refer to a field on this type
- --> $DIR/session-derive-errors.rs:102:1
+ --> $DIR/session-derive-errors.rs:108:1
|
LL | #[message = "This error has a field, and references {name}"]
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
error: invalid format string: expected `'}'` but string was terminated
- --> $DIR/session-derive-errors.rs:110:1
+ --> $DIR/session-derive-errors.rs:116:1
|
LL | #[error = "E0123"]
| - because of this opening brace
= note: this error originates in the derive macro `SessionDiagnostic` (in Nightly builds, run with -Z macro-backtrace for more info)
error: invalid format string: unmatched `}` found
- --> $DIR/session-derive-errors.rs:119:1
+ --> $DIR/session-derive-errors.rs:125:1
|
LL | #[message = "This is missing an opening brace: name}"]
| ^ unmatched `}` in format string
= note: this error originates in the derive macro `SessionDiagnostic` (in Nightly builds, run with -Z macro-backtrace for more info)
error: The `#[label = ...]` attribute can only be applied to fields of type Span
- --> $DIR/session-derive-errors.rs:138:5
+ --> $DIR/session-derive-errors.rs:144:5
|
LL | #[label = "See here"]
| ^^^^^^^^^^^^^^^^^^^^^
error: `nonsense` is not a valid key for `#[suggestion(...)]`
- --> $DIR/session-derive-errors.rs:163:18
+ --> $DIR/session-derive-errors.rs:169:18
|
LL | #[suggestion(nonsense = "This is nonsense")]
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
error: `msg` is not a valid key for `#[suggestion(...)]`
- --> $DIR/session-derive-errors.rs:171:18
+ --> $DIR/session-derive-errors.rs:177:18
|
LL | #[suggestion(msg = "This is a suggestion")]
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^
error: missing suggestion message
- --> $DIR/session-derive-errors.rs:179:7
+ --> $DIR/session-derive-errors.rs:185:7
|
LL | #[suggestion(code = "This is suggested code")]
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
= help: provide a suggestion message using #[suggestion(message = "...")]
error: wrong field type for suggestion
- --> $DIR/session-derive-errors.rs:194:5
+ --> $DIR/session-derive-errors.rs:200:5
|
LL | / #[suggestion(message = "This is a message", code = "This is suggested code")]
LL | |
= help: #[suggestion(...)] should be applied to fields of type Span or (Span, Applicability)
error: type of field annotated with `#[suggestion(...)]` contains more than one Span
- --> $DIR/session-derive-errors.rs:209:5
+ --> $DIR/session-derive-errors.rs:215:5
|
LL | / #[suggestion(message = "This is a message", code = "This is suggested code")]
LL | |
| |___________________________________________^
error: type of field annotated with `#[suggestion(...)]` contains more than one Applicability
- --> $DIR/session-derive-errors.rs:217:5
+ --> $DIR/session-derive-errors.rs:223:5
|
LL | / #[suggestion(message = "This is a message", code = "This is suggested code")]
LL | |
| |____________________________________________________^
error: invalid annotation list `#[label(...)]`
- --> $DIR/session-derive-errors.rs:225:7
+ --> $DIR/session-derive-errors.rs:231:7
|
LL | #[label("wrong kind of annotation for label")]
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
-// compile-flags: --error-format human-annotate-rs
+// compile-flags: --error-format human-annotate-rs -Z unstable-options
pub fn main() {
let x: Iter; //~ ERROR cannot find type `Iter` in this scope
// aux-build:multispan.rs
-// compile-flags: --error-format human-annotate-rs
+// compile-flags: --error-format human-annotate-rs -Z unstable-options
#![feature(proc_macro_hygiene)]
--- /dev/null
+// check-pass
+
+#![feature(destructuring_assignment)]
+#![feature(more_qualified_paths)]
+
+enum E { V() }
+
+fn main() {
+ <E>::V() = E::V(); // OK, destructuring assignment
+ <E>::V {} = E::V(); // OK, destructuring assignment
+}
--- /dev/null
+fn main() {
+ #[cfg(FALSE)]
+ <() as module>::mac!(); //~ ERROR macros cannot use qualified paths
+}
--- /dev/null
+error: macros cannot use qualified paths
+ --> $DIR/associated-type-macro.rs:3:5
+ |
+LL | <() as module>::mac!();
+ | ^^^^^^^^^^^^^^^^^^^
+
+error: aborting due to previous error
+
--- /dev/null
+// Make sure that users can construct structs through associated types
+// in both expressions and patterns
+
+#![feature(more_qualified_paths)]
+
+// check-pass
+fn main() {
+ let <Foo as A>::Assoc { br } = <Foo as A>::Assoc { br: 2 };
+ assert!(br == 2);
+}
+
+struct StructStruct {
+ br: i8,
+}
+
+struct Foo;
+
+trait A {
+ type Assoc;
+}
+
+impl A for Foo {
+ type Assoc = StructStruct;
+}
--- /dev/null
+// Users cannot yet construct structs through associated types
+// in both expressions and patterns
+
+#![feature(more_qualified_paths)]
+
+fn main() {
+ let <Foo as A>::Assoc(n) = <Foo as A>::Assoc(2);
+ //~^ ERROR expected method or associated constant, found associated type
+ //~| ERROR expected method or associated constant, found associated type
+ assert!(n == 2);
+}
+
+struct TupleStruct(i8);
+
+struct Foo;
+
+
+trait A {
+ type Assoc;
+}
+
+impl A for Foo {
+ type Assoc = TupleStruct;
+}
--- /dev/null
+error[E0575]: expected method or associated constant, found associated type `A::Assoc`
+ --> $DIR/associated-type-tuple-struct-construction.rs:7:32
+ |
+LL | let <Foo as A>::Assoc(n) = <Foo as A>::Assoc(2);
+ | ^^^^^^^^^^^^^^^^^
+ |
+ = note: can't use a type alias as a constructor
+
+error[E0575]: expected method or associated constant, found associated type `A::Assoc`
+ --> $DIR/associated-type-tuple-struct-construction.rs:7:9
+ |
+LL | let <Foo as A>::Assoc(n) = <Foo as A>::Assoc(2);
+ | ^^^^^^^^^^^^^^^^^
+ |
+ = note: can't use a type alias as a constructor
+
+error: aborting due to 2 previous errors
+
+For more information about this error, try `rustc --explain E0575`.
// run-pass
-// revisions: default nomiropt
+// revisions: default nomiropt thirunsafeck
//[nomiropt]compile-flags: -Z mir-opt-level=0
+//[thirunsafeck]compile-flags: -Zthir-unsafeck
#![allow(unused)]
|
= help: the trait `Sync` is not implemented for `RefCell<i32>`
= note: required because of the requirements on the impl of `Send` for `Arc<RefCell<i32>>`
- = note: required because it appears within the type `[static generator@$DIR/issue-68112.rs:47:31: 47:36 {}]`
- = note: required because it appears within the type `from_generator::GenFuture<[static generator@$DIR/issue-68112.rs:47:31: 47:36 {}]>`
+ = note: required because it appears within the type `[static generator@$DIR/issue-68112.rs:47:31: 47:36]`
+ = note: required because it appears within the type `from_generator::GenFuture<[static generator@$DIR/issue-68112.rs:47:31: 47:36]>`
= note: required because it appears within the type `impl Future`
= note: required because it appears within the type `impl Future`
= note: required because it appears within the type `impl Future`
= note: required because it appears within the type `{ResumeTy, impl Future, (), i32, Ready<i32>}`
- = note: required because it appears within the type `[static generator@$DIR/issue-68112.rs:55:26: 59:6 {ResumeTy, impl Future, (), i32, Ready<i32>}]`
- = note: required because it appears within the type `from_generator::GenFuture<[static generator@$DIR/issue-68112.rs:55:26: 59:6 {ResumeTy, impl Future, (), i32, Ready<i32>}]>`
+ = note: required because it appears within the type `[static generator@$DIR/issue-68112.rs:55:26: 59:6]`
+ = note: required because it appears within the type `from_generator::GenFuture<[static generator@$DIR/issue-68112.rs:55:26: 59:6]>`
= note: required because it appears within the type `impl Future`
error: aborting due to 3 previous errors
|
= help: within `impl Future`, the trait `Send` is not implemented for `MutexGuard<'_, ()>`
= note: required because it appears within the type `for<'r, 's, 't0, 't1, 't2, 't3> {ResumeTy, Arc<Mutex<()>>, &'r Mutex<()>, Result<MutexGuard<'s, ()>, PoisonError<MutexGuard<'t0, ()>>>, &'t1 MutexGuard<'t2, ()>, MutexGuard<'t3, ()>, (), impl Future}`
- = note: required because it appears within the type `[static generator@run::{closure#0} for<'r, 's, 't0, 't1, 't2, 't3> {ResumeTy, Arc<Mutex<()>>, &'r Mutex<()>, Result<MutexGuard<'s, ()>, PoisonError<MutexGuard<'t0, ()>>>, &'t1 MutexGuard<'t2, ()>, MutexGuard<'t3, ()>, (), impl Future}]`
- = note: required because it appears within the type `from_generator::GenFuture<[static generator@run::{closure#0} for<'r, 's, 't0, 't1, 't2, 't3> {ResumeTy, Arc<Mutex<()>>, &'r Mutex<()>, Result<MutexGuard<'s, ()>, PoisonError<MutexGuard<'t0, ()>>>, &'t1 MutexGuard<'t2, ()>, MutexGuard<'t3, ()>, (), impl Future}]>`
+ = note: required because it appears within the type `[static generator@run::{closure#0}]`
+ = note: required because it appears within the type `from_generator::GenFuture<[static generator@run::{closure#0}]>`
= note: required because it appears within the type `impl Future`
= note: required because it appears within the type `impl Future`
// edition:2018
// run-pass
-// Test that a feature gate is needed to use `impl Trait` as the
-// return type of an async.
-
-#![feature(member_constraints)]
+// Test member constraints that appear in the `impl Trait`
+// return type of an async function.
+// (This used to require a feature gate.)
trait Trait<'a, 'b> { }
impl<T> Trait<'_, '_> for T { }
+++ /dev/null
-// edition:2018
-
-// Test that a feature gate is needed to use `impl Trait` as the
-// return type of an async.
-
-trait Trait<'a, 'b> { }
-impl<T> Trait<'_, '_> for T { }
-
-async fn async_ret_impl_trait<'a, 'b>(a: &'a u8, b: &'b u8) -> impl Trait<'a, 'b> {
- //~^ ERROR ambiguous lifetime bound
- //~| ERROR ambiguous lifetime bound
- //~| ERROR ambiguous lifetime bound
- //~| ERROR hidden type for `impl Trait` captures lifetime that does not appear in bounds
- //~| ERROR hidden type for `impl Trait` captures lifetime that does not appear in bounds
- (a, b)
-}
-
-fn main() {
- let _ = async_ret_impl_trait(&22, &44);
-}
+++ /dev/null
-error: ambiguous lifetime bound in `impl Trait`
- --> $DIR/ret-impl-trait-no-fg.rs:9:64
- |
-LL | async fn async_ret_impl_trait<'a, 'b>(a: &'a u8, b: &'b u8) -> impl Trait<'a, 'b> {
- | ^^^^^^^^^^^^^^^^^^ neither `'a` nor `'b` outlives the other
- |
- = help: add #![feature(member_constraints)] to the crate attributes to enable
-
-error: ambiguous lifetime bound in `impl Trait`
- --> $DIR/ret-impl-trait-no-fg.rs:9:64
- |
-LL | async fn async_ret_impl_trait<'a, 'b>(a: &'a u8, b: &'b u8) -> impl Trait<'a, 'b> {
- | ^^^^^^^^^^^^^^^^^^ neither `'a` nor `'b` outlives the other
- |
- = help: add #![feature(member_constraints)] to the crate attributes to enable
-
-error: ambiguous lifetime bound in `impl Trait`
- --> $DIR/ret-impl-trait-no-fg.rs:9:64
- |
-LL | async fn async_ret_impl_trait<'a, 'b>(a: &'a u8, b: &'b u8) -> impl Trait<'a, 'b> {
- | ^^^^^^^^^^^^^^^^^^ the elided lifetimes here do not outlive one another
- |
- = help: add #![feature(member_constraints)] to the crate attributes to enable
-
-error[E0700]: hidden type for `impl Trait` captures lifetime that does not appear in bounds
- --> $DIR/ret-impl-trait-no-fg.rs:9:1
- |
-LL | async fn async_ret_impl_trait<'a, 'b>(a: &'a u8, b: &'b u8) -> impl Trait<'a, 'b> {
- | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
- |
- = note: hidden type `(&u8, &u8)` captures lifetime '_#5r
-
-error[E0700]: hidden type for `impl Trait` captures lifetime that does not appear in bounds
- --> $DIR/ret-impl-trait-no-fg.rs:9:1
- |
-LL | async fn async_ret_impl_trait<'a, 'b>(a: &'a u8, b: &'b u8) -> impl Trait<'a, 'b> {
- | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
- |
- = note: hidden type `(&u8, &u8)` captures lifetime '_#6r
-
-error: aborting due to 5 previous errors
-
-For more information about this error, try `rustc --explain E0700`.
error: lifetime may not live long enough
- --> $DIR/ret-impl-trait-one.rs:12:80
+ --> $DIR/ret-impl-trait-one.rs:10:80
|
LL | async fn async_ret_impl_trait1<'a, 'b>(a: &'a u8, b: &'b u8) -> impl Trait<'a> {
| ________________________________--__--__________________________________________^
// Test that a feature gate is needed to use `impl Trait` as the
// return type of an async.
-#![feature(member_constraints)]
-
trait Trait<'a> { }
impl<T> Trait<'_> for T { }
error[E0623]: lifetime mismatch
- --> $DIR/ret-impl-trait-one.rs:12:65
+ --> $DIR/ret-impl-trait-one.rs:10:65
|
LL | async fn async_ret_impl_trait1<'a, 'b>(a: &'a u8, b: &'b u8) -> impl Trait<'a> {
| ------ ^^^^^^^^^^^^^^
--- /dev/null
+fn main() {
+ let mut test = Vec::new();
+ let rofl: &Vec<Vec<i32>> = &mut test;
+ //~^ HELP consider changing this to be a mutable reference
+ rofl.push(Vec::new());
+ //~^ ERROR cannot borrow `*rofl` as mutable, as it is behind a `&` reference
+ //~| NOTE `rofl` is a `&` reference, so the data it refers to cannot be borrowed as mutable
+}
--- /dev/null
+error[E0596]: cannot borrow `*rofl` as mutable, as it is behind a `&` reference
+ --> $DIR/issue-85765.rs:5:5
+ |
+LL | let rofl: &Vec<Vec<i32>> = &mut test;
+ | ---- help: consider changing this to be a mutable reference: `&mut Vec<Vec<i32>>`
+LL |
+LL | rofl.push(Vec::new());
+ | ^^^^ `rofl` is a `&` reference, so the data it refers to cannot be borrowed as mutable
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0596`.
--- /dev/null
+// Regression test for the ICE described in issue #86053.
+// error-pattern:unexpected `self` parameter in function
+// error-pattern:`...` must be the last argument of a C-variadic function
+// error-pattern:cannot find type `F` in this scope
+// error-pattern:in type `&'a &'b usize`, reference has a longer lifetime than the data it references
+
+#![feature(c_variadic)]
+#![crate_type="lib"]
+
+fn ordering4 < 'a , 'b > ( a : , self , self , self ,
+ self , ... , self , self , ... ) where F : FnOnce ( & 'a & 'b usize ) {
+}
--- /dev/null
+error: expected type, found `,`
+ --> $DIR/issue-86053-1.rs:10:47
+ |
+LL | fn ordering4 < 'a , 'b > ( a : , self , self , self ,
+ | ^ expected type
+
+error: unexpected `self` parameter in function
+ --> $DIR/issue-86053-1.rs:10:51
+ |
+LL | fn ordering4 < 'a , 'b > ( a : , self , self , self ,
+ | ^^^^ must be the first parameter of an associated function
+
+error: unexpected `self` parameter in function
+ --> $DIR/issue-86053-1.rs:10:58
+ |
+LL | fn ordering4 < 'a , 'b > ( a : , self , self , self ,
+ | ^^^^ must be the first parameter of an associated function
+
+error: unexpected `self` parameter in function
+ --> $DIR/issue-86053-1.rs:10:67
+ |
+LL | fn ordering4 < 'a , 'b > ( a : , self , self , self ,
+ | ^^^^ must be the first parameter of an associated function
+
+error: unexpected `self` parameter in function
+ --> $DIR/issue-86053-1.rs:11:5
+ |
+LL | self , ... , self , self , ... ) where F : FnOnce ( & 'a & 'b usize ) {
+ | ^^^^ must be the first parameter of an associated function
+
+error: unexpected `self` parameter in function
+ --> $DIR/issue-86053-1.rs:11:20
+ |
+LL | self , ... , self , self , ... ) where F : FnOnce ( & 'a & 'b usize ) {
+ | ^^^^ must be the first parameter of an associated function
+
+error: unexpected `self` parameter in function
+ --> $DIR/issue-86053-1.rs:11:29
+ |
+LL | self , ... , self , self , ... ) where F : FnOnce ( & 'a & 'b usize ) {
+ | ^^^^ must be the first parameter of an associated function
+
+error: `...` must be the last argument of a C-variadic function
+ --> $DIR/issue-86053-1.rs:11:12
+ |
+LL | self , ... , self , self , ... ) where F : FnOnce ( & 'a & 'b usize ) {
+ | ^^^^
+
+error: only foreign or `unsafe extern "C"` functions may be C-variadic
+ --> $DIR/issue-86053-1.rs:11:12
+ |
+LL | self , ... , self , self , ... ) where F : FnOnce ( & 'a & 'b usize ) {
+ | ^^^^
+
+error: only foreign or `unsafe extern "C"` functions may be C-variadic
+ --> $DIR/issue-86053-1.rs:11:36
+ |
+LL | self , ... , self , self , ... ) where F : FnOnce ( & 'a & 'b usize ) {
+ | ^^^^
+
+error[E0412]: cannot find type `F` in this scope
+ --> $DIR/issue-86053-1.rs:11:48
+ |
+LL | self , ... , self , self , ... ) where F : FnOnce ( & 'a & 'b usize ) {
+ | ^
+ |
+ ::: $SRC_DIR/core/src/ops/function.rs:LL:COL
+ |
+LL | pub trait Fn<Args>: FnMut<Args> {
+ | ------------------------------- similarly named trait `Fn` defined here
+ |
+help: a trait with a similar name exists
+ |
+LL | self , ... , self , self , ... ) where Fn : FnOnce ( & 'a & 'b usize ) {
+ | ^^
+help: you might be missing a type parameter
+ |
+LL | fn ordering4 < 'a , 'b, F > ( a : , self , self , self ,
+ | ^^^
+
+error[E0491]: in type `&'a &'b usize`, reference has a longer lifetime than the data it references
+ --> $DIR/issue-86053-1.rs:11:52
+ |
+LL | self , ... , self , self , ... ) where F : FnOnce ( & 'a & 'b usize ) {
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^
+ |
+note: the pointer is valid for the lifetime `'a` as defined on the function body at 10:16
+ --> $DIR/issue-86053-1.rs:10:16
+ |
+LL | fn ordering4 < 'a , 'b > ( a : , self , self , self ,
+ | ^^
+note: but the referenced data is only valid for the lifetime `'b` as defined on the function body at 10:21
+ --> $DIR/issue-86053-1.rs:10:21
+ |
+LL | fn ordering4 < 'a , 'b > ( a : , self , self , self ,
+ | ^^
+
+error: aborting due to 12 previous errors
+
+Some errors have detailed explanations: E0412, E0491.
+For more information about an error, try `rustc --explain E0412`.
--- /dev/null
+// Regression test for the ICE caused by the example in
+// https://github.com/rust-lang/rust/issues/86053#issuecomment-855672258
+
+#![feature(c_variadic)]
+
+trait H<T> {}
+
+unsafe extern "C" fn ordering4<'a, F: H<&'static &'a ()>>(_: (), ...) {}
+//~^ ERROR: in type `&'static &'a ()`, reference has a longer lifetime than the data it references [E0491]
+
+fn main() {}
--- /dev/null
+error[E0491]: in type `&'static &'a ()`, reference has a longer lifetime than the data it references
+ --> $DIR/issue-86053-2.rs:8:39
+ |
+LL | unsafe extern "C" fn ordering4<'a, F: H<&'static &'a ()>>(_: (), ...) {}
+ | ^^^^^^^^^^^^^^^^^^
+ |
+ = note: the pointer is valid for the static lifetime
+note: but the referenced data is only valid for the lifetime `'a` as defined on the function body at 8:32
+ --> $DIR/issue-86053-2.rs:8:32
+ |
+LL | unsafe extern "C" fn ordering4<'a, F: H<&'static &'a ()>>(_: (), ...) {}
+ | ^^
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0491`.
| has type `&mut VaListImpl<'1>`
LL | ap0 = &mut ap1;
| ^^^^^^^^^^^^^^ assignment requires that `'1` must outlive `'2`
+ |
+ = note: requirement occurs because of a mutable reference to VaListImpl<'_>
+ = note: mutable references are invariant over their type parameter
+ = help: see <https://doc.rust-lang.org/nomicon/subtyping.html> for more information about variance
error: lifetime may not live long enough
--> $DIR/variadic-ffi-4.rs:28:5
| has type `&mut VaListImpl<'1>`
LL | ap0 = &mut ap1;
| ^^^^^^^^^^^^^^ assignment requires that `'2` must outlive `'1`
+ |
+ = note: requirement occurs because of a mutable reference to VaListImpl<'_>
+ = note: mutable references are invariant over their type parameter
+ = help: see <https://doc.rust-lang.org/nomicon/subtyping.html> for more information about variance
error[E0597]: `ap1` does not live long enough
--> $DIR/variadic-ffi-4.rs:28:11
+++ /dev/null
-error[E0133]: cast of pointer to int is unsafe and requires unsafe function or block
- --> $DIR/cast-ptr-to-int-const.rs:16:9
- |
-LL | &Y as *const u32 as usize
- | ^^^^^^^^^^^^^^^^^^^^^^^^^ cast of pointer to int
- |
- = note: casting pointers to integers in constants
-
-error[E0133]: cast of pointer to int is unsafe and requires unsafe function or block
- --> $DIR/cast-ptr-to-int-const.rs:23:5
- |
-LL | &0 as *const i32 as usize
- | ^^^^^^^^^^^^^^^^^^^^^^^^^ cast of pointer to int
- |
- = note: casting pointers to integers in constants
-
-error: aborting due to 2 previous errors
-
-For more information about this error, try `rustc --explain E0133`.
+++ /dev/null
-error[E0658]: casting pointers to integers in constants is unstable
- --> $DIR/cast-ptr-to-int-const.rs:8:9
- |
-LL | main as usize
- | ^^^^^^^^^^^^^
- |
- = note: see issue #51910 <https://github.com/rust-lang/rust/issues/51910> for more information
- = help: add `#![feature(const_raw_ptr_to_usize_cast)]` to the crate attributes to enable
-
-error[E0658]: casting pointers to integers in constants is unstable
- --> $DIR/cast-ptr-to-int-const.rs:12:9
- |
-LL | &Y as *const u32 as usize
- | ^^^^^^^^^^^^^^^^^^^^^^^^^
- |
- = note: see issue #51910 <https://github.com/rust-lang/rust/issues/51910> for more information
- = help: add `#![feature(const_raw_ptr_to_usize_cast)]` to the crate attributes to enable
-
-error[E0658]: casting pointers to integers in constants is unstable
- --> $DIR/cast-ptr-to-int-const.rs:16:9
- |
-LL | &Y as *const u32 as usize
- | ^^^^^^^^^^^^^^^^^^^^^^^^^
- |
- = note: see issue #51910 <https://github.com/rust-lang/rust/issues/51910> for more information
- = help: add `#![feature(const_raw_ptr_to_usize_cast)]` to the crate attributes to enable
-
-error[E0658]: casting pointers to integers in constant functions is unstable
- --> $DIR/cast-ptr-to-int-const.rs:23:5
- |
-LL | &0 as *const i32 as usize
- | ^^^^^^^^^^^^^^^^^^^^^^^^^
- |
- = note: see issue #51910 <https://github.com/rust-lang/rust/issues/51910> for more information
- = help: add `#![feature(const_raw_ptr_to_usize_cast)]` to the crate attributes to enable
-
-error: aborting due to 4 previous errors
-
-For more information about this error, try `rustc --explain E0658`.
LL | let _pointer_to_something = something as *const Something;
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ invalid cast
|
-help: borrow the value for the cast to be valid
+help: consider borrowing the value
|
LL | let _pointer_to_something = &something as *const Something;
| ^
LL | let _mut_pointer_to_something = something as *mut Something;
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^ invalid cast
|
-help: borrow the value for the cast to be valid
+help: consider borrowing the value
|
LL | let _mut_pointer_to_something = &mut something as *mut Something;
| ^^^^
// run-pass
+// revisions: mir thir
+// [thir]compile-flags: -Zthir-unsafeck
#![allow(stable_features)]
// ignore-windows - this is a unix-specific test
-error[E0599]: no method named `closure` found for struct `Obj<[closure@$DIR/issue-18343.rs:6:28: 6:33]>` in the current scope
+error[E0599]: no method named `closure` found for struct `Obj` in the current scope
--> $DIR/issue-18343.rs:7:7
|
LL | struct Obj<F> where F: FnMut() -> u32 {
-error[E0599]: no method named `closure` found for struct `Obj<[closure@$DIR/issue-2392.rs:35:36: 35:41]>` in the current scope
+error[E0599]: no method named `closure` found for struct `Obj` in the current scope
--> $DIR/issue-2392.rs:36:15
|
LL | struct Obj<F> where F: FnOnce() -> u32 {
LL | (o_closure.closure)();
| ^ ^
-error[E0599]: no method named `not_closure` found for struct `Obj<[closure@$DIR/issue-2392.rs:35:36: 35:41]>` in the current scope
+error[E0599]: no method named `not_closure` found for struct `Obj` in the current scope
--> $DIR/issue-2392.rs:38:15
|
LL | struct Obj<F> where F: FnOnce() -> u32 {
| |
| field, not a method
-error[E0599]: no method named `closure` found for struct `Obj<fn() -> u32 {func}>` in the current scope
+error[E0599]: no method named `closure` found for struct `Obj` in the current scope
--> $DIR/issue-2392.rs:42:12
|
LL | struct Obj<F> where F: FnOnce() -> u32 {
LL | (boxed_closure.boxed_closure)();
| ^ ^
-error[E0599]: no method named `closure` found for struct `Obj<fn() -> u32 {func}>` in the current scope
+error[E0599]: no method named `closure` found for struct `Obj` in the current scope
--> $DIR/issue-2392.rs:53:12
|
LL | struct Obj<F> where F: FnOnce() -> u32 {
LL | (w.wrap.closure)();
| ^ ^
-error[E0599]: no method named `not_closure` found for struct `Obj<fn() -> u32 {func}>` in the current scope
+error[E0599]: no method named `not_closure` found for struct `Obj` in the current scope
--> $DIR/issue-2392.rs:55:12
|
LL | struct Obj<F> where F: FnOnce() -> u32 {
| |
| field, not a method
-error[E0599]: no method named `closure` found for struct `Obj<Box<(dyn FnOnce() -> u32 + 'static)>>` in the current scope
+error[E0599]: no method named `closure` found for struct `Obj` in the current scope
--> $DIR/issue-2392.rs:58:24
|
LL | struct Obj<F> where F: FnOnce() -> u32 {
};
pub fn yes_iterator() -> impl Iterator<Item = i32> {
- IntoIter::new([0i32; 32])
+ IntoIterator::into_iter([0i32; 32])
}
pub fn yes_double_ended_iterator() -> impl DoubleEndedIterator {
- IntoIter::new([0i32; 32])
+ IntoIterator::into_iter([0i32; 32])
}
pub fn yes_exact_size_iterator() -> impl ExactSizeIterator {
- IntoIter::new([0i32; 32])
+ IntoIterator::into_iter([0i32; 32])
}
pub fn yes_fused_iterator() -> impl FusedIterator {
- IntoIter::new([0i32; 32])
+ IntoIterator::into_iter([0i32; 32])
}
pub fn yes_trusted_len() -> impl TrustedLen {
- IntoIter::new([0i32; 32])
+ IntoIterator::into_iter([0i32; 32])
}
pub fn yes_clone() -> impl Clone {
- IntoIter::new([0i32; 32])
+ IntoIterator::into_iter([0i32; 32])
}
pub fn yes_debug() -> impl Debug {
- IntoIter::new([0i32; 32])
+ IntoIterator::into_iter([0i32; 32])
}
};
pub fn yes_iterator() -> impl Iterator<Item = i32> {
- IntoIter::new([0i32; 33])
+ IntoIterator::into_iter([0i32; 33])
}
pub fn yes_double_ended_iterator() -> impl DoubleEndedIterator {
- IntoIter::new([0i32; 33])
+ IntoIterator::into_iter([0i32; 33])
}
pub fn yes_exact_size_iterator() -> impl ExactSizeIterator {
- IntoIter::new([0i32; 33])
+ IntoIterator::into_iter([0i32; 33])
}
pub fn yes_fused_iterator() -> impl FusedIterator {
- IntoIter::new([0i32; 33])
+ IntoIterator::into_iter([0i32; 33])
}
pub fn yes_trusted_len() -> impl TrustedLen {
- IntoIter::new([0i32; 33])
+ IntoIterator::into_iter([0i32; 33])
}
pub fn yes_clone() -> impl Clone {
- IntoIter::new([0i32; 33])
+ IntoIterator::into_iter([0i32; 33])
}
pub fn yes_debug() -> impl Debug {
- IntoIter::new([0i32; 33])
+ IntoIterator::into_iter([0i32; 33])
}
--- /dev/null
+// check-pass
+#![feature(const_evaluatable_checked, const_generics)]
+#![allow(incomplete_features)]
+
+struct Foo<const N: u8>([u8; N as usize])
+where
+ [(); N as usize]:;
+
+struct Bar<const N: u8>([u8; (N + 2) as usize]) where [(); (N + 2) as usize]:;
+
+// unifying with subtrees
+struct Evaluatable<const N: u16>;
+fn foo<const N: u8>() where Evaluatable<{N as usize as u16 }>: {
+ let _ = Foo::<N>([1; N as usize]);
+}
+
+
+fn main() {}
--- /dev/null
+#![feature(const_evaluatable_checked, const_generics)]
+#![allow(incomplete_features)]
+
+struct Evaluatable<const N: u128> {}
+
+struct Foo<const N: u8>([u8; N as usize])
+//~^ Error: unconstrained generic constant
+//~| help: try adding a `where` bound using this expression: `where [(); N as usize]:`
+where
+ Evaluatable<{N as u128}>:;
+
+struct Foo2<const N: u8>(Evaluatable::<{N as u128}>) where Evaluatable<{N as usize as u128 }>:;
+//~^ Error: unconstrained generic constant
+//~| help: try adding a `where` bound using this expression: `where [(); {N as u128}]:`
+
+struct Bar<const N: u8>([u8; (N + 2) as usize]) where [(); (N + 1) as usize]:;
+//~^ Error: unconstrained generic constant
+//~| help: try adding a `where` bound using this expression: `where [(); (N + 2) as usize]:`
+
+fn main() {}
--- /dev/null
+error: unconstrained generic constant
+ --> $DIR/abstract-const-as-cast-2.rs:6:25
+ |
+LL | struct Foo<const N: u8>([u8; N as usize])
+ | ^^^^^^^^^^^^^^^^
+ |
+ = help: try adding a `where` bound using this expression: `where [(); N as usize]:`
+
+error: unconstrained generic constant
+ --> $DIR/abstract-const-as-cast-2.rs:12:26
+ |
+LL | struct Foo2<const N: u8>(Evaluatable::<{N as u128}>) where Evaluatable<{N as usize as u128 }>:;
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^
+ |
+ = help: try adding a `where` bound using this expression: `where [(); {N as u128}]:`
+
+error: unconstrained generic constant
+ --> $DIR/abstract-const-as-cast-2.rs:16:25
+ |
+LL | struct Bar<const N: u8>([u8; (N + 2) as usize]) where [(); (N + 1) as usize]:;
+ | ^^^^^^^^^^^^^^^^^^^^^^
+ |
+ = help: try adding a `where` bound using this expression: `where [(); (N + 2) as usize]:`
+
+error: aborting due to 3 previous errors
+
--- /dev/null
+#![feature(const_generics, const_evaluatable_checked)]
+#![allow(incomplete_features)]
+
+trait Trait {}
+pub struct EvaluatableU128<const N: u128>;
+
+struct HasCastInTraitImpl<const N: usize, const M: u128>;
+impl<const O: usize> Trait for HasCastInTraitImpl<O, { O as u128 }> {}
+
+pub fn use_trait_impl<const N: usize>()
+where
+ [(); { N + 1}]:,
+ EvaluatableU128<{N as u128}>:, {
+ fn assert_impl<T: Trait>() {}
+
+ // errors are bad but seems to be pre-existing issue #86198
+ assert_impl::<HasCastInTraitImpl<{ N + 1 }, { N as u128 }>>();
+ //~^ Error: mismatched types
+ //~^^ Error: unconstrained generic constant
+ assert_impl::<HasCastInTraitImpl<{ N + 1 }, { N as _ }>>();
+ //~^ Error: mismatched types
+ //~^^ Error: unconstrained generic constant
+ assert_impl::<HasCastInTraitImpl<13, { 12 as u128 }>>();
+ //~^ Error: mismatched types
+ assert_impl::<HasCastInTraitImpl<14, 13>>();
+ //~^ Error: mismatched types
+}
+pub fn use_trait_impl_2<const N: usize>()
+where
+ [(); { N + 1}]:,
+ EvaluatableU128<{N as _}>:, {
+ fn assert_impl<T: Trait>() {}
+
+ // errors are bad but seems to be pre-existing issue #86198
+ assert_impl::<HasCastInTraitImpl<{ N + 1 }, { N as u128 }>>();
+ //~^ Error: mismatched types
+ //~^^ Error: unconstrained generic constant
+ assert_impl::<HasCastInTraitImpl<{ N + 1 }, { N as _ }>>();
+ //~^ Error: mismatched types
+ //~^^ Error: unconstrained generic constant
+ assert_impl::<HasCastInTraitImpl<13, { 12 as u128 }>>();
+ //~^ Error: mismatched types
+ assert_impl::<HasCastInTraitImpl<14, 13>>();
+ //~^ Error: mismatched types
+}
+
+fn main() {}
--- /dev/null
+error: unconstrained generic constant
+ --> $DIR/abstract-const-as-cast-3.rs:17:5
+ |
+LL | fn assert_impl<T: Trait>() {}
+ | ----- required by this bound in `use_trait_impl::assert_impl`
+...
+LL | assert_impl::<HasCastInTraitImpl<{ N + 1 }, { N as u128 }>>();
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+ |
+ = help: try adding a `where` bound using this expression: `where [(); { O as u128 }]:`
+note: required because of the requirements on the impl of `Trait` for `HasCastInTraitImpl<{ N + 1 }, { N as u128 }>`
+ --> $DIR/abstract-const-as-cast-3.rs:8:22
+ |
+LL | impl<const O: usize> Trait for HasCastInTraitImpl<O, { O as u128 }> {}
+ | ^^^^^ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+error[E0308]: mismatched types
+ --> $DIR/abstract-const-as-cast-3.rs:17:5
+ |
+LL | assert_impl::<HasCastInTraitImpl<{ N + 1 }, { N as u128 }>>();
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ expected `{ N as u128 }`, found `{ O as u128 }`
+ |
+ = note: expected type `{ N as u128 }`
+ found type `{ O as u128 }`
+
+error: unconstrained generic constant
+ --> $DIR/abstract-const-as-cast-3.rs:20:5
+ |
+LL | fn assert_impl<T: Trait>() {}
+ | ----- required by this bound in `use_trait_impl::assert_impl`
+...
+LL | assert_impl::<HasCastInTraitImpl<{ N + 1 }, { N as _ }>>();
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+ |
+ = help: try adding a `where` bound using this expression: `where [(); { O as u128 }]:`
+note: required because of the requirements on the impl of `Trait` for `HasCastInTraitImpl<{ N + 1 }, { N as _ }>`
+ --> $DIR/abstract-const-as-cast-3.rs:8:22
+ |
+LL | impl<const O: usize> Trait for HasCastInTraitImpl<O, { O as u128 }> {}
+ | ^^^^^ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+error[E0308]: mismatched types
+ --> $DIR/abstract-const-as-cast-3.rs:20:5
+ |
+LL | assert_impl::<HasCastInTraitImpl<{ N + 1 }, { N as _ }>>();
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ expected `{ N as _ }`, found `{ O as u128 }`
+ |
+ = note: expected type `{ N as _ }`
+ found type `{ O as u128 }`
+
+error[E0308]: mismatched types
+ --> $DIR/abstract-const-as-cast-3.rs:23:5
+ |
+LL | assert_impl::<HasCastInTraitImpl<13, { 12 as u128 }>>();
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ expected `12_u128`, found `13_u128`
+ |
+ = note: expected type `12_u128`
+ found type `13_u128`
+
+error[E0308]: mismatched types
+ --> $DIR/abstract-const-as-cast-3.rs:25:5
+ |
+LL | assert_impl::<HasCastInTraitImpl<14, 13>>();
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ expected `13_u128`, found `14_u128`
+ |
+ = note: expected type `13_u128`
+ found type `14_u128`
+
+error: unconstrained generic constant
+ --> $DIR/abstract-const-as-cast-3.rs:35:5
+ |
+LL | fn assert_impl<T: Trait>() {}
+ | ----- required by this bound in `use_trait_impl_2::assert_impl`
+...
+LL | assert_impl::<HasCastInTraitImpl<{ N + 1 }, { N as u128 }>>();
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+ |
+ = help: try adding a `where` bound using this expression: `where [(); { O as u128 }]:`
+note: required because of the requirements on the impl of `Trait` for `HasCastInTraitImpl<{ N + 1 }, { N as u128 }>`
+ --> $DIR/abstract-const-as-cast-3.rs:8:22
+ |
+LL | impl<const O: usize> Trait for HasCastInTraitImpl<O, { O as u128 }> {}
+ | ^^^^^ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+error[E0308]: mismatched types
+ --> $DIR/abstract-const-as-cast-3.rs:35:5
+ |
+LL | assert_impl::<HasCastInTraitImpl<{ N + 1 }, { N as u128 }>>();
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ expected `{ N as u128 }`, found `{ O as u128 }`
+ |
+ = note: expected type `{ N as u128 }`
+ found type `{ O as u128 }`
+
+error: unconstrained generic constant
+ --> $DIR/abstract-const-as-cast-3.rs:38:5
+ |
+LL | fn assert_impl<T: Trait>() {}
+ | ----- required by this bound in `use_trait_impl_2::assert_impl`
+...
+LL | assert_impl::<HasCastInTraitImpl<{ N + 1 }, { N as _ }>>();
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+ |
+ = help: try adding a `where` bound using this expression: `where [(); { O as u128 }]:`
+note: required because of the requirements on the impl of `Trait` for `HasCastInTraitImpl<{ N + 1 }, { N as _ }>`
+ --> $DIR/abstract-const-as-cast-3.rs:8:22
+ |
+LL | impl<const O: usize> Trait for HasCastInTraitImpl<O, { O as u128 }> {}
+ | ^^^^^ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+error[E0308]: mismatched types
+ --> $DIR/abstract-const-as-cast-3.rs:38:5
+ |
+LL | assert_impl::<HasCastInTraitImpl<{ N + 1 }, { N as _ }>>();
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ expected `{ N as _ }`, found `{ O as u128 }`
+ |
+ = note: expected type `{ N as _ }`
+ found type `{ O as u128 }`
+
+error[E0308]: mismatched types
+ --> $DIR/abstract-const-as-cast-3.rs:41:5
+ |
+LL | assert_impl::<HasCastInTraitImpl<13, { 12 as u128 }>>();
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ expected `12_u128`, found `13_u128`
+ |
+ = note: expected type `12_u128`
+ found type `13_u128`
+
+error[E0308]: mismatched types
+ --> $DIR/abstract-const-as-cast-3.rs:43:5
+ |
+LL | assert_impl::<HasCastInTraitImpl<14, 13>>();
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ expected `13_u128`, found `14_u128`
+ |
+ = note: expected type `13_u128`
+ found type `14_u128`
+
+error: aborting due to 12 previous errors
+
+For more information about this error, try `rustc --explain E0308`.
--- /dev/null
+// check-pass
+#![feature(const_evaluatable_checked, const_generics)]
+#![allow(incomplete_features)]
+
+trait Trait {}
+pub struct EvaluatableU128<const N: u128>;
+
+struct HasCastInTraitImpl<const N: usize, const M: u128>;
+impl<const O: usize> Trait for HasCastInTraitImpl<O, { O as u128 }> {}
+
+pub fn use_trait_impl<const N: usize>() where EvaluatableU128<{N as u128}>:, {
+ fn assert_impl<T: Trait>() {}
+
+ assert_impl::<HasCastInTraitImpl<N, { N as u128 }>>();
+ assert_impl::<HasCastInTraitImpl<N, { N as _ }>>();
+ assert_impl::<HasCastInTraitImpl<12, { 12 as u128 }>>();
+ assert_impl::<HasCastInTraitImpl<13, 13>>();
+}
+pub fn use_trait_impl_2<const N: usize>() where EvaluatableU128<{N as _}>:, {
+ fn assert_impl<T: Trait>() {}
+
+ assert_impl::<HasCastInTraitImpl<N, { N as u128 }>>();
+ assert_impl::<HasCastInTraitImpl<N, { N as _ }>>();
+ assert_impl::<HasCastInTraitImpl<12, { 12 as u128 }>>();
+ assert_impl::<HasCastInTraitImpl<13, 13>>();
+}
+
+
+fn main() {}
fn test<T>() -> [u8; size_of::<T>()] {
[0; size_of::<Foo<T>>()]
//~^ ERROR unconstrained generic constant
+ //~| ERROR mismatched types
}
fn main() {
+error[E0308]: mismatched types
+ --> $DIR/different-fn.rs:10:5
+ |
+LL | [0; size_of::<Foo<T>>()]
+ | ^^^^^^^^^^^^^^^^^^^^^^^^ expected `size_of::<T>()`, found `size_of::<Foo<T>>()`
+ |
+ = note: expected type `size_of::<T>()`
+ found type `size_of::<Foo<T>>()`
+
error: unconstrained generic constant
--> $DIR/different-fn.rs:10:9
|
|
= help: try adding a `where` bound using this expression: `where [(); size_of::<Foo<T>>()]:`
-error: aborting due to previous error
+error: aborting due to 2 previous errors
+For more information about this error, try `rustc --explain E0308`.
--- /dev/null
+// check-pass
+
+// We previously always returned ambiguity when equating generic consts, even if they
+// only contain generic parameters. This is incorrect as trying to unify `N > 1` with `M > 1`
+// should fail.
+#![allow(incomplete_features)]
+#![feature(const_generics, const_evaluatable_checked)]
+
+enum Assert<const COND: bool> {}
+trait IsTrue {}
+impl IsTrue for Assert<true> {}
+
+struct Foo<const N: usize, const M: usize>;
+trait Bar<const N: usize, const M: usize> {}
+impl<const N: usize, const M: usize> Bar<N, M> for Foo<N, M>
+where
+ Assert<{ N > 1 }>: IsTrue,
+ Assert<{ M > 1 }>: IsTrue,
+{
+}
+
+fn main() {}
#![allow(incomplete_features)]
fn test<const N: usize>() -> [u8; N - 1] {
- //~^ ERROR evaluation of constant
+ //~^ ERROR evaluation of `test::<0_usize>::{constant#0}` failed
todo!()
}
-error[E0080]: evaluation of constant value failed
+error[E0080]: evaluation of `test::<0_usize>::{constant#0}` failed
--> $DIR/from-sig-fail.rs:4:35
|
LL | fn test<const N: usize>() -> [u8; N - 1] {
-error[E0080]: evaluation of constant value failed
- --> $DIR/simple_fail.rs:9:48
+error[E0080]: evaluation of `test::<0_usize>::{constant#0}` failed
+ --> $DIR/simple_fail.rs:10:48
|
LL | fn test<const N: usize>() -> Arr<N> where [u8; N - 1]: Sized {
| ^^^^^ attempt to compute `0_usize - 1_usize`, which would overflow
-error[E0080]: evaluation of constant value failed
+error[E0080]: evaluation of `Arr::<0_usize>::{constant#0}` failed
--> $DIR/simple_fail.rs:6:33
|
LL | type Arr<const N: usize> = [u8; N - 1];
= help: use `#![feature(const_generics)]` and `#![feature(const_evaluatable_checked)]` to allow generic const expressions
error: generic parameters may not be used in const operations
- --> $DIR/simple_fail.rs:9:48
+ --> $DIR/simple_fail.rs:10:48
|
LL | fn test<const N: usize>() -> Arr<N> where [u8; N - 1]: Sized {
| ^ cannot perform const operation using `N`
#![cfg_attr(full, feature(const_evaluatable_checked))]
#![allow(incomplete_features)]
-type Arr<const N: usize> = [u8; N - 1]; //[full]~ ERROR evaluation of constant
+type Arr<const N: usize> = [u8; N - 1];
//[min]~^ ERROR generic parameters may not be used in const operations
+//[full]~^^ ERROR evaluation of `Arr::<0_usize>::{constant#0}` failed
fn test<const N: usize>() -> Arr<N> where [u8; N - 1]: Sized {
//[min]~^ ERROR generic parameters may not be used in const operations
-//[full]~^^ ERROR evaluation of constant
+//[full]~^^ ERROR evaluation of `test::<0_usize>::{constant#0}` failed
todo!()
}
--- /dev/null
+#![feature(const_generics_defaults)]
+
+struct Foo<const N: usize = M, const M: usize = 10>;
+//~^ ERROR generic parameters with a default cannot use forward declared identifiers
+
+enum Bar<const N: usize = M, const M: usize = 10> {}
+//~^ ERROR generic parameters with a default cannot use forward declared identifiers
+
+struct Foo2<const N: usize = N>;
+//~^ ERROR generic parameters with a default cannot use forward declared identifiers
+
+enum Bar2<const N: usize = N> {}
+//~^ ERROR generic parameters with a default cannot use forward declared identifiers
+
+fn main() {}
--- /dev/null
+error[E0128]: generic parameters with a default cannot use forward declared identifiers
+ --> $DIR/forward-declared.rs:3:29
+ |
+LL | struct Foo<const N: usize = M, const M: usize = 10>;
+ | ^ defaulted generic parameters cannot be forward declared
+
+error[E0128]: generic parameters with a default cannot use forward declared identifiers
+ --> $DIR/forward-declared.rs:6:27
+ |
+LL | enum Bar<const N: usize = M, const M: usize = 10> {}
+ | ^ defaulted generic parameters cannot be forward declared
+
+error[E0128]: generic parameters with a default cannot use forward declared identifiers
+ --> $DIR/forward-declared.rs:9:30
+ |
+LL | struct Foo2<const N: usize = N>;
+ | ^ defaulted generic parameters cannot be forward declared
+
+error[E0128]: generic parameters with a default cannot use forward declared identifiers
+ --> $DIR/forward-declared.rs:12:28
+ |
+LL | enum Bar2<const N: usize = N> {}
+ | ^ defaulted generic parameters cannot be forward declared
+
+error: aborting due to 4 previous errors
+
+For more information about this error, try `rustc --explain E0128`.
--> $DIR/intermixed-lifetime.rs:7:28
|
LL | struct Foo<const N: usize, 'a, T = u32>(&'a (), T);
- | -----------------^^---------- help: reorder the parameters: lifetimes, then types, then consts: `<'a, const N: usize, T = u32>`
+ | -----------------^^---------- help: reorder the parameters: lifetimes, then consts and types: `<'a, const N: usize, T = u32>`
error: lifetime parameters must be declared prior to type parameters
--> $DIR/intermixed-lifetime.rs:10:37
|
LL | struct Bar<const N: usize, T = u32, 'a>(&'a (), T);
- | --------------------------^^- help: reorder the parameters: lifetimes, then types, then consts: `<'a, const N: usize, T = u32>`
+ | --------------------------^^- help: reorder the parameters: lifetimes, then consts and types: `<'a, const N: usize, T = u32>`
error: aborting due to 2 previous errors
| ------------- ^^ expected struct `Example`, found `()`
| |
| expected due to this
+ |
+ = note: expected struct `Example`
+ found unit type `()`
error[E0308]: mismatched types
- --> $DIR/mismatch.rs:14:34
+ --> $DIR/mismatch.rs:15:34
|
LL | let e: Example2::<u32, 13> = ();
| ------------------- ^^ expected struct `Example2`, found `()`
found unit type `()`
error[E0308]: mismatched types
- --> $DIR/mismatch.rs:16:34
+ --> $DIR/mismatch.rs:18:34
|
LL | let e: Example3::<13, u32> = ();
| ------------------- ^^ expected struct `Example3`, found `()`
found unit type `()`
error[E0308]: mismatched types
- --> $DIR/mismatch.rs:18:28
+ --> $DIR/mismatch.rs:21:28
|
LL | let e: Example3::<7> = ();
| ------------- ^^ expected struct `Example3`, found `()`
found unit type `()`
error[E0308]: mismatched types
- --> $DIR/mismatch.rs:22:28
+ --> $DIR/mismatch.rs:24:28
|
LL | let e: Example4::<7> = ();
| ------------- ^^ expected struct `Example4`, found `()`
| |
| expected due to this
+ |
+ = note: expected struct `Example4<7_usize>`
+ found unit type `()`
error: aborting due to 5 previous errors
| ------------- ^^ expected struct `Example`, found `()`
| |
| expected due to this
+ |
+ = note: expected struct `Example`
+ found unit type `()`
error[E0308]: mismatched types
- --> $DIR/mismatch.rs:14:34
+ --> $DIR/mismatch.rs:15:34
|
LL | let e: Example2::<u32, 13> = ();
| ------------------- ^^ expected struct `Example2`, found `()`
found unit type `()`
error[E0308]: mismatched types
- --> $DIR/mismatch.rs:16:34
+ --> $DIR/mismatch.rs:18:34
|
LL | let e: Example3::<13, u32> = ();
| ------------------- ^^ expected struct `Example3`, found `()`
found unit type `()`
error[E0308]: mismatched types
- --> $DIR/mismatch.rs:18:28
+ --> $DIR/mismatch.rs:21:28
|
LL | let e: Example3::<7> = ();
| ------------- ^^ expected struct `Example3`, found `()`
found unit type `()`
error[E0308]: mismatched types
- --> $DIR/mismatch.rs:22:28
+ --> $DIR/mismatch.rs:24:28
|
LL | let e: Example4::<7> = ();
| ------------- ^^ expected struct `Example4`, found `()`
| |
| expected due to this
+ |
+ = note: expected struct `Example4<7_usize>`
+ found unit type `()`
error: aborting due to 5 previous errors
fn main() {
let e: Example::<13> = ();
//~^ Error: mismatched types
+ //~| expected struct `Example`
let e: Example2::<u32, 13> = ();
//~^ Error: mismatched types
+ //~| expected struct `Example2`
let e: Example3::<13, u32> = ();
//~^ Error: mismatched types
+ //~| expected struct `Example3`
let e: Example3::<7> = ();
//~^ Error: mismatched types
- // FIXME(const_generics_defaults): There should be a note for the error below, but it is
- // missing.
+ //~| expected struct `Example3<7_usize>`
let e: Example4::<7> = ();
//~^ Error: mismatched types
+ //~| expected struct `Example4<7_usize>`
}
--- /dev/null
+#![feature(const_generics_defaults)]
+struct Foo<const M: usize = 10, 'a>(&'a u32);
+//~^ Error lifetime parameters must be declared prior to const parameters
+
+fn main() {}
--- /dev/null
+error: lifetime parameters must be declared prior to const parameters
+ --> $DIR/param-order-err-pretty-prints-default.rs:2:33
+ |
+LL | struct Foo<const M: usize = 10, 'a>(&'a u32);
+ | ----------------------^^- help: reorder the parameters: lifetimes, then consts and types: `<'a, const M: usize = 10>`
+
+error: aborting due to previous error
+
+error[E0308]: mismatched types
+ --> $DIR/issue-62504.rs:18:21
+ |
+LL | ArrayHolder([0; Self::SIZE])
+ | ^^^^^^^^^^^^^^^ expected `X`, found `Self::SIZE`
+ |
+ = note: expected type `X`
+ found type `Self::SIZE`
+
error: constant expression depends on a generic parameter
--> $DIR/issue-62504.rs:18:25
|
|
= note: this may fail depending on what value the parameter takes
-error: aborting due to previous error
+error: aborting due to 2 previous errors
+For more information about this error, try `rustc --explain E0308`.
pub const fn new() -> Self {
ArrayHolder([0; Self::SIZE])
//~^ ERROR constant expression depends on a generic parameter
- //[min]~| ERROR mismatched types
+ //~| ERROR mismatched types
}
}
+++ /dev/null
-struct Const<const P: &'static ()>;
-//~^ ERROR `&'static ()` is forbidden as the type of a const generic parameter
-
-fn main() {
- const A: &'static () = unsafe {
- std::mem::transmute(10 as *const ())
- };
-
- let _ = Const::<{A}>;
-}
+++ /dev/null
-error: `&'static ()` is forbidden as the type of a const generic parameter
- --> $DIR/transmute-const-param-static-reference.rs:1:23
- |
-LL | struct Const<const P: &'static ()>;
- | ^^^^^^^^^^^
- |
- = note: the only supported types are integers, `bool` and `char`
- = help: more complex types are supported with `#![feature(const_generics)]`
-
-error: aborting due to previous error
-
--- /dev/null
+error: `&'static ()` is forbidden as the type of a const generic parameter
+ --> $DIR/transmute-const-param-static-reference.rs:7:23
+ |
+LL | struct Const<const P: &'static ()>;
+ | ^^^^^^^^^^^
+ |
+ = note: the only supported types are integers, `bool` and `char`
+ = help: more complex types are supported with `#![feature(const_generics)]`
+
+error: aborting due to previous error
+
--- /dev/null
+// revisions: full min
+//[full] check-pass
+
+#![cfg_attr(full, feature(const_generics))]
+#![cfg_attr(full, allow(incomplete_features))]
+
+struct Const<const P: &'static ()>;
+//[min]~^ ERROR `&'static ()` is forbidden as the type of a const generic parameter
+
+fn main() {
+ const A: &'static () = unsafe {
+ std::mem::transmute(10 as *const ())
+ };
+
+ let _ = Const::<{A}>;
+}
+++ /dev/null
-// error-pattern: any use of this value will cause an error
-
-#![feature(const_ptr_read)]
-#![feature(const_ptr_offset)]
-
-fn main() {
- use std::ptr;
-
- const DATA: [u32; 1] = [42];
-
- const PAST_END_PTR: *const u32 = unsafe { DATA.as_ptr().add(1) };
-
- const _READ: u32 = unsafe { ptr::read(PAST_END_PTR) };
- const _CONST_READ: u32 = unsafe { PAST_END_PTR.read() };
- const _MUT_READ: u32 = unsafe { (PAST_END_PTR as *mut u32).read() };
-}
+++ /dev/null
-error: any use of this value will cause an error
- --> $SRC_DIR/core/src/ptr/mod.rs:LL:COL
- |
-LL | copy_nonoverlapping(src, tmp.as_mut_ptr(), 1);
- | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
- | |
- | memory access failed: pointer must be in-bounds at offset 8, but is outside bounds of alloc6 which has size 4
- | inside `std::ptr::read::<u32>` at $SRC_DIR/core/src/ptr/mod.rs:LL:COL
- | inside `_READ` at $DIR/out_of_bounds_read.rs:13:33
- |
- ::: $DIR/out_of_bounds_read.rs:13:5
- |
-LL | const _READ: u32 = unsafe { ptr::read(PAST_END_PTR) };
- | ------------------------------------------------------
- |
- = note: `#[deny(const_err)]` on by default
- = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
- = note: for more information, see issue #71800 <https://github.com/rust-lang/rust/issues/71800>
-
-error: any use of this value will cause an error
- --> $SRC_DIR/core/src/ptr/mod.rs:LL:COL
- |
-LL | copy_nonoverlapping(src, tmp.as_mut_ptr(), 1);
- | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
- | |
- | memory access failed: pointer must be in-bounds at offset 8, but is outside bounds of alloc6 which has size 4
- | inside `std::ptr::read::<u32>` at $SRC_DIR/core/src/ptr/mod.rs:LL:COL
- | inside `ptr::const_ptr::<impl *const u32>::read` at $SRC_DIR/core/src/ptr/const_ptr.rs:LL:COL
- | inside `_CONST_READ` at $DIR/out_of_bounds_read.rs:14:39
- |
- ::: $DIR/out_of_bounds_read.rs:14:5
- |
-LL | const _CONST_READ: u32 = unsafe { PAST_END_PTR.read() };
- | --------------------------------------------------------
- |
- = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
- = note: for more information, see issue #71800 <https://github.com/rust-lang/rust/issues/71800>
-
-error: any use of this value will cause an error
- --> $SRC_DIR/core/src/ptr/mod.rs:LL:COL
- |
-LL | copy_nonoverlapping(src, tmp.as_mut_ptr(), 1);
- | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
- | |
- | memory access failed: pointer must be in-bounds at offset 8, but is outside bounds of alloc6 which has size 4
- | inside `std::ptr::read::<u32>` at $SRC_DIR/core/src/ptr/mod.rs:LL:COL
- | inside `ptr::mut_ptr::<impl *mut u32>::read` at $SRC_DIR/core/src/ptr/mut_ptr.rs:LL:COL
- | inside `_MUT_READ` at $DIR/out_of_bounds_read.rs:15:37
- |
- ::: $DIR/out_of_bounds_read.rs:15:5
- |
-LL | const _MUT_READ: u32 = unsafe { (PAST_END_PTR as *mut u32).read() };
- | --------------------------------------------------------------------
- |
- = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
- = note: for more information, see issue #71800 <https://github.com/rust-lang/rust/issues/71800>
-
-error: aborting due to 3 previous errors
-
--- /dev/null
+// Auxiliary crate used for testing post-monomorphization errors cross-crate.
+// It duplicates the setup used in `stdarch` to validate its intrinsics' const arguments.
+
+struct ValidateConstImm<const IMM: i32, const MIN: i32, const MAX: i32>;
+impl<const IMM: i32, const MIN: i32, const MAX: i32> ValidateConstImm<IMM, MIN, MAX> {
+ pub(crate) const VALID: () = {
+ let _ = 1 / ((IMM >= MIN && IMM <= MAX) as usize);
+ };
+}
+
+macro_rules! static_assert_imm1 {
+ ($imm:ident) => {
+ let _ = $crate::ValidateConstImm::<$imm, 0, { (1 << 1) - 1 }>::VALID;
+ };
+}
+
+// This function triggers an error whenever the const argument does not fit in 1-bit.
+pub fn stdarch_intrinsic<const IMM1: i32>() {
+ static_assert_imm1!(IMM1);
+}
const Z: () = std::panic!("cheese");
//~^ ERROR any use of this value will cause an error
-//~| WARN this was previously accepted by the compiler but is being phased out
const Z2: () = std::panic!();
//~^ ERROR any use of this value will cause an error
-//~| WARN this was previously accepted by the compiler but is being phased out
const Y: () = std::unreachable!();
//~^ ERROR any use of this value will cause an error
-//~| WARN this was previously accepted by the compiler but is being phased out
const X: () = std::unimplemented!();
//~^ ERROR any use of this value will cause an error
-//~| WARN this was previously accepted by the compiler but is being phased out
//
const W: () = std::panic!(MSG);
//~^ ERROR any use of this value will cause an error
-//~| WARN this was previously accepted by the compiler but is being phased out
const Z_CORE: () = core::panic!("cheese");
//~^ ERROR any use of this value will cause an error
-//~| WARN this was previously accepted by the compiler but is being phased out
const Z2_CORE: () = core::panic!();
//~^ ERROR any use of this value will cause an error
-//~| WARN this was previously accepted by the compiler but is being phased out
const Y_CORE: () = core::unreachable!();
//~^ ERROR any use of this value will cause an error
-//~| WARN this was previously accepted by the compiler but is being phased out
const X_CORE: () = core::unimplemented!();
//~^ ERROR any use of this value will cause an error
-//~| WARN this was previously accepted by the compiler but is being phased out
const W_CORE: () = core::panic!(MSG);
//~^ ERROR any use of this value will cause an error
-//~| WARN this was previously accepted by the compiler but is being phased out
-error: any use of this value will cause an error
+error[E0080]: any use of this value will cause an error
--> $DIR/const_panic.rs:7:15
|
LL | const Z: () = std::panic!("cheese");
| |
| the evaluated program panicked at 'cheese', $DIR/const_panic.rs:7:15
|
- = note: `#[deny(const_err)]` on by default
- = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
- = note: for more information, see issue #71800 <https://github.com/rust-lang/rust/issues/71800>
= note: this error originates in the macro `$crate::panic::panic_2015` (in Nightly builds, run with -Z macro-backtrace for more info)
-error: any use of this value will cause an error
- --> $DIR/const_panic.rs:11:16
+error[E0080]: any use of this value will cause an error
+ --> $DIR/const_panic.rs:10:16
|
LL | const Z2: () = std::panic!();
| ---------------^^^^^^^^^^^^^-
| |
- | the evaluated program panicked at 'explicit panic', $DIR/const_panic.rs:11:16
+ | the evaluated program panicked at 'explicit panic', $DIR/const_panic.rs:10:16
|
- = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
- = note: for more information, see issue #71800 <https://github.com/rust-lang/rust/issues/71800>
= note: this error originates in the macro `$crate::panic::panic_2015` (in Nightly builds, run with -Z macro-backtrace for more info)
-error: any use of this value will cause an error
- --> $DIR/const_panic.rs:15:15
+error[E0080]: any use of this value will cause an error
+ --> $DIR/const_panic.rs:13:15
|
LL | const Y: () = std::unreachable!();
| --------------^^^^^^^^^^^^^^^^^^^-
| |
- | the evaluated program panicked at 'internal error: entered unreachable code', $DIR/const_panic.rs:15:15
+ | the evaluated program panicked at 'internal error: entered unreachable code', $DIR/const_panic.rs:13:15
|
- = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
- = note: for more information, see issue #71800 <https://github.com/rust-lang/rust/issues/71800>
= note: this error originates in the macro `$crate::panic::panic_2015` (in Nightly builds, run with -Z macro-backtrace for more info)
-error: any use of this value will cause an error
- --> $DIR/const_panic.rs:19:15
+error[E0080]: any use of this value will cause an error
+ --> $DIR/const_panic.rs:16:15
|
LL | const X: () = std::unimplemented!();
| --------------^^^^^^^^^^^^^^^^^^^^^-
| |
- | the evaluated program panicked at 'not implemented', $DIR/const_panic.rs:19:15
+ | the evaluated program panicked at 'not implemented', $DIR/const_panic.rs:16:15
|
- = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
- = note: for more information, see issue #71800 <https://github.com/rust-lang/rust/issues/71800>
= note: this error originates in the macro `$crate::panic::panic_2015` (in Nightly builds, run with -Z macro-backtrace for more info)
-error: any use of this value will cause an error
- --> $DIR/const_panic.rs:23:15
+error[E0080]: any use of this value will cause an error
+ --> $DIR/const_panic.rs:19:15
|
LL | const W: () = std::panic!(MSG);
| --------------^^^^^^^^^^^^^^^^-
| |
- | the evaluated program panicked at 'hello', $DIR/const_panic.rs:23:15
+ | the evaluated program panicked at 'hello', $DIR/const_panic.rs:19:15
|
- = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
- = note: for more information, see issue #71800 <https://github.com/rust-lang/rust/issues/71800>
= note: this error originates in the macro `$crate::panic::panic_2015` (in Nightly builds, run with -Z macro-backtrace for more info)
-error: any use of this value will cause an error
- --> $DIR/const_panic.rs:27:20
+error[E0080]: any use of this value will cause an error
+ --> $DIR/const_panic.rs:22:20
|
LL | const Z_CORE: () = core::panic!("cheese");
| -------------------^^^^^^^^^^^^^^^^^^^^^^-
| |
- | the evaluated program panicked at 'cheese', $DIR/const_panic.rs:27:20
+ | the evaluated program panicked at 'cheese', $DIR/const_panic.rs:22:20
|
- = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
- = note: for more information, see issue #71800 <https://github.com/rust-lang/rust/issues/71800>
= note: this error originates in the macro `$crate::panic::panic_2015` (in Nightly builds, run with -Z macro-backtrace for more info)
-error: any use of this value will cause an error
- --> $DIR/const_panic.rs:31:21
+error[E0080]: any use of this value will cause an error
+ --> $DIR/const_panic.rs:25:21
|
LL | const Z2_CORE: () = core::panic!();
| --------------------^^^^^^^^^^^^^^-
| |
- | the evaluated program panicked at 'explicit panic', $DIR/const_panic.rs:31:21
+ | the evaluated program panicked at 'explicit panic', $DIR/const_panic.rs:25:21
|
- = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
- = note: for more information, see issue #71800 <https://github.com/rust-lang/rust/issues/71800>
= note: this error originates in the macro `$crate::panic::panic_2015` (in Nightly builds, run with -Z macro-backtrace for more info)
-error: any use of this value will cause an error
- --> $DIR/const_panic.rs:35:20
+error[E0080]: any use of this value will cause an error
+ --> $DIR/const_panic.rs:28:20
|
LL | const Y_CORE: () = core::unreachable!();
| -------------------^^^^^^^^^^^^^^^^^^^^-
| |
- | the evaluated program panicked at 'internal error: entered unreachable code', $DIR/const_panic.rs:35:20
+ | the evaluated program panicked at 'internal error: entered unreachable code', $DIR/const_panic.rs:28:20
|
- = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
- = note: for more information, see issue #71800 <https://github.com/rust-lang/rust/issues/71800>
= note: this error originates in the macro `$crate::panic::panic_2015` (in Nightly builds, run with -Z macro-backtrace for more info)
-error: any use of this value will cause an error
- --> $DIR/const_panic.rs:39:20
+error[E0080]: any use of this value will cause an error
+ --> $DIR/const_panic.rs:31:20
|
LL | const X_CORE: () = core::unimplemented!();
| -------------------^^^^^^^^^^^^^^^^^^^^^^-
| |
- | the evaluated program panicked at 'not implemented', $DIR/const_panic.rs:39:20
+ | the evaluated program panicked at 'not implemented', $DIR/const_panic.rs:31:20
|
- = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
- = note: for more information, see issue #71800 <https://github.com/rust-lang/rust/issues/71800>
= note: this error originates in the macro `$crate::panic::panic_2015` (in Nightly builds, run with -Z macro-backtrace for more info)
-error: any use of this value will cause an error
- --> $DIR/const_panic.rs:43:20
+error[E0080]: any use of this value will cause an error
+ --> $DIR/const_panic.rs:34:20
|
LL | const W_CORE: () = core::panic!(MSG);
| -------------------^^^^^^^^^^^^^^^^^-
| |
- | the evaluated program panicked at 'hello', $DIR/const_panic.rs:43:20
+ | the evaluated program panicked at 'hello', $DIR/const_panic.rs:34:20
|
- = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
- = note: for more information, see issue #71800 <https://github.com/rust-lang/rust/issues/71800>
= note: this error originates in the macro `$crate::panic::panic_2015` (in Nightly builds, run with -Z macro-backtrace for more info)
error: aborting due to 10 previous errors
+For more information about this error, try `rustc --explain E0080`.
const Z: () = panic!("cheese");
//~^ ERROR any use of this value will cause an error
-//~| WARN this was previously accepted by the compiler but is being phased out
const Y: () = unreachable!();
//~^ ERROR any use of this value will cause an error
-//~| WARN this was previously accepted by the compiler but is being phased out
const X: () = unimplemented!();
//~^ ERROR any use of this value will cause an error
-//~| WARN this was previously accepted by the compiler but is being phased out
#[lang = "eh_personality"]
fn eh() {}
-error: any use of this value will cause an error
+error[E0080]: any use of this value will cause an error
--> $DIR/const_panic_libcore_bin.rs:9:15
|
LL | const Z: () = panic!("cheese");
| |
| the evaluated program panicked at 'cheese', $DIR/const_panic_libcore_bin.rs:9:15
|
- = note: `#[deny(const_err)]` on by default
- = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
- = note: for more information, see issue #71800 <https://github.com/rust-lang/rust/issues/71800>
= note: this error originates in the macro `$crate::panic::panic_2015` (in Nightly builds, run with -Z macro-backtrace for more info)
-error: any use of this value will cause an error
- --> $DIR/const_panic_libcore_bin.rs:13:15
+error[E0080]: any use of this value will cause an error
+ --> $DIR/const_panic_libcore_bin.rs:12:15
|
LL | const Y: () = unreachable!();
| --------------^^^^^^^^^^^^^^-
| |
- | the evaluated program panicked at 'internal error: entered unreachable code', $DIR/const_panic_libcore_bin.rs:13:15
+ | the evaluated program panicked at 'internal error: entered unreachable code', $DIR/const_panic_libcore_bin.rs:12:15
|
- = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
- = note: for more information, see issue #71800 <https://github.com/rust-lang/rust/issues/71800>
= note: this error originates in the macro `$crate::panic::panic_2015` (in Nightly builds, run with -Z macro-backtrace for more info)
-error: any use of this value will cause an error
- --> $DIR/const_panic_libcore_bin.rs:17:15
+error[E0080]: any use of this value will cause an error
+ --> $DIR/const_panic_libcore_bin.rs:15:15
|
LL | const X: () = unimplemented!();
| --------------^^^^^^^^^^^^^^^^-
| |
- | the evaluated program panicked at 'not implemented', $DIR/const_panic_libcore_bin.rs:17:15
+ | the evaluated program panicked at 'not implemented', $DIR/const_panic_libcore_bin.rs:15:15
|
- = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
- = note: for more information, see issue #71800 <https://github.com/rust-lang/rust/issues/71800>
= note: this error originates in the macro `$crate::panic::panic_2015` (in Nightly builds, run with -Z macro-backtrace for more info)
error: aborting due to 3 previous errors
+For more information about this error, try `rustc --explain E0080`.
--> $DIR/alloc_intrinsic_uninit.rs:9:1
|
LL | const BAR: &i32 = unsafe { &*(intrinsics::const_allocate(4, 4) as *mut i32) };
- | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type validation failed: encountered uninitialized bytes at .<deref>, but expected initialized plain (non-pointer) bytes
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type validation failed at .<deref>: encountered uninitialized bytes, but expected initialized plain (non-pointer) bytes
|
= note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior.
= note: the raw bytes of the constant (size: 4, align: 4) {
--> $DIR/alloc_intrinsic_uninit.rs:9:1
|
LL | const BAR: &i32 = unsafe { &*(intrinsics::const_allocate(4, 4) as *mut i32) };
- | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type validation failed: encountered uninitialized bytes at .<deref>, but expected initialized plain (non-pointer) bytes
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type validation failed at .<deref>: encountered uninitialized bytes, but expected initialized plain (non-pointer) bytes
|
= note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior.
= note: the raw bytes of the constant (size: 8, align: 8) {
= warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
= note: for more information, see issue #71800 <https://github.com/rust-lang/rust/issues/71800>
-error[E0080]: evaluation of constant value failed
+error[E0080]: evaluation of `foo::<()>` failed
--> $DIR/issue-50814-2.rs:19:6
|
LL | &<A<T> as Foo<T>>::BAR
= warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
= note: for more information, see issue #71800 <https://github.com/rust-lang/rust/issues/71800>
-error[E0080]: evaluation of constant value failed
+error[E0080]: evaluation of `foo::<i32>` failed
--> $DIR/issue-50814.rs:21:6
|
LL | &Sum::<U8,U8>::MAX
--- /dev/null
+// This is a test with a setup similar to issue 85155, which triggers a const eval error: a const
+// argument value is outside the range expected by the `stdarch` intrinsic.
+//
+// It's not the exact code mentioned in that issue because it depends both on `stdarch` intrinsics
+// only available on x64, and internal implementation details of `stdarch`. But mostly because these
+// are not important to trigger the diagnostics issue: it's specifically about the lack of context
+// in the diagnostics of post-monomorphization errors (PMEs) for consts, happening in a dependency.
+// Therefore, its setup is reproduced with an aux crate, which will similarly trigger a PME
+// depending on the const argument value, like the `stdarch` intrinsics would.
+//
+// aux-build: post_monomorphization_error.rs
+// build-fail: this is a post-monomorphization error, it passes check runs and requires building
+// to actually fail.
+
+extern crate post_monomorphization_error;
+
+fn main() {
+ // This function triggers a PME whenever the const argument does not fit in 1-bit.
+ post_monomorphization_error::stdarch_intrinsic::<2>();
+ //~^ NOTE the above error was encountered while instantiating
+}
--- /dev/null
+error[E0080]: evaluation of `post_monomorphization_error::ValidateConstImm::<2_i32, 0_i32, 1_i32>::VALID` failed
+ --> $DIR/auxiliary/post_monomorphization_error.rs:7:17
+ |
+LL | let _ = 1 / ((IMM >= MIN && IMM <= MAX) as usize);
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ attempt to divide `1_usize` by zero
+
+note: the above error was encountered while instantiating `fn post_monomorphization_error::stdarch_intrinsic::<2_i32>`
+ --> $DIR/issue-85155.rs:19:5
+ |
+LL | post_monomorphization_error::stdarch_intrinsic::<2>();
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0080`.
impl PrintName {
const VOID: ! = panic!();
- //~^ WARN any use of this value will cause an error
- //~| WARN this was previously accepted by the compiler but is being phased out
+ //~^ ERROR any use of this value will cause an error
}
fn main() {
-warning: any use of this value will cause an error
+error[E0080]: any use of this value will cause an error
--> $DIR/panic-assoc-never-type.rs:11:21
|
LL | const VOID: ! = panic!();
| |
| the evaluated program panicked at 'explicit panic', $DIR/panic-assoc-never-type.rs:11:21
|
-note: the lint level is defined here
- --> $DIR/panic-assoc-never-type.rs:4:9
- |
-LL | #![warn(const_err)]
- | ^^^^^^^^^
- = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
- = note: for more information, see issue #71800 <https://github.com/rust-lang/rust/issues/71800>
- = note: this warning originates in the macro `$crate::panic::panic_2015` (in Nightly builds, run with -Z macro-backtrace for more info)
+ = note: this error originates in the macro `$crate::panic::panic_2015` (in Nightly builds, run with -Z macro-backtrace for more info)
error[E0080]: erroneous constant used
- --> $DIR/panic-assoc-never-type.rs:17:13
+ --> $DIR/panic-assoc-never-type.rs:16:13
|
LL | let _ = PrintName::VOID;
| ^^^^^^^^^^^^^^^ referenced constant has errors
-error: aborting due to previous error; 1 warning emitted
+error: aborting due to 2 previous errors
For more information about this error, try `rustc --explain E0080`.
-// build-fail
-
// Regression test for #66975
#![warn(const_err)]
#![feature(const_panic)]
#![feature(never_type)]
const VOID: ! = panic!();
-//~^ WARN any use of this value will cause an error
-//~| WARN this was previously accepted by the compiler but is being phased out
+//~^ ERROR any use of this value will cause an error
fn main() {
let _ = VOID;
- //~^ ERROR erroneous constant used
}
-warning: any use of this value will cause an error
- --> $DIR/panic-never-type.rs:8:17
+error[E0080]: any use of this value will cause an error
+ --> $DIR/panic-never-type.rs:6:17
|
LL | const VOID: ! = panic!();
| ----------------^^^^^^^^-
| |
- | the evaluated program panicked at 'explicit panic', $DIR/panic-never-type.rs:8:17
+ | the evaluated program panicked at 'explicit panic', $DIR/panic-never-type.rs:6:17
|
-note: the lint level is defined here
- --> $DIR/panic-never-type.rs:4:9
- |
-LL | #![warn(const_err)]
- | ^^^^^^^^^
- = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
- = note: for more information, see issue #71800 <https://github.com/rust-lang/rust/issues/71800>
- = note: this warning originates in the macro `$crate::panic::panic_2015` (in Nightly builds, run with -Z macro-backtrace for more info)
-
-error[E0080]: erroneous constant used
- --> $DIR/panic-never-type.rs:13:13
- |
-LL | let _ = VOID;
- | ^^^^ referenced constant has errors
+ = note: this error originates in the macro `$crate::panic::panic_2015` (in Nightly builds, run with -Z macro-backtrace for more info)
-error: aborting due to previous error; 1 warning emitted
+error: aborting due to previous error
For more information about this error, try `rustc --explain E0080`.
--> $DIR/ub-enum.rs:24:1
|
LL | const BAD_ENUM: Enum = unsafe { mem::transmute(1usize) };
- | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type validation failed: encountered 0x00000001 at .<enum-tag>, but expected a valid enum tag
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type validation failed at .<enum-tag>: encountered 0x00000001, but expected a valid enum tag
|
= note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior.
= note: the raw bytes of the constant (size: 4, align: 4) {
--> $DIR/ub-enum.rs:27:1
|
LL | const BAD_ENUM_PTR: Enum = unsafe { mem::transmute(&1) };
- | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type validation failed: encountered pointer to alloc8 at .<enum-tag>, but expected initialized plain (non-pointer) bytes
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type validation failed at .<enum-tag>: encountered pointer to alloc8, but expected initialized plain (non-pointer) bytes
|
= note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior.
= note: the raw bytes of the constant (size: 4, align: 4) {
--> $DIR/ub-enum.rs:30:1
|
LL | const BAD_ENUM_WRAPPED: Wrap<Enum> = unsafe { mem::transmute(&1) };
- | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type validation failed: encountered pointer to alloc12 at .0.<enum-tag>, but expected initialized plain (non-pointer) bytes
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type validation failed at .0.<enum-tag>: encountered pointer to alloc12, but expected initialized plain (non-pointer) bytes
|
= note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior.
= note: the raw bytes of the constant (size: 4, align: 4) {
--> $DIR/ub-enum.rs:42:1
|
LL | const BAD_ENUM2: Enum2 = unsafe { mem::transmute(0usize) };
- | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type validation failed: encountered 0x00000000 at .<enum-tag>, but expected a valid enum tag
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type validation failed at .<enum-tag>: encountered 0x00000000, but expected a valid enum tag
|
= note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior.
= note: the raw bytes of the constant (size: 4, align: 4) {
--> $DIR/ub-enum.rs:44:1
|
LL | const BAD_ENUM2_PTR: Enum2 = unsafe { mem::transmute(&0) };
- | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type validation failed: encountered pointer to alloc18 at .<enum-tag>, but expected initialized plain (non-pointer) bytes
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type validation failed at .<enum-tag>: encountered pointer to alloc18, but expected initialized plain (non-pointer) bytes
|
= note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior.
= note: the raw bytes of the constant (size: 4, align: 4) {
--> $DIR/ub-enum.rs:47:1
|
LL | const BAD_ENUM2_WRAPPED: Wrap<Enum2> = unsafe { mem::transmute(&0) };
- | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type validation failed: encountered pointer to alloc22 at .0.<enum-tag>, but expected initialized plain (non-pointer) bytes
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type validation failed at .0.<enum-tag>: encountered pointer to alloc22, but expected initialized plain (non-pointer) bytes
|
= note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior.
= note: the raw bytes of the constant (size: 4, align: 4) {
--> $DIR/ub-enum.rs:56:1
|
LL | const BAD_ENUM2_UNDEF : Enum2 = unsafe { MaybeUninit { uninit: () }.init };
- | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type validation failed: encountered uninitialized bytes at .<enum-tag>, but expected initialized plain (non-pointer) bytes
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type validation failed at .<enum-tag>: encountered uninitialized bytes, but expected initialized plain (non-pointer) bytes
|
= note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior.
= note: the raw bytes of the constant (size: 4, align: 4) {
--> $DIR/ub-enum.rs:60:1
|
LL | const BAD_ENUM2_OPTION_PTR: Option<Enum2> = unsafe { mem::transmute(&0) };
- | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type validation failed: encountered pointer to alloc28 at .<enum-tag>, but expected initialized plain (non-pointer) bytes
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type validation failed at .<enum-tag>: encountered pointer to alloc28, but expected initialized plain (non-pointer) bytes
|
= note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior.
= note: the raw bytes of the constant (size: 4, align: 4) {
--> $DIR/ub-enum.rs:77:1
|
LL | const BAD_UNINHABITED_VARIANT1: UninhDiscriminant = unsafe { mem::transmute(1u8) };
- | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type validation failed: encountered a value of the never type `!` at .<enum-variant(B)>.0
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type validation failed at .<enum-variant(B)>.0: encountered a value of the never type `!`
|
= note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior.
= note: the raw bytes of the constant (size: 1, align: 1) {
--> $DIR/ub-enum.rs:79:1
|
LL | const BAD_UNINHABITED_VARIANT2: UninhDiscriminant = unsafe { mem::transmute(3u8) };
- | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type validation failed: encountered a value of uninhabited type Never at .<enum-variant(D)>.0
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type validation failed at .<enum-variant(D)>.0: encountered a value of uninhabited type Never
|
= note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior.
= note: the raw bytes of the constant (size: 1, align: 1) {
--> $DIR/ub-enum.rs:87:1
|
LL | const BAD_OPTION_CHAR: Option<(char, char)> = Some(('x', unsafe { mem::transmute(!0u32) }));
- | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type validation failed: encountered 0xffffffff at .<enum-variant(Some)>.0.1, but expected a valid unicode scalar value (in `0..=0x10FFFF` but not in `0xD800..=0xDFFF`)
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type validation failed at .<enum-variant(Some)>.0.1: encountered 0xffffffff, but expected a valid unicode scalar value (in `0..=0x10FFFF` but not in `0xD800..=0xDFFF`)
|
= note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior.
= note: the raw bytes of the constant (size: 8, align: 4) {
--> $DIR/ub-enum.rs:92:1
|
LL | const BAD_UNINHABITED_WITH_DATA1: Result<(i32, Never), (i32, !)> = unsafe { mem::transmute(0u64) };
- | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type validation failed: encountered a value of uninhabited type Never at .<enum-variant(Ok)>.0.1
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type validation failed at .<enum-variant(Ok)>.0.1: encountered a value of uninhabited type Never
|
= note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior.
= note: the raw bytes of the constant (size: 8, align: 4) {
--> $DIR/ub-enum.rs:94:1
|
LL | const BAD_UNINHABITED_WITH_DATA2: Result<(i32, !), (i32, Never)> = unsafe { mem::transmute(0u64) };
- | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type validation failed: encountered a value of the never type `!` at .<enum-variant(Ok)>.0.1
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type validation failed at .<enum-variant(Ok)>.0.1: encountered a value of the never type `!`
|
= note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior.
= note: the raw bytes of the constant (size: 8, align: 4) {
--> $DIR/ub-enum.rs:24:1
|
LL | const BAD_ENUM: Enum = unsafe { mem::transmute(1usize) };
- | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type validation failed: encountered 0x0000000000000001 at .<enum-tag>, but expected a valid enum tag
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type validation failed at .<enum-tag>: encountered 0x0000000000000001, but expected a valid enum tag
|
= note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior.
= note: the raw bytes of the constant (size: 8, align: 8) {
--> $DIR/ub-enum.rs:27:1
|
LL | const BAD_ENUM_PTR: Enum = unsafe { mem::transmute(&1) };
- | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type validation failed: encountered pointer to alloc8 at .<enum-tag>, but expected initialized plain (non-pointer) bytes
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type validation failed at .<enum-tag>: encountered pointer to alloc8, but expected initialized plain (non-pointer) bytes
|
= note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior.
= note: the raw bytes of the constant (size: 8, align: 8) {
--> $DIR/ub-enum.rs:30:1
|
LL | const BAD_ENUM_WRAPPED: Wrap<Enum> = unsafe { mem::transmute(&1) };
- | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type validation failed: encountered pointer to alloc12 at .0.<enum-tag>, but expected initialized plain (non-pointer) bytes
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type validation failed at .0.<enum-tag>: encountered pointer to alloc12, but expected initialized plain (non-pointer) bytes
|
= note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior.
= note: the raw bytes of the constant (size: 8, align: 8) {
--> $DIR/ub-enum.rs:42:1
|
LL | const BAD_ENUM2: Enum2 = unsafe { mem::transmute(0usize) };
- | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type validation failed: encountered 0x0000000000000000 at .<enum-tag>, but expected a valid enum tag
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type validation failed at .<enum-tag>: encountered 0x0000000000000000, but expected a valid enum tag
|
= note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior.
= note: the raw bytes of the constant (size: 8, align: 8) {
--> $DIR/ub-enum.rs:44:1
|
LL | const BAD_ENUM2_PTR: Enum2 = unsafe { mem::transmute(&0) };
- | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type validation failed: encountered pointer to alloc18 at .<enum-tag>, but expected initialized plain (non-pointer) bytes
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type validation failed at .<enum-tag>: encountered pointer to alloc18, but expected initialized plain (non-pointer) bytes
|
= note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior.
= note: the raw bytes of the constant (size: 8, align: 8) {
--> $DIR/ub-enum.rs:47:1
|
LL | const BAD_ENUM2_WRAPPED: Wrap<Enum2> = unsafe { mem::transmute(&0) };
- | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type validation failed: encountered pointer to alloc22 at .0.<enum-tag>, but expected initialized plain (non-pointer) bytes
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type validation failed at .0.<enum-tag>: encountered pointer to alloc22, but expected initialized plain (non-pointer) bytes
|
= note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior.
= note: the raw bytes of the constant (size: 8, align: 8) {
--> $DIR/ub-enum.rs:56:1
|
LL | const BAD_ENUM2_UNDEF : Enum2 = unsafe { MaybeUninit { uninit: () }.init };
- | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type validation failed: encountered uninitialized bytes at .<enum-tag>, but expected initialized plain (non-pointer) bytes
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type validation failed at .<enum-tag>: encountered uninitialized bytes, but expected initialized plain (non-pointer) bytes
|
= note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior.
= note: the raw bytes of the constant (size: 8, align: 8) {
--> $DIR/ub-enum.rs:60:1
|
LL | const BAD_ENUM2_OPTION_PTR: Option<Enum2> = unsafe { mem::transmute(&0) };
- | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type validation failed: encountered pointer to alloc28 at .<enum-tag>, but expected initialized plain (non-pointer) bytes
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type validation failed at .<enum-tag>: encountered pointer to alloc28, but expected initialized plain (non-pointer) bytes
|
= note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior.
= note: the raw bytes of the constant (size: 8, align: 8) {
--> $DIR/ub-enum.rs:77:1
|
LL | const BAD_UNINHABITED_VARIANT1: UninhDiscriminant = unsafe { mem::transmute(1u8) };
- | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type validation failed: encountered a value of the never type `!` at .<enum-variant(B)>.0
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type validation failed at .<enum-variant(B)>.0: encountered a value of the never type `!`
|
= note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior.
= note: the raw bytes of the constant (size: 1, align: 1) {
--> $DIR/ub-enum.rs:79:1
|
LL | const BAD_UNINHABITED_VARIANT2: UninhDiscriminant = unsafe { mem::transmute(3u8) };
- | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type validation failed: encountered a value of uninhabited type Never at .<enum-variant(D)>.0
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type validation failed at .<enum-variant(D)>.0: encountered a value of uninhabited type Never
|
= note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior.
= note: the raw bytes of the constant (size: 1, align: 1) {
--> $DIR/ub-enum.rs:87:1
|
LL | const BAD_OPTION_CHAR: Option<(char, char)> = Some(('x', unsafe { mem::transmute(!0u32) }));
- | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type validation failed: encountered 0xffffffff at .<enum-variant(Some)>.0.1, but expected a valid unicode scalar value (in `0..=0x10FFFF` but not in `0xD800..=0xDFFF`)
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type validation failed at .<enum-variant(Some)>.0.1: encountered 0xffffffff, but expected a valid unicode scalar value (in `0..=0x10FFFF` but not in `0xD800..=0xDFFF`)
|
= note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior.
= note: the raw bytes of the constant (size: 8, align: 4) {
--> $DIR/ub-enum.rs:92:1
|
LL | const BAD_UNINHABITED_WITH_DATA1: Result<(i32, Never), (i32, !)> = unsafe { mem::transmute(0u64) };
- | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type validation failed: encountered a value of uninhabited type Never at .<enum-variant(Ok)>.0.1
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type validation failed at .<enum-variant(Ok)>.0.1: encountered a value of uninhabited type Never
|
= note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior.
= note: the raw bytes of the constant (size: 8, align: 4) {
--> $DIR/ub-enum.rs:94:1
|
LL | const BAD_UNINHABITED_WITH_DATA2: Result<(i32, !), (i32, Never)> = unsafe { mem::transmute(0u64) };
- | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type validation failed: encountered a value of the never type `!` at .<enum-variant(Ok)>.0.1
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type validation failed at .<enum-variant(Ok)>.0.1: encountered a value of the never type `!`
|
= note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior.
= note: the raw bytes of the constant (size: 8, align: 4) {
--- /dev/null
+error: any use of this value will cause an error
+ --> $DIR/ub-incorrect-vtable.rs:19:14
+ |
+LL | / const INVALID_VTABLE_ALIGNMENT: &dyn Trait =
+LL | | unsafe { std::mem::transmute((&92u8, &[0usize, 1usize, 1000usize])) };
+ | |______________^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^__-
+ | |
+ | invalid vtable: alignment `1000` is not a power of 2
+ |
+ = note: `#[deny(const_err)]` on by default
+ = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
+ = note: for more information, see issue #71800 <https://github.com/rust-lang/rust/issues/71800>
+
+error: any use of this value will cause an error
+ --> $DIR/ub-incorrect-vtable.rs:25:14
+ |
+LL | / const INVALID_VTABLE_SIZE: &dyn Trait =
+LL | | unsafe { std::mem::transmute((&92u8, &[1usize, usize::MAX, 1usize])) };
+ | |______________^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^__-
+ | |
+ | invalid vtable: size is bigger than largest supported object
+ |
+ = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
+ = note: for more information, see issue #71800 <https://github.com/rust-lang/rust/issues/71800>
+
+error[E0080]: it is undefined behavior to use this value
+ --> $DIR/ub-incorrect-vtable.rs:36:1
+ |
+LL | / const INVALID_VTABLE_ALIGNMENT_UB: W<&dyn Trait> =
+LL | | unsafe { std::mem::transmute((&92u8, &(drop_me as fn(*mut usize), 1usize, 1000usize))) };
+ | |_____________________________________________________________________________________________^ type validation failed at .0: encountered invalid vtable: alignment `1000` is not a power of 2
+ |
+ = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior.
+ = note: the raw bytes of the constant (size: 8, align: 4) {
+ ╾─allocN─╼ ╾─allocN─╼ │ ╾──╼╾──╼
+ }
+
+error[E0080]: it is undefined behavior to use this value
+ --> $DIR/ub-incorrect-vtable.rs:41:1
+ |
+LL | / const INVALID_VTABLE_SIZE_UB: W<&dyn Trait> =
+LL | | unsafe { std::mem::transmute((&92u8, &(drop_me as fn(*mut usize), usize::MAX, 1usize))) };
+ | |______________________________________________________________________________________________^ type validation failed at .0: encountered invalid vtable: size is bigger than largest supported object
+ |
+ = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior.
+ = note: the raw bytes of the constant (size: 8, align: 4) {
+ ╾─allocN─╼ ╾─allocN─╼ │ ╾──╼╾──╼
+ }
+
+error: aborting due to 4 previous errors
+
+For more information about this error, try `rustc --explain E0080`.
--- /dev/null
+error: any use of this value will cause an error
+ --> $DIR/ub-incorrect-vtable.rs:19:14
+ |
+LL | / const INVALID_VTABLE_ALIGNMENT: &dyn Trait =
+LL | | unsafe { std::mem::transmute((&92u8, &[0usize, 1usize, 1000usize])) };
+ | |______________^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^__-
+ | |
+ | invalid vtable: alignment `1000` is not a power of 2
+ |
+ = note: `#[deny(const_err)]` on by default
+ = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
+ = note: for more information, see issue #71800 <https://github.com/rust-lang/rust/issues/71800>
+
+error: any use of this value will cause an error
+ --> $DIR/ub-incorrect-vtable.rs:25:14
+ |
+LL | / const INVALID_VTABLE_SIZE: &dyn Trait =
+LL | | unsafe { std::mem::transmute((&92u8, &[1usize, usize::MAX, 1usize])) };
+ | |______________^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^__-
+ | |
+ | invalid vtable: size is bigger than largest supported object
+ |
+ = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
+ = note: for more information, see issue #71800 <https://github.com/rust-lang/rust/issues/71800>
+
+error[E0080]: it is undefined behavior to use this value
+ --> $DIR/ub-incorrect-vtable.rs:36:1
+ |
+LL | / const INVALID_VTABLE_ALIGNMENT_UB: W<&dyn Trait> =
+LL | | unsafe { std::mem::transmute((&92u8, &(drop_me as fn(*mut usize), 1usize, 1000usize))) };
+ | |_____________________________________________________________________________________________^ type validation failed at .0: encountered invalid vtable: alignment `1000` is not a power of 2
+ |
+ = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior.
+ = note: the raw bytes of the constant (size: 16, align: 8) {
+ ╾───────allocN───────╼ ╾───────allocN───────╼ │ ╾──────╼╾──────╼
+ }
+
+error[E0080]: it is undefined behavior to use this value
+ --> $DIR/ub-incorrect-vtable.rs:41:1
+ |
+LL | / const INVALID_VTABLE_SIZE_UB: W<&dyn Trait> =
+LL | | unsafe { std::mem::transmute((&92u8, &(drop_me as fn(*mut usize), usize::MAX, 1usize))) };
+ | |______________________________________________________________________________________________^ type validation failed at .0: encountered invalid vtable: size is bigger than largest supported object
+ |
+ = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior.
+ = note: the raw bytes of the constant (size: 16, align: 8) {
+ ╾───────allocN───────╼ ╾───────allocN───────╼ │ ╾──────╼╾──────╼
+ }
+
+error: aborting due to 4 previous errors
+
+For more information about this error, try `rustc --explain E0080`.
--- /dev/null
+// This test contains code with incorrect vtables in a const context:
+// - from issue 86132: a trait object with invalid alignment caused an ICE in const eval, and now
+// triggers an error
+// - a similar test that triggers a previously-untested const UB error: emitted close to the above
+// error, it checks the correctness of the size
+//
+// As is, this code will only hard error when the constants are used, and the errors are emitted via
+// the `#[allow]`-able `const_err` lint. However, if the transparent wrapper technique to prevent
+// reborrows is used -- from `ub-wide-ptr.rs` -- these two errors reach validation and would trigger
+// ICEs as tracked by #86193. So we also use the transparent wrapper to verify proper validation
+// errors are emitted instead of ICEs.
+
+// stderr-per-bitwidth
+// normalize-stderr-test "alloc\d+" -> "allocN"
+
+trait Trait {}
+
+const INVALID_VTABLE_ALIGNMENT: &dyn Trait =
+ unsafe { std::mem::transmute((&92u8, &[0usize, 1usize, 1000usize])) };
+//~^ ERROR any use of this value will cause an error
+//~| WARNING this was previously accepted by the compiler
+//~| invalid vtable: alignment `1000` is not a power of 2
+
+const INVALID_VTABLE_SIZE: &dyn Trait =
+ unsafe { std::mem::transmute((&92u8, &[1usize, usize::MAX, 1usize])) };
+//~^ ERROR any use of this value will cause an error
+//~| WARNING this was previously accepted by the compiler
+//~| invalid vtable: size is bigger than largest supported object
+
+#[repr(transparent)]
+struct W<T>(T);
+
+// The drop fn is checked before size/align are, so get ourselves a "sufficiently valid" drop fn
+fn drop_me(_: *mut usize) {}
+
+const INVALID_VTABLE_ALIGNMENT_UB: W<&dyn Trait> =
+ unsafe { std::mem::transmute((&92u8, &(drop_me as fn(*mut usize), 1usize, 1000usize))) };
+//~^^ ERROR it is undefined behavior to use this value
+//~| invalid vtable: alignment `1000` is not a power of 2
+
+const INVALID_VTABLE_SIZE_UB: W<&dyn Trait> =
+ unsafe { std::mem::transmute((&92u8, &(drop_me as fn(*mut usize), usize::MAX, 1usize))) };
+//~^^ ERROR it is undefined behavior to use this value
+//~| invalid vtable: size is bigger than largest supported object
+
+fn main() {}
... |
LL | | ]
LL | | };
- | |__^ type validation failed: encountered uninitialized bytes at [0]
+ | |__^ type validation failed at [0]: encountered uninitialized bytes
|
= note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior.
= note: the raw bytes of the constant (size: 12, align: 4) {
... |
LL | | )
LL | | };
- | |__^ type validation failed: encountered uninitialized bytes at [1]
+ | |__^ type validation failed at [1]: encountered uninitialized bytes
|
= note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior.
= note: the raw bytes of the constant (size: 12, align: 4) {
... |
LL | | )
LL | | };
- | |__^ type validation failed: encountered uninitialized bytes at [2]
+ | |__^ type validation failed at [2]: encountered uninitialized bytes
|
= note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior.
= note: the raw bytes of the constant (size: 12, align: 4) {
... |
LL | | ]
LL | | };
- | |__^ type validation failed: encountered uninitialized bytes at [0]
+ | |__^ type validation failed at [0]: encountered uninitialized bytes
|
= note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior.
= note: the raw bytes of the constant (size: 12, align: 4) {
... |
LL | | )
LL | | };
- | |__^ type validation failed: encountered uninitialized bytes at [1]
+ | |__^ type validation failed at [1]: encountered uninitialized bytes
|
= note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior.
= note: the raw bytes of the constant (size: 12, align: 4) {
... |
LL | | )
LL | | };
- | |__^ type validation failed: encountered uninitialized bytes at [2]
+ | |__^ type validation failed at [2]: encountered uninitialized bytes
|
= note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior.
= note: the raw bytes of the constant (size: 12, align: 4) {
const UNINIT_INT_0: [u32; 3] = unsafe {
//~^ ERROR it is undefined behavior to use this value
-//~| type validation failed: encountered uninitialized bytes at [0]
+//~| type validation failed at [0]: encountered uninitialized bytes
[
MaybeUninit { uninit: () }.init,
1,
};
const UNINIT_INT_1: [u32; 3] = unsafe {
//~^ ERROR it is undefined behavior to use this value
-//~| type validation failed: encountered uninitialized bytes at [1]
+//~| type validation failed at [1]: encountered uninitialized bytes
mem::transmute(
[
0u8,
};
const UNINIT_INT_2: [u32; 3] = unsafe {
//~^ ERROR it is undefined behavior to use this value
-//~| type validation failed: encountered uninitialized bytes at [2]
+//~| type validation failed at [2]: encountered uninitialized bytes
mem::transmute(
[
0u8,
--> $DIR/ub-nonnull.rs:34:1
|
LL | const UNINIT: NonZeroU8 = unsafe { MaybeUninit { uninit: () }.init };
- | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type validation failed: encountered uninitialized bytes at .0, but expected initialized plain (non-pointer) bytes
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type validation failed at .0: encountered uninitialized bytes, but expected initialized plain (non-pointer) bytes
|
= note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior.
= note: the raw bytes of the constant (size: 1, align: 1) {
--> $DIR/ub-nonnull.rs:34:1
|
LL | const UNINIT: NonZeroU8 = unsafe { MaybeUninit { uninit: () }.init };
- | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type validation failed: encountered uninitialized bytes at .0, but expected initialized plain (non-pointer) bytes
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type validation failed at .0: encountered uninitialized bytes, but expected initialized plain (non-pointer) bytes
|
= note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior.
= note: the raw bytes of the constant (size: 1, align: 1) {
--> $DIR/ub-ref-ptr.rs:33:1
|
LL | const REF_AS_USIZE_SLICE: &[usize] = &[unsafe { mem::transmute(&0) }];
- | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type validation failed: encountered a pointer at .<deref>, but expected plain (non-pointer) bytes
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type validation failed at .<deref>: encountered a pointer, but expected plain (non-pointer) bytes
|
= note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior.
= note: the raw bytes of the constant (size: 4, align: 4) {
--> $DIR/ub-ref-ptr.rs:36:1
|
LL | const REF_AS_USIZE_BOX_SLICE: Box<[usize]> = unsafe { mem::transmute::<&[usize], _>(&[mem::transmute(&0)]) };
- | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type validation failed: encountered a pointer at .<deref>, but expected plain (non-pointer) bytes
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type validation failed at .<deref>: encountered a pointer, but expected plain (non-pointer) bytes
|
= note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior.
= note: the raw bytes of the constant (size: 4, align: 4) {
--> $DIR/ub-ref-ptr.rs:33:1
|
LL | const REF_AS_USIZE_SLICE: &[usize] = &[unsafe { mem::transmute(&0) }];
- | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type validation failed: encountered a pointer at .<deref>, but expected plain (non-pointer) bytes
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type validation failed at .<deref>: encountered a pointer, but expected plain (non-pointer) bytes
|
= note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior.
= note: the raw bytes of the constant (size: 8, align: 8) {
--> $DIR/ub-ref-ptr.rs:36:1
|
LL | const REF_AS_USIZE_BOX_SLICE: Box<[usize]> = unsafe { mem::transmute::<&[usize], _>(&[mem::transmute(&0)]) };
- | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type validation failed: encountered a pointer at .<deref>, but expected plain (non-pointer) bytes
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type validation failed at .<deref>: encountered a pointer, but expected plain (non-pointer) bytes
|
= note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior.
= note: the raw bytes of the constant (size: 8, align: 8) {
--> $DIR/ub-uninhabit.rs:18:1
|
LL | const BAD_BAD_REF: &Bar = unsafe { mem::transmute(1usize) };
- | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type validation failed: encountered a value of uninhabited type Bar at .<deref>
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type validation failed at .<deref>: encountered a value of uninhabited type Bar
|
= note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior.
= note: the raw bytes of the constant (size: 4, align: 4) {
--> $DIR/ub-uninhabit.rs:21:1
|
LL | const BAD_BAD_ARRAY: [Bar; 1] = unsafe { MaybeUninit { uninit: () }.init };
- | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type validation failed: encountered a value of uninhabited type Bar at [0]
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type validation failed at [0]: encountered a value of uninhabited type Bar
|
= note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior.
= note: the raw bytes of the constant (size: 0, align: 1) {}
--> $DIR/ub-uninhabit.rs:18:1
|
LL | const BAD_BAD_REF: &Bar = unsafe { mem::transmute(1usize) };
- | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type validation failed: encountered a value of uninhabited type Bar at .<deref>
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type validation failed at .<deref>: encountered a value of uninhabited type Bar
|
= note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior.
= note: the raw bytes of the constant (size: 8, align: 8) {
--> $DIR/ub-uninhabit.rs:21:1
|
LL | const BAD_BAD_ARRAY: [Bar; 1] = unsafe { MaybeUninit { uninit: () }.init };
- | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type validation failed: encountered a value of uninhabited type Bar at [0]
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type validation failed at [0]: encountered a value of uninhabited type Bar
|
= note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior.
= note: the raw bytes of the constant (size: 0, align: 1) {}
LL | | let another_var = 13;
LL | | move || { let _ = bad_ref; let _ = another_var; }
LL | | };
- | |__^ type validation failed: encountered a null reference at .<deref>.<dyn-downcast>.<captured-var(bad_ref)>
+ | |__^ type validation failed at .<deref>.<dyn-downcast>.<captured-var(bad_ref)>: encountered a null reference
|
= note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior.
= note: the raw bytes of the constant (size: 8, align: 4) {
LL | | let another_var = 13;
LL | | move || { let _ = bad_ref; let _ = another_var; }
LL | | };
- | |__^ type validation failed: encountered a null reference at .<deref>.<dyn-downcast>.<captured-var(bad_ref)>
+ | |__^ type validation failed at .<deref>.<dyn-downcast>.<captured-var(bad_ref)>: encountered a null reference
|
= note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior.
= note: the raw bytes of the constant (size: 16, align: 8) {
--> $DIR/ub-wide-ptr.rs:40:1
|
LL | const NESTED_STR_MUCH_TOO_LONG: (&str,) = (unsafe { mem::transmute((&42, usize::MAX)) },);
- | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type validation failed: encountered invalid reference metadata: slice is bigger than largest supported object at .0
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type validation failed at .0: encountered invalid reference metadata: slice is bigger than largest supported object
|
= note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior.
= note: the raw bytes of the constant (size: 8, align: 4) {
--> $DIR/ub-wide-ptr.rs:52:1
|
LL | const STR_NO_INIT: &str = unsafe { mem::transmute::<&[_], _>(&[MaybeUninit::<u8> { uninit: () }]) };
- | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type validation failed: encountered uninitialized data in `str` at .<deref>
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type validation failed at .<deref>: encountered uninitialized data in `str`
|
= note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior.
= note: the raw bytes of the constant (size: 8, align: 4) {
--> $DIR/ub-wide-ptr.rs:55:1
|
LL | const MYSTR_NO_INIT: &MyStr = unsafe { mem::transmute::<&[_], _>(&[MaybeUninit::<u8> { uninit: () }]) };
- | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type validation failed: encountered uninitialized data in `str` at .<deref>.0
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type validation failed at .<deref>.0: encountered uninitialized data in `str`
|
= note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior.
= note: the raw bytes of the constant (size: 8, align: 4) {
--> $DIR/ub-wide-ptr.rs:81:1
|
LL | const SLICE_CONTENT_INVALID: &[bool] = &[unsafe { mem::transmute(3u8) }];
- | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type validation failed: encountered 0x03 at .<deref>[0], but expected a boolean
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type validation failed at .<deref>[0]: encountered 0x03, but expected a boolean
|
= note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior.
= note: the raw bytes of the constant (size: 4, align: 4) {
--> $DIR/ub-wide-ptr.rs:87:1
|
LL | const MYSLICE_PREFIX_BAD: &MySliceBool = &MySlice(unsafe { mem::transmute(3u8) }, [false]);
- | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type validation failed: encountered 0x03 at .<deref>.0, but expected a boolean
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type validation failed at .<deref>.0: encountered 0x03, but expected a boolean
|
= note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior.
= note: the raw bytes of the constant (size: 4, align: 4) {
--> $DIR/ub-wide-ptr.rs:90:1
|
LL | const MYSLICE_SUFFIX_BAD: &MySliceBool = &MySlice(true, [unsafe { mem::transmute(3u8) }]);
- | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type validation failed: encountered 0x03 at .<deref>.1[0], but expected a boolean
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type validation failed at .<deref>.1[0]: encountered 0x03, but expected a boolean
|
= note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior.
= note: the raw bytes of the constant (size: 4, align: 4) {
--> $DIR/ub-wide-ptr.rs:105:1
|
LL | const TRAIT_OBJ_SHORT_VTABLE_1: W<&dyn Trait> = unsafe { mem::transmute(W((&92u8, &3u8))) };
- | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type validation failed: encountered too small vtable at .0
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type validation failed at .0: encountered too small vtable
|
= note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior.
= note: the raw bytes of the constant (size: 8, align: 4) {
--> $DIR/ub-wide-ptr.rs:108:1
|
LL | const TRAIT_OBJ_SHORT_VTABLE_2: W<&dyn Trait> = unsafe { mem::transmute(W((&92u8, &3u64))) };
- | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type validation failed: encountered too small vtable at .0
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type validation failed at .0: encountered too small vtable
|
= note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior.
= note: the raw bytes of the constant (size: 8, align: 4) {
--> $DIR/ub-wide-ptr.rs:111:1
|
LL | const TRAIT_OBJ_INT_VTABLE: W<&dyn Trait> = unsafe { mem::transmute(W((&92u8, 4usize))) };
- | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type validation failed: encountered dangling vtable pointer in wide pointer at .0
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type validation failed at .0: encountered dangling vtable pointer in wide pointer
|
= note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior.
= note: the raw bytes of the constant (size: 8, align: 4) {
--> $DIR/ub-wide-ptr.rs:119:1
|
LL | const TRAIT_OBJ_BAD_DROP_FN_NOT_FN_PTR: W<&dyn Trait> = unsafe { mem::transmute(W((&92u8, &[&42u8; 8]))) };
- | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type validation failed: encountered invalid drop function pointer in vtable (not pointing to a function) at .0
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type validation failed at .0: encountered invalid drop function pointer in vtable (not pointing to a function)
|
= note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior.
= note: the raw bytes of the constant (size: 8, align: 4) {
--> $DIR/ub-wide-ptr.rs:123:1
|
LL | const TRAIT_OBJ_CONTENT_INVALID: &dyn Trait = unsafe { mem::transmute::<_, &bool>(&3u8) };
- | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type validation failed: encountered 0x03 at .<deref>.<dyn-downcast>, but expected a boolean
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type validation failed at .<deref>.<dyn-downcast>: encountered 0x03, but expected a boolean
|
= note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior.
= note: the raw bytes of the constant (size: 8, align: 4) {
--> $DIR/ub-wide-ptr.rs:40:1
|
LL | const NESTED_STR_MUCH_TOO_LONG: (&str,) = (unsafe { mem::transmute((&42, usize::MAX)) },);
- | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type validation failed: encountered invalid reference metadata: slice is bigger than largest supported object at .0
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type validation failed at .0: encountered invalid reference metadata: slice is bigger than largest supported object
|
= note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior.
= note: the raw bytes of the constant (size: 16, align: 8) {
--> $DIR/ub-wide-ptr.rs:52:1
|
LL | const STR_NO_INIT: &str = unsafe { mem::transmute::<&[_], _>(&[MaybeUninit::<u8> { uninit: () }]) };
- | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type validation failed: encountered uninitialized data in `str` at .<deref>
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type validation failed at .<deref>: encountered uninitialized data in `str`
|
= note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior.
= note: the raw bytes of the constant (size: 16, align: 8) {
--> $DIR/ub-wide-ptr.rs:55:1
|
LL | const MYSTR_NO_INIT: &MyStr = unsafe { mem::transmute::<&[_], _>(&[MaybeUninit::<u8> { uninit: () }]) };
- | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type validation failed: encountered uninitialized data in `str` at .<deref>.0
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type validation failed at .<deref>.0: encountered uninitialized data in `str`
|
= note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior.
= note: the raw bytes of the constant (size: 16, align: 8) {
--> $DIR/ub-wide-ptr.rs:81:1
|
LL | const SLICE_CONTENT_INVALID: &[bool] = &[unsafe { mem::transmute(3u8) }];
- | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type validation failed: encountered 0x03 at .<deref>[0], but expected a boolean
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type validation failed at .<deref>[0]: encountered 0x03, but expected a boolean
|
= note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior.
= note: the raw bytes of the constant (size: 8, align: 8) {
--> $DIR/ub-wide-ptr.rs:87:1
|
LL | const MYSLICE_PREFIX_BAD: &MySliceBool = &MySlice(unsafe { mem::transmute(3u8) }, [false]);
- | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type validation failed: encountered 0x03 at .<deref>.0, but expected a boolean
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type validation failed at .<deref>.0: encountered 0x03, but expected a boolean
|
= note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior.
= note: the raw bytes of the constant (size: 8, align: 8) {
--> $DIR/ub-wide-ptr.rs:90:1
|
LL | const MYSLICE_SUFFIX_BAD: &MySliceBool = &MySlice(true, [unsafe { mem::transmute(3u8) }]);
- | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type validation failed: encountered 0x03 at .<deref>.1[0], but expected a boolean
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type validation failed at .<deref>.1[0]: encountered 0x03, but expected a boolean
|
= note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior.
= note: the raw bytes of the constant (size: 8, align: 8) {
--> $DIR/ub-wide-ptr.rs:105:1
|
LL | const TRAIT_OBJ_SHORT_VTABLE_1: W<&dyn Trait> = unsafe { mem::transmute(W((&92u8, &3u8))) };
- | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type validation failed: encountered too small vtable at .0
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type validation failed at .0: encountered too small vtable
|
= note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior.
= note: the raw bytes of the constant (size: 16, align: 8) {
--> $DIR/ub-wide-ptr.rs:108:1
|
LL | const TRAIT_OBJ_SHORT_VTABLE_2: W<&dyn Trait> = unsafe { mem::transmute(W((&92u8, &3u64))) };
- | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type validation failed: encountered too small vtable at .0
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type validation failed at .0: encountered too small vtable
|
= note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior.
= note: the raw bytes of the constant (size: 16, align: 8) {
--> $DIR/ub-wide-ptr.rs:111:1
|
LL | const TRAIT_OBJ_INT_VTABLE: W<&dyn Trait> = unsafe { mem::transmute(W((&92u8, 4usize))) };
- | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type validation failed: encountered dangling vtable pointer in wide pointer at .0
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type validation failed at .0: encountered dangling vtable pointer in wide pointer
|
= note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior.
= note: the raw bytes of the constant (size: 16, align: 8) {
--> $DIR/ub-wide-ptr.rs:119:1
|
LL | const TRAIT_OBJ_BAD_DROP_FN_NOT_FN_PTR: W<&dyn Trait> = unsafe { mem::transmute(W((&92u8, &[&42u8; 8]))) };
- | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type validation failed: encountered invalid drop function pointer in vtable (not pointing to a function) at .0
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type validation failed at .0: encountered invalid drop function pointer in vtable (not pointing to a function)
|
= note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior.
= note: the raw bytes of the constant (size: 16, align: 8) {
--> $DIR/ub-wide-ptr.rs:123:1
|
LL | const TRAIT_OBJ_CONTENT_INVALID: &dyn Trait = unsafe { mem::transmute::<_, &bool>(&3u8) };
- | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type validation failed: encountered 0x03 at .<deref>.<dyn-downcast>, but expected a boolean
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type validation failed at .<deref>.<dyn-downcast>: encountered 0x03, but expected a boolean
|
= note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior.
= note: the raw bytes of the constant (size: 16, align: 8) {
LL | | a: 42,
LL | | b: unsafe { UNION.field3 },
LL | | };
- | |__^ type validation failed: encountered uninitialized bytes at .b, but expected initialized plain (non-pointer) bytes
+ | |__^ type validation failed at .b: encountered uninitialized bytes, but expected initialized plain (non-pointer) bytes
|
= note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior.
= note: the raw bytes of the constant (size: 16, align: 8) {
... |
LL | | a: 42,
LL | | };
- | |__^ type validation failed: encountered uninitialized bytes at .b[1]
+ | |__^ type validation failed at .b[1]: encountered uninitialized bytes
|
= note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior.
= note: the raw bytes of the constant (size: 40, align: 8) {
#[unwind(aborts)]
const fn foo() {
- panic!() //~ ERROR any use of this value will cause an error [const_err]
- //~| WARN this was previously accepted by the compiler but is being phased out
+ panic!() //~ ERROR any use of this value will cause an error
}
const _: () = foo();
-error: any use of this value will cause an error
+error[E0080]: any use of this value will cause an error
--> $DIR/unwind-abort.rs:5:5
|
LL | panic!()
| |
| the evaluated program panicked at 'explicit panic', $DIR/unwind-abort.rs:5:5
| inside `foo` at $SRC_DIR/std/src/panic.rs:LL:COL
- | inside `_` at $DIR/unwind-abort.rs:9:15
+ | inside `_` at $DIR/unwind-abort.rs:8:15
...
LL | const _: () = foo();
| --------------------
|
- = note: `#[deny(const_err)]` on by default
- = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
- = note: for more information, see issue #71800 <https://github.com/rust-lang/rust/issues/71800>
= note: this error originates in the macro `$crate::panic::panic_2015` (in Nightly builds, run with -Z macro-backtrace for more info)
error: aborting due to previous error
+For more information about this error, try `rustc --explain E0080`.
--> $DIR/validate_uninhabited_zsts.rs:18:1
|
LL | const BAR: [Empty; 3] = [unsafe { std::mem::transmute(()) }; 3];
- | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type validation failed: encountered a value of uninhabited type Empty at [0]
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type validation failed at [0]: encountered a value of uninhabited type Empty
|
= note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior.
= note: the raw bytes of the constant (size: 0, align: 1) {}
--> $DIR/validate_uninhabited_zsts.rs:18:1
|
LL | const BAR: [Empty; 3] = [unsafe { std::mem::transmute(()) }; 3];
- | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type validation failed: encountered a value of uninhabited type Empty at [0]
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type validation failed at [0]: encountered a value of uninhabited type Empty
|
= note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior.
= note: the raw bytes of the constant (size: 0, align: 1) {}
--- /dev/null
+error[E0764]: mutable references are not allowed in the final value of constants
+ --> $DIR/issue-76510.rs:5:29
+ |
+LL | const S: &'static mut str = &mut " hello ";
+ | ^^^^^^^^^^^^^^
+
+error[E0658]: mutation through a reference is not allowed in constants
+ --> $DIR/issue-76510.rs:5:29
+ |
+LL | const S: &'static mut str = &mut " hello ";
+ | ^^^^^^^^^^^^^^
+ |
+ = note: see issue #57349 <https://github.com/rust-lang/rust/issues/57349> for more information
+ = help: add `#![feature(const_mut_refs)]` to the crate attributes to enable
+
+error[E0596]: cannot borrow data in a `&` reference as mutable
+ --> $DIR/issue-76510.rs:5:29
+ |
+LL | const S: &'static mut str = &mut " hello ";
+ | ^^^^^^^^^^^^^^ cannot borrow as mutable
+
+error[E0080]: it is undefined behavior to use this value
+ --> $DIR/issue-76510.rs:5:1
+ |
+LL | const S: &'static mut str = &mut " hello ";
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type validation failed: encountered mutable reference in a `const`
+ |
+ = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior.
+ = note: the raw bytes of the constant (size: 8, align: 4) {
+ ╾─alloc2──╼ 07 00 00 00 │ ╾──╼....
+ }
+
+error: aborting due to 4 previous errors
+
+Some errors have detailed explanations: E0080, E0596, E0658, E0764.
+For more information about an error, try `rustc --explain E0080`.
--- /dev/null
+error[E0764]: mutable references are not allowed in the final value of constants
+ --> $DIR/issue-76510.rs:5:29
+ |
+LL | const S: &'static mut str = &mut " hello ";
+ | ^^^^^^^^^^^^^^
+
+error[E0658]: mutation through a reference is not allowed in constants
+ --> $DIR/issue-76510.rs:5:29
+ |
+LL | const S: &'static mut str = &mut " hello ";
+ | ^^^^^^^^^^^^^^
+ |
+ = note: see issue #57349 <https://github.com/rust-lang/rust/issues/57349> for more information
+ = help: add `#![feature(const_mut_refs)]` to the crate attributes to enable
+
+error[E0596]: cannot borrow data in a `&` reference as mutable
+ --> $DIR/issue-76510.rs:5:29
+ |
+LL | const S: &'static mut str = &mut " hello ";
+ | ^^^^^^^^^^^^^^ cannot borrow as mutable
+
+error[E0080]: it is undefined behavior to use this value
+ --> $DIR/issue-76510.rs:5:1
+ |
+LL | const S: &'static mut str = &mut " hello ";
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type validation failed: encountered mutable reference in a `const`
+ |
+ = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior.
+ = note: the raw bytes of the constant (size: 16, align: 8) {
+ ╾───────alloc2────────╼ 07 00 00 00 00 00 00 00 │ ╾──────╼........
+ }
+
+error: aborting due to 4 previous errors
+
+Some errors have detailed explanations: E0080, E0596, E0658, E0764.
+For more information about an error, try `rustc --explain E0080`.
--- /dev/null
+// stderr-per-bitwidth
+
+use std::mem::{transmute, ManuallyDrop};
+
+const S: &'static mut str = &mut " hello ";
+//~^ ERROR: mutable references are not allowed in the final value of constants
+//~| ERROR: mutation through a reference is not allowed in constants
+//~| ERROR: cannot borrow data in a `&` reference as mutable
+//~| ERROR: it is undefined behavior to use this value
+
+const fn trigger() -> [(); unsafe {
+ let s = transmute::<(*const u8, usize), &ManuallyDrop<str>>((S.as_ptr(), 3));
+ 0
+ }] {
+ [(); 0]
+}
+
+fn main() {}
--- /dev/null
+// Check that evaluation of needs_drop<T> fails when T is not monomorphic.
+#![feature(const_generics)]
+#![allow(const_evaluatable_unchecked)]
+#![allow(incomplete_features)]
+
+struct Bool<const B: bool> {}
+impl Bool<true> {
+ fn assert() {}
+}
+fn f<T>() {
+ Bool::<{ std::mem::needs_drop::<T>() }>::assert();
+ //~^ ERROR no function or associated item named `assert` found
+ //~| ERROR constant expression depends on a generic parameter
+}
+fn main() {
+ f::<u32>();
+}
--- /dev/null
+error[E0599]: no function or associated item named `assert` found for struct `Bool<{ std::mem::needs_drop::<T>() }>` in the current scope
+ --> $DIR/const-needs_drop-monomorphic.rs:11:46
+ |
+LL | struct Bool<const B: bool> {}
+ | -------------------------- function or associated item `assert` not found for this
+...
+LL | Bool::<{ std::mem::needs_drop::<T>() }>::assert();
+ | ^^^^^^ function or associated item cannot be called on `Bool<{ std::mem::needs_drop::<T>() }>` due to unsatisfied trait bounds
+
+error: constant expression depends on a generic parameter
+ --> $DIR/const-needs_drop-monomorphic.rs:11:5
+ |
+LL | Bool::<{ std::mem::needs_drop::<T>() }>::assert();
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+ |
+ = note: this may fail depending on what value the parameter takes
+
+error: aborting due to 2 previous errors
+
+For more information about this error, try `rustc --explain E0599`.
-error: any use of this value will cause an error
+error[E0080]: any use of this value will cause an error
--> $SRC_DIR/core/src/option.rs:LL:COL
|
LL | None => panic!("called `Option::unwrap()` on a `None` value"),
LL | const BAR: i32 = Option::<i32>::None.unwrap();
| ----------------------------------------------
|
- = note: `#[deny(const_err)]` on by default
- = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
- = note: for more information, see issue #71800 <https://github.com/rust-lang/rust/issues/71800>
= note: this error originates in the macro `$crate::panic::panic_2015` (in Nightly builds, run with -Z macro-backtrace for more info)
error: aborting due to previous error
+For more information about this error, try `rustc --explain E0080`.
-error: any use of this value will cause an error
+error[E0080]: any use of this value will cause an error
--> $DIR/assert.rs:10:15
|
LL | const _: () = assert!(false);
| |
| the evaluated program panicked at 'assertion failed: false', $DIR/assert.rs:10:15
|
- = note: `#[deny(const_err)]` on by default
- = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
- = note: for more information, see issue #71800 <https://github.com/rust-lang/rust/issues/71800>
= note: this error originates in the macro `assert` (in Nightly builds, run with -Z macro-backtrace for more info)
error: aborting due to previous error
+For more information about this error, try `rustc --explain E0080`.
const _: () = assert!(false);
//[stock]~^ ERROR panicking in constants is unstable
//[const_panic]~^^ ERROR any use of this value will cause an error
-//[const_panic]~| WARN this was previously accepted by the compiler but is being phased out
fn main() {}
+++ /dev/null
-// ignore-tidy-linelength
-#![feature(const_mut_refs, const_intrinsic_copy, const_ptr_offset)]
-use std::{ptr, mem};
-
-const COPY_ZERO: () = unsafe {
- // Since we are not copying anything, this should be allowed.
- let src = ();
- let mut dst = ();
- ptr::copy_nonoverlapping(&src as *const _ as *const i32, &mut dst as *mut _ as *mut i32, 0);
-};
-
-const COPY_OOB_1: () = unsafe {
- let mut x = 0i32;
- let dangle = (&mut x as *mut i32).wrapping_add(10);
- // Even if the first ptr is an int ptr and this is a ZST copy, we should detect dangling 2nd ptrs.
- ptr::copy_nonoverlapping(0x100 as *const i32, dangle, 0); //~ ERROR any use of this value will cause an error
- //~| memory access failed: pointer must be in-bounds
- //~| previously accepted
-};
-const COPY_OOB_2: () = unsafe {
- let x = 0i32;
- let dangle = (&x as *const i32).wrapping_add(10);
- // Even if the second ptr is an int ptr and this is a ZST copy, we should detect dangling 1st ptrs.
- ptr::copy_nonoverlapping(dangle, 0x100 as *mut i32, 0); //~ ERROR any use of this value will cause an error
- //~| memory access failed: pointer must be in-bounds
- //~| previously accepted
-};
-
-const COPY_SIZE_OVERFLOW: () = unsafe {
- let x = 0;
- let mut y = 0;
- ptr::copy(&x, &mut y, 1usize << (mem::size_of::<usize>() * 8 - 1)); //~ ERROR any use of this value will cause an error
- //~| overflow computing total size of `copy`
- //~| previously accepted
-};
-const COPY_NONOVERLAPPING_SIZE_OVERFLOW: () = unsafe {
- let x = 0;
- let mut y = 0;
- ptr::copy_nonoverlapping(&x, &mut y, 1usize << (mem::size_of::<usize>() * 8 - 1)); //~ ERROR any use of this value will cause an error
- //~| overflow computing total size of `copy_nonoverlapping`
- //~| previously accepted
-};
-
-fn main() {
-}
+++ /dev/null
-error: any use of this value will cause an error
- --> $DIR/copy-intrinsic.rs:16:5
- |
-LL | / const COPY_OOB_1: () = unsafe {
-LL | | let mut x = 0i32;
-LL | | let dangle = (&mut x as *mut i32).wrapping_add(10);
-LL | | // Even if the first ptr is an int ptr and this is a ZST copy, we should detect dangling 2nd ptrs.
-LL | | ptr::copy_nonoverlapping(0x100 as *const i32, dangle, 0);
- | | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ memory access failed: pointer must be in-bounds at offset 40, but is outside bounds of alloc4 which has size 4
-LL | |
-LL | |
-LL | | };
- | |__-
- |
- = note: `#[deny(const_err)]` on by default
- = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
- = note: for more information, see issue #71800 <https://github.com/rust-lang/rust/issues/71800>
-
-error: any use of this value will cause an error
- --> $DIR/copy-intrinsic.rs:24:5
- |
-LL | / const COPY_OOB_2: () = unsafe {
-LL | | let x = 0i32;
-LL | | let dangle = (&x as *const i32).wrapping_add(10);
-LL | | // Even if the second ptr is an int ptr and this is a ZST copy, we should detect dangling 1st ptrs.
-LL | | ptr::copy_nonoverlapping(dangle, 0x100 as *mut i32, 0);
- | | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ memory access failed: pointer must be in-bounds at offset 40, but is outside bounds of alloc6 which has size 4
-LL | |
-LL | |
-LL | | };
- | |__-
- |
- = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
- = note: for more information, see issue #71800 <https://github.com/rust-lang/rust/issues/71800>
-
-error: any use of this value will cause an error
- --> $DIR/copy-intrinsic.rs:32:5
- |
-LL | / const COPY_SIZE_OVERFLOW: () = unsafe {
-LL | | let x = 0;
-LL | | let mut y = 0;
-LL | | ptr::copy(&x, &mut y, 1usize << (mem::size_of::<usize>() * 8 - 1));
- | | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ overflow computing total size of `copy`
-LL | |
-LL | |
-LL | | };
- | |__-
- |
- = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
- = note: for more information, see issue #71800 <https://github.com/rust-lang/rust/issues/71800>
-
-error: any use of this value will cause an error
- --> $DIR/copy-intrinsic.rs:39:5
- |
-LL | / const COPY_NONOVERLAPPING_SIZE_OVERFLOW: () = unsafe {
-LL | | let x = 0;
-LL | | let mut y = 0;
-LL | | ptr::copy_nonoverlapping(&x, &mut y, 1usize << (mem::size_of::<usize>() * 8 - 1));
- | | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ overflow computing total size of `copy_nonoverlapping`
-LL | |
-LL | |
-LL | | };
- | |__-
- |
- = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
- = note: for more information, see issue #71800 <https://github.com/rust-lang/rust/issues/71800>
-
-error: aborting due to 4 previous errors
-
--> $DIR/issue-79690.rs:30:1
|
LL | const G: Fat = unsafe { Transmute { t: FOO }.u };
- | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type validation failed: encountered (potentially part of) a pointer at .1.<deref>.size.foo, but expected plain (non-pointer) bytes
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type validation failed at .1.<deref>.size.foo: encountered (potentially part of) a pointer, but expected plain (non-pointer) bytes
|
= note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior.
= note: the raw bytes of the constant (size: 16, align: 8) {
--> $DIR/issue-83182.rs:5:1
|
LL | const MYSTR_NO_INIT: &MyStr = unsafe { mem::transmute::<&[_], _>(&[&()]) };
- | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type validation failed: encountered a pointer in `str` at .<deref>.0
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type validation failed at .<deref>.0: encountered a pointer in `str`
|
= note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior.
= note: the raw bytes of the constant (size: 8, align: 4) {
--> $DIR/issue-83182.rs:5:1
|
LL | const MYSTR_NO_INIT: &MyStr = unsafe { mem::transmute::<&[_], _>(&[&()]) };
- | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type validation failed: encountered a pointer in `str` at .<deref>.0
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type validation failed at .<deref>.0: encountered a pointer in `str`
|
= note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior.
= note: the raw bytes of the constant (size: 16, align: 8) {
struct MyStr(str);
const MYSTR_NO_INIT: &MyStr = unsafe { mem::transmute::<&[_], _>(&[&()]) };
//~^ ERROR: it is undefined behavior to use this value
-//~| type validation failed: encountered a pointer in `str`
+//~| type validation failed at .<deref>.0: encountered a pointer in `str`
fn main() {}
LL | / const MUH: Meh = Meh {
LL | | x: &UnsafeCell::new(42),
LL | | };
- | |__^ type validation failed: encountered `UnsafeCell` in a `const` at .x.<deref>
+ | |__^ type validation failed at .x.<deref>: encountered `UnsafeCell` in a `const`
|
= note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior.
= note: the raw bytes of the constant (size: 4, align: 4) {
--> $DIR/mutable_references_err.rs:27:1
|
LL | const SNEAKY: &dyn Sync = &Synced { x: UnsafeCell::new(42) };
- | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type validation failed: encountered `UnsafeCell` in a `const` at .<deref>.<dyn-downcast>.x
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type validation failed at .<deref>.<dyn-downcast>.x: encountered `UnsafeCell` in a `const`
|
= note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior.
= note: the raw bytes of the constant (size: 8, align: 4) {
LL | / const MUH: Meh = Meh {
LL | | x: &UnsafeCell::new(42),
LL | | };
- | |__^ type validation failed: encountered `UnsafeCell` in a `const` at .x.<deref>
+ | |__^ type validation failed at .x.<deref>: encountered `UnsafeCell` in a `const`
|
= note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior.
= note: the raw bytes of the constant (size: 8, align: 8) {
--> $DIR/mutable_references_err.rs:27:1
|
LL | const SNEAKY: &dyn Sync = &Synced { x: UnsafeCell::new(42) };
- | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type validation failed: encountered `UnsafeCell` in a `const` at .<deref>.<dyn-downcast>.x
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type validation failed at .<deref>.<dyn-downcast>.x: encountered `UnsafeCell` in a `const`
|
= note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior.
= note: the raw bytes of the constant (size: 16, align: 8) {
--> $DIR/alloc.rs:8:1
|
LL | const LAYOUT_INVALID: Layout = unsafe { Layout::from_size_align_unchecked(0x1000, 0x00) };
- | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type validation failed: encountered 0 at .align_, but expected something greater or equal to 1
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type validation failed at .align_: encountered 0, but expected something greater or equal to 1
|
= note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior.
= note: the raw bytes of the constant (size: 8, align: 4) {
--> $DIR/alloc.rs:8:1
|
LL | const LAYOUT_INVALID: Layout = unsafe { Layout::from_size_align_unchecked(0x1000, 0x00) };
- | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type validation failed: encountered 0 at .align_, but expected something greater or equal to 1
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type validation failed at .align_: encountered 0, but expected something greater or equal to 1
|
= note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior.
= note: the raw bytes of the constant (size: 16, align: 8) {
--> $DIR/validate_never_arrays.rs:4:1
|
LL | const _: &[!; 1] = unsafe { &*(1_usize as *const [!; 1]) };
- | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type validation failed: encountered a value of the never type `!` at .<deref>[0]
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type validation failed at .<deref>[0]: encountered a value of the never type `!`
|
= note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior.
= note: the raw bytes of the constant (size: 4, align: 4) {
--> $DIR/validate_never_arrays.rs:7:1
|
LL | const _: &[!] = unsafe { &*(1_usize as *const [!; 1]) };
- | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type validation failed: encountered a value of the never type `!` at .<deref>[0]
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type validation failed at .<deref>[0]: encountered a value of the never type `!`
|
= note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior.
= note: the raw bytes of the constant (size: 8, align: 4) {
--> $DIR/validate_never_arrays.rs:8:1
|
LL | const _: &[!] = unsafe { &*(1_usize as *const [!; 42]) };
- | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type validation failed: encountered a value of the never type `!` at .<deref>[0]
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type validation failed at .<deref>[0]: encountered a value of the never type `!`
|
= note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior.
= note: the raw bytes of the constant (size: 8, align: 4) {
--> $DIR/validate_never_arrays.rs:4:1
|
LL | const _: &[!; 1] = unsafe { &*(1_usize as *const [!; 1]) };
- | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type validation failed: encountered a value of the never type `!` at .<deref>[0]
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type validation failed at .<deref>[0]: encountered a value of the never type `!`
|
= note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior.
= note: the raw bytes of the constant (size: 8, align: 8) {
--> $DIR/validate_never_arrays.rs:7:1
|
LL | const _: &[!] = unsafe { &*(1_usize as *const [!; 1]) };
- | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type validation failed: encountered a value of the never type `!` at .<deref>[0]
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type validation failed at .<deref>[0]: encountered a value of the never type `!`
|
= note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior.
= note: the raw bytes of the constant (size: 16, align: 8) {
--> $DIR/validate_never_arrays.rs:8:1
|
LL | const _: &[!] = unsafe { &*(1_usize as *const [!; 42]) };
- | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type validation failed: encountered a value of the never type `!` at .<deref>[0]
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type validation failed at .<deref>[0]: encountered a value of the never type `!`
|
= note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior.
= note: the raw bytes of the constant (size: 16, align: 8) {
LL | #[deny("literal")]
| ^^^^^^^^^ bad attribute argument
-error[E0452]: malformed lint attribute input
- --> $DIR/deduplicate-diagnostics.rs:8:8
- |
-LL | #[deny("literal")]
- | ^^^^^^^^^ bad attribute argument
-
-error: aborting due to 5 previous errors
+error: aborting due to 4 previous errors
For more information about this error, try `rustc --explain E0452`.
#[deny("literal")] //~ ERROR malformed lint attribute input
//[duplicate]~| ERROR malformed lint attribute input
- //[duplicate]~| ERROR malformed lint attribute input
fn main() {}
#![allow(dead_code)]
#![allow(unused_variables)]
-#[rustc_dirty(hir_owner)] //~ ERROR attribute requires -Z query-dep-graph
+#[rustc_clean(hir_owner)] //~ ERROR attribute requires -Z query-dep-graph
fn main() {}
#[rustc_if_this_changed(hir_owner)] //~ ERROR attribute requires -Z query-dep-graph
error: attribute requires -Z query-dep-graph to be enabled
--> $DIR/dep-graph-check-attr.rs:8:1
|
-LL | #[rustc_dirty(hir_owner)]
+LL | #[rustc_clean(hir_owner)]
| ^^^^^^^^^^^^^^^^^^^^^^^^^
error: attribute requires -Z query-dep-graph to be enabled
// the patterns are all fine:
(..) = x;
}
+
+ #[derive(Debug)]
+ #[deprecated(note = "Use something else instead")]
+ enum DeprecatedDebugEnum {
+ Variant1 { value: Option<String> },
+ }
+
+ #[allow(deprecated)]
+ impl DeprecatedDebugEnum {
+ fn new() -> Self {
+ DeprecatedDebugEnum::Variant1 { value: None }
+ }
+ }
+
+ #[allow(deprecated)]
+ pub fn allow_dep() {
+ let _ = DeprecatedDebugEnum::new();
+ }
}
fn main() {}
struct Foo<'a>(&'a str);
struct Buzz<'a, 'b>(&'a str, &'b str);
+struct Qux<'a, T>(&'a T);
+struct Quux<T>(T);
enum Bar {
A,
foo2: Foo<'a, 'b, 'c>,
//~^ ERROR this struct takes 1 lifetime argument
//~| HELP remove these lifetime arguments
+
+ qux1: Qux<'a, 'b, i32>,
+ //~^ ERROR this struct takes 1 lifetime argument
+ //~| HELP remove this lifetime argument
+
+ qux2: Qux<'a, i32, 'b>,
+ //~^ ERROR this struct takes 1 lifetime argument
+ //~| HELP remove this lifetime argument
+
+ qux3: Qux<'a, 'b, 'c, i32>,
+ //~^ ERROR this struct takes 1 lifetime argument
+ //~| HELP remove these lifetime arguments
+
+ qux4: Qux<'a, i32, 'b, 'c>,
+ //~^ ERROR this struct takes 1 lifetime argument
+ //~| HELP remove these lifetime arguments
+
+ qux5: Qux<'a, 'b, i32, 'c>,
+ //~^ ERROR this struct takes 1 lifetime argument
+ //~| HELP remove this lifetime argument
+
+ quux: Quux<'a, i32, 'b>,
+ //~^ ERROR this struct takes 0 lifetime arguments
+ //~| HELP remove this lifetime argument
}
fn main() {}
error[E0107]: this struct takes 2 lifetime arguments but 1 lifetime argument was supplied
- --> $DIR/E0107.rs:11:11
+ --> $DIR/E0107.rs:13:11
|
LL | buzz: Buzz<'a>,
| ^^^^ -- supplied 1 lifetime argument
| ^^^^
error[E0107]: this enum takes 0 lifetime arguments but 1 lifetime argument was supplied
- --> $DIR/E0107.rs:15:10
+ --> $DIR/E0107.rs:17:10
|
LL | bar: Bar<'a>,
| ^^^---- help: remove these generics
| expected 0 lifetime arguments
|
note: enum defined here, with 0 lifetime parameters
- --> $DIR/E0107.rs:4:6
+ --> $DIR/E0107.rs:6:6
|
LL | enum Bar {
| ^^^
error[E0107]: this struct takes 1 lifetime argument but 3 lifetime arguments were supplied
- --> $DIR/E0107.rs:19:11
+ --> $DIR/E0107.rs:21:11
|
LL | foo2: Foo<'a, 'b, 'c>,
| ^^^ ------ help: remove these lifetime arguments
LL | struct Foo<'a>(&'a str);
| ^^^ --
-error: aborting due to 3 previous errors
+error[E0107]: this struct takes 1 lifetime argument but 2 lifetime arguments were supplied
+ --> $DIR/E0107.rs:25:11
+ |
+LL | qux1: Qux<'a, 'b, i32>,
+ | ^^^ -- help: remove this lifetime argument
+ | |
+ | expected 1 lifetime argument
+ |
+note: struct defined here, with 1 lifetime parameter: `'a`
+ --> $DIR/E0107.rs:3:8
+ |
+LL | struct Qux<'a, T>(&'a T);
+ | ^^^ --
+
+error[E0107]: this struct takes 1 lifetime argument but 2 lifetime arguments were supplied
+ --> $DIR/E0107.rs:29:11
+ |
+LL | qux2: Qux<'a, i32, 'b>,
+ | ^^^ -- help: remove this lifetime argument
+ | |
+ | expected 1 lifetime argument
+ |
+note: struct defined here, with 1 lifetime parameter: `'a`
+ --> $DIR/E0107.rs:3:8
+ |
+LL | struct Qux<'a, T>(&'a T);
+ | ^^^ --
+
+error[E0107]: this struct takes 1 lifetime argument but 3 lifetime arguments were supplied
+ --> $DIR/E0107.rs:33:11
+ |
+LL | qux3: Qux<'a, 'b, 'c, i32>,
+ | ^^^ ------ help: remove these lifetime arguments
+ | |
+ | expected 1 lifetime argument
+ |
+note: struct defined here, with 1 lifetime parameter: `'a`
+ --> $DIR/E0107.rs:3:8
+ |
+LL | struct Qux<'a, T>(&'a T);
+ | ^^^ --
+
+error[E0107]: this struct takes 1 lifetime argument but 3 lifetime arguments were supplied
+ --> $DIR/E0107.rs:37:11
+ |
+LL | qux4: Qux<'a, i32, 'b, 'c>,
+ | ^^^ ------ help: remove these lifetime arguments
+ | |
+ | expected 1 lifetime argument
+ |
+note: struct defined here, with 1 lifetime parameter: `'a`
+ --> $DIR/E0107.rs:3:8
+ |
+LL | struct Qux<'a, T>(&'a T);
+ | ^^^ --
+
+error[E0107]: this struct takes 1 lifetime argument but 3 lifetime arguments were supplied
+ --> $DIR/E0107.rs:41:11
+ |
+LL | qux5: Qux<'a, 'b, i32, 'c>,
+ | ^^^ -- help: remove this lifetime argument
+ | |
+ | expected 1 lifetime argument
+ |
+note: struct defined here, with 1 lifetime parameter: `'a`
+ --> $DIR/E0107.rs:3:8
+ |
+LL | struct Qux<'a, T>(&'a T);
+ | ^^^ --
+
+error[E0107]: this struct takes 0 lifetime arguments but 2 lifetime arguments were supplied
+ --> $DIR/E0107.rs:45:11
+ |
+LL | quux: Quux<'a, i32, 'b>,
+ | ^^^^ -- help: remove this lifetime argument
+ | |
+ | expected 0 lifetime arguments
+ |
+note: struct defined here, with 0 lifetime parameters
+ --> $DIR/E0107.rs:4:8
+ |
+LL | struct Quux<T>(T);
+ | ^^^^
+
+error: aborting due to 9 previous errors
For more information about this error, try `rustc --explain E0107`.
| ^
| |
| not allowed in type signatures
- | help: replace `_` with the correct type: `&str`
+ | help: replace with the correct type: `&str`
error: aborting due to 2 previous errors
//~| ERROR E0452
//~| ERROR E0452
//~| ERROR E0452
- //~| ERROR E0452
- //~| ERROR E0452
fn main() {
}
LL | #![allow(foo = "")]
| ^^^^^^^^ bad attribute argument
-error[E0452]: malformed lint attribute input
- --> $DIR/E0452.rs:1:10
- |
-LL | #![allow(foo = "")]
- | ^^^^^^^^ bad attribute argument
-
-error[E0452]: malformed lint attribute input
- --> $DIR/E0452.rs:1:10
- |
-LL | #![allow(foo = "")]
- | ^^^^^^^^ bad attribute argument
-
-error: aborting due to 6 previous errors
+error: aborting due to 4 previous errors
For more information about this error, try `rustc --explain E0452`.
#[allow(non_snake_case)]
//~^ ERROR allow(non_snake_case) incompatible
//~| ERROR allow(non_snake_case) incompatible
-//~| ERROR allow(non_snake_case) incompatible
fn main() {
}
LL | #[allow(non_snake_case)]
| ^^^^^^^^^^^^^^ overruled by previous forbid
-error[E0453]: allow(non_snake_case) incompatible with previous forbid
- --> $DIR/E0453.rs:3:9
- |
-LL | #![forbid(non_snake_case)]
- | -------------- `forbid` level set here
-LL |
-LL | #[allow(non_snake_case)]
- | ^^^^^^^^^^^^^^ overruled by previous forbid
-
-error: aborting due to 3 previous errors
+error: aborting due to 2 previous errors
For more information about this error, try `rustc --explain E0453`.
|
= note: requested on the command line with `-D bogus`
-error[E0602]: unknown lint: `bogus`
- |
- = note: requested on the command line with `-D bogus`
-
-error: aborting due to 3 previous errors
+error: aborting due to 2 previous errors
For more information about this error, try `rustc --explain E0602`.
--> $DIR/E0605.rs:6:5
|
LL | v as &u8;
- | ^^^^^^^^ an `as` expression can only be used to convert between primitive types or to coerce to a specific trait object
+ | ^^^^^^^^ invalid cast
+ |
+help: consider borrowing the value
+ |
+LL | &*v as &u8;
+ | ^^
error: aborting due to 2 previous errors
+++ /dev/null
-// normalize-stderr-test: "not-a-file.md:.*\(" -> "not-a-file.md: $$FILE_NOT_FOUND_MSG ("
-
-#![feature(external_doc)]
-
-#[doc(include = "not-a-file.md")]
-pub struct SomeStruct; //~^ ERROR couldn't read
-
-#[doc(include = "auxiliary/invalid-utf8.txt")]
-pub struct InvalidUtf8; //~^ ERROR wasn't a utf-8 file
-
-#[doc(include)]
-pub struct MissingPath; //~^ ERROR expected path
- //~| HELP provide a file path with `=`
- //~| SUGGESTION include = "<path>"
-
-#[doc(include("../README.md"))]
-pub struct InvalidPathSyntax; //~^ ERROR expected path
- //~| HELP provide a file path with `=`
- //~| SUGGESTION include = "../README.md"
-
-#[doc(include = 123)]
-pub struct InvalidPathType; //~^ ERROR expected path
- //~| HELP provide a file path with `=`
- //~| SUGGESTION include = "<path>"
-
-#[doc(include(123))]
-pub struct InvalidPathSyntaxAndType; //~^ ERROR expected path
- //~| HELP provide a file path with `=`
- //~| SUGGESTION include = "<path>"
-
-fn main() {}
+++ /dev/null
-error: couldn't read $DIR/not-a-file.md: $FILE_NOT_FOUND_MSG (os error 2)
- --> $DIR/external-doc-error.rs:5:17
- |
-LL | #[doc(include = "not-a-file.md")]
- | ^^^^^^^^^^^^^^^ couldn't read file
-
-error: $DIR/auxiliary/invalid-utf8.txt wasn't a utf-8 file
- --> $DIR/external-doc-error.rs:8:17
- |
-LL | #[doc(include = "auxiliary/invalid-utf8.txt")]
- | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ contains invalid utf-8
-
-error: expected path to external documentation
- --> $DIR/external-doc-error.rs:11:7
- |
-LL | #[doc(include)]
- | ^^^^^^^ help: provide a file path with `=`: `include = "<path>"`
-
-error: expected path to external documentation
- --> $DIR/external-doc-error.rs:16:7
- |
-LL | #[doc(include("../README.md"))]
- | ^^^^^^^^^^^^^^^^^^^^^^^ help: provide a file path with `=`: `include = "../README.md"`
-
-error: expected path to external documentation
- --> $DIR/external-doc-error.rs:21:7
- |
-LL | #[doc(include = 123)]
- | ^^^^^^^^^^^^^ help: provide a file path with `=`: `include = "<path>"`
-
-error: expected path to external documentation
- --> $DIR/external-doc-error.rs:26:7
- |
-LL | #[doc(include(123))]
- | ^^^^^^^^^^^^ help: provide a file path with `=`: `include = "<path>"`
-
-error: aborting due to 6 previous errors
-
+++ /dev/null
-#[doc(include="asdf.md")] //~ ERROR: `#[doc(include)]` is experimental
- //~| ERROR: `#[doc(include)]` is experimental
-fn main() {}
+++ /dev/null
-error[E0658]: `#[doc(include)]` is experimental
- --> $DIR/feature-gate-external_doc.rs:1:1
- |
-LL | #[doc(include="asdf.md")]
- | ^^^^^^^^^^^^^^^^^^^^^^^^^
- |
- = note: see issue #44732 <https://github.com/rust-lang/rust/issues/44732> for more information
- = help: add `#![feature(external_doc)]` to the crate attributes to enable
-
-error[E0658]: `#[doc(include)]` is experimental
- --> $DIR/feature-gate-external_doc.rs:1:1
- |
-LL | #[doc(include="asdf.md")]
- | ^^^^^^^^^^^^^^^^^^^^^^^^^
- |
- = note: see issue #44732 <https://github.com/rust-lang/rust/issues/44732> for more information
- = help: add `#![feature(external_doc)]` to the crate attributes to enable
-
-error: aborting due to 2 previous errors
-
-For more information about this error, try `rustc --explain E0658`.
#![warn(nonstandard_style, reason = "the standard should be respected")]
//~^ ERROR lint reasons are experimental
//~| ERROR lint reasons are experimental
-//~| ERROR lint reasons are experimental
fn main() {}
= note: see issue #54503 <https://github.com/rust-lang/rust/issues/54503> for more information
= help: add `#![feature(lint_reasons)]` to the crate attributes to enable
-error[E0658]: lint reasons are experimental
- --> $DIR/feature-gate-lint-reasons.rs:1:28
- |
-LL | #![warn(nonstandard_style, reason = "the standard should be respected")]
- | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
- |
- = note: see issue #54503 <https://github.com/rust-lang/rust/issues/54503> for more information
- = help: add `#![feature(lint_reasons)]` to the crate attributes to enable
-
-error: aborting due to 3 previous errors
+error: aborting due to 2 previous errors
For more information about this error, try `rustc --explain E0658`.
+++ /dev/null
-trait Trait<'a, 'b> {}
-impl<T> Trait<'_, '_> for T {}
-
-fn foo<'a, 'b>(x: &'a u32, y: &'b u32) -> impl Trait<'a, 'b> {
- //~^ ERROR ambiguous lifetime bound
- //~| ERROR ambiguous lifetime bound
- (x, y)
-}
-
-fn main() {}
+++ /dev/null
-error: ambiguous lifetime bound in `impl Trait`
- --> $DIR/feature-gate-member-constraints.rs:4:43
- |
-LL | fn foo<'a, 'b>(x: &'a u32, y: &'b u32) -> impl Trait<'a, 'b> {
- | ^^^^^^^^^^^^^^^^^^ neither `'a` nor `'b` outlives the other
- |
- = help: add #![feature(member_constraints)] to the crate attributes to enable
-
-error: ambiguous lifetime bound in `impl Trait`
- --> $DIR/feature-gate-member-constraints.rs:4:43
- |
-LL | fn foo<'a, 'b>(x: &'a u32, y: &'b u32) -> impl Trait<'a, 'b> {
- | ^^^^^^^^^^^^^^^^^^ the elided lifetimes here do not outlive one another
- |
- = help: add #![feature(member_constraints)] to the crate attributes to enable
-
-error: aborting due to 2 previous errors
-
--- /dev/null
+fn main() {
+ // destructure through a qualified path
+ let <Foo as A>::Assoc { br } = StructStruct { br: 2 };
+ //~^ ERROR usage of qualified paths in this context is experimental
+ let _ = <Foo as A>::Assoc { br: 2 };
+ //~^ ERROR usage of qualified paths in this context is experimental
+ let <E>::V(..) = E::V(0);
+ //~^ ERROR usage of qualified paths in this context is experimental
+}
+
+struct StructStruct {
+ br: i8,
+}
+
+struct Foo;
+
+trait A {
+ type Assoc;
+}
+
+impl A for Foo {
+ type Assoc = StructStruct;
+}
+
+enum E {
+ V(u8)
+}
--- /dev/null
+error[E0658]: usage of qualified paths in this context is experimental
+ --> $DIR/feature-gate-more-qualified-paths.rs:3:9
+ |
+LL | let <Foo as A>::Assoc { br } = StructStruct { br: 2 };
+ | ^^^^^^^^^^^^^^^^^
+ |
+ = note: see issue #80080 <https://github.com/rust-lang/rust/issues/80080> for more information
+ = help: add `#![feature(more_qualified_paths)]` to the crate attributes to enable
+
+error[E0658]: usage of qualified paths in this context is experimental
+ --> $DIR/feature-gate-more-qualified-paths.rs:5:13
+ |
+LL | let _ = <Foo as A>::Assoc { br: 2 };
+ | ^^^^^^^^^^^^^^^^^
+ |
+ = note: see issue #80080 <https://github.com/rust-lang/rust/issues/80080> for more information
+ = help: add `#![feature(more_qualified_paths)]` to the crate attributes to enable
+
+error[E0658]: usage of qualified paths in this context is experimental
+ --> $DIR/feature-gate-more-qualified-paths.rs:7:9
+ |
+LL | let <E>::V(..) = E::V(0);
+ | ^^^^^^
+ |
+ = note: see issue #80080 <https://github.com/rust-lang/rust/issues/80080> for more information
+ = help: add `#![feature(more_qualified_paths)]` to the crate attributes to enable
+
+error: aborting due to 3 previous errors
+
+For more information about this error, try `rustc --explain E0658`.
--- /dev/null
+#[link(name = "foo")]
+extern "C" {
+ #[link_ordinal(42)]
+ //~^ ERROR: the `#[link_ordinal]` attribute is an experimental feature
+ fn foo();
+}
+
+fn main() {}
--- /dev/null
+error[E0658]: the `#[link_ordinal]` attribute is an experimental feature
+ --> $DIR/feature-gate-raw-dylib-2.rs:3:5
+ |
+LL | #[link_ordinal(42)]
+ | ^^^^^^^^^^^^^^^^^^^
+ |
+ = note: see issue #58713 <https://github.com/rust-lang/rust/issues/58713> for more information
+ = help: add `#![feature(raw_dylib)]` to the crate attributes to enable
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0658`.
--- /dev/null
+// gate-test-raw_dylib
+// only-windows-gnu
+#[link(name = "foo", kind = "raw-dylib")]
+//~^ ERROR: kind="raw-dylib" is unstable
+//~| WARNING: `#[link(...)]` with `kind = "raw-dylib"` not supported on windows-gnu
+extern "C" {}
+
+fn main() {}
--- /dev/null
+warning: `#[link(...)]` with `kind = "raw-dylib"` not supported on windows-gnu
+ --> $DIR/feature-gate-raw-dylib-windows-gnu.rs:3:1
+ |
+LL | #[link(name = "foo", kind = "raw-dylib")]
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+error[E0658]: kind="raw-dylib" is unstable
+ --> $DIR/feature-gate-raw-dylib-windows-gnu.rs:3:1
+ |
+LL | #[link(name = "foo", kind = "raw-dylib")]
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+ |
+ = note: see issue #58713 <https://github.com/rust-lang/rust/issues/58713> for more information
+ = help: add `#![feature(raw_dylib)]` to the crate attributes to enable
+
+error: aborting due to previous error; 1 warning emitted
+
+For more information about this error, try `rustc --explain E0658`.
--- /dev/null
+// gate-test-raw_dylib
+// only-windows-msvc
+#[link(name = "foo", kind = "raw-dylib")]
+//~^ ERROR: kind="raw-dylib" is unstable
+extern "C" {}
+
+fn main() {}
--- /dev/null
+error[E0658]: kind="raw-dylib" is unstable
+ --> $DIR/feature-gate-raw-dylib-windows-msvc.rs:3:1
+ |
+LL | #[link(name = "foo", kind = "raw-dylib")]
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+ |
+ = note: see issue #58713 <https://github.com/rust-lang/rust/issues/58713> for more information
+ = help: add `#![feature(raw_dylib)]` to the crate attributes to enable
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0658`.
--- /dev/null
+// If the format string is another macro invocation, rustc would previously
+// compute nonsensical spans, such as:
+//
+// error: invalid format string: unmatched `}` found
+// --> test.rs:2:17
+// |
+// 2 | format!(concat!("abc}"));
+// | ^ unmatched `}` in format string
+//
+// This test checks that this behavior has been fixed.
+
+fn main() {
+ format!(concat!("abc}"));
+ //~^ ERROR: invalid format string: unmatched `}` found
+}
--- /dev/null
+error: invalid format string: unmatched `}` found
+ --> $DIR/format-concat-span.rs:13:13
+ |
+LL | format!(concat!("abc}"));
+ | ^^^^^^^^^^^^^^^ unmatched `}` in format string
+ |
+ = note: if you intended to print `}`, you can escape it using `}}`
+ = note: this error originates in the macro `concat` (in Nightly builds, run with -Z macro-backtrace for more info)
+
+error: aborting due to previous error
+
--- /dev/null
+// Tests for an ICE with the fuzzed input below.
+
+fn main ( ) {
+format ! ( concat ! ( r#"lJ�.�"# , "r} {}" ) ) ;
+//~^ ERROR: invalid format string: unmatched `}` found
+}
--- /dev/null
+error: invalid format string: unmatched `}` found
+ --> $DIR/issue-86085.rs:4:12
+ |
+LL | format ! ( concat ! ( r#"lJ�.�"# , "r} {}" ) ) ;
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ unmatched `}` in format string
+ |
+ = note: if you intended to print `}`, you can escape it using `}}`
+ = note: this error originates in the macro `concat` (in Nightly builds, run with -Z macro-backtrace for more info)
+
+error: aborting due to previous error
+
|
= help: the trait `Sync` is not implemented for `RefCell<i32>`
= note: required because of the requirements on the impl of `Send` for `Arc<RefCell<i32>>`
- = note: required because it appears within the type `[generator@$DIR/issue-68112.rs:38:5: 41:6 {()}]`
+ = note: required because it appears within the type `[generator@$DIR/issue-68112.rs:38:5: 41:6]`
= note: required because it appears within the type `impl Generator`
= note: required because it appears within the type `impl Generator`
= note: required because it appears within the type `{impl Generator, ()}`
- = note: required because it appears within the type `[generator@$DIR/issue-68112.rs:48:20: 51:6 {impl Generator, ()}]`
+ = note: required because it appears within the type `[generator@$DIR/issue-68112.rs:48:20: 51:6]`
error: aborting due to 2 previous errors
|
= help: the trait `Sync` is not implemented for `Cell<i32>`
= note: required because of the requirements on the impl of `Send` for `&Cell<i32>`
- = note: required because it appears within the type `[generator@$DIR/not-send-sync.rs:16:17: 20:6 _]`
+ = note: required because it appears within the type `[generator@$DIR/not-send-sync.rs:16:17: 20:6]`
error: generator cannot be shared between threads safely
--> $DIR/not-send-sync.rs:9:5
LL | assert_sync(|| {
| ^^^^^^^^^^^ generator is not `Sync`
|
- = help: within `[generator@$DIR/not-send-sync.rs:9:17: 13:6 {Cell<i32>, ()}]`, the trait `Sync` is not implemented for `Cell<i32>`
+ = help: within `[generator@$DIR/not-send-sync.rs:9:17: 13:6]`, the trait `Sync` is not implemented for `Cell<i32>`
note: generator is not `Sync` as this value is used across a yield
--> $DIR/not-send-sync.rs:12:9
|
// build-pass
+// revisions: mir thir
+// [thir]compile-flags: -Zthir-unsafeck
+
#![feature(generators)]
static mut A: [i32; 5] = [1, 2, 3, 4, 5];
//~| ERROR missing lifetime specifier
//~| HELP consider introducing
//~| HELP add missing
+
+ type F = Ty<'static, usize, 'static, usize>;
+ //~^ ERROR this struct takes 1 lifetime argument but 2 lifetime arguments
+ //~| ERROR this struct takes 1 generic argument but 2 generic arguments
+ //~| HELP remove this lifetime argument
+ //~| HELP remove this generic argument
}
mod type_and_type_and_type {
LL | type E<'a> = Ty<'a>;
| ^^^^ ^^
+error[E0107]: this struct takes 1 lifetime argument but 2 lifetime arguments were supplied
+ --> $DIR/wrong-number-of-args.rs:70:14
+ |
+LL | type F = Ty<'static, usize, 'static, usize>;
+ | ^^ ------- help: remove this lifetime argument
+ | |
+ | expected 1 lifetime argument
+ |
+note: struct defined here, with 1 lifetime parameter: `'a`
+ --> $DIR/wrong-number-of-args.rs:46:12
+ |
+LL | struct Ty<'a, T>;
+ | ^^ --
+
+error[E0107]: this struct takes 1 generic argument but 2 generic arguments were supplied
+ --> $DIR/wrong-number-of-args.rs:70:14
+ |
+LL | type F = Ty<'static, usize, 'static, usize>;
+ | ^^ ----- help: remove this generic argument
+ | |
+ | expected 1 generic argument
+ |
+note: struct defined here, with 1 generic parameter: `T`
+ --> $DIR/wrong-number-of-args.rs:46:12
+ |
+LL | struct Ty<'a, T>;
+ | ^^ -
+
error[E0107]: missing generics for struct `type_and_type_and_type::Ty`
- --> $DIR/wrong-number-of-args.rs:74:14
+ --> $DIR/wrong-number-of-args.rs:80:14
|
LL | type A = Ty;
| ^^ expected at least 2 generic arguments
|
note: struct defined here, with at least 2 generic parameters: `A`, `B`
- --> $DIR/wrong-number-of-args.rs:72:12
+ --> $DIR/wrong-number-of-args.rs:78:12
|
LL | struct Ty<A, B, C = &'static str>;
| ^^ - -
| ^^^^^^^^
error[E0107]: this struct takes at least 2 generic arguments but 1 generic argument was supplied
- --> $DIR/wrong-number-of-args.rs:78:14
+ --> $DIR/wrong-number-of-args.rs:84:14
|
LL | type B = Ty<usize>;
| ^^ ----- supplied 1 generic argument
| expected at least 2 generic arguments
|
note: struct defined here, with at least 2 generic parameters: `A`, `B`
- --> $DIR/wrong-number-of-args.rs:72:12
+ --> $DIR/wrong-number-of-args.rs:78:12
|
LL | struct Ty<A, B, C = &'static str>;
| ^^ - -
| ^^^
error[E0107]: this struct takes at most 3 generic arguments but 4 generic arguments were supplied
- --> $DIR/wrong-number-of-args.rs:86:14
+ --> $DIR/wrong-number-of-args.rs:92:14
|
LL | type E = Ty<usize, String, char, f64>;
| ^^ --- help: remove this generic argument
| expected at most 3 generic arguments
|
note: struct defined here, with at most 3 generic parameters: `A`, `B`, `C`
- --> $DIR/wrong-number-of-args.rs:72:12
+ --> $DIR/wrong-number-of-args.rs:78:12
|
LL | struct Ty<A, B, C = &'static str>;
| ^^ - - -
error[E0107]: this struct takes at least 2 generic arguments but 0 generic arguments were supplied
- --> $DIR/wrong-number-of-args.rs:90:14
+ --> $DIR/wrong-number-of-args.rs:96:14
|
LL | type F = Ty<>;
| ^^ expected at least 2 generic arguments
|
note: struct defined here, with at least 2 generic parameters: `A`, `B`
- --> $DIR/wrong-number-of-args.rs:72:12
+ --> $DIR/wrong-number-of-args.rs:78:12
|
LL | struct Ty<A, B, C = &'static str>;
| ^^ - -
| ^^^^
error[E0107]: this trait takes 0 generic arguments but 1 generic argument was supplied
- --> $DIR/wrong-number-of-args.rs:110:22
+ --> $DIR/wrong-number-of-args.rs:116:22
|
LL | type A = Box<dyn NonGeneric<usize>>;
| ^^^^^^^^^^------- help: remove these generics
| expected 0 generic arguments
|
note: trait defined here, with 0 generic parameters
- --> $DIR/wrong-number-of-args.rs:98:11
+ --> $DIR/wrong-number-of-args.rs:104:11
|
LL | trait NonGeneric {
| ^^^^^^^^^^
error[E0106]: missing lifetime specifier
- --> $DIR/wrong-number-of-args.rs:114:22
+ --> $DIR/wrong-number-of-args.rs:120:22
|
LL | type B = Box<dyn GenericLifetime>;
| ^^^^^^^^^^^^^^^ expected named lifetime parameter
| ^^^^ ^^^^^^^^^^^^^^^^^^^
error[E0107]: this trait takes 1 lifetime argument but 2 lifetime arguments were supplied
- --> $DIR/wrong-number-of-args.rs:118:22
+ --> $DIR/wrong-number-of-args.rs:124:22
|
LL | type C = Box<dyn GenericLifetime<'static, 'static>>;
| ^^^^^^^^^^^^^^^ ------- help: remove this lifetime argument
| expected 1 lifetime argument
|
note: trait defined here, with 1 lifetime parameter: `'a`
- --> $DIR/wrong-number-of-args.rs:102:11
+ --> $DIR/wrong-number-of-args.rs:108:11
|
LL | trait GenericLifetime<'a> {
| ^^^^^^^^^^^^^^^ --
error[E0107]: missing generics for trait `GenericType`
- --> $DIR/wrong-number-of-args.rs:122:22
+ --> $DIR/wrong-number-of-args.rs:128:22
|
LL | type D = Box<dyn GenericType>;
| ^^^^^^^^^^^ expected 1 generic argument
|
note: trait defined here, with 1 generic parameter: `A`
- --> $DIR/wrong-number-of-args.rs:106:11
+ --> $DIR/wrong-number-of-args.rs:112:11
|
LL | trait GenericType<A> {
| ^^^^^^^^^^^ -
| ^^^^^^^^^^^^^^
error[E0107]: this trait takes 1 generic argument but 2 generic arguments were supplied
- --> $DIR/wrong-number-of-args.rs:126:22
+ --> $DIR/wrong-number-of-args.rs:132:22
|
LL | type E = Box<dyn GenericType<String, usize>>;
| ^^^^^^^^^^^ ----- help: remove this generic argument
| expected 1 generic argument
|
note: trait defined here, with 1 generic parameter: `A`
- --> $DIR/wrong-number-of-args.rs:106:11
+ --> $DIR/wrong-number-of-args.rs:112:11
|
LL | trait GenericType<A> {
| ^^^^^^^^^^^ -
error[E0106]: missing lifetime specifier
- --> $DIR/wrong-number-of-args.rs:130:37
+ --> $DIR/wrong-number-of-args.rs:136:37
|
LL | type F = Box<dyn GenericLifetime<>>;
| ^- expected named lifetime parameter
| ^^^^ ^^
error[E0107]: this trait takes 1 generic argument but 0 generic arguments were supplied
- --> $DIR/wrong-number-of-args.rs:134:22
+ --> $DIR/wrong-number-of-args.rs:140:22
|
LL | type G = Box<dyn GenericType<>>;
| ^^^^^^^^^^^ expected 1 generic argument
|
note: trait defined here, with 1 generic parameter: `A`
- --> $DIR/wrong-number-of-args.rs:106:11
+ --> $DIR/wrong-number-of-args.rs:112:11
|
LL | trait GenericType<A> {
| ^^^^^^^^^^^ -
| ^
error[E0107]: this trait takes 0 generic arguments but 1 generic argument was supplied
- --> $DIR/wrong-number-of-args.rs:145:26
+ --> $DIR/wrong-number-of-args.rs:151:26
|
LL | type A = Box<dyn NonGenericAT<usize, AssocTy=()>>;
| ^^^^^^^^^^^^------------------- help: remove these generics
| expected 0 generic arguments
|
note: trait defined here, with 0 generic parameters
- --> $DIR/wrong-number-of-args.rs:141:15
+ --> $DIR/wrong-number-of-args.rs:147:15
|
LL | trait NonGenericAT {
| ^^^^^^^^^^^^
error[E0106]: missing lifetime specifier
- --> $DIR/wrong-number-of-args.rs:155:44
+ --> $DIR/wrong-number-of-args.rs:161:44
|
LL | type A = Box<dyn GenericLifetimeAT<AssocTy=()>>;
| ^ expected named lifetime parameter
| ^^^^ ^^^
error[E0107]: this trait takes 1 lifetime argument but 2 lifetime arguments were supplied
- --> $DIR/wrong-number-of-args.rs:159:26
+ --> $DIR/wrong-number-of-args.rs:165:26
|
LL | type B = Box<dyn GenericLifetimeAT<'static, 'static, AssocTy=()>>;
| ^^^^^^^^^^^^^^^^^ ------- help: remove this lifetime argument
| expected 1 lifetime argument
|
note: trait defined here, with 1 lifetime parameter: `'a`
- --> $DIR/wrong-number-of-args.rs:151:15
+ --> $DIR/wrong-number-of-args.rs:157:15
|
LL | trait GenericLifetimeAT<'a> {
| ^^^^^^^^^^^^^^^^^ --
error[E0106]: missing lifetime specifier
- --> $DIR/wrong-number-of-args.rs:163:44
+ --> $DIR/wrong-number-of-args.rs:169:44
|
LL | type C = Box<dyn GenericLifetimeAT<(), AssocTy=()>>;
| ^ expected named lifetime parameter
| ^^^^ ^^^
error[E0107]: this trait takes 0 generic arguments but 1 generic argument was supplied
- --> $DIR/wrong-number-of-args.rs:163:26
+ --> $DIR/wrong-number-of-args.rs:169:26
|
LL | type C = Box<dyn GenericLifetimeAT<(), AssocTy=()>>;
| ^^^^^^^^^^^^^^^^^ -- help: remove this generic argument
| expected 0 generic arguments
|
note: trait defined here, with 0 generic parameters
- --> $DIR/wrong-number-of-args.rs:151:15
+ --> $DIR/wrong-number-of-args.rs:157:15
|
LL | trait GenericLifetimeAT<'a> {
| ^^^^^^^^^^^^^^^^^
error[E0107]: this trait takes 1 generic argument but 0 generic arguments were supplied
- --> $DIR/wrong-number-of-args.rs:175:26
+ --> $DIR/wrong-number-of-args.rs:181:26
|
LL | type A = Box<dyn GenericTypeAT<AssocTy=()>>;
| ^^^^^^^^^^^^^ expected 1 generic argument
|
note: trait defined here, with 1 generic parameter: `A`
- --> $DIR/wrong-number-of-args.rs:171:15
+ --> $DIR/wrong-number-of-args.rs:177:15
|
LL | trait GenericTypeAT<A> {
| ^^^^^^^^^^^^^ -
| ^^
error[E0107]: this trait takes 1 generic argument but 2 generic arguments were supplied
- --> $DIR/wrong-number-of-args.rs:179:26
+ --> $DIR/wrong-number-of-args.rs:185:26
|
LL | type B = Box<dyn GenericTypeAT<(), (), AssocTy=()>>;
| ^^^^^^^^^^^^^ -- help: remove this generic argument
| expected 1 generic argument
|
note: trait defined here, with 1 generic parameter: `A`
- --> $DIR/wrong-number-of-args.rs:171:15
+ --> $DIR/wrong-number-of-args.rs:177:15
|
LL | trait GenericTypeAT<A> {
| ^^^^^^^^^^^^^ -
error[E0107]: this trait takes 0 lifetime arguments but 1 lifetime argument was supplied
- --> $DIR/wrong-number-of-args.rs:183:26
+ --> $DIR/wrong-number-of-args.rs:189:26
|
LL | type C = Box<dyn GenericTypeAT<'static, AssocTy=()>>;
| ^^^^^^^^^^^^^--------------------- help: remove these generics
| expected 0 lifetime arguments
|
note: trait defined here, with 0 lifetime parameters
- --> $DIR/wrong-number-of-args.rs:171:15
+ --> $DIR/wrong-number-of-args.rs:177:15
|
LL | trait GenericTypeAT<A> {
| ^^^^^^^^^^^^^
error[E0107]: this trait takes 1 generic argument but 0 generic arguments were supplied
- --> $DIR/wrong-number-of-args.rs:183:26
+ --> $DIR/wrong-number-of-args.rs:189:26
|
LL | type C = Box<dyn GenericTypeAT<'static, AssocTy=()>>;
| ^^^^^^^^^^^^^ expected 1 generic argument
|
note: trait defined here, with 1 generic parameter: `A`
- --> $DIR/wrong-number-of-args.rs:171:15
+ --> $DIR/wrong-number-of-args.rs:177:15
|
LL | trait GenericTypeAT<A> {
| ^^^^^^^^^^^^^ -
| ^^^
error[E0106]: missing lifetime specifier
- --> $DIR/wrong-number-of-args.rs:195:48
+ --> $DIR/wrong-number-of-args.rs:201:48
|
LL | type A = Box<dyn GenericLifetimeTypeAT<AssocTy=()>>;
| ^ expected named lifetime parameter
| ^^^^ ^^^
error[E0107]: this trait takes 1 generic argument but 0 generic arguments were supplied
- --> $DIR/wrong-number-of-args.rs:195:26
+ --> $DIR/wrong-number-of-args.rs:201:26
|
LL | type A = Box<dyn GenericLifetimeTypeAT<AssocTy=()>>;
| ^^^^^^^^^^^^^^^^^^^^^ expected 1 generic argument
|
note: trait defined here, with 1 generic parameter: `A`
- --> $DIR/wrong-number-of-args.rs:191:15
+ --> $DIR/wrong-number-of-args.rs:197:15
|
LL | trait GenericLifetimeTypeAT<'a, A> {
| ^^^^^^^^^^^^^^^^^^^^^ -
| ^^
error[E0107]: this trait takes 1 generic argument but 0 generic arguments were supplied
- --> $DIR/wrong-number-of-args.rs:201:26
+ --> $DIR/wrong-number-of-args.rs:207:26
|
LL | type B = Box<dyn GenericLifetimeTypeAT<'static, AssocTy=()>>;
| ^^^^^^^^^^^^^^^^^^^^^ expected 1 generic argument
|
note: trait defined here, with 1 generic parameter: `A`
- --> $DIR/wrong-number-of-args.rs:191:15
+ --> $DIR/wrong-number-of-args.rs:197:15
|
LL | trait GenericLifetimeTypeAT<'a, A> {
| ^^^^^^^^^^^^^^^^^^^^^ -
| ^^^
error[E0107]: this trait takes 1 lifetime argument but 2 lifetime arguments were supplied
- --> $DIR/wrong-number-of-args.rs:205:26
+ --> $DIR/wrong-number-of-args.rs:211:26
|
LL | type C = Box<dyn GenericLifetimeTypeAT<'static, 'static, AssocTy=()>>;
| ^^^^^^^^^^^^^^^^^^^^^ ------- help: remove this lifetime argument
| expected 1 lifetime argument
|
note: trait defined here, with 1 lifetime parameter: `'a`
- --> $DIR/wrong-number-of-args.rs:191:15
+ --> $DIR/wrong-number-of-args.rs:197:15
|
LL | trait GenericLifetimeTypeAT<'a, A> {
| ^^^^^^^^^^^^^^^^^^^^^ --
error[E0107]: this trait takes 1 generic argument but 0 generic arguments were supplied
- --> $DIR/wrong-number-of-args.rs:205:26
+ --> $DIR/wrong-number-of-args.rs:211:26
|
LL | type C = Box<dyn GenericLifetimeTypeAT<'static, 'static, AssocTy=()>>;
| ^^^^^^^^^^^^^^^^^^^^^ expected 1 generic argument
|
note: trait defined here, with 1 generic parameter: `A`
- --> $DIR/wrong-number-of-args.rs:191:15
+ --> $DIR/wrong-number-of-args.rs:197:15
|
LL | trait GenericLifetimeTypeAT<'a, A> {
| ^^^^^^^^^^^^^^^^^^^^^ -
| ^^^
error[E0106]: missing lifetime specifier
- --> $DIR/wrong-number-of-args.rs:211:48
+ --> $DIR/wrong-number-of-args.rs:217:48
|
LL | type D = Box<dyn GenericLifetimeTypeAT<(), AssocTy=()>>;
| ^ expected named lifetime parameter
| ^^^^ ^^^
error[E0106]: missing lifetime specifier
- --> $DIR/wrong-number-of-args.rs:215:48
+ --> $DIR/wrong-number-of-args.rs:221:48
|
LL | type E = Box<dyn GenericLifetimeTypeAT<(), (), AssocTy=()>>;
| ^ expected named lifetime parameter
| ^^^^ ^^^
error[E0107]: this trait takes 1 generic argument but 2 generic arguments were supplied
- --> $DIR/wrong-number-of-args.rs:215:26
+ --> $DIR/wrong-number-of-args.rs:221:26
|
LL | type E = Box<dyn GenericLifetimeTypeAT<(), (), AssocTy=()>>;
| ^^^^^^^^^^^^^^^^^^^^^ -- help: remove this generic argument
| expected 1 generic argument
|
note: trait defined here, with 1 generic parameter: `A`
- --> $DIR/wrong-number-of-args.rs:191:15
+ --> $DIR/wrong-number-of-args.rs:197:15
|
LL | trait GenericLifetimeTypeAT<'a, A> {
| ^^^^^^^^^^^^^^^^^^^^^ -
error[E0107]: this trait takes 1 lifetime argument but 2 lifetime arguments were supplied
- --> $DIR/wrong-number-of-args.rs:221:26
+ --> $DIR/wrong-number-of-args.rs:227:26
|
LL | type F = Box<dyn GenericLifetimeTypeAT<'static, 'static, (), AssocTy=()>>;
| ^^^^^^^^^^^^^^^^^^^^^ ------- help: remove this lifetime argument
| expected 1 lifetime argument
|
note: trait defined here, with 1 lifetime parameter: `'a`
- --> $DIR/wrong-number-of-args.rs:191:15
+ --> $DIR/wrong-number-of-args.rs:197:15
|
LL | trait GenericLifetimeTypeAT<'a, A> {
| ^^^^^^^^^^^^^^^^^^^^^ --
error[E0107]: this trait takes 1 generic argument but 2 generic arguments were supplied
- --> $DIR/wrong-number-of-args.rs:225:26
+ --> $DIR/wrong-number-of-args.rs:231:26
|
LL | type G = Box<dyn GenericLifetimeTypeAT<'static, (), (), AssocTy=()>>;
| ^^^^^^^^^^^^^^^^^^^^^ -- help: remove this generic argument
| expected 1 generic argument
|
note: trait defined here, with 1 generic parameter: `A`
- --> $DIR/wrong-number-of-args.rs:191:15
+ --> $DIR/wrong-number-of-args.rs:197:15
|
LL | trait GenericLifetimeTypeAT<'a, A> {
| ^^^^^^^^^^^^^^^^^^^^^ -
error[E0107]: this trait takes 1 lifetime argument but 2 lifetime arguments were supplied
- --> $DIR/wrong-number-of-args.rs:229:26
+ --> $DIR/wrong-number-of-args.rs:235:26
|
LL | type H = Box<dyn GenericLifetimeTypeAT<'static, 'static, (), (), AssocTy=()>>;
| ^^^^^^^^^^^^^^^^^^^^^ ------- help: remove this lifetime argument
| expected 1 lifetime argument
|
note: trait defined here, with 1 lifetime parameter: `'a`
- --> $DIR/wrong-number-of-args.rs:191:15
+ --> $DIR/wrong-number-of-args.rs:197:15
|
LL | trait GenericLifetimeTypeAT<'a, A> {
| ^^^^^^^^^^^^^^^^^^^^^ --
error[E0107]: this trait takes 1 generic argument but 2 generic arguments were supplied
- --> $DIR/wrong-number-of-args.rs:229:26
+ --> $DIR/wrong-number-of-args.rs:235:26
|
LL | type H = Box<dyn GenericLifetimeTypeAT<'static, 'static, (), (), AssocTy=()>>;
| ^^^^^^^^^^^^^^^^^^^^^ -- help: remove this generic argument
| expected 1 generic argument
|
note: trait defined here, with 1 generic parameter: `A`
- --> $DIR/wrong-number-of-args.rs:191:15
+ --> $DIR/wrong-number-of-args.rs:197:15
|
LL | trait GenericLifetimeTypeAT<'a, A> {
| ^^^^^^^^^^^^^^^^^^^^^ -
error[E0107]: this trait takes 2 generic arguments but 0 generic arguments were supplied
- --> $DIR/wrong-number-of-args.rs:241:26
+ --> $DIR/wrong-number-of-args.rs:247:26
|
LL | type A = Box<dyn GenericTypeTypeAT<AssocTy=()>>;
| ^^^^^^^^^^^^^^^^^ expected 2 generic arguments
|
note: trait defined here, with 2 generic parameters: `A`, `B`
- --> $DIR/wrong-number-of-args.rs:237:15
+ --> $DIR/wrong-number-of-args.rs:243:15
|
LL | trait GenericTypeTypeAT<A, B> {
| ^^^^^^^^^^^^^^^^^ - -
| ^^^^^
error[E0107]: this trait takes 2 generic arguments but 1 generic argument was supplied
- --> $DIR/wrong-number-of-args.rs:245:26
+ --> $DIR/wrong-number-of-args.rs:251:26
|
LL | type B = Box<dyn GenericTypeTypeAT<(), AssocTy=()>>;
| ^^^^^^^^^^^^^^^^^ -- supplied 1 generic argument
| expected 2 generic arguments
|
note: trait defined here, with 2 generic parameters: `A`, `B`
- --> $DIR/wrong-number-of-args.rs:237:15
+ --> $DIR/wrong-number-of-args.rs:243:15
|
LL | trait GenericTypeTypeAT<A, B> {
| ^^^^^^^^^^^^^^^^^ - -
| ^^^
error[E0107]: this trait takes 2 generic arguments but 3 generic arguments were supplied
- --> $DIR/wrong-number-of-args.rs:249:26
+ --> $DIR/wrong-number-of-args.rs:255:26
|
LL | type C = Box<dyn GenericTypeTypeAT<(), (), (), AssocTy=()>>;
| ^^^^^^^^^^^^^^^^^ -- help: remove this generic argument
| expected 2 generic arguments
|
note: trait defined here, with 2 generic parameters: `A`, `B`
- --> $DIR/wrong-number-of-args.rs:237:15
+ --> $DIR/wrong-number-of-args.rs:243:15
|
LL | trait GenericTypeTypeAT<A, B> {
| ^^^^^^^^^^^^^^^^^ - -
error[E0106]: missing lifetime specifiers
- --> $DIR/wrong-number-of-args.rs:259:52
+ --> $DIR/wrong-number-of-args.rs:265:52
|
LL | type A = Box<dyn GenericLifetimeLifetimeAT<AssocTy=()>>;
| ^ expected 2 lifetime parameters
| ^^^^ ^^^^^^^
error[E0107]: this trait takes 2 lifetime arguments but 1 lifetime argument was supplied
- --> $DIR/wrong-number-of-args.rs:263:26
+ --> $DIR/wrong-number-of-args.rs:269:26
|
LL | type B = Box<dyn GenericLifetimeLifetimeAT<'static, AssocTy=()>>;
| ^^^^^^^^^^^^^^^^^^^^^^^^^ ------- supplied 1 lifetime argument
| expected 2 lifetime arguments
|
note: trait defined here, with 2 lifetime parameters: `'a`, `'b`
- --> $DIR/wrong-number-of-args.rs:255:15
+ --> $DIR/wrong-number-of-args.rs:261:15
|
LL | trait GenericLifetimeLifetimeAT<'a, 'b> {
| ^^^^^^^^^^^^^^^^^^^^^^^^^ -- --
| ^^^^
error[E0106]: missing lifetime specifiers
- --> $DIR/wrong-number-of-args.rs:273:56
+ --> $DIR/wrong-number-of-args.rs:279:56
|
LL | type A = Box<dyn GenericLifetimeLifetimeTypeAT<AssocTy=()>>;
| ^ expected 2 lifetime parameters
| ^^^^ ^^^^^^^
error[E0107]: this trait takes 1 generic argument but 0 generic arguments were supplied
- --> $DIR/wrong-number-of-args.rs:273:26
+ --> $DIR/wrong-number-of-args.rs:279:26
|
LL | type A = Box<dyn GenericLifetimeLifetimeTypeAT<AssocTy=()>>;
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ expected 1 generic argument
|
note: trait defined here, with 1 generic parameter: `A`
- --> $DIR/wrong-number-of-args.rs:269:15
+ --> $DIR/wrong-number-of-args.rs:275:15
|
LL | trait GenericLifetimeLifetimeTypeAT<'a, 'b, A> {
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -
| ^^
error[E0107]: this trait takes 2 lifetime arguments but 1 lifetime argument was supplied
- --> $DIR/wrong-number-of-args.rs:279:26
+ --> $DIR/wrong-number-of-args.rs:285:26
|
LL | type B = Box<dyn GenericLifetimeLifetimeTypeAT<'static, AssocTy=()>>;
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ ------- supplied 1 lifetime argument
| expected 2 lifetime arguments
|
note: trait defined here, with 2 lifetime parameters: `'a`, `'b`
- --> $DIR/wrong-number-of-args.rs:269:15
+ --> $DIR/wrong-number-of-args.rs:275:15
|
LL | trait GenericLifetimeLifetimeTypeAT<'a, 'b, A> {
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -- --
| ^^^^
error[E0107]: this trait takes 1 generic argument but 0 generic arguments were supplied
- --> $DIR/wrong-number-of-args.rs:279:26
+ --> $DIR/wrong-number-of-args.rs:285:26
|
LL | type B = Box<dyn GenericLifetimeLifetimeTypeAT<'static, AssocTy=()>>;
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ expected 1 generic argument
|
note: trait defined here, with 1 generic parameter: `A`
- --> $DIR/wrong-number-of-args.rs:269:15
+ --> $DIR/wrong-number-of-args.rs:275:15
|
LL | trait GenericLifetimeLifetimeTypeAT<'a, 'b, A> {
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -
| ^^^
error[E0107]: this trait takes 2 lifetime arguments but 1 lifetime argument was supplied
- --> $DIR/wrong-number-of-args.rs:285:26
+ --> $DIR/wrong-number-of-args.rs:291:26
|
LL | type C = Box<dyn GenericLifetimeLifetimeTypeAT<'static, (), AssocTy=()>>;
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ ------- supplied 1 lifetime argument
| expected 2 lifetime arguments
|
note: trait defined here, with 2 lifetime parameters: `'a`, `'b`
- --> $DIR/wrong-number-of-args.rs:269:15
+ --> $DIR/wrong-number-of-args.rs:275:15
|
LL | trait GenericLifetimeLifetimeTypeAT<'a, 'b, A> {
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -- --
| ^^^^
error[E0107]: missing generics for struct `HashMap`
- --> $DIR/wrong-number-of-args.rs:295:18
+ --> $DIR/wrong-number-of-args.rs:301:18
|
LL | type A = HashMap;
| ^^^^^^^ expected at least 2 generic arguments
| ^^^^^^^^^^^^^
error[E0107]: this struct takes at least 2 generic arguments but 1 generic argument was supplied
- --> $DIR/wrong-number-of-args.rs:299:18
+ --> $DIR/wrong-number-of-args.rs:305:18
|
LL | type B = HashMap<String>;
| ^^^^^^^ ------ supplied 1 generic argument
| ^^^
error[E0107]: this struct takes 0 lifetime arguments but 1 lifetime argument was supplied
- --> $DIR/wrong-number-of-args.rs:303:18
+ --> $DIR/wrong-number-of-args.rs:309:18
|
LL | type C = HashMap<'static>;
| ^^^^^^^--------- help: remove these generics
| ^^^^^^^
error[E0107]: this struct takes at least 2 generic arguments but 0 generic arguments were supplied
- --> $DIR/wrong-number-of-args.rs:303:18
+ --> $DIR/wrong-number-of-args.rs:309:18
|
LL | type C = HashMap<'static>;
| ^^^^^^^ expected at least 2 generic arguments
| ^^^^^^
error[E0107]: this struct takes at most 3 generic arguments but 4 generic arguments were supplied
- --> $DIR/wrong-number-of-args.rs:309:18
+ --> $DIR/wrong-number-of-args.rs:315:18
|
LL | type D = HashMap<usize, String, char, f64>;
| ^^^^^^^ --- help: remove this generic argument
| ^^^^^^^ - - -
error[E0107]: this struct takes at least 2 generic arguments but 0 generic arguments were supplied
- --> $DIR/wrong-number-of-args.rs:313:18
+ --> $DIR/wrong-number-of-args.rs:319:18
|
LL | type E = HashMap<>;
| ^^^^^^^ expected at least 2 generic arguments
| ^^^^
error[E0107]: missing generics for enum `Result`
- --> $DIR/wrong-number-of-args.rs:319:18
+ --> $DIR/wrong-number-of-args.rs:325:18
|
LL | type A = Result;
| ^^^^^^ expected 2 generic arguments
| ^^^^^^^^^^^^
error[E0107]: this enum takes 2 generic arguments but 1 generic argument was supplied
- --> $DIR/wrong-number-of-args.rs:323:18
+ --> $DIR/wrong-number-of-args.rs:329:18
|
LL | type B = Result<String>;
| ^^^^^^ ------ supplied 1 generic argument
| ^^^
error[E0107]: this enum takes 0 lifetime arguments but 1 lifetime argument was supplied
- --> $DIR/wrong-number-of-args.rs:327:18
+ --> $DIR/wrong-number-of-args.rs:333:18
|
LL | type C = Result<'static>;
| ^^^^^^--------- help: remove these generics
| ^^^^^^
error[E0107]: this enum takes 2 generic arguments but 0 generic arguments were supplied
- --> $DIR/wrong-number-of-args.rs:327:18
+ --> $DIR/wrong-number-of-args.rs:333:18
|
LL | type C = Result<'static>;
| ^^^^^^ expected 2 generic arguments
| ^^^^^^
error[E0107]: this enum takes 2 generic arguments but 3 generic arguments were supplied
- --> $DIR/wrong-number-of-args.rs:333:18
+ --> $DIR/wrong-number-of-args.rs:339:18
|
LL | type D = Result<usize, String, char>;
| ^^^^^^ ---- help: remove this generic argument
| ^^^^^^ - -
error[E0107]: this enum takes 2 generic arguments but 0 generic arguments were supplied
- --> $DIR/wrong-number-of-args.rs:337:18
+ --> $DIR/wrong-number-of-args.rs:343:18
|
LL | type E = Result<>;
| ^^^^^^ expected 2 generic arguments
LL | type E = Result<T, E>;
| ^^^^
-error: aborting due to 69 previous errors
+error: aborting due to 71 previous errors
Some errors have detailed explanations: E0106, E0107.
For more information about an error, try `rustc --explain E0106`.
#![feature(fn_traits,
step_trait,
- step_trait_ext,
unboxed_closures,
)]
}
}
-unsafe impl std::iter::Step for NaiveDate {
+impl std::iter::Step for NaiveDate {
fn steps_between(_: &Self, _: &Self) -> Option<usize> {
unimplemented!()
}
warning: the feature `type_alias_impl_trait` is incomplete and may not be safe to use and/or cause compiler crashes
- --> $DIR/error-handling.rs:6:32
+ --> $DIR/error-handling.rs:5:32
|
LL | #![cfg_attr(full_tait, feature(type_alias_impl_trait))]
| ^^^^^^^^^^^^^^^^^^^^^
= note: see issue #63063 <https://github.com/rust-lang/rust/issues/63063> for more information
error: lifetime may not live long enough
- --> $DIR/error-handling.rs:26:16
+ --> $DIR/error-handling.rs:25:16
|
LL | fn foo<'a, 'b, 'c>(x: &'static i32, mut y: &'a i32) -> E<'b, 'c> {
| -- -- lifetime `'b` defined here
error: lifetime may not live long enough
- --> $DIR/error-handling.rs:26:16
+ --> $DIR/error-handling.rs:25:16
|
LL | fn foo<'a, 'b, 'c>(x: &'static i32, mut y: &'a i32) -> E<'b, 'c> {
| -- -- lifetime `'b` defined here
// compile-flags:-Zborrowck=mir
-#![feature(member_constraints)]
// revisions: min_tait full_tait
#![feature(min_type_alias_impl_trait)]
#![cfg_attr(full_tait, feature(type_alias_impl_trait))]
// revisions: migrate mir
//[mir]compile-flags: -Z borrowck=mir
-#![feature(member_constraints)]
-
trait Trait<'a, 'b> {}
impl<T> Trait<'_, '_> for T {}
// revisions: migrate mir
//[mir]compile-flags: -Z borrowck=mir
-#![feature(member_constraints)]
-
-trait Trait<'a, 'b> { }
-impl<T> Trait<'_, '_> for T { }
+trait Trait<'a, 'b> {}
+impl<T> Trait<'_, '_> for T {}
// Test case where we have elision in the impl trait and we have to
// pick the right region.
(a, a)
}
-fn main() { }
+fn main() {}
// revisions: migrate mir
//[mir]compile-flags: -Z borrowck=mir
-#![feature(member_constraints)]
#![feature(min_type_alias_impl_trait)]
-trait Trait<'a, 'b> { }
-impl<T> Trait<'_, '_> for T { }
+trait Trait<'a, 'b> {}
+impl<T> Trait<'_, '_> for T {}
// Here we wind up selecting `'a` and `'b` in the hidden type because
// those are the types that appear in the original values.
(a, b)
}
-fn main() { }
+fn main() {}
// revisions: migrate mir
//[mir]compile-flags: -Z borrowck=mir
-#![feature(member_constraints)]
-
-trait Trait<'a, 'b> { }
-impl<T> Trait<'_, '_> for T { }
+trait Trait<'a, 'b> {}
+impl<T> Trait<'_, '_> for T {}
// Here we wind up selecting `'a` and `'b` in the hidden type because
// those are the types that appear in the original values.
(a, b)
}
-fn main() { }
+fn main() {}
// revisions: migrate mir
//[mir]compile-flags: -Z borrowck=mir
-#![feature(member_constraints)]
-
trait Trait<'a, 'b> {}
impl<T> Trait<'_, '_> for T {}
error[E0700]: hidden type for `impl Trait` captures lifetime that does not appear in bounds
- --> $DIR/ordinary-bounds-unrelated.rs:18:74
+ --> $DIR/ordinary-bounds-unrelated.rs:16:74
|
LL | fn upper_bounds<'a, 'b, 'c, 'd, 'e>(a: Ordinary<'a>, b: Ordinary<'b>) -> impl Trait<'d, 'e>
| ^^^^^^^^^^^^^^^^^^
// edition:2018
-#![feature(member_constraints)]
-
trait Trait<'a, 'b> {}
impl<T> Trait<'_, '_> for T {}
error[E0700]: hidden type for `impl Trait` captures lifetime that does not appear in bounds
- --> $DIR/ordinary-bounds-unrelated.rs:18:74
+ --> $DIR/ordinary-bounds-unrelated.rs:16:74
|
LL | fn upper_bounds<'a, 'b, 'c, 'd, 'e>(a: Ordinary<'a>, b: Ordinary<'b>) -> impl Trait<'d, 'e>
| ^^^^^^^^^^^^^^^^^^
|
note: hidden type `Ordinary<'_>` captures lifetime smaller than the function body
- --> $DIR/ordinary-bounds-unrelated.rs:18:74
+ --> $DIR/ordinary-bounds-unrelated.rs:16:74
|
LL | fn upper_bounds<'a, 'b, 'c, 'd, 'e>(a: Ordinary<'a>, b: Ordinary<'b>) -> impl Trait<'d, 'e>
| ^^^^^^^^^^^^^^^^^^
error[E0700]: hidden type for `impl Trait` captures lifetime that does not appear in bounds
- --> $DIR/ordinary-bounds-unsuited.rs:20:62
+ --> $DIR/ordinary-bounds-unsuited.rs:18:62
|
LL | fn upper_bounds<'a, 'b>(a: Ordinary<'a>, b: Ordinary<'b>) -> impl Trait<'a, 'b>
| ^^^^^^^^^^^^^^^^^^
// edition:2018
-#![feature(member_constraints)]
-
trait Trait<'a, 'b> {}
impl<T> Trait<'_, '_> for T {}
// consider the loans for both `'a` and `'b` alive.
fn upper_bounds<'a, 'b>(a: Ordinary<'a>, b: Ordinary<'b>) -> impl Trait<'a, 'b>
- //~^ ERROR hidden type for `impl Trait` captures lifetime that does not appear in bounds
+//~^ ERROR hidden type for `impl Trait` captures lifetime that does not appear in bounds
{
// We return a value:
//
error[E0700]: hidden type for `impl Trait` captures lifetime that does not appear in bounds
- --> $DIR/ordinary-bounds-unsuited.rs:20:62
+ --> $DIR/ordinary-bounds-unsuited.rs:18:62
|
LL | fn upper_bounds<'a, 'b>(a: Ordinary<'a>, b: Ordinary<'b>) -> impl Trait<'a, 'b>
| ^^^^^^^^^^^^^^^^^^
|
note: hidden type `Ordinary<'_>` captures lifetime smaller than the function body
- --> $DIR/ordinary-bounds-unsuited.rs:20:62
+ --> $DIR/ordinary-bounds-unsuited.rs:18:62
|
LL | fn upper_bounds<'a, 'b>(a: Ordinary<'a>, b: Ordinary<'b>) -> impl Trait<'a, 'b>
| ^^^^^^^^^^^^^^^^^^
// check-pass
-#![feature(member_constraints)]
-
trait MultiRegionTrait<'a, 'b> {}
impl<'a, 'b> MultiRegionTrait<'a, 'b> for (&'a u32, &'b u32) {}
LL | | yield;
LL | | x;
LL | | }
- | |_____- returning here with type `[generator@$DIR/recursive-impl-trait-type-indirect.rs:61:5: 64:6 {()}]`
+ | |_____- returning here with type `[generator@$DIR/recursive-impl-trait-type-indirect.rs:61:5: 64:6]`
error[E0720]: cannot resolve opaque type
--> $DIR/recursive-impl-trait-type-indirect.rs:67:35
LL | | yield;
LL | | x;
LL | | }
- | |_____- returning here with type `[generator@$DIR/recursive-impl-trait-type-indirect.rs:74:5: 78:6 {impl Sized, ()}]`
+ | |_____- returning here with type `[generator@$DIR/recursive-impl-trait-type-indirect.rs:74:5: 78:6]`
error[E0720]: cannot resolve opaque type
--> $DIR/recursive-impl-trait-type-indirect.rs:86:26
--- /dev/null
+// check-pass
+
+fn main() {
+ let _unused = if true {
+ core::ptr::copy::<i32>
+ } else {
+ core::ptr::copy_nonoverlapping::<i32>
+ };
+}
// run-pass
// ignore-wasm32-bare compiled with panic=abort by default
+// revisions: mir thir
+// [thir]compile-flags: -Zthir-unsafeck
// This test checks panic emitted from `mem::{uninitialized,zeroed}`.
// check-pass
+// revisions: mir thir
+// [thir]compile-flags: -Zthir-unsafeck
struct Attr {
name: String,
LL | 0 as &dyn std::any::Any;
| ^^^^^^^^^^^^^^^^^^^^^^^ invalid cast
|
-help: borrow the value for the cast to be valid
+help: consider borrowing the value
|
LL | &0 as &dyn std::any::Any;
| ^
LL | let indexer = &(*self as &dyn Index<usize, Output = <Self as Index<usize>>::Output>);
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ invalid cast
|
-help: borrow the value for the cast to be valid
+help: consider borrowing the value
|
LL | let indexer = &(&*self as &dyn Index<usize, Output = <Self as Index<usize>>::Output>);
| ^
--> $DIR/issue-2995.rs:2:22
|
LL | let _q: &isize = p as &isize;
- | ^^^^^^^^^^^ an `as` expression can only be used to convert between primitive types or to coerce to a specific trait object
+ | ^^^^^^^^^^^ invalid cast
+ |
+help: consider borrowing the value
+ |
+LL | let _q: &isize = &*p as &isize;
+ | ^^
error: aborting due to previous error
|
LL | let ug = Graph::<i32, i32>::new_undirected();
| ^^^^^^^^^^^^^^ function or associated item not found in `issue_30123_aux::Graph<i32, i32>`
+ |
+ = note: the function or associated item was found for
+ - `issue_30123_aux::Graph<N, E, Undirected>`
error: aborting due to previous error
// run-pass
+// revisions: mir thir
+// [thir]compile-flags: -Zthir-unsafeck
+
use std::ops::Deref;
struct ArenaSet<U: Deref, V=<U as Deref>::Target>(U, &'static V)
-error[E0599]: no method named `iter` found for struct `Iterate<{integer}, [closure@$DIR/issue-41880.rs:26:24: 26:31]>` in the current scope
+error[E0599]: no method named `iter` found for struct `Iterate` in the current scope
--> $DIR/issue-41880.rs:27:24
|
LL | pub struct Iterate<T, F> {
--- /dev/null
+error: unnecessary `unsafe` block
+ --> $DIR/issue-45107-unnecessary-unsafe-in-closure.rs:10:13
+ |
+LL | unsafe {
+ | ------ because it's nested under this `unsafe` block
+LL | let f = |v: &mut Vec<_>| {
+LL | unsafe {
+ | ^^^^^^ unnecessary `unsafe` block
+ |
+note: the lint level is defined here
+ --> $DIR/issue-45107-unnecessary-unsafe-in-closure.rs:4:8
+ |
+LL | #[deny(unused_unsafe)]
+ | ^^^^^^^^^^^^^
+
+error: unnecessary `unsafe` block
+ --> $DIR/issue-45107-unnecessary-unsafe-in-closure.rs:12:38
+ |
+LL | unsafe {
+ | ------ because it's nested under this `unsafe` block
+...
+LL | |w: &mut Vec<u32>| { unsafe {
+ | ^^^^^^ unnecessary `unsafe` block
+
+error: unnecessary `unsafe` block
+ --> $DIR/issue-45107-unnecessary-unsafe-in-closure.rs:16:34
+ |
+LL | unsafe {
+ | ------ because it's nested under this `unsafe` block
+...
+LL | |x: &mut Vec<u32>| { unsafe {
+ | ^^^^^^ unnecessary `unsafe` block
+
+error: aborting due to 3 previous errors
+
+// revisions: mir thir
+// [thir]compile-flags: -Zthir-unsafeck
+
#[deny(unused_unsafe)]
fn main() {
let mut v = Vec::<i32>::with_capacity(24);
+++ /dev/null
-error: unnecessary `unsafe` block
- --> $DIR/issue-45107-unnecessary-unsafe-in-closure.rs:7:13
- |
-LL | unsafe {
- | ------ because it's nested under this `unsafe` block
-LL | let f = |v: &mut Vec<_>| {
-LL | unsafe {
- | ^^^^^^ unnecessary `unsafe` block
- |
-note: the lint level is defined here
- --> $DIR/issue-45107-unnecessary-unsafe-in-closure.rs:1:8
- |
-LL | #[deny(unused_unsafe)]
- | ^^^^^^^^^^^^^
-
-error: unnecessary `unsafe` block
- --> $DIR/issue-45107-unnecessary-unsafe-in-closure.rs:9:38
- |
-LL | unsafe {
- | ------ because it's nested under this `unsafe` block
-...
-LL | |w: &mut Vec<u32>| { unsafe {
- | ^^^^^^ unnecessary `unsafe` block
-
-error: unnecessary `unsafe` block
- --> $DIR/issue-45107-unnecessary-unsafe-in-closure.rs:13:34
- |
-LL | unsafe {
- | ------ because it's nested under this `unsafe` block
-...
-LL | |x: &mut Vec<u32>| { unsafe {
- | ^^^^^^ unnecessary `unsafe` block
-
-error: aborting due to 3 previous errors
-
--- /dev/null
+error: unnecessary `unsafe` block
+ --> $DIR/issue-45107-unnecessary-unsafe-in-closure.rs:10:13
+ |
+LL | unsafe {
+ | ------ because it's nested under this `unsafe` block
+LL | let f = |v: &mut Vec<_>| {
+LL | unsafe {
+ | ^^^^^^ unnecessary `unsafe` block
+ |
+note: the lint level is defined here
+ --> $DIR/issue-45107-unnecessary-unsafe-in-closure.rs:4:8
+ |
+LL | #[deny(unused_unsafe)]
+ | ^^^^^^^^^^^^^
+
+error: unnecessary `unsafe` block
+ --> $DIR/issue-45107-unnecessary-unsafe-in-closure.rs:12:38
+ |
+LL | unsafe {
+ | ------ because it's nested under this `unsafe` block
+...
+LL | |w: &mut Vec<u32>| { unsafe {
+ | ^^^^^^ unnecessary `unsafe` block
+
+error: unnecessary `unsafe` block
+ --> $DIR/issue-45107-unnecessary-unsafe-in-closure.rs:16:34
+ |
+LL | unsafe {
+ | ------ because it's nested under this `unsafe` block
+...
+LL | |x: &mut Vec<u32>| { unsafe {
+ | ^^^^^^ unnecessary `unsafe` block
+
+error: aborting due to 3 previous errors
+
| ^
| |
| not allowed in type signatures
- | help: replace `_` with the correct type: `bool`
+ | help: replace with the correct type: `bool`
...
LL | / suite! {
LL | | len;
--- /dev/null
+// See issue #84108 -- this is a test to ensure we do not ICE
+// on this invalid code.
+
+#![crate_type = "lib"]
+
+static FOO: (dyn AsRef<OsStr>, u8) = ("hello", 42);
+//~^ ERROR cannot find type `OsStr` in this scope
+
+const BAR: (&Path, [u8], usize) = ("hello", [], 42);
+//~^ ERROR cannot find type `Path` in this scope
+//~| ERROR the size for values of type `[u8]` cannot be known at compilation time
+
+static BAZ: ([u8], usize) = ([], 0);
+//~^ ERROR the size for values of type `[u8]` cannot be known at compilation time
--- /dev/null
+error[E0412]: cannot find type `OsStr` in this scope
+ --> $DIR/issue-84108.rs:6:24
+ |
+LL | static FOO: (dyn AsRef<OsStr>, u8) = ("hello", 42);
+ | ^^^^^ not found in this scope
+ |
+help: consider importing this struct
+ |
+LL | use std::ffi::OsStr;
+ |
+
+error[E0412]: cannot find type `Path` in this scope
+ --> $DIR/issue-84108.rs:9:14
+ |
+LL | const BAR: (&Path, [u8], usize) = ("hello", [], 42);
+ | ^^^^ not found in this scope
+ |
+help: consider importing this struct
+ |
+LL | use std::path::Path;
+ |
+
+error[E0277]: the size for values of type `[u8]` cannot be known at compilation time
+ --> $DIR/issue-84108.rs:9:12
+ |
+LL | const BAR: (&Path, [u8], usize) = ("hello", [], 42);
+ | ^^^^^^^^^^^^^^^^^^^^ doesn't have a size known at compile-time
+ |
+ = help: the trait `Sized` is not implemented for `[u8]`
+ = note: only the last element of a tuple may have a dynamically sized type
+
+error[E0277]: the size for values of type `[u8]` cannot be known at compilation time
+ --> $DIR/issue-84108.rs:13:13
+ |
+LL | static BAZ: ([u8], usize) = ([], 0);
+ | ^^^^^^^^^^^^^ doesn't have a size known at compile-time
+ |
+ = help: the trait `Sized` is not implemented for `[u8]`
+ = note: only the last element of a tuple may have a dynamically sized type
+
+error: aborting due to 4 previous errors
+
+Some errors have detailed explanations: E0277, E0412.
+For more information about an error, try `rustc --explain E0277`.
#![allow(uncommon_codepoints)]
//~^ ERROR allow(uncommon_codepoints) is ignored unless specified at crate level [unused_attributes]
//~| ERROR allow(uncommon_codepoints) is ignored unless specified at crate level [unused_attributes]
-//~| ERROR allow(uncommon_codepoints) is ignored unless specified at crate level [unused_attributes]
#[allow(uncommon_codepoints)]
//~^ ERROR allow(uncommon_codepoints) is ignored unless specified at crate level [unused_attributes]
//~| ERROR allow(uncommon_codepoints) is ignored unless specified at crate level [unused_attributes]
-//~| ERROR allow(uncommon_codepoints) is ignored unless specified at crate level [unused_attributes]
const BAR: f64 = 0.000001;
}
#[allow(uncommon_codepoints)]
//~^ ERROR allow(uncommon_codepoints) is ignored unless specified at crate level [unused_attributes]
//~| ERROR allow(uncommon_codepoints) is ignored unless specified at crate level [unused_attributes]
-//~| ERROR allow(uncommon_codepoints) is ignored unless specified at crate level [unused_attributes]
fn main() {
}
| ^^^^^^^^^^^^^^^^^
error: allow(uncommon_codepoints) is ignored unless specified at crate level
- --> $DIR/crate_level_only_lint.rs:9:9
+ --> $DIR/crate_level_only_lint.rs:8:9
|
LL | #[allow(uncommon_codepoints)]
| ^^^^^^^^^^^^^^^^^^^
error: allow(uncommon_codepoints) is ignored unless specified at crate level
- --> $DIR/crate_level_only_lint.rs:17:9
+ --> $DIR/crate_level_only_lint.rs:15:9
|
LL | #[allow(uncommon_codepoints)]
| ^^^^^^^^^^^^^^^^^^^
| ^^^^^^^^^^^^^^^^^^^
error: allow(uncommon_codepoints) is ignored unless specified at crate level
- --> $DIR/crate_level_only_lint.rs:9:9
+ --> $DIR/crate_level_only_lint.rs:8:9
|
LL | #[allow(uncommon_codepoints)]
| ^^^^^^^^^^^^^^^^^^^
error: allow(uncommon_codepoints) is ignored unless specified at crate level
- --> $DIR/crate_level_only_lint.rs:17:9
+ --> $DIR/crate_level_only_lint.rs:15:9
|
LL | #[allow(uncommon_codepoints)]
| ^^^^^^^^^^^^^^^^^^^
-error: allow(uncommon_codepoints) is ignored unless specified at crate level
- --> $DIR/crate_level_only_lint.rs:4:10
- |
-LL | #![allow(uncommon_codepoints)]
- | ^^^^^^^^^^^^^^^^^^^
-
-error: allow(uncommon_codepoints) is ignored unless specified at crate level
- --> $DIR/crate_level_only_lint.rs:9:9
- |
-LL | #[allow(uncommon_codepoints)]
- | ^^^^^^^^^^^^^^^^^^^
-
-error: allow(uncommon_codepoints) is ignored unless specified at crate level
- --> $DIR/crate_level_only_lint.rs:17:9
- |
-LL | #[allow(uncommon_codepoints)]
- | ^^^^^^^^^^^^^^^^^^^
-
-error: aborting due to 9 previous errors
+error: aborting due to 6 previous errors
//~| WARNING previously accepted by the compiler
//~| ERROR incompatible with previous
//~| WARNING previously accepted by the compiler
-//~| ERROR incompatible with previous
-//~| WARNING previously accepted by the compiler
-//~| ERROR incompatible with previous
-//~| WARNING previously accepted by the compiler
-//~| ERROR incompatible with previous
-//~| WARNING previously accepted by the compiler
fn main() {}
= warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
= note: for more information, see issue #81670 <https://github.com/rust-lang/rust/issues/81670>
-error: allow(nonstandard_style) incompatible with previous forbid
- --> $DIR/forbid-group-group-2.rs:7:9
- |
-LL | #![forbid(warnings)]
- | -------- `forbid` level set here
-...
-LL | #[allow(nonstandard_style)]
- | ^^^^^^^^^^^^^^^^^ overruled by previous forbid
- |
- = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
- = note: for more information, see issue #81670 <https://github.com/rust-lang/rust/issues/81670>
-
-error: allow(nonstandard_style) incompatible with previous forbid
- --> $DIR/forbid-group-group-2.rs:7:9
- |
-LL | #![forbid(warnings)]
- | -------- `forbid` level set here
-...
-LL | #[allow(nonstandard_style)]
- | ^^^^^^^^^^^^^^^^^ overruled by previous forbid
- |
- = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
- = note: for more information, see issue #81670 <https://github.com/rust-lang/rust/issues/81670>
-
-error: allow(nonstandard_style) incompatible with previous forbid
- --> $DIR/forbid-group-group-2.rs:7:9
- |
-LL | #![forbid(warnings)]
- | -------- `forbid` level set here
-...
-LL | #[allow(nonstandard_style)]
- | ^^^^^^^^^^^^^^^^^ overruled by previous forbid
- |
- = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
- = note: for more information, see issue #81670 <https://github.com/rust-lang/rust/issues/81670>
-
-error: aborting due to 9 previous errors
+error: aborting due to 6 previous errors
//~| WARNING previously accepted
//~| WARNING incompatible with previous forbid
//~| WARNING previously accepted
-//~| WARNING incompatible with previous forbid
-//~| WARNING previously accepted
fn main() {
let a: ();
}
= warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
= note: for more information, see issue #81670 <https://github.com/rust-lang/rust/issues/81670>
-warning: allow(unused_variables) incompatible with previous forbid
- --> $DIR/forbid-group-member.rs:8:9
- |
-LL | #![forbid(unused)]
- | ------ `forbid` level set here
-LL |
-LL | #[allow(unused_variables)]
- | ^^^^^^^^^^^^^^^^ overruled by previous forbid
- |
- = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
- = note: for more information, see issue #81670 <https://github.com/rust-lang/rust/issues/81670>
-
-warning: 4 warnings emitted
+warning: 3 warnings emitted
#[allow(unused)]
//~^ ERROR incompatible with previous forbid
//~| ERROR incompatible with previous forbid
-//~| ERROR incompatible with previous forbid
fn main() {
let a: ();
}
LL | #[allow(unused)]
| ^^^^^^ overruled by previous forbid
-error[E0453]: allow(unused) incompatible with previous forbid
- --> $DIR/forbid-member-group.rs:6:9
- |
-LL | #![forbid(unused_variables)]
- | ---------------- `forbid` level set here
-LL |
-LL | #[allow(unused)]
- | ^^^^^^ overruled by previous forbid
-
-error: aborting due to 3 previous errors
+error: aborting due to 2 previous errors
For more information about this error, try `rustc --explain E0453`.
--- /dev/null
+// compile-flags: --force-warns elided_lifetimes_in_paths -Zunstable-options
+// check-pass
+
+struct Foo<'a> {
+ x: &'a u32,
+}
+
+fn foo(x: &Foo) {}
+//~^ WARN hidden lifetime parameters in types are deprecated
+
+fn main() {}
--- /dev/null
+warning: hidden lifetime parameters in types are deprecated
+ --> $DIR/force-allowed-by-default-lint.rs:8:12
+ |
+LL | fn foo(x: &Foo) {}
+ | ^^^- help: indicate the anonymous lifetime: `<'_>`
+ |
+ = note: warning forced by `force-warns` commandline option
+
+warning: 1 warning emitted
+
--- /dev/null
+// compile-flags: --force-warns const_err -Zunstable-options
+// check-pass
+
+#![allow(const_err)]
+const C: i32 = 1 / 0;
+//~^ WARN any use of this value will cause an error
+//~| WARN this was previously accepted by the compiler
+
+fn main() {}
--- /dev/null
+warning: any use of this value will cause an error
+ --> $DIR/force-allowed-deny-by-default-lint.rs:5:16
+ |
+LL | const C: i32 = 1 / 0;
+ | ---------------^^^^^-
+ | |
+ | attempt to divide `1_i32` by zero
+ |
+ = note: warning forced by `force-warns` commandline option
+ = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
+ = note: for more information, see issue #71800 <https://github.com/rust-lang/rust/issues/71800>
+
+warning: 1 warning emitted
+
--- /dev/null
+// compile-flags: --force-warns dead_code -Zunstable-options
+// check-pass
+
+#![allow(dead_code)]
+
+fn dead_function() {}
+//~^ WARN function is never used
+
+fn main() {}
--- /dev/null
+warning: function is never used: `dead_function`
+ --> $DIR/force-allowed-warning.rs:6:4
+ |
+LL | fn dead_function() {}
+ | ^^^^^^^^^^^^^
+ |
+ = note: warning forced by `force-warns` commandline option
+
+warning: 1 warning emitted
+
--- /dev/null
+// compile-flags: --force-warns const_err -Zunstable-options
+// check-pass
+
+const C: i32 = 1 / 0;
+//~^ WARN any use of this value will cause an error
+//~| WARN this was previously accepted by the compiler
+
+fn main() {}
--- /dev/null
+warning: any use of this value will cause an error
+ --> $DIR/force-deny-by-default-lint.rs:4:16
+ |
+LL | const C: i32 = 1 / 0;
+ | ---------------^^^^^-
+ | |
+ | attempt to divide `1_i32` by zero
+ |
+ = note: warning forced by `force-warns` commandline option
+ = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
+ = note: for more information, see issue #71800 <https://github.com/rust-lang/rust/issues/71800>
+
+warning: 1 warning emitted
+
--- /dev/null
+// compile-flags: --force-warns dead_code -Zunstable-options
+// check-pass
+
+#![allow(warnings)]
+
+fn dead_function() {}
+//~^ WARN function is never used
+
+fn main() {}
--- /dev/null
+warning: function is never used: `dead_function`
+ --> $DIR/force-lint-allow-all-warnings.rs:6:4
+ |
+LL | fn dead_function() {}
+ | ^^^^^^^^^^^^^
+ |
+ = note: warning forced by `force-warns` commandline option
+
+warning: 1 warning emitted
+
--- /dev/null
+// compile-flags: --force-warns nonstandard_style -Zunstable-options
+// check-pass
+
+#![allow(warnings)]
+
+pub fn FUNCTION() {}
+//~^ WARN function `FUNCTION` should have a snake case name
+
+fn main() {}
--- /dev/null
+warning: function `FUNCTION` should have a snake case name
+ --> $DIR/force-lint-group-allow-all-warnings.rs:6:8
+ |
+LL | pub fn FUNCTION() {}
+ | ^^^^^^^^ help: convert the identifier to snake case: `function`
+ |
+ = note: warning forced by `force-warns` commandline option
+
+warning: 1 warning emitted
+
--- /dev/null
+// compile-flags: --force-warns bare_trait_objects -Zunstable-options
+// check-pass
+
+#![allow(rust_2018_idioms)]
+
+pub trait SomeTrait {}
+
+pub fn function(_x: Box<SomeTrait>) {}
+//~^ WARN trait objects without an explicit `dyn` are deprecated
+//~| WARN this was previously accepted by the compiler
+
+fn main() {}
--- /dev/null
+warning: trait objects without an explicit `dyn` are deprecated
+ --> $DIR/force-lint-in-allowed-group.rs:8:25
+ |
+LL | pub fn function(_x: Box<SomeTrait>) {}
+ | ^^^^^^^^^ help: use `dyn`: `dyn SomeTrait`
+ |
+ = note: warning forced by `force-warns` commandline option
+ = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in the 2021 edition!
+ = note: for more information, see issue #80165 <https://github.com/rust-lang/rust/issues/80165>
+
+warning: 1 warning emitted
+
--- /dev/null
+// compile-flags: --force-warns rust-2018-idioms -Zunstable-options
+// check-pass
+
+#![allow(bare_trait_objects)]
+
+pub trait SomeTrait {}
+
+pub fn function(_x: Box<SomeTrait>) {}
+//~^ WARN trait objects without an explicit `dyn` are deprecated
+//~| WARN this was previously accepted by the compiler
+
+fn main() {}
--- /dev/null
+warning: trait objects without an explicit `dyn` are deprecated
+ --> $DIR/force-warn-group-allow-warning.rs:8:25
+ |
+LL | pub fn function(_x: Box<SomeTrait>) {}
+ | ^^^^^^^^^ help: use `dyn`: `dyn SomeTrait`
+ |
+ = note: warning forced by `force-warns` commandline option
+ = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in the 2021 edition!
+ = note: for more information, see issue #80165 <https://github.com/rust-lang/rust/issues/80165>
+
+warning: 1 warning emitted
+
--- /dev/null
+// compile-flags: --force-warns rust_2018_idioms -Zunstable-options
+// check-pass
+
+#![allow(rust_2018_idioms)]
+
+pub trait SomeTrait {}
+
+pub fn function(_x: Box<SomeTrait>) {}
+//~^ WARN trait objects without an explicit `dyn` are deprecated
+//~| WARN this was previously accepted by the compiler
+
+fn main() {}
--- /dev/null
+warning: trait objects without an explicit `dyn` are deprecated
+ --> $DIR/force-warn-group.rs:8:25
+ |
+LL | pub fn function(_x: Box<SomeTrait>) {}
+ | ^^^^^^^^^ help: use `dyn`: `dyn SomeTrait`
+ |
+ = note: warning forced by `force-warns` commandline option
+ = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in the 2021 edition!
+ = note: for more information, see issue #80165 <https://github.com/rust-lang/rust/issues/80165>
+
+warning: 1 warning emitted
+
//~| WARNING being phased out
//~| WARNING incompatible with previous forbid
//~| WARNING being phased out
-//~| WARNING incompatible with previous forbid
-//~| WARNING being phased out
fn main() {}
= warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
= note: for more information, see issue #81670 <https://github.com/rust-lang/rust/issues/81670>
-warning: deny(warnings) incompatible with previous forbid
- --> $DIR/issue-80988.rs:7:8
- |
-LL | #![forbid(warnings)]
- | -------- `forbid` level set here
-LL |
-LL | #[deny(warnings)]
- | ^^^^^^^^ overruled by previous forbid
- |
- = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
- = note: for more information, see issue #81670 <https://github.com/rust-lang/rust/issues/81670>
-
-warning: 4 warnings emitted
+warning: 3 warnings emitted
+// compile-flags: -Zunstable-options
// check-pass
#![warn(rustc::internal)]
warning: unknown lint: `rustc::foo::bar::default_hash_types`
- --> $DIR/issue-83477.rs:4:9
+ --> $DIR/issue-83477.rs:5:9
|
LL | #[allow(rustc::foo::bar::default_hash_types)]
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: did you mean: `rustc::default_hash_types`
= note: `#[warn(unknown_lints)]` on by default
warning: unknown lint: `rustc::foo::default_hash_types`
- --> $DIR/issue-83477.rs:8:9
+ --> $DIR/issue-83477.rs:9:9
|
LL | #[allow(rustc::foo::default_hash_types)]
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: did you mean: `rustc::default_hash_types`
warning: Prefer FxHashMap over HashMap, it has better performance
- --> $DIR/issue-83477.rs:13:31
+ --> $DIR/issue-83477.rs:14:31
|
LL | let _ = std::collections::HashMap::<String, String>::new();
| ^^^^^^^ help: use: `FxHashMap`
|
note: the lint level is defined here
- --> $DIR/issue-83477.rs:2:9
+ --> $DIR/issue-83477.rs:3:9
|
LL | #![warn(rustc::internal)]
| ^^^^^^^^^^^^^^^
use std::default::Default;
use std::marker::PhantomData;
+trait Trait {}
+
trait Mirror { type It: ?Sized; }
impl<T: ?Sized> Mirror for T { type It = Self; }
pub extern "C" fn opt_box_type(p: Option<Box<u32>>) { }
+pub extern "C" fn boxed_slice(p: Box<[u8]>) { }
+//~^ ERROR: uses type `Box<[u8]>`
+
+pub extern "C" fn boxed_string(p: Box<str>) { }
+//~^ ERROR: uses type `Box<str>`
+
+pub extern "C" fn boxed_trait(p: Box<dyn Trait>) { }
+//~^ ERROR: uses type `Box<dyn Trait>`
+
pub extern "C" fn char_type(p: char) { }
//~^ ERROR uses type `char`
error: `extern` fn uses type `[u32]`, which is not FFI-safe
- --> $DIR/lint-ctypes-fn.rs:67:33
+ --> $DIR/lint-ctypes-fn.rs:69:33
|
LL | pub extern "C" fn slice_type(p: &[u32]) { }
| ^^^^^^ not FFI-safe
= note: slices have no C equivalent
error: `extern` fn uses type `str`, which is not FFI-safe
- --> $DIR/lint-ctypes-fn.rs:70:31
+ --> $DIR/lint-ctypes-fn.rs:72:31
|
LL | pub extern "C" fn str_type(p: &str) { }
| ^^^^ not FFI-safe
= help: consider using `*const u8` and a length instead
= note: string slices have no C equivalent
+error: `extern` fn uses type `Box<[u8]>`, which is not FFI-safe
+ --> $DIR/lint-ctypes-fn.rs:79:34
+ |
+LL | pub extern "C" fn boxed_slice(p: Box<[u8]>) { }
+ | ^^^^^^^^^ not FFI-safe
+ |
+ = note: box cannot be represented as a single pointer
+
+error: `extern` fn uses type `Box<str>`, which is not FFI-safe
+ --> $DIR/lint-ctypes-fn.rs:82:35
+ |
+LL | pub extern "C" fn boxed_string(p: Box<str>) { }
+ | ^^^^^^^^ not FFI-safe
+ |
+ = note: box cannot be represented as a single pointer
+
+error: `extern` fn uses type `Box<dyn Trait>`, which is not FFI-safe
+ --> $DIR/lint-ctypes-fn.rs:85:34
+ |
+LL | pub extern "C" fn boxed_trait(p: Box<dyn Trait>) { }
+ | ^^^^^^^^^^^^^^ not FFI-safe
+ |
+ = note: box cannot be represented as a single pointer
+
error: `extern` fn uses type `char`, which is not FFI-safe
- --> $DIR/lint-ctypes-fn.rs:77:32
+ --> $DIR/lint-ctypes-fn.rs:88:32
|
LL | pub extern "C" fn char_type(p: char) { }
| ^^^^ not FFI-safe
= note: the `char` type has no C equivalent
error: `extern` fn uses type `i128`, which is not FFI-safe
- --> $DIR/lint-ctypes-fn.rs:80:32
+ --> $DIR/lint-ctypes-fn.rs:91:32
|
LL | pub extern "C" fn i128_type(p: i128) { }
| ^^^^ not FFI-safe
= note: 128-bit integers don't currently have a known stable ABI
error: `extern` fn uses type `u128`, which is not FFI-safe
- --> $DIR/lint-ctypes-fn.rs:83:32
+ --> $DIR/lint-ctypes-fn.rs:94:32
|
LL | pub extern "C" fn u128_type(p: u128) { }
| ^^^^ not FFI-safe
= note: 128-bit integers don't currently have a known stable ABI
error: `extern` fn uses type `(i32, i32)`, which is not FFI-safe
- --> $DIR/lint-ctypes-fn.rs:86:33
+ --> $DIR/lint-ctypes-fn.rs:97:33
|
LL | pub extern "C" fn tuple_type(p: (i32, i32)) { }
| ^^^^^^^^^^ not FFI-safe
= note: tuples have unspecified layout
error: `extern` fn uses type `(i32, i32)`, which is not FFI-safe
- --> $DIR/lint-ctypes-fn.rs:89:34
+ --> $DIR/lint-ctypes-fn.rs:100:34
|
LL | pub extern "C" fn tuple_type2(p: I32Pair) { }
| ^^^^^^^ not FFI-safe
= note: tuples have unspecified layout
error: `extern` fn uses type `ZeroSize`, which is not FFI-safe
- --> $DIR/lint-ctypes-fn.rs:92:32
+ --> $DIR/lint-ctypes-fn.rs:103:32
|
LL | pub extern "C" fn zero_size(p: ZeroSize) { }
| ^^^^^^^^ not FFI-safe
= help: consider adding a member to this struct
= note: this struct has no fields
note: the type is defined here
- --> $DIR/lint-ctypes-fn.rs:26:1
+ --> $DIR/lint-ctypes-fn.rs:28:1
|
LL | pub struct ZeroSize;
| ^^^^^^^^^^^^^^^^^^^^
error: `extern` fn uses type `ZeroSizeWithPhantomData`, which is not FFI-safe
- --> $DIR/lint-ctypes-fn.rs:95:40
+ --> $DIR/lint-ctypes-fn.rs:106:40
|
LL | pub extern "C" fn zero_size_phantom(p: ZeroSizeWithPhantomData) { }
| ^^^^^^^^^^^^^^^^^^^^^^^ not FFI-safe
|
= note: composed only of `PhantomData`
note: the type is defined here
- --> $DIR/lint-ctypes-fn.rs:61:1
+ --> $DIR/lint-ctypes-fn.rs:63:1
|
LL | pub struct ZeroSizeWithPhantomData(PhantomData<i32>);
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
error: `extern` fn uses type `PhantomData<bool>`, which is not FFI-safe
- --> $DIR/lint-ctypes-fn.rs:98:51
+ --> $DIR/lint-ctypes-fn.rs:109:51
|
LL | pub extern "C" fn zero_size_phantom_toplevel() -> PhantomData<bool> {
| ^^^^^^^^^^^^^^^^^ not FFI-safe
= note: composed only of `PhantomData`
error: `extern` fn uses type `fn()`, which is not FFI-safe
- --> $DIR/lint-ctypes-fn.rs:103:30
+ --> $DIR/lint-ctypes-fn.rs:114:30
|
LL | pub extern "C" fn fn_type(p: RustFn) { }
| ^^^^^^ not FFI-safe
= note: this function pointer has Rust-specific calling convention
error: `extern` fn uses type `fn()`, which is not FFI-safe
- --> $DIR/lint-ctypes-fn.rs:106:31
+ --> $DIR/lint-ctypes-fn.rs:117:31
|
LL | pub extern "C" fn fn_type2(p: fn()) { }
| ^^^^ not FFI-safe
= note: this function pointer has Rust-specific calling convention
error: `extern` fn uses type `i128`, which is not FFI-safe
- --> $DIR/lint-ctypes-fn.rs:111:39
+ --> $DIR/lint-ctypes-fn.rs:122:39
|
LL | pub extern "C" fn transparent_i128(p: TransparentI128) { }
| ^^^^^^^^^^^^^^^ not FFI-safe
= note: 128-bit integers don't currently have a known stable ABI
error: `extern` fn uses type `str`, which is not FFI-safe
- --> $DIR/lint-ctypes-fn.rs:114:38
+ --> $DIR/lint-ctypes-fn.rs:125:38
|
LL | pub extern "C" fn transparent_str(p: TransparentStr) { }
| ^^^^^^^^^^^^^^ not FFI-safe
= note: string slices have no C equivalent
error: `extern` fn uses type `PhantomData<bool>`, which is not FFI-safe
- --> $DIR/lint-ctypes-fn.rs:160:43
+ --> $DIR/lint-ctypes-fn.rs:171:43
|
LL | pub extern "C" fn unused_generic2<T>() -> PhantomData<bool> {
| ^^^^^^^^^^^^^^^^^ not FFI-safe
= note: composed only of `PhantomData`
error: `extern` fn uses type `Vec<T>`, which is not FFI-safe
- --> $DIR/lint-ctypes-fn.rs:173:39
+ --> $DIR/lint-ctypes-fn.rs:184:39
|
LL | pub extern "C" fn used_generic4<T>(x: Vec<T>) { }
| ^^^^^^ not FFI-safe
= note: this struct has unspecified layout
error: `extern` fn uses type `Vec<T>`, which is not FFI-safe
- --> $DIR/lint-ctypes-fn.rs:176:41
+ --> $DIR/lint-ctypes-fn.rs:187:41
|
LL | pub extern "C" fn used_generic5<T>() -> Vec<T> {
| ^^^^^^ not FFI-safe
= help: consider adding a `#[repr(C)]` or `#[repr(transparent)]` attribute to this struct
= note: this struct has unspecified layout
-error: aborting due to 17 previous errors
+error: aborting due to 20 previous errors
#[allow(deprecated)]
//~^ ERROR allow(deprecated) incompatible
//~| ERROR allow(deprecated) incompatible
-//~| ERROR allow(deprecated) incompatible
fn main() {
}
LL | #[allow(deprecated)]
| ^^^^^^^^^^ overruled by previous forbid
-error[E0453]: allow(deprecated) incompatible with previous forbid
- --> $DIR/lint-forbid-attr.rs:3:9
- |
-LL | #![forbid(deprecated)]
- | ---------- `forbid` level set here
-LL |
-LL | #[allow(deprecated)]
- | ^^^^^^^^^^ overruled by previous forbid
-
-error: aborting due to 3 previous errors
+error: aborting due to 2 previous errors
For more information about this error, try `rustc --explain E0453`.
#[allow(deprecated)] //~ ERROR allow(deprecated) incompatible
//~| ERROR allow(deprecated) incompatible
- //~| ERROR allow(deprecated) incompatible
fn main() {
}
|
= note: `forbid` lint level was set on command line
-error[E0453]: allow(deprecated) incompatible with previous forbid
- --> $DIR/lint-forbid-cmdline.rs:3:9
- |
-LL | #[allow(deprecated)]
- | ^^^^^^^^^^ overruled by previous forbid
- |
- = note: `forbid` lint level was set on command line
-
-error: aborting due to 3 previous errors
+error: aborting due to 2 previous errors
For more information about this error, try `rustc --explain E0453`.
//~| ERROR malformed lint attribute
//~| ERROR malformed lint attribute
//~| ERROR malformed lint attribute
- //~| ERROR malformed lint attribute
- //~| ERROR malformed lint attribute
fn main() { }
LL | #![allow(bar = "baz")]
| ^^^^^^^^^^^ bad attribute argument
-error[E0452]: malformed lint attribute input
- --> $DIR/lint-malformed.rs:2:10
- |
-LL | #![allow(bar = "baz")]
- | ^^^^^^^^^^^ bad attribute argument
-
-error[E0452]: malformed lint attribute input
- --> $DIR/lint-malformed.rs:2:10
- |
-LL | #![allow(bar = "baz")]
- | ^^^^^^^^^^^ bad attribute argument
-
-error: aborting due to 7 previous errors
+error: aborting due to 5 previous errors
For more information about this error, try `rustc --explain E0452`.
|
= note: requested on the command line with `-D raw_pointer_derive`
-warning: lint `raw_pointer_derive` has been removed: using derive with raw pointers is ok
- |
- = note: requested on the command line with `-D raw_pointer_derive`
-
error: unused variable: `unused`
--> $DIR/lint-removed-cmdline.rs:12:17
|
| ^^^^^^^^
= note: `#[deny(unused_variables)]` implied by `#[deny(warnings)]`
-error: aborting due to previous error; 4 warnings emitted
+error: aborting due to previous error; 3 warnings emitted
|
= note: requested on the command line with `-D bare_trait_object`
-warning: lint `bare_trait_object` has been renamed to `bare_trait_objects`
- |
- = note: requested on the command line with `-D bare_trait_object`
-
error: unused variable: `unused`
--> $DIR/lint-renamed-cmdline.rs:8:17
|
| ^^^^^^
= note: `#[deny(unused_variables)]` implied by `#[deny(unused)]`
-error: aborting due to previous error; 4 warnings emitted
+error: aborting due to previous error; 3 warnings emitted
|
= note: requested on the command line with `-F private_no_mangle_statics`
-warning: lint `private_no_mangle_fns` has been removed: no longer a warning, `#[no_mangle]` functions always exported
- |
- = note: requested on the command line with `-F private_no_mangle_fns`
-
-warning: lint `private_no_mangle_statics` has been removed: no longer a warning, `#[no_mangle]` statics always exported
- |
- = note: requested on the command line with `-F private_no_mangle_statics`
-
error: const items should never be `#[no_mangle]`
--> $DIR/lint-unexported-no-mangle.rs:9:1
|
| |
| help: try a static value: `pub static`
-error: aborting due to 2 previous errors; 8 warnings emitted
+error: aborting due to 2 previous errors; 6 warnings emitted
= help: did you mean: `dead_code`
= note: requested on the command line with `-D dead_cod`
-error[E0602]: unknown lint: `bogus`
- |
- = note: requested on the command line with `-D bogus`
-
-error[E0602]: unknown lint: `dead_cod`
- |
- = help: did you mean: `dead_code`
- = note: requested on the command line with `-D dead_cod`
-
-error: aborting due to 6 previous errors
+error: aborting due to 4 previous errors
For more information about this error, try `rustc --explain E0602`.
#![warn(absolute_paths_not_starting_with_crate, reason = 0)]
//~^ ERROR malformed lint attribute
//~| ERROR malformed lint attribute
-//~| ERROR malformed lint attribute
-//~| NOTE reason must be a string literal
//~| NOTE reason must be a string literal
//~| NOTE reason must be a string literal
#![warn(anonymous_parameters, reason = b"consider these, for we have condemned them")]
//~^ ERROR malformed lint attribute
//~| ERROR malformed lint attribute
-//~| ERROR malformed lint attribute
-//~| NOTE reason must be a string literal
//~| NOTE reason must be a string literal
//~| NOTE reason must be a string literal
#![warn(bare_trait_objects, reasons = "leaders to no sure land, guides their bearings lost")]
//~| ERROR malformed lint attribute
//~| ERROR malformed lint attribute
//~| ERROR malformed lint attribute
-//~| ERROR malformed lint attribute
-//~| ERROR malformed lint attribute
-//~| NOTE bad attribute argument
-//~| NOTE bad attribute argument
//~| NOTE bad attribute argument
//~| NOTE bad attribute argument
//~| NOTE bad attribute argument
//~| ERROR malformed lint attribute
//~| ERROR malformed lint attribute
//~| ERROR malformed lint attribute
-//~| ERROR malformed lint attribute
-//~| ERROR malformed lint attribute
-//~| NOTE bad attribute argument
-//~| NOTE bad attribute argument
//~| NOTE bad attribute argument
//~| NOTE bad attribute argument
//~| NOTE bad attribute argument
//~| ERROR malformed lint attribute
//~| ERROR malformed lint attribute
//~| ERROR malformed lint attribute
-//~| ERROR malformed lint attribute
-//~| ERROR malformed lint attribute
-//~| NOTE bad attribute argument
-//~| NOTE bad attribute argument
//~| NOTE bad attribute argument
//~| NOTE bad attribute argument
//~| NOTE bad attribute argument
#![warn(ellipsis_inclusive_range_patterns, reason = "born barren", reason = "a freak growth")]
//~^ ERROR malformed lint attribute
//~| ERROR malformed lint attribute
-//~| ERROR malformed lint attribute
-//~| NOTE reason in lint attribute must come last
//~| NOTE reason in lint attribute must come last
//~| NOTE reason in lint attribute must come last
#![warn(keyword_idents, reason = "root in rubble", macro_use_extern_crate)]
//~^ ERROR malformed lint attribute
//~| ERROR malformed lint attribute
-//~| ERROR malformed lint attribute
-//~| NOTE reason in lint attribute must come last
//~| NOTE reason in lint attribute must come last
//~| NOTE reason in lint attribute must come last
#![warn(missing_copy_implementations, reason)]
| ^ reason must be a string literal
error[E0452]: malformed lint attribute input
- --> $DIR/reasons-erroneous.rs:10:40
+ --> $DIR/reasons-erroneous.rs:8:40
|
LL | #![warn(anonymous_parameters, reason = b"consider these, for we have condemned them")]
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ reason must be a string literal
error[E0452]: malformed lint attribute input
- --> $DIR/reasons-erroneous.rs:17:29
+ --> $DIR/reasons-erroneous.rs:13:29
|
LL | #![warn(bare_trait_objects, reasons = "leaders to no sure land, guides their bearings lost")]
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ bad attribute argument
error[E0452]: malformed lint attribute input
- --> $DIR/reasons-erroneous.rs:17:29
+ --> $DIR/reasons-erroneous.rs:13:29
|
LL | #![warn(bare_trait_objects, reasons = "leaders to no sure land, guides their bearings lost")]
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ bad attribute argument
error[E0452]: malformed lint attribute input
- --> $DIR/reasons-erroneous.rs:30:23
+ --> $DIR/reasons-erroneous.rs:22:23
|
LL | #![warn(box_pointers, blerp = "or in league with robbers have reversed the signposts")]
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ bad attribute argument
error[E0452]: malformed lint attribute input
- --> $DIR/reasons-erroneous.rs:30:23
+ --> $DIR/reasons-erroneous.rs:22:23
|
LL | #![warn(box_pointers, blerp = "or in league with robbers have reversed the signposts")]
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ bad attribute argument
error[E0452]: malformed lint attribute input
- --> $DIR/reasons-erroneous.rs:43:36
+ --> $DIR/reasons-erroneous.rs:31:36
|
LL | #![warn(elided_lifetimes_in_paths, reason("disrespectful to ancestors", "irresponsible to heirs"))]
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ bad attribute argument
error[E0452]: malformed lint attribute input
- --> $DIR/reasons-erroneous.rs:43:36
+ --> $DIR/reasons-erroneous.rs:31:36
|
LL | #![warn(elided_lifetimes_in_paths, reason("disrespectful to ancestors", "irresponsible to heirs"))]
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ bad attribute argument
error[E0452]: malformed lint attribute input
- --> $DIR/reasons-erroneous.rs:56:44
+ --> $DIR/reasons-erroneous.rs:40:44
|
LL | #![warn(ellipsis_inclusive_range_patterns, reason = "born barren", reason = "a freak growth")]
| ^^^^^^^^^^^^^^^^^^^^^^ reason in lint attribute must come last
error[E0452]: malformed lint attribute input
- --> $DIR/reasons-erroneous.rs:63:25
+ --> $DIR/reasons-erroneous.rs:45:25
|
LL | #![warn(keyword_idents, reason = "root in rubble", macro_use_extern_crate)]
| ^^^^^^^^^^^^^^^^^^^^^^^^^ reason in lint attribute must come last
warning: unknown lint: `reason`
- --> $DIR/reasons-erroneous.rs:70:39
+ --> $DIR/reasons-erroneous.rs:50:39
|
LL | #![warn(missing_copy_implementations, reason)]
| ^^^^^^
| ^ reason must be a string literal
error[E0452]: malformed lint attribute input
- --> $DIR/reasons-erroneous.rs:10:40
+ --> $DIR/reasons-erroneous.rs:8:40
|
LL | #![warn(anonymous_parameters, reason = b"consider these, for we have condemned them")]
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ reason must be a string literal
error[E0452]: malformed lint attribute input
- --> $DIR/reasons-erroneous.rs:17:29
+ --> $DIR/reasons-erroneous.rs:13:29
|
LL | #![warn(bare_trait_objects, reasons = "leaders to no sure land, guides their bearings lost")]
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ bad attribute argument
error[E0452]: malformed lint attribute input
- --> $DIR/reasons-erroneous.rs:17:29
+ --> $DIR/reasons-erroneous.rs:13:29
|
LL | #![warn(bare_trait_objects, reasons = "leaders to no sure land, guides their bearings lost")]
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ bad attribute argument
error[E0452]: malformed lint attribute input
- --> $DIR/reasons-erroneous.rs:30:23
+ --> $DIR/reasons-erroneous.rs:22:23
|
LL | #![warn(box_pointers, blerp = "or in league with robbers have reversed the signposts")]
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ bad attribute argument
error[E0452]: malformed lint attribute input
- --> $DIR/reasons-erroneous.rs:30:23
+ --> $DIR/reasons-erroneous.rs:22:23
|
LL | #![warn(box_pointers, blerp = "or in league with robbers have reversed the signposts")]
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ bad attribute argument
error[E0452]: malformed lint attribute input
- --> $DIR/reasons-erroneous.rs:43:36
+ --> $DIR/reasons-erroneous.rs:31:36
|
LL | #![warn(elided_lifetimes_in_paths, reason("disrespectful to ancestors", "irresponsible to heirs"))]
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ bad attribute argument
error[E0452]: malformed lint attribute input
- --> $DIR/reasons-erroneous.rs:43:36
+ --> $DIR/reasons-erroneous.rs:31:36
|
LL | #![warn(elided_lifetimes_in_paths, reason("disrespectful to ancestors", "irresponsible to heirs"))]
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ bad attribute argument
error[E0452]: malformed lint attribute input
- --> $DIR/reasons-erroneous.rs:56:44
+ --> $DIR/reasons-erroneous.rs:40:44
|
LL | #![warn(ellipsis_inclusive_range_patterns, reason = "born barren", reason = "a freak growth")]
| ^^^^^^^^^^^^^^^^^^^^^^ reason in lint attribute must come last
error[E0452]: malformed lint attribute input
- --> $DIR/reasons-erroneous.rs:63:25
+ --> $DIR/reasons-erroneous.rs:45:25
|
LL | #![warn(keyword_idents, reason = "root in rubble", macro_use_extern_crate)]
| ^^^^^^^^^^^^^^^^^^^^^^^^^ reason in lint attribute must come last
-error[E0452]: malformed lint attribute input
- --> $DIR/reasons-erroneous.rs:3:58
- |
-LL | #![warn(absolute_paths_not_starting_with_crate, reason = 0)]
- | ^ reason must be a string literal
-
-error[E0452]: malformed lint attribute input
- --> $DIR/reasons-erroneous.rs:10:40
- |
-LL | #![warn(anonymous_parameters, reason = b"consider these, for we have condemned them")]
- | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ reason must be a string literal
-
-error[E0452]: malformed lint attribute input
- --> $DIR/reasons-erroneous.rs:17:29
- |
-LL | #![warn(bare_trait_objects, reasons = "leaders to no sure land, guides their bearings lost")]
- | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ bad attribute argument
-
-error[E0452]: malformed lint attribute input
- --> $DIR/reasons-erroneous.rs:17:29
- |
-LL | #![warn(bare_trait_objects, reasons = "leaders to no sure land, guides their bearings lost")]
- | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ bad attribute argument
-
-error[E0452]: malformed lint attribute input
- --> $DIR/reasons-erroneous.rs:30:23
- |
-LL | #![warn(box_pointers, blerp = "or in league with robbers have reversed the signposts")]
- | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ bad attribute argument
-
-error[E0452]: malformed lint attribute input
- --> $DIR/reasons-erroneous.rs:30:23
- |
-LL | #![warn(box_pointers, blerp = "or in league with robbers have reversed the signposts")]
- | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ bad attribute argument
-
-error[E0452]: malformed lint attribute input
- --> $DIR/reasons-erroneous.rs:43:36
- |
-LL | #![warn(elided_lifetimes_in_paths, reason("disrespectful to ancestors", "irresponsible to heirs"))]
- | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ bad attribute argument
-
-error[E0452]: malformed lint attribute input
- --> $DIR/reasons-erroneous.rs:43:36
- |
-LL | #![warn(elided_lifetimes_in_paths, reason("disrespectful to ancestors", "irresponsible to heirs"))]
- | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ bad attribute argument
-
-error[E0452]: malformed lint attribute input
- --> $DIR/reasons-erroneous.rs:56:44
- |
-LL | #![warn(ellipsis_inclusive_range_patterns, reason = "born barren", reason = "a freak growth")]
- | ^^^^^^^^^^^^^^^^^^^^^^ reason in lint attribute must come last
-
-error[E0452]: malformed lint attribute input
- --> $DIR/reasons-erroneous.rs:63:25
- |
-LL | #![warn(keyword_idents, reason = "root in rubble", macro_use_extern_crate)]
- | ^^^^^^^^^^^^^^^^^^^^^^^^^ reason in lint attribute must come last
-
-error: aborting due to 30 previous errors; 1 warning emitted
+error: aborting due to 20 previous errors; 1 warning emitted
For more information about this error, try `rustc --explain E0452`.
//~| HELP add `#![register_tool(abc)]`
//~| ERROR unknown tool name `abc`
//~| HELP add `#![register_tool(abc)]`
-//~| ERROR unknown tool name `abc`
-//~| HELP add `#![register_tool(abc)]`
|
= help: add `#![register_tool(abc)]` to the crate root
-error[E0710]: unknown tool name `abc` found in scoped lint: `abc::my_lint`
- --> $DIR/register-tool-lint.rs:5:9
- |
-LL | #![warn(abc::my_lint)]
- | ^^^
- |
- = help: add `#![register_tool(abc)]` to the crate root
-
-error: aborting due to 3 previous errors
+error: aborting due to 2 previous errors
For more information about this error, try `rustc --explain E0710`.
-{
- "message": "cannot find type `Iter` in this scope",
- "code": {
- "code": "E0412",
- "explanation": "A used type name is not in scope.
+{"message":"`--error-format=pretty-json` is unstable","code":null,"level":"error","spans":[],"children":[],"rendered":"\u001b[0m\u001b[1m\u001b[38;5;9merror\u001b[0m\u001b[0m\u001b[1m: `--error-format=pretty-json` is unstable\u001b[0m
-Erroneous code examples:
-
-```compile_fail,E0412
-impl Something {} // error: type name `Something` is not in scope
-
-// or:
-
-trait Foo {
- fn bar(N); // error: type name `N` is not in scope
-}
-
-// or:
-
-fn foo(x: T) {} // type name `T` is not in scope
-```
-
-To fix this error, please verify you didn't misspell the type name, you did
-declare it or imported it into the scope. Examples:
-
-```
-struct Something;
-
-impl Something {} // ok!
-
-// or:
-
-trait Foo {
- type N;
-
- fn bar(_: Self::N); // ok!
-}
-
-// or:
-
-fn foo<T>(x: T) {} // ok!
-```
-
-Another case that causes this error is when a type is imported into a parent
-module. To fix this, you can follow the suggestion and use File directly or
-`use super::File;` which will import the types from the parent namespace. An
-example that causes this error is below:
-
-```compile_fail,E0412
-use std::fs::File;
-
-mod foo {
- fn some_function(f: File) {}
-}
-```
-
-```
-use std::fs::File;
-
-mod foo {
- // either
- use super::File;
- // or
- // use std::fs::File;
- fn foo(f: File) {}
-}
-# fn main() {} // don't insert it for us; that'll break imports
-```
-"
- },
- "level": "error",
- "spans": [
- {
- "file_name": "$DIR/use_suggestion_json.rs",
- "byte_start": 541,
- "byte_end": 545,
- "line_start": 12,
- "line_end": 12,
- "column_start": 12,
- "column_end": 16,
- "is_primary": true,
- "text": [
- {
- "text": " let x: Iter;",
- "highlight_start": 12,
- "highlight_end": 16
- }
- ],
- "label": "not found in this scope",
- "suggested_replacement": null,
- "suggestion_applicability": null,
- "expansion": null
- }
- ],
- "children": [
- {
- "message": "consider importing one of these items",
- "code": null,
- "level": "help",
- "spans": [
- {
- "file_name": "$DIR/use_suggestion_json.rs",
- "byte_start": 518,
- "byte_end": 518,
- "line_start": 11,
- "line_end": 11,
- "column_start": 1,
- "column_end": 1,
- "is_primary": true,
- "text": [
- {
- "text": "fn main() {",
- "highlight_start": 1,
- "highlight_end": 1
- }
- ],
- "label": null,
- "suggested_replacement": "use std::collections::binary_heap::Iter;
-
-",
- "suggestion_applicability": "Unspecified",
- "expansion": null
- },
- {
- "file_name": "$DIR/use_suggestion_json.rs",
- "byte_start": 518,
- "byte_end": 518,
- "line_start": 11,
- "line_end": 11,
- "column_start": 1,
- "column_end": 1,
- "is_primary": true,
- "text": [
- {
- "text": "fn main() {",
- "highlight_start": 1,
- "highlight_end": 1
- }
- ],
- "label": null,
- "suggested_replacement": "use std::collections::btree_map::Iter;
-
-",
- "suggestion_applicability": "Unspecified",
- "expansion": null
- },
- {
- "file_name": "$DIR/use_suggestion_json.rs",
- "byte_start": 518,
- "byte_end": 518,
- "line_start": 11,
- "line_end": 11,
- "column_start": 1,
- "column_end": 1,
- "is_primary": true,
- "text": [
- {
- "text": "fn main() {",
- "highlight_start": 1,
- "highlight_end": 1
- }
- ],
- "label": null,
- "suggested_replacement": "use std::collections::btree_set::Iter;
-
-",
- "suggestion_applicability": "Unspecified",
- "expansion": null
- },
- {
- "file_name": "$DIR/use_suggestion_json.rs",
- "byte_start": 518,
- "byte_end": 518,
- "line_start": 11,
- "line_end": 11,
- "column_start": 1,
- "column_end": 1,
- "is_primary": true,
- "text": [
- {
- "text": "fn main() {",
- "highlight_start": 1,
- "highlight_end": 1
- }
- ],
- "label": null,
- "suggested_replacement": "use std::collections::hash_map::Iter;
-
-",
- "suggestion_applicability": "Unspecified",
- "expansion": null
- },
- {
- "file_name": "$DIR/use_suggestion_json.rs",
- "byte_start": 518,
- "byte_end": 518,
- "line_start": 11,
- "line_end": 11,
- "column_start": 1,
- "column_end": 1,
- "is_primary": true,
- "text": [
- {
- "text": "fn main() {",
- "highlight_start": 1,
- "highlight_end": 1
- }
- ],
- "label": null,
- "suggested_replacement": "use std::collections::hash_set::Iter;
-
-",
- "suggestion_applicability": "Unspecified",
- "expansion": null
- },
- {
- "file_name": "$DIR/use_suggestion_json.rs",
- "byte_start": 518,
- "byte_end": 518,
- "line_start": 11,
- "line_end": 11,
- "column_start": 1,
- "column_end": 1,
- "is_primary": true,
- "text": [
- {
- "text": "fn main() {",
- "highlight_start": 1,
- "highlight_end": 1
- }
- ],
- "label": null,
- "suggested_replacement": "use std::collections::linked_list::Iter;
-
-",
- "suggestion_applicability": "Unspecified",
- "expansion": null
- },
- {
- "file_name": "$DIR/use_suggestion_json.rs",
- "byte_start": 518,
- "byte_end": 518,
- "line_start": 11,
- "line_end": 11,
- "column_start": 1,
- "column_end": 1,
- "is_primary": true,
- "text": [
- {
- "text": "fn main() {",
- "highlight_start": 1,
- "highlight_end": 1
- }
- ],
- "label": null,
- "suggested_replacement": "use std::collections::vec_deque::Iter;
-
-",
- "suggestion_applicability": "Unspecified",
- "expansion": null
- },
- {
- "file_name": "$DIR/use_suggestion_json.rs",
- "byte_start": 518,
- "byte_end": 518,
- "line_start": 11,
- "line_end": 11,
- "column_start": 1,
- "column_end": 1,
- "is_primary": true,
- "text": [
- {
- "text": "fn main() {",
- "highlight_start": 1,
- "highlight_end": 1
- }
- ],
- "label": null,
- "suggested_replacement": "use std::option::Iter;
-
-",
- "suggestion_applicability": "Unspecified",
- "expansion": null
- },
- {
- "file_name": "$DIR/use_suggestion_json.rs",
- "byte_start": 518,
- "byte_end": 518,
- "line_start": 11,
- "line_end": 11,
- "column_start": 1,
- "column_end": 1,
- "is_primary": true,
- "text": [
- {
- "text": "fn main() {",
- "highlight_start": 1,
- "highlight_end": 1
- }
- ],
- "label": null,
- "suggested_replacement": "use std::path::Iter;
-
-",
- "suggestion_applicability": "Unspecified",
- "expansion": null
- },
- {
- "file_name": "$DIR/use_suggestion_json.rs",
- "byte_start": 518,
- "byte_end": 518,
- "line_start": 11,
- "line_end": 11,
- "column_start": 1,
- "column_end": 1,
- "is_primary": true,
- "text": [
- {
- "text": "fn main() {",
- "highlight_start": 1,
- "highlight_end": 1
- }
- ],
- "label": null,
- "suggested_replacement": "use std::result::Iter;
-
-",
- "suggestion_applicability": "Unspecified",
- "expansion": null
- },
- {
- "file_name": "$DIR/use_suggestion_json.rs",
- "byte_start": 518,
- "byte_end": 518,
- "line_start": 11,
- "line_end": 11,
- "column_start": 1,
- "column_end": 1,
- "is_primary": true,
- "text": [
- {
- "text": "fn main() {",
- "highlight_start": 1,
- "highlight_end": 1
- }
- ],
- "label": null,
- "suggested_replacement": "use std::slice::Iter;
-
-",
- "suggestion_applicability": "Unspecified",
- "expansion": null
- },
- {
- "file_name": "$DIR/use_suggestion_json.rs",
- "byte_start": 518,
- "byte_end": 518,
- "line_start": 11,
- "line_end": 11,
- "column_start": 1,
- "column_end": 1,
- "is_primary": true,
- "text": [
- {
- "text": "fn main() {",
- "highlight_start": 1,
- "highlight_end": 1
- }
- ],
- "label": null,
- "suggested_replacement": "use std::sync::mpsc::Iter;
-
-",
- "suggestion_applicability": "Unspecified",
- "expansion": null
- }
- ],
- "children": [],
- "rendered": null
- }
- ],
- "rendered": "\u001b[0m\u001b[1m\u001b[38;5;9merror[E0412]\u001b[0m\u001b[0m\u001b[1m: cannot find type `Iter` in this scope\u001b[0m
-\u001b[0m \u001b[0m\u001b[0m\u001b[1m\u001b[38;5;12m--> \u001b[0m\u001b[0m$DIR/use_suggestion_json.rs:12:12\u001b[0m
-\u001b[0m \u001b[0m\u001b[0m\u001b[1m\u001b[38;5;12m|\u001b[0m
-\u001b[0m\u001b[1m\u001b[38;5;12mLL\u001b[0m\u001b[0m \u001b[0m\u001b[0m\u001b[1m\u001b[38;5;12m| \u001b[0m\u001b[0m let x: Iter;\u001b[0m
-\u001b[0m \u001b[0m\u001b[0m\u001b[1m\u001b[38;5;12m| \u001b[0m\u001b[0m \u001b[0m\u001b[0m\u001b[1m\u001b[38;5;9m^^^^\u001b[0m\u001b[0m \u001b[0m\u001b[0m\u001b[1m\u001b[38;5;9mnot found in this scope\u001b[0m
-\u001b[0m \u001b[0m\u001b[0m\u001b[1m\u001b[38;5;12m|\u001b[0m
-\u001b[0m\u001b[1m\u001b[38;5;14mhelp\u001b[0m\u001b[0m: consider importing one of these items\u001b[0m
-\u001b[0m \u001b[0m\u001b[0m\u001b[1m\u001b[38;5;12m|\u001b[0m
-\u001b[0m\u001b[1m\u001b[38;5;12mLL\u001b[0m\u001b[0m \u001b[0m\u001b[0m\u001b[1m\u001b[38;5;12m| \u001b[0m\u001b[0muse std::collections::binary_heap::Iter;\u001b[0m
-\u001b[0m \u001b[0m\u001b[0m\u001b[1m\u001b[38;5;12m|\u001b[0m
-\u001b[0m\u001b[1m\u001b[38;5;12mLL\u001b[0m\u001b[0m \u001b[0m\u001b[0m\u001b[1m\u001b[38;5;12m| \u001b[0m\u001b[0muse std::collections::btree_map::Iter;\u001b[0m
-\u001b[0m \u001b[0m\u001b[0m\u001b[1m\u001b[38;5;12m|\u001b[0m
-\u001b[0m\u001b[1m\u001b[38;5;12mLL\u001b[0m\u001b[0m \u001b[0m\u001b[0m\u001b[1m\u001b[38;5;12m| \u001b[0m\u001b[0muse std::collections::btree_set::Iter;\u001b[0m
-\u001b[0m \u001b[0m\u001b[0m\u001b[1m\u001b[38;5;12m|\u001b[0m
-\u001b[0m\u001b[1m\u001b[38;5;12mLL\u001b[0m\u001b[0m \u001b[0m\u001b[0m\u001b[1m\u001b[38;5;12m| \u001b[0m\u001b[0muse std::collections::hash_map::Iter;\u001b[0m
-\u001b[0m \u001b[0m\u001b[0m\u001b[1m\u001b[38;5;12m|\u001b[0m
-\u001b[0m and 8 other candidates\u001b[0m
-
-"
-}
-{
- "message": "aborting due to previous error",
- "code": null,
- "level": "error",
- "spans": [],
- "children": [],
- "rendered": "\u001b[0m\u001b[1m\u001b[38;5;9merror\u001b[0m\u001b[0m\u001b[1m: aborting due to previous error\u001b[0m
-
-"
-}
-{
- "message": "For more information about this error, try `rustc --explain E0412`.",
- "code": null,
- "level": "failure-note",
- "spans": [],
- "children": [],
- "rendered": "\u001b[0m\u001b[1mFor more information about this error, try `rustc --explain E0412`.\u001b[0m
-"
-}
+"}
// compile-flags: -C lto
// no-prefer-dynamic
// ignore-emscripten no threads support
+// revisions: mir thir
+// [thir]compile-flags: -Zthir-unsafeck
use std::thread;
--- /dev/null
+// edition:2018
+
+#[macro_export]
+macro_rules! custom_matches {
+ ($expression:expr, $( $pattern:pat )|+ $( if $guard: expr )? $(,)?) => {
+ match $expression {
+ $( $pattern )|+ $( if $guard )? => true,
+ _ => false
+ }
+ }
+}
--- /dev/null
+// edition:2021
+// check-pass
+// aux-build: foreign-crate-macro-pat.rs
+//
+// Tests that the edition of the foreign crate is used
+// when determining the behavior of the `:pat` matcher.
+
+extern crate foreign_crate_macro_pat;
+
+fn main() {
+ let _b = foreign_crate_macro_pat::custom_matches!(b'3', b'0' ..= b'9');
+}
--- /dev/null
+// edition:2021
+// check-pass
+//
+// Regression test for issue #84429
+// Tests that we can properly invoke `matches!` from a 2021-edition crate.
+
+fn main() {
+ let _b = matches!(b'3', b'0' ..= b'9');
+}
-error: local ambiguity: multiple parsing options: built-in NTs ident ('i') or ident ('j').
+error: local ambiguity when calling macro `ambiguity`: multiple parsing options: built-in NTs ident ('i') or ident ('j').
--> $DIR/local-ambiguity-multiple-parsing-options.rs:7:12
|
LL | ambiguity!(error);
| ^^^^^
-error: local ambiguity: multiple parsing options: built-in NTs ident ('i') or ident ('j').
+error: local ambiguity when calling macro `ambiguity`: multiple parsing options: built-in NTs ident ('i') or ident ('j').
--> $DIR/local-ambiguity-multiple-parsing-options.rs:8:12
|
LL | ambiguity!(error);
--- /dev/null
+// compile-flags:-l raw-dylib=foo
+// error-pattern: unknown library kind `raw-dylib`, expected one of dylib, framework, or static
+
+fn main() {
+}
--- /dev/null
+error: unknown library kind `raw-dylib`, expected one of dylib, framework, or static
+
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ returning this value requires that `'a` must outlive `'b`
|
= help: consider adding the following bound: `'a: 'b`
+ = note: requirement occurs because of a mutable reference to &i32
+ = note: mutable references are invariant over their type parameter
+ = help: see <https://doc.rust-lang.org/nomicon/subtyping.html> for more information about variance
error: aborting due to previous error
| ^ returning this value requires that `'a` must outlive `'b`
|
= help: consider adding the following bound: `'a: 'b`
+ = note: requirement occurs because of a mutable reference to &i32
+ = note: mutable references are invariant over their type parameter
+ = help: see <https://doc.rust-lang.org/nomicon/subtyping.html> for more information about variance
error: aborting due to previous error
--- /dev/null
+// run-pass
+// edition:2021
+// compile-flags: -Zunstable-options
+
+// regression test for https://github.com/rust-lang/rust/pull/85678
+
+#![feature(assert_matches)]
+
+fn main() {
+ assert!(matches!((), ()));
+ assert_matches!((), ());
+}
--- /dev/null
+// Test for issue 81576
+// Remove generic arguments if no method is found for all possible generic argument
+
+use std::marker::PhantomData;
+
+struct Wrapper2<'a, T, const C: usize> {
+ x: &'a T,
+}
+
+impl<'a, const C: usize> Wrapper2<'a, i8, C> {
+ fn method(&self) {}
+}
+
+impl<'a, const C: usize> Wrapper2<'a, i16, C> {
+ fn method(&self) {}
+}
+
+impl<'a, const C: usize> Wrapper2<'a, i32, C> {
+ fn method(&self) {}
+}
+struct Wrapper<T>(T);
+
+impl Wrapper<i8> {
+ fn method(&self) {}
+}
+
+impl Wrapper<i16> {
+ fn method(&self) {}
+}
+
+impl Wrapper<i32> {
+ fn method(&self) {}
+}
+
+impl Wrapper<i64> {
+ fn method(&self) {}
+}
+
+impl Wrapper<u8> {
+ fn method(&self) {}
+}
+
+impl Wrapper<u16> {
+ fn method(&self) {}
+}
+
+struct Point<T> {
+ x: T,
+ y: T,
+}
+
+impl Point<f64> {
+ fn distance(&self) -> f64 {
+ self.x.hypot(self.y)
+ }
+}
+
+struct Other;
+
+impl Other {
+ fn other(&self) {}
+}
+
+struct Struct<T>{
+ _phatom: PhantomData<T>
+}
+
+impl<T> Default for Struct<T> {
+ fn default() -> Self {
+ Self{ _phatom: PhantomData }
+ }
+}
+
+impl<T: Clone + Copy + PartialEq + Eq + PartialOrd + Ord> Struct<T> {
+ fn method(&self) {}
+}
+
+fn main() {
+ let point_f64 = Point{ x: 1_f64, y: 1_f64};
+ let d = point_f64.distance();
+ let point_i32 = Point{ x: 1_i32, y: 1_i32};
+ let d = point_i32.distance();
+ //~^ ERROR no method named `distance` found for struct `Point<i32>
+ let d = point_i32.other();
+ //~^ ERROR no method named `other` found for struct `Point
+ let v = vec![1_i32, 2, 3];
+ v.iter().map(|x| x * x).extend(std::iter::once(100));
+ //~^ ERROR no method named `extend` found for struct `Map
+ let wrapper = Wrapper(true);
+ wrapper.method();
+ //~^ ERROR no method named `method` found for struct `Wrapper<bool>
+ wrapper.other();
+ //~^ ERROR no method named `other` found for struct `Wrapper
+ let boolean = true;
+ let wrapper = Wrapper2::<'_, _, 3> {x: &boolean};
+ wrapper.method();
+ //~^ ERROR no method named `method` found for struct `Wrapper2<'_, bool, 3_usize>
+ wrapper.other();
+ //~^ ERROR no method named `other` found for struct `Wrapper2
+ let a = vec![1, 2, 3];
+ a.not_found();
+ //~^ ERROR no method named `not_found` found for struct `Vec
+ let s = Struct::<f64>::default();
+ s.method();
+ //~^ ERROR the method `method` exists for struct `Struct<f64>`, but its trait bounds were not satisfied
+}
--- /dev/null
+error[E0599]: no method named `distance` found for struct `Point<i32>` in the current scope
+ --> $DIR/method-not-found-generic-arg-elision.rs:82:23
+ |
+LL | struct Point<T> {
+ | --------------- method `distance` not found for this
+...
+LL | let d = point_i32.distance();
+ | ^^^^^^^^ method not found in `Point<i32>`
+ |
+ = note: the method was found for
+ - `Point<f64>`
+
+error[E0599]: no method named `other` found for struct `Point` in the current scope
+ --> $DIR/method-not-found-generic-arg-elision.rs:84:23
+ |
+LL | struct Point<T> {
+ | --------------- method `other` not found for this
+...
+LL | let d = point_i32.other();
+ | ^^^^^ method not found in `Point<i32>`
+
+error[E0599]: no method named `extend` found for struct `Map` in the current scope
+ --> $DIR/method-not-found-generic-arg-elision.rs:87:29
+ |
+LL | v.iter().map(|x| x * x).extend(std::iter::once(100));
+ | ^^^^^^ method not found in `Map<std::slice::Iter<'_, i32>, [closure@$DIR/method-not-found-generic-arg-elision.rs:87:18: 87:27]>`
+
+error[E0599]: no method named `method` found for struct `Wrapper<bool>` in the current scope
+ --> $DIR/method-not-found-generic-arg-elision.rs:90:13
+ |
+LL | struct Wrapper<T>(T);
+ | --------------------- method `method` not found for this
+...
+LL | wrapper.method();
+ | ^^^^^^ method not found in `Wrapper<bool>`
+ |
+ = note: the method was found for
+ - `Wrapper<i8>`
+ - `Wrapper<i16>`
+ - `Wrapper<i32>`
+ - `Wrapper<i64>`
+ and 2 more types
+
+error[E0599]: no method named `other` found for struct `Wrapper` in the current scope
+ --> $DIR/method-not-found-generic-arg-elision.rs:92:13
+ |
+LL | struct Wrapper<T>(T);
+ | --------------------- method `other` not found for this
+...
+LL | wrapper.other();
+ | ^^^^^ method not found in `Wrapper<bool>`
+
+error[E0599]: no method named `method` found for struct `Wrapper2<'_, bool, 3_usize>` in the current scope
+ --> $DIR/method-not-found-generic-arg-elision.rs:96:13
+ |
+LL | struct Wrapper2<'a, T, const C: usize> {
+ | -------------------------------------- method `method` not found for this
+...
+LL | wrapper.method();
+ | ^^^^^^ method not found in `Wrapper2<'_, bool, 3_usize>`
+ |
+ = note: the method was found for
+ - `Wrapper2<'a, i8, C>`
+ - `Wrapper2<'a, i16, C>`
+ - `Wrapper2<'a, i32, C>`
+
+error[E0599]: no method named `other` found for struct `Wrapper2` in the current scope
+ --> $DIR/method-not-found-generic-arg-elision.rs:98:13
+ |
+LL | struct Wrapper2<'a, T, const C: usize> {
+ | -------------------------------------- method `other` not found for this
+...
+LL | wrapper.other();
+ | ^^^^^ method not found in `Wrapper2<'_, bool, 3_usize>`
+
+error[E0599]: no method named `not_found` found for struct `Vec<{integer}>` in the current scope
+ --> $DIR/method-not-found-generic-arg-elision.rs:101:7
+ |
+LL | a.not_found();
+ | ^^^^^^^^^ method not found in `Vec<{integer}>`
+
+error[E0599]: the method `method` exists for struct `Struct<f64>`, but its trait bounds were not satisfied
+ --> $DIR/method-not-found-generic-arg-elision.rs:104:7
+ |
+LL | struct Struct<T>{
+ | ---------------- method `method` not found for this
+...
+LL | s.method();
+ | ^^^^^^ method cannot be called on `Struct<f64>` due to unsatisfied trait bounds
+ |
+ = note: the following trait bounds were not satisfied:
+ `f64: Eq`
+ `f64: Ord`
+
+error: aborting due to 9 previous errors
+
+For more information about this error, try `rustc --explain E0599`.
-error[E0080]: evaluation of constant value failed
+error[E0080]: evaluation of `Inline::<dyn std::fmt::Debug>::{constant#0}` failed
--> $SRC_DIR/core/src/mem/mod.rs:LL:COL
|
LL | intrinsics::size_of::<T>()
= note: the following trait bounds were not satisfied:
`dyn Debug: Sized`
-error[E0080]: evaluation of constant value failed
+error[E0080]: evaluation of `Inline::<dyn std::fmt::Debug>::{constant#0}` failed
--> $SRC_DIR/core/src/mem/mod.rs:LL:COL
|
LL | intrinsics::size_of::<T>()
fn main() {}
fn foo(_: Bar, ...) -> impl {}
-//~^ ERROR only foreign or `unsafe extern "C" functions may be C-variadic
+//~^ ERROR only foreign or `unsafe extern "C"` functions may be C-variadic
//~| ERROR cannot find type `Bar` in this scope
//~| ERROR at least one trait must be specified
-error: only foreign or `unsafe extern "C" functions may be C-variadic
+error: only foreign or `unsafe extern "C"` functions may be C-variadic
--> $DIR/issue-83499-input-output-iteration-ice.rs:7:16
|
LL | fn foo(_: Bar, ...) -> impl {}
--> $DIR/cast-rfc0401.rs:29:13
|
LL | let _ = v as &u8;
- | ^^^^^^^^ an `as` expression can only be used to convert between primitive types or to coerce to a specific trait object
+ | ^^^^^^^^ invalid cast
+ |
+help: consider borrowing the value
+ |
+LL | let _ = &*v as &u8;
+ | ^^
error[E0605]: non-primitive cast: `*const u8` as `E`
--> $DIR/cast-rfc0401.rs:30:13
| ^ 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`
+ = note: requirement occurs because of a mutable pointer to &i32
+ = note: mutable pointers are invariant over their type parameter
+ = help: see <https://doc.rust-lang.org/nomicon/subtyping.html> for more information about variance
error: lifetime may not live long enough
--> $DIR/type-check-pointer-coercions.rs:13:5
| ^ returning this value requires that `'a` must outlive `'b`
|
= help: consider adding the following bound: `'a: 'b`
+ = note: requirement occurs because of a mutable pointer to &i32
+ = note: mutable pointers are invariant over their type parameter
+ = help: see <https://doc.rust-lang.org/nomicon/subtyping.html> for more information about variance
help: `'b` and `'a` must be the same: replace one with the other
| ^ requires that `'a` must outlive `'b`
|
= help: consider adding the following bound: `'a: 'b`
+ = note: requirement occurs because of a mutable reference to &i32
+ = note: mutable references are invariant over their type parameter
+ = help: see <https://doc.rust-lang.org/nomicon/subtyping.html> for more information about variance
error: lifetime may not live long enough
--> $DIR/type-check-pointer-comparisons.rs:6:10
| ^ requires that `'b` must outlive `'a`
|
= help: consider adding the following bound: `'b: 'a`
+ = note: requirement occurs because of a mutable reference to &i32
+ = note: mutable references are invariant over their type parameter
+ = help: see <https://doc.rust-lang.org/nomicon/subtyping.html> for more information about variance
help: `'a` and `'b` must be the same: replace one with the other
| ^ requires that `'a` must outlive `'b`
|
= help: consider adding the following bound: `'a: 'b`
+ = note: requirement occurs because of a mutable pointer to &i32
+ = note: mutable pointers are invariant over their type parameter
+ = help: see <https://doc.rust-lang.org/nomicon/subtyping.html> for more information about variance
error: lifetime may not live long enough
--> $DIR/type-check-pointer-comparisons.rs:12:10
| ^ requires that `'b` must outlive `'a`
|
= help: consider adding the following bound: `'b: 'a`
+ = note: requirement occurs because of a mutable pointer to &i32
+ = note: mutable pointers are invariant over their type parameter
+ = help: see <https://doc.rust-lang.org/nomicon/subtyping.html> for more information about variance
help: `'a` and `'b` must be the same: replace one with the other
| ^ requires that `'a` must outlive `'b`
|
= help: consider adding the following bound: `'a: 'b`
+ = note: requirement occurs because of a mutable reference to &i32
+ = note: mutable references are invariant over their type parameter
+ = help: see <https://doc.rust-lang.org/nomicon/subtyping.html> for more information about variance
error: lifetime may not live long enough
--> $DIR/type-check-pointer-comparisons.rs:18:10
| ^ requires that `'b` must outlive `'a`
|
= help: consider adding the following bound: `'b: 'a`
+ = note: requirement occurs because of a mutable reference to &i32
+ = note: mutable references are invariant over their type parameter
+ = help: see <https://doc.rust-lang.org/nomicon/subtyping.html> for more information about variance
help: `'a` and `'b` must be the same: replace one with the other
// ignore-android
// ignore-emscripten no processes
// ignore-sgx no processes
+// revisions: mir thir
+// [thir]compile-flags: -Zthir-unsafeck
#![feature(rustc_private)]
// run-fail
-// error-pattern:panicked at 'Box<Any>'
+// error-pattern:panicked at 'Box<dyn Any>'
// ignore-emscripten no processes
#![allow(non_fmt_panic)]
// run-fail
-// error-pattern:panicked at 'Box<Any>'
+// error-pattern:panicked at 'Box<dyn Any>'
// ignore-emscripten no processes
#![feature(box_syntax)]
+++ /dev/null
-fn main() {
- match 10 {
- <T as Trait>::Type{key: value} => (),
- //~^ ERROR unexpected `{` after qualified path
- _ => (),
- }
-}
+++ /dev/null
-error: unexpected `{` after qualified path
- --> $DIR/brace-after-qualified-path-in-match.rs:3:27
- |
-LL | <T as Trait>::Type{key: value} => (),
- | ------------------^ unexpected `{` after qualified path
- | |
- | the qualified path
-
-error: aborting due to previous error
-
--- /dev/null
+// Regression test for #85794
+
+struct Baz {
+ inner : dyn fn ()
+ //~^ ERROR expected `,`, or `}`, found keyword `fn`
+ //~| ERROR functions are not allowed in struct definitions
+ //~| ERROR cannot find type `dyn` in this scope
+}
+
+fn main() {}
--- /dev/null
+error: expected `,`, or `}`, found keyword `fn`
+ --> $DIR/fn-field-parse-error-ice.rs:4:16
+ |
+LL | inner : dyn fn ()
+ | ^ help: try adding a comma: `,`
+
+error: functions are not allowed in struct definitions
+ --> $DIR/fn-field-parse-error-ice.rs:4:17
+ |
+LL | inner : dyn fn ()
+ | ^^
+ |
+ = help: unlike in C++, Java, and C#, functions are declared in `impl` blocks
+ = help: see https://doc.rust-lang.org/book/ch05-03-method-syntax.html for more information
+
+error[E0412]: cannot find type `dyn` in this scope
+ --> $DIR/fn-field-parse-error-ice.rs:4:13
+ |
+LL | inner : dyn fn ()
+ | ^^^ not found in this scope
+
+error: aborting due to 3 previous errors
+
+For more information about this error, try `rustc --explain E0412`.
--- /dev/null
+// error-pattern: this file contains an unclosed delimiter
+// error-pattern: expected one of
+#[i=i::<ښܖ<
--- /dev/null
+error: this file contains an unclosed delimiter
+ --> $DIR/issue-84104.rs:3:13
+ |
+LL | #[i=i::<ښܖ<
+ | - ^
+ | |
+ | unclosed delimiter
+
+error: expected one of `>`, a const expression, lifetime, or type, found `]`
+ --> $DIR/issue-84104.rs:3:13
+ |
+LL | #[i=i::<ښܖ<
+ | ^ expected one of `>`, a const expression, lifetime, or type
+
+error: aborting due to 2 previous errors
+
--- /dev/null
+fn f(t:for<>t?)
+//~^ ERROR: expected parameter name
+//~| ERROR: expected one of
+//~| ERROR: expected one of
--- /dev/null
+error: expected parameter name, found `?`
+ --> $DIR/issue-84148-1.rs:1:14
+ |
+LL | fn f(t:for<>t?)
+ | ^ expected parameter name
+
+error: expected one of `(`, `)`, `+`, `,`, `::`, or `<`, found `?`
+ --> $DIR/issue-84148-1.rs:1:14
+ |
+LL | fn f(t:for<>t?)
+ | ^
+ | |
+ | expected one of `(`, `)`, `+`, `,`, `::`, or `<`
+ | help: missing `,`
+
+error: expected one of `->`, `;`, `where`, or `{`, found `<eof>`
+ --> $DIR/issue-84148-1.rs:1:15
+ |
+LL | fn f(t:for<>t?)
+ | ^ expected one of `->`, `;`, `where`, or `{`
+
+error: aborting due to 3 previous errors
+
--- /dev/null
+// error-pattern: this file contains an unclosed delimiter
+// error-pattern: expected parameter name
+// error-pattern: expected one of
+fn f(t:for<>t?
--- /dev/null
+error: this file contains an unclosed delimiter
+ --> $DIR/issue-84148-2.rs:4:16
+ |
+LL | fn f(t:for<>t?
+ | - ^
+ | |
+ | unclosed delimiter
+
+error: expected parameter name, found `?`
+ --> $DIR/issue-84148-2.rs:4:14
+ |
+LL | fn f(t:for<>t?
+ | ^ expected parameter name
+
+error: expected one of `(`, `)`, `+`, `,`, `::`, or `<`, found `?`
+ --> $DIR/issue-84148-2.rs:4:14
+ |
+LL | fn f(t:for<>t?
+ | ^
+ | |
+ | expected one of `(`, `)`, `+`, `,`, `::`, or `<`
+ | help: missing `,`
+
+error: expected one of `->`, `;`, `where`, or `{`, found `<eof>`
+ --> $DIR/issue-84148-2.rs:4:16
+ |
+LL | fn f(t:for<>t?
+ | ^ expected one of `->`, `;`, `where`, or `{`
+
+error: aborting due to 4 previous errors
+
+++ /dev/null
-fn main() {
- match 10 {
- <T as Trait>::Type(2) => (),
- //~^ ERROR unexpected `(` after qualified path
- _ => (),
- }
-}
+++ /dev/null
-error: unexpected `(` after qualified path
- --> $DIR/paren-after-qualified-path-in-match.rs:3:27
- |
-LL | <T as Trait>::Type(2) => (),
- | ------------------^ unexpected `(` after qualified path
- | |
- | the qualified path
-
-error: aborting due to previous error
-
--- /dev/null
+// Check that a suggestion is issued if there are too many `<`s in a
+// generic argument list, and that the parser recovers properly.
+
+fn main() {
+ foo::<<<<Ty<i32>>();
+ //~^ ERROR: unmatched angle brackets
+ //~| ERROR: cannot find function `foo` in this scope [E0425]
+ //~| ERROR: cannot find type `Ty` in this scope [E0412]
+}
--- /dev/null
+error: unmatched angle brackets
+ --> $DIR/unmatched-langle-1.rs:5:10
+ |
+LL | foo::<<<<Ty<i32>>();
+ | ^^^ help: remove extra angle brackets
+
+error[E0425]: cannot find function `foo` in this scope
+ --> $DIR/unmatched-langle-1.rs:5:5
+ |
+LL | foo::<<<<Ty<i32>>();
+ | ^^^ not found in this scope
+
+error[E0412]: cannot find type `Ty` in this scope
+ --> $DIR/unmatched-langle-1.rs:5:14
+ |
+LL | foo::<<<<Ty<i32>>();
+ | ^^ not found in this scope
+
+error: aborting due to 3 previous errors
+
+Some errors have detailed explanations: E0412, E0425.
+For more information about an error, try `rustc --explain E0412`.
--- /dev/null
+// When there are too many opening `<`s, the compiler would previously
+// suggest nonsense if the `<`s were interspersed with other tokens:
+//
+// error: unmatched angle brackets
+// --> unmatched-langle.rs:2:10
+// |
+// 2 | foo::<Ty<<<i32>();
+// | ^^^ help: remove extra angle brackets
+//
+// This test makes sure that this is no longer happening.
+
+fn main() {
+ foo::<Ty<<<i32>();
+ //~^ ERROR: expected `::`, found `(`
+}
--- /dev/null
+error: expected `::`, found `(`
+ --> $DIR/unmatched-langle-2.rs:13:20
+ |
+LL | foo::<Ty<<<i32>();
+ | ^ expected `::`
+
+error: aborting due to previous error
+
fn main() {}
fn f1_1(x: isize, ...) {}
-//~^ ERROR only foreign or `unsafe extern "C" functions may be C-variadic
+//~^ ERROR only foreign or `unsafe extern "C"` functions may be C-variadic
fn f1_2(...) {}
-//~^ ERROR only foreign or `unsafe extern "C" functions may be C-variadic
+//~^ ERROR only foreign or `unsafe extern "C"` functions may be C-variadic
//~| ERROR C-variadic function must be declared with at least one named argument
extern "C" fn f2_1(x: isize, ...) {}
-//~^ ERROR only foreign or `unsafe extern "C" functions may be C-variadic
+//~^ ERROR only foreign or `unsafe extern "C"` functions may be C-variadic
extern "C" fn f2_2(...) {}
-//~^ ERROR only foreign or `unsafe extern "C" functions may be C-variadic
+//~^ ERROR only foreign or `unsafe extern "C"` functions may be C-variadic
//~| ERROR C-variadic function must be declared with at least one named argument
extern "C" fn f2_3(..., x: isize) {}
-//~^ ERROR only foreign or `unsafe extern "C" functions may be C-variadic
+//~^ ERROR only foreign or `unsafe extern "C"` functions may be C-variadic
//~| ERROR `...` must be the last argument of a C-variadic function
extern "C" fn f3_1(x: isize, ...) {}
-//~^ ERROR only foreign or `unsafe extern "C" functions may be C-variadic
+//~^ ERROR only foreign or `unsafe extern "C"` functions may be C-variadic
extern "C" fn f3_2(...) {}
-//~^ ERROR only foreign or `unsafe extern "C" functions may be C-variadic
+//~^ ERROR only foreign or `unsafe extern "C"` functions may be C-variadic
//~| ERROR C-variadic function must be declared with at least one named argument
extern "C" fn f3_3(..., x: isize) {}
-//~^ ERROR only foreign or `unsafe extern "C" functions may be C-variadic
+//~^ ERROR only foreign or `unsafe extern "C"` functions may be C-variadic
//~| ERROR `...` must be the last argument of a C-variadic function
extern "C" {
impl X {
fn i_f1(x: isize, ...) {}
- //~^ ERROR only foreign or `unsafe extern "C" functions may be C-variadic
+ //~^ ERROR only foreign or `unsafe extern "C"` functions may be C-variadic
fn i_f2(...) {}
- //~^ ERROR only foreign or `unsafe extern "C" functions may be C-variadic
+ //~^ ERROR only foreign or `unsafe extern "C"` functions may be C-variadic
//~| ERROR C-variadic function must be declared with at least one named argument
fn i_f3(..., x: isize, ...) {}
- //~^ ERROR only foreign or `unsafe extern "C" functions may be C-variadic
- //~| ERROR only foreign or `unsafe extern "C" functions may be C-variadic
+ //~^ ERROR only foreign or `unsafe extern "C"` functions may be C-variadic
+ //~| ERROR only foreign or `unsafe extern "C"` functions may be C-variadic
//~| ERROR `...` must be the last argument of a C-variadic function
fn i_f4(..., x: isize, ...) {}
- //~^ ERROR only foreign or `unsafe extern "C" functions may be C-variadic
- //~| ERROR only foreign or `unsafe extern "C" functions may be C-variadic
+ //~^ ERROR only foreign or `unsafe extern "C"` functions may be C-variadic
+ //~| ERROR only foreign or `unsafe extern "C"` functions may be C-variadic
//~| ERROR `...` must be the last argument of a C-variadic function
}
trait T {
fn t_f1(x: isize, ...) {}
- //~^ ERROR only foreign or `unsafe extern "C" functions may be C-variadic
+ //~^ ERROR only foreign or `unsafe extern "C"` functions may be C-variadic
fn t_f2(x: isize, ...);
- //~^ ERROR only foreign or `unsafe extern "C" functions may be C-variadic
+ //~^ ERROR only foreign or `unsafe extern "C"` functions may be C-variadic
fn t_f3(...) {}
- //~^ ERROR only foreign or `unsafe extern "C" functions may be C-variadic
+ //~^ ERROR only foreign or `unsafe extern "C"` functions may be C-variadic
//~| ERROR C-variadic function must be declared with at least one named argument
fn t_f4(...);
- //~^ ERROR only foreign or `unsafe extern "C" functions may be C-variadic
+ //~^ ERROR only foreign or `unsafe extern "C"` functions may be C-variadic
//~| ERROR C-variadic function must be declared with at least one named argument
fn t_f5(..., x: isize) {}
- //~^ ERROR only foreign or `unsafe extern "C" functions may be C-variadic
+ //~^ ERROR only foreign or `unsafe extern "C"` functions may be C-variadic
//~| ERROR `...` must be the last argument of a C-variadic function
fn t_f6(..., x: isize);
- //~^ ERROR only foreign or `unsafe extern "C" functions may be C-variadic
+ //~^ ERROR only foreign or `unsafe extern "C"` functions may be C-variadic
//~| ERROR `...` must be the last argument of a C-variadic function
}
-error: only foreign or `unsafe extern "C" functions may be C-variadic
+error: only foreign or `unsafe extern "C"` functions may be C-variadic
--> $DIR/variadic-ffi-semantic-restrictions.rs:6:19
|
LL | fn f1_1(x: isize, ...) {}
LL | fn f1_2(...) {}
| ^^^
-error: only foreign or `unsafe extern "C" functions may be C-variadic
+error: only foreign or `unsafe extern "C"` functions may be C-variadic
--> $DIR/variadic-ffi-semantic-restrictions.rs:9:9
|
LL | fn f1_2(...) {}
| ^^^
-error: only foreign or `unsafe extern "C" functions may be C-variadic
+error: only foreign or `unsafe extern "C"` functions may be C-variadic
--> $DIR/variadic-ffi-semantic-restrictions.rs:13:30
|
LL | extern "C" fn f2_1(x: isize, ...) {}
LL | extern "C" fn f2_2(...) {}
| ^^^
-error: only foreign or `unsafe extern "C" functions may be C-variadic
+error: only foreign or `unsafe extern "C"` functions may be C-variadic
--> $DIR/variadic-ffi-semantic-restrictions.rs:16:20
|
LL | extern "C" fn f2_2(...) {}
LL | extern "C" fn f2_3(..., x: isize) {}
| ^^^
-error: only foreign or `unsafe extern "C" functions may be C-variadic
+error: only foreign or `unsafe extern "C"` functions may be C-variadic
--> $DIR/variadic-ffi-semantic-restrictions.rs:20:20
|
LL | extern "C" fn f2_3(..., x: isize) {}
| ^^^
-error: only foreign or `unsafe extern "C" functions may be C-variadic
+error: only foreign or `unsafe extern "C"` functions may be C-variadic
--> $DIR/variadic-ffi-semantic-restrictions.rs:24:30
|
LL | extern "C" fn f3_1(x: isize, ...) {}
LL | extern "C" fn f3_2(...) {}
| ^^^
-error: only foreign or `unsafe extern "C" functions may be C-variadic
+error: only foreign or `unsafe extern "C"` functions may be C-variadic
--> $DIR/variadic-ffi-semantic-restrictions.rs:27:20
|
LL | extern "C" fn f3_2(...) {}
LL | extern "C" fn f3_3(..., x: isize) {}
| ^^^
-error: only foreign or `unsafe extern "C" functions may be C-variadic
+error: only foreign or `unsafe extern "C"` functions may be C-variadic
--> $DIR/variadic-ffi-semantic-restrictions.rs:31:20
|
LL | extern "C" fn f3_3(..., x: isize) {}
LL | fn e_f2(..., x: isize);
| ^^^
-error: only foreign or `unsafe extern "C" functions may be C-variadic
+error: only foreign or `unsafe extern "C"` functions may be C-variadic
--> $DIR/variadic-ffi-semantic-restrictions.rs:45:23
|
LL | fn i_f1(x: isize, ...) {}
LL | fn i_f2(...) {}
| ^^^
-error: only foreign or `unsafe extern "C" functions may be C-variadic
+error: only foreign or `unsafe extern "C"` functions may be C-variadic
--> $DIR/variadic-ffi-semantic-restrictions.rs:47:13
|
LL | fn i_f2(...) {}
LL | fn i_f3(..., x: isize, ...) {}
| ^^^
-error: only foreign or `unsafe extern "C" functions may be C-variadic
+error: only foreign or `unsafe extern "C"` functions may be C-variadic
--> $DIR/variadic-ffi-semantic-restrictions.rs:50:13
|
LL | fn i_f3(..., x: isize, ...) {}
| ^^^
-error: only foreign or `unsafe extern "C" functions may be C-variadic
+error: only foreign or `unsafe extern "C"` functions may be C-variadic
--> $DIR/variadic-ffi-semantic-restrictions.rs:50:28
|
LL | fn i_f3(..., x: isize, ...) {}
LL | fn i_f4(..., x: isize, ...) {}
| ^^^
-error: only foreign or `unsafe extern "C" functions may be C-variadic
+error: only foreign or `unsafe extern "C"` functions may be C-variadic
--> $DIR/variadic-ffi-semantic-restrictions.rs:54:13
|
LL | fn i_f4(..., x: isize, ...) {}
| ^^^
-error: only foreign or `unsafe extern "C" functions may be C-variadic
+error: only foreign or `unsafe extern "C"` functions may be C-variadic
--> $DIR/variadic-ffi-semantic-restrictions.rs:54:28
|
LL | fn i_f4(..., x: isize, ...) {}
| ^^^
-error: only foreign or `unsafe extern "C" functions may be C-variadic
+error: only foreign or `unsafe extern "C"` functions may be C-variadic
--> $DIR/variadic-ffi-semantic-restrictions.rs:61:23
|
LL | fn t_f1(x: isize, ...) {}
| ^^^
-error: only foreign or `unsafe extern "C" functions may be C-variadic
+error: only foreign or `unsafe extern "C"` functions may be C-variadic
--> $DIR/variadic-ffi-semantic-restrictions.rs:63:23
|
LL | fn t_f2(x: isize, ...);
LL | fn t_f3(...) {}
| ^^^
-error: only foreign or `unsafe extern "C" functions may be C-variadic
+error: only foreign or `unsafe extern "C"` functions may be C-variadic
--> $DIR/variadic-ffi-semantic-restrictions.rs:65:13
|
LL | fn t_f3(...) {}
LL | fn t_f4(...);
| ^^^
-error: only foreign or `unsafe extern "C" functions may be C-variadic
+error: only foreign or `unsafe extern "C"` functions may be C-variadic
--> $DIR/variadic-ffi-semantic-restrictions.rs:68:13
|
LL | fn t_f4(...);
LL | fn t_f5(..., x: isize) {}
| ^^^
-error: only foreign or `unsafe extern "C" functions may be C-variadic
+error: only foreign or `unsafe extern "C"` functions may be C-variadic
--> $DIR/variadic-ffi-semantic-restrictions.rs:71:13
|
LL | fn t_f5(..., x: isize) {}
LL | fn t_f6(..., x: isize);
| ^^^
-error: only foreign or `unsafe extern "C" functions may be C-variadic
+error: only foreign or `unsafe extern "C"` functions may be C-variadic
--> $DIR/variadic-ffi-semantic-restrictions.rs:74:13
|
LL | fn t_f6(..., x: isize);
--- /dev/null
+// check-pass
+// edition:2021
+// compile-flags: -Zunstable-options
+
+fn main() {
+ let _: u16 = 123i32.try_into().unwrap();
+}
--- /dev/null
+// check-pass
+// aux-build:test-macros.rs
+
+#![feature(decl_macro)]
+#![feature(stmt_expr_attributes)]
+
+#![no_std] // Don't load unnecessary hygiene information from std
+extern crate std;
+
+#[macro_use]
+extern crate test_macros;
+
+macro mac {
+ (expr $expr:expr) => {
+ #[derive(Print)]
+ enum E {
+ V = { let _ = $expr; 0 },
+ }
+ },
+ (stmt $stmt:stmt) => {
+ #[derive(Print)]
+ enum E {
+ V = { let _ = { $stmt }; 0 },
+ }
+ },
+}
+
+const PATH: u8 = 2;
+
+fn main() {
+ mac!(expr #[allow(warnings)] 0);
+ mac!(stmt 0);
+ mac!(stmt {});
+ mac!(stmt PATH);
+ mac!(stmt 0 + 1);
+ mac!(stmt PATH + 1);
+}
--- /dev/null
+PRINT-DERIVE INPUT (DISPLAY): enum E { V = { let _ = #[allow(warnings)] 0 ; 0 }, }
+PRINT-DERIVE DEEP-RE-COLLECTED (DISPLAY): enum E { V = { let _ = #[allow(warnings)] #[allow(warnings)] 0 ; 0 }, }
+PRINT-DERIVE INPUT (DEBUG): TokenStream [
+ Ident {
+ ident: "enum",
+ span: #4 bytes(299..303),
+ },
+ Ident {
+ ident: "E",
+ span: #4 bytes(304..305),
+ },
+ Group {
+ delimiter: Brace,
+ stream: TokenStream [
+ Ident {
+ ident: "V",
+ span: #4 bytes(320..321),
+ },
+ Punct {
+ ch: '=',
+ spacing: Alone,
+ span: #4 bytes(322..323),
+ },
+ Group {
+ delimiter: Brace,
+ stream: TokenStream [
+ Ident {
+ ident: "let",
+ span: #4 bytes(326..329),
+ },
+ Ident {
+ ident: "_",
+ span: #4 bytes(330..331),
+ },
+ Punct {
+ ch: '=',
+ spacing: Alone,
+ span: #4 bytes(332..333),
+ },
+ Group {
+ delimiter: None,
+ stream: TokenStream [
+ Punct {
+ ch: '#',
+ spacing: Alone,
+ span: #0 bytes(541..542),
+ },
+ Group {
+ delimiter: Bracket,
+ stream: TokenStream [
+ Ident {
+ ident: "allow",
+ span: #0 bytes(543..548),
+ },
+ Group {
+ delimiter: Parenthesis,
+ stream: TokenStream [
+ Ident {
+ ident: "warnings",
+ span: #0 bytes(549..557),
+ },
+ ],
+ span: #0 bytes(548..558),
+ },
+ ],
+ span: #0 bytes(542..559),
+ },
+ Punct {
+ ch: '#',
+ spacing: Alone,
+ span: #0 bytes(541..542),
+ },
+ Group {
+ delimiter: Bracket,
+ stream: TokenStream [
+ Ident {
+ ident: "allow",
+ span: #0 bytes(543..548),
+ },
+ Group {
+ delimiter: Parenthesis,
+ stream: TokenStream [
+ Ident {
+ ident: "warnings",
+ span: #0 bytes(549..557),
+ },
+ ],
+ span: #0 bytes(548..558),
+ },
+ ],
+ span: #0 bytes(542..559),
+ },
+ Literal {
+ kind: Integer,
+ symbol: "0",
+ suffix: None,
+ span: #0 bytes(560..561),
+ },
+ ],
+ span: #4 bytes(334..339),
+ },
+ Punct {
+ ch: ';',
+ spacing: Alone,
+ span: #4 bytes(339..340),
+ },
+ Literal {
+ kind: Integer,
+ symbol: "0",
+ suffix: None,
+ span: #4 bytes(341..342),
+ },
+ ],
+ span: #4 bytes(324..344),
+ },
+ Punct {
+ ch: ',',
+ spacing: Alone,
+ span: #4 bytes(344..345),
+ },
+ ],
+ span: #4 bytes(306..355),
+ },
+]
+PRINT-DERIVE INPUT (DISPLAY): enum E { V = { let _ = { 0; } ; 0 }, }
+PRINT-DERIVE DEEP-RE-COLLECTED (DISPLAY): enum E { V = { let _ = { 0 } ; 0 }, }
+PRINT-DERIVE INPUT (DEBUG): TokenStream [
+ Ident {
+ ident: "enum",
+ span: #8 bytes(423..427),
+ },
+ Ident {
+ ident: "E",
+ span: #8 bytes(428..429),
+ },
+ Group {
+ delimiter: Brace,
+ stream: TokenStream [
+ Ident {
+ ident: "V",
+ span: #8 bytes(444..445),
+ },
+ Punct {
+ ch: '=',
+ spacing: Alone,
+ span: #8 bytes(446..447),
+ },
+ Group {
+ delimiter: Brace,
+ stream: TokenStream [
+ Ident {
+ ident: "let",
+ span: #8 bytes(450..453),
+ },
+ Ident {
+ ident: "_",
+ span: #8 bytes(454..455),
+ },
+ Punct {
+ ch: '=',
+ spacing: Alone,
+ span: #8 bytes(456..457),
+ },
+ Group {
+ delimiter: Brace,
+ stream: TokenStream [
+ Group {
+ delimiter: None,
+ stream: TokenStream [
+ Literal {
+ kind: Integer,
+ symbol: "0",
+ suffix: None,
+ span: #0 bytes(578..579),
+ },
+ ],
+ span: #8 bytes(460..465),
+ },
+ ],
+ span: #8 bytes(458..467),
+ },
+ Punct {
+ ch: ';',
+ spacing: Alone,
+ span: #8 bytes(467..468),
+ },
+ Literal {
+ kind: Integer,
+ symbol: "0",
+ suffix: None,
+ span: #8 bytes(469..470),
+ },
+ ],
+ span: #8 bytes(448..472),
+ },
+ Punct {
+ ch: ',',
+ spacing: Alone,
+ span: #8 bytes(472..473),
+ },
+ ],
+ span: #8 bytes(430..483),
+ },
+]
+PRINT-DERIVE INPUT (DISPLAY): enum E { V = { let _ = { { } } ; 0 }, }
+PRINT-DERIVE INPUT (DEBUG): TokenStream [
+ Ident {
+ ident: "enum",
+ span: #12 bytes(423..427),
+ },
+ Ident {
+ ident: "E",
+ span: #12 bytes(428..429),
+ },
+ Group {
+ delimiter: Brace,
+ stream: TokenStream [
+ Ident {
+ ident: "V",
+ span: #12 bytes(444..445),
+ },
+ Punct {
+ ch: '=',
+ spacing: Alone,
+ span: #12 bytes(446..447),
+ },
+ Group {
+ delimiter: Brace,
+ stream: TokenStream [
+ Ident {
+ ident: "let",
+ span: #12 bytes(450..453),
+ },
+ Ident {
+ ident: "_",
+ span: #12 bytes(454..455),
+ },
+ Punct {
+ ch: '=',
+ spacing: Alone,
+ span: #12 bytes(456..457),
+ },
+ Group {
+ delimiter: Brace,
+ stream: TokenStream [
+ Group {
+ delimiter: None,
+ stream: TokenStream [
+ Group {
+ delimiter: Brace,
+ stream: TokenStream [],
+ span: #0 bytes(596..598),
+ },
+ ],
+ span: #12 bytes(460..465),
+ },
+ ],
+ span: #12 bytes(458..467),
+ },
+ Punct {
+ ch: ';',
+ spacing: Alone,
+ span: #12 bytes(467..468),
+ },
+ Literal {
+ kind: Integer,
+ symbol: "0",
+ suffix: None,
+ span: #12 bytes(469..470),
+ },
+ ],
+ span: #12 bytes(448..472),
+ },
+ Punct {
+ ch: ',',
+ spacing: Alone,
+ span: #12 bytes(472..473),
+ },
+ ],
+ span: #12 bytes(430..483),
+ },
+]
+PRINT-DERIVE INPUT (DISPLAY): enum E { V = { let _ = { PATH; } ; 0 }, }
+PRINT-DERIVE DEEP-RE-COLLECTED (DISPLAY): enum E { V = { let _ = { PATH } ; 0 }, }
+PRINT-DERIVE INPUT (DEBUG): TokenStream [
+ Ident {
+ ident: "enum",
+ span: #16 bytes(423..427),
+ },
+ Ident {
+ ident: "E",
+ span: #16 bytes(428..429),
+ },
+ Group {
+ delimiter: Brace,
+ stream: TokenStream [
+ Ident {
+ ident: "V",
+ span: #16 bytes(444..445),
+ },
+ Punct {
+ ch: '=',
+ spacing: Alone,
+ span: #16 bytes(446..447),
+ },
+ Group {
+ delimiter: Brace,
+ stream: TokenStream [
+ Ident {
+ ident: "let",
+ span: #16 bytes(450..453),
+ },
+ Ident {
+ ident: "_",
+ span: #16 bytes(454..455),
+ },
+ Punct {
+ ch: '=',
+ spacing: Alone,
+ span: #16 bytes(456..457),
+ },
+ Group {
+ delimiter: Brace,
+ stream: TokenStream [
+ Group {
+ delimiter: None,
+ stream: TokenStream [
+ Ident {
+ ident: "PATH",
+ span: #0 bytes(615..619),
+ },
+ ],
+ span: #16 bytes(460..465),
+ },
+ ],
+ span: #16 bytes(458..467),
+ },
+ Punct {
+ ch: ';',
+ spacing: Alone,
+ span: #16 bytes(467..468),
+ },
+ Literal {
+ kind: Integer,
+ symbol: "0",
+ suffix: None,
+ span: #16 bytes(469..470),
+ },
+ ],
+ span: #16 bytes(448..472),
+ },
+ Punct {
+ ch: ',',
+ spacing: Alone,
+ span: #16 bytes(472..473),
+ },
+ ],
+ span: #16 bytes(430..483),
+ },
+]
+PRINT-DERIVE INPUT (DISPLAY): enum E { V = { let _ = { 0 + 1; } ; 0 }, }
+PRINT-DERIVE DEEP-RE-COLLECTED (DISPLAY): enum E { V = { let _ = { 0 + 1 } ; 0 }, }
+PRINT-DERIVE INPUT (DEBUG): TokenStream [
+ Ident {
+ ident: "enum",
+ span: #20 bytes(423..427),
+ },
+ Ident {
+ ident: "E",
+ span: #20 bytes(428..429),
+ },
+ Group {
+ delimiter: Brace,
+ stream: TokenStream [
+ Ident {
+ ident: "V",
+ span: #20 bytes(444..445),
+ },
+ Punct {
+ ch: '=',
+ spacing: Alone,
+ span: #20 bytes(446..447),
+ },
+ Group {
+ delimiter: Brace,
+ stream: TokenStream [
+ Ident {
+ ident: "let",
+ span: #20 bytes(450..453),
+ },
+ Ident {
+ ident: "_",
+ span: #20 bytes(454..455),
+ },
+ Punct {
+ ch: '=',
+ spacing: Alone,
+ span: #20 bytes(456..457),
+ },
+ Group {
+ delimiter: Brace,
+ stream: TokenStream [
+ Group {
+ delimiter: None,
+ stream: TokenStream [
+ Literal {
+ kind: Integer,
+ symbol: "0",
+ suffix: None,
+ span: #0 bytes(636..637),
+ },
+ Punct {
+ ch: '+',
+ spacing: Alone,
+ span: #0 bytes(638..639),
+ },
+ Literal {
+ kind: Integer,
+ symbol: "1",
+ suffix: None,
+ span: #0 bytes(640..641),
+ },
+ ],
+ span: #20 bytes(460..465),
+ },
+ ],
+ span: #20 bytes(458..467),
+ },
+ Punct {
+ ch: ';',
+ spacing: Alone,
+ span: #20 bytes(467..468),
+ },
+ Literal {
+ kind: Integer,
+ symbol: "0",
+ suffix: None,
+ span: #20 bytes(469..470),
+ },
+ ],
+ span: #20 bytes(448..472),
+ },
+ Punct {
+ ch: ',',
+ spacing: Alone,
+ span: #20 bytes(472..473),
+ },
+ ],
+ span: #20 bytes(430..483),
+ },
+]
+PRINT-DERIVE INPUT (DISPLAY): enum E { V = { let _ = { PATH + 1; } ; 0 }, }
+PRINT-DERIVE DEEP-RE-COLLECTED (DISPLAY): enum E { V = { let _ = { PATH + 1 } ; 0 }, }
+PRINT-DERIVE INPUT (DEBUG): TokenStream [
+ Ident {
+ ident: "enum",
+ span: #24 bytes(423..427),
+ },
+ Ident {
+ ident: "E",
+ span: #24 bytes(428..429),
+ },
+ Group {
+ delimiter: Brace,
+ stream: TokenStream [
+ Ident {
+ ident: "V",
+ span: #24 bytes(444..445),
+ },
+ Punct {
+ ch: '=',
+ spacing: Alone,
+ span: #24 bytes(446..447),
+ },
+ Group {
+ delimiter: Brace,
+ stream: TokenStream [
+ Ident {
+ ident: "let",
+ span: #24 bytes(450..453),
+ },
+ Ident {
+ ident: "_",
+ span: #24 bytes(454..455),
+ },
+ Punct {
+ ch: '=',
+ spacing: Alone,
+ span: #24 bytes(456..457),
+ },
+ Group {
+ delimiter: Brace,
+ stream: TokenStream [
+ Group {
+ delimiter: None,
+ stream: TokenStream [
+ Ident {
+ ident: "PATH",
+ span: #0 bytes(658..662),
+ },
+ Punct {
+ ch: '+',
+ spacing: Alone,
+ span: #0 bytes(663..664),
+ },
+ Literal {
+ kind: Integer,
+ symbol: "1",
+ suffix: None,
+ span: #0 bytes(665..666),
+ },
+ ],
+ span: #24 bytes(460..465),
+ },
+ ],
+ span: #24 bytes(458..467),
+ },
+ Punct {
+ ch: ';',
+ spacing: Alone,
+ span: #24 bytes(467..468),
+ },
+ Literal {
+ kind: Integer,
+ symbol: "0",
+ suffix: None,
+ span: #24 bytes(469..470),
+ },
+ ],
+ span: #24 bytes(448..472),
+ },
+ Punct {
+ ch: ',',
+ spacing: Alone,
+ span: #24 bytes(472..473),
+ },
+ ],
+ span: #24 bytes(430..483),
+ },
+]
| ^^^^^^^ argument requires that `'b` must outlive `'a`
|
= help: consider adding the following bound: `'b: 'a`
+ = note: requirement occurs because of a mutable reference to &isize
+ = note: mutable references are invariant over their type parameter
+ = help: see <https://doc.rust-lang.org/nomicon/subtyping.html> for more information about variance
error: higher-ranked subtype error
--> $DIR/region-lifetime-bounds-on-fns-where-clause.rs:20:12
| ^^^^^^^^^^ argument requires that `'b` must outlive `'a`
|
= help: consider adding the following bound: `'b: 'a`
+ = note: requirement occurs because of a mutable reference to &isize
+ = note: mutable references are invariant over their type parameter
+ = help: see <https://doc.rust-lang.org/nomicon/subtyping.html> for more information about variance
error: higher-ranked subtype error
--> $DIR/region-multiple-lifetime-bounds-on-fns-where-clause.rs:22:12
| ^^^^^^^ argument requires that `'b` must outlive `'a`
|
= help: consider adding the following bound: `'b: 'a`
+ = note: requirement occurs because of a mutable reference to &isize
+ = note: mutable references are invariant over their type parameter
+ = help: see <https://doc.rust-lang.org/nomicon/subtyping.html> for more information about variance
error: higher-ranked subtype error
--> $DIR/regions-lifetime-bounds-on-fns.rs:20:12
| ^ returning this value requires that `'a` must outlive `'b`
|
= help: consider adding the following bound: `'a: 'b`
+ = note: requirement occurs because of a mutable reference to dyn Dummy
+ = note: mutable references are invariant over their type parameter
+ = help: see <https://doc.rust-lang.org/nomicon/subtyping.html> for more information about variance
error: lifetime may not live long enough
--> $DIR/regions-trait-object-subtyping.rs:22:5
| ^ returning this value requires that `'b` must outlive `'a`
|
= help: consider adding the following bound: `'b: 'a`
+ = note: requirement occurs because of a mutable reference to dyn Dummy
+ = note: mutable references are invariant over their type parameter
+ = help: see <https://doc.rust-lang.org/nomicon/subtyping.html> for more information about variance
error: aborting due to 2 previous errors
// check-fail
-#![feature(intrinsics)]
+#![feature(core_intrinsics, intrinsics)]
fn a() {
let _: unsafe extern "rust-intrinsic" fn(isize) -> usize = std::mem::transmute;
fn c() {
let _ = [
- std::intrinsics::copy_nonoverlapping::<i32>,
- std::intrinsics::copy::<i32>,
+ std::intrinsics::likely,
+ std::intrinsics::unlikely,
//~^ ERROR cannot coerce
];
}
error[E0308]: cannot coerce intrinsics to function pointers
--> $DIR/reify-intrinsic.rs:18:9
|
-LL | std::intrinsics::copy::<i32>,
- | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ cannot coerce intrinsics to function pointers
+LL | std::intrinsics::unlikely,
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^ cannot coerce intrinsics to function pointers
|
- = note: expected type `unsafe extern "rust-intrinsic" fn(_, _, _) {copy_nonoverlapping::<i32>}`
- found fn item `unsafe extern "rust-intrinsic" fn(_, _, _) {std::intrinsics::copy::<i32>}`
+ = note: expected type `extern "rust-intrinsic" fn(_) -> _ {likely}`
+ found fn item `extern "rust-intrinsic" fn(_) -> _ {unlikely}`
error: aborting due to 3 previous errors
--- /dev/null
+// Checks whether shadowing a const parameter leads to an ICE (#85348).
+
+impl<const N: usize> ArrayWindowsExample {
+//~^ ERROR: cannot find type `ArrayWindowsExample` in this scope [E0412]
+ fn next() {
+ let mut N;
+ //~^ ERROR: let bindings cannot shadow const parameters [E0530]
+ //~| ERROR: type annotations needed [E0282]
+ }
+}
+
+fn main() {}
--- /dev/null
+error[E0530]: let bindings cannot shadow const parameters
+ --> $DIR/issue-85348.rs:6:17
+ |
+LL | impl<const N: usize> ArrayWindowsExample {
+ | - the const parameter `N` is defined here
+...
+LL | let mut N;
+ | ^ cannot be named the same as a const parameter
+
+error[E0412]: cannot find type `ArrayWindowsExample` in this scope
+ --> $DIR/issue-85348.rs:3:22
+ |
+LL | impl<const N: usize> ArrayWindowsExample {
+ | ^^^^^^^^^^^^^^^^^^^ not found in this scope
+
+error[E0282]: type annotations needed
+ --> $DIR/issue-85348.rs:6:13
+ |
+LL | let mut N;
+ | ^^^^^ consider giving `N` a type
+
+error: aborting due to 3 previous errors
+
+Some errors have detailed explanations: E0282, E0412, E0530.
+For more information about an error, try `rustc --explain E0282`.
--- /dev/null
+// Checks that const parameters cannot be shadowed with fresh bindings
+// even in syntactically unambiguous contexts. See
+// https://github.com/rust-lang/rust/issues/33118#issuecomment-233962221
+
+fn foo<const N: i32>(i: i32) -> bool {
+ match i {
+ N @ _ => true,
+ //~^ ERROR: match bindings cannot shadow const parameters [E0530]
+ }
+}
+
+fn bar<const N: i32>(i: i32) -> bool {
+ let N @ _ = 0;
+ //~^ ERROR: let bindings cannot shadow const parameters [E0530]
+ match i {
+ N @ _ => true,
+ }
+}
+
+fn main() {}
--- /dev/null
+error[E0530]: match bindings cannot shadow const parameters
+ --> $DIR/shadow-const-param.rs:7:9
+ |
+LL | fn foo<const N: i32>(i: i32) -> bool {
+ | - the const parameter `N` is defined here
+LL | match i {
+LL | N @ _ => true,
+ | ^ cannot be named the same as a const parameter
+
+error[E0530]: let bindings cannot shadow const parameters
+ --> $DIR/shadow-const-param.rs:13:9
+ |
+LL | fn bar<const N: i32>(i: i32) -> bool {
+ | - the const parameter `N` is defined here
+LL | let N @ _ = 0;
+ | ^ cannot be named the same as a const parameter
+
+error: aborting due to 2 previous errors
+
+For more information about this error, try `rustc --explain E0530`.
+++ /dev/null
-#[link(name = "foo")]
-extern "C" {
- #[link_ordinal(42)]
- //~^ ERROR: the `#[link_ordinal]` attribute is an experimental feature
- fn foo();
-}
-
-fn main() {}
+++ /dev/null
-error[E0658]: the `#[link_ordinal]` attribute is an experimental feature
- --> $DIR/feature-gate-raw-dylib-2.rs:3:5
- |
-LL | #[link_ordinal(42)]
- | ^^^^^^^^^^^^^^^^^^^
- |
- = note: see issue #58713 <https://github.com/rust-lang/rust/issues/58713> for more information
- = help: add `#![feature(raw_dylib)]` to the crate attributes to enable
-
-error: aborting due to previous error
-
-For more information about this error, try `rustc --explain E0658`.
+++ /dev/null
-#[link(name = "foo", kind = "raw-dylib")]
-//~^ ERROR: kind="raw-dylib" is unstable
-extern "C" {}
-
-fn main() {}
+++ /dev/null
-error[E0658]: kind="raw-dylib" is unstable
- --> $DIR/feature-gate-raw-dylib.rs:1:1
- |
-LL | #[link(name = "foo", kind = "raw-dylib")]
- | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
- |
- = note: see issue #58713 <https://github.com/rust-lang/rust/issues/58713> for more information
- = help: add `#![feature(raw_dylib)]` to the crate attributes to enable
-
-error: aborting due to previous error
-
-For more information about this error, try `rustc --explain E0658`.
--- /dev/null
+// only-windows-gnu
+// check-pass
+// compile-flags: --crate-type lib
+#![feature(raw_dylib)]
+//~^ WARNING: the feature `raw_dylib` is incomplete
+#[link(name = "foo", kind = "raw-dylib")]
+//~^ WARNING: `#[link(...)]` with `kind = "raw-dylib"` not supported on windows-gnu
+extern "C" {}
--- /dev/null
+warning: the feature `raw_dylib` is incomplete and may not be safe to use and/or cause compiler crashes
+ --> $DIR/raw-dylib-msvc-only.rs:4:12
+ |
+LL | #![feature(raw_dylib)]
+ | ^^^^^^^^^
+ |
+ = note: `#[warn(incomplete_features)]` on by default
+ = note: see issue #58713 <https://github.com/rust-lang/rust/issues/58713> for more information
+
+warning: `#[link(...)]` with `kind = "raw-dylib"` not supported on windows-gnu
+ --> $DIR/raw-dylib-msvc-only.rs:6:1
+ |
+LL | #[link(name = "foo", kind = "raw-dylib")]
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+warning: 2 warnings emitted
+
--- /dev/null
+// ignore-windows
+// compile-flags: --crate-type lib
+#![feature(raw_dylib)]
+//~^ WARNING: the feature `raw_dylib` is incomplete
+#[link(name = "foo", kind = "raw-dylib")]
+//~^ ERROR: `#[link(...)]` with `kind = "raw-dylib"` only supported on Windows
+extern "C" {}
--- /dev/null
+warning: the feature `raw_dylib` is incomplete and may not be safe to use and/or cause compiler crashes
+ --> $DIR/raw-dylib-windows-only.rs:3:12
+ |
+LL | #![feature(raw_dylib)]
+ | ^^^^^^^^^
+ |
+ = note: `#[warn(incomplete_features)]` on by default
+ = note: see issue #58713 <https://github.com/rust-lang/rust/issues/58713> for more information
+
+error: `#[link(...)]` with `kind = "raw-dylib"` only supported on Windows
+ --> $DIR/raw-dylib-windows-only.rs:5:1
+ |
+LL | #[link(name = "foo", kind = "raw-dylib")]
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+error: aborting due to previous error; 1 warning emitted
+
// run-pass
// ignore-emscripten spawning processes is not supported
// ignore-sgx no processes
+// revisions: mir thir
+// [thir]compile-flags: -Zthir-unsafeck
#![feature(start)]
-#![crate_type="lib"]
+#![crate_type = "lib"]
pub struct Bar;
pub trait Foo {
type X;
- fn foo() -> Self::X;
+ fn foo(x: u32) -> Self::X;
}
#[doc(alias = "foo")] //~ ERROR
impl Foo for Bar {
#[doc(alias = "assoc")] //~ ERROR
type X = i32;
- fn foo() -> Self::X {
+ fn foo(#[doc(alias = "qux")] _x: u32) -> Self::X {
+ //~^ ERROR
0
}
}
+error: allow, cfg, cfg_attr, deny, forbid, and warn are the only allowed built-in attributes in function parameters
+ --> $DIR/check-doc-alias-attr-location.rs:22:12
+ |
+LL | fn foo(#[doc(alias = "qux")] _x: u32) -> Self::X {
+ | ^^^^^^^^^^^^^^^^^^^^^
+
error: `#[doc(alias = "...")]` isn't allowed on extern block
--> $DIR/check-doc-alias-attr-location.rs:9:7
|
LL | #[doc(alias = "assoc")]
| ^^^^^^^^^^^^^^^
-error: aborting due to 4 previous errors
+error: aborting due to 5 previous errors
--- /dev/null
+#![deny(invalid_doc_attributes)]
+//~^ NOTE defined here
+#![doc(x)]
+//~^ ERROR unknown `doc` attribute `x`
+//~| WARNING will become a hard error
+//~| NOTE see issue #82730
+fn main() {}
--- /dev/null
+error: unknown `doc` attribute `x`
+ --> $DIR/deny-invalid-doc-attrs.rs:3:8
+ |
+LL | #![doc(x)]
+ | ^
+ |
+note: the lint level is defined here
+ --> $DIR/deny-invalid-doc-attrs.rs:1:9
+ |
+LL | #![deny(invalid_doc_attributes)]
+ | ^^^^^^^^^^^^^^^^^^^^^^
+ = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
+ = note: for more information, see issue #82730 <https://github.com/rust-lang/rust/issues/82730>
+
+error: aborting due to previous error
+
--- /dev/null
+#[doc(inline)]
+//~^ ERROR conflicting
+#[doc(no_inline)]
+pub extern crate core;
+
+// no warning
+pub extern crate alloc;
+
+fn main() {}
--- /dev/null
+error: conflicting doc inlining attributes
+ --> $DIR/doc-inline-extern-crate.rs:1:7
+ |
+LL | #[doc(inline)]
+ | ^^^^^^ this attribute...
+LL |
+LL | #[doc(no_inline)]
+ | ^^^^^^^^^ ...conflicts with this attribute
+ |
+ = help: remove one of the conflicting attributes
+
+error: aborting due to previous error
+
--- /dev/null
+// compile-flags: -Z sanitizer=address -C target-feature=+crt-static --target x86_64-unknown-linux-gnu
+
+#![feature(no_core)]
+#![no_core]
+#![no_main]
--- /dev/null
+error: Sanitizer is incompatible with statically linked libc, disable it using `-C target-feature=-crt-static`
+
+error: aborting due to previous error
+
--- /dev/null
+// run-pass
+// ignore-emscripten
+
+// Short form of the generic gather/scatter tests,
+// verifying simd([*const T; N]) and simd([*mut T; N]) pass typeck and work.
+#![feature(repr_simd, platform_intrinsics)]
+#![allow(non_camel_case_types)]
+
+#[repr(simd)]
+#[derive(Copy, Clone, PartialEq, Debug)]
+struct cptrx4<T>([*const T; 4]);
+
+#[repr(simd)]
+#[derive(Copy, Clone, PartialEq, Debug)]
+struct mptrx4<T>([*mut T; 4]);
+
+#[repr(simd)]
+#[derive(Copy, Clone, PartialEq, Debug)]
+struct f32x4([f32; 4]);
+
+#[repr(simd)]
+#[derive(Copy, Clone, PartialEq, Debug)]
+struct i32x4([i32; 4]);
+
+extern "platform-intrinsic" {
+ fn simd_gather<T, U, V>(x: T, y: U, z: V) -> T;
+ fn simd_scatter<T, U, V>(x: T, y: U, z: V) -> ();
+}
+
+fn main() {
+ let mut x = [0_f32, 1., 2., 3., 4., 5., 6., 7.];
+
+ let default = f32x4([-3_f32, -3., -3., -3.]);
+ let s_strided = f32x4([0_f32, 2., -3., 6.]);
+ let mask = i32x4([-1_i32, -1, 0, -1]);
+
+ // reading from *const
+ unsafe {
+ let pointer = &x as *const f32;
+ let pointers = cptrx4([
+ pointer.offset(0) as *const f32,
+ pointer.offset(2),
+ pointer.offset(4),
+ pointer.offset(6)
+ ]);
+
+ let r_strided = simd_gather(default, pointers, mask);
+
+ assert_eq!(r_strided, s_strided);
+ }
+
+ // writing to *mut
+ unsafe {
+ let pointer = &mut x as *mut f32;
+ let pointers = mptrx4([
+ pointer.offset(0) as *mut f32,
+ pointer.offset(2),
+ pointer.offset(4),
+ pointer.offset(6)
+ ]);
+
+ let values = f32x4([42_f32, 43_f32, 44_f32, 45_f32]);
+ simd_scatter(values, pointers, mask);
+
+ assert_eq!(x, [42., 1., 43., 3., 4., 5., 45., 7.]);
+ }
+}
// run-pass
// ignore-emscripten FIXME(#45351) hits an LLVM assert
+// revisions: mir thir
+// [thir]compile-flags: -Zthir-unsafeck
#![feature(repr_simd, platform_intrinsics, concat_idents)]
#![allow(non_camel_case_types)]
--- /dev/null
+// run-pass
+// ignore-emscripten
+
+#![feature(extern_types)]
+#![feature(repr_simd)]
+
+use std::ptr::NonNull;
+
+extern {
+ type Extern;
+}
+
+#[repr(simd)]
+struct S<T>(T);
+
+#[inline(never)]
+fn identity<T>(v: T) -> T {
+ v
+}
+
+fn main() {
+ let _v: S<[Option<NonNull<Extern>>; 4]> = identity(S([None; 4]));
+}
--- /dev/null
+// build-fail
+
+#![feature(repr_simd)]
+
+// error-pattern:monomorphising SIMD type `S<[*mut [u8]; 4]>` with a non-primitive-scalar (integer/float/pointer) element type `*mut [u8]`
+
+#[repr(simd)]
+struct S<T>(T);
+
+fn main() {
+ let _v: Option<S<[*mut [u8]; 4]>> = None;
+}
--- /dev/null
+error: monomorphising SIMD type `S<[*mut [u8]; 4]>` with a non-primitive-scalar (integer/float/pointer) element type `*mut [u8]`
+
+error: aborting due to previous error
+
--- /dev/null
+// build-fail
+
+#![feature(repr_simd)]
+
+// error-pattern:monomorphising SIMD type `S` with a non-primitive-scalar (integer/float/pointer) element type `*mut [u8]`
+
+#[repr(simd)]
+struct S([*mut [u8]; 4]);
+
+fn main() {
+ let _v: Option<S> = None;
+}
--- /dev/null
+error: monomorphising SIMD type `S` with a non-primitive-scalar (integer/float/pointer) element type `*mut [u8]`
+
+error: aborting due to previous error
+
--- /dev/null
+// build-pass
+
+#[cfg(target_arch = "wasm32")]
+fn main() {
+ unsafe {
+ a::api_with_simd_feature();
+ }
+}
+
+#[cfg(target_arch = "wasm32")]
+mod a {
+ use std::arch::wasm32::*;
+
+ #[target_feature(enable = "simd128")]
+ pub unsafe fn api_with_simd_feature() {
+ crate::b::api_takes_v128(u64x2(0, 1));
+ }
+}
+
+#[cfg(target_arch = "wasm32")]
+mod b {
+ use std::arch::wasm32::*;
+
+ #[inline(never)]
+ pub fn api_takes_v128(a: v128) -> v128 {
+ a
+ }
+}
+
+#[cfg(not(target_arch = "wasm32"))]
+fn main() {}
--- /dev/null
+error: unnecessary `unsafe` block
+ --> $DIR/lint-unused-unsafe.rs:19:13
+ |
+LL | fn bad1() { unsafe {} }
+ | ^^^^^^ unnecessary `unsafe` block
+ |
+note: the lint level is defined here
+ --> $DIR/lint-unused-unsafe.rs:7:9
+ |
+LL | #![deny(unused_unsafe)]
+ | ^^^^^^^^^^^^^
+
+error: unnecessary `unsafe` block
+ --> $DIR/lint-unused-unsafe.rs:20:13
+ |
+LL | fn bad2() { unsafe { bad1() } }
+ | ^^^^^^ unnecessary `unsafe` block
+
+error: unnecessary `unsafe` block
+ --> $DIR/lint-unused-unsafe.rs:21:20
+ |
+LL | unsafe fn bad3() { unsafe {} }
+ | ---------------- ^^^^^^ unnecessary `unsafe` block
+ | |
+ | because it's nested under this `unsafe` fn
+
+error: unnecessary `unsafe` block
+ --> $DIR/lint-unused-unsafe.rs:22:13
+ |
+LL | fn bad4() { unsafe { callback(||{}) } }
+ | ^^^^^^ unnecessary `unsafe` block
+
+error: unnecessary `unsafe` block
+ --> $DIR/lint-unused-unsafe.rs:23:20
+ |
+LL | unsafe fn bad5() { unsafe { unsf() } }
+ | ---------------- ^^^^^^ unnecessary `unsafe` block
+ | |
+ | because it's nested under this `unsafe` fn
+
+error: unnecessary `unsafe` block
+ --> $DIR/lint-unused-unsafe.rs:26:9
+ |
+LL | unsafe { // don't put the warning here
+ | ------ because it's nested under this `unsafe` block
+LL | unsafe {
+ | ^^^^^^ unnecessary `unsafe` block
+
+error: unnecessary `unsafe` block
+ --> $DIR/lint-unused-unsafe.rs:32:5
+ |
+LL | unsafe fn bad7() {
+ | ---------------- because it's nested under this `unsafe` fn
+LL | unsafe {
+ | ^^^^^^ unnecessary `unsafe` block
+
+error: unnecessary `unsafe` block
+ --> $DIR/lint-unused-unsafe.rs:33:9
+ |
+LL | unsafe fn bad7() {
+ | ---------------- because it's nested under this `unsafe` fn
+LL | unsafe {
+LL | unsafe {
+ | ^^^^^^ unnecessary `unsafe` block
+
+error: aborting due to 8 previous errors
+
// Exercise the unused_unsafe attribute in some positive and negative cases
+// revisions: mir thir
+// [thir]compile-flags: -Zthir-unsafeck
+
#![allow(dead_code)]
#![deny(unused_unsafe)]
+++ /dev/null
-error: unnecessary `unsafe` block
- --> $DIR/lint-unused-unsafe.rs:16:13
- |
-LL | fn bad1() { unsafe {} }
- | ^^^^^^ unnecessary `unsafe` block
- |
-note: the lint level is defined here
- --> $DIR/lint-unused-unsafe.rs:4:9
- |
-LL | #![deny(unused_unsafe)]
- | ^^^^^^^^^^^^^
-
-error: unnecessary `unsafe` block
- --> $DIR/lint-unused-unsafe.rs:17:13
- |
-LL | fn bad2() { unsafe { bad1() } }
- | ^^^^^^ unnecessary `unsafe` block
-
-error: unnecessary `unsafe` block
- --> $DIR/lint-unused-unsafe.rs:18:20
- |
-LL | unsafe fn bad3() { unsafe {} }
- | ---------------- ^^^^^^ unnecessary `unsafe` block
- | |
- | because it's nested under this `unsafe` fn
-
-error: unnecessary `unsafe` block
- --> $DIR/lint-unused-unsafe.rs:19:13
- |
-LL | fn bad4() { unsafe { callback(||{}) } }
- | ^^^^^^ unnecessary `unsafe` block
-
-error: unnecessary `unsafe` block
- --> $DIR/lint-unused-unsafe.rs:20:20
- |
-LL | unsafe fn bad5() { unsafe { unsf() } }
- | ---------------- ^^^^^^ unnecessary `unsafe` block
- | |
- | because it's nested under this `unsafe` fn
-
-error: unnecessary `unsafe` block
- --> $DIR/lint-unused-unsafe.rs:23:9
- |
-LL | unsafe { // don't put the warning here
- | ------ because it's nested under this `unsafe` block
-LL | unsafe {
- | ^^^^^^ unnecessary `unsafe` block
-
-error: unnecessary `unsafe` block
- --> $DIR/lint-unused-unsafe.rs:29:5
- |
-LL | unsafe fn bad7() {
- | ---------------- because it's nested under this `unsafe` fn
-LL | unsafe {
- | ^^^^^^ unnecessary `unsafe` block
-
-error: unnecessary `unsafe` block
- --> $DIR/lint-unused-unsafe.rs:30:9
- |
-LL | unsafe fn bad7() {
- | ---------------- because it's nested under this `unsafe` fn
-LL | unsafe {
-LL | unsafe {
- | ^^^^^^ unnecessary `unsafe` block
-
-error: aborting due to 8 previous errors
-
--- /dev/null
+error: unnecessary `unsafe` block
+ --> $DIR/lint-unused-unsafe.rs:19:13
+ |
+LL | fn bad1() { unsafe {} }
+ | ^^^^^^ unnecessary `unsafe` block
+ |
+note: the lint level is defined here
+ --> $DIR/lint-unused-unsafe.rs:7:9
+ |
+LL | #![deny(unused_unsafe)]
+ | ^^^^^^^^^^^^^
+
+error: unnecessary `unsafe` block
+ --> $DIR/lint-unused-unsafe.rs:20:13
+ |
+LL | fn bad2() { unsafe { bad1() } }
+ | ^^^^^^ unnecessary `unsafe` block
+
+error: unnecessary `unsafe` block
+ --> $DIR/lint-unused-unsafe.rs:21:20
+ |
+LL | unsafe fn bad3() { unsafe {} }
+ | ---------------- ^^^^^^ unnecessary `unsafe` block
+ | |
+ | because it's nested under this `unsafe` fn
+
+error: unnecessary `unsafe` block
+ --> $DIR/lint-unused-unsafe.rs:22:13
+ |
+LL | fn bad4() { unsafe { callback(||{}) } }
+ | ^^^^^^ unnecessary `unsafe` block
+
+error: unnecessary `unsafe` block
+ --> $DIR/lint-unused-unsafe.rs:23:20
+ |
+LL | unsafe fn bad5() { unsafe { unsf() } }
+ | ---------------- ^^^^^^ unnecessary `unsafe` block
+ | |
+ | because it's nested under this `unsafe` fn
+
+error: unnecessary `unsafe` block
+ --> $DIR/lint-unused-unsafe.rs:26:9
+ |
+LL | unsafe { // don't put the warning here
+ | ------ because it's nested under this `unsafe` block
+LL | unsafe {
+ | ^^^^^^ unnecessary `unsafe` block
+
+error: unnecessary `unsafe` block
+ --> $DIR/lint-unused-unsafe.rs:33:9
+ |
+LL | unsafe {
+ | ------ because it's nested under this `unsafe` block
+LL | unsafe {
+ | ^^^^^^ unnecessary `unsafe` block
+
+error: unnecessary `unsafe` block
+ --> $DIR/lint-unused-unsafe.rs:32:5
+ |
+LL | unsafe fn bad7() {
+ | ---------------- because it's nested under this `unsafe` fn
+LL | unsafe {
+ | ^^^^^^ unnecessary `unsafe` block
+
+error: aborting due to 8 previous errors
+
--- /dev/null
+// force-host
+// no-prefer-dynamic
+#![crate_type = "proc-macro"]
+#![feature(proc_macro_quote)]
+
+extern crate proc_macro;
+
+use proc_macro::{quote, TokenStream};
+
+#[proc_macro_attribute]
+pub fn hello(_: TokenStream, _: TokenStream) -> TokenStream {
+ quote!(
+ fn f(_: &mut i32) {}
+ fn g() {
+ f(123);
+ }
+ )
+}
//~^ ERROR mismatched types
let b: String = &format!("b");
//~^ ERROR mismatched types
+ let c: String = &mut format!("c");
+ //~^ ERROR mismatched types
+ let d: String = &mut (format!("d"));
+ //~^ ERROR mismatched types
}
| | help: consider removing the borrow: `format!("b")`
| expected due to this
-error: aborting due to 2 previous errors
+error[E0308]: mismatched types
+ --> $DIR/format-borrow.rs:6:21
+ |
+LL | let c: String = &mut format!("c");
+ | ------ ^^^^^^^^^^^^^^^^^
+ | | |
+ | | expected struct `String`, found `&mut String`
+ | | help: consider removing the borrow: `format!("c")`
+ | expected due to this
+
+error[E0308]: mismatched types
+ --> $DIR/format-borrow.rs:8:21
+ |
+LL | let d: String = &mut (format!("d"));
+ | ------ ^^^^^^^^^^^^^^^^^^^
+ | | |
+ | | expected struct `String`, found `&mut String`
+ | | help: consider removing the borrow: `format!("d")`
+ | expected due to this
+
+error: aborting due to 4 previous errors
For more information about this error, try `rustc --explain E0308`.
--- /dev/null
+// Regression test for #85943: should not emit suggestions for adding
+// indirection to type parameters in where-clauses when suggesting
+// adding `?Sized`.
+struct A<T>(T) where T: Send;
+struct B(A<[u8]>);
+//~^ ERROR the size for values of type
+
+pub fn main() {
+}
--- /dev/null
+error[E0277]: the size for values of type `[u8]` cannot be known at compilation time
+ --> $DIR/issue-85943-no-suggest-unsized-indirection-in-where-clause.rs:5:10
+ |
+LL | struct A<T>(T) where T: Send;
+ | - required by this bound in `A`
+LL | struct B(A<[u8]>);
+ | ^^^^^^^ doesn't have a size known at compile-time
+ |
+ = help: the trait `Sized` is not implemented for `[u8]`
+help: you could relax the implicit `Sized` bound on `T` if it were used through indirection like `&T` or `Box<T>`
+ --> $DIR/issue-85943-no-suggest-unsized-indirection-in-where-clause.rs:4:10
+ |
+LL | struct A<T>(T) where T: Send;
+ | ^ - ...if indirection were used here: `Box<T>`
+ | |
+ | this could be changed to `T: ?Sized`...
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0277`.
--- /dev/null
+// Tests that a suggestion is issued for type mismatch errors when a
+// 1-tuple is expected and a parenthesized expression of non-tuple
+// type is supplied.
+
+fn foo<T>(_t: (T,)) {}
+struct S { _s: (String,) }
+
+fn main() {
+ let _x: (i32,) = (5);
+ //~^ ERROR: mismatched types [E0308]
+ //~| HELP: use a trailing comma to create a tuple with one element
+
+ foo((Some(3)));
+ //~^ ERROR: mismatched types [E0308]
+ //~| HELP: use a trailing comma to create a tuple with one element
+
+ let _s = S { _s: ("abc".to_string()) };
+ //~^ ERROR: mismatched types [E0308]
+ //~| HELP: use a trailing comma to create a tuple with one element
+
+ // Do not issue the suggestion if the found type is already a tuple.
+ let t = (1, 2);
+ let _x: (i32,) = (t);
+ //~^ ERROR: mismatched types [E0308]
+}
--- /dev/null
+error[E0308]: mismatched types
+ --> $DIR/issue-86100-tuple-paren-comma.rs:9:22
+ |
+LL | let _x: (i32,) = (5);
+ | ------ ^^^ expected tuple, found integer
+ | |
+ | expected due to this
+ |
+ = note: expected tuple `(i32,)`
+ found type `{integer}`
+help: use a trailing comma to create a tuple with one element
+ |
+LL | let _x: (i32,) = (5,);
+ | ^^^^
+
+error[E0308]: mismatched types
+ --> $DIR/issue-86100-tuple-paren-comma.rs:13:9
+ |
+LL | foo((Some(3)));
+ | ^^^^^^^^^ expected tuple, found enum `Option`
+ |
+ = note: expected tuple `(_,)`
+ found enum `Option<{integer}>`
+help: use a trailing comma to create a tuple with one element
+ |
+LL | foo((Some(3),));
+ | ^^^^^^^^^^
+
+error[E0308]: mismatched types
+ --> $DIR/issue-86100-tuple-paren-comma.rs:17:22
+ |
+LL | let _s = S { _s: ("abc".to_string()) };
+ | ^^^^^^^^^^^^^^^^^^^ expected tuple, found struct `String`
+ |
+ = note: expected tuple `(String,)`
+ found struct `String`
+help: use a trailing comma to create a tuple with one element
+ |
+LL | let _s = S { _s: ("abc".to_string(),) };
+ | ^^^^^^^^^^^^^^^^^^^^
+
+error[E0308]: mismatched types
+ --> $DIR/issue-86100-tuple-paren-comma.rs:23:22
+ |
+LL | let _x: (i32,) = (t);
+ | ------ ^^^ expected a tuple with 1 element, found one with 2 elements
+ | |
+ | expected due to this
+ |
+ = note: expected tuple `(i32,)`
+ found tuple `({integer}, {integer})`
+
+error: aborting due to 4 previous errors
+
+For more information about this error, try `rustc --explain E0308`.
--- /dev/null
+// run-check
+// aux-build:proc-macro-type-error.rs
+
+extern crate proc_macro_type_error;
+
+use proc_macro_type_error::hello;
+
+#[hello] //~ERROR mismatched types
+fn abc() {}
+
+fn x(_: &mut i32) {}
+
+macro_rules! bla {
+ () => {
+ x(123);
+ //~^ ERROR mismatched types
+ //~| SUGGESTION &mut 123
+ };
+ ($v:expr) => {
+ x($v)
+ }
+}
+
+fn main() {
+ bla!();
+ bla!(456);
+ //~^ ERROR mismatched types
+ //~| SUGGESTION &mut 456
+}
--- /dev/null
+error[E0308]: mismatched types
+ --> $DIR/suggest-ref-macro.rs:8:1
+ |
+LL | #[hello]
+ | ^^^^^^^^ expected `&mut i32`, found integer
+ |
+ = note: this error originates in the attribute macro `hello` (in Nightly builds, run with -Z macro-backtrace for more info)
+
+error[E0308]: mismatched types
+ --> $DIR/suggest-ref-macro.rs:15:11
+ |
+LL | x(123);
+ | ^^^
+ | |
+ | expected `&mut i32`, found integer
+ | help: consider mutably borrowing here: `&mut 123`
+...
+LL | bla!();
+ | ------- in this macro invocation
+ |
+ = note: this error originates in the macro `bla` (in Nightly builds, run with -Z macro-backtrace for more info)
+
+error[E0308]: mismatched types
+ --> $DIR/suggest-ref-macro.rs:26:10
+ |
+LL | bla!(456);
+ | ^^^
+ | |
+ | expected `&mut i32`, found integer
+ | help: consider mutably borrowing here: `&mut 456`
+
+error: aborting due to 3 previous errors
+
+For more information about this error, try `rustc --explain E0308`.
--- /dev/null
+// Test that we do not suggest to add type annotations for unnamable types.
+
+#![crate_type="lib"]
+#![feature(generators)]
+
+const A = 5;
+//~^ ERROR: missing type for `const` item
+//~| HELP: provide a type for the item
+
+static B: _ = "abc";
+//~^ ERROR: the type placeholder `_` is not allowed within types on item signatures
+//~| NOTE: not allowed in type signatures
+//~| HELP: replace with the correct type
+
+
+// FIXME: this should also suggest a function pointer, as the closure is non-capturing
+const C: _ = || 42;
+//~^ ERROR: the type placeholder `_` is not allowed within types on item signatures
+//~| NOTE: not allowed in type signatures
+//~| NOTE: however, the inferred type
+
+struct S<T> { t: T }
+const D = S { t: { let i = 0; move || -> i32 { i } } };
+//~^ ERROR: missing type for `const` item
+//~| NOTE: however, the inferred type
+
+
+fn foo() -> i32 { 42 }
+const E = foo;
+//~^ ERROR: missing type for `const` item
+//~| HELP: provide a type for the item
+const F = S { t: foo };
+//~^ ERROR: missing type for `const` item
+//~| HELP: provide a type for the item
+
+
+const G = || -> i32 { yield 0; return 1; };
+//~^ ERROR: missing type for `const` item
+//~| NOTE: however, the inferred type
--- /dev/null
+error: missing type for `const` item
+ --> $DIR/unnamable-types.rs:6:7
+ |
+LL | const A = 5;
+ | ^ help: provide a type for the item: `A: i32`
+
+error[E0121]: the type placeholder `_` is not allowed within types on item signatures
+ --> $DIR/unnamable-types.rs:10:11
+ |
+LL | static B: _ = "abc";
+ | ^
+ | |
+ | not allowed in type signatures
+ | help: replace with the correct type: `&str`
+
+error[E0121]: the type placeholder `_` is not allowed within types on item signatures
+ --> $DIR/unnamable-types.rs:17:10
+ |
+LL | const C: _ = || 42;
+ | ^ not allowed in type signatures
+ |
+note: however, the inferred type `[closure@$DIR/unnamable-types.rs:17:14: 17:19]` cannot be named
+ --> $DIR/unnamable-types.rs:17:14
+ |
+LL | const C: _ = || 42;
+ | ^^^^^
+
+error: missing type for `const` item
+ --> $DIR/unnamable-types.rs:23:7
+ |
+LL | const D = S { t: { let i = 0; move || -> i32 { i } } };
+ | ^
+ |
+note: however, the inferred type `S<[closure@$DIR/unnamable-types.rs:23:31: 23:51]>` cannot be named
+ --> $DIR/unnamable-types.rs:23:11
+ |
+LL | const D = S { t: { let i = 0; move || -> i32 { i } } };
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+error: missing type for `const` item
+ --> $DIR/unnamable-types.rs:29:7
+ |
+LL | const E = foo;
+ | ^ help: provide a type for the item: `E: fn() -> i32`
+
+error: missing type for `const` item
+ --> $DIR/unnamable-types.rs:32:7
+ |
+LL | const F = S { t: foo };
+ | ^ help: provide a type for the item: `F: S<fn() -> i32>`
+
+error: missing type for `const` item
+ --> $DIR/unnamable-types.rs:37:7
+ |
+LL | const G = || -> i32 { yield 0; return 1; };
+ | ^
+ |
+note: however, the inferred type `[generator@$DIR/unnamable-types.rs:37:11: 37:43]` cannot be named
+ --> $DIR/unnamable-types.rs:37:11
+ |
+LL | const G = || -> i32 { yield 0; return 1; };
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+error: aborting due to 7 previous errors
+
+For more information about this error, try `rustc --explain E0121`.
// gate-test-f16c_target_feature
// gate-test-riscv_target_feature
// gate-test-ermsb_target_feature
+// gate-test-bpf_target_feature
#[target_feature(enable = "avx512bw")]
//~^ ERROR: currently unstable
error[E0658]: the target feature `avx512bw` is currently unstable
- --> $DIR/gate.rs:31:18
+ --> $DIR/gate.rs:32:18
|
LL | #[target_feature(enable = "avx512bw")]
| ^^^^^^^^^^^^^^^^^^^
--- /dev/null
+// only-wasm32
+// check-pass
+
+#![feature(wasm_target_feature)]
+#![allow(dead_code)]
+
+#[target_feature(enable = "nontrapping-fptoint")]
+fn foo() {}
+
+#[target_feature(enable = "nontrapping-fptoint")]
+extern "C" fn bar() {}
+
+trait A {
+ fn foo();
+ fn bar(&self);
+}
+
+struct B;
+
+impl B {
+ #[target_feature(enable = "nontrapping-fptoint")]
+ fn foo() {}
+ #[target_feature(enable = "nontrapping-fptoint")]
+ fn bar(&self) {}
+}
+
+impl A for B {
+ #[target_feature(enable = "nontrapping-fptoint")]
+ fn foo() {}
+ #[target_feature(enable = "nontrapping-fptoint")]
+ fn bar(&self) {}
+}
+
+fn no_features_enabled_on_this_function() {
+ bar();
+ foo();
+ B.bar();
+ B::foo();
+ <B as A>::foo();
+ <B as A>::bar(&B);
+}
+
+#[target_feature(enable = "nontrapping-fptoint")]
+fn main() {}
--- /dev/null
+// compile-flags: --test
+// run-flags: --test-threads=1
+// check-run-results
+// normalize-stdout-test "finished in \d+\.\d+s" -> "finished in $$TIME"
+// ignore-emscripten no threads support
+// run-pass
+
+
+#[test]
+fn test_ok() {
+ let _a = true;
+}
+
+#[test]
+#[should_panic]
+fn test_panic() {
+ panic!();
+}
+
+#[test]
+#[ignore]
+fn test_no_run() {
+ loop{
+ println!("Hello, world");
+ }
+}
+
+fn main() {}
--- /dev/null
+
+running 3 tests
+test test_no_run ... ignored
+test test_ok ... ok
+test test_panic - should panic ... ok
+
+test result: ok. 2 passed; 0 failed; 1 ignored; 0 measured; 0 filtered out; finished in $TIME
+
running 4 tests
test it_fails ... about to fail
FAILED
-test it_panics ... about to panic
+test it_panics - should panic ... about to panic
ok
test it_works ... about to succeed
ok
running 5 tests
test it_exits ... FAILED
test it_fails ... FAILED
-test it_panics ... ok
+test it_panics - should panic ... ok
test it_works ... ok
test no_residual_environment ... ok
--- /dev/null
+// edition:2018
+
+#![feature(thread_local)]
+#![feature(const_swap)]
+#[thread_local]
+static mut STATIC_VAR_2: [u32; 8] = [4; 8];
+const fn g(x: &mut [u32; 8]) {
+ //~^ ERROR mutable references are not allowed
+ std::mem::swap(x, &mut STATIC_VAR_2)
+ //~^ ERROR thread-local statics cannot be accessed
+ //~| ERROR mutable references are not allowed
+ //~| ERROR use of mutable static is unsafe
+ //~| constant functions cannot refer to statics
+ //~| ERROR calls in constant functions are limited to constant functions
+}
+
+fn main() {}
--- /dev/null
+error[E0658]: mutable references are not allowed in constant functions
+ --> $DIR/thread-local-static.rs:7:12
+ |
+LL | const fn g(x: &mut [u32; 8]) {
+ | ^
+ |
+ = note: see issue #57349 <https://github.com/rust-lang/rust/issues/57349> for more information
+ = help: add `#![feature(const_mut_refs)]` to the crate attributes to enable
+
+error[E0625]: thread-local statics cannot be accessed at compile-time
+ --> $DIR/thread-local-static.rs:9:28
+ |
+LL | std::mem::swap(x, &mut STATIC_VAR_2)
+ | ^^^^^^^^^^^^
+
+error[E0013]: constant functions cannot refer to statics
+ --> $DIR/thread-local-static.rs:9:28
+ |
+LL | std::mem::swap(x, &mut STATIC_VAR_2)
+ | ^^^^^^^^^^^^
+ |
+ = help: consider extracting the value of the `static` to a `const`, and referring to that
+
+error[E0658]: mutable references are not allowed in constant functions
+ --> $DIR/thread-local-static.rs:9:23
+ |
+LL | std::mem::swap(x, &mut STATIC_VAR_2)
+ | ^^^^^^^^^^^^^^^^^
+ |
+ = note: see issue #57349 <https://github.com/rust-lang/rust/issues/57349> for more information
+ = help: add `#![feature(const_mut_refs)]` to the crate attributes to enable
+
+error[E0015]: calls in constant functions are limited to constant functions, tuple structs and tuple variants
+ --> $DIR/thread-local-static.rs:9:5
+ |
+LL | std::mem::swap(x, &mut STATIC_VAR_2)
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+error[E0133]: use of mutable static is unsafe and requires unsafe function or block
+ --> $DIR/thread-local-static.rs:9:23
+ |
+LL | std::mem::swap(x, &mut STATIC_VAR_2)
+ | ^^^^^^^^^^^^^^^^^ use of mutable static
+ |
+ = note: mutable statics can be mutated by multiple threads: aliasing violations or data races will cause undefined behavior
+
+error: aborting due to 6 previous errors
+
+Some errors have detailed explanations: E0013, E0015, E0133, E0658.
+For more information about an error, try `rustc --explain E0013`.
#[warn(foo::bar)]
//~^ ERROR unknown tool name `foo` found in scoped lint: `foo::bar`
//~| ERROR unknown tool name `foo` found in scoped lint: `foo::bar`
-//~| ERROR unknown tool name `foo` found in scoped lint: `foo::bar`
fn main() {}
|
= help: add `#![register_tool(foo)]` to the crate root
-error[E0710]: unknown tool name `foo` found in scoped lint: `foo::bar`
- --> $DIR/tool_lints.rs:1:8
- |
-LL | #[warn(foo::bar)]
- | ^^^
- |
- = help: add `#![register_tool(foo)]` to the crate root
-
-error: aborting due to 3 previous errors
+error: aborting due to 2 previous errors
For more information about this error, try `rustc --explain E0710`.
--- /dev/null
+// check-pass
+
+#![feature(trait_alias)]
+
+trait Foo = std::fmt::Display + std::fmt::Debug;
+trait bar = std::fmt::Display + std::fmt::Debug; //~WARN trait alias `bar` should have an upper camel case name
+
+fn main() {}
--- /dev/null
+warning: trait alias `bar` should have an upper camel case name
+ --> $DIR/style_lint.rs:6:7
+ |
+LL | trait bar = std::fmt::Display + std::fmt::Debug;
+ | ^^^ help: convert the identifier to upper camel case: `Bar`
+ |
+ = note: `#[warn(non_camel_case_types)]` on by default
+
+warning: 1 warning emitted
+
warning: the feature `type_alias_impl_trait` is incomplete and may not be safe to use and/or cause compiler crashes
- --> $DIR/issue-74761.rs:4:32
+ --> $DIR/issue-74761.rs:3:32
|
LL | #![cfg_attr(full_tait, feature(type_alias_impl_trait))]
| ^^^^^^^^^^^^^^^^^^^^^
= note: see issue #63063 <https://github.com/rust-lang/rust/issues/63063> for more information
error[E0207]: the lifetime parameter `'a` is not constrained by the impl trait, self type, or predicates
- --> $DIR/issue-74761.rs:11:6
+ --> $DIR/issue-74761.rs:10:6
|
LL | impl<'a, 'b> A for () {
| ^^ unconstrained lifetime parameter
error[E0207]: the lifetime parameter `'b` is not constrained by the impl trait, self type, or predicates
- --> $DIR/issue-74761.rs:11:10
+ --> $DIR/issue-74761.rs:10:10
|
LL | impl<'a, 'b> A for () {
| ^^ unconstrained lifetime parameter
error[E0207]: the lifetime parameter `'a` is not constrained by the impl trait, self type, or predicates
- --> $DIR/issue-74761.rs:11:6
+ --> $DIR/issue-74761.rs:10:6
|
LL | impl<'a, 'b> A for () {
| ^^ unconstrained lifetime parameter
error[E0207]: the lifetime parameter `'b` is not constrained by the impl trait, self type, or predicates
- --> $DIR/issue-74761.rs:11:10
+ --> $DIR/issue-74761.rs:10:10
|
LL | impl<'a, 'b> A for () {
| ^^ unconstrained lifetime parameter
-#![feature(member_constraints)]
// revisions: min_tait full_tait
#![feature(min_type_alias_impl_trait)]
#![cfg_attr(full_tait, feature(type_alias_impl_trait))]
--- /dev/null
+// check-pass
+#![feature(min_type_alias_impl_trait)]
+
+type X<A: ToString + Clone, B: ToString + Clone> = impl ToString;
+
+fn f<A: ToString + Clone, B: ToString + Clone>(a: A, b: B) -> (X<A, B>, X<A, B>) {
+ (a.clone(), a)
+}
+
+fn main() {
+ println!("{}", <X<_, _> as ToString>::to_string(&f(42_i32, String::new()).1));
+}
--- /dev/null
+// https://github.com/rust-lang/rust/issues/73481
+// This test used to cause unsoundness, since one of the two possible
+// resolutions was chosen at random instead of erroring due to conflicts.
+
+#![feature(min_type_alias_impl_trait)]
+
+type X<A, B> = impl Into<&'static A>;
+//~^ ERROR the trait bound `&'static B: From<&A>` is not satisfied
+
+fn f<A, B: 'static>(a: &'static A, b: B) -> (X<A, B>, X<B, A>) {
+ (a, a)
+}
+
+fn main() {
+ println!("{}", <X<_, _> as Into<&String>>::into(f(&[1isize, 2, 3], String::new()).1));
+}
--- /dev/null
+error[E0277]: the trait bound `&'static B: From<&A>` is not satisfied
+ --> $DIR/multiple-def-uses-in-one-fn.rs:7:16
+ |
+LL | type X<A, B> = impl Into<&'static A>;
+ | ^^^^^^^^^^^^^^^^^^^^^ the trait `From<&A>` is not implemented for `&'static B`
+ |
+ = note: required because of the requirements on the impl of `Into<&'static B>` for `&A`
+help: consider introducing a `where` bound, but there might be an alternative better way to express this requirement
+ |
+LL | fn f<A, B: 'static>(a: &'static A, b: B) -> (X<A, B>, X<B, A>) where &'static B: From<&A> {
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0277`.
--- /dev/null
+// https://github.com/rust-lang/rust/issues/73481
+// This test used to cause unsoundness, since one of the two possible
+// resolutions was chosen at random instead of erroring due to conflicts.
+
+#![feature(min_type_alias_impl_trait)]
+
+type X<A: ToString + Clone, B: ToString + Clone> = impl ToString;
+//~^ ERROR could not find defining uses
+
+fn f<A: ToString + Clone, B: ToString + Clone>(a: A, b: B) -> (X<A, B>, X<B, A>) {
+ (a.clone(), a)
+}
+
+fn main() {
+ println!("{}", <X<_, _> as ToString>::to_string(&f(42_i32, String::new()).1));
+}
--- /dev/null
+error: could not find defining uses
+ --> $DIR/multiple-def-uses-in-one-fn2.rs:7:52
+ |
+LL | type X<A: ToString + Clone, B: ToString + Clone> = impl ToString;
+ | ^^^^^^^^^^^^^
+
+error: aborting due to previous error
+
--- /dev/null
+// https://github.com/rust-lang/rust/issues/73481
+// This test used to cause unsoundness, since one of the two possible
+// resolutions was chosen at random instead of erroring due to conflicts.
+
+#![feature(min_type_alias_impl_trait)]
+
+type X<A: ToString + Clone, B: ToString + Clone> = impl ToString;
+
+fn f<A: ToString + Clone, B: ToString + Clone>(a: A, b: B) -> (X<A, B>, X<B, A>) {
+ (a, b)
+}
+
+fn g<A: ToString + Clone, B: ToString + Clone>(a: A, b: B) -> (X<A, B>, X<A, B>) {
+ (a, b)
+ //~^ ERROR mismatched types
+}
+
+fn main() {}
--- /dev/null
+error[E0308]: mismatched types
+ --> $DIR/multiple-def-uses-in-one-fn3.rs:14:9
+ |
+LL | fn g<A: ToString + Clone, B: ToString + Clone>(a: A, b: B) -> (X<A, B>, X<A, B>) {
+ | - - found type parameter
+ | |
+ | expected type parameter
+LL | (a, b)
+ | ^ expected type parameter `A`, found type parameter `B`
+ |
+ = note: expected type parameter `A`
+ found type parameter `B`
+ = note: a type parameter was expected, but a different one was found; you might be missing a type parameter or trait bound
+ = note: for more information, visit https://doc.rust-lang.org/book/ch10-02-traits.html#traits-as-parameters
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0308`.
| ^
| |
| not allowed in type signatures
- | help: replace `_` with the correct type: `&str`
+ | help: replace with the correct type: `&str`
error[E0121]: the type placeholder `_` is not allowed within types on item signatures
--> $DIR/typeck_type_placeholder_item.rs:19:15
| ^
| |
| not allowed in type signatures
- | help: replace `_` with the correct type: `i32`
+ | help: replace with the correct type: `i32`
error[E0121]: the type placeholder `_` is not allowed within types on item signatures
--> $DIR/typeck_type_placeholder_item.rs:22:15
| ^
| |
| not allowed in type signatures
- | help: replace `_` with the correct type: `i32`
+ | help: replace with the correct type: `i32`
error[E0121]: the type placeholder `_` is not allowed within types on item signatures
--> $DIR/typeck_type_placeholder_item.rs:80:15
| ^
| |
| not allowed in type signatures
- | help: replace `_` with the correct type: `&str`
+ | help: replace with the correct type: `&str`
error[E0121]: the type placeholder `_` is not allowed within types on item signatures
--> $DIR/typeck_type_placeholder_item.rs:92:22
| ^
| |
| not allowed in type signatures
- | help: replace `_` with the correct type: `i32`
+ | help: replace with the correct type: `i32`
error[E0121]: the type placeholder `_` is not allowed within types on item signatures
--> $DIR/typeck_type_placeholder_item.rs:95:22
| ^^^^^^^^^
| |
| not allowed in type signatures
- | help: replace `_` with the correct type: `Option<u8>`
+ | help: replace with the correct type: `Option<u8>`
error[E0121]: the type placeholder `_` is not allowed within types on item signatures
--> $DIR/typeck_type_placeholder_item.rs:144:31
| ^
| |
| not allowed in type signatures
- | help: replace `_` with the correct type: `i32`
+ | help: replace with the correct type: `i32`
error[E0121]: the type placeholder `_` is not allowed within types on item signatures
--> $DIR/typeck_type_placeholder_item.rs:201:26
| ^
| |
| not allowed in type signatures
- | help: replace `_` with the correct type: `i32`
+ | help: replace with the correct type: `i32`
error: aborting due to 69 previous errors; 1 warning emitted
| ^
| |
| not allowed in type signatures
- | help: replace `_` with the correct type: `&str`
+ | help: replace with the correct type: `&str`
error[E0121]: the type placeholder `_` is not allowed within types on item signatures
--> $DIR/typeck_type_placeholder_item.rs:19:15
| ^
| |
| not allowed in type signatures
- | help: replace `_` with the correct type: `i32`
+ | help: replace with the correct type: `i32`
error[E0121]: the type placeholder `_` is not allowed within types on item signatures
--> $DIR/typeck_type_placeholder_item.rs:22:15
| ^
| |
| not allowed in type signatures
- | help: replace `_` with the correct type: `i32`
+ | help: replace with the correct type: `i32`
error[E0121]: the type placeholder `_` is not allowed within types on item signatures
--> $DIR/typeck_type_placeholder_item.rs:80:15
| ^
| |
| not allowed in type signatures
- | help: replace `_` with the correct type: `&str`
+ | help: replace with the correct type: `&str`
error[E0121]: the type placeholder `_` is not allowed within types on item signatures
--> $DIR/typeck_type_placeholder_item.rs:92:22
| ^
| |
| not allowed in type signatures
- | help: replace `_` with the correct type: `i32`
+ | help: replace with the correct type: `i32`
error[E0121]: the type placeholder `_` is not allowed within types on item signatures
--> $DIR/typeck_type_placeholder_item.rs:95:22
| ^^^^^^^^^
| |
| not allowed in type signatures
- | help: replace `_` with the correct type: `Option<u8>`
+ | help: replace with the correct type: `Option<u8>`
error[E0121]: the type placeholder `_` is not allowed within types on item signatures
--> $DIR/typeck_type_placeholder_item.rs:144:31
| ^
| |
| not allowed in type signatures
- | help: replace `_` with the correct type: `i32`
+ | help: replace with the correct type: `i32`
error[E0121]: the type placeholder `_` is not allowed within types on item signatures
--> $DIR/typeck_type_placeholder_item.rs:201:26
| ^
| |
| not allowed in type signatures
- | help: replace `_` with the correct type: `i32`
+ | help: replace with the correct type: `i32`
error: aborting due to 69 previous errors
| ^
| |
| not allowed in type signatures
- | help: replace `_` with the correct type: `u32`
+ | help: replace with the correct type: `u32`
error[E0121]: the type placeholder `_` is not allowed within types on item signatures
--> $DIR/typeck_type_placeholder_item_help.rs:10:14
| ^
| |
| not allowed in type signatures
- | help: replace `_` with the correct type: `Option<i32>`
+ | help: replace with the correct type: `Option<i32>`
error[E0121]: the type placeholder `_` is not allowed within types on item signatures
--> $DIR/typeck_type_placeholder_item_help.rs:13:22
| ^
| |
| not allowed in type signatures
- | help: replace `_` with the correct type: `i32`
+ | help: replace with the correct type: `i32`
error[E0121]: the type placeholder `_` is not allowed within types on item signatures
--> $DIR/typeck_type_placeholder_item_help.rs:24:18
| ^
| |
| not allowed in type signatures
- | help: replace `_` with the correct type: `i32`
+ | help: replace with the correct type: `i32`
error: aborting due to 6 previous errors
#![deny(foo::bar)] //~ ERROR unknown tool name `foo` found in scoped lint: `foo::bar`
//~| ERROR unknown tool name `foo` found in scoped lint: `foo::bar`
- //~| ERROR unknown tool name `foo` found in scoped lint: `foo::bar`
#[allow(foo::bar)] //~ ERROR unknown tool name `foo` found in scoped lint: `foo::bar`
//~| ERROR unknown tool name `foo` found in scoped lint: `foo::bar`
- //~| ERROR unknown tool name `foo` found in scoped lint: `foo::bar`
fn main() {}
= help: add `#![register_tool(foo)]` to the crate root
error[E0710]: unknown tool name `foo` found in scoped lint: `foo::bar`
- --> $DIR/unknown-lint-tool-name.rs:5:9
+ --> $DIR/unknown-lint-tool-name.rs:4:9
|
LL | #[allow(foo::bar)]
| ^^^
= help: add `#![register_tool(foo)]` to the crate root
error[E0710]: unknown tool name `foo` found in scoped lint: `foo::bar`
- --> $DIR/unknown-lint-tool-name.rs:5:9
+ --> $DIR/unknown-lint-tool-name.rs:4:9
|
LL | #[allow(foo::bar)]
| ^^^
|
= help: add `#![register_tool(foo)]` to the crate root
-error[E0710]: unknown tool name `foo` found in scoped lint: `foo::bar`
- --> $DIR/unknown-lint-tool-name.rs:1:9
- |
-LL | #![deny(foo::bar)]
- | ^^^
- |
- = help: add `#![register_tool(foo)]` to the crate root
-
-error[E0710]: unknown tool name `foo` found in scoped lint: `foo::bar`
- --> $DIR/unknown-lint-tool-name.rs:5:9
- |
-LL | #[allow(foo::bar)]
- | ^^^
- |
- = help: add `#![register_tool(foo)]` to the crate root
-
-error: aborting due to 6 previous errors
+error: aborting due to 4 previous errors
For more information about this error, try `rustc --explain E0710`.
--- /dev/null
+// check-pass
+// revisions: mir thir
+// [thir]compile-flags: -Z thir-unsafeck
+
+// This is issue #85435. But the real story is reflected in issue #85561, where
+// a bug in the implementation of feature(capture_disjoint_fields) () was
+// exposed to non-feature-gated code by a diagnostic changing PR that removed
+// the gating in one case.
+
+// This test is double-checking that the case of interest continues to work as
+// expected in the *absence* of that feature gate. At the time of this writing,
+// enabling the feature gate will cause this test to fail. We obviously cannot
+// stabilize that feature until it can correctly handle this test.
+
+fn main() {
+ let val: u8 = 5;
+ let u8_ptr: *const u8 = &val;
+ let _closure = || {
+ unsafe {
+ let tmp = *u8_ptr;
+ tmp
+
+ // Just dereferencing and returning directly compiles fine:
+ // *u8_ptr
+ }
+ };
+}
--- /dev/null
+error: call to unsafe function is unsafe and requires unsafe block (error E0133)
+ --> $DIR/rfc-2585-unsafe_op_in_unsafe_fn.rs:12:5
+ |
+LL | unsf();
+ | ^^^^^^ call to unsafe function
+ |
+note: the lint level is defined here
+ --> $DIR/rfc-2585-unsafe_op_in_unsafe_fn.rs:4:9
+ |
+LL | #![deny(unsafe_op_in_unsafe_fn)]
+ | ^^^^^^^^^^^^^^^^^^^^^^
+ = note: consult the function's documentation for information on how to avoid undefined behavior
+
+error: dereference of raw pointer is unsafe and requires unsafe block (error E0133)
+ --> $DIR/rfc-2585-unsafe_op_in_unsafe_fn.rs:14:5
+ |
+LL | *PTR;
+ | ^^^^ dereference of raw pointer
+ |
+ = note: raw pointers may be null, dangling or unaligned; they can violate aliasing rules and cause data races: all of these are undefined behavior
+
+error: use of mutable static is unsafe and requires unsafe block (error E0133)
+ --> $DIR/rfc-2585-unsafe_op_in_unsafe_fn.rs:16:5
+ |
+LL | VOID = ();
+ | ^^^^^^^^^ use of mutable static
+ |
+ = note: mutable statics can be mutated by multiple threads: aliasing violations or data races will cause undefined behavior
+
+error: unnecessary `unsafe` block
+ --> $DIR/rfc-2585-unsafe_op_in_unsafe_fn.rs:19:5
+ |
+LL | unsafe {}
+ | ^^^^^^ unnecessary `unsafe` block
+ |
+note: the lint level is defined here
+ --> $DIR/rfc-2585-unsafe_op_in_unsafe_fn.rs:5:9
+ |
+LL | #![deny(unused_unsafe)]
+ | ^^^^^^^^^^^^^
+
+error: call to unsafe function is unsafe and requires unsafe block (error E0133)
+ --> $DIR/rfc-2585-unsafe_op_in_unsafe_fn.rs:27:5
+ |
+LL | unsf();
+ | ^^^^^^ call to unsafe function
+ |
+note: the lint level is defined here
+ --> $DIR/rfc-2585-unsafe_op_in_unsafe_fn.rs:25:8
+ |
+LL | #[deny(warnings)]
+ | ^^^^^^^^
+ = note: `#[deny(unsafe_op_in_unsafe_fn)]` implied by `#[deny(warnings)]`
+ = note: consult the function's documentation for information on how to avoid undefined behavior
+
+error: dereference of raw pointer is unsafe and requires unsafe block (error E0133)
+ --> $DIR/rfc-2585-unsafe_op_in_unsafe_fn.rs:29:5
+ |
+LL | *PTR;
+ | ^^^^ dereference of raw pointer
+ |
+ = note: raw pointers may be null, dangling or unaligned; they can violate aliasing rules and cause data races: all of these are undefined behavior
+
+error: use of mutable static is unsafe and requires unsafe block (error E0133)
+ --> $DIR/rfc-2585-unsafe_op_in_unsafe_fn.rs:31:5
+ |
+LL | VOID = ();
+ | ^^^^^^^^^ use of mutable static
+ |
+ = note: mutable statics can be mutated by multiple threads: aliasing violations or data races will cause undefined behavior
+
+error: unnecessary `unsafe` block
+ --> $DIR/rfc-2585-unsafe_op_in_unsafe_fn.rs:33:5
+ |
+LL | unsafe {}
+ | ^^^^^^ unnecessary `unsafe` block
+
+error: unnecessary `unsafe` block
+ --> $DIR/rfc-2585-unsafe_op_in_unsafe_fn.rs:47:14
+ |
+LL | unsafe { unsafe { unsf() } }
+ | ------ ^^^^^^ unnecessary `unsafe` block
+ | |
+ | because it's nested under this `unsafe` block
+
+error: unnecessary `unsafe` block
+ --> $DIR/rfc-2585-unsafe_op_in_unsafe_fn.rs:58:5
+ |
+LL | unsafe fn allow_level() {
+ | ----------------------- because it's nested under this `unsafe` fn
+...
+LL | unsafe { unsf() }
+ | ^^^^^^ unnecessary `unsafe` block
+
+error: unnecessary `unsafe` block
+ --> $DIR/rfc-2585-unsafe_op_in_unsafe_fn.rs:70:9
+ |
+LL | unsafe fn nested_allow_level() {
+ | ------------------------------ because it's nested under this `unsafe` fn
+...
+LL | unsafe { unsf() }
+ | ^^^^^^ unnecessary `unsafe` block
+
+error[E0133]: call to unsafe function is unsafe and requires unsafe block
+ --> $DIR/rfc-2585-unsafe_op_in_unsafe_fn.rs:76:5
+ |
+LL | unsf();
+ | ^^^^^^ call to unsafe function
+ |
+ = note: consult the function's documentation for information on how to avoid undefined behavior
+
+error[E0133]: call to unsafe function is unsafe and requires unsafe function or block
+ --> $DIR/rfc-2585-unsafe_op_in_unsafe_fn.rs:80:9
+ |
+LL | unsf();
+ | ^^^^^^ call to unsafe function
+ |
+ = note: consult the function's documentation for information on how to avoid undefined behavior
+
+error: aborting due to 13 previous errors
+
+For more information about this error, try `rustc --explain E0133`.
+// revisions: mir thir
+// [thir]compile-flags: -Zthir-unsafeck
+
#![deny(unsafe_op_in_unsafe_fn)]
#![deny(unused_unsafe)]
+++ /dev/null
-error: call to unsafe function is unsafe and requires unsafe block (error E0133)
- --> $DIR/rfc-2585-unsafe_op_in_unsafe_fn.rs:9:5
- |
-LL | unsf();
- | ^^^^^^ call to unsafe function
- |
-note: the lint level is defined here
- --> $DIR/rfc-2585-unsafe_op_in_unsafe_fn.rs:1:9
- |
-LL | #![deny(unsafe_op_in_unsafe_fn)]
- | ^^^^^^^^^^^^^^^^^^^^^^
- = note: consult the function's documentation for information on how to avoid undefined behavior
-
-error: dereference of raw pointer is unsafe and requires unsafe block (error E0133)
- --> $DIR/rfc-2585-unsafe_op_in_unsafe_fn.rs:11:5
- |
-LL | *PTR;
- | ^^^^ dereference of raw pointer
- |
- = note: raw pointers may be null, dangling or unaligned; they can violate aliasing rules and cause data races: all of these are undefined behavior
-
-error: use of mutable static is unsafe and requires unsafe block (error E0133)
- --> $DIR/rfc-2585-unsafe_op_in_unsafe_fn.rs:13:5
- |
-LL | VOID = ();
- | ^^^^^^^^^ use of mutable static
- |
- = note: mutable statics can be mutated by multiple threads: aliasing violations or data races will cause undefined behavior
-
-error: unnecessary `unsafe` block
- --> $DIR/rfc-2585-unsafe_op_in_unsafe_fn.rs:16:5
- |
-LL | unsafe {}
- | ^^^^^^ unnecessary `unsafe` block
- |
-note: the lint level is defined here
- --> $DIR/rfc-2585-unsafe_op_in_unsafe_fn.rs:2:9
- |
-LL | #![deny(unused_unsafe)]
- | ^^^^^^^^^^^^^
-
-error: call to unsafe function is unsafe and requires unsafe block (error E0133)
- --> $DIR/rfc-2585-unsafe_op_in_unsafe_fn.rs:24:5
- |
-LL | unsf();
- | ^^^^^^ call to unsafe function
- |
-note: the lint level is defined here
- --> $DIR/rfc-2585-unsafe_op_in_unsafe_fn.rs:22:8
- |
-LL | #[deny(warnings)]
- | ^^^^^^^^
- = note: `#[deny(unsafe_op_in_unsafe_fn)]` implied by `#[deny(warnings)]`
- = note: consult the function's documentation for information on how to avoid undefined behavior
-
-error: dereference of raw pointer is unsafe and requires unsafe block (error E0133)
- --> $DIR/rfc-2585-unsafe_op_in_unsafe_fn.rs:26:5
- |
-LL | *PTR;
- | ^^^^ dereference of raw pointer
- |
- = note: raw pointers may be null, dangling or unaligned; they can violate aliasing rules and cause data races: all of these are undefined behavior
-
-error: use of mutable static is unsafe and requires unsafe block (error E0133)
- --> $DIR/rfc-2585-unsafe_op_in_unsafe_fn.rs:28:5
- |
-LL | VOID = ();
- | ^^^^^^^^^ use of mutable static
- |
- = note: mutable statics can be mutated by multiple threads: aliasing violations or data races will cause undefined behavior
-
-error: unnecessary `unsafe` block
- --> $DIR/rfc-2585-unsafe_op_in_unsafe_fn.rs:30:5
- |
-LL | unsafe {}
- | ^^^^^^ unnecessary `unsafe` block
-
-error: unnecessary `unsafe` block
- --> $DIR/rfc-2585-unsafe_op_in_unsafe_fn.rs:44:14
- |
-LL | unsafe { unsafe { unsf() } }
- | ------ ^^^^^^ unnecessary `unsafe` block
- | |
- | because it's nested under this `unsafe` block
-
-error: unnecessary `unsafe` block
- --> $DIR/rfc-2585-unsafe_op_in_unsafe_fn.rs:55:5
- |
-LL | unsafe fn allow_level() {
- | ----------------------- because it's nested under this `unsafe` fn
-...
-LL | unsafe { unsf() }
- | ^^^^^^ unnecessary `unsafe` block
-
-error: unnecessary `unsafe` block
- --> $DIR/rfc-2585-unsafe_op_in_unsafe_fn.rs:67:9
- |
-LL | unsafe fn nested_allow_level() {
- | ------------------------------ because it's nested under this `unsafe` fn
-...
-LL | unsafe { unsf() }
- | ^^^^^^ unnecessary `unsafe` block
-
-error[E0133]: call to unsafe function is unsafe and requires unsafe block
- --> $DIR/rfc-2585-unsafe_op_in_unsafe_fn.rs:73:5
- |
-LL | unsf();
- | ^^^^^^ call to unsafe function
- |
- = note: consult the function's documentation for information on how to avoid undefined behavior
-
-error[E0133]: call to unsafe function is unsafe and requires unsafe function or block
- --> $DIR/rfc-2585-unsafe_op_in_unsafe_fn.rs:77:9
- |
-LL | unsf();
- | ^^^^^^ call to unsafe function
- |
- = note: consult the function's documentation for information on how to avoid undefined behavior
-
-error: aborting due to 13 previous errors
-
-For more information about this error, try `rustc --explain E0133`.
--- /dev/null
+error: call to unsafe function is unsafe and requires unsafe block (error E0133)
+ --> $DIR/rfc-2585-unsafe_op_in_unsafe_fn.rs:12:5
+ |
+LL | unsf();
+ | ^^^^^^ call to unsafe function
+ |
+note: the lint level is defined here
+ --> $DIR/rfc-2585-unsafe_op_in_unsafe_fn.rs:4:9
+ |
+LL | #![deny(unsafe_op_in_unsafe_fn)]
+ | ^^^^^^^^^^^^^^^^^^^^^^
+ = note: consult the function's documentation for information on how to avoid undefined behavior
+
+error: dereference of raw pointer is unsafe and requires unsafe block (error E0133)
+ --> $DIR/rfc-2585-unsafe_op_in_unsafe_fn.rs:14:5
+ |
+LL | *PTR;
+ | ^^^^ dereference of raw pointer
+ |
+ = note: raw pointers may be null, dangling or unaligned; they can violate aliasing rules and cause data races: all of these are undefined behavior
+
+error: use of mutable static is unsafe and requires unsafe block (error E0133)
+ --> $DIR/rfc-2585-unsafe_op_in_unsafe_fn.rs:16:5
+ |
+LL | VOID = ();
+ | ^^^^ use of mutable static
+ |
+ = note: mutable statics can be mutated by multiple threads: aliasing violations or data races will cause undefined behavior
+
+error: unnecessary `unsafe` block
+ --> $DIR/rfc-2585-unsafe_op_in_unsafe_fn.rs:19:5
+ |
+LL | unsafe {}
+ | ^^^^^^ unnecessary `unsafe` block
+ |
+note: the lint level is defined here
+ --> $DIR/rfc-2585-unsafe_op_in_unsafe_fn.rs:5:9
+ |
+LL | #![deny(unused_unsafe)]
+ | ^^^^^^^^^^^^^
+
+error: call to unsafe function is unsafe and requires unsafe block (error E0133)
+ --> $DIR/rfc-2585-unsafe_op_in_unsafe_fn.rs:27:5
+ |
+LL | unsf();
+ | ^^^^^^ call to unsafe function
+ |
+note: the lint level is defined here
+ --> $DIR/rfc-2585-unsafe_op_in_unsafe_fn.rs:25:8
+ |
+LL | #[deny(warnings)]
+ | ^^^^^^^^
+ = note: `#[deny(unsafe_op_in_unsafe_fn)]` implied by `#[deny(warnings)]`
+ = note: consult the function's documentation for information on how to avoid undefined behavior
+
+error: dereference of raw pointer is unsafe and requires unsafe block (error E0133)
+ --> $DIR/rfc-2585-unsafe_op_in_unsafe_fn.rs:29:5
+ |
+LL | *PTR;
+ | ^^^^ dereference of raw pointer
+ |
+ = note: raw pointers may be null, dangling or unaligned; they can violate aliasing rules and cause data races: all of these are undefined behavior
+
+error: use of mutable static is unsafe and requires unsafe block (error E0133)
+ --> $DIR/rfc-2585-unsafe_op_in_unsafe_fn.rs:31:5
+ |
+LL | VOID = ();
+ | ^^^^ use of mutable static
+ |
+ = note: mutable statics can be mutated by multiple threads: aliasing violations or data races will cause undefined behavior
+
+error: unnecessary `unsafe` block
+ --> $DIR/rfc-2585-unsafe_op_in_unsafe_fn.rs:33:5
+ |
+LL | unsafe {}
+ | ^^^^^^ unnecessary `unsafe` block
+
+error: unnecessary `unsafe` block
+ --> $DIR/rfc-2585-unsafe_op_in_unsafe_fn.rs:47:14
+ |
+LL | unsafe { unsafe { unsf() } }
+ | ------ ^^^^^^ unnecessary `unsafe` block
+ | |
+ | because it's nested under this `unsafe` block
+
+error: unnecessary `unsafe` block
+ --> $DIR/rfc-2585-unsafe_op_in_unsafe_fn.rs:58:5
+ |
+LL | unsafe fn allow_level() {
+ | ----------------------- because it's nested under this `unsafe` fn
+...
+LL | unsafe { unsf() }
+ | ^^^^^^ unnecessary `unsafe` block
+
+error: unnecessary `unsafe` block
+ --> $DIR/rfc-2585-unsafe_op_in_unsafe_fn.rs:70:9
+ |
+LL | unsafe fn nested_allow_level() {
+ | ------------------------------ because it's nested under this `unsafe` fn
+...
+LL | unsafe { unsf() }
+ | ^^^^^^ unnecessary `unsafe` block
+
+error[E0133]: call to unsafe function is unsafe and requires unsafe block
+ --> $DIR/rfc-2585-unsafe_op_in_unsafe_fn.rs:76:5
+ |
+LL | unsf();
+ | ^^^^^^ call to unsafe function
+ |
+ = note: consult the function's documentation for information on how to avoid undefined behavior
+
+error[E0133]: call to unsafe function is unsafe and requires unsafe function or block
+ --> $DIR/rfc-2585-unsafe_op_in_unsafe_fn.rs:80:9
+ |
+LL | unsf();
+ | ^^^^^^ call to unsafe function
+ |
+ = note: consult the function's documentation for information on how to avoid undefined behavior
+
+error: aborting due to 13 previous errors
+
+For more information about this error, try `rustc --explain E0133`.
// --extern-location with bad location type
// aux-crate:bar=bar.rs
-// compile-flags:--extern-location bar=badloc:in-the-test-file
+// compile-flags:--extern-location bar=badloc:in-the-test-file -Z unstable-options
#![warn(unused_crate_dependencies)]
// --extern-location with a raw reference
// aux-crate:bar=bar.rs
-// compile-flags:--extern-location bar=json:[{"malformed
+// compile-flags:--extern-location bar=json:[{"malformed -Z unstable-options
#![warn(unused_crate_dependencies)]
// check-pass
// aux-crate:bar=bar.rs
-// compile-flags:--extern-location bar=json:{"key":123,"value":{}} --error-format json
+// compile-flags:--extern-location bar=json:{"key":123,"value":{}} --error-format json -Z unstable-options
#![warn(unused_crate_dependencies)]
//~^ WARNING external crate `bar` unused in
-{"message":"external crate `bar` unused in `extern_loc_json_json`: remove the dependency or add `use bar as _;`","code":{"code":"unused_crate_dependencies","explanation":null},"level":"warning","spans":[{"file_name":"$DIR/extern-loc-json-json.rs","byte_start":169,"byte_end":169,"line_start":7,"line_end":7,"column_start":1,"column_end":1,"is_primary":true,"text":[{"text":"#![warn(unused_crate_dependencies)]","highlight_start":1,"highlight_end":1}],"label":null,"suggested_replacement":null,"suggestion_applicability":null,"expansion":null}],"children":[{"message":"the lint level is defined here","code":null,"level":"note","spans":[{"file_name":"$DIR/extern-loc-json-json.rs","byte_start":177,"byte_end":202,"line_start":7,"line_end":7,"column_start":9,"column_end":34,"is_primary":true,"text":[{"text":"#![warn(unused_crate_dependencies)]","highlight_start":9,"highlight_end":34}],"label":null,"suggested_replacement":null,"suggestion_applicability":null,"expansion":null}],"children":[],"rendered":null},{"message":"remove unnecessary dependency `bar`","code":null,"level":"help","spans":[],"children":[],"rendered":null},{"message":"json extern location","code":null,"level":"help","spans":[],"children":[],"rendered":null,"tool_metadata":{"key":123,"value":{}}}],"rendered":"warning: external crate `bar` unused in `extern_loc_json_json`: remove the dependency or add `use bar as _;`
+{"message":"external crate `bar` unused in `extern_loc_json_json`: remove the dependency or add `use bar as _;`","code":{"code":"unused_crate_dependencies","explanation":null},"level":"warning","spans":[{"file_name":"$DIR/extern-loc-json-json.rs","byte_start":189,"byte_end":189,"line_start":7,"line_end":7,"column_start":1,"column_end":1,"is_primary":true,"text":[{"text":"#![warn(unused_crate_dependencies)]","highlight_start":1,"highlight_end":1}],"label":null,"suggested_replacement":null,"suggestion_applicability":null,"expansion":null}],"children":[{"message":"the lint level is defined here","code":null,"level":"note","spans":[{"file_name":"$DIR/extern-loc-json-json.rs","byte_start":197,"byte_end":222,"line_start":7,"line_end":7,"column_start":9,"column_end":34,"is_primary":true,"text":[{"text":"#![warn(unused_crate_dependencies)]","highlight_start":9,"highlight_end":34}],"label":null,"suggested_replacement":null,"suggestion_applicability":null,"expansion":null}],"children":[],"rendered":null},{"message":"remove unnecessary dependency `bar`","code":null,"level":"help","spans":[],"children":[],"rendered":null},{"message":"json extern location","code":null,"level":"help","spans":[],"children":[],"rendered":null,"tool_metadata":{"key":123,"value":{}}}],"rendered":"warning: external crate `bar` unused in `extern_loc_json_json`: remove the dependency or add `use bar as _;`
--> $DIR/extern-loc-json-json.rs:7:1
|
LL | #![warn(unused_crate_dependencies)]
// check-pass
// aux-crate:bar=bar.rs
-// compile-flags:--extern-location bar=json:{"key":123,"value":{}}
+// compile-flags:--extern-location bar=json:{"key":123,"value":{}} -Z unstable-options
#![warn(unused_crate_dependencies)]
//~^ WARNING external crate `bar` unused in
// --extern-location with no type
// aux-crate:bar=bar.rs
-// compile-flags:--extern-location bar=missing-loc-type
+// compile-flags:--extern-location bar=missing-loc-type -Z unstable-options
#![warn(unused_crate_dependencies)]
// check-pass
// aux-crate:bar=bar.rs
-// compile-flags:--extern-location bar=raw:in-the-test-file --error-format json
+// compile-flags:--extern-location bar=raw:in-the-test-file --error-format json -Z unstable-options
#![warn(unused_crate_dependencies)]
//~^ WARNING external crate `bar` unused in
-{"message":"external crate `bar` unused in `extern_loc_raw_json`: remove the dependency or add `use bar as _;`","code":{"code":"unused_crate_dependencies","explanation":null},"level":"warning","spans":[{"file_name":"$DIR/extern-loc-raw-json.rs","byte_start":162,"byte_end":162,"line_start":7,"line_end":7,"column_start":1,"column_end":1,"is_primary":true,"text":[{"text":"#![warn(unused_crate_dependencies)]","highlight_start":1,"highlight_end":1}],"label":null,"suggested_replacement":null,"suggestion_applicability":null,"expansion":null}],"children":[{"message":"the lint level is defined here","code":null,"level":"note","spans":[{"file_name":"$DIR/extern-loc-raw-json.rs","byte_start":170,"byte_end":195,"line_start":7,"line_end":7,"column_start":9,"column_end":34,"is_primary":true,"text":[{"text":"#![warn(unused_crate_dependencies)]","highlight_start":9,"highlight_end":34}],"label":null,"suggested_replacement":null,"suggestion_applicability":null,"expansion":null}],"children":[],"rendered":null},{"message":"remove unnecessary dependency `bar` at `in-the-test-file`","code":null,"level":"help","spans":[],"children":[],"rendered":null},{"message":"raw extern location","code":null,"level":"help","spans":[{"file_name":"$DIR/extern-loc-raw-json.rs","byte_start":0,"byte_end":0,"line_start":1,"line_end":1,"column_start":1,"column_end":1,"is_primary":true,"text":[],"label":null,"suggested_replacement":"in-the-test-file","suggestion_applicability":"Unspecified","expansion":null}],"children":[],"rendered":null},{"message":"json extern location","code":null,"level":"help","spans":[],"children":[],"rendered":null,"tool_metadata":"in-the-test-file"}],"rendered":"warning: external crate `bar` unused in `extern_loc_raw_json`: remove the dependency or add `use bar as _;`
+{"message":"external crate `bar` unused in `extern_loc_raw_json`: remove the dependency or add `use bar as _;`","code":{"code":"unused_crate_dependencies","explanation":null},"level":"warning","spans":[{"file_name":"$DIR/extern-loc-raw-json.rs","byte_start":182,"byte_end":182,"line_start":7,"line_end":7,"column_start":1,"column_end":1,"is_primary":true,"text":[{"text":"#![warn(unused_crate_dependencies)]","highlight_start":1,"highlight_end":1}],"label":null,"suggested_replacement":null,"suggestion_applicability":null,"expansion":null}],"children":[{"message":"the lint level is defined here","code":null,"level":"note","spans":[{"file_name":"$DIR/extern-loc-raw-json.rs","byte_start":190,"byte_end":215,"line_start":7,"line_end":7,"column_start":9,"column_end":34,"is_primary":true,"text":[{"text":"#![warn(unused_crate_dependencies)]","highlight_start":9,"highlight_end":34}],"label":null,"suggested_replacement":null,"suggestion_applicability":null,"expansion":null}],"children":[],"rendered":null},{"message":"remove unnecessary dependency `bar` at `in-the-test-file`","code":null,"level":"help","spans":[],"children":[],"rendered":null},{"message":"raw extern location","code":null,"level":"help","spans":[{"file_name":"$DIR/extern-loc-raw-json.rs","byte_start":0,"byte_end":0,"line_start":1,"line_end":1,"column_start":1,"column_end":1,"is_primary":true,"text":[],"label":null,"suggested_replacement":"in-the-test-file","suggestion_applicability":"Unspecified","expansion":null}],"children":[],"rendered":null},{"message":"json extern location","code":null,"level":"help","spans":[],"children":[],"rendered":null,"tool_metadata":"in-the-test-file"}],"rendered":"warning: external crate `bar` unused in `extern_loc_raw_json`: remove the dependency or add `use bar as _;`
--> $DIR/extern-loc-raw-json.rs:7:1
|
LL | #![warn(unused_crate_dependencies)]
// --extern-location with a raw reference
// aux-crate:bar=bar.rs
-// compile-flags:--extern-location bar=raw
+// compile-flags:--extern-location bar=raw -Z unstable-options
#![warn(unused_crate_dependencies)]
// check-pass
// aux-crate:bar=bar.rs
-// compile-flags:--extern-location bar=raw:in-the-test-file
+// compile-flags:--extern-location bar=raw:in-the-test-file -Z unstable-options
#![warn(unused_crate_dependencies)]
//~^ WARNING external crate `bar` unused in
error: aborting due to previous error
+For more information about this error, try `rustc --explain E0316`.
"armv7r-none-eabihf",
"armv7s-apple-ios",
"asmjs-unknown-emscripten",
+ "bpfeb-unknown-none",
+ "bpfel-unknown-none",
"i386-apple-ios",
"i586-pc-windows-msvc",
"i586-unknown-linux-gnu",
-Subproject commit 070e459c2d8b79c5b2ac5218064e7603329c92ae
+Subproject commit 44456677b5d1d82fe981c955dc5c67734b31f340
[`manual_ok_or`]: https://rust-lang.github.io/rust-clippy/master/index.html#manual_ok_or
[`manual_range_contains`]: https://rust-lang.github.io/rust-clippy/master/index.html#manual_range_contains
[`manual_saturating_arithmetic`]: https://rust-lang.github.io/rust-clippy/master/index.html#manual_saturating_arithmetic
+[`manual_str_repeat`]: https://rust-lang.github.io/rust-clippy/master/index.html#manual_str_repeat
[`manual_strip`]: https://rust-lang.github.io/rust-clippy/master/index.html#manual_strip
[`manual_swap`]: https://rust-lang.github.io/rust-clippy/master/index.html#manual_swap
[`manual_unwrap_or`]: https://rust-lang.github.io/rust-clippy/master/index.html#manual_unwrap_or
[`redundant_pub_crate`]: https://rust-lang.github.io/rust-clippy/master/index.html#redundant_pub_crate
[`redundant_slicing`]: https://rust-lang.github.io/rust-clippy/master/index.html#redundant_slicing
[`redundant_static_lifetimes`]: https://rust-lang.github.io/rust-clippy/master/index.html#redundant_static_lifetimes
+[`ref_binding_to_reference`]: https://rust-lang.github.io/rust-clippy/master/index.html#ref_binding_to_reference
[`ref_in_deref`]: https://rust-lang.github.io/rust-clippy/master/index.html#ref_in_deref
[`ref_option_ref`]: https://rust-lang.github.io/rust-clippy/master/index.html#ref_option_ref
[`regex_macro`]: https://rust-lang.github.io/rust-clippy/master/index.html#regex_macro
[`suspicious_map`]: https://rust-lang.github.io/rust-clippy/master/index.html#suspicious_map
[`suspicious_op_assign_impl`]: https://rust-lang.github.io/rust-clippy/master/index.html#suspicious_op_assign_impl
[`suspicious_operation_groupings`]: https://rust-lang.github.io/rust-clippy/master/index.html#suspicious_operation_groupings
+[`suspicious_splitn`]: https://rust-lang.github.io/rust-clippy/master/index.html#suspicious_splitn
[`suspicious_unary_op_formatting`]: https://rust-lang.github.io/rust-clippy/master/index.html#suspicious_unary_op_formatting
[`tabs_in_doc_comments`]: https://rust-lang.github.io/rust-clippy/master/index.html#tabs_in_doc_comments
[`temporary_assignment`]: https://rust-lang.github.io/rust-clippy/master/index.html#temporary_assignment
-Copyright 2014-2020 The Rust Project Developers
+Copyright 2014-2021 The Rust Project Developers
Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
cargo_metadata = "0.12"
compiletest_rs = { version = "0.6.0", features = ["tmp"] }
tester = "0.9"
-clippy-mini-macro-test = { version = "0.2", path = "mini-macro" }
serde = { version = "1.0", features = ["derive"] }
derive-new = "0.5"
regex = "1.4"
quote = "1"
syn = { version = "1", features = ["full"] }
+# This is used by the `collect-metadata` alias.
+filetime = "0.2"
# A noop dependency that changes in the Rust repository, it's a bit of a hack.
# See the `src/tools/rustc-workspace-hack/README.md` file in `rust-lang/rust`
same "printed page" as the copyright notice for easier
identification within third-party archives.
-Copyright 2014-2020 The Rust Project Developers
+Copyright 2014-2021 The Rust Project Developers
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
MIT License
-Copyright (c) 2014-2020 The Rust Project Developers
+Copyright (c) 2014-2021 The Rust Project Developers
Permission is hereby granted, free of charge, to any
person obtaining a copy of this software and associated
value` mapping eg.
```toml
+avoid-breaking-exported-api = false
blacklisted-names = ["toto", "tata", "titi"]
cognitive-complexity-threshold = 30
```
## License
-Copyright 2014-2020 The Rust Project Developers
+Copyright 2014-2021 The Rust Project Developers
Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
[https://www.apache.org/licenses/LICENSE-2.0](https://www.apache.org/licenses/LICENSE-2.0)> or the MIT license
);
println!(
"cargo:rustc-env=RUSTC_RELEASE_CHANNEL={}",
- rustc_tools_util::get_channel().unwrap_or_default()
+ rustc_tools_util::get_channel()
);
}
--- /dev/null
+avoid-breaking-exported-api = false
use rustc_middle::ty;
use rustc_session::{declare_lint_pass, declare_tool_lint};
-use crate::consts::{constant, Constant};
-
use clippy_utils::comparisons::{normalize_comparison, Rel};
+use clippy_utils::consts::{constant, Constant};
use clippy_utils::diagnostics::span_lint_and_help;
use clippy_utils::source::snippet;
use clippy_utils::ty::is_isize_or_usize;
-use crate::consts::constant_simple;
+use clippy_utils::consts::constant_simple;
use clippy_utils::diagnostics::span_lint;
use rustc_hir as hir;
use rustc_lint::{LateContext, LateLintPass};
-use crate::consts::{constant, Constant};
+use clippy_utils::consts::{constant, Constant};
use clippy_utils::diagnostics::span_lint_and_help;
use clippy_utils::source::snippet_opt;
use clippy_utils::{is_direct_expn_of, is_expn_of, match_panic_call};
&format!("`assert!(false, {})` should probably be replaced", panic_message),
None,
&format!("use `panic!({})` or `unreachable!({})`", panic_message, panic_message),
- )
+ );
};
if let Some(debug_assert_span) = is_expn_of(e.span, "debug_assert") {
fn check_item(&mut self, cx: &LateContext<'tcx>, item: &'tcx Item<'_>) {
let attrs = cx.tcx.hir().attrs(item.hir_id());
if is_relevant_item(cx, item) {
- check_attrs(cx, item.span, item.ident.name, attrs)
+ check_attrs(cx, item.span, item.ident.name, attrs);
}
match item.kind {
ItemKind::ExternCrate(..) | ItemKind::Use(..) => {
fn check_impl_item(&mut self, cx: &LateContext<'tcx>, item: &'tcx ImplItem<'_>) {
if is_relevant_impl(cx, item) {
- check_attrs(cx, item.span, item.ident.name, cx.tcx.hir().attrs(item.hir_id()))
+ check_attrs(cx, item.span, item.ident.name, cx.tcx.hir().attrs(item.hir_id()));
}
}
fn check_trait_item(&mut self, cx: &LateContext<'tcx>, item: &'tcx TraitItem<'_>) {
if is_relevant_trait(cx, item) {
- check_attrs(cx, item.span, item.ident.name, cx.tcx.hir().attrs(item.hir_id()))
+ check_attrs(cx, item.span, item.ident.name, cx.tcx.hir().attrs(item.hir_id()));
}
}
}
-use crate::consts::{constant, Constant};
+use clippy_utils::consts::{constant, Constant};
use clippy_utils::diagnostics::{span_lint, span_lint_and_then};
use clippy_utils::sugg::Sugg;
use if_chain::if_chain;
if let ExprKind::Binary(cmp, left, right) = &e.kind {
if cmp.node.is_comparison() {
if let Some(cmp_opt) = fetch_int_literal(cx, right) {
- check_compare(cx, left, cmp.node, cmp_opt, e.span)
+ check_compare(cx, left, cmp.node, cmp_opt, e.span);
} else if let Some(cmp_val) = fetch_int_literal(cx, left) {
- check_compare(cx, right, invert_cmp(cmp.node), cmp_val, e.span)
+ check_compare(cx, right, invert_cmp(cmp.node), cmp_val, e.span);
}
}
}
}
fetch_int_literal(cx, right)
.or_else(|| fetch_int_literal(cx, left))
- .map_or((), |mask| check_bit_mask(cx, op.node, cmp_op, mask, cmp_value, span))
+ .map_or((), |mask| check_bit_mask(cx, op.node, cmp_op, mask, cmp_value, span));
}
}
_: Span,
_: HirId,
) {
- NonminimalBoolVisitor { cx }.visit_body(body)
+ NonminimalBoolVisitor { cx }.visit_body(body);
}
}
Term(n) => {
let terminal = self.terminals[n as usize];
if let Some(str) = simplify_not(self.cx, terminal) {
- self.output.push_str(&str)
+ self.output.push_str(&str);
} else {
self.output.push('!');
let snip = snippet_opt(self.cx, terminal.span)?;
}
match &e.kind {
ExprKind::Binary(binop, _, _) if binop.node == BinOpKind::Or || binop.node == BinOpKind::And => {
- self.bool_expr(e)
+ self.bool_expr(e);
},
ExprKind::Unary(UnOp::Not, inner) => {
if self.cx.typeck_results().node_types()[inner.hir_id].is_bool() {
-use crate::consts::{constant, Constant};
+use clippy_utils::consts::{constant, Constant};
use clippy_utils::diagnostics::span_lint;
use clippy_utils::{method_chain_args, sext};
use if_chain::if_chain;
impl EarlyLintPass for CollapsibleIf {
fn check_expr(&mut self, cx: &EarlyContext<'_>, expr: &ast::Expr) {
if !expr.span.from_expansion() {
- check_if(cx, expr)
+ check_if(cx, expr);
}
}
}
"`if` chain can be rewritten with `match`",
None,
"consider rewriting the `if` chain to use `cmp` and `match`",
- )
+ );
}
}
+++ /dev/null
-pub use clippy_utils::consts::*;
}
suggestions.push(("end", span, suggestion.to_string()));
- add_expr_note = !cx.typeck_results().expr_ty(if_expr).is_unit()
+ add_expr_note = !cx.typeck_results().expr_ty(if_expr).is_unit();
}
let add_optional_msgs = |diag: &mut DiagnosticBuilder<'_>| {
match stmt.kind {
StmtKind::Local(local) => {
if local.ty.is_some() {
- self.ty_bounds.push(TyBound::Any)
+ self.ty_bounds.push(TyBound::Any);
} else {
- self.ty_bounds.push(TyBound::Nothing)
+ self.ty_bounds.push(TyBound::Nothing);
}
},
pub FILTER_MAP,
"this lint has been replaced by `manual_filter_map`, a more specific lint"
}
+
+declare_deprecated_lint! {
+ /// **What it does:** Nothing. This lint has been deprecated.
+ ///
+ /// **Deprecation reason:** The `avoid_breaking_exported_api` config option was added, which
+ /// enables the `enum_variant_names` lint for public items.
+ /// ```
+ pub PUB_ENUM_VARIANT_NAMES,
+ "set the `avoid_breaking_exported_api` config option to `false` to enable the `enum_variant_names` lint for public items"
+}
+
+declare_deprecated_lint! {
+ /// **What it does:** Nothing. This lint has been deprecated.
+ ///
+ /// **Deprecation reason:** The `avoid_breaking_exported_api` config option was added, which
+ /// enables the `wrong_self_conversion` lint for public items.
+ pub WRONG_PUB_SELF_CONVENTION,
+ "set the `avoid_breaking_exported_api` config option to `false` to enable the `wrong_self_convention` lint for public items"
+}
#[rustfmt::skip]
match (op, lkind, rkind) {
(BinOpKind::Or, BinOpKind::Eq, BinOpKind::Lt) | (BinOpKind::Or, BinOpKind::Lt, BinOpKind::Eq) => {
- lint_double_comparison!(<=)
+ lint_double_comparison!(<=);
},
(BinOpKind::Or, BinOpKind::Eq, BinOpKind::Gt) | (BinOpKind::Or, BinOpKind::Gt, BinOpKind::Eq) => {
- lint_double_comparison!(>=)
+ lint_double_comparison!(>=);
},
(BinOpKind::Or, BinOpKind::Lt, BinOpKind::Gt) | (BinOpKind::Or, BinOpKind::Gt, BinOpKind::Lt) => {
- lint_double_comparison!(!=)
+ lint_double_comparison!(!=);
},
(BinOpKind::And, BinOpKind::Le, BinOpKind::Ge) | (BinOpKind::And, BinOpKind::Ge, BinOpKind::Le) => {
- lint_double_comparison!(==)
+ lint_double_comparison!(==);
},
_ => (),
};
use rustc_session::{declare_lint_pass, declare_tool_lint};
use rustc_span::source_map::Spanned;
-use crate::consts::{constant, Constant};
+use clippy_utils::consts::{constant, Constant};
use clippy_utils::diagnostics::span_lint_and_sugg;
use clippy_utils::paths;
let mut is_map_used = self.is_map_used;
for arm in arms {
if let Some(Guard::If(guard) | Guard::IfLet(_, guard)) = arm.guard {
- self.visit_non_tail_expr(guard)
+ self.visit_non_tail_expr(guard);
}
is_map_used |= self.visit_cond_arm(arm.body);
}
//! lint on C-like enums that are `repr(isize/usize)` and have values that
//! don't fit into an `i32`
-use crate::consts::{miri_to_const, Constant};
+use clippy_utils::consts::{miri_to_const, Constant};
use clippy_utils::diagnostics::span_lint;
use rustc_hir::{Item, ItemKind};
use rustc_lint::{LateContext, LateLintPass};
use clippy_utils::camel_case;
use clippy_utils::diagnostics::{span_lint, span_lint_and_help};
use clippy_utils::source::is_present_in_source;
-use rustc_ast::ast::{EnumDef, Item, ItemKind, VisibilityKind};
-use rustc_lint::{EarlyContext, EarlyLintPass, Lint};
+use rustc_hir::{EnumDef, Item, ItemKind};
+use rustc_lint::{LateContext, LateLintPass};
use rustc_session::{declare_tool_lint, impl_lint_pass};
use rustc_span::source_map::Span;
use rustc_span::symbol::Symbol;
"enums where all variants share a prefix/postfix"
}
-declare_clippy_lint! {
- /// **What it does:** Detects public enumeration variants that are
- /// prefixed or suffixed by the same characters.
- ///
- /// **Why is this bad?** Public enumeration variant names should specify their variant,
- /// not repeat the enumeration name.
- ///
- /// **Known problems:** None.
- ///
- /// **Example:**
- /// ```rust
- /// pub enum Cake {
- /// BlackForestCake,
- /// HummingbirdCake,
- /// BattenbergCake,
- /// }
- /// ```
- /// Could be written as:
- /// ```rust
- /// pub enum Cake {
- /// BlackForest,
- /// Hummingbird,
- /// Battenberg,
- /// }
- /// ```
- pub PUB_ENUM_VARIANT_NAMES,
- pedantic,
- "public enums where all variants share a prefix/postfix"
-}
-
declare_clippy_lint! {
/// **What it does:** Detects type names that are prefixed or suffixed by the
/// containing module's name.
pub struct EnumVariantNames {
modules: Vec<(Symbol, String)>,
threshold: u64,
+ avoid_breaking_exported_api: bool,
}
impl EnumVariantNames {
#[must_use]
- pub fn new(threshold: u64) -> Self {
+ pub fn new(threshold: u64, avoid_breaking_exported_api: bool) -> Self {
Self {
modules: Vec::new(),
threshold,
+ avoid_breaking_exported_api,
}
}
}
impl_lint_pass!(EnumVariantNames => [
ENUM_VARIANT_NAMES,
- PUB_ENUM_VARIANT_NAMES,
MODULE_NAME_REPETITIONS,
MODULE_INCEPTION
]);
}
fn check_variant(
- cx: &EarlyContext<'_>,
+ cx: &LateContext<'_>,
threshold: u64,
- def: &EnumDef,
+ def: &EnumDef<'_>,
item_name: &str,
item_name_chars: usize,
span: Span,
- lint: &'static Lint,
) {
if (def.variants.len() as u64) < threshold {
return;
}
- for var in &def.variants {
+ for var in def.variants {
let name = var.ident.name.as_str();
if partial_match(item_name, &name) == item_name_chars
&& name.chars().nth(item_name_chars).map_or(false, |c| !c.is_lowercase())
&& name.chars().nth(item_name_chars + 1).map_or(false, |c| !c.is_numeric())
{
- span_lint(cx, lint, var.span, "variant name starts with the enum's name");
+ span_lint(
+ cx,
+ ENUM_VARIANT_NAMES,
+ var.span,
+ "variant name starts with the enum's name",
+ );
}
if partial_rmatch(item_name, &name) == item_name_chars {
- span_lint(cx, lint, var.span, "variant name ends with the enum's name");
+ span_lint(
+ cx,
+ ENUM_VARIANT_NAMES,
+ var.span,
+ "variant name ends with the enum's name",
+ );
}
}
let first = &def.variants[0].ident.name.as_str();
let mut pre = &first[..camel_case::until(&*first)];
let mut post = &first[camel_case::from(&*first)..];
- for var in &def.variants {
+ for var in def.variants {
let name = var.ident.name.as_str();
let pre_match = partial_match(pre, &name);
};
span_lint_and_help(
cx,
- lint,
+ ENUM_VARIANT_NAMES,
span,
&format!("all variants have the same {}fix: `{}`", what, value),
None,
s
}
-impl EarlyLintPass for EnumVariantNames {
- fn check_item_post(&mut self, _cx: &EarlyContext<'_>, _item: &Item) {
+impl LateLintPass<'_> for EnumVariantNames {
+ fn check_item_post(&mut self, _cx: &LateContext<'_>, _item: &Item<'_>) {
let last = self.modules.pop();
assert!(last.is_some());
}
#[allow(clippy::similar_names)]
- fn check_item(&mut self, cx: &EarlyContext<'_>, item: &Item) {
+ fn check_item(&mut self, cx: &LateContext<'_>, item: &Item<'_>) {
let item_name = item.ident.name.as_str();
let item_name_chars = item_name.chars().count();
let item_camel = to_camel_case(&item_name);
);
}
}
- if item.vis.kind.is_pub() {
+ if item.vis.node.is_pub() {
let matching = partial_match(mod_camel, &item_camel);
let rmatching = partial_rmatch(mod_camel, &item_camel);
let nchars = mod_camel.chars().count();
}
}
if let ItemKind::Enum(ref def, _) = item.kind {
- let lint = match item.vis.kind {
- VisibilityKind::Public => PUB_ENUM_VARIANT_NAMES,
- _ => ENUM_VARIANT_NAMES,
- };
- check_variant(cx, self.threshold, def, &item_name, item_name_chars, item.span, lint);
+ if !(self.avoid_breaking_exported_api && cx.access_levels.is_exported(item.hir_id())) {
+ check_variant(cx, self.threshold, def, &item_name, item_name_chars, item.span);
+ }
}
self.modules.push((item.ident.name, item_camel));
}
vec![(left.span, lsnip), (right.span, rsnip)],
);
},
- )
+ );
} else if lcpy
&& !rcpy
&& implements_trait(cx, lty, trait_id, &[cx.typeck_results().expr_ty(right).into()])
Applicability::MaybeIncorrect, // FIXME #2597
);
},
- )
+ );
} else if !lcpy
&& rcpy
&& implements_trait(cx, cx.typeck_results().expr_ty(left), trait_id, &[rty.into()])
Applicability::MaybeIncorrect, // FIXME #2597
);
},
- )
+ );
}
},
// &foo == bar
Applicability::MaybeIncorrect, // FIXME #2597
);
},
- )
+ );
}
},
// foo == &bar
rsnip,
Applicability::MaybeIncorrect, // FIXME #2597
);
- })
+ });
}
},
_ => {},
+use clippy_utils::consts::{constant_simple, Constant};
use clippy_utils::diagnostics::span_lint;
use rustc_hir::{BinOpKind, Expr, ExprKind};
use rustc_lint::{LateContext, LateLintPass};
use rustc_session::{declare_lint_pass, declare_tool_lint};
use rustc_span::source_map::Span;
-use crate::consts::{constant_simple, Constant};
-
declare_clippy_lint! {
/// **What it does:** Checks for erasing operations, e.g., `x * 0`.
///
for arg in args {
// skip `foo(macro!())`
if arg.span.ctxt() == expr.span.ctxt() {
- check_closure(cx, arg)
+ check_closure(cx, arg);
}
}
},
let ex = &body.value;
if ex.span.ctxt() != expr.span.ctxt() {
- if let Some(VecArgs::Vec(&[])) = higher::vec_macro(cx, ex) {
- // replace `|| vec![]` with `Vec::new`
- span_lint_and_sugg(
- cx,
- REDUNDANT_CLOSURE,
- expr.span,
- "redundant closure",
- "replace the closure with `Vec::new`",
- "std::vec::Vec::new".into(),
- Applicability::MachineApplicable,
- );
+ if decl.inputs.is_empty() {
+ if let Some(VecArgs::Vec(&[])) = higher::vec_macro(cx, ex) {
+ // replace `|| vec![]` with `Vec::new`
+ span_lint_and_sugg(
+ cx,
+ REDUNDANT_CLOSURE,
+ expr.span,
+ "redundant closure",
+ "replace the closure with `Vec::new`",
+ "std::vec::Vec::new".into(),
+ Applicability::MachineApplicable,
+ );
+ }
}
// skip `foo(|| macro!())`
return;
cx.tcx.impl_of_method(method_def_id).and_then(|_| {
//a type may implicitly implement other type's methods (e.g. Deref)
if match_types(expected_type_of_self, actual_type_of_self) {
- return Some(get_type_name(cx, actual_type_of_self));
+ Some(get_type_name(cx, actual_type_of_self))
+ } else {
+ None
}
- None
})
}
self.visit_expr(e);
for arm in arms {
if let Some(Guard::If(if_expr)) = arm.guard {
- self.visit_expr(if_expr)
+ self.visit_expr(if_expr);
}
// make sure top level arm expressions aren't linted
self.maybe_walk_expr(&*arm.body);
-use crate::consts::{
+use clippy_utils::consts::{
constant, constant_simple, Constant,
Constant::{Int, F32, F64},
};
}
},
Assign(target, ..) | AssignOp(_, target, _) | AddrOf(_, hir::Mutability::Mut, target) => {
- self.mutates_static |= is_mutated_static(target)
+ self.mutates_static |= is_mutated_static(target);
},
_ => {},
}
self.cx,
NOT_UNSAFE_PTR_ARG_DEREF,
ptr.span,
- "this public function dereferences a raw pointer but is not marked `unsafe`",
+ "this public function might dereference a raw pointer but is not marked `unsafe`",
);
}
}
use rustc_span::Span;
use clippy_utils::diagnostics::span_lint;
-use clippy_utils::source::snippet;
+use clippy_utils::source::snippet_opt;
use super::TOO_MANY_LINES;
return;
}
- let code_snippet = snippet(cx, body.value.span, "..");
+ let code_snippet = match snippet_opt(cx, body.value.span) {
+ Some(s) => s,
+ _ => return,
+ };
let mut line_count: u64 = 0;
let mut in_comment = false;
let mut code_in_line;
- // Skip the surrounding function decl.
- let start_brace_idx = code_snippet.find('{').map_or(0, |i| i + 1);
- let end_brace_idx = code_snippet.rfind('}').unwrap_or_else(|| code_snippet.len());
- let function_lines = code_snippet[start_brace_idx..end_brace_idx].lines();
+ let function_lines = if matches!(body.value.kind, hir::ExprKind::Block(..))
+ && code_snippet.as_bytes().first().copied() == Some(b'{')
+ && code_snippet.as_bytes().last().copied() == Some(b'}')
+ {
+ // Removing the braces from the enclosing block
+ &code_snippet[1..code_snippet.len() - 1]
+ } else {
+ &code_snippet
+ }
+ .trim() // Remove leading and trailing blank lines
+ .lines();
for mut line in function_lines {
code_in_line = false;
"this function has too many lines ({}/{})",
line_count, too_many_lines_threshold
),
- )
+ );
}
}
));
}
}
- })
+ });
},
);
}
use rustc_session::{declare_lint_pass, declare_tool_lint};
use rustc_span::source_map::Span;
-use crate::consts::{constant_simple, Constant};
+use clippy_utils::consts::{constant_simple, Constant};
use clippy_utils::diagnostics::span_lint;
use clippy_utils::{clip, unsext};
"change `break` to `return` as shown",
format!("return {}", snip),
app,
- )
+ );
}
#[derive(Clone, Copy, PartialEq, Eq)]
//! lint on indexing and slicing operations
-use crate::consts::{constant, Constant};
+use clippy_utils::consts::{constant, Constant};
use clippy_utils::diagnostics::{span_lint, span_lint_and_help};
use clippy_utils::higher;
use rustc_ast::ast::RangeLimits;
return;
},
};
- span_lint(cx, lint, expr.span, msg)
+ span_lint(cx, lint, expr.span, msg);
}
}
use rustc_span::Span;
use rustc_target::abi::LayoutOf;
-use crate::consts::{constant, Constant};
-
use clippy_utils::comparisons::Rel;
+use clippy_utils::consts::{constant, Constant};
use clippy_utils::diagnostics::span_lint;
use clippy_utils::source::snippet;
use clippy_utils::{comparisons, sext};
},
Rel::Eq | Rel::Ne => unreachable!(),
} {
- err_upcast_comparison(cx, span, lhs, true)
+ err_upcast_comparison(cx, span, lhs, true);
} else if match rel {
Rel::Lt => {
if invert {
},
Rel::Eq | Rel::Ne => unreachable!(),
} {
- err_upcast_comparison(cx, span, lhs, false)
+ err_upcast_comparison(cx, span, lhs, false);
}
}
}
}
}
- check_len(cx, span, method_path.ident.name, args, &lit.node, op, compare_to)
+ check_len(cx, span, method_path.ident.name, args, &lit.node, op, compare_to);
} else {
- check_empty_expr(cx, span, method, lit, op)
+ check_empty_expr(cx, span, method, lit, op);
}
}
None,
"consider using an underscore-prefixed named \
binding or dropping explicitly with `std::mem::drop`"
- )
+ );
} else if init_ty.needs_drop(cx.tcx, cx.param_env) {
span_lint_and_help(
cx,
None,
"consider using an underscore-prefixed named \
binding or dropping explicitly with `std::mem::drop`"
- )
+ );
} else if is_must_use_ty(cx, cx.typeck_results().expr_ty(init)) {
span_lint_and_help(
cx,
"non-binding let on an expression with `#[must_use]` type",
None,
"consider explicitly using expression value"
- )
+ );
} else if is_must_use_func_call(cx, init) {
span_lint_and_help(
cx,
"non-binding let on a result of a `#[must_use]` function",
None,
"consider explicitly using function result"
- )
+ );
}
}
}
extern crate rustc_trait_selection;
extern crate rustc_typeck;
+#[macro_use]
+extern crate clippy_utils;
+
use clippy_utils::parse_msrv;
use rustc_data_structures::fx::FxHashSet;
use rustc_lint::LintId;
};
}
-#[macro_export]
-macro_rules! sym {
- ( $($x:tt)* ) => { clippy_utils::sym!($($x)*) }
-}
-
-#[macro_export]
-macro_rules! unwrap_cargo_metadata {
- ( $($x:tt)* ) => { clippy_utils::unwrap_cargo_metadata!($($x)*) }
-}
-
-macro_rules! extract_msrv_attr {
- ( $($x:tt)* ) => { clippy_utils::extract_msrv_attr!($($x)*); }
-}
-
-mod consts;
-#[macro_use]
-mod utils;
#[cfg(feature = "metadata-collector-lint")]
mod deprecated_lints;
+mod utils;
// begin lints modules, do not remove this comment, it’s used in `update_lints`
mod absurd_extreme_comparisons;
#[doc(hidden)]
pub fn read_conf(sess: &Session) -> Conf {
- use std::path::Path;
let file_name = match utils::conf::lookup_conf_file() {
Ok(Some(path)) => path,
Ok(None) => return Conf::default(),
},
};
- let file_name = if file_name.is_relative() {
- sess.local_crate_source_file
- .as_deref()
- .and_then(Path::parent)
- .unwrap_or_else(|| Path::new(""))
- .join(file_name)
- } else {
- file_name
- };
-
let TryConf { conf, errors } = utils::conf::read(&file_name);
// all conf errors are non-fatal, we just use the default conf in case of error
for error in errors {
"clippy::filter_map",
"this lint has been replaced by `manual_filter_map`, a more specific lint",
);
+ store.register_removed(
+ "clippy::pub_enum_variant_names",
+ "set the `avoid_breaking_exported_api` config option to `false` to enable the `enum_variant_names` lint for public items",
+ );
+ store.register_removed(
+ "clippy::wrong_pub_self_convention",
+ "set the `avoid_breaking_exported_api` config option to `false` to enable the `wrong_self_convention` lint for public items",
+ );
// end deprecated lints, do not remove this comment, it’s used in `update_lints`
// begin register lints, do not remove this comment, it’s used in `update_lints`
enum_variants::ENUM_VARIANT_NAMES,
enum_variants::MODULE_INCEPTION,
enum_variants::MODULE_NAME_REPETITIONS,
- enum_variants::PUB_ENUM_VARIANT_NAMES,
eq_op::EQ_OP,
eq_op::OP_REF,
erasing_op::ERASING_OP,
methods::MANUAL_FILTER_MAP,
methods::MANUAL_FIND_MAP,
methods::MANUAL_SATURATING_ARITHMETIC,
+ methods::MANUAL_STR_REPEAT,
methods::MAP_COLLECT_RESULT_UNIT,
methods::MAP_FLATTEN,
methods::MAP_UNWRAP_OR,
methods::SKIP_WHILE_NEXT,
methods::STRING_EXTEND_CHARS,
methods::SUSPICIOUS_MAP,
+ methods::SUSPICIOUS_SPLITN,
methods::UNINIT_ASSUMED_INIT,
methods::UNNECESSARY_FILTER_MAP,
methods::UNNECESSARY_FOLD,
methods::UNNECESSARY_LAZY_EVALUATIONS,
methods::UNWRAP_USED,
methods::USELESS_ASREF,
- methods::WRONG_PUB_SELF_CONVENTION,
methods::WRONG_SELF_CONVENTION,
methods::ZST_OFFSET,
minmax::MIN_MAX,
needless_bool::BOOL_COMPARISON,
needless_bool::NEEDLESS_BOOL,
needless_borrow::NEEDLESS_BORROW,
+ needless_borrow::REF_BINDING_TO_REFERENCE,
needless_borrowed_ref::NEEDLESS_BORROWED_REFERENCE,
needless_continue::NEEDLESS_CONTINUE,
needless_for_each::NEEDLESS_FOR_EACH,
]);
// end register lints, do not remove this comment, it’s used in `update_lints`
- // all the internal lints
- #[cfg(feature = "internal-lints")]
- {
- store.register_early_pass(|| box utils::internal_lints::ClippyLintsInternal);
- store.register_early_pass(|| box utils::internal_lints::ProduceIce);
- store.register_late_pass(|| box utils::inspector::DeepCodeInspector);
- store.register_late_pass(|| box utils::internal_lints::CollapsibleCalls);
- store.register_late_pass(|| box utils::internal_lints::CompilerLintFunctions::new());
- store.register_late_pass(|| box utils::internal_lints::IfChainStyle);
- store.register_late_pass(|| box utils::internal_lints::InvalidPaths);
- store.register_late_pass(|| box utils::internal_lints::InterningDefinedSymbol::default());
- store.register_late_pass(|| box utils::internal_lints::LintWithoutLintPass::default());
- store.register_late_pass(|| box utils::internal_lints::MatchTypeOnDiagItem);
- store.register_late_pass(|| box utils::internal_lints::OuterExpnDataPass);
- }
- #[cfg(feature = "metadata-collector-lint")]
- {
- if std::env::var("ENABLE_METADATA_COLLECTION").eq(&Ok("1".to_string())) {
- store.register_late_pass(|| box utils::internal_lints::metadata_collector::MetadataCollector::new());
- }
- }
+ store.register_group(true, "clippy::restriction", Some("clippy_restriction"), vec![
+ LintId::of(arithmetic::FLOAT_ARITHMETIC),
+ LintId::of(arithmetic::INTEGER_ARITHMETIC),
+ LintId::of(as_conversions::AS_CONVERSIONS),
+ LintId::of(asm_syntax::INLINE_ASM_X86_ATT_SYNTAX),
+ LintId::of(asm_syntax::INLINE_ASM_X86_INTEL_SYNTAX),
+ LintId::of(create_dir::CREATE_DIR),
+ LintId::of(dbg_macro::DBG_MACRO),
+ LintId::of(default_numeric_fallback::DEFAULT_NUMERIC_FALLBACK),
+ LintId::of(else_if_without_else::ELSE_IF_WITHOUT_ELSE),
+ LintId::of(exhaustive_items::EXHAUSTIVE_ENUMS),
+ LintId::of(exhaustive_items::EXHAUSTIVE_STRUCTS),
+ LintId::of(exit::EXIT),
+ LintId::of(float_literal::LOSSY_FLOAT_LITERAL),
+ LintId::of(if_then_some_else_none::IF_THEN_SOME_ELSE_NONE),
+ LintId::of(implicit_return::IMPLICIT_RETURN),
+ LintId::of(indexing_slicing::INDEXING_SLICING),
+ LintId::of(inherent_impl::MULTIPLE_INHERENT_IMPL),
+ LintId::of(integer_division::INTEGER_DIVISION),
+ LintId::of(let_underscore::LET_UNDERSCORE_MUST_USE),
+ LintId::of(literal_representation::DECIMAL_LITERAL_REPRESENTATION),
+ LintId::of(map_err_ignore::MAP_ERR_IGNORE),
+ LintId::of(matches::REST_PAT_IN_FULLY_BOUND_STRUCTS),
+ LintId::of(matches::WILDCARD_ENUM_MATCH_ARM),
+ LintId::of(mem_forget::MEM_FORGET),
+ LintId::of(methods::CLONE_ON_REF_PTR),
+ LintId::of(methods::EXPECT_USED),
+ LintId::of(methods::FILETYPE_IS_FILE),
+ LintId::of(methods::GET_UNWRAP),
+ LintId::of(methods::UNWRAP_USED),
+ LintId::of(misc::FLOAT_CMP_CONST),
+ LintId::of(misc_early::UNNEEDED_FIELD_PATTERN),
+ LintId::of(missing_doc::MISSING_DOCS_IN_PRIVATE_ITEMS),
+ LintId::of(missing_inline::MISSING_INLINE_IN_PUBLIC_ITEMS),
+ LintId::of(modulo_arithmetic::MODULO_ARITHMETIC),
+ LintId::of(panic_in_result_fn::PANIC_IN_RESULT_FN),
+ LintId::of(panic_unimplemented::PANIC),
+ LintId::of(panic_unimplemented::TODO),
+ LintId::of(panic_unimplemented::UNIMPLEMENTED),
+ LintId::of(panic_unimplemented::UNREACHABLE),
+ LintId::of(pattern_type_mismatch::PATTERN_TYPE_MISMATCH),
+ LintId::of(shadow::SHADOW_REUSE),
+ LintId::of(shadow::SHADOW_SAME),
+ LintId::of(strings::STRING_ADD),
+ LintId::of(strings::STRING_TO_STRING),
+ LintId::of(strings::STR_TO_STRING),
+ LintId::of(types::RC_BUFFER),
+ LintId::of(unnecessary_self_imports::UNNECESSARY_SELF_IMPORTS),
+ LintId::of(unwrap_in_result::UNWRAP_IN_RESULT),
+ LintId::of(verbose_file_reads::VERBOSE_FILE_READS),
+ LintId::of(write::PRINT_STDERR),
+ LintId::of(write::PRINT_STDOUT),
+ LintId::of(write::USE_DEBUG),
+ ]);
- store.register_late_pass(|| box utils::author::Author);
- store.register_late_pass(|| box await_holding_invalid::AwaitHolding);
- store.register_late_pass(|| box serde_api::SerdeApi);
- let vec_box_size_threshold = conf.vec_box_size_threshold;
- let type_complexity_threshold = conf.type_complexity_threshold;
- store.register_late_pass(move || box types::Types::new(vec_box_size_threshold, type_complexity_threshold));
- store.register_late_pass(|| box booleans::NonminimalBool);
- store.register_late_pass(|| box needless_bitwise_bool::NeedlessBitwiseBool);
- store.register_late_pass(|| box eq_op::EqOp);
- store.register_late_pass(|| box enum_clike::UnportableVariant);
- store.register_late_pass(|| box float_literal::FloatLiteral);
- let verbose_bit_mask_threshold = conf.verbose_bit_mask_threshold;
- store.register_late_pass(move || box bit_mask::BitMask::new(verbose_bit_mask_threshold));
- store.register_late_pass(|| box ptr::Ptr);
- store.register_late_pass(|| box ptr_eq::PtrEq);
- store.register_late_pass(|| box needless_bool::NeedlessBool);
- store.register_late_pass(|| box needless_bool::BoolComparison);
- store.register_late_pass(|| box needless_for_each::NeedlessForEach);
- store.register_late_pass(|| box approx_const::ApproxConstant);
- store.register_late_pass(|| box misc::MiscLints);
- store.register_late_pass(|| box eta_reduction::EtaReduction);
- store.register_late_pass(|| box identity_op::IdentityOp);
- store.register_late_pass(|| box erasing_op::ErasingOp);
- store.register_late_pass(|| box mut_mut::MutMut);
- store.register_late_pass(|| box mut_reference::UnnecessaryMutPassed);
- store.register_late_pass(|| box len_zero::LenZero);
- store.register_late_pass(|| box attrs::Attributes);
- store.register_late_pass(|| box blocks_in_if_conditions::BlocksInIfConditions);
- store.register_late_pass(|| box collapsible_match::CollapsibleMatch);
- store.register_late_pass(|| box unicode::Unicode);
- store.register_late_pass(|| box unit_return_expecting_ord::UnitReturnExpectingOrd);
- store.register_late_pass(|| box strings::StringAdd);
- store.register_late_pass(|| box implicit_return::ImplicitReturn);
- store.register_late_pass(|| box implicit_saturating_sub::ImplicitSaturatingSub);
- store.register_late_pass(|| box default_numeric_fallback::DefaultNumericFallback);
- store.register_late_pass(|| box inconsistent_struct_constructor::InconsistentStructConstructor);
- store.register_late_pass(|| box non_octal_unix_permissions::NonOctalUnixPermissions);
- store.register_early_pass(|| box unnecessary_self_imports::UnnecessarySelfImports);
+ store.register_group(true, "clippy::pedantic", Some("clippy_pedantic"), vec![
+ LintId::of(attrs::INLINE_ALWAYS),
+ LintId::of(await_holding_invalid::AWAIT_HOLDING_LOCK),
+ LintId::of(await_holding_invalid::AWAIT_HOLDING_REFCELL_REF),
+ LintId::of(bit_mask::VERBOSE_BIT_MASK),
+ LintId::of(bytecount::NAIVE_BYTECOUNT),
+ LintId::of(case_sensitive_file_extension_comparisons::CASE_SENSITIVE_FILE_EXTENSION_COMPARISONS),
+ LintId::of(casts::CAST_LOSSLESS),
+ LintId::of(casts::CAST_POSSIBLE_TRUNCATION),
+ LintId::of(casts::CAST_POSSIBLE_WRAP),
+ LintId::of(casts::CAST_PRECISION_LOSS),
+ LintId::of(casts::CAST_PTR_ALIGNMENT),
+ LintId::of(casts::CAST_SIGN_LOSS),
+ LintId::of(casts::PTR_AS_PTR),
+ LintId::of(checked_conversions::CHECKED_CONVERSIONS),
+ LintId::of(copies::SAME_FUNCTIONS_IN_IF_CONDITION),
+ LintId::of(copy_iterator::COPY_ITERATOR),
+ LintId::of(default::DEFAULT_TRAIT_ACCESS),
+ LintId::of(dereference::EXPLICIT_DEREF_METHODS),
+ LintId::of(derive::EXPL_IMPL_CLONE_ON_COPY),
+ LintId::of(derive::UNSAFE_DERIVE_DESERIALIZE),
+ LintId::of(doc::DOC_MARKDOWN),
+ LintId::of(doc::MISSING_ERRORS_DOC),
+ LintId::of(doc::MISSING_PANICS_DOC),
+ LintId::of(empty_enum::EMPTY_ENUM),
+ LintId::of(enum_variants::MODULE_NAME_REPETITIONS),
+ LintId::of(eta_reduction::REDUNDANT_CLOSURE_FOR_METHOD_CALLS),
+ LintId::of(excessive_bools::FN_PARAMS_EXCESSIVE_BOOLS),
+ LintId::of(excessive_bools::STRUCT_EXCESSIVE_BOOLS),
+ LintId::of(functions::MUST_USE_CANDIDATE),
+ LintId::of(functions::TOO_MANY_LINES),
+ LintId::of(if_not_else::IF_NOT_ELSE),
+ LintId::of(implicit_hasher::IMPLICIT_HASHER),
+ LintId::of(implicit_saturating_sub::IMPLICIT_SATURATING_SUB),
+ LintId::of(inconsistent_struct_constructor::INCONSISTENT_STRUCT_CONSTRUCTOR),
+ LintId::of(infinite_iter::MAYBE_INFINITE_ITER),
+ LintId::of(invalid_upcast_comparisons::INVALID_UPCAST_COMPARISONS),
+ LintId::of(items_after_statements::ITEMS_AFTER_STATEMENTS),
+ LintId::of(large_stack_arrays::LARGE_STACK_ARRAYS),
+ LintId::of(let_underscore::LET_UNDERSCORE_DROP),
+ LintId::of(literal_representation::LARGE_DIGIT_GROUPS),
+ LintId::of(literal_representation::UNREADABLE_LITERAL),
+ LintId::of(loops::EXPLICIT_INTO_ITER_LOOP),
+ LintId::of(loops::EXPLICIT_ITER_LOOP),
+ LintId::of(macro_use::MACRO_USE_IMPORTS),
+ LintId::of(manual_ok_or::MANUAL_OK_OR),
+ LintId::of(match_on_vec_items::MATCH_ON_VEC_ITEMS),
+ LintId::of(matches::MATCH_BOOL),
+ LintId::of(matches::MATCH_SAME_ARMS),
+ LintId::of(matches::MATCH_WILDCARD_FOR_SINGLE_VARIANTS),
+ LintId::of(matches::MATCH_WILD_ERR_ARM),
+ LintId::of(matches::SINGLE_MATCH_ELSE),
+ LintId::of(methods::CLONED_INSTEAD_OF_COPIED),
+ LintId::of(methods::FILTER_MAP_NEXT),
+ LintId::of(methods::FLAT_MAP_OPTION),
+ LintId::of(methods::IMPLICIT_CLONE),
+ LintId::of(methods::INEFFICIENT_TO_STRING),
+ LintId::of(methods::MAP_FLATTEN),
+ LintId::of(methods::MAP_UNWRAP_OR),
+ LintId::of(misc::USED_UNDERSCORE_BINDING),
+ LintId::of(misc_early::UNSEPARATED_LITERAL_SUFFIX),
+ LintId::of(mut_mut::MUT_MUT),
+ LintId::of(needless_bitwise_bool::NEEDLESS_BITWISE_BOOL),
+ LintId::of(needless_borrow::REF_BINDING_TO_REFERENCE),
+ LintId::of(needless_continue::NEEDLESS_CONTINUE),
+ LintId::of(needless_for_each::NEEDLESS_FOR_EACH),
+ LintId::of(needless_pass_by_value::NEEDLESS_PASS_BY_VALUE),
+ LintId::of(non_expressive_names::SIMILAR_NAMES),
+ LintId::of(option_if_let_else::OPTION_IF_LET_ELSE),
+ LintId::of(pass_by_ref_or_value::LARGE_TYPES_PASSED_BY_VALUE),
+ LintId::of(pass_by_ref_or_value::TRIVIALLY_COPY_PASS_BY_REF),
+ LintId::of(ranges::RANGE_MINUS_ONE),
+ LintId::of(ranges::RANGE_PLUS_ONE),
+ LintId::of(redundant_else::REDUNDANT_ELSE),
+ LintId::of(ref_option_ref::REF_OPTION_REF),
+ LintId::of(semicolon_if_nothing_returned::SEMICOLON_IF_NOTHING_RETURNED),
+ LintId::of(shadow::SHADOW_UNRELATED),
+ LintId::of(strings::STRING_ADD_ASSIGN),
+ LintId::of(trait_bounds::TRAIT_DUPLICATION_IN_BOUNDS),
+ LintId::of(trait_bounds::TYPE_REPETITION_IN_BOUNDS),
+ LintId::of(transmute::TRANSMUTE_PTR_TO_PTR),
+ LintId::of(types::LINKEDLIST),
+ LintId::of(types::OPTION_OPTION),
+ LintId::of(unicode::NON_ASCII_LITERAL),
+ LintId::of(unicode::UNICODE_NOT_NFC),
+ LintId::of(unit_types::LET_UNIT_VALUE),
+ LintId::of(unnecessary_wraps::UNNECESSARY_WRAPS),
+ LintId::of(unnested_or_patterns::UNNESTED_OR_PATTERNS),
+ LintId::of(unused_async::UNUSED_ASYNC),
+ LintId::of(unused_self::UNUSED_SELF),
+ LintId::of(wildcard_imports::ENUM_GLOB_USE),
+ LintId::of(wildcard_imports::WILDCARD_IMPORTS),
+ LintId::of(zero_sized_map_values::ZERO_SIZED_MAP_VALUES),
+ ]);
- let msrv = conf.msrv.as_ref().and_then(|s| {
- parse_msrv(s, None, None).or_else(|| {
- sess.err(&format!("error reading Clippy's configuration file. `{}` is not a valid Rust version", s));
- None
- })
- });
-
- store.register_late_pass(move || box methods::Methods::new(msrv));
- store.register_late_pass(move || box matches::Matches::new(msrv));
- store.register_early_pass(move || box manual_non_exhaustive::ManualNonExhaustive::new(msrv));
- store.register_late_pass(move || box manual_strip::ManualStrip::new(msrv));
- store.register_early_pass(move || box redundant_static_lifetimes::RedundantStaticLifetimes::new(msrv));
- store.register_early_pass(move || box redundant_field_names::RedundantFieldNames::new(msrv));
- store.register_late_pass(move || box checked_conversions::CheckedConversions::new(msrv));
- store.register_late_pass(move || box mem_replace::MemReplace::new(msrv));
- store.register_late_pass(move || box ranges::Ranges::new(msrv));
- store.register_late_pass(move || box from_over_into::FromOverInto::new(msrv));
- store.register_late_pass(move || box use_self::UseSelf::new(msrv));
- store.register_late_pass(move || box missing_const_for_fn::MissingConstForFn::new(msrv));
- store.register_late_pass(move || box needless_question_mark::NeedlessQuestionMark);
- store.register_late_pass(move || box casts::Casts::new(msrv));
- store.register_early_pass(move || box unnested_or_patterns::UnnestedOrPatterns::new(msrv));
-
- store.register_late_pass(|| box size_of_in_element_count::SizeOfInElementCount);
- store.register_late_pass(|| box map_clone::MapClone);
- store.register_late_pass(|| box map_err_ignore::MapErrIgnore);
- store.register_late_pass(|| box shadow::Shadow);
- store.register_late_pass(|| box unit_types::UnitTypes);
- store.register_late_pass(|| box loops::Loops);
- store.register_late_pass(|| box main_recursion::MainRecursion::default());
- store.register_late_pass(|| box lifetimes::Lifetimes);
- store.register_late_pass(|| box entry::HashMapPass);
- store.register_late_pass(|| box minmax::MinMaxPass);
- store.register_late_pass(|| box open_options::OpenOptions);
- store.register_late_pass(|| box zero_div_zero::ZeroDiv);
- store.register_late_pass(|| box mutex_atomic::Mutex);
- store.register_late_pass(|| box needless_update::NeedlessUpdate);
- store.register_late_pass(|| box needless_borrow::NeedlessBorrow::default());
- store.register_late_pass(|| box needless_borrowed_ref::NeedlessBorrowedRef);
- store.register_late_pass(|| box no_effect::NoEffect);
- store.register_late_pass(|| box temporary_assignment::TemporaryAssignment);
- store.register_late_pass(|| box transmute::Transmute);
- let cognitive_complexity_threshold = conf.cognitive_complexity_threshold;
- store.register_late_pass(move || box cognitive_complexity::CognitiveComplexity::new(cognitive_complexity_threshold));
- let too_large_for_stack = conf.too_large_for_stack;
- store.register_late_pass(move || box escape::BoxedLocal{too_large_for_stack});
- store.register_late_pass(move || box vec::UselessVec{too_large_for_stack});
- store.register_late_pass(|| box panic_unimplemented::PanicUnimplemented);
- store.register_late_pass(|| box strings::StringLitAsBytes);
- store.register_late_pass(|| box derive::Derive);
- store.register_late_pass(|| box get_last_with_len::GetLastWithLen);
- store.register_late_pass(|| box drop_forget_ref::DropForgetRef);
- store.register_late_pass(|| box empty_enum::EmptyEnum);
- store.register_late_pass(|| box absurd_extreme_comparisons::AbsurdExtremeComparisons);
- store.register_late_pass(|| box invalid_upcast_comparisons::InvalidUpcastComparisons);
- store.register_late_pass(|| box regex::Regex::default());
- store.register_late_pass(|| box copies::CopyAndPaste);
- store.register_late_pass(|| box copy_iterator::CopyIterator);
- store.register_late_pass(|| box format::UselessFormat);
- store.register_late_pass(|| box swap::Swap);
- store.register_late_pass(|| box overflow_check_conditional::OverflowCheckConditional);
- store.register_late_pass(|| box new_without_default::NewWithoutDefault::default());
- let blacklisted_names = conf.blacklisted_names.iter().cloned().collect::<FxHashSet<_>>();
- store.register_late_pass(move || box blacklisted_name::BlacklistedName::new(blacklisted_names.clone()));
- let too_many_arguments_threshold = conf.too_many_arguments_threshold;
- let too_many_lines_threshold = conf.too_many_lines_threshold;
- store.register_late_pass(move || box functions::Functions::new(too_many_arguments_threshold, too_many_lines_threshold));
- let doc_valid_idents = conf.doc_valid_idents.iter().cloned().collect::<FxHashSet<_>>();
- store.register_late_pass(move || box doc::DocMarkdown::new(doc_valid_idents.clone()));
- store.register_late_pass(|| box neg_multiply::NegMultiply);
- store.register_late_pass(|| box mem_discriminant::MemDiscriminant);
- store.register_late_pass(|| box mem_forget::MemForget);
- store.register_late_pass(|| box arithmetic::Arithmetic::default());
- store.register_late_pass(|| box assign_ops::AssignOps);
- store.register_late_pass(|| box let_if_seq::LetIfSeq);
- store.register_late_pass(|| box eval_order_dependence::EvalOrderDependence);
- store.register_late_pass(|| box missing_doc::MissingDoc::new());
- store.register_late_pass(|| box missing_inline::MissingInline);
- store.register_late_pass(move || box exhaustive_items::ExhaustiveItems);
- store.register_late_pass(|| box if_let_some_result::OkIfLet);
- store.register_late_pass(|| box partialeq_ne_impl::PartialEqNeImpl);
- store.register_late_pass(|| box unused_io_amount::UnusedIoAmount);
- let enum_variant_size_threshold = conf.enum_variant_size_threshold;
- store.register_late_pass(move || box large_enum_variant::LargeEnumVariant::new(enum_variant_size_threshold));
- store.register_late_pass(|| box explicit_write::ExplicitWrite);
- store.register_late_pass(|| box needless_pass_by_value::NeedlessPassByValue);
- let pass_by_ref_or_value = pass_by_ref_or_value::PassByRefOrValue::new(
- conf.trivial_copy_size_limit,
- conf.pass_by_value_size_limit,
- &sess.target,
- );
- store.register_late_pass(move || box pass_by_ref_or_value);
- store.register_late_pass(|| box ref_option_ref::RefOptionRef);
- store.register_late_pass(|| box try_err::TryErr);
- store.register_late_pass(|| box bytecount::ByteCount);
- store.register_late_pass(|| box infinite_iter::InfiniteIter);
- store.register_late_pass(|| box inline_fn_without_body::InlineFnWithoutBody);
- store.register_late_pass(|| box useless_conversion::UselessConversion::default());
- store.register_late_pass(|| box implicit_hasher::ImplicitHasher);
- store.register_late_pass(|| box fallible_impl_from::FallibleImplFrom);
- store.register_late_pass(|| box double_comparison::DoubleComparisons);
- store.register_late_pass(|| box question_mark::QuestionMark);
- store.register_early_pass(|| box suspicious_operation_groupings::SuspiciousOperationGroupings);
- store.register_late_pass(|| box suspicious_trait_impl::SuspiciousImpl);
- store.register_late_pass(|| box map_unit_fn::MapUnit);
- store.register_late_pass(|| box inherent_impl::MultipleInherentImpl);
- store.register_late_pass(|| box neg_cmp_op_on_partial_ord::NoNegCompOpForPartialOrd);
- store.register_late_pass(|| box unwrap::Unwrap);
- store.register_late_pass(|| box duration_subsec::DurationSubsec);
- store.register_late_pass(|| box indexing_slicing::IndexingSlicing);
- store.register_late_pass(|| box non_copy_const::NonCopyConst);
- store.register_late_pass(|| box ptr_offset_with_cast::PtrOffsetWithCast);
- store.register_late_pass(|| box redundant_clone::RedundantClone);
- store.register_late_pass(|| box slow_vector_initialization::SlowVectorInit);
- store.register_late_pass(|| box unnecessary_sort_by::UnnecessarySortBy);
- store.register_late_pass(|| box unnecessary_wraps::UnnecessaryWraps);
- store.register_late_pass(|| box assertions_on_constants::AssertionsOnConstants);
- store.register_late_pass(|| box transmuting_null::TransmutingNull);
- store.register_late_pass(|| box path_buf_push_overwrite::PathBufPushOverwrite);
- store.register_late_pass(|| box integer_division::IntegerDivision);
- store.register_late_pass(|| box inherent_to_string::InherentToString);
- let max_trait_bounds = conf.max_trait_bounds;
- store.register_late_pass(move || box trait_bounds::TraitBounds::new(max_trait_bounds));
- store.register_late_pass(|| box comparison_chain::ComparisonChain);
- store.register_late_pass(|| box mut_key::MutableKeyType);
- store.register_late_pass(|| box modulo_arithmetic::ModuloArithmetic);
- store.register_early_pass(|| box reference::DerefAddrOf);
- store.register_early_pass(|| box reference::RefInDeref);
- store.register_early_pass(|| box double_parens::DoubleParens);
- store.register_late_pass(|| box to_string_in_display::ToStringInDisplay::new());
- store.register_early_pass(|| box unsafe_removed_from_name::UnsafeNameRemoval);
- store.register_early_pass(|| box if_not_else::IfNotElse);
- store.register_early_pass(|| box else_if_without_else::ElseIfWithoutElse);
- store.register_early_pass(|| box int_plus_one::IntPlusOne);
- store.register_early_pass(|| box formatting::Formatting);
- store.register_early_pass(|| box misc_early::MiscEarlyLints);
- store.register_early_pass(|| box redundant_closure_call::RedundantClosureCall);
- store.register_late_pass(|| box redundant_closure_call::RedundantClosureCall);
- store.register_early_pass(|| box unused_unit::UnusedUnit);
- store.register_late_pass(|| box returns::Return);
- store.register_early_pass(|| box collapsible_if::CollapsibleIf);
- store.register_early_pass(|| box items_after_statements::ItemsAfterStatements);
- store.register_early_pass(|| box precedence::Precedence);
- store.register_early_pass(|| box needless_continue::NeedlessContinue);
- store.register_early_pass(|| box redundant_else::RedundantElse);
- store.register_late_pass(|| box create_dir::CreateDir);
- store.register_early_pass(|| box needless_arbitrary_self_type::NeedlessArbitrarySelfType);
- let cargo_ignore_publish = conf.cargo_ignore_publish;
- store.register_late_pass(move || box cargo_common_metadata::CargoCommonMetadata::new(cargo_ignore_publish));
- store.register_late_pass(|| box multiple_crate_versions::MultipleCrateVersions);
- store.register_late_pass(|| box wildcard_dependencies::WildcardDependencies);
- let literal_representation_lint_fraction_readability = conf.unreadable_literal_lint_fractions;
- store.register_early_pass(move || box literal_representation::LiteralDigitGrouping::new(literal_representation_lint_fraction_readability));
- let literal_representation_threshold = conf.literal_representation_threshold;
- store.register_early_pass(move || box literal_representation::DecimalLiteralRepresentation::new(literal_representation_threshold));
- let enum_variant_name_threshold = conf.enum_variant_name_threshold;
- store.register_early_pass(move || box enum_variants::EnumVariantNames::new(enum_variant_name_threshold));
- store.register_early_pass(|| box tabs_in_doc_comments::TabsInDocComments);
- let upper_case_acronyms_aggressive = conf.upper_case_acronyms_aggressive;
- store.register_early_pass(move || box upper_case_acronyms::UpperCaseAcronyms::new(upper_case_acronyms_aggressive));
- store.register_late_pass(|| box default::Default::default());
- store.register_late_pass(|| box unused_self::UnusedSelf);
- store.register_late_pass(|| box mutable_debug_assertion::DebugAssertWithMutCall);
- store.register_late_pass(|| box exit::Exit);
- store.register_late_pass(|| box to_digit_is_some::ToDigitIsSome);
- let array_size_threshold = conf.array_size_threshold;
- store.register_late_pass(move || box large_stack_arrays::LargeStackArrays::new(array_size_threshold));
- store.register_late_pass(move || box large_const_arrays::LargeConstArrays::new(array_size_threshold));
- store.register_late_pass(|| box floating_point_arithmetic::FloatingPointArithmetic);
- store.register_early_pass(|| box as_conversions::AsConversions);
- store.register_late_pass(|| box let_underscore::LetUnderscore);
- store.register_late_pass(|| box atomic_ordering::AtomicOrdering);
- store.register_early_pass(|| box single_component_path_imports::SingleComponentPathImports);
- let max_fn_params_bools = conf.max_fn_params_bools;
- let max_struct_bools = conf.max_struct_bools;
- store.register_early_pass(move || box excessive_bools::ExcessiveBools::new(max_struct_bools, max_fn_params_bools));
- store.register_early_pass(|| box option_env_unwrap::OptionEnvUnwrap);
- let warn_on_all_wildcard_imports = conf.warn_on_all_wildcard_imports;
- store.register_late_pass(move || box wildcard_imports::WildcardImports::new(warn_on_all_wildcard_imports));
- store.register_late_pass(|| box verbose_file_reads::VerboseFileReads);
- store.register_late_pass(|| box redundant_pub_crate::RedundantPubCrate::default());
- store.register_late_pass(|| box unnamed_address::UnnamedAddress);
- store.register_late_pass(|| box dereference::Dereferencing::default());
- store.register_late_pass(|| box option_if_let_else::OptionIfLetElse);
- store.register_late_pass(|| box future_not_send::FutureNotSend);
- store.register_late_pass(|| box if_let_mutex::IfLetMutex);
- store.register_late_pass(|| box mut_mutex_lock::MutMutexLock);
- store.register_late_pass(|| box match_on_vec_items::MatchOnVecItems);
- store.register_late_pass(|| box manual_async_fn::ManualAsyncFn);
- store.register_late_pass(|| box vec_resize_to_zero::VecResizeToZero);
- store.register_late_pass(|| box panic_in_result_fn::PanicInResultFn);
- let single_char_binding_names_threshold = conf.single_char_binding_names_threshold;
- store.register_early_pass(move || box non_expressive_names::NonExpressiveNames {
- single_char_binding_names_threshold,
- });
- store.register_late_pass(|| box macro_use::MacroUseImports::default());
- store.register_late_pass(|| box map_identity::MapIdentity);
- store.register_late_pass(|| box pattern_type_mismatch::PatternTypeMismatch);
- store.register_late_pass(|| box stable_sort_primitive::StableSortPrimitive);
- store.register_late_pass(|| box repeat_once::RepeatOnce);
- store.register_late_pass(|| box unwrap_in_result::UnwrapInResult);
- store.register_late_pass(|| box self_assignment::SelfAssignment);
- store.register_late_pass(|| box manual_unwrap_or::ManualUnwrapOr);
- store.register_late_pass(|| box manual_ok_or::ManualOkOr);
- store.register_late_pass(|| box float_equality_without_abs::FloatEqualityWithoutAbs);
- store.register_late_pass(|| box semicolon_if_nothing_returned::SemicolonIfNothingReturned);
- store.register_late_pass(|| box async_yields_async::AsyncYieldsAsync);
- let disallowed_methods = conf.disallowed_methods.iter().cloned().collect::<FxHashSet<_>>();
- store.register_late_pass(move || box disallowed_method::DisallowedMethod::new(&disallowed_methods));
- store.register_early_pass(|| box asm_syntax::InlineAsmX86AttSyntax);
- store.register_early_pass(|| box asm_syntax::InlineAsmX86IntelSyntax);
- store.register_late_pass(|| box undropped_manually_drops::UndroppedManuallyDrops);
- store.register_late_pass(|| box strings::StrToString);
- store.register_late_pass(|| box strings::StringToString);
- store.register_late_pass(|| box zero_sized_map_values::ZeroSizedMapValues);
- store.register_late_pass(|| box vec_init_then_push::VecInitThenPush::default());
- store.register_late_pass(|| box case_sensitive_file_extension_comparisons::CaseSensitiveFileExtensionComparisons);
- store.register_late_pass(|| box redundant_slicing::RedundantSlicing);
- store.register_late_pass(|| box from_str_radix_10::FromStrRadix10);
- store.register_late_pass(|| box manual_map::ManualMap);
- store.register_late_pass(move || box if_then_some_else_none::IfThenSomeElseNone::new(msrv));
- store.register_early_pass(|| box bool_assert_comparison::BoolAssertComparison);
- store.register_late_pass(|| box unused_async::UnusedAsync);
-
- store.register_group(true, "clippy::restriction", Some("clippy_restriction"), vec![
- LintId::of(arithmetic::FLOAT_ARITHMETIC),
- LintId::of(arithmetic::INTEGER_ARITHMETIC),
- LintId::of(as_conversions::AS_CONVERSIONS),
- LintId::of(asm_syntax::INLINE_ASM_X86_ATT_SYNTAX),
- LintId::of(asm_syntax::INLINE_ASM_X86_INTEL_SYNTAX),
- LintId::of(create_dir::CREATE_DIR),
- LintId::of(dbg_macro::DBG_MACRO),
- LintId::of(default_numeric_fallback::DEFAULT_NUMERIC_FALLBACK),
- LintId::of(else_if_without_else::ELSE_IF_WITHOUT_ELSE),
- LintId::of(exhaustive_items::EXHAUSTIVE_ENUMS),
- LintId::of(exhaustive_items::EXHAUSTIVE_STRUCTS),
- LintId::of(exit::EXIT),
- LintId::of(float_literal::LOSSY_FLOAT_LITERAL),
- LintId::of(if_then_some_else_none::IF_THEN_SOME_ELSE_NONE),
- LintId::of(implicit_return::IMPLICIT_RETURN),
- LintId::of(indexing_slicing::INDEXING_SLICING),
- LintId::of(inherent_impl::MULTIPLE_INHERENT_IMPL),
- LintId::of(integer_division::INTEGER_DIVISION),
- LintId::of(let_underscore::LET_UNDERSCORE_MUST_USE),
- LintId::of(literal_representation::DECIMAL_LITERAL_REPRESENTATION),
- LintId::of(map_err_ignore::MAP_ERR_IGNORE),
- LintId::of(matches::REST_PAT_IN_FULLY_BOUND_STRUCTS),
- LintId::of(matches::WILDCARD_ENUM_MATCH_ARM),
- LintId::of(mem_forget::MEM_FORGET),
- LintId::of(methods::CLONE_ON_REF_PTR),
- LintId::of(methods::EXPECT_USED),
- LintId::of(methods::FILETYPE_IS_FILE),
- LintId::of(methods::GET_UNWRAP),
- LintId::of(methods::UNWRAP_USED),
- LintId::of(methods::WRONG_PUB_SELF_CONVENTION),
- LintId::of(misc::FLOAT_CMP_CONST),
- LintId::of(misc_early::UNNEEDED_FIELD_PATTERN),
- LintId::of(missing_doc::MISSING_DOCS_IN_PRIVATE_ITEMS),
- LintId::of(missing_inline::MISSING_INLINE_IN_PUBLIC_ITEMS),
- LintId::of(modulo_arithmetic::MODULO_ARITHMETIC),
- LintId::of(panic_in_result_fn::PANIC_IN_RESULT_FN),
- LintId::of(panic_unimplemented::PANIC),
- LintId::of(panic_unimplemented::TODO),
- LintId::of(panic_unimplemented::UNIMPLEMENTED),
- LintId::of(panic_unimplemented::UNREACHABLE),
- LintId::of(pattern_type_mismatch::PATTERN_TYPE_MISMATCH),
- LintId::of(semicolon_if_nothing_returned::SEMICOLON_IF_NOTHING_RETURNED),
- LintId::of(shadow::SHADOW_REUSE),
- LintId::of(shadow::SHADOW_SAME),
- LintId::of(strings::STRING_ADD),
- LintId::of(strings::STRING_TO_STRING),
- LintId::of(strings::STR_TO_STRING),
- LintId::of(types::RC_BUFFER),
- LintId::of(unnecessary_self_imports::UNNECESSARY_SELF_IMPORTS),
- LintId::of(unwrap_in_result::UNWRAP_IN_RESULT),
- LintId::of(verbose_file_reads::VERBOSE_FILE_READS),
- LintId::of(write::PRINT_STDERR),
- LintId::of(write::PRINT_STDOUT),
- LintId::of(write::USE_DEBUG),
- ]);
-
- store.register_group(true, "clippy::pedantic", Some("clippy_pedantic"), vec![
- LintId::of(attrs::INLINE_ALWAYS),
- LintId::of(await_holding_invalid::AWAIT_HOLDING_LOCK),
- LintId::of(await_holding_invalid::AWAIT_HOLDING_REFCELL_REF),
- LintId::of(bit_mask::VERBOSE_BIT_MASK),
- LintId::of(bytecount::NAIVE_BYTECOUNT),
- LintId::of(case_sensitive_file_extension_comparisons::CASE_SENSITIVE_FILE_EXTENSION_COMPARISONS),
- LintId::of(casts::CAST_LOSSLESS),
- LintId::of(casts::CAST_POSSIBLE_TRUNCATION),
- LintId::of(casts::CAST_POSSIBLE_WRAP),
- LintId::of(casts::CAST_PRECISION_LOSS),
- LintId::of(casts::CAST_PTR_ALIGNMENT),
- LintId::of(casts::CAST_SIGN_LOSS),
- LintId::of(casts::PTR_AS_PTR),
- LintId::of(checked_conversions::CHECKED_CONVERSIONS),
- LintId::of(copies::SAME_FUNCTIONS_IN_IF_CONDITION),
- LintId::of(copy_iterator::COPY_ITERATOR),
- LintId::of(default::DEFAULT_TRAIT_ACCESS),
- LintId::of(dereference::EXPLICIT_DEREF_METHODS),
- LintId::of(derive::EXPL_IMPL_CLONE_ON_COPY),
- LintId::of(derive::UNSAFE_DERIVE_DESERIALIZE),
- LintId::of(doc::DOC_MARKDOWN),
- LintId::of(doc::MISSING_ERRORS_DOC),
- LintId::of(doc::MISSING_PANICS_DOC),
- LintId::of(empty_enum::EMPTY_ENUM),
- LintId::of(enum_variants::MODULE_NAME_REPETITIONS),
- LintId::of(enum_variants::PUB_ENUM_VARIANT_NAMES),
- LintId::of(eta_reduction::REDUNDANT_CLOSURE_FOR_METHOD_CALLS),
- LintId::of(excessive_bools::FN_PARAMS_EXCESSIVE_BOOLS),
- LintId::of(excessive_bools::STRUCT_EXCESSIVE_BOOLS),
- LintId::of(functions::MUST_USE_CANDIDATE),
- LintId::of(functions::TOO_MANY_LINES),
- LintId::of(if_not_else::IF_NOT_ELSE),
- LintId::of(implicit_hasher::IMPLICIT_HASHER),
- LintId::of(implicit_saturating_sub::IMPLICIT_SATURATING_SUB),
- LintId::of(inconsistent_struct_constructor::INCONSISTENT_STRUCT_CONSTRUCTOR),
- LintId::of(infinite_iter::MAYBE_INFINITE_ITER),
- LintId::of(invalid_upcast_comparisons::INVALID_UPCAST_COMPARISONS),
- LintId::of(items_after_statements::ITEMS_AFTER_STATEMENTS),
- LintId::of(large_stack_arrays::LARGE_STACK_ARRAYS),
- LintId::of(let_underscore::LET_UNDERSCORE_DROP),
- LintId::of(literal_representation::LARGE_DIGIT_GROUPS),
- LintId::of(literal_representation::UNREADABLE_LITERAL),
- LintId::of(loops::EXPLICIT_INTO_ITER_LOOP),
- LintId::of(loops::EXPLICIT_ITER_LOOP),
- LintId::of(macro_use::MACRO_USE_IMPORTS),
- LintId::of(manual_ok_or::MANUAL_OK_OR),
- LintId::of(match_on_vec_items::MATCH_ON_VEC_ITEMS),
- LintId::of(matches::MATCH_BOOL),
- LintId::of(matches::MATCH_SAME_ARMS),
- LintId::of(matches::MATCH_WILDCARD_FOR_SINGLE_VARIANTS),
- LintId::of(matches::MATCH_WILD_ERR_ARM),
- LintId::of(matches::SINGLE_MATCH_ELSE),
- LintId::of(methods::CLONED_INSTEAD_OF_COPIED),
- LintId::of(methods::FILTER_MAP_NEXT),
- LintId::of(methods::FLAT_MAP_OPTION),
- LintId::of(methods::IMPLICIT_CLONE),
- LintId::of(methods::INEFFICIENT_TO_STRING),
- LintId::of(methods::MAP_FLATTEN),
- LintId::of(methods::MAP_UNWRAP_OR),
- LintId::of(misc::USED_UNDERSCORE_BINDING),
- LintId::of(misc_early::UNSEPARATED_LITERAL_SUFFIX),
- LintId::of(mut_mut::MUT_MUT),
- LintId::of(needless_bitwise_bool::NEEDLESS_BITWISE_BOOL),
- LintId::of(needless_continue::NEEDLESS_CONTINUE),
- LintId::of(needless_for_each::NEEDLESS_FOR_EACH),
- LintId::of(needless_pass_by_value::NEEDLESS_PASS_BY_VALUE),
- LintId::of(non_expressive_names::SIMILAR_NAMES),
- LintId::of(option_if_let_else::OPTION_IF_LET_ELSE),
- LintId::of(pass_by_ref_or_value::LARGE_TYPES_PASSED_BY_VALUE),
- LintId::of(pass_by_ref_or_value::TRIVIALLY_COPY_PASS_BY_REF),
- LintId::of(ranges::RANGE_MINUS_ONE),
- LintId::of(ranges::RANGE_PLUS_ONE),
- LintId::of(redundant_else::REDUNDANT_ELSE),
- LintId::of(ref_option_ref::REF_OPTION_REF),
- LintId::of(shadow::SHADOW_UNRELATED),
- LintId::of(strings::STRING_ADD_ASSIGN),
- LintId::of(trait_bounds::TRAIT_DUPLICATION_IN_BOUNDS),
- LintId::of(trait_bounds::TYPE_REPETITION_IN_BOUNDS),
- LintId::of(transmute::TRANSMUTE_PTR_TO_PTR),
- LintId::of(types::LINKEDLIST),
- LintId::of(types::OPTION_OPTION),
- LintId::of(unicode::NON_ASCII_LITERAL),
- LintId::of(unicode::UNICODE_NOT_NFC),
- LintId::of(unit_types::LET_UNIT_VALUE),
- LintId::of(unnecessary_wraps::UNNECESSARY_WRAPS),
- LintId::of(unnested_or_patterns::UNNESTED_OR_PATTERNS),
- LintId::of(unused_async::UNUSED_ASYNC),
- LintId::of(unused_self::UNUSED_SELF),
- LintId::of(wildcard_imports::ENUM_GLOB_USE),
- LintId::of(wildcard_imports::WILDCARD_IMPORTS),
- LintId::of(zero_sized_map_values::ZERO_SIZED_MAP_VALUES),
- ]);
-
- #[cfg(feature = "internal-lints")]
- store.register_group(true, "clippy::internal", Some("clippy_internal"), vec![
- LintId::of(utils::internal_lints::CLIPPY_LINTS_INTERNAL),
- LintId::of(utils::internal_lints::COLLAPSIBLE_SPAN_LINT_CALLS),
- LintId::of(utils::internal_lints::COMPILER_LINT_FUNCTIONS),
- LintId::of(utils::internal_lints::DEFAULT_LINT),
- LintId::of(utils::internal_lints::IF_CHAIN_STYLE),
- LintId::of(utils::internal_lints::INTERNING_DEFINED_SYMBOL),
- LintId::of(utils::internal_lints::INVALID_PATHS),
- LintId::of(utils::internal_lints::LINT_WITHOUT_LINT_PASS),
- LintId::of(utils::internal_lints::MATCH_TYPE_ON_DIAGNOSTIC_ITEM),
- LintId::of(utils::internal_lints::OUTER_EXPN_EXPN_DATA),
- LintId::of(utils::internal_lints::PRODUCE_ICE),
- LintId::of(utils::internal_lints::UNNECESSARY_SYMBOL_STR),
- ]);
+ #[cfg(feature = "internal-lints")]
+ store.register_group(true, "clippy::internal", Some("clippy_internal"), vec![
+ LintId::of(utils::internal_lints::CLIPPY_LINTS_INTERNAL),
+ LintId::of(utils::internal_lints::COLLAPSIBLE_SPAN_LINT_CALLS),
+ LintId::of(utils::internal_lints::COMPILER_LINT_FUNCTIONS),
+ LintId::of(utils::internal_lints::DEFAULT_LINT),
+ LintId::of(utils::internal_lints::IF_CHAIN_STYLE),
+ LintId::of(utils::internal_lints::INTERNING_DEFINED_SYMBOL),
+ LintId::of(utils::internal_lints::INVALID_PATHS),
+ LintId::of(utils::internal_lints::LINT_WITHOUT_LINT_PASS),
+ LintId::of(utils::internal_lints::MATCH_TYPE_ON_DIAGNOSTIC_ITEM),
+ LintId::of(utils::internal_lints::OUTER_EXPN_EXPN_DATA),
+ LintId::of(utils::internal_lints::PRODUCE_ICE),
+ LintId::of(utils::internal_lints::UNNECESSARY_SYMBOL_STR),
+ ]);
store.register_group(true, "clippy::all", Some("clippy"), vec![
LintId::of(absurd_extreme_comparisons::ABSURD_EXTREME_COMPARISONS),
LintId::of(methods::MANUAL_FILTER_MAP),
LintId::of(methods::MANUAL_FIND_MAP),
LintId::of(methods::MANUAL_SATURATING_ARITHMETIC),
+ LintId::of(methods::MANUAL_STR_REPEAT),
LintId::of(methods::MAP_COLLECT_RESULT_UNIT),
LintId::of(methods::NEW_RET_NO_SELF),
LintId::of(methods::OK_EXPECT),
LintId::of(methods::SKIP_WHILE_NEXT),
LintId::of(methods::STRING_EXTEND_CHARS),
LintId::of(methods::SUSPICIOUS_MAP),
+ LintId::of(methods::SUSPICIOUS_SPLITN),
LintId::of(methods::UNINIT_ASSUMED_INIT),
LintId::of(methods::UNNECESSARY_FILTER_MAP),
LintId::of(methods::UNNECESSARY_FOLD),
LintId::of(needless_arbitrary_self_type::NEEDLESS_ARBITRARY_SELF_TYPE),
LintId::of(needless_bool::BOOL_COMPARISON),
LintId::of(needless_bool::NEEDLESS_BOOL),
+ LintId::of(needless_borrow::NEEDLESS_BORROW),
LintId::of(needless_borrowed_ref::NEEDLESS_BORROWED_REFERENCE),
LintId::of(needless_question_mark::NEEDLESS_QUESTION_MARK),
LintId::of(needless_update::NEEDLESS_UPDATE),
LintId::of(slow_vector_initialization::SLOW_VECTOR_INITIALIZATION),
LintId::of(stable_sort_primitive::STABLE_SORT_PRIMITIVE),
LintId::of(strings::STRING_FROM_UTF8_AS_BYTES),
- LintId::of(suspicious_operation_groupings::SUSPICIOUS_OPERATION_GROUPINGS),
LintId::of(suspicious_trait_impl::SUSPICIOUS_ARITHMETIC_IMPL),
LintId::of(suspicious_trait_impl::SUSPICIOUS_OP_ASSIGN_IMPL),
LintId::of(swap::ALMOST_SWAPPED),
LintId::of(misc_early::REDUNDANT_PATTERN),
LintId::of(mut_mutex_lock::MUT_MUTEX_LOCK),
LintId::of(mut_reference::UNNECESSARY_MUT_PASSED),
+ LintId::of(needless_borrow::NEEDLESS_BORROW),
LintId::of(neg_multiply::NEG_MULTIPLY),
LintId::of(new_without_default::NEW_WITHOUT_DEFAULT),
LintId::of(non_copy_const::BORROW_INTERIOR_MUTABLE_CONST),
LintId::of(returns::LET_AND_RETURN),
LintId::of(returns::NEEDLESS_RETURN),
LintId::of(single_component_path_imports::SINGLE_COMPONENT_PATH_IMPORTS),
- LintId::of(suspicious_operation_groupings::SUSPICIOUS_OPERATION_GROUPINGS),
LintId::of(tabs_in_doc_comments::TABS_IN_DOC_COMMENTS),
LintId::of(to_digit_is_some::TO_DIGIT_IS_SOME),
LintId::of(try_err::TRY_ERR),
LintId::of(mem_replace::MEM_REPLACE_WITH_UNINIT),
LintId::of(methods::CLONE_DOUBLE_REF),
LintId::of(methods::ITERATOR_STEP_BY_ZERO),
+ LintId::of(methods::SUSPICIOUS_SPLITN),
LintId::of(methods::UNINIT_ASSUMED_INIT),
LintId::of(methods::ZST_OFFSET),
LintId::of(minmax::MIN_MAX),
LintId::of(loops::NEEDLESS_COLLECT),
LintId::of(methods::EXPECT_FUN_CALL),
LintId::of(methods::ITER_NTH),
+ LintId::of(methods::MANUAL_STR_REPEAT),
LintId::of(methods::OR_FUN_CALL),
LintId::of(methods::SINGLE_CHAR_PATTERN),
LintId::of(misc::CMP_OWNED),
LintId::of(vec_init_then_push::VEC_INIT_THEN_PUSH),
]);
- store.register_group(true, "clippy::cargo", Some("clippy_cargo"), vec![
- LintId::of(cargo_common_metadata::CARGO_COMMON_METADATA),
- LintId::of(multiple_crate_versions::MULTIPLE_CRATE_VERSIONS),
- LintId::of(wildcard_dependencies::WILDCARD_DEPENDENCIES),
- ]);
+ store.register_group(true, "clippy::cargo", Some("clippy_cargo"), vec![
+ LintId::of(cargo_common_metadata::CARGO_COMMON_METADATA),
+ LintId::of(multiple_crate_versions::MULTIPLE_CRATE_VERSIONS),
+ LintId::of(wildcard_dependencies::WILDCARD_DEPENDENCIES),
+ ]);
+
+ store.register_group(true, "clippy::nursery", Some("clippy_nursery"), vec![
+ LintId::of(attrs::EMPTY_LINE_AFTER_OUTER_ATTR),
+ LintId::of(cognitive_complexity::COGNITIVE_COMPLEXITY),
+ LintId::of(disallowed_method::DISALLOWED_METHOD),
+ LintId::of(fallible_impl_from::FALLIBLE_IMPL_FROM),
+ LintId::of(floating_point_arithmetic::IMPRECISE_FLOPS),
+ LintId::of(floating_point_arithmetic::SUBOPTIMAL_FLOPS),
+ LintId::of(future_not_send::FUTURE_NOT_SEND),
+ LintId::of(let_if_seq::USELESS_LET_IF_SEQ),
+ LintId::of(missing_const_for_fn::MISSING_CONST_FOR_FN),
+ LintId::of(mutable_debug_assertion::DEBUG_ASSERT_WITH_MUT_CALL),
+ LintId::of(mutex_atomic::MUTEX_INTEGER),
+ LintId::of(path_buf_push_overwrite::PATH_BUF_PUSH_OVERWRITE),
+ LintId::of(redundant_pub_crate::REDUNDANT_PUB_CRATE),
+ LintId::of(regex::TRIVIAL_REGEX),
+ LintId::of(strings::STRING_LIT_AS_BYTES),
+ LintId::of(suspicious_operation_groupings::SUSPICIOUS_OPERATION_GROUPINGS),
+ LintId::of(transmute::USELESS_TRANSMUTE),
+ LintId::of(use_self::USE_SELF),
+ ]);
+
+ #[cfg(feature = "metadata-collector-lint")]
+ {
+ if std::env::var("ENABLE_METADATA_COLLECTION").eq(&Ok("1".to_string())) {
+ store.register_late_pass(|| box utils::internal_lints::metadata_collector::MetadataCollector::new());
+ return;
+ }
+ }
+
+ // all the internal lints
+ #[cfg(feature = "internal-lints")]
+ {
+ store.register_early_pass(|| box utils::internal_lints::ClippyLintsInternal);
+ store.register_early_pass(|| box utils::internal_lints::ProduceIce);
+ store.register_late_pass(|| box utils::inspector::DeepCodeInspector);
+ store.register_late_pass(|| box utils::internal_lints::CollapsibleCalls);
+ store.register_late_pass(|| box utils::internal_lints::CompilerLintFunctions::new());
+ store.register_late_pass(|| box utils::internal_lints::IfChainStyle);
+ store.register_late_pass(|| box utils::internal_lints::InvalidPaths);
+ store.register_late_pass(|| box utils::internal_lints::InterningDefinedSymbol::default());
+ store.register_late_pass(|| box utils::internal_lints::LintWithoutLintPass::default());
+ store.register_late_pass(|| box utils::internal_lints::MatchTypeOnDiagItem);
+ store.register_late_pass(|| box utils::internal_lints::OuterExpnDataPass);
+ }
+
+ store.register_late_pass(|| box utils::author::Author);
+ store.register_late_pass(|| box await_holding_invalid::AwaitHolding);
+ store.register_late_pass(|| box serde_api::SerdeApi);
+ let vec_box_size_threshold = conf.vec_box_size_threshold;
+ let type_complexity_threshold = conf.type_complexity_threshold;
+ store.register_late_pass(move || box types::Types::new(vec_box_size_threshold, type_complexity_threshold));
+ store.register_late_pass(|| box booleans::NonminimalBool);
+ store.register_late_pass(|| box needless_bitwise_bool::NeedlessBitwiseBool);
+ store.register_late_pass(|| box eq_op::EqOp);
+ store.register_late_pass(|| box enum_clike::UnportableVariant);
+ store.register_late_pass(|| box float_literal::FloatLiteral);
+ let verbose_bit_mask_threshold = conf.verbose_bit_mask_threshold;
+ store.register_late_pass(move || box bit_mask::BitMask::new(verbose_bit_mask_threshold));
+ store.register_late_pass(|| box ptr::Ptr);
+ store.register_late_pass(|| box ptr_eq::PtrEq);
+ store.register_late_pass(|| box needless_bool::NeedlessBool);
+ store.register_late_pass(|| box needless_bool::BoolComparison);
+ store.register_late_pass(|| box needless_for_each::NeedlessForEach);
+ store.register_late_pass(|| box approx_const::ApproxConstant);
+ store.register_late_pass(|| box misc::MiscLints);
+ store.register_late_pass(|| box eta_reduction::EtaReduction);
+ store.register_late_pass(|| box identity_op::IdentityOp);
+ store.register_late_pass(|| box erasing_op::ErasingOp);
+ store.register_late_pass(|| box mut_mut::MutMut);
+ store.register_late_pass(|| box mut_reference::UnnecessaryMutPassed);
+ store.register_late_pass(|| box len_zero::LenZero);
+ store.register_late_pass(|| box attrs::Attributes);
+ store.register_late_pass(|| box blocks_in_if_conditions::BlocksInIfConditions);
+ store.register_late_pass(|| box collapsible_match::CollapsibleMatch);
+ store.register_late_pass(|| box unicode::Unicode);
+ store.register_late_pass(|| box unit_return_expecting_ord::UnitReturnExpectingOrd);
+ store.register_late_pass(|| box strings::StringAdd);
+ store.register_late_pass(|| box implicit_return::ImplicitReturn);
+ store.register_late_pass(|| box implicit_saturating_sub::ImplicitSaturatingSub);
+ store.register_late_pass(|| box default_numeric_fallback::DefaultNumericFallback);
+ store.register_late_pass(|| box inconsistent_struct_constructor::InconsistentStructConstructor);
+ store.register_late_pass(|| box non_octal_unix_permissions::NonOctalUnixPermissions);
+ store.register_early_pass(|| box unnecessary_self_imports::UnnecessarySelfImports);
+
+ let msrv = conf.msrv.as_ref().and_then(|s| {
+ parse_msrv(s, None, None).or_else(|| {
+ sess.err(&format!("error reading Clippy's configuration file. `{}` is not a valid Rust version", s));
+ None
+ })
+ });
+
+ let avoid_breaking_exported_api = conf.avoid_breaking_exported_api;
+ store.register_late_pass(move || box methods::Methods::new(avoid_breaking_exported_api, msrv));
+ store.register_late_pass(move || box matches::Matches::new(msrv));
+ store.register_early_pass(move || box manual_non_exhaustive::ManualNonExhaustive::new(msrv));
+ store.register_late_pass(move || box manual_strip::ManualStrip::new(msrv));
+ store.register_early_pass(move || box redundant_static_lifetimes::RedundantStaticLifetimes::new(msrv));
+ store.register_early_pass(move || box redundant_field_names::RedundantFieldNames::new(msrv));
+ store.register_late_pass(move || box checked_conversions::CheckedConversions::new(msrv));
+ store.register_late_pass(move || box mem_replace::MemReplace::new(msrv));
+ store.register_late_pass(move || box ranges::Ranges::new(msrv));
+ store.register_late_pass(move || box from_over_into::FromOverInto::new(msrv));
+ store.register_late_pass(move || box use_self::UseSelf::new(msrv));
+ store.register_late_pass(move || box missing_const_for_fn::MissingConstForFn::new(msrv));
+ store.register_late_pass(move || box needless_question_mark::NeedlessQuestionMark);
+ store.register_late_pass(move || box casts::Casts::new(msrv));
+ store.register_early_pass(move || box unnested_or_patterns::UnnestedOrPatterns::new(msrv));
+
+ store.register_late_pass(|| box size_of_in_element_count::SizeOfInElementCount);
+ store.register_late_pass(|| box map_clone::MapClone);
+ store.register_late_pass(|| box map_err_ignore::MapErrIgnore);
+ store.register_late_pass(|| box shadow::Shadow);
+ store.register_late_pass(|| box unit_types::UnitTypes);
+ store.register_late_pass(|| box loops::Loops);
+ store.register_late_pass(|| box main_recursion::MainRecursion::default());
+ store.register_late_pass(|| box lifetimes::Lifetimes);
+ store.register_late_pass(|| box entry::HashMapPass);
+ store.register_late_pass(|| box minmax::MinMaxPass);
+ store.register_late_pass(|| box open_options::OpenOptions);
+ store.register_late_pass(|| box zero_div_zero::ZeroDiv);
+ store.register_late_pass(|| box mutex_atomic::Mutex);
+ store.register_late_pass(|| box needless_update::NeedlessUpdate);
+ store.register_late_pass(|| box needless_borrow::NeedlessBorrow::default());
+ store.register_late_pass(|| box needless_borrowed_ref::NeedlessBorrowedRef);
+ store.register_late_pass(|| box no_effect::NoEffect);
+ store.register_late_pass(|| box temporary_assignment::TemporaryAssignment);
+ store.register_late_pass(|| box transmute::Transmute);
+ let cognitive_complexity_threshold = conf.cognitive_complexity_threshold;
+ store.register_late_pass(move || box cognitive_complexity::CognitiveComplexity::new(cognitive_complexity_threshold));
+ let too_large_for_stack = conf.too_large_for_stack;
+ store.register_late_pass(move || box escape::BoxedLocal{too_large_for_stack});
+ store.register_late_pass(move || box vec::UselessVec{too_large_for_stack});
+ store.register_late_pass(|| box panic_unimplemented::PanicUnimplemented);
+ store.register_late_pass(|| box strings::StringLitAsBytes);
+ store.register_late_pass(|| box derive::Derive);
+ store.register_late_pass(|| box get_last_with_len::GetLastWithLen);
+ store.register_late_pass(|| box drop_forget_ref::DropForgetRef);
+ store.register_late_pass(|| box empty_enum::EmptyEnum);
+ store.register_late_pass(|| box absurd_extreme_comparisons::AbsurdExtremeComparisons);
+ store.register_late_pass(|| box invalid_upcast_comparisons::InvalidUpcastComparisons);
+ store.register_late_pass(|| box regex::Regex::default());
+ store.register_late_pass(|| box copies::CopyAndPaste);
+ store.register_late_pass(|| box copy_iterator::CopyIterator);
+ store.register_late_pass(|| box format::UselessFormat);
+ store.register_late_pass(|| box swap::Swap);
+ store.register_late_pass(|| box overflow_check_conditional::OverflowCheckConditional);
+ store.register_late_pass(|| box new_without_default::NewWithoutDefault::default());
+ let blacklisted_names = conf.blacklisted_names.iter().cloned().collect::<FxHashSet<_>>();
+ store.register_late_pass(move || box blacklisted_name::BlacklistedName::new(blacklisted_names.clone()));
+ let too_many_arguments_threshold = conf.too_many_arguments_threshold;
+ let too_many_lines_threshold = conf.too_many_lines_threshold;
+ store.register_late_pass(move || box functions::Functions::new(too_many_arguments_threshold, too_many_lines_threshold));
+ let doc_valid_idents = conf.doc_valid_idents.iter().cloned().collect::<FxHashSet<_>>();
+ store.register_late_pass(move || box doc::DocMarkdown::new(doc_valid_idents.clone()));
+ store.register_late_pass(|| box neg_multiply::NegMultiply);
+ store.register_late_pass(|| box mem_discriminant::MemDiscriminant);
+ store.register_late_pass(|| box mem_forget::MemForget);
+ store.register_late_pass(|| box arithmetic::Arithmetic::default());
+ store.register_late_pass(|| box assign_ops::AssignOps);
+ store.register_late_pass(|| box let_if_seq::LetIfSeq);
+ store.register_late_pass(|| box eval_order_dependence::EvalOrderDependence);
+ store.register_late_pass(|| box missing_doc::MissingDoc::new());
+ store.register_late_pass(|| box missing_inline::MissingInline);
+ store.register_late_pass(move || box exhaustive_items::ExhaustiveItems);
+ store.register_late_pass(|| box if_let_some_result::OkIfLet);
+ store.register_late_pass(|| box partialeq_ne_impl::PartialEqNeImpl);
+ store.register_late_pass(|| box unused_io_amount::UnusedIoAmount);
+ let enum_variant_size_threshold = conf.enum_variant_size_threshold;
+ store.register_late_pass(move || box large_enum_variant::LargeEnumVariant::new(enum_variant_size_threshold));
+ store.register_late_pass(|| box explicit_write::ExplicitWrite);
+ store.register_late_pass(|| box needless_pass_by_value::NeedlessPassByValue);
+ let pass_by_ref_or_value = pass_by_ref_or_value::PassByRefOrValue::new(
+ conf.trivial_copy_size_limit,
+ conf.pass_by_value_size_limit,
+ conf.avoid_breaking_exported_api,
+ &sess.target,
+ );
+ store.register_late_pass(move || box pass_by_ref_or_value);
+ store.register_late_pass(|| box ref_option_ref::RefOptionRef);
+ store.register_late_pass(|| box try_err::TryErr);
+ store.register_late_pass(|| box bytecount::ByteCount);
+ store.register_late_pass(|| box infinite_iter::InfiniteIter);
+ store.register_late_pass(|| box inline_fn_without_body::InlineFnWithoutBody);
+ store.register_late_pass(|| box useless_conversion::UselessConversion::default());
+ store.register_late_pass(|| box implicit_hasher::ImplicitHasher);
+ store.register_late_pass(|| box fallible_impl_from::FallibleImplFrom);
+ store.register_late_pass(|| box double_comparison::DoubleComparisons);
+ store.register_late_pass(|| box question_mark::QuestionMark);
+ store.register_early_pass(|| box suspicious_operation_groupings::SuspiciousOperationGroupings);
+ store.register_late_pass(|| box suspicious_trait_impl::SuspiciousImpl);
+ store.register_late_pass(|| box map_unit_fn::MapUnit);
+ store.register_late_pass(|| box inherent_impl::MultipleInherentImpl);
+ store.register_late_pass(|| box neg_cmp_op_on_partial_ord::NoNegCompOpForPartialOrd);
+ store.register_late_pass(|| box unwrap::Unwrap);
+ store.register_late_pass(|| box duration_subsec::DurationSubsec);
+ store.register_late_pass(|| box indexing_slicing::IndexingSlicing);
+ store.register_late_pass(|| box non_copy_const::NonCopyConst);
+ store.register_late_pass(|| box ptr_offset_with_cast::PtrOffsetWithCast);
+ store.register_late_pass(|| box redundant_clone::RedundantClone);
+ store.register_late_pass(|| box slow_vector_initialization::SlowVectorInit);
+ store.register_late_pass(|| box unnecessary_sort_by::UnnecessarySortBy);
+ store.register_late_pass(move || box unnecessary_wraps::UnnecessaryWraps::new(avoid_breaking_exported_api));
+ store.register_late_pass(|| box assertions_on_constants::AssertionsOnConstants);
+ store.register_late_pass(|| box transmuting_null::TransmutingNull);
+ store.register_late_pass(|| box path_buf_push_overwrite::PathBufPushOverwrite);
+ store.register_late_pass(|| box integer_division::IntegerDivision);
+ store.register_late_pass(|| box inherent_to_string::InherentToString);
+ let max_trait_bounds = conf.max_trait_bounds;
+ store.register_late_pass(move || box trait_bounds::TraitBounds::new(max_trait_bounds));
+ store.register_late_pass(|| box comparison_chain::ComparisonChain);
+ store.register_late_pass(|| box mut_key::MutableKeyType);
+ store.register_late_pass(|| box modulo_arithmetic::ModuloArithmetic);
+ store.register_early_pass(|| box reference::DerefAddrOf);
+ store.register_early_pass(|| box reference::RefInDeref);
+ store.register_early_pass(|| box double_parens::DoubleParens);
+ store.register_late_pass(|| box to_string_in_display::ToStringInDisplay::new());
+ store.register_early_pass(|| box unsafe_removed_from_name::UnsafeNameRemoval);
+ store.register_early_pass(|| box if_not_else::IfNotElse);
+ store.register_early_pass(|| box else_if_without_else::ElseIfWithoutElse);
+ store.register_early_pass(|| box int_plus_one::IntPlusOne);
+ store.register_early_pass(|| box formatting::Formatting);
+ store.register_early_pass(|| box misc_early::MiscEarlyLints);
+ store.register_early_pass(|| box redundant_closure_call::RedundantClosureCall);
+ store.register_late_pass(|| box redundant_closure_call::RedundantClosureCall);
+ store.register_early_pass(|| box unused_unit::UnusedUnit);
+ store.register_late_pass(|| box returns::Return);
+ store.register_early_pass(|| box collapsible_if::CollapsibleIf);
+ store.register_early_pass(|| box items_after_statements::ItemsAfterStatements);
+ store.register_early_pass(|| box precedence::Precedence);
+ store.register_early_pass(|| box needless_continue::NeedlessContinue);
+ store.register_early_pass(|| box redundant_else::RedundantElse);
+ store.register_late_pass(|| box create_dir::CreateDir);
+ store.register_early_pass(|| box needless_arbitrary_self_type::NeedlessArbitrarySelfType);
+ let cargo_ignore_publish = conf.cargo_ignore_publish;
+ store.register_late_pass(move || box cargo_common_metadata::CargoCommonMetadata::new(cargo_ignore_publish));
+ store.register_late_pass(|| box multiple_crate_versions::MultipleCrateVersions);
+ store.register_late_pass(|| box wildcard_dependencies::WildcardDependencies);
+ let literal_representation_lint_fraction_readability = conf.unreadable_literal_lint_fractions;
+ store.register_early_pass(move || box literal_representation::LiteralDigitGrouping::new(literal_representation_lint_fraction_readability));
+ let literal_representation_threshold = conf.literal_representation_threshold;
+ store.register_early_pass(move || box literal_representation::DecimalLiteralRepresentation::new(literal_representation_threshold));
+ let enum_variant_name_threshold = conf.enum_variant_name_threshold;
+ store.register_late_pass(move || box enum_variants::EnumVariantNames::new(enum_variant_name_threshold, avoid_breaking_exported_api));
+ store.register_early_pass(|| box tabs_in_doc_comments::TabsInDocComments);
+ let upper_case_acronyms_aggressive = conf.upper_case_acronyms_aggressive;
+ store.register_late_pass(move || box upper_case_acronyms::UpperCaseAcronyms::new(avoid_breaking_exported_api, upper_case_acronyms_aggressive));
+ store.register_late_pass(|| box default::Default::default());
+ store.register_late_pass(|| box unused_self::UnusedSelf);
+ store.register_late_pass(|| box mutable_debug_assertion::DebugAssertWithMutCall);
+ store.register_late_pass(|| box exit::Exit);
+ store.register_late_pass(|| box to_digit_is_some::ToDigitIsSome);
+ let array_size_threshold = conf.array_size_threshold;
+ store.register_late_pass(move || box large_stack_arrays::LargeStackArrays::new(array_size_threshold));
+ store.register_late_pass(move || box large_const_arrays::LargeConstArrays::new(array_size_threshold));
+ store.register_late_pass(|| box floating_point_arithmetic::FloatingPointArithmetic);
+ store.register_early_pass(|| box as_conversions::AsConversions);
+ store.register_late_pass(|| box let_underscore::LetUnderscore);
+ store.register_late_pass(|| box atomic_ordering::AtomicOrdering);
+ store.register_early_pass(|| box single_component_path_imports::SingleComponentPathImports);
+ let max_fn_params_bools = conf.max_fn_params_bools;
+ let max_struct_bools = conf.max_struct_bools;
+ store.register_early_pass(move || box excessive_bools::ExcessiveBools::new(max_struct_bools, max_fn_params_bools));
+ store.register_early_pass(|| box option_env_unwrap::OptionEnvUnwrap);
+ let warn_on_all_wildcard_imports = conf.warn_on_all_wildcard_imports;
+ store.register_late_pass(move || box wildcard_imports::WildcardImports::new(warn_on_all_wildcard_imports));
+ store.register_late_pass(|| box verbose_file_reads::VerboseFileReads);
+ store.register_late_pass(|| box redundant_pub_crate::RedundantPubCrate::default());
+ store.register_late_pass(|| box unnamed_address::UnnamedAddress);
+ store.register_late_pass(|| box dereference::Dereferencing::default());
+ store.register_late_pass(|| box option_if_let_else::OptionIfLetElse);
+ store.register_late_pass(|| box future_not_send::FutureNotSend);
+ store.register_late_pass(|| box if_let_mutex::IfLetMutex);
+ store.register_late_pass(|| box mut_mutex_lock::MutMutexLock);
+ store.register_late_pass(|| box match_on_vec_items::MatchOnVecItems);
+ store.register_late_pass(|| box manual_async_fn::ManualAsyncFn);
+ store.register_late_pass(|| box vec_resize_to_zero::VecResizeToZero);
+ store.register_late_pass(|| box panic_in_result_fn::PanicInResultFn);
+ let single_char_binding_names_threshold = conf.single_char_binding_names_threshold;
+ store.register_early_pass(move || box non_expressive_names::NonExpressiveNames {
+ single_char_binding_names_threshold,
+ });
+ store.register_late_pass(|| box macro_use::MacroUseImports::default());
+ store.register_late_pass(|| box map_identity::MapIdentity);
+ store.register_late_pass(|| box pattern_type_mismatch::PatternTypeMismatch);
+ store.register_late_pass(|| box stable_sort_primitive::StableSortPrimitive);
+ store.register_late_pass(|| box repeat_once::RepeatOnce);
+ store.register_late_pass(|| box unwrap_in_result::UnwrapInResult);
+ store.register_late_pass(|| box self_assignment::SelfAssignment);
+ store.register_late_pass(|| box manual_unwrap_or::ManualUnwrapOr);
+ store.register_late_pass(|| box manual_ok_or::ManualOkOr);
+ store.register_late_pass(|| box float_equality_without_abs::FloatEqualityWithoutAbs);
+ store.register_late_pass(|| box semicolon_if_nothing_returned::SemicolonIfNothingReturned);
+ store.register_late_pass(|| box async_yields_async::AsyncYieldsAsync);
+ let disallowed_methods = conf.disallowed_methods.iter().cloned().collect::<FxHashSet<_>>();
+ store.register_late_pass(move || box disallowed_method::DisallowedMethod::new(&disallowed_methods));
+ store.register_early_pass(|| box asm_syntax::InlineAsmX86AttSyntax);
+ store.register_early_pass(|| box asm_syntax::InlineAsmX86IntelSyntax);
+ store.register_late_pass(|| box undropped_manually_drops::UndroppedManuallyDrops);
+ store.register_late_pass(|| box strings::StrToString);
+ store.register_late_pass(|| box strings::StringToString);
+ store.register_late_pass(|| box zero_sized_map_values::ZeroSizedMapValues);
+ store.register_late_pass(|| box vec_init_then_push::VecInitThenPush::default());
+ store.register_late_pass(|| box case_sensitive_file_extension_comparisons::CaseSensitiveFileExtensionComparisons);
+ store.register_late_pass(|| box redundant_slicing::RedundantSlicing);
+ store.register_late_pass(|| box from_str_radix_10::FromStrRadix10);
+ store.register_late_pass(|| box manual_map::ManualMap);
+ store.register_late_pass(move || box if_then_some_else_none::IfThenSomeElseNone::new(msrv));
+ store.register_early_pass(|| box bool_assert_comparison::BoolAssertComparison);
+ store.register_late_pass(|| box unused_async::UnusedAsync);
- store.register_group(true, "clippy::nursery", Some("clippy_nursery"), vec![
- LintId::of(attrs::EMPTY_LINE_AFTER_OUTER_ATTR),
- LintId::of(cognitive_complexity::COGNITIVE_COMPLEXITY),
- LintId::of(disallowed_method::DISALLOWED_METHOD),
- LintId::of(fallible_impl_from::FALLIBLE_IMPL_FROM),
- LintId::of(floating_point_arithmetic::IMPRECISE_FLOPS),
- LintId::of(floating_point_arithmetic::SUBOPTIMAL_FLOPS),
- LintId::of(future_not_send::FUTURE_NOT_SEND),
- LintId::of(let_if_seq::USELESS_LET_IF_SEQ),
- LintId::of(missing_const_for_fn::MISSING_CONST_FOR_FN),
- LintId::of(mutable_debug_assertion::DEBUG_ASSERT_WITH_MUT_CALL),
- LintId::of(mutex_atomic::MUTEX_INTEGER),
- LintId::of(needless_borrow::NEEDLESS_BORROW),
- LintId::of(path_buf_push_overwrite::PATH_BUF_PUSH_OVERWRITE),
- LintId::of(redundant_pub_crate::REDUNDANT_PUB_CRATE),
- LintId::of(regex::TRIVIAL_REGEX),
- LintId::of(strings::STRING_LIT_AS_BYTES),
- LintId::of(transmute::USELESS_TRANSMUTE),
- LintId::of(use_self::USE_SELF),
- ]);
}
#[rustfmt::skip]
output_visitor.visit_ty(ty);
}
for lt in named_generics {
- input_visitor.visit_generic_param(lt)
+ input_visitor.visit_generic_param(lt);
}
if input_visitor.abort() || output_visitor.abort() {
// `'b` in `'a: 'b` is useless unless used elsewhere in
// a non-lifetime bound
if let GenericParamKind::Type { .. } = param.kind {
- walk_generic_param(self, param)
+ walk_generic_param(self, param);
}
}
fn nested_visit_map(&mut self) -> NestedVisitorMap<Self::Map> {
}
if let ExprKind::Lit(ref lit) = expr.kind {
- self.check_lit(cx, lit)
+ self.check_lit(cx, lit);
}
}
}
}
};
if should_warn {
- warning_type.display(num_lit.format(), cx, lit.span)
+ warning_type.display(num_lit.format(), cx, lit.span);
}
}
}
}
if let ExprKind::Lit(ref lit) = expr.kind {
- self.check_lit(cx, lit)
+ self.check_lit(cx, lit);
}
}
}
let hex = format!("{:#X}", val);
let num_lit = NumericLiteral::new(&hex, num_lit.suffix, false);
let _ = Self::do_lint(num_lit.integer).map_err(|warning_type| {
- warning_type.display(num_lit.format(), cx, lit.span)
+ warning_type.display(num_lit.format(), cx, lit.span);
});
}
}
"to write this more concisely, try",
format!("&{}{}", muta, object),
applicability,
- )
+ );
}
/// Returns `true` if the type of expr is one that provides `IntoIterator` impls
if let ty::BorrowKind::MutBorrow = bk {
if let PlaceBase::Local(id) = cmt.place.base {
if Some(id) == self.hir_id_low {
- self.span_low = Some(self.cx.tcx.hir().span(diag_expr_id))
+ self.span_low = Some(self.cx.tcx.hir().span(diag_expr_id));
}
if Some(id) == self.hir_id_high {
- self.span_high = Some(self.cx.tcx.hir().span(diag_expr_id))
+ self.span_high = Some(self.cx.tcx.hir().span(diag_expr_id));
}
}
}
fn mutate(&mut self, cmt: &PlaceWithHirId<'tcx>, diag_expr_id: HirId) {
if let PlaceBase::Local(id) = cmt.place.base {
if Some(id) == self.hir_id_low {
- self.span_low = Some(self.cx.tcx.hir().span(diag_expr_id))
+ self.span_low = Some(self.cx.tcx.hir().span(diag_expr_id));
}
if Some(id) == self.hir_id_high {
- self.span_high = Some(self.cx.tcx.hir().span(diag_expr_id))
+ self.span_high = Some(self.cx.tcx.hir().span(diag_expr_id));
}
}
}
use super::NEEDLESS_COLLECT;
-use clippy_utils::diagnostics::{span_lint_and_sugg, span_lint_and_then};
+use clippy_utils::diagnostics::{span_lint_and_sugg, span_lint_hir_and_then};
use clippy_utils::source::{snippet, snippet_with_applicability};
use clippy_utils::sugg::Sugg;
use clippy_utils::ty::is_type_diagnostic_item;
// Suggest replacing iter_call with iter_replacement, and removing stmt
let mut span = MultiSpan::from_span(collect_span);
span.push_span_label(iter_call.span, "the iterator could be used here instead".into());
- span_lint_and_then(
+ span_lint_hir_and_then(
cx,
super::NEEDLESS_COLLECT,
+ init_expr.hir_id,
span,
NEEDLESS_COLLECT_MSG,
|diag| {
"try using vec![{};SIZE] or {}.resize(NEW_SIZE, {})",
item_str, vec_str, item_str
),
- )
+ );
}
if !matches!(pat.kind, PatKind::Wild) {
}
},
ExprKind::Assign(lhs, _, _) if lhs.hir_id == expr.hir_id => {
- *state = IncrementVisitorVarState::DontWarn
+ *state = IncrementVisitorVarState::DontWarn;
},
ExprKind::AddrOf(BorrowKind::Ref, mutability, _) if mutability == Mutability::Mut => {
- *state = IncrementVisitorVarState::DontWarn
+ *state = IncrementVisitorVarState::DontWarn;
},
_ => (),
}
}
},
ExprKind::AddrOf(BorrowKind::Ref, mutability, _) if mutability == Mutability::Mut => {
- self.state = InitializeVisitorState::DontWarn
+ self.state = InitializeVisitorState::DontWarn;
},
_ => (),
}
return;
}
}
- walk_pat(self, pat)
+ walk_pat(self, pat);
}
fn nested_visit_map(&mut self) -> NestedVisitorMap<Self::Map> {
use super::WHILE_IMMUTABLE_CONDITION;
-use crate::consts::constant;
+use clippy_utils::consts::constant;
use clippy_utils::diagnostics::span_lint_and_then;
use clippy_utils::usage::mutated_variables;
use if_chain::if_chain;
let mut suggestions = vec![];
for ((root, span), path) in used {
if path.len() == 1 {
- suggestions.push((span, format!("{}::{}", root, path[0])))
+ suggestions.push((span, format!("{}::{}", root, path[0])));
} else {
- suggestions.push((span, format!("{}::{{{}}}", root, path.join(", "))))
+ suggestions.push((span, format!("{}::{{{}}}", root, path.join(", "))));
}
}
"remove the attribute and import the macro directly, try",
help,
Applicability::MaybeIncorrect,
- )
+ );
}
}
}
-use crate::consts::{constant, Constant};
+use clippy_utils::consts::{constant, Constant};
use clippy_utils::diagnostics::{multispan_sugg, span_lint_and_then};
use clippy_utils::source::snippet;
use clippy_utils::usage::mutated_variables;
kind_word,
snippet(cx, pattern.span, "..")))]
.into_iter().chain(strippings.into_iter().map(|span| (span, "<stripped>".into()))),
- )
+ );
});
}
}
-use crate::consts::constant_simple;
+use clippy_utils::consts::constant_simple;
use clippy_utils::diagnostics::span_lint_and_sugg;
use clippy_utils::source::{indent_of, reindent_multiline, snippet_opt};
use clippy_utils::ty::is_type_diagnostic_item;
"remove the `map` call",
String::new(),
Applicability::MachineApplicable,
- )
+ );
}
fn lint(cx: &LateContext<'_>, replace: Span, root: Span, copied: bool) {
snippet_with_applicability(cx, root, "..", &mut applicability)
),
applicability,
- )
+ );
} else {
span_lint_and_sugg(
cx,
snippet_with_applicability(cx, root, "..", &mut applicability)
),
applicability,
- )
+ );
}
}
-use crate::consts::{constant, miri_to_const, Constant};
+use clippy_utils::consts::{constant, miri_to_const, Constant};
use clippy_utils::diagnostics::{
multispan_sugg, span_lint_and_help, span_lint_and_note, span_lint_and_sugg, span_lint_and_then,
};
"try this",
suggestions.join(" | "),
Applicability::MaybeIncorrect,
- )
+ );
},
};
}
cast,
),
applicability,
- )
+ );
}
}
}
"consider using the scrutinee and body instead",
sugg,
applicability,
- )
+ );
} else {
span_lint_and_sugg(
cx,
match match_source {
MatchSource::Normal => find_sugg_for_match(cx, expr, op, arms),
MatchSource::IfLetDesugar { contains_else_clause } => {
- find_sugg_for_if_let(cx, expr, op, &arms[0], "if", *contains_else_clause)
+ find_sugg_for_if_let(cx, expr, op, &arms[0], "if", *contains_else_clause);
},
MatchSource::WhileLetDesugar => find_sugg_for_if_let(cx, expr, op, &arms[0], "while", false),
_ => {},
{
self.res = true;
} else {
- self.visit_expr(self_arg)
+ self.visit_expr(self_arg);
}
}
args.iter().for_each(|arg| self.visit_expr(arg));
use rustc_hir::{BorrowKind, Expr, ExprKind};
use rustc_lint::{LateContext, LateLintPass};
use rustc_session::{declare_lint_pass, declare_tool_lint};
-use std::iter;
declare_clippy_lint! {
/// **What it does:** Checks for calls of `mem::discriminant()` on a non-enum type.
}
}
- let derefs: String = iter::repeat('*').take(derefs_needed).collect();
+ let derefs = "*".repeat(derefs_needed);
diag.span_suggestion(
param.span,
"try dereferencing",
.into_iter()
.map(|(span1, span2)| (span1, snippet(cx, span2, "_").into())),
),
- )
+ );
});
true
}
use rustc_lint::LateContext;
use rustc_middle::ty::{self, adjustment::Adjust};
use rustc_span::symbol::{sym, Symbol};
-use std::iter;
use super::CLONE_DOUBLE_REF;
use super::CLONE_ON_COPY;
ty = inner;
n += 1;
}
- let refs: String = iter::repeat('&').take(n + 1).collect();
- let derefs: String = iter::repeat('*').take(n).collect();
+ let refs = "&".repeat(n + 1);
+ let derefs = "*".repeat(n);
let explicit = format!("<{}{}>::clone({})", refs, ty, snip);
diag.span_suggestion(
expr.span,
"try",
"copied".into(),
Applicability::MachineApplicable,
- )
+ );
}
"try",
"filter_map".into(),
Applicability::MachineApplicable,
- )
+ );
}
}
fn extract_turbofish(cx: &LateContext<'_>, expr: &hir::Expr<'_>, ty: Ty<'tcx>) -> String {
+ fn strip_angle_brackets(s: &str) -> Option<&str> {
+ s.strip_prefix('<')?.strip_suffix('>')
+ }
+
let call_site = expr.span.source_callsite();
if_chain! {
if let Ok(snippet) = cx.sess().source_map().span_to_snippet(call_site);
if let Some((_, elements)) = snippet_split.split_last();
then {
- // is there a type specifier? (i.e.: like `<u32>` in `collections::BTreeSet::<u32>::`)
- if let Some(type_specifier) = snippet_split.iter().find(|e| e.starts_with('<') && e.ends_with('>')) {
- // remove the type specifier from the path elements
- let without_ts = elements.iter().filter_map(|e| {
- if e == type_specifier { None } else { Some((*e).to_string()) }
- }).collect::<Vec<_>>();
- // join and add the type specifier at the end (i.e.: `collections::BTreeSet<u32>`)
- format!("{}{}", without_ts.join("::"), type_specifier)
- } else {
- // type is not explicitly specified so wildcards are needed
- // i.e.: 2 wildcards in `std::collections::BTreeMap<&i32, &char>`
- let ty_str = ty.to_string();
- let start = ty_str.find('<').unwrap_or(0);
- let end = ty_str.find('>').unwrap_or_else(|| ty_str.len());
- let nb_wildcard = ty_str[start..end].split(',').count();
- let wildcards = format!("_{}", ", _".repeat(nb_wildcard - 1));
- format!("{}<{}>", elements.join("::"), wildcards)
+ if_chain! {
+ if let [type_specifier, _] = snippet_split.as_slice();
+ if let Some(type_specifier) = strip_angle_brackets(type_specifier);
+ if let Some((type_specifier, ..)) = type_specifier.split_once(" as ");
+ then {
+ type_specifier.to_string()
+ } else {
+ // is there a type specifier? (i.e.: like `<u32>` in `collections::BTreeSet::<u32>::`)
+ if let Some(type_specifier) = snippet_split.iter().find(|e| strip_angle_brackets(e).is_some()) {
+ // remove the type specifier from the path elements
+ let without_ts = elements.iter().filter_map(|e| {
+ if e == type_specifier { None } else { Some((*e).to_string()) }
+ }).collect::<Vec<_>>();
+ // join and add the type specifier at the end (i.e.: `collections::BTreeSet<u32>`)
+ format!("{}{}", without_ts.join("::"), type_specifier)
+ } else {
+ // type is not explicitly specified so wildcards are needed
+ // i.e.: 2 wildcards in `std::collections::BTreeMap<&i32, &char>`
+ let ty_str = ty.to_string();
+ let start = ty_str.find('<').unwrap_or(0);
+ let end = ty_str.find('>').unwrap_or_else(|| ty_str.len());
+ let nb_wildcard = ty_str[start..end].split(',').count();
+ let wildcards = format!("_{}", ", _".repeat(nb_wildcard - 1));
+ format!("{}<{}>", elements.join("::"), wildcards)
+ }
+ }
}
} else {
ty.to_string()
-use crate::consts::{constant, Constant};
+use clippy_utils::consts::{constant, Constant};
use clippy_utils::diagnostics::span_lint_and_sugg;
use clippy_utils::is_trait_method;
use clippy_utils::source::snippet_with_applicability;
-use crate::consts::{constant, Constant};
+use clippy_utils::consts::{constant, Constant};
use clippy_utils::diagnostics::span_lint;
use clippy_utils::is_trait_method;
use rustc_hir as hir;
--- /dev/null
+use clippy_utils::diagnostics::span_lint_and_sugg;
+use clippy_utils::source::{snippet_with_applicability, snippet_with_context};
+use clippy_utils::sugg::Sugg;
+use clippy_utils::ty::{is_type_diagnostic_item, is_type_lang_item, match_type};
+use clippy_utils::{is_expr_path_def_path, paths};
+use if_chain::if_chain;
+use rustc_ast::LitKind;
+use rustc_errors::Applicability;
+use rustc_hir::{Expr, ExprKind, LangItem};
+use rustc_lint::LateContext;
+use rustc_middle::ty::{self, Ty, TyS};
+use rustc_span::symbol::sym;
+use std::borrow::Cow;
+
+use super::MANUAL_STR_REPEAT;
+
+enum RepeatKind {
+ String,
+ Char(char),
+}
+
+fn get_ty_param(ty: Ty<'_>) -> Option<Ty<'_>> {
+ if let ty::Adt(_, subs) = ty.kind() {
+ subs.types().next()
+ } else {
+ None
+ }
+}
+
+fn parse_repeat_arg(cx: &LateContext<'_>, e: &Expr<'_>) -> Option<RepeatKind> {
+ if let ExprKind::Lit(lit) = &e.kind {
+ match lit.node {
+ LitKind::Str(..) => Some(RepeatKind::String),
+ LitKind::Char(c) => Some(RepeatKind::Char(c)),
+ _ => None,
+ }
+ } else {
+ let ty = cx.typeck_results().expr_ty(e);
+ if is_type_diagnostic_item(cx, ty, sym::string_type)
+ || (is_type_lang_item(cx, ty, LangItem::OwnedBox) && get_ty_param(ty).map_or(false, TyS::is_str))
+ || (match_type(cx, ty, &paths::COW) && get_ty_param(ty).map_or(false, TyS::is_str))
+ {
+ Some(RepeatKind::String)
+ } else {
+ let ty = ty.peel_refs();
+ (ty.is_str() || is_type_diagnostic_item(cx, ty, sym::string_type)).then(|| RepeatKind::String)
+ }
+ }
+}
+
+pub(super) fn check(
+ cx: &LateContext<'_>,
+ collect_expr: &Expr<'_>,
+ take_expr: &Expr<'_>,
+ take_self_arg: &Expr<'_>,
+ take_arg: &Expr<'_>,
+) {
+ if_chain! {
+ if let ExprKind::Call(repeat_fn, [repeat_arg]) = take_self_arg.kind;
+ if is_expr_path_def_path(cx, repeat_fn, &paths::ITER_REPEAT);
+ if is_type_diagnostic_item(cx, cx.typeck_results().expr_ty(collect_expr), sym::string_type);
+ if let Some(collect_id) = cx.typeck_results().type_dependent_def_id(collect_expr.hir_id);
+ if let Some(take_id) = cx.typeck_results().type_dependent_def_id(take_expr.hir_id);
+ if let Some(iter_trait_id) = cx.tcx.get_diagnostic_item(sym::Iterator);
+ if cx.tcx.trait_of_item(collect_id) == Some(iter_trait_id);
+ if cx.tcx.trait_of_item(take_id) == Some(iter_trait_id);
+ if let Some(repeat_kind) = parse_repeat_arg(cx, repeat_arg);
+ let ctxt = collect_expr.span.ctxt();
+ if ctxt == take_expr.span.ctxt();
+ if ctxt == take_self_arg.span.ctxt();
+ then {
+ let mut app = Applicability::MachineApplicable;
+ let count_snip = snippet_with_context(cx, take_arg.span, ctxt, "..", &mut app).0;
+
+ let val_str = match repeat_kind {
+ RepeatKind::Char(_) if repeat_arg.span.ctxt() != ctxt => return,
+ RepeatKind::Char('\'') => r#""'""#.into(),
+ RepeatKind::Char('"') => r#""\"""#.into(),
+ RepeatKind::Char(_) =>
+ match snippet_with_applicability(cx, repeat_arg.span, "..", &mut app) {
+ Cow::Owned(s) => Cow::Owned(format!("\"{}\"", &s[1..s.len() - 1])),
+ s @ Cow::Borrowed(_) => s,
+ },
+ RepeatKind::String =>
+ Sugg::hir_with_context(cx, repeat_arg, ctxt, "..", &mut app).maybe_par().to_string().into(),
+ };
+
+ span_lint_and_sugg(
+ cx,
+ MANUAL_STR_REPEAT,
+ collect_expr.span,
+ "manual implementation of `str::repeat` using iterators",
+ "try this",
+ format!("{}.repeat({})", val_str, count_snip),
+ app
+ )
+ }
+ }
+}
mod iter_skip_next;
mod iterator_step_by_zero;
mod manual_saturating_arithmetic;
+mod manual_str_repeat;
mod map_collect_result_unit;
mod map_flatten;
mod map_unwrap_or;
mod skip_while_next;
mod string_extend_chars;
mod suspicious_map;
+mod suspicious_splitn;
mod uninit_assumed_init;
mod unnecessary_filter_map;
mod unnecessary_fold;
use bind_instead_of_map::BindInsteadOfMap;
use clippy_utils::diagnostics::{span_lint, span_lint_and_help};
use clippy_utils::ty::{contains_adt_constructor, contains_ty, implements_trait, is_copy, is_type_diagnostic_item};
-use clippy_utils::{contains_return, get_trait_def_id, in_macro, iter_input_pats, paths, return_ty};
+use clippy_utils::{contains_return, get_trait_def_id, in_macro, iter_input_pats, meets_msrv, msrvs, paths, return_ty};
use if_chain::if_chain;
use rustc_hir as hir;
use rustc_hir::def::Res;
"defining a method named with an established prefix (like \"into_\") that takes `self` with the wrong convention"
}
-declare_clippy_lint! {
- /// **What it does:** This is the same as
- /// [`wrong_self_convention`](#wrong_self_convention), but for public items.
- ///
- /// **Why is this bad?** See [`wrong_self_convention`](#wrong_self_convention).
- ///
- /// **Known problems:** Actually *renaming* the function may break clients if
- /// the function is part of the public interface. In that case, be mindful of
- /// the stability guarantees you've given your users.
- ///
- /// **Example:**
- /// ```rust
- /// # struct X;
- /// impl<'a> X {
- /// pub fn as_str(self) -> &'a str {
- /// "foo"
- /// }
- /// }
- /// ```
- pub WRONG_PUB_SELF_CONVENTION,
- restriction,
- "defining a public method named with an established prefix (like \"into_\") that takes `self` with the wrong convention"
-}
-
declare_clippy_lint! {
/// **What it does:** Checks for usage of `ok().expect(..)`.
///
"replace `.iter().count()` with `.len()`"
}
+declare_clippy_lint! {
+ /// **What it does:** Checks for calls to [`splitn`]
+ /// (https://doc.rust-lang.org/std/primitive.str.html#method.splitn) and
+ /// related functions with either zero or one splits.
+ ///
+ /// **Why is this bad?** These calls don't actually split the value and are
+ /// likely to be intended as a different number.
+ ///
+ /// **Known problems:** None.
+ ///
+ /// **Example:**
+ ///
+ /// ```rust
+ /// // Bad
+ /// let s = "";
+ /// for x in s.splitn(1, ":") {
+ /// // use x
+ /// }
+ ///
+ /// // Good
+ /// let s = "";
+ /// for x in s.splitn(2, ":") {
+ /// // use x
+ /// }
+ /// ```
+ pub SUSPICIOUS_SPLITN,
+ correctness,
+ "checks for `.splitn(0, ..)` and `.splitn(1, ..)`"
+}
+
+declare_clippy_lint! {
+ /// **What it does:** Checks for manual implementations of `str::repeat`
+ ///
+ /// **Why is this bad?** These are both harder to read, as well as less performant.
+ ///
+ /// **Known problems:** None.
+ ///
+ /// **Example:**
+ ///
+ /// ```rust
+ /// // Bad
+ /// let x: String = std::iter::repeat('x').take(10).collect();
+ ///
+ /// // Good
+ /// let x: String = "x".repeat(10);
+ /// ```
+ pub MANUAL_STR_REPEAT,
+ perf,
+ "manual implementation of `str::repeat`"
+}
+
pub struct Methods {
+ avoid_breaking_exported_api: bool,
msrv: Option<RustcVersion>,
}
impl Methods {
#[must_use]
- pub fn new(msrv: Option<RustcVersion>) -> Self {
- Self { msrv }
+ pub fn new(avoid_breaking_exported_api: bool, msrv: Option<RustcVersion>) -> Self {
+ Self {
+ avoid_breaking_exported_api,
+ msrv,
+ }
}
}
EXPECT_USED,
SHOULD_IMPLEMENT_TRAIT,
WRONG_SELF_CONVENTION,
- WRONG_PUB_SELF_CONVENTION,
OK_EXPECT,
MAP_UNWRAP_OR,
RESULT_MAP_OR_INTO_OPTION,
MAP_COLLECT_RESULT_UNIT,
FROM_ITER_INSTEAD_OF_COLLECT,
INSPECT_FOR_EACH,
- IMPLICIT_CLONE
+ IMPLICIT_CLONE,
+ SUSPICIOUS_SPLITN,
+ MANUAL_STR_REPEAT
]);
/// Extracts a method call name, args, and `Span` of the method name.
}
}
- if sig.decl.implicit_self.has_implicit_self() {
+ if sig.decl.implicit_self.has_implicit_self()
+ && !(self.avoid_breaking_exported_api
+ && cx.access_levels.is_exported(impl_item.hir_id()))
+ {
wrong_self_convention::check(
cx,
&name,
- item.vis.node.is_pub(),
self_ty,
first_arg_ty,
first_arg.pat.span,
wrong_self_convention::check(
cx,
&item.ident.name.as_str(),
- false,
self_ty,
first_arg_ty,
first_arg_span,
if let Some((name, [recv, args @ ..], span)) = method_call!(expr) {
match (name, args) {
("add" | "offset" | "sub" | "wrapping_offset" | "wrapping_add" | "wrapping_sub", [recv, _]) => {
- zst_offset::check(cx, expr, recv)
+ zst_offset::check(cx, expr, recv);
},
("and_then", [arg]) => {
let biom_option_linted = bind_instead_of_map::OptionAndThenSome::check(cx, expr, recv, arg);
Some(("map", [m_recv, m_arg], _)) => {
map_collect_result_unit::check(cx, expr, m_recv, m_arg, recv);
},
+ Some(("take", [take_self_arg, take_arg], _)) => {
+ if meets_msrv(msrv, &msrvs::STR_REPEAT) {
+ manual_str_repeat::check(cx, expr, recv, take_self_arg, take_arg);
+ }
+ },
_ => {},
},
("count", []) => match method_call!(recv) {
("as_mut", []) => option_as_ref_deref::check(cx, expr, recv2, m_arg, true, msrv),
("as_ref", []) => option_as_ref_deref::check(cx, expr, recv2, m_arg, false, msrv),
("filter", [f_arg]) => {
- filter_map::check(cx, expr, recv2, f_arg, span2, recv, m_arg, span, false)
+ filter_map::check(cx, expr, recv2, f_arg, span2, recv, m_arg, span, false);
},
("find", [f_arg]) => filter_map::check(cx, expr, recv2, f_arg, span2, recv, m_arg, span, true),
_ => {},
unnecessary_lazy_eval::check(cx, expr, recv, arg, "or");
}
},
+ ("splitn" | "splitn_mut" | "rsplitn" | "rsplitn_mut", [count_arg, _]) => {
+ suspicious_splitn::check(cx, name, expr, recv, count_arg);
+ },
("step_by", [arg]) => iterator_step_by_zero::check(cx, expr, arg),
("to_os_string" | "to_owned" | "to_path_buf" | "to_vec", []) => {
implicit_clone::check(cx, name, expr, recv, span);
manual_saturating_arithmetic::check(cx, expr, lhs, rhs, u_arg, &arith["checked_".len()..]);
},
Some(("map", [m_recv, m_arg], span)) => {
- option_map_unwrap_or::check(cx, expr, m_recv, m_arg, recv, u_arg, span)
+ option_map_unwrap_or::check(cx, expr, m_recv, m_arg, recv, u_arg, span);
},
_ => {},
},
fn check_is_some_is_none(cx: &LateContext<'_>, expr: &Expr<'_>, recv: &Expr<'_>, is_some: bool) {
if let Some((name @ ("find" | "position" | "rposition"), [f_recv, arg], span)) = method_call!(recv) {
- search_is_some::check(cx, expr, name, is_some, f_recv, arg, recv, span)
+ search_is_some::check(cx, expr, name, is_some, f_recv, arg, recv, span);
}
}
--- /dev/null
+use clippy_utils::consts::{constant, Constant};
+use clippy_utils::diagnostics::span_lint_and_note;
+use if_chain::if_chain;
+use rustc_ast::LitKind;
+use rustc_hir::{Expr, ExprKind};
+use rustc_lint::LateContext;
+use rustc_span::source_map::Spanned;
+
+use super::SUSPICIOUS_SPLITN;
+
+pub(super) fn check(
+ cx: &LateContext<'_>,
+ method_name: &str,
+ expr: &Expr<'_>,
+ self_arg: &Expr<'_>,
+ count_arg: &Expr<'_>,
+) {
+ if_chain! {
+ if let Some((Constant::Int(count), _)) = constant(cx, cx.typeck_results(), count_arg);
+ if count <= 1;
+ if let Some(call_id) = cx.typeck_results().type_dependent_def_id(expr.hir_id);
+ if let Some(impl_id) = cx.tcx.impl_of_method(call_id);
+ let lang_items = cx.tcx.lang_items();
+ if lang_items.slice_impl() == Some(impl_id) || lang_items.str_impl() == Some(impl_id);
+ then {
+ // Ignore empty slice and string literals when used with a literal count.
+ if (matches!(self_arg.kind, ExprKind::Array([]))
+ || matches!(self_arg.kind, ExprKind::Lit(Spanned { node: LitKind::Str(s, _), .. }) if s.is_empty())
+ ) && matches!(count_arg.kind, ExprKind::Lit(_))
+ {
+ return;
+ }
+
+ let (msg, note_msg) = if count == 0 {
+ (format!("`{}` called with `0` splits", method_name),
+ "the resulting iterator will always return `None`")
+ } else {
+ (format!("`{}` called with `1` split", method_name),
+ if lang_items.slice_impl() == Some(impl_id) {
+ "the resulting iterator will always return the entire slice followed by `None`"
+ } else {
+ "the resulting iterator will always return the entire string followed by `None`"
+ })
+ };
+
+ span_lint_and_note(
+ cx,
+ SUSPICIOUS_SPLITN,
+ expr.span,
+ &msg,
+ None,
+ note_msg,
+ );
+ }
+ }
+}
ast::LitKind::Bool(true) => check_fold_with_op(cx, expr, acc, fold_span, hir::BinOpKind::And, "all", true),
ast::LitKind::Int(0, _) => check_fold_with_op(cx, expr, acc, fold_span, hir::BinOpKind::Add, "sum", false),
ast::LitKind::Int(1, _) => {
- check_fold_with_op(cx, expr, acc, fold_span, hir::BinOpKind::Mul, "product", false)
+ check_fold_with_op(cx, expr, acc, fold_span, hir::BinOpKind::Mul, "product", false);
},
_ => (),
}
use rustc_span::source_map::Span;
use std::fmt;
-use super::WRONG_PUB_SELF_CONVENTION;
use super::WRONG_SELF_CONVENTION;
#[rustfmt::skip]
// Conversion using `to_` can use borrowed (non-Copy types) or owned (Copy types).
// Source: https://rust-lang.github.io/api-guidelines/naming.html#ad-hoc-conversions-follow-as_-to_-into_-conventions-c-conv
- (&[Convention::StartsWith("to_"), Convention::NotEndsWith("_mut"), Convention::IsSelfTypeCopy(false),
+ (&[Convention::StartsWith("to_"), Convention::NotEndsWith("_mut"), Convention::IsSelfTypeCopy(false),
Convention::IsTraitItem(false), Convention::ImplementsTrait(false)], &[SelfKind::Ref]),
- (&[Convention::StartsWith("to_"), Convention::NotEndsWith("_mut"), Convention::IsSelfTypeCopy(true),
+ (&[Convention::StartsWith("to_"), Convention::NotEndsWith("_mut"), Convention::IsSelfTypeCopy(true),
Convention::IsTraitItem(false), Convention::ImplementsTrait(false)], &[SelfKind::Value]),
];
pub(super) fn check<'tcx>(
cx: &LateContext<'tcx>,
item_name: &str,
- is_pub: bool,
self_ty: &'tcx TyS<'tcx>,
first_arg_ty: &'tcx TyS<'tcx>,
first_arg_span: Span,
implements_trait: bool,
is_trait_item: bool,
) {
- let lint = if is_pub {
- WRONG_PUB_SELF_CONVENTION
- } else {
- WRONG_SELF_CONVENTION
- };
if let Some((conventions, self_kinds)) = &CONVENTIONS.iter().find(|(convs, _)| {
convs
.iter()
span_lint_and_help(
cx,
- lint,
+ WRONG_SELF_CONVENTION,
first_arg_span,
&format!(
"{} usually take {}",
-use crate::consts::{constant_simple, Constant};
+use clippy_utils::consts::{constant_simple, Constant};
use clippy_utils::diagnostics::span_lint;
use clippy_utils::{match_def_path, match_trait_method, paths};
use if_chain::if_chain;
use rustc_span::source_map::{ExpnKind, Span};
use rustc_span::symbol::sym;
-use crate::consts::{constant, Constant};
+use clippy_utils::consts::{constant, Constant};
use clippy_utils::sugg::Sugg;
use clippy_utils::{
expr_path_res, get_item_name, get_parent_expr, higher, in_constant, is_diag_trait_item, is_integer_const,
if binop.node == BinOpKind::And || binop.node == BinOpKind::Or;
if let Some(sugg) = Sugg::hir_opt(cx, a);
then {
- span_lint_and_then(cx,
+ span_lint_hir_and_then(
+ cx,
SHORT_CIRCUIT_STATEMENT,
+ expr.hir_id,
stmt.span,
"boolean short circuit operator in statement may be clearer using an explicit test",
|diag| {
if in_external_macro(cx.sess(), expr.span) {
return;
}
- double_neg::check(cx, expr)
+ double_neg::check(cx, expr);
}
}
};
unseparated_literal_suffix::check(cx, lit, &lit_snip, suffix, "integer");
if lit_snip.starts_with("0x") {
- mixed_case_hex_literals::check(cx, lit, suffix, &lit_snip)
+ mixed_case_hex_literals::check(cx, lit, suffix, &lit_snip);
} else if lit_snip.starts_with("0b") || lit_snip.starts_with("0o") {
- /* nothing to do */
+ // nothing to do
} else if value != 0 && lit_snip.starts_with('0') {
- zero_prefixed_literal::check(cx, lit, &lit_snip)
+ zero_prefixed_literal::check(cx, lit, &lit_snip);
}
} else if let LitKind::Float(_, LitFloatType::Suffixed(float_ty)) = lit.kind {
let suffix = float_ty.name_str();
- unseparated_literal_suffix::check(cx, lit, &lit_snip, suffix, "float")
+ unseparated_literal_suffix::check(cx, lit, &lit_snip, suffix, "float");
}
}
}
use super::UNNEEDED_FIELD_PATTERN;
pub(super) fn check(cx: &EarlyContext<'_>, pat: &Pat) {
- if let PatKind::Struct(ref npat, ref pfields, _) = pat.kind {
+ if let PatKind::Struct(_, ref npat, ref pfields, _) = pat.kind {
let mut wilds = 0;
let type_name = npat
.segments
use super::UNNEEDED_WILDCARD_PATTERN;
pub(super) fn check(cx: &EarlyContext<'_>, pat: &Pat) {
- if let PatKind::TupleStruct(_, ref patterns) | PatKind::Tuple(ref patterns) = pat.kind {
+ if let PatKind::TupleStruct(_, _, ref patterns) | PatKind::Tuple(ref patterns) = pat.kind {
if let Some(rest_index) = patterns.iter().position(|pat| pat.is_rest()) {
if let Some((left_index, left_pat)) = patterns[..rest_index]
.iter()
use clippy_utils::attrs::is_doc_hidden;
use clippy_utils::diagnostics::span_lint;
-use if_chain::if_chain;
-use rustc_ast::ast::{self, MetaItem, MetaItemKind};
+use rustc_ast::ast;
use rustc_hir as hir;
use rustc_lint::{LateContext, LateLintPass, LintContext};
use rustc_middle::ty;
*self.doc_hidden_stack.last().expect("empty doc_hidden_stack")
}
- fn has_include(meta: Option<MetaItem>) -> bool {
- if_chain! {
- if let Some(meta) = meta;
- if let MetaItemKind::List(list) = meta.kind;
- if let Some(meta) = list.get(0);
- if let Some(name) = meta.ident();
- then {
- name.name == sym::include
- } else {
- false
- }
- }
- }
-
fn check_missing_docs_attrs(
&self,
cx: &LateContext<'_>,
return;
}
- let has_doc = attrs.iter().any(|a| {
- a.is_doc_comment() || a.doc_str().is_some() || a.value_str().is_some() || Self::has_include(a.meta())
- });
+ let has_doc = attrs
+ .iter()
+ .any(|a| a.doc_str().is_some());
if !has_doc {
span_lint(
cx,
-use crate::consts::{constant, Constant};
+use clippy_utils::consts::{constant, Constant};
use clippy_utils::diagnostics::span_lint_and_then;
use clippy_utils::sext;
use if_chain::if_chain;
let def_id = cx.typeck_results().type_dependent_def_id(e.hir_id).unwrap();
let substs = cx.typeck_results().node_substs(e.hir_id);
let method_type = cx.tcx.type_of(def_id).subst(cx.tcx, substs);
- check_arguments(cx, arguments, method_type, &path.ident.as_str(), "method")
+ check_arguments(cx, arguments, method_type, &path.ident.as_str(), "method");
},
_ => (),
}
_ if !self.found => self.expr_span = Some(expr.span),
_ => return,
}
- walk_expr(self, expr)
+ walk_expr(self, expr);
}
fn nested_visit_map(&mut self) -> NestedVisitorMap<Self::Map> {
match &p.ty.kind {
TyKind::Path(None, path) => {
if let PatKind::Ident(BindingMode::ByValue(mutbl), _, _) = p.pat.kind {
- check_param_inner(cx, path, p.span.to(p.ty.span), &Mode::Value, mutbl)
+ check_param_inner(cx, path, p.span.to(p.ty.span), &Mode::Value, mutbl);
}
},
TyKind::Rptr(lifetime, mut_ty) => {
if let TyKind::Path(None, path) = &mut_ty.ty.kind;
if let PatKind::Ident(BindingMode::ByValue(Mutability::Not), _, _) = p.pat.kind;
then {
- check_param_inner(cx, path, p.span.to(p.ty.span), &Mode::Ref(*lifetime), mut_ty.mutbl)
+ check_param_inner(cx, path, p.span.to(p.ty.span), &Mode::Ref(*lifetime), mut_ty.mutbl);
}
}
},
}
if is_else_clause(cx.tcx, e) {
- snip = snip.blockify()
+ snip = snip.blockify();
}
span_lint_and_sugg(
|h: Sugg<'_>| !h,
"equality checks against false can be replaced by a negation",
));
- check_comparison(cx, e, true_case, false_case, true_case, false_case, ignore_no_literal)
+ check_comparison(cx, e, true_case, false_case, true_case, false_case, ignore_no_literal);
},
BinOpKind::Ne => {
let true_case = Some((
"inequality checks against true can be replaced by a negation",
));
let false_case = Some((|h| h, "inequality checks against false are unnecessary"));
- check_comparison(cx, e, true_case, false_case, true_case, false_case, ignore_no_literal)
+ check_comparison(cx, e, true_case, false_case, true_case, false_case, ignore_no_literal);
},
BinOpKind::Lt => check_comparison(
cx,
snippet_with_applicability(cx, expression_info.right_span, "..", &mut applicability)
),
applicability,
- )
+ );
}
}
match (fetch_bool_expr(left_side), fetch_bool_expr(right_side)) {
(Bool(true), Other) => left_true.map_or((), |(h, m)| {
- suggest_bool_comparison(cx, e, right_side, applicability, m, h)
+ suggest_bool_comparison(cx, e, right_side, applicability, m, h);
}),
(Other, Bool(true)) => right_true.map_or((), |(h, m)| {
- suggest_bool_comparison(cx, e, left_side, applicability, m, h)
+ suggest_bool_comparison(cx, e, left_side, applicability, m, h);
}),
(Bool(false), Other) => left_false.map_or((), |(h, m)| {
- suggest_bool_comparison(cx, e, right_side, applicability, m, h)
+ suggest_bool_comparison(cx, e, right_side, applicability, m, h);
}),
(Other, Bool(false)) => right_false.map_or((), |(h, m)| {
- suggest_bool_comparison(cx, e, left_side, applicability, m, h)
+ suggest_bool_comparison(cx, e, left_side, applicability, m, h);
}),
(Other, Other) => no_literal.map_or((), |(h, m)| {
let left_side = Sugg::hir_with_applicability(cx, left_side, "..", &mut applicability);
"try simplifying it as shown",
h(left_side, right_side).to_string(),
applicability,
- )
+ );
}),
_ => (),
}
//! This lint is **warn** by default
use clippy_utils::diagnostics::span_lint_and_then;
-use clippy_utils::is_automatically_derived;
-use clippy_utils::source::snippet_opt;
+use clippy_utils::source::{snippet_opt, snippet_with_applicability, snippet_with_context};
+use clippy_utils::{get_parent_expr, in_macro, path_to_local};
use if_chain::if_chain;
+use rustc_ast::util::parser::PREC_POSTFIX;
+use rustc_data_structures::fx::FxIndexMap;
use rustc_errors::Applicability;
-use rustc_hir::{BindingAnnotation, BorrowKind, Expr, ExprKind, Item, Mutability, Pat, PatKind};
+use rustc_hir::{BindingAnnotation, Body, BodyId, BorrowKind, Expr, ExprKind, HirId, Mutability, Pat, PatKind, UnOp};
use rustc_lint::{LateContext, LateLintPass};
use rustc_middle::ty;
use rustc_middle::ty::adjustment::{Adjust, Adjustment};
use rustc_session::{declare_tool_lint, impl_lint_pass};
-use rustc_span::def_id::LocalDefId;
+use rustc_span::Span;
declare_clippy_lint! {
/// **What it does:** Checks for address of operations (`&`) that are going to
/// let x: &i32 = &5;
/// ```
pub NEEDLESS_BORROW,
- nursery,
+ style,
"taking a reference that is going to be automatically dereferenced"
}
+declare_clippy_lint! {
+ /// **What it does:** Checks for `ref` bindings which create a reference to a reference.
+ ///
+ /// **Why is this bad?** The address-of operator at the use site is clearer about the need for a reference.
+ ///
+ /// **Known problems:** None.
+ ///
+ /// **Example:**
+ /// ```rust
+ /// // Bad
+ /// let x = Some("");
+ /// if let Some(ref x) = x {
+ /// // use `x` here
+ /// }
+ ///
+ /// // Good
+ /// let x = Some("");
+ /// if let Some(x) = x {
+ /// // use `&x` here
+ /// }
+ /// ```
+ pub REF_BINDING_TO_REFERENCE,
+ pedantic,
+ "`ref` binding to a reference"
+}
+
+impl_lint_pass!(NeedlessBorrow => [NEEDLESS_BORROW, REF_BINDING_TO_REFERENCE]);
#[derive(Default)]
pub struct NeedlessBorrow {
- derived_item: Option<LocalDefId>,
+ /// The body the first local was found in. Used to emit lints when the traversal of the body has
+ /// been finished. Note we can't lint at the end of every body as they can be nested within each
+ /// other.
+ current_body: Option<BodyId>,
+ /// The list of locals currently being checked by the lint.
+ /// If the value is `None`, then the binding has been seen as a ref pattern, but is not linted.
+ /// This is needed for or patterns where one of the branches can be linted, but another can not
+ /// be.
+ ///
+ /// e.g. `m!(x) | Foo::Bar(ref x)`
+ ref_locals: FxIndexMap<HirId, Option<RefPat>>,
}
-impl_lint_pass!(NeedlessBorrow => [NEEDLESS_BORROW]);
+struct RefPat {
+ /// Whether every usage of the binding is dereferenced.
+ always_deref: bool,
+ /// The spans of all the ref bindings for this local.
+ spans: Vec<Span>,
+ /// The applicability of this suggestion.
+ app: Applicability,
+ /// All the replacements which need to be made.
+ replacements: Vec<(Span, String)>,
+}
impl<'tcx> LateLintPass<'tcx> for NeedlessBorrow {
fn check_expr(&mut self, cx: &LateContext<'tcx>, e: &'tcx Expr<'_>) {
- if e.span.from_expansion() || self.derived_item.is_some() {
+ if let Some(local) = path_to_local(e) {
+ self.check_local_usage(cx, e, local);
+ }
+
+ if e.span.from_expansion() {
return;
}
if let ExprKind::AddrOf(BorrowKind::Ref, Mutability::Not, inner) = e.kind {
}
}
}
+
fn check_pat(&mut self, cx: &LateContext<'tcx>, pat: &'tcx Pat<'_>) {
- if pat.span.from_expansion() || self.derived_item.is_some() {
- return;
+ if let PatKind::Binding(BindingAnnotation::Ref, id, name, _) = pat.kind {
+ if let Some(opt_prev_pat) = self.ref_locals.get_mut(&id) {
+ // This binding id has been seen before. Add this pattern to the list of changes.
+ if let Some(prev_pat) = opt_prev_pat {
+ if in_macro(pat.span) {
+ // Doesn't match the context of the previous pattern. Can't lint here.
+ *opt_prev_pat = None;
+ } else {
+ prev_pat.spans.push(pat.span);
+ prev_pat.replacements.push((
+ pat.span,
+ snippet_with_context(cx, name.span, pat.span.ctxt(), "..", &mut prev_pat.app)
+ .0
+ .into(),
+ ));
+ }
+ }
+ return;
+ }
+
+ if_chain! {
+ if !in_macro(pat.span);
+ if let ty::Ref(_, tam, _) = *cx.typeck_results().pat_ty(pat).kind();
+ // only lint immutable refs, because borrowed `&mut T` cannot be moved out
+ if let ty::Ref(_, _, Mutability::Not) = *tam.kind();
+ then {
+ let mut app = Applicability::MachineApplicable;
+ let snip = snippet_with_context(cx, name.span, pat.span.ctxt(), "..", &mut app).0;
+ self.current_body = self.current_body.or(cx.enclosing_body);
+ self.ref_locals.insert(
+ id,
+ Some(RefPat {
+ always_deref: true,
+ spans: vec![pat.span],
+ app,
+ replacements: vec![(pat.span, snip.into())],
+ }),
+ );
+ }
+ }
}
- if_chain! {
- if let PatKind::Binding(BindingAnnotation::Ref, .., name, _) = pat.kind;
- if let ty::Ref(_, tam, mutbl) = *cx.typeck_results().pat_ty(pat).kind();
- if mutbl == Mutability::Not;
- if let ty::Ref(_, _, mutbl) = *tam.kind();
- // only lint immutable refs, because borrowed `&mut T` cannot be moved out
- if mutbl == Mutability::Not;
- then {
+ }
+
+ fn check_body_post(&mut self, cx: &LateContext<'tcx>, body: &'tcx Body<'_>) {
+ if Some(body.id()) == self.current_body {
+ for pat in self.ref_locals.drain(..).filter_map(|(_, x)| x) {
+ let replacements = pat.replacements;
+ let app = pat.app;
span_lint_and_then(
cx,
- NEEDLESS_BORROW,
- pat.span,
+ if pat.always_deref {
+ NEEDLESS_BORROW
+ } else {
+ REF_BINDING_TO_REFERENCE
+ },
+ pat.spans,
"this pattern creates a reference to a reference",
|diag| {
- if let Some(snippet) = snippet_opt(cx, name.span) {
- diag.span_suggestion(
- pat.span,
- "change this to",
- snippet,
- Applicability::MachineApplicable,
- );
- }
- }
- )
+ diag.multipart_suggestion("try this", replacements, app);
+ },
+ );
}
+ self.current_body = None;
}
}
-
- fn check_item(&mut self, cx: &LateContext<'tcx>, item: &'tcx Item<'_>) {
- let attrs = cx.tcx.hir().attrs(item.hir_id());
- if is_automatically_derived(attrs) {
- debug_assert!(self.derived_item.is_none());
- self.derived_item = Some(item.def_id);
- }
- }
-
- fn check_item_post(&mut self, _: &LateContext<'tcx>, item: &'tcx Item<'_>) {
- if let Some(id) = self.derived_item {
- if item.def_id == id {
- self.derived_item = None;
+}
+impl NeedlessBorrow {
+ fn check_local_usage(&mut self, cx: &LateContext<'tcx>, e: &'tcx Expr<'_>, local: HirId) {
+ if let Some(outer_pat) = self.ref_locals.get_mut(&local) {
+ if let Some(pat) = outer_pat {
+ // Check for auto-deref
+ if !matches!(
+ cx.typeck_results().expr_adjustments(e),
+ [
+ Adjustment {
+ kind: Adjust::Deref(_),
+ ..
+ },
+ Adjustment {
+ kind: Adjust::Deref(_),
+ ..
+ },
+ ..
+ ]
+ ) {
+ match get_parent_expr(cx, e) {
+ // Field accesses are the same no matter the number of references.
+ Some(Expr {
+ kind: ExprKind::Field(..),
+ ..
+ }) => (),
+ Some(&Expr {
+ span,
+ kind: ExprKind::Unary(UnOp::Deref, _),
+ ..
+ }) if !in_macro(span) => {
+ // Remove explicit deref.
+ let snip = snippet_with_context(cx, e.span, span.ctxt(), "..", &mut pat.app).0;
+ pat.replacements.push((span, snip.into()));
+ },
+ Some(parent) if !in_macro(parent.span) => {
+ // Double reference might be needed at this point.
+ if parent.precedence().order() == PREC_POSTFIX {
+ // Parentheses would be needed here, don't lint.
+ *outer_pat = None;
+ } else {
+ pat.always_deref = false;
+ let snip = snippet_with_context(cx, e.span, parent.span.ctxt(), "..", &mut pat.app).0;
+ pat.replacements.push((e.span, format!("&{}", snip)));
+ }
+ },
+ _ if !in_macro(e.span) => {
+ // Double reference might be needed at this point.
+ pat.always_deref = false;
+ let snip = snippet_with_applicability(cx, e.span, "..", &mut pat.app);
+ pat.replacements.push((e.span, format!("&{}", snip)));
+ },
+ // Edge case for macros. The span of the identifier will usually match the context of the
+ // binding, but not if the identifier was created in a macro. e.g. `concat_idents` and proc
+ // macros
+ _ => *outer_pat = None,
+ }
+ }
}
}
}
match expr.kind {
ExprKind::Ret(..) => {
if self.loop_depth > 0 && !self.ret_in_loop {
- self.ret_in_loop = true
+ self.ret_in_loop = true;
}
- self.spans.push(expr.span)
+ self.spans.push(expr.span);
},
ExprKind::Loop(..) => {
types produces code that is hard to read and refactor, please \
consider using the `partial_cmp` method instead, to make it \
clear that the two values could be incomparable"
- )
+ );
}
}
}
+use clippy_utils::consts::{self, Constant};
use clippy_utils::diagnostics::span_lint;
use if_chain::if_chain;
use rustc_hir::{BinOpKind, Expr, ExprKind, UnOp};
use rustc_session::{declare_lint_pass, declare_tool_lint};
use rustc_span::source_map::Span;
-use crate::consts::{self, Constant};
-
declare_clippy_lint! {
/// **What it does:** Checks for multiplication by -1 as a form of negation.
///
-use clippy_utils::diagnostics::{span_lint, span_lint_and_sugg};
+use clippy_utils::diagnostics::{span_lint_hir, span_lint_hir_and_then};
use clippy_utils::source::snippet_opt;
use clippy_utils::ty::has_drop;
use rustc_errors::Applicability;
fn check_stmt(&mut self, cx: &LateContext<'tcx>, stmt: &'tcx Stmt<'_>) {
if let StmtKind::Semi(expr) = stmt.kind {
if has_no_effect(cx, expr) {
- span_lint(cx, NO_EFFECT, stmt.span, "statement with no effect");
+ span_lint_hir(cx, NO_EFFECT, expr.hir_id, stmt.span, "statement with no effect");
} else if let Some(reduced) = reduce_expression(cx, expr) {
let mut snippet = String::new();
for e in reduced {
return;
}
}
- span_lint_and_sugg(
+ span_lint_hir_and_then(
cx,
UNNECESSARY_OPERATION,
+ expr.hir_id,
stmt.span,
"statement can be reduced",
- "replace it with",
- snippet,
- Applicability::MachineApplicable,
+ |diag| {
+ diag.span_suggestion(stmt.span, "replace it with", snippet, Applicability::MachineApplicable);
+ },
);
}
}
&["args", "arms"],
&["qpath", "path"],
&["lit", "lint"],
+ &["wparam", "lparam"],
];
struct SimilarNamesNameVisitor<'a, 'tcx, 'b>(&'b mut SimilarNamesLocalVisitor<'a, 'tcx>);
self.check_ident(ident);
}
},
- PatKind::Struct(_, ref fields, _) => {
+ PatKind::Struct(_, _, ref fields, _) => {
for field in fields {
if !field.is_shorthand {
self.visit_pat(&field.pat);
"the method `create` is called more than once",
);
} else {
- create = true
+ create = true;
}
create_arg = create_arg || (arg == Argument::True);
},
"the method `append` is called more than once",
);
} else {
- append = true
+ append = true;
}
append_arg = append_arg || (arg == Argument::True);
},
"the method `truncate` is called more than once",
);
} else {
- truncate = true
+ truncate = true;
}
truncate_arg = truncate_arg || (arg == Argument::True);
},
"the method `read` is called more than once",
);
} else {
- read = true
+ read = true;
}
read_arg = read_arg || (arg == Argument::True);
},
"the method `write` is called more than once",
);
} else {
- write = true
+ write = true;
}
write_arg = write_arg || (arg == Argument::True);
},
pub struct PassByRefOrValue {
ref_min_size: u64,
value_max_size: u64,
+ avoid_breaking_exported_api: bool,
}
impl<'tcx> PassByRefOrValue {
- pub fn new(ref_min_size: Option<u64>, value_max_size: u64, target: &Target) -> Self {
+ pub fn new(
+ ref_min_size: Option<u64>,
+ value_max_size: u64,
+ avoid_breaking_exported_api: bool,
+ target: &Target,
+ ) -> Self {
let ref_min_size = ref_min_size.unwrap_or_else(|| {
let bit_width = u64::from(target.pointer_width);
// Cap the calculated bit width at 32-bits to reduce
Self {
ref_min_size,
value_max_size,
+ avoid_breaking_exported_api,
}
}
fn check_poly_fn(&mut self, cx: &LateContext<'tcx>, hir_id: HirId, decl: &FnDecl<'_>, span: Option<Span>) {
+ if self.avoid_breaking_exported_api && cx.access_levels.is_exported(hir_id) {
+ return;
+ }
let fn_def_id = cx.tcx.hir().local_def_id(hir_id);
let fn_sig = cx.tcx.fn_sig(fn_def_id);
}
if_chain! {
- if !cx.access_levels.is_exported(hir_id);
if is_copy(cx, ty);
if !is_self_ty(input);
if let Some(size) = cx.layout_of(ty).ok().map(|l| l.size.bytes());
];
if_chain! {
- if let ExprKind::Call(ref fun, ref args) = expr.kind;
+ if let ExprKind::Call(fun, args) = expr.kind;
if let ExprKind::Path(ref qpath) = fun.kind;
if let Some(fun_def_id) = cx.qpath_res(qpath, fun.hir_id).opt_def_id();
let fun_def_path = cx.get_def_path(fun_def_id).into_iter().map(Symbol::to_ident_string).collect::<Vec<_>>();
"replace it with",
replacement_str,
applicability,
- )
+ );
}
}
}
"replace it with",
replacement,
applicability,
- )
+ );
}
}
}
-use crate::consts::{constant, Constant};
+use clippy_utils::consts::{constant, Constant};
use clippy_utils::diagnostics::{span_lint, span_lint_and_sugg, span_lint_and_then};
use clippy_utils::source::{snippet, snippet_opt, snippet_with_applicability};
use clippy_utils::sugg::Sugg;
self.found_return = true;
}
- ast_visit::walk_expr(self, ex)
+ ast_visit::walk_expr(self, ex);
}
}
Applicability::MachineApplicable,
);
},
- )
+ );
}
}
}
-use crate::consts::{constant, Constant};
+use clippy_utils::consts::{constant, Constant};
use clippy_utils::diagnostics::{span_lint, span_lint_and_help};
use clippy_utils::{match_def_path, paths};
use if_chain::if_chain;
-use crate::consts::{constant_context, Constant};
+use clippy_utils::consts::{constant_context, Constant};
use clippy_utils::diagnostics::span_lint_and_sugg;
use clippy_utils::in_macro;
use clippy_utils::source::snippet;
} else {
RetReplacement::Empty
};
- check_final_expr(cx, &body.value, Some(body.value.span), replacement)
+ check_final_expr(cx, &body.value, Some(body.value.span), replacement);
},
FnKind::ItemFn(..) | FnKind::Method(..) => {
if let ExprKind::Block(block, _) = body.value.kind {
if let Some(snippet) = snippet_opt(cx, inner_span) {
diag.span_suggestion(ret_span, "remove `return`", snippet, Applicability::MachineApplicable);
}
- })
+ });
},
None => match replacement {
RetReplacement::Empty => {
use rustc_session::{declare_lint_pass, declare_tool_lint};
declare_clippy_lint! {
- /// **What it does:** Looks for blocks of expressions and fires if the last expression returns `()`
- /// but is not followed by a semicolon.
+ /// **What it does:** Looks for blocks of expressions and fires if the last expression returns
+ /// `()` but is not followed by a semicolon.
///
- /// **Why is this bad?** The semicolon might be optional but when
- /// extending the block with new code, it doesn't require a change in previous last line.
+ /// **Why is this bad?** The semicolon might be optional but when extending the block with new
+ /// code, it doesn't require a change in previous last line.
///
/// **Known problems:** None.
///
/// }
/// ```
pub SEMICOLON_IF_NOTHING_RETURNED,
- restriction,
+ pedantic,
"add a semicolon if nothing is returned"
}
let mut bindings = Vec::with_capacity(decl.inputs.len());
for arg in iter_input_pats(decl, body) {
if let PatKind::Binding(.., ident, _) = arg.pat.kind {
- bindings.push((ident.name, ident.span))
+ bindings.push((ident.name, ident.span));
}
}
check_expr(cx, &body.value, &mut bindings);
..
} = *local;
if let Some(t) = *ty {
- check_ty(cx, t, bindings)
+ check_ty(cx, t, bindings);
}
if let Some(o) = *init {
check_expr(cx, o, bindings);
}
match expr.kind {
ExprKind::Unary(_, e) | ExprKind::Field(e, _) | ExprKind::AddrOf(_, _, e) | ExprKind::Box(e) => {
- check_expr(cx, e, bindings)
+ check_expr(cx, e, bindings);
},
ExprKind::Block(block, _) | ExprKind::Loop(block, ..) => check_block(cx, block, bindings),
// ExprKind::Call
// ExprKind::MethodCall
ExprKind::Array(v) | ExprKind::Tup(v) => {
for e in v {
- check_expr(cx, e, bindings)
+ check_expr(cx, e, bindings);
}
},
ExprKind::If(cond, then, ref otherwise) => {
TyKind::Ptr(MutTy { ty: mty, .. }) | TyKind::Rptr(_, MutTy { ty: mty, .. }) => check_ty(cx, mty, bindings),
TyKind::Tup(tup) => {
for t in tup {
- check_ty(cx, t, bindings)
+ check_ty(cx, t, bindings);
}
},
TyKind::Typeof(ref anon_const) => check_expr(cx, &cx.tcx.hir().body(anon_const.body).value, bindings),
for item in items {
track_uses(
cx,
- &item,
+ item,
&mut imports_reused_with_self,
&mut single_use_usages,
&mut macros,
match &item.kind {
ItemKind::Mod(_, ModKind::Loaded(ref items, ..)) => {
- check_mod(cx, &items);
+ check_mod(cx, items);
},
ItemKind::MacroDef(MacroDef { macro_rules: true, .. }) => {
macros.push(item.ident.name);
) {
match initialization {
InitializationType::Extend(e) | InitializationType::Resize(e) => {
- Self::emit_lint(cx, e, vec_alloc, "slow zero-filling initialization")
+ Self::emit_lint(cx, e, vec_alloc, "slow zero-filling initialization");
},
};
}
fn visit_block(&mut self, block: &'tcx Block<'_>) {
if self.initialization_found {
if let Some(s) = block.stmts.get(0) {
- self.visit_stmt(s)
+ self.visit_stmt(s);
}
self.initialization_found = false;
/// }
/// ```
pub SUSPICIOUS_OPERATION_GROUPINGS,
- style,
+ nursery,
"groupings of binary operations that look suspiciously like typos"
}
"did you mean",
sugg,
applicability,
- )
+ );
}
fn ident_swap_sugg(
impl AddAssign for IdentLocation {
fn add_assign(&mut self, other: Self) {
- *self = *self + other
+ *self = *self + other;
}
}
impl AddAssign for IdentDifference {
fn add_assign(&mut self, other: Self) {
- *self = *self + other
+ *self = *self + other;
}
}
use clippy_utils::{in_macro, SpanlessHash};
use if_chain::if_chain;
use rustc_data_structures::fx::FxHashMap;
+use rustc_data_structures::unhash::UnhashMap;
use rustc_errors::Applicability;
use rustc_hir::{def::Res, GenericBound, Generics, ParamName, Path, QPath, TyKind, WherePredicate};
use rustc_lint::{LateContext, LateLintPass};
hasher.hash_ty(ty);
hasher.finish()
};
- let mut map = FxHashMap::default();
+ let mut map: UnhashMap<u64, Vec<&GenericBound<'_>>> = UnhashMap::default();
let mut applicability = Applicability::MaybeIncorrect;
for bound in gen.where_clause.predicates {
if_chain! {
-use crate::consts::{constant_context, Constant};
+use clippy_utils::consts::{constant_context, Constant};
use clippy_utils::diagnostics::span_lint;
use clippy_utils::{is_expr_path_def_path, paths};
use if_chain::if_chain;
fn check_trait_item(&mut self, cx: &LateContext<'_>, item: &TraitItem<'_>) {
match item.kind {
TraitItemKind::Const(ty, _) | TraitItemKind::Type(_, Some(ty)) => {
- self.check_ty(cx, ty, CheckTyContext::default())
+ self.check_ty(cx, ty, CheckTyContext::default());
},
TraitItemKind::Fn(ref sig, _) => self.check_fn_decl(cx, sig.decl, CheckTyContext::default()),
TraitItemKind::Type(..) => (),
},
TyKind::Slice(ty) | TyKind::Array(ty, _) | TyKind::Ptr(MutTy { ty, .. }) => {
context.is_nested_call = true;
- self.check_ty(cx, ty, context)
+ self.check_ty(cx, ty, context);
},
TyKind::Tup(tys) => {
context.is_nested_call = true;
fn check_expr(&mut self, cx: &LateContext<'_>, expr: &'_ Expr<'_>) {
if let ExprKind::Lit(ref lit) = expr.kind {
if let LitKind::Str(_, _) = lit.node {
- check_str(cx, lit.span, expr.hir_id)
+ check_str(cx, lit.span, expr.hir_id);
}
}
}
for c in s {
if c as u32 > 0x7F {
for d in c.escape_unicode() {
- result.push(d)
+ result.push(d);
}
} else {
result.push(c);
use rustc_hir::{Body, ExprKind, FnDecl, HirId, Impl, ItemKind, Node};
use rustc_lint::{LateContext, LateLintPass};
use rustc_middle::ty;
-use rustc_session::{declare_lint_pass, declare_tool_lint};
+use rustc_session::{declare_tool_lint, impl_lint_pass};
use rustc_span::symbol::sym;
use rustc_span::Span;
"functions that only return `Ok` or `Some`"
}
-declare_lint_pass!(UnnecessaryWraps => [UNNECESSARY_WRAPS]);
+pub struct UnnecessaryWraps {
+ avoid_breaking_exported_api: bool,
+}
+
+impl_lint_pass!(UnnecessaryWraps => [UNNECESSARY_WRAPS]);
+
+impl UnnecessaryWraps {
+ pub fn new(avoid_breaking_exported_api: bool) -> Self {
+ Self {
+ avoid_breaking_exported_api,
+ }
+ }
+}
impl<'tcx> LateLintPass<'tcx> for UnnecessaryWraps {
fn check_fn(
) {
// Abort if public function/method or closure.
match fn_kind {
- FnKind::ItemFn(.., visibility) | FnKind::Method(.., Some(visibility)) => {
- if visibility.node.is_pub() {
+ FnKind::ItemFn(..) | FnKind::Method(..) => {
+ if self.avoid_breaking_exported_api && cx.access_levels.is_exported(hir_id) {
return;
}
},
FnKind::Closure => return,
- FnKind::Method(..) => (),
}
// Abort if the method is implementing a trait or of it a trait method.
#![allow(clippy::wildcard_imports, clippy::enum_glob_use)]
-use clippy_utils::ast_utils::{eq_field_pat, eq_id, eq_pat, eq_path};
+use clippy_utils::ast_utils::{eq_field_pat, eq_id, eq_pat, eq_path, eq_maybe_qself};
use clippy_utils::diagnostics::span_lint_and_then;
use clippy_utils::{meets_msrv, msrvs, over};
use rustc_ast::mut_visit::*;
|k| always_pat!(k, Tuple(ps) => ps),
),
// Transform `S(pre, x, post) | ... | S(pre, y, post)` into `S(pre, x | y, post)`.
- TupleStruct(path1, ps1) => extend_with_matching_product(
+ TupleStruct(qself1, path1, ps1) => extend_with_matching_product(
ps1, start, alternatives,
|k, ps1, idx| matches!(
k,
- TupleStruct(path2, ps2) if eq_path(path1, path2) && eq_pre_post(ps1, ps2, idx)
+ TupleStruct(qself2, path2, ps2) if eq_maybe_qself(qself1, qself2) && eq_path(path1, path2) && eq_pre_post(ps1, ps2, idx)
),
- |k| always_pat!(k, TupleStruct(_, ps) => ps),
+ |k| always_pat!(k, TupleStruct(_, _, ps) => ps),
),
// Transform a record pattern `S { fp_0, ..., fp_n }`.
- Struct(path1, fps1, rest1) => extend_with_struct_pat(path1, fps1, *rest1, start, alternatives),
+ Struct(qself1, path1, fps1, rest1) => extend_with_struct_pat(qself1, path1, fps1, *rest1, start, alternatives),
};
alternatives[focus_idx].kind = focus_kind;
/// So when we fixate on some `ident_k: pat_k`, we try to find `ident_k` in the other pattern
/// and check that all `fp_i` where `i ∈ ((0...n) \ k)` between two patterns are equal.
fn extend_with_struct_pat(
+ qself1: &Option<ast::QSelf>,
path1: &ast::Path,
fps1: &mut Vec<ast::PatField>,
rest1: bool,
start,
alternatives,
|k| {
- matches!(k, Struct(path2, fps2, rest2)
+ matches!(k, Struct(qself2, path2, fps2, rest2)
if rest1 == *rest2 // If one struct pattern has `..` so must the other.
+ && eq_maybe_qself(qself1, qself2)
&& eq_path(path1, path2)
&& fps1.len() == fps2.len()
&& fps1.iter().enumerate().all(|(idx_1, fp1)| {
}))
},
// Extract `p2_k`.
- |k| always_pat!(k, Struct(_, mut fps, _) => fps.swap_remove(pos_in_2.take().unwrap()).pat),
+ |k| always_pat!(k, Struct(_, _, mut fps, _) => fps.swap_remove(pos_in_2.take().unwrap()).pat),
);
extend_with_tail_or(&mut fps1[idx].pat, tail_or)
})
fn check_map_error(cx: &LateContext<'_>, call: &hir::Expr<'_>, expr: &hir::Expr<'_>) {
let mut call = call;
- while let hir::ExprKind::MethodCall(ref path, _, ref args, _) = call.kind {
+ while let hir::ExprKind::MethodCall(path, _, args, _) = call.kind {
if matches!(&*path.ident.as_str(), "or" | "or_else" | "ok") {
call = &args[0];
} else {
use clippy_utils::diagnostics::span_lint_and_sugg;
use itertools::Itertools;
-use rustc_ast::ast::{Item, ItemKind, VisibilityKind};
use rustc_errors::Applicability;
-use rustc_lint::{EarlyContext, EarlyLintPass, LintContext};
+use rustc_hir::{Item, ItemKind};
+use rustc_lint::{LateContext, LateLintPass, LintContext};
use rustc_middle::lint::in_external_macro;
use rustc_session::{declare_tool_lint, impl_lint_pass};
use rustc_span::symbol::Ident;
#[derive(Default)]
pub struct UpperCaseAcronyms {
+ avoid_breaking_exported_api: bool,
upper_case_acronyms_aggressive: bool,
}
impl UpperCaseAcronyms {
- pub fn new(aggressive: bool) -> Self {
+ pub fn new(avoid_breaking_exported_api: bool, aggressive: bool) -> Self {
Self {
+ avoid_breaking_exported_api,
upper_case_acronyms_aggressive: aggressive,
}
}
ident
}
-fn check_ident(cx: &EarlyContext<'_>, ident: &Ident, be_aggressive: bool) {
+fn check_ident(cx: &LateContext<'_>, ident: &Ident, be_aggressive: bool) {
let span = ident.span;
let ident = &ident.as_str();
let corrected = correct_ident(ident);
"consider making the acronym lowercase, except the initial letter",
corrected,
Applicability::MaybeIncorrect,
- )
+ );
}
}
-impl EarlyLintPass for UpperCaseAcronyms {
- fn check_item(&mut self, cx: &EarlyContext<'_>, it: &Item) {
+impl LateLintPass<'_> for UpperCaseAcronyms {
+ fn check_item(&mut self, cx: &LateContext<'_>, it: &Item<'_>) {
// do not lint public items or in macros
- if !in_external_macro(cx.sess(), it.span) && !matches!(it.vis.kind, VisibilityKind::Public) {
- if matches!(
- it.kind,
- ItemKind::TyAlias(..) | ItemKind::Struct(..) | ItemKind::Trait(..)
- ) {
+ if in_external_macro(cx.sess(), it.span)
+ || (self.avoid_breaking_exported_api && cx.access_levels.is_exported(it.hir_id()))
+ {
+ return;
+ }
+ match it.kind {
+ ItemKind::TyAlias(..) | ItemKind::Struct(..) | ItemKind::Trait(..) => {
check_ident(cx, &it.ident, self.upper_case_acronyms_aggressive);
- } else if let ItemKind::Enum(ref enumdef, _) = it.kind {
+ },
+ ItemKind::Enum(ref enumdef, _) => {
// check enum variants seperately because again we only want to lint on private enums and
// the fn check_variant does not know about the vis of the enum of its variants
enumdef
.variants
.iter()
.for_each(|variant| check_ident(cx, &variant.ident, self.upper_case_acronyms_aggressive));
- }
+ },
+ _ => {},
}
}
}
fn visit_ty(&mut self, hir_ty: &hir::Ty<'_>) {
self.types_to_skip.push(hir_ty.hir_id);
- walk_ty(self, hir_ty)
+ walk_ty(self, hir_ty);
}
fn nested_visit_map(&mut self) -> NestedVisitorMap<Self::Map> {
}
}
- walk_ty(self, hir_ty)
+ walk_ty(self, hir_ty);
}
fn nested_visit_map(&mut self) -> NestedVisitorMap<Self::Map> {
LitKind::Str(ref text, _) => {
let str_pat = self.next("s");
println!(" if let LitKind::Str(ref {}, _) = {}.node;", str_pat, lit_pat);
- println!(" if {}.as_str() == {:?}", str_pat, &*text.as_str())
+ println!(" if {}.as_str() == {:?}", str_pat, &*text.as_str());
},
}
},
// N.B., this macro is parsed by util/lintlib.py
define_Conf! {
- /// Lint: CLONED_INSTEAD_OF_COPIED, REDUNDANT_FIELD_NAMES, REDUNDANT_STATIC_LIFETIMES, FILTER_MAP_NEXT, CHECKED_CONVERSIONS, MANUAL_RANGE_CONTAINS, USE_SELF, MEM_REPLACE_WITH_DEFAULT, MANUAL_NON_EXHAUSTIVE, OPTION_AS_REF_DEREF, MAP_UNWRAP_OR, MATCH_LIKE_MATCHES_MACRO, MANUAL_STRIP, MISSING_CONST_FOR_FN, UNNESTED_OR_PATTERNS, FROM_OVER_INTO, PTR_AS_PTR, IF_THEN_SOME_ELSE_NONE. The minimum rust version that the project supports
+ /// Lint: ENUM_VARIANT_NAMES, LARGE_TYPES_PASSED_BY_VALUE, TRIVIALLY_COPY_PASS_BY_REF, UNNECESSARY_WRAPS, UPPER_CASE_ACRONYMS, WRONG_SELF_CONVENTION. Suppress lints whenever the suggested change would cause breakage for other crates.
+ (avoid_breaking_exported_api: bool = true),
+ /// Lint: MANUAL_STR_REPEAT, CLONED_INSTEAD_OF_COPIED, REDUNDANT_FIELD_NAMES, REDUNDANT_STATIC_LIFETIMES, FILTER_MAP_NEXT, CHECKED_CONVERSIONS, MANUAL_RANGE_CONTAINS, USE_SELF, MEM_REPLACE_WITH_DEFAULT, MANUAL_NON_EXHAUSTIVE, OPTION_AS_REF_DEREF, MAP_UNWRAP_OR, MATCH_LIKE_MATCHES_MACRO, MANUAL_STRIP, MISSING_CONST_FOR_FN, UNNESTED_OR_PATTERNS, FROM_OVER_INTO, PTR_AS_PTR, IF_THEN_SOME_ELSE_NONE. The minimum rust version that the project supports
(msrv: Option<String> = None),
/// Lint: BLACKLISTED_NAME. The list of blacklisted names to lint about. NB: `bar` is not here since it has legitimate uses
(blacklisted_names: Vec<String> = ["foo", "baz", "quux"].iter().map(ToString::to_string).collect()),
.map_or_else(|| PathBuf::from("."), PathBuf::from);
loop {
for config_file_name in &CONFIG_FILE_NAMES {
- let config_file = current.join(config_file_name);
- match fs::metadata(&config_file) {
- // Only return if it's a file to handle the unlikely situation of a directory named
- // `clippy.toml`.
- Ok(ref md) if !md.is_dir() => return Ok(Some(config_file)),
- // Return the error if it's something other than `NotFound`; otherwise we didn't
- // find the project file yet, and continue searching.
- Err(e) if e.kind() != io::ErrorKind::NotFound => return Err(e),
- _ => {},
+ if let Ok(config_file) = current.join(config_file_name).canonicalize() {
+ match fs::metadata(&config_file) {
+ Err(e) if e.kind() == io::ErrorKind::NotFound => {},
+ Err(e) => return Err(e),
+ Ok(md) if md.is_dir() => {},
+ Ok(_) => return Ok(Some(config_file)),
+ }
}
}
-use crate::consts::{constant_simple, Constant};
+use clippy_utils::consts::{constant_simple, Constant};
use clippy_utils::diagnostics::{span_lint, span_lint_and_help, span_lint_and_sugg, span_lint_and_then};
use clippy_utils::source::snippet;
use clippy_utils::ty::match_type;
IF_CHAIN_STYLE,
if_chain_local_span(cx, local, if_chain_span),
"`let` expression should be inside `then { .. }`",
- )
+ );
}
}
if is_first_if_chain_expr(cx, expr.hir_id, if_chain_span)
&& is_if_chain_then(then_block.stmts, then_block.expr, if_chain_span)
{
- span_lint(cx, IF_CHAIN_STYLE, expr.span, "`if_chain!` only has one `if`")
+ span_lint(cx, IF_CHAIN_STYLE, expr.span, "`if_chain!` only has one `if`");
}
}
}
/// }
/// ```
fn check_item(&mut self, cx: &LateContext<'hir>, item: &'hir Item<'_>) {
- if let ItemKind::Static(ref ty, Mutability::Not, _) = item.kind {
+ if let ItemKind::Static(ty, Mutability::Not, _) = item.kind {
// Normal lint
if_chain! {
// item validation
.hir()
.attrs(item.hir_id())
.iter()
- .filter_map(|ref x| x.doc_str().map(|sym| sym.as_str().to_string()))
+ .filter_map(|x| x.doc_str().map(|sym| sym.as_str().to_string()))
.reduce(|mut acc, sym| {
acc.push_str(&sym);
acc.push('\n');
let mut multi_part = false;
for arg in args {
- let (arg_ty, _) = walk_ptrs_ty_depth(cx.typeck_results().expr_ty(&arg));
+ let (arg_ty, _) = walk_ptrs_ty_depth(cx.typeck_results().expr_ty(arg));
if match_type(cx, arg_ty, &paths::LINT) {
// If we found the lint arg, extract the lint name
if let ExprKind::Path(qpath) = &expr.kind;
if let QPath::Resolved(_, path) = qpath;
- let (expr_ty, _) = walk_ptrs_ty_depth(self.cx.typeck_results().expr_ty(&expr));
+ let (expr_ty, _) = walk_ptrs_ty_depth(self.cx.typeck_results().expr_ty(expr));
if match_type(self.cx, expr_ty, &paths::LINT);
then {
if let hir::def::Res::Def(DefKind::Static, _) = path.res {
}
fn visit_expr(&mut self, expr: &'hir hir::Expr<'hir>) {
- let (expr_ty, _) = walk_ptrs_ty_depth(self.cx.typeck_results().expr_ty(&expr));
+ let (expr_ty, _) = walk_ptrs_ty_depth(self.cx.typeck_results().expr_ty(expr));
if_chain! {
if match_type(self.cx, expr_ty, &paths::APPLICABILITY);
.any(|func_path| match_function_call(self.cx, fn_expr, func_path).is_some());
if found_function {
// These functions are all multi part suggestions
- self.add_single_span_suggestion()
+ self.add_single_span_suggestion();
}
},
ExprKind::MethodCall(path, _path_span, arg, _arg_span) => {
-use crate::consts::{constant, Constant};
use crate::rustc_target::abi::LayoutOf;
+use clippy_utils::consts::{constant, Constant};
use clippy_utils::diagnostics::span_lint_and_sugg;
use clippy_utils::higher;
use clippy_utils::source::snippet_with_applicability;
"use of `File::read_to_string`",
None,
"consider using `fs::read_to_string` instead",
- )
+ );
}
}
}
Applicability::MachineApplicable,
);
},
- )
+ );
}
}
} else if mac.path == sym!(writeln) {
-use crate::consts::{constant_simple, Constant};
+use clippy_utils::consts::{constant_simple, Constant};
use clippy_utils::diagnostics::span_lint_and_help;
use if_chain::if_chain;
use rustc_hir::{BinOpKind, Expr, ExprKind};
| (Ref(l, Mutability::Mut), Ref(r, Mutability::Mut)) => eq_pat(l, r),
(Tuple(l), Tuple(r)) | (Slice(l), Slice(r)) => over(l, r, |l, r| eq_pat(l, r)),
(Path(lq, lp), Path(rq, rp)) => both(lq, rq, |l, r| eq_qself(l, r)) && eq_path(lp, rp),
- (TupleStruct(lp, lfs), TupleStruct(rp, rfs)) => eq_path(lp, rp) && over(lfs, rfs, |l, r| eq_pat(l, r)),
- (Struct(lp, lfs, lr), Struct(rp, rfs, rr)) => {
- lr == rr && eq_path(lp, rp) && unordered_over(lfs, rfs, |lf, rf| eq_field_pat(lf, rf))
+ (TupleStruct(lqself, lp, lfs), TupleStruct(rqself, rp, rfs)) => eq_maybe_qself(lqself, rqself) && eq_path(lp, rp) && over(lfs, rfs, |l, r| eq_pat(l, r)),
+ (Struct(lqself, lp, lfs, lr), Struct(rqself, rp, rfs, rr)) => {
+ lr == rr && eq_maybe_qself(lqself, rqself) &&eq_path(lp, rp) && unordered_over(lfs, rfs, |lf, rf| eq_field_pat(lf, rf))
},
(Or(ls), Or(rs)) => unordered_over(ls, rs, |l, r| eq_pat(l, r)),
(MacCall(l), MacCall(r)) => eq_mac_call(l, r),
l.position == r.position && eq_ty(&l.ty, &r.ty)
}
+pub fn eq_maybe_qself(l: &Option<QSelf>, r: &Option<QSelf>) -> bool {
+ match (l, r) {
+ (Some(l), Some(r)) => eq_qself(l, r),
+ (None, None) => true,
+ _ => false
+ }
+}
+
pub fn eq_path(l: &Path, r: &Path) -> bool {
over(&l.segments, &r.segments, |l, r| eq_path_seg(l, r))
}
(Path(lq, lp), Path(rq, rp)) => both(lq, rq, |l, r| eq_qself(l, r)) && eq_path(lp, rp),
(MacCall(l), MacCall(r)) => eq_mac_call(l, r),
(Struct(lse), Struct(rse)) => {
- eq_path(&lse.path, &rse.path)
+ eq_maybe_qself(&lse.qself, &rse.qself)
+ && eq_path(&lse.path, &rse.path)
&& eq_struct_rest(&lse.rest, &rse.rest)
&& unordered_over(&lse.fields, &rse.fields, |l, r| eq_field(l, r))
},
for attr in get_attr(sess, attrs, name) {
if let Some(ref value) = attr.value_str() {
if let Ok(value) = FromStr::from_str(&value.as_str()) {
- f(value)
+ f(value);
} else {
sess.span_err(attr.span, "not a number");
}
pub fn expr(&mut self, e: &Expr<'_>) -> Option<Constant> {
match e.kind {
ExprKind::Path(ref qpath) => self.fetch_path(qpath, e.hir_id, self.typeck_results.expr_ty(e)),
- ExprKind::Block(ref block, _) => self.block(block),
+ ExprKind::Block(block, _) => self.block(block),
ExprKind::Lit(ref lit) => Some(lit_to_constant(&lit.node, self.typeck_results.expr_ty_opt(e))),
- ExprKind::Array(ref vec) => self.multi(vec).map(Constant::Vec),
- ExprKind::Tup(ref tup) => self.multi(tup).map(Constant::Tuple),
- ExprKind::Repeat(ref value, _) => {
+ ExprKind::Array(vec) => self.multi(vec).map(Constant::Vec),
+ ExprKind::Tup(tup) => self.multi(tup).map(Constant::Tuple),
+ ExprKind::Repeat(value, _) => {
let n = match self.typeck_results.expr_ty(e).kind() {
ty::Array(_, n) => n.try_eval_usize(self.lcx.tcx, self.lcx.param_env)?,
_ => span_bug!(e.span, "typeck error"),
};
self.expr(value).map(|v| Constant::Repeat(Box::new(v), n))
},
- ExprKind::Unary(op, ref operand) => self.expr(operand).and_then(|o| match op {
+ ExprKind::Unary(op, operand) => self.expr(operand).and_then(|o| match op {
UnOp::Not => self.constant_not(&o, self.typeck_results.expr_ty(e)),
UnOp::Neg => self.constant_negate(&o, self.typeck_results.expr_ty(e)),
UnOp::Deref => Some(if let Constant::Ref(r) = o { *r } else { o }),
}),
- ExprKind::If(ref cond, ref then, ref otherwise) => self.ifthenelse(cond, then, *otherwise),
- ExprKind::Binary(op, ref left, ref right) => self.binop(op, left, right),
- ExprKind::Call(ref callee, ref args) => {
+ ExprKind::If(cond, then, ref otherwise) => self.ifthenelse(cond, then, *otherwise),
+ ExprKind::Binary(op, left, right) => self.binop(op, left, right),
+ ExprKind::Call(callee, args) => {
// We only handle a few const functions for now.
if_chain! {
if args.is_empty();
}
}
},
- ExprKind::Index(ref arr, ref index) => self.index(arr, index),
- ExprKind::AddrOf(_, _, ref inner) => self.expr(inner).map(|r| Constant::Ref(Box::new(r))),
+ ExprKind::Index(arr, index) => self.index(arr, index),
+ ExprKind::AddrOf(_, _, inner) => self.expr(inner).map(|r| Constant::Ref(Box::new(r))),
// TODO: add other expressions.
_ => None,
}
)
.ok()
.map(|val| rustc_middle::ty::Const::from_value(self.lcx.tcx, val, ty))?;
- let result = miri_to_const(&result);
+ let result = miri_to_const(result);
if result.is_some() {
self.needed_resolution = true;
}
cx: &LateContext<'_>,
lint: &'static Lint,
hir_id: HirId,
- sp: Span,
+ sp: impl Into<MultiSpan>,
msg: &str,
f: impl FnOnce(&mut DiagnosticBuilder<'_>),
) {
where
I: IntoIterator<Item = (Span, String)>,
{
- multispan_sugg_with_applicability(diag, help_msg, Applicability::Unspecified, sugg)
+ multispan_sugg_with_applicability(diag, help_msg, Applicability::Unspecified, sugg);
}
/// Create a suggestion made from several `span → replacement`.
}
match expr.kind {
- hir::ExprKind::Call(ref path, ref args)
+ hir::ExprKind::Call(path, args)
if matches!(
path.kind,
hir::ExprKind::Path(hir::QPath::LangItem(hir::LangItem::RangeInclusiveNew, _))
limits: ast::RangeLimits::Closed,
})
},
- hir::ExprKind::Struct(ref path, ref fields, None) => match path {
+ hir::ExprKind::Struct(path, fields, None) => match path {
hir::QPath::LangItem(hir::LangItem::RangeFull, _) => Some(Range {
start: None,
end: None,
// }
// ```
if_chain! {
- if let Some(ref expr) = local.init;
+ if let Some(expr) = local.init;
if let hir::ExprKind::Match(_, _, hir::MatchSource::ForLoopDesugar) = expr.kind;
then {
return true;
expr: &'tcx hir::Expr<'tcx>,
) -> Option<(&hir::Pat<'_>, &'tcx hir::Expr<'tcx>, &'tcx hir::Expr<'tcx>, Span)> {
if_chain! {
- if let hir::ExprKind::Match(ref iterexpr, ref arms, hir::MatchSource::ForLoopDesugar) = expr.kind;
- if let hir::ExprKind::Call(_, ref iterargs) = iterexpr.kind;
+ if let hir::ExprKind::Match(iterexpr, arms, hir::MatchSource::ForLoopDesugar) = expr.kind;
+ if let hir::ExprKind::Call(_, iterargs) = iterexpr.kind;
if iterargs.len() == 1 && arms.len() == 1 && arms[0].guard.is_none();
- if let hir::ExprKind::Loop(ref block, ..) = arms[0].body.kind;
+ if let hir::ExprKind::Loop(block, ..) = arms[0].body.kind;
if block.expr.is_none();
if let [ _, _, ref let_stmt, ref body ] = *block.stmts;
- if let hir::StmtKind::Local(ref local) = let_stmt.kind;
- if let hir::StmtKind::Expr(ref expr) = body.kind;
+ if let hir::StmtKind::Local(local) = let_stmt.kind;
+ if let hir::StmtKind::Expr(expr) = body.kind;
then {
return Some((&*local.pat, &iterargs[0], expr, arms[0].span));
}
/// from `vec!`.
pub fn vec_macro<'e>(cx: &LateContext<'_>, expr: &'e hir::Expr<'_>) -> Option<VecArgs<'e>> {
if_chain! {
- if let hir::ExprKind::Call(ref fun, ref args) = expr.kind;
+ if let hir::ExprKind::Call(fun, args) = expr.kind;
if let hir::ExprKind::Path(ref qpath) = fun.kind;
if is_expn_of(fun.span, "vec").is_some();
if let Some(fun_def_id) = cx.qpath_res(qpath, fun.hir_id).opt_def_id();
else if match_def_path(cx, fun_def_id, &paths::SLICE_INTO_VEC) && args.len() == 1 {
// `vec![a, b, c]` case
if_chain! {
- if let hir::ExprKind::Box(ref boxed) = args[0].kind;
- if let hir::ExprKind::Array(ref args) = boxed.kind;
+ if let hir::ExprKind::Box(boxed) = args[0].kind;
+ if let hir::ExprKind::Array(args) = boxed.kind;
then {
return Some(VecArgs::Vec(&*args));
}
/// compared
fn ast_matchblock(matchblock_expr: &'tcx Expr<'tcx>) -> Option<Vec<&Expr<'_>>> {
if_chain! {
- if let ExprKind::Match(ref headerexpr, _, _) = &matchblock_expr.kind;
+ if let ExprKind::Match(headerexpr, _, _) = &matchblock_expr.kind;
if let ExprKind::Tup([lhs, rhs]) = &headerexpr.kind;
if let ExprKind::AddrOf(BorrowKind::Ref, _, lhs) = lhs.kind;
if let ExprKind::AddrOf(BorrowKind::Ref, _, rhs) = rhs.kind;
None
}
- if let ExprKind::Block(ref block, _) = e.kind {
+ if let ExprKind::Block(block, _) = e.kind {
if block.stmts.len() == 1 {
- if let StmtKind::Semi(ref matchexpr) = block.stmts.get(0)?.kind {
+ if let StmtKind::Semi(matchexpr) = block.stmts.get(0)?.kind {
// macros with unique arg: `{debug_}assert!` (e.g., `debug_assert!(some_condition)`)
if_chain! {
- if let ExprKind::If(ref clause, _, _) = matchexpr.kind;
+ if let ExprKind::If(clause, _, _) = matchexpr.kind;
if let ExprKind::Unary(UnOp::Not, condition) = clause.kind;
then {
return Some(vec![condition]);
// debug macros with two args: `debug_assert_{ne, eq}` (e.g., `assert_ne!(a, b)`)
if_chain! {
- if let ExprKind::Block(ref matchblock,_) = matchexpr.kind;
- if let Some(ref matchblock_expr) = matchblock.expr;
+ if let ExprKind::Block(matchblock,_) = matchexpr.kind;
+ if let Some(matchblock_expr) = matchblock.expr;
then {
return ast_matchblock(matchblock_expr);
}
}
} else if let Some(matchblock_expr) = block.expr {
// macros with two args: `assert_{ne, eq}` (e.g., `assert_ne!(a, b)`)
- return ast_matchblock(&matchblock_expr);
+ return ast_matchblock(matchblock_expr);
}
}
None
use crate::differing_macro_contexts;
use crate::source::snippet_opt;
use rustc_ast::ast::InlineAsmTemplatePiece;
-use rustc_data_structures::stable_hasher::{HashStable, StableHasher};
+use rustc_data_structures::fx::FxHasher;
use rustc_hir::def::Res;
use rustc_hir::HirIdMap;
use rustc_hir::{
- BinOpKind, Block, BlockCheckMode, BodyId, BorrowKind, CaptureBy, Expr, ExprField, ExprKind, FnRetTy, GenericArg,
- GenericArgs, Guard, HirId, InlineAsmOperand, Lifetime, LifetimeName, ParamName, Pat, PatField, PatKind, Path,
- PathSegment, QPath, Stmt, StmtKind, Ty, TyKind, TypeBinding,
+ BinOpKind, Block, BodyId, Expr, ExprField, ExprKind, FnRetTy, GenericArg, GenericArgs, Guard, HirId,
+ InlineAsmOperand, Lifetime, LifetimeName, ParamName, Pat, PatField, PatKind, Path, PathSegment, QPath, Stmt,
+ StmtKind, Ty, TyKind, TypeBinding,
};
use rustc_lexer::{tokenize, TokenKind};
use rustc_lint::LateContext;
-use rustc_middle::ich::StableHashingContextProvider;
use rustc_middle::ty::TypeckResults;
use rustc_span::Symbol;
-use std::hash::Hash;
+use std::hash::{Hash, Hasher};
/// Type used to check whether two ast are the same. This is different from the
/// operator
impl HirEqInterExpr<'_, '_, '_> {
pub fn eq_stmt(&mut self, left: &Stmt<'_>, right: &Stmt<'_>) -> bool {
match (&left.kind, &right.kind) {
- (&StmtKind::Local(ref l), &StmtKind::Local(ref r)) => {
+ (&StmtKind::Local(l), &StmtKind::Local(r)) => {
// This additional check ensures that the type of the locals are equivalent even if the init
// expression or type have some inferred parts.
if let Some(typeck) = self.inner.maybe_typeck_results {
- let l_ty = typeck.pat_ty(&l.pat);
- let r_ty = typeck.pat_ty(&r.pat);
+ let l_ty = typeck.pat_ty(l.pat);
+ let r_ty = typeck.pat_ty(r.pat);
if !rustc_middle::ty::TyS::same_type(l_ty, r_ty) {
return false;
}
// these only get added if the init and type is equal.
both(&l.init, &r.init, |l, r| self.eq_expr(l, r))
&& both(&l.ty, &r.ty, |l, r| self.eq_ty(l, r))
- && self.eq_pat(&l.pat, &r.pat)
- },
- (&StmtKind::Expr(ref l), &StmtKind::Expr(ref r)) | (&StmtKind::Semi(ref l), &StmtKind::Semi(ref r)) => {
- self.eq_expr(l, r)
+ && self.eq_pat(l.pat, r.pat)
},
+ (&StmtKind::Expr(l), &StmtKind::Expr(r)) | (&StmtKind::Semi(l), &StmtKind::Semi(r)) => self.eq_expr(l, r),
_ => false,
}
}
left.eq(right)
},
_ => {
- over(&left.stmts, &right.stmts, |l, r| self.eq_stmt(l, r))
+ over(left.stmts, right.stmts, |l, r| self.eq_stmt(l, r))
&& both(&left.expr, &right.expr, |l, r| self.eq_expr(l, r))
},
}
}
+ pub fn eq_body(&mut self, left: BodyId, right: BodyId) -> bool {
+ let cx = self.inner.cx;
+ let eval_const = |body| constant_context(cx, cx.tcx.typeck_body(body)).expr(&cx.tcx.hir().body(body).value);
+ eval_const(left) == eval_const(right)
+ }
+
#[allow(clippy::similar_names)]
pub fn eq_expr(&mut self, left: &Expr<'_>, right: &Expr<'_>) -> bool {
if !self.inner.allow_side_effects && differing_macro_contexts(left.span, right.span) {
&reduce_exprkind(self.inner.cx, &left.kind),
&reduce_exprkind(self.inner.cx, &right.kind),
) {
- (&ExprKind::AddrOf(lb, l_mut, ref le), &ExprKind::AddrOf(rb, r_mut, ref re)) => {
+ (&ExprKind::AddrOf(lb, l_mut, le), &ExprKind::AddrOf(rb, r_mut, re)) => {
lb == rb && l_mut == r_mut && self.eq_expr(le, re)
},
(&ExprKind::Continue(li), &ExprKind::Continue(ri)) => {
both(&li.label, &ri.label, |l, r| l.ident.name == r.ident.name)
},
- (&ExprKind::Assign(ref ll, ref lr, _), &ExprKind::Assign(ref rl, ref rr, _)) => {
+ (&ExprKind::Assign(ll, lr, _), &ExprKind::Assign(rl, rr, _)) => {
self.inner.allow_side_effects && self.eq_expr(ll, rl) && self.eq_expr(lr, rr)
},
- (&ExprKind::AssignOp(ref lo, ref ll, ref lr), &ExprKind::AssignOp(ref ro, ref rl, ref rr)) => {
+ (&ExprKind::AssignOp(ref lo, ll, lr), &ExprKind::AssignOp(ref ro, rl, rr)) => {
self.inner.allow_side_effects && lo.node == ro.node && self.eq_expr(ll, rl) && self.eq_expr(lr, rr)
},
- (&ExprKind::Block(ref l, _), &ExprKind::Block(ref r, _)) => self.eq_block(l, r),
- (&ExprKind::Binary(l_op, ref ll, ref lr), &ExprKind::Binary(r_op, ref rl, ref rr)) => {
+ (&ExprKind::Block(l, _), &ExprKind::Block(r, _)) => self.eq_block(l, r),
+ (&ExprKind::Binary(l_op, ll, lr), &ExprKind::Binary(r_op, rl, rr)) => {
l_op.node == r_op.node && self.eq_expr(ll, rl) && self.eq_expr(lr, rr)
|| swap_binop(l_op.node, ll, lr).map_or(false, |(l_op, ll, lr)| {
l_op == r_op.node && self.eq_expr(ll, rl) && self.eq_expr(lr, rr)
both(&li.label, &ri.label, |l, r| l.ident.name == r.ident.name)
&& both(le, re, |l, r| self.eq_expr(l, r))
},
- (&ExprKind::Box(ref l), &ExprKind::Box(ref r)) => self.eq_expr(l, r),
+ (&ExprKind::Box(l), &ExprKind::Box(r)) => self.eq_expr(l, r),
(&ExprKind::Call(l_fun, l_args), &ExprKind::Call(r_fun, r_args)) => {
self.inner.allow_side_effects && self.eq_expr(l_fun, r_fun) && self.eq_exprs(l_args, r_args)
},
- (&ExprKind::Cast(ref lx, ref lt), &ExprKind::Cast(ref rx, ref rt))
- | (&ExprKind::Type(ref lx, ref lt), &ExprKind::Type(ref rx, ref rt)) => {
+ (&ExprKind::Cast(lx, lt), &ExprKind::Cast(rx, rt)) | (&ExprKind::Type(lx, lt), &ExprKind::Type(rx, rt)) => {
self.eq_expr(lx, rx) && self.eq_ty(lt, rt)
},
- (&ExprKind::Field(ref l_f_exp, ref l_f_ident), &ExprKind::Field(ref r_f_exp, ref r_f_ident)) => {
+ (&ExprKind::Field(l_f_exp, ref l_f_ident), &ExprKind::Field(r_f_exp, ref r_f_ident)) => {
l_f_ident.name == r_f_ident.name && self.eq_expr(l_f_exp, r_f_exp)
},
- (&ExprKind::Index(ref la, ref li), &ExprKind::Index(ref ra, ref ri)) => {
- self.eq_expr(la, ra) && self.eq_expr(li, ri)
- },
- (&ExprKind::If(ref lc, ref lt, ref le), &ExprKind::If(ref rc, ref rt, ref re)) => {
+ (&ExprKind::Index(la, li), &ExprKind::Index(ra, ri)) => self.eq_expr(la, ra) && self.eq_expr(li, ri),
+ (&ExprKind::If(lc, lt, ref le), &ExprKind::If(rc, rt, ref re)) => {
self.eq_expr(lc, rc) && self.eq_expr(&**lt, &**rt) && both(le, re, |l, r| self.eq_expr(l, r))
},
(&ExprKind::Lit(ref l), &ExprKind::Lit(ref r)) => l.node == r.node,
- (&ExprKind::Loop(ref lb, ref ll, ref lls, _), &ExprKind::Loop(ref rb, ref rl, ref rls, _)) => {
+ (&ExprKind::Loop(lb, ref ll, ref lls, _), &ExprKind::Loop(rb, ref rl, ref rls, _)) => {
lls == rls && self.eq_block(lb, rb) && both(ll, rl, |l, r| l.ident.name == r.ident.name)
},
- (&ExprKind::Match(ref le, ref la, ref ls), &ExprKind::Match(ref re, ref ra, ref rs)) => {
+ (&ExprKind::Match(le, la, ref ls), &ExprKind::Match(re, ra, ref rs)) => {
ls == rs
&& self.eq_expr(le, re)
&& over(la, ra, |l, r| {
- self.eq_pat(&l.pat, &r.pat)
+ self.eq_pat(l.pat, r.pat)
&& both(&l.guard, &r.guard, |l, r| self.eq_guard(l, r))
- && self.eq_expr(&l.body, &r.body)
+ && self.eq_expr(l.body, r.body)
})
},
(&ExprKind::MethodCall(l_path, _, l_args, _), &ExprKind::MethodCall(r_path, _, r_args, _)) => {
self.inner.allow_side_effects && self.eq_path_segment(l_path, r_path) && self.eq_exprs(l_args, r_args)
},
- (&ExprKind::Repeat(ref le, ref ll_id), &ExprKind::Repeat(ref re, ref rl_id)) => {
- let mut celcx = constant_context(self.inner.cx, self.inner.cx.tcx.typeck_body(ll_id.body));
- let ll = celcx.expr(&self.inner.cx.tcx.hir().body(ll_id.body).value);
- let mut celcx = constant_context(self.inner.cx, self.inner.cx.tcx.typeck_body(rl_id.body));
- let rl = celcx.expr(&self.inner.cx.tcx.hir().body(rl_id.body).value);
-
- self.eq_expr(le, re) && ll == rl
+ (&ExprKind::Repeat(le, ref ll_id), &ExprKind::Repeat(re, ref rl_id)) => {
+ self.eq_expr(le, re) && self.eq_body(ll_id.body, rl_id.body)
},
(&ExprKind::Ret(ref l), &ExprKind::Ret(ref r)) => both(l, r, |l, r| self.eq_expr(l, r)),
(&ExprKind::Path(ref l), &ExprKind::Path(ref r)) => self.eq_qpath(l, r),
- (&ExprKind::Struct(ref l_path, ref lf, ref lo), &ExprKind::Struct(ref r_path, ref rf, ref ro)) => {
+ (&ExprKind::Struct(l_path, lf, ref lo), &ExprKind::Struct(r_path, rf, ref ro)) => {
self.eq_qpath(l_path, r_path)
&& both(lo, ro, |l, r| self.eq_expr(l, r))
&& over(lf, rf, |l, r| self.eq_expr_field(l, r))
},
(&ExprKind::Tup(l_tup), &ExprKind::Tup(r_tup)) => self.eq_exprs(l_tup, r_tup),
- (&ExprKind::Unary(l_op, ref le), &ExprKind::Unary(r_op, ref re)) => l_op == r_op && self.eq_expr(le, re),
+ (&ExprKind::Unary(l_op, le), &ExprKind::Unary(r_op, re)) => l_op == r_op && self.eq_expr(le, re),
(&ExprKind::Array(l), &ExprKind::Array(r)) => self.eq_exprs(l, r),
- (&ExprKind::DropTemps(ref le), &ExprKind::DropTemps(ref re)) => self.eq_expr(le, re),
+ (&ExprKind::DropTemps(le), &ExprKind::DropTemps(re)) => self.eq_expr(le, re),
_ => false,
};
is_eq || self.inner.expr_fallback.as_mut().map_or(false, |f| f(left, right))
}
fn eq_expr_field(&mut self, left: &ExprField<'_>, right: &ExprField<'_>) -> bool {
- left.ident.name == right.ident.name && self.eq_expr(&left.expr, &right.expr)
+ left.ident.name == right.ident.name && self.eq_expr(left.expr, right.expr)
}
fn eq_guard(&mut self, left: &Guard<'_>, right: &Guard<'_>) -> bool {
fn eq_generic_arg(&mut self, left: &GenericArg<'_>, right: &GenericArg<'_>) -> bool {
match (left, right) {
+ (GenericArg::Const(l), GenericArg::Const(r)) => self.eq_body(l.value.body, r.value.body),
(GenericArg::Lifetime(l_lt), GenericArg::Lifetime(r_lt)) => Self::eq_lifetime(l_lt, r_lt),
(GenericArg::Type(l_ty), GenericArg::Type(r_ty)) => self.eq_ty(l_ty, r_ty),
_ => false,
/// Checks whether two patterns are the same.
fn eq_pat(&mut self, left: &Pat<'_>, right: &Pat<'_>) -> bool {
match (&left.kind, &right.kind) {
- (&PatKind::Box(ref l), &PatKind::Box(ref r)) => self.eq_pat(l, r),
- (&PatKind::Struct(ref lp, ref la, ..), &PatKind::Struct(ref rp, ref ra, ..)) => {
+ (&PatKind::Box(l), &PatKind::Box(r)) => self.eq_pat(l, r),
+ (&PatKind::Struct(ref lp, la, ..), &PatKind::Struct(ref rp, ra, ..)) => {
self.eq_qpath(lp, rp) && over(la, ra, |l, r| self.eq_pat_field(l, r))
},
- (&PatKind::TupleStruct(ref lp, ref la, ls), &PatKind::TupleStruct(ref rp, ref ra, rs)) => {
+ (&PatKind::TupleStruct(ref lp, la, ls), &PatKind::TupleStruct(ref rp, ra, rs)) => {
self.eq_qpath(lp, rp) && over(la, ra, |l, r| self.eq_pat(l, r)) && ls == rs
},
(&PatKind::Binding(lb, li, _, ref lp), &PatKind::Binding(rb, ri, _, ref rp)) => {
eq
},
(&PatKind::Path(ref l), &PatKind::Path(ref r)) => self.eq_qpath(l, r),
- (&PatKind::Lit(ref l), &PatKind::Lit(ref r)) => self.eq_expr(l, r),
- (&PatKind::Tuple(ref l, ls), &PatKind::Tuple(ref r, rs)) => {
- ls == rs && over(l, r, |l, r| self.eq_pat(l, r))
- },
+ (&PatKind::Lit(l), &PatKind::Lit(r)) => self.eq_expr(l, r),
+ (&PatKind::Tuple(l, ls), &PatKind::Tuple(r, rs)) => ls == rs && over(l, r, |l, r| self.eq_pat(l, r)),
(&PatKind::Range(ref ls, ref le, li), &PatKind::Range(ref rs, ref re, ri)) => {
both(ls, rs, |a, b| self.eq_expr(a, b)) && both(le, re, |a, b| self.eq_expr(a, b)) && (li == ri)
},
- (&PatKind::Ref(ref le, ref lm), &PatKind::Ref(ref re, ref rm)) => lm == rm && self.eq_pat(le, re),
- (&PatKind::Slice(ref ls, ref li, ref le), &PatKind::Slice(ref rs, ref ri, ref re)) => {
+ (&PatKind::Ref(le, ref lm), &PatKind::Ref(re, ref rm)) => lm == rm && self.eq_pat(le, re),
+ (&PatKind::Slice(ls, ref li, le), &PatKind::Slice(rs, ref ri, re)) => {
over(ls, rs, |l, r| self.eq_pat(l, r))
&& over(le, re, |l, r| self.eq_pat(l, r))
&& both(li, ri, |l, r| self.eq_pat(l, r))
#[allow(clippy::similar_names)]
fn eq_qpath(&mut self, left: &QPath<'_>, right: &QPath<'_>) -> bool {
match (left, right) {
- (&QPath::Resolved(ref lty, ref lpath), &QPath::Resolved(ref rty, ref rpath)) => {
+ (&QPath::Resolved(ref lty, lpath), &QPath::Resolved(ref rty, rpath)) => {
both(lty, rty, |l, r| self.eq_ty(l, r)) && self.eq_path(lpath, rpath)
},
- (&QPath::TypeRelative(ref lty, ref lseg), &QPath::TypeRelative(ref rty, ref rseg)) => {
+ (&QPath::TypeRelative(lty, lseg), &QPath::TypeRelative(rty, rseg)) => {
self.eq_ty(lty, rty) && self.eq_path_segment(lseg, rseg)
},
(&QPath::LangItem(llang_item, _), &QPath::LangItem(rlang_item, _)) => llang_item == rlang_item,
match (left.res, right.res) {
(Res::Local(l), Res::Local(r)) => l == r || self.locals.get(&l) == Some(&r),
(Res::Local(_), _) | (_, Res::Local(_)) => false,
- _ => over(&left.segments, &right.segments, |l, r| self.eq_path_segment(l, r)),
+ _ => over(left.segments, right.segments, |l, r| self.eq_path_segment(l, r)),
}
}
fn eq_path_parameters(&mut self, left: &GenericArgs<'_>, right: &GenericArgs<'_>) -> bool {
if !(left.parenthesized || right.parenthesized) {
- over(&left.args, &right.args, |l, r| self.eq_generic_arg(l, r)) // FIXME(flip1995): may not work
- && over(&left.bindings, &right.bindings, |l, r| self.eq_type_binding(l, r))
+ over(left.args, right.args, |l, r| self.eq_generic_arg(l, r)) // FIXME(flip1995): may not work
+ && over(left.bindings, right.bindings, |l, r| self.eq_type_binding(l, r))
} else if left.parenthesized && right.parenthesized {
over(left.inputs(), right.inputs(), |l, r| self.eq_ty(l, r))
&& both(&Some(&left.bindings[0].ty()), &Some(&right.bindings[0].ty()), |l, r| {
#[allow(clippy::similar_names)]
fn eq_ty(&mut self, left: &Ty<'_>, right: &Ty<'_>) -> bool {
match (&left.kind, &right.kind) {
- (&TyKind::Slice(ref l_vec), &TyKind::Slice(ref r_vec)) => self.eq_ty(l_vec, r_vec),
- (&TyKind::Array(ref lt, ref ll_id), &TyKind::Array(ref rt, ref rl_id)) => {
- let cx = self.inner.cx;
- let eval_const =
- |body| constant_context(cx, cx.tcx.typeck_body(body)).expr(&cx.tcx.hir().body(body).value);
- self.eq_ty(lt, rt) && eval_const(ll_id.body) == eval_const(rl_id.body)
+ (&TyKind::Slice(l_vec), &TyKind::Slice(r_vec)) => self.eq_ty(l_vec, r_vec),
+ (&TyKind::Array(lt, ref ll_id), &TyKind::Array(rt, ref rl_id)) => {
+ self.eq_ty(lt, rt) && self.eq_body(ll_id.body, rl_id.body)
},
(&TyKind::Ptr(ref l_mut), &TyKind::Ptr(ref r_mut)) => {
l_mut.mutbl == r_mut.mutbl && self.eq_ty(&*l_mut.ty, &*r_mut.ty)
l_rmut.mutbl == r_rmut.mutbl && self.eq_ty(&*l_rmut.ty, &*r_rmut.ty)
},
(&TyKind::Path(ref l), &TyKind::Path(ref r)) => self.eq_qpath(l, r),
- (&TyKind::Tup(ref l), &TyKind::Tup(ref r)) => over(l, r, |l, r| self.eq_ty(l, r)),
+ (&TyKind::Tup(l), &TyKind::Tup(r)) => over(l, r, |l, r| self.eq_ty(l, r)),
(&TyKind::Infer, &TyKind::Infer) => true,
_ => false,
}
}
fn eq_type_binding(&mut self, left: &TypeBinding<'_>, right: &TypeBinding<'_>) -> bool {
- left.ident.name == right.ident.name && self.eq_ty(&left.ty(), &right.ty())
+ left.ident.name == right.ident.name && self.eq_ty(left.ty(), right.ty())
}
}
/// Context used to evaluate constant expressions.
cx: &'a LateContext<'tcx>,
maybe_typeck_results: Option<&'tcx TypeckResults<'tcx>>,
- s: StableHasher,
+ s: FxHasher,
}
impl<'a, 'tcx> SpanlessHash<'a, 'tcx> {
Self {
cx,
maybe_typeck_results: cx.maybe_typeck_results(),
- s: StableHasher::new(),
+ s: FxHasher::default(),
}
}
self.hash_stmt(s);
}
- if let Some(ref e) = b.expr {
+ if let Some(e) = b.expr {
self.hash_expr(e);
}
- match b.rules {
- BlockCheckMode::DefaultBlock => 0,
- BlockCheckMode::UnsafeBlock(_) => 1,
- BlockCheckMode::PushUnsafeBlock(_) => 2,
- BlockCheckMode::PopUnsafeBlock(_) => 3,
- }
- .hash(&mut self.s);
+ std::mem::discriminant(&b.rules).hash(&mut self.s);
}
#[allow(clippy::many_single_char_names, clippy::too_many_lines)]
// const hashing may result in the same hash as some unrelated node, so add a sort of
// discriminant depending on which path we're choosing next
- simple_const.is_some().hash(&mut self.s);
-
- if let Some(e) = simple_const {
- return e.hash(&mut self.s);
+ simple_const.hash(&mut self.s);
+ if simple_const.is_some() {
+ return;
}
std::mem::discriminant(&e.kind).hash(&mut self.s);
match e.kind {
- ExprKind::AddrOf(kind, m, ref e) => {
- match kind {
- BorrowKind::Ref => 0,
- BorrowKind::Raw => 1,
- }
- .hash(&mut self.s);
+ ExprKind::AddrOf(kind, m, e) => {
+ std::mem::discriminant(&kind).hash(&mut self.s);
m.hash(&mut self.s);
self.hash_expr(e);
},
self.hash_name(i.ident.name);
}
},
- ExprKind::Assign(ref l, ref r, _) => {
+ ExprKind::Assign(l, r, _) => {
self.hash_expr(l);
self.hash_expr(r);
},
- ExprKind::AssignOp(ref o, ref l, ref r) => {
- o.node
- .hash_stable(&mut self.cx.tcx.get_stable_hashing_context(), &mut self.s);
+ ExprKind::AssignOp(ref o, l, r) => {
+ std::mem::discriminant(&o.node).hash(&mut self.s);
self.hash_expr(l);
self.hash_expr(r);
},
- ExprKind::Block(ref b, _) => {
+ ExprKind::Block(b, _) => {
self.hash_block(b);
},
- ExprKind::Binary(op, ref l, ref r) => {
- op.node
- .hash_stable(&mut self.cx.tcx.get_stable_hashing_context(), &mut self.s);
+ ExprKind::Binary(op, l, r) => {
+ std::mem::discriminant(&op.node).hash(&mut self.s);
self.hash_expr(l);
self.hash_expr(r);
},
if let Some(i) = i.label {
self.hash_name(i.ident.name);
}
- if let Some(ref j) = *j {
+ if let Some(j) = *j {
self.hash_expr(&*j);
}
},
- ExprKind::Box(ref e) | ExprKind::DropTemps(ref e) | ExprKind::Yield(ref e, _) => {
+ ExprKind::Box(e) | ExprKind::DropTemps(e) | ExprKind::Yield(e, _) => {
self.hash_expr(e);
},
- ExprKind::Call(ref fun, args) => {
+ ExprKind::Call(fun, args) => {
self.hash_expr(fun);
self.hash_exprs(args);
},
- ExprKind::Cast(ref e, ref ty) | ExprKind::Type(ref e, ref ty) => {
+ ExprKind::Cast(e, ty) | ExprKind::Type(e, ty) => {
self.hash_expr(e);
self.hash_ty(ty);
},
ExprKind::Closure(cap, _, eid, _, _) => {
- match cap {
- CaptureBy::Value => 0,
- CaptureBy::Ref => 1,
- }
- .hash(&mut self.s);
+ std::mem::discriminant(&cap).hash(&mut self.s);
// closures inherit TypeckResults
self.hash_expr(&self.cx.tcx.hir().body(eid).value);
},
- ExprKind::Field(ref e, ref f) => {
+ ExprKind::Field(e, ref f) => {
self.hash_expr(e);
self.hash_name(f.name);
},
- ExprKind::Index(ref a, ref i) => {
+ ExprKind::Index(a, i) => {
self.hash_expr(a);
self.hash_expr(i);
},
- ExprKind::InlineAsm(ref asm) => {
+ ExprKind::InlineAsm(asm) => {
for piece in asm.template {
match piece {
InlineAsmTemplatePiece::String(s) => s.hash(&mut self.s),
ExprKind::Lit(ref l) => {
l.node.hash(&mut self.s);
},
- ExprKind::Loop(ref b, ref i, ..) => {
+ ExprKind::Loop(b, ref i, ..) => {
self.hash_block(b);
if let Some(i) = *i {
self.hash_name(i.ident.name);
}
},
- ExprKind::If(ref cond, ref then, ref else_opt) => {
- let c: fn(_, _, _) -> _ = ExprKind::If;
- c.hash(&mut self.s);
+ ExprKind::If(cond, then, ref else_opt) => {
self.hash_expr(cond);
- self.hash_expr(&**then);
- if let Some(ref e) = *else_opt {
+ self.hash_expr(then);
+ if let Some(e) = *else_opt {
self.hash_expr(e);
}
},
- ExprKind::Match(ref e, arms, ref s) => {
+ ExprKind::Match(e, arms, ref s) => {
self.hash_expr(e);
for arm in arms {
if let Some(ref e) = arm.guard {
self.hash_guard(e);
}
- self.hash_expr(&arm.body);
+ self.hash_expr(arm.body);
}
s.hash(&mut self.s);
},
- ExprKind::MethodCall(ref path, ref _tys, args, ref _fn_span) => {
+ ExprKind::MethodCall(path, ref _tys, args, ref _fn_span) => {
self.hash_name(path.ident.name);
self.hash_exprs(args);
},
ExprKind::ConstBlock(ref l_id) => {
self.hash_body(l_id.body);
},
- ExprKind::Repeat(ref e, ref l_id) => {
+ ExprKind::Repeat(e, ref l_id) => {
self.hash_expr(e);
self.hash_body(l_id.body);
},
ExprKind::Ret(ref e) => {
- if let Some(ref e) = *e {
+ if let Some(e) = *e {
self.hash_expr(e);
}
},
ExprKind::Path(ref qpath) => {
self.hash_qpath(qpath);
},
- ExprKind::Struct(ref path, fields, ref expr) => {
+ ExprKind::Struct(path, fields, ref expr) => {
self.hash_qpath(path);
for f in fields {
self.hash_name(f.ident.name);
- self.hash_expr(&f.expr);
+ self.hash_expr(f.expr);
}
- if let Some(ref e) = *expr {
+ if let Some(e) = *expr {
self.hash_expr(e);
}
},
ExprKind::Array(v) => {
self.hash_exprs(v);
},
- ExprKind::Unary(lop, ref le) => {
- lop.hash_stable(&mut self.cx.tcx.get_stable_hashing_context(), &mut self.s);
+ ExprKind::Unary(lop, le) => {
+ std::mem::discriminant(&lop).hash(&mut self.s);
self.hash_expr(le);
},
}
}
pub fn hash_name(&mut self, n: Symbol) {
- n.as_str().hash(&mut self.s);
+ n.hash(&mut self.s);
}
pub fn hash_qpath(&mut self, p: &QPath<'_>) {
match *p {
- QPath::Resolved(_, ref path) => {
+ QPath::Resolved(_, path) => {
self.hash_path(path);
},
- QPath::TypeRelative(_, ref path) => {
+ QPath::TypeRelative(_, path) => {
self.hash_name(path.ident.name);
},
QPath::LangItem(lang_item, ..) => {
- lang_item.hash_stable(&mut self.cx.tcx.get_stable_hashing_context(), &mut self.s);
+ std::mem::discriminant(&lang_item).hash(&mut self.s);
},
}
// self.maybe_typeck_results.unwrap().qpath_res(p, id).hash(&mut self.s);
std::mem::discriminant(&pat.kind).hash(&mut self.s);
match pat.kind {
PatKind::Binding(ann, _, _, pat) => {
- ann.hash_stable(&mut self.cx.tcx.get_stable_hashing_context(), &mut self.s);
+ std::mem::discriminant(&ann).hash(&mut self.s);
if let Some(pat) = pat {
self.hash_pat(pat);
}
if let Some(e) = e {
self.hash_expr(e);
}
- i.hash_stable(&mut self.cx.tcx.get_stable_hashing_context(), &mut self.s);
+ std::mem::discriminant(&i).hash(&mut self.s);
},
- PatKind::Ref(pat, m) => {
+ PatKind::Ref(pat, mu) => {
self.hash_pat(pat);
- m.hash(&mut self.s);
+ std::mem::discriminant(&mu).hash(&mut self.s);
},
PatKind::Slice(l, m, r) => {
for pat in l {
self.hash_name(f.ident.name);
self.hash_pat(f.pat);
}
- e.hash(&mut self.s)
+ e.hash(&mut self.s);
},
PatKind::Tuple(pats, e) => {
for pat in pats {
_ => {
for seg in path.segments {
self.hash_name(seg.ident.name);
+ self.hash_generic_args(seg.args().args);
}
},
}
match &b.kind {
StmtKind::Local(local) => {
self.hash_pat(local.pat);
- if let Some(ref init) = local.init {
+ if let Some(init) = local.init {
self.hash_expr(init);
}
},
pub fn hash_guard(&mut self, g: &Guard<'_>) {
match g {
- Guard::If(ref expr) | Guard::IfLet(_, ref expr) => {
+ Guard::If(expr) | Guard::IfLet(_, expr) => {
self.hash_expr(expr);
},
}
self.hash_body(anon_const.body);
},
TyKind::Ptr(ref mut_ty) => {
- self.hash_ty(&mut_ty.ty);
+ self.hash_ty(mut_ty.ty);
mut_ty.mutbl.hash(&mut self.s);
},
TyKind::Rptr(lifetime, ref mut_ty) => {
self.hash_lifetime(lifetime);
- self.hash_ty(&mut_ty.ty);
+ self.hash_ty(mut_ty.ty);
mut_ty.mutbl.hash(&mut self.s);
},
TyKind::BareFn(bfn) => {
bfn.unsafety.hash(&mut self.s);
bfn.abi.hash(&mut self.s);
for arg in bfn.decl.inputs {
- self.hash_ty(&arg);
+ self.hash_ty(arg);
}
+ std::mem::discriminant(&bfn.decl.output).hash(&mut self.s);
match bfn.decl.output {
- FnRetTy::DefaultReturn(_) => {
- ().hash(&mut self.s);
- },
- FnRetTy::Return(ref ty) => {
+ FnRetTy::DefaultReturn(_) => {},
+ FnRetTy::Return(ty) => {
self.hash_ty(ty);
},
}
self.hash_ty(ty);
}
},
- TyKind::Path(ref qpath) => match qpath {
- QPath::Resolved(ref maybe_ty, ref path) => {
- if let Some(ref ty) = maybe_ty {
- self.hash_ty(ty);
- }
- for segment in path.segments {
- segment.ident.name.hash(&mut self.s);
- self.hash_generic_args(segment.args().args);
- }
- },
- QPath::TypeRelative(ref ty, ref segment) => {
- self.hash_ty(ty);
- segment.ident.name.hash(&mut self.s);
- },
- QPath::LangItem(lang_item, ..) => {
- lang_item.hash(&mut self.s);
- },
- },
+ TyKind::Path(ref qpath) => self.hash_qpath(qpath),
TyKind::OpaqueDef(_, arg_list) => {
self.hash_generic_args(arg_list);
},
use if_chain::if_chain;
use rustc_ast::ast::{self, Attribute, BorrowKind, LitKind};
-use rustc_data_structures::fx::FxHashMap;
+use rustc_data_structures::unhash::UnhashMap;
use rustc_hir as hir;
use rustc_hir::def::{DefKind, Res};
use rustc_hir::def_id::DefId;
/// Checks if an expression references a variable of the given name.
pub fn match_var(expr: &Expr<'_>, var: Symbol) -> bool {
- if let ExprKind::Path(QPath::Resolved(None, ref path)) = expr.kind {
+ if let ExprKind::Path(QPath::Resolved(None, path)) = expr.kind {
if let [p] = path.segments {
return p.ident.name == var;
}
pub fn last_path_segment<'tcx>(path: &QPath<'tcx>) -> &'tcx PathSegment<'tcx> {
match *path {
- QPath::Resolved(_, ref path) => path.segments.last().expect("A path must have at least one segment"),
- QPath::TypeRelative(_, ref seg) => seg,
+ QPath::Resolved(_, path) => path.segments.last().expect("A path must have at least one segment"),
+ QPath::TypeRelative(_, seg) => seg,
QPath::LangItem(..) => panic!("last_path_segment: lang item has no path segments"),
}
}
pub fn single_segment_path<'tcx>(path: &QPath<'tcx>) -> Option<&'tcx PathSegment<'tcx>> {
match *path {
- QPath::Resolved(_, ref path) => path.segments.get(0),
- QPath::TypeRelative(_, ref seg) => Some(seg),
+ QPath::Resolved(_, path) => path.segments.get(0),
+ QPath::TypeRelative(_, seg) => Some(seg),
QPath::LangItem(..) => None,
}
}
/// ```
pub fn match_qpath(path: &QPath<'_>, segments: &[&str]) -> bool {
match *path {
- QPath::Resolved(_, ref path) => match_path(path, segments),
- QPath::TypeRelative(ref ty, ref segment) => match ty.kind {
+ QPath::Resolved(_, path) => match_path(path, segments),
+ QPath::TypeRelative(ty, segment) => match ty.kind {
TyKind::Path(ref inner_path) => {
if let [prefix @ .., end] = segments {
if match_qpath(inner_path, prefix) {
/// If the expression is a path to a local, returns the canonical `HirId` of the local.
pub fn path_to_local(expr: &Expr<'_>) -> Option<HirId> {
- if let ExprKind::Path(QPath::Resolved(None, ref path)) = expr.kind {
+ if let ExprKind::Path(QPath::Resolved(None, path)) = expr.kind {
if let Res::Local(id) = path.res {
return Some(id);
}
let mut matched = Vec::with_capacity(methods.len());
for method_name in methods.iter().rev() {
// method chains are stored last -> first
- if let ExprKind::MethodCall(ref path, _, ref args, _) = current.kind {
+ if let ExprKind::MethodCall(path, _, args, _) = current.kind {
if path.ident.name.as_str() == *method_name {
if args.iter().any(|e| e.span.from_expansion()) {
return None;
}
- matched.push(&**args); // build up `matched` backwards
- current = &args[0] // go to parent expression
+ matched.push(args); // build up `matched` backwards
+ current = &args[0]; // go to parent expression
} else {
return None;
}
match pat.kind {
PatKind::Binding(.., ref spname, _) => Some(spname.name),
PatKind::Path(ref qpath) => single_segment_path(qpath).map(|ps| ps.ident.name),
- PatKind::Box(ref p) | PatKind::Ref(ref p, _) => get_pat_name(&*p),
+ PatKind::Box(p) | PatKind::Ref(p, _) => get_pat_name(&*p),
_ => None,
}
}
kind: ImplItemKind::Fn(_, eid),
..
}) => match cx.tcx.hir().body(eid).value.kind {
- ExprKind::Block(ref block, _) => Some(block),
+ ExprKind::Block(block, _) => Some(block),
_ => None,
},
_ => None,
/// Checks if an expression is constructing a tuple-like enum variant or struct
pub fn is_ctor_or_promotable_const_function(cx: &LateContext<'_>, expr: &Expr<'_>) -> bool {
- if let ExprKind::Call(ref fun, _) = expr.kind {
+ if let ExprKind::Call(fun, _) = expr.kind {
if let ExprKind::Path(ref qp) = fun.kind {
let res = cx.qpath_res(qp, fun.hir_id);
return match res {
match pat.kind {
PatKind::Wild => false,
PatKind::Binding(_, _, _, pat) => pat.map_or(false, |pat| is_refutable(cx, pat)),
- PatKind::Box(ref pat) | PatKind::Ref(ref pat, _) => is_refutable(cx, pat),
+ PatKind::Box(pat) | PatKind::Ref(pat, _) => is_refutable(cx, pat),
PatKind::Lit(..) | PatKind::Range(..) => true,
PatKind::Path(ref qpath) => is_enum_variant(cx, qpath, pat.hir_id),
- PatKind::Or(ref pats) => {
+ PatKind::Or(pats) => {
// TODO: should be the honest check, that pats is exhaustive set
are_refutable(cx, pats.iter().map(|pat| &**pat))
},
- PatKind::Tuple(ref pats, _) => are_refutable(cx, pats.iter().map(|pat| &**pat)),
- PatKind::Struct(ref qpath, ref fields, _) => {
+ PatKind::Tuple(pats, _) => are_refutable(cx, pats.iter().map(|pat| &**pat)),
+ PatKind::Struct(ref qpath, fields, _) => {
is_enum_variant(cx, qpath, pat.hir_id) || are_refutable(cx, fields.iter().map(|field| &*field.pat))
},
- PatKind::TupleStruct(ref qpath, ref pats, _) => {
+ PatKind::TupleStruct(ref qpath, pats, _) => {
is_enum_variant(cx, qpath, pat.hir_id) || are_refutable(cx, pats.iter().map(|pat| &**pat))
},
- PatKind::Slice(ref head, ref middle, ref tail) => {
+ PatKind::Slice(head, ref middle, tail) => {
match &cx.typeck_results().node_type(pat.hir_id).kind() {
rustc_ty::Slice(..) => {
// [..] is the only irrefutable slice pattern.
/// the function once on the given pattern.
pub fn recurse_or_patterns<'tcx, F: FnMut(&'tcx Pat<'tcx>)>(pat: &'tcx Pat<'tcx>, mut f: F) {
if let PatKind::Or(pats) = pat.kind {
- pats.iter().copied().for_each(f)
+ pats.iter().copied().for_each(f);
} else {
- f(pat)
+ f(pat);
}
}
/// Ie. `x`, `{ x }` and `{{{{ x }}}}` all give `x`. `{ x; y }` and `{}` return
/// themselves.
pub fn remove_blocks<'tcx>(mut expr: &'tcx Expr<'tcx>) -> &'tcx Expr<'tcx> {
- while let ExprKind::Block(ref block, ..) = expr.kind {
+ while let ExprKind::Block(block, ..) = expr.kind {
match (block.stmts.is_empty(), block.expr.as_ref()) {
(true, Some(e)) => expr = e,
_ => break,
pub fn is_self_ty(slf: &hir::Ty<'_>) -> bool {
if_chain! {
- if let TyKind::Path(QPath::Resolved(None, ref path)) = slf.kind;
+ if let TyKind::Path(QPath::Resolved(None, path)) = slf.kind;
if let Res::SelfTy(..) = path.res;
then {
return true
pub fn is_try<'tcx>(cx: &LateContext<'_>, expr: &'tcx Expr<'tcx>) -> Option<&'tcx Expr<'tcx>> {
fn is_ok(cx: &LateContext<'_>, arm: &Arm<'_>) -> bool {
if_chain! {
- if let PatKind::TupleStruct(ref path, ref pat, None) = arm.pat.kind;
+ if let PatKind::TupleStruct(ref path, pat, None) = arm.pat.kind;
if is_lang_ctor(cx, path, ResultOk);
if let PatKind::Binding(_, hir_id, _, None) = pat[0].kind;
if path_to_local_id(arm.body, hir_id);
}
}
- if let ExprKind::Match(_, ref arms, ref source) = expr.kind {
+ if let ExprKind::Match(_, arms, ref source) = expr.kind {
// desugared from a `?` operator
if let MatchSource::TryDesugar = *source {
return Some(expr);
path: &[&str],
) -> Option<&'tcx [Expr<'tcx>]> {
if_chain! {
- if let ExprKind::Call(ref fun, ref args) = expr.kind;
+ if let ExprKind::Call(fun, args) = expr.kind;
if let ExprKind::Path(ref qpath) = fun.kind;
if let Some(fun_def_id) = cx.qpath_res(qpath, fun.hir_id).opt_def_id();
if match_def_path(cx, fun_def_id, path);
then {
- return Some(&args)
+ return Some(args)
}
};
None
let mut conds = Vec::new();
let mut blocks: Vec<&Block<'_>> = Vec::new();
- while let ExprKind::If(ref cond, ref then_expr, ref else_expr) = expr.kind {
- conds.push(&**cond);
- if let ExprKind::Block(ref block, _) = then_expr.kind {
+ while let ExprKind::If(cond, then_expr, ref else_expr) = expr.kind {
+ conds.push(cond);
+ if let ExprKind::Block(block, _) = then_expr.kind {
blocks.push(block);
} else {
panic!("ExprKind::If node is not an ExprKind::Block");
}
- if let Some(ref else_expr) = *else_expr {
+ if let Some(else_expr) = *else_expr {
expr = else_expr;
} else {
break;
// final `else {..}`
if !blocks.is_empty() {
- if let ExprKind::Block(ref block, _) = expr.kind {
- blocks.push(&**block);
+ if let ExprKind::Block(block, _) = expr.kind {
+ blocks.push(block);
}
}
// check if expr is calling method or function with #[must_use] attribute
pub fn is_must_use_func_call(cx: &LateContext<'_>, expr: &Expr<'_>) -> bool {
let did = match expr.kind {
- ExprKind::Call(ref path, _) => if_chain! {
+ ExprKind::Call(path, _) => if_chain! {
if let ExprKind::Path(ref qpath) = path.kind;
if let def::Res::Def(_, did) = cx.qpath_res(qpath, path.hir_id);
then {
_ => None,
};
- did.map_or(false, |did| must_use_attr(&cx.tcx.get_attrs(did)).is_some())
+ did.map_or(false, |did| must_use_attr(cx.tcx.get_attrs(did)).is_some())
}
/// Gets the node where an expression is either used, or it's type is unified with another branch.
Hash: Fn(&T) -> u64,
Eq: Fn(&T, &T) -> bool,
{
- if exprs.len() == 2 && eq(&exprs[0], &exprs[1]) {
- return vec![(&exprs[0], &exprs[1])];
+ match exprs {
+ [a, b] if eq(a, b) => return vec![(a, b)],
+ _ if exprs.len() <= 2 => return vec![],
+ _ => {},
}
let mut match_expr_list: Vec<(&T, &T)> = Vec::new();
- let mut map: FxHashMap<_, Vec<&_>> =
- FxHashMap::with_capacity_and_hasher(exprs.len(), BuildHasherDefault::default());
+ let mut map: UnhashMap<u64, Vec<&_>> =
+ UnhashMap::with_capacity_and_hasher(exprs.len(), BuildHasherDefault::default());
for expr in exprs {
match map.entry(hash(expr)) {
1,34,0 { TRY_FROM }
1,30,0 { ITERATOR_FIND_MAP }
1,17,0 { FIELD_INIT_SHORTHAND, STATIC_IN_CONST }
+ 1,16,0 { STR_REPEAT }
}
pub fn from_lit_kind(src: &'a str, lit_kind: &LitKind) -> Option<NumericLiteral<'a>> {
if lit_kind.is_numeric() && src.chars().next().map_or(false, |c| c.is_digit(10)) {
- let (unsuffixed, suffix) = split_suffix(&src, lit_kind);
+ let (unsuffixed, suffix) = split_suffix(src, lit_kind);
let float = matches!(lit_kind, LitKind::Float(..));
Some(NumericLiteral::new(unsuffixed, suffix, float))
} else {
pub const POLL: [&str; 4] = ["core", "task", "poll", "Poll"];
pub const POLL_PENDING: [&str; 5] = ["core", "task", "poll", "Poll", "Pending"];
pub const POLL_READY: [&str; 5] = ["core", "task", "poll", "Poll", "Ready"];
-pub const PTR_COPY: [&str; 4] = ["core", "intrinsics", "", "copy"];
-pub const PTR_COPY_NONOVERLAPPING: [&str; 4] = ["core", "intrinsics", "", "copy_nonoverlapping"];
+pub const PTR_COPY: [&str; 3] = ["core", "intrinsics", "copy"];
+pub const PTR_COPY_NONOVERLAPPING: [&str; 3] = ["core", "intrinsics", "copy_nonoverlapping"];
pub const PTR_EQ: [&str; 3] = ["core", "ptr", "eq"];
pub const PTR_NULL: [&str; 3] = ["core", "ptr", "null"];
pub const PTR_NULL_MUT: [&str; 3] = ["core", "ptr", "null_mut"];
if self.abort {
return;
}
- if let ExprKind::MethodCall(ref seg, _, ref args, _) = expr.kind {
+ if let ExprKind::MethodCall(seg, _, args, _) = expr.kind {
if args.len() == 1 && match_var(&args[0], self.name) {
if seg.ident.name.as_str() == "capacity" {
self.abort = true;
}
fn get_binding_name(arg: &Param<'_>) -> Option<Symbol> {
- get_pat_name(&arg.pat)
+ get_pat_name(arg.pat)
}
cursor = proj_base;
match elem {
ProjectionElem::Field(..) => {
- let base_ty = Place::ty_from(place.local, &proj_base, body, tcx).ty;
+ let base_ty = Place::ty_from(place.local, proj_base, body, tcx).ty;
if let Some(def) = base_ty.ty_adt_def() {
// No union field accesses in `const fn`
if def.is_union() {
#![deny(clippy::missing_docs_in_private_items)]
use crate::higher;
-use crate::source::{snippet, snippet_opt, snippet_with_macro_callsite};
+use crate::source::{snippet, snippet_opt, snippet_with_context, snippet_with_macro_callsite};
use rustc_ast::util::parser::AssocOp;
use rustc_ast::{ast, token};
use rustc_ast_pretty::pprust::token_kind_to_string;
use rustc_hir as hir;
use rustc_lint::{EarlyContext, LateContext, LintContext};
use rustc_span::source_map::{CharPos, Span};
-use rustc_span::{BytePos, Pos};
+use rustc_span::{BytePos, Pos, SyntaxContext};
use std::borrow::Cow;
use std::convert::TryInto;
use std::fmt::Display;
Self::hir_from_snippet(expr, snippet)
}
+ /// Same as `hir`, but first walks the span up to the given context. This will result in the
+ /// macro call, rather then the expansion, if the span is from a child context. If the span is
+ /// not from a child context, it will be used directly instead.
+ ///
+ /// e.g. Given the expression `&vec![]`, getting a snippet from the span for `vec![]` as a HIR
+ /// node would result in `box []`. If given the context of the address of expression, this
+ /// function will correctly get a snippet of `vec![]`.
+ pub fn hir_with_context(
+ cx: &LateContext<'_>,
+ expr: &hir::Expr<'_>,
+ ctxt: SyntaxContext,
+ default: &'a str,
+ applicability: &mut Applicability,
+ ) -> Self {
+ let (snippet, in_macro) = snippet_with_context(cx, expr.span, ctxt, default, applicability);
+
+ if in_macro {
+ Sugg::NonParen(snippet)
+ } else {
+ Self::hir_from_snippet(expr, snippet)
+ }
+ }
+
/// Generate a suggestion for an expression with the given snippet. This is used by the `hir_*`
/// function variants of `Sugg`, since these use different snippet functions.
fn hir_from_snippet(expr: &hir::Expr<'_>, snippet: Cow<'a, str>) -> Self {
if let Some(non_whitespace_offset) = non_whitespace_offset {
remove_span = remove_span
- .with_hi(remove_span.hi() + BytePos(non_whitespace_offset.try_into().expect("offset too large")))
+ .with_hi(remove_span.hi() + BytePos(non_whitespace_offset.try_into().expect("offset too large")));
}
}
// Returns whether the type has #[must_use] attribute
pub fn is_must_use_ty<'tcx>(cx: &LateContext<'tcx>, ty: Ty<'tcx>) -> bool {
match ty.kind() {
- ty::Adt(ref adt, _) => must_use_attr(&cx.tcx.get_attrs(adt.did)).is_some(),
- ty::Foreign(ref did) => must_use_attr(&cx.tcx.get_attrs(*did)).is_some(),
- ty::Slice(ref ty)
- | ty::Array(ref ty, _)
- | ty::RawPtr(ty::TypeAndMut { ref ty, .. })
- | ty::Ref(_, ref ty, _) => {
+ ty::Adt(adt, _) => must_use_attr(cx.tcx.get_attrs(adt.did)).is_some(),
+ ty::Foreign(ref did) => must_use_attr(cx.tcx.get_attrs(*did)).is_some(),
+ ty::Slice(ty) | ty::Array(ty, _) | ty::RawPtr(ty::TypeAndMut { ty, .. }) | ty::Ref(_, ty, _) => {
// for the Array case we don't need to care for the len == 0 case
// because we don't want to lint functions returning empty arrays
is_must_use_ty(cx, *ty)
},
- ty::Tuple(ref substs) => substs.types().any(|ty| is_must_use_ty(cx, ty)),
+ ty::Tuple(substs) => substs.types().any(|ty| is_must_use_ty(cx, ty)),
ty::Opaque(ref def_id, _) => {
for (predicate, _) in cx.tcx.explicit_item_bounds(*def_id) {
if let ty::PredicateKind::Trait(trait_predicate, _) = predicate.kind().skip_binder() {
- if must_use_attr(&cx.tcx.get_attrs(trait_predicate.trait_ref.def_id)).is_some() {
+ if must_use_attr(cx.tcx.get_attrs(trait_predicate.trait_ref.def_id)).is_some() {
return true;
}
}
ty::Dynamic(binder, _) => {
for predicate in binder.iter() {
if let ty::ExistentialPredicate::Trait(ref trait_ref) = predicate.skip_binder() {
- if must_use_attr(&cx.tcx.get_attrs(trait_ref.def_id)).is_some() {
+ if must_use_attr(cx.tcx.get_attrs(trait_ref.def_id)).is_some() {
return true;
}
}
/// Returns the base type for HIR references and pointers.
pub fn walk_ptrs_hir_ty<'tcx>(ty: &'tcx hir::Ty<'tcx>) -> &'tcx hir::Ty<'tcx> {
match ty.kind {
- TyKind::Ptr(ref mut_ty) | TyKind::Rptr(_, ref mut_ty) => walk_ptrs_hir_ty(&mut_ty.ty),
+ TyKind::Ptr(ref mut_ty) | TyKind::Rptr(_, ref mut_ty) => walk_ptrs_hir_ty(mut_ty.ty),
_ => ty,
}
}
//FIXME: This causes false negatives. We can't get the `NodeId` from
//`Categorization::Upvar(_)`. So we search for any `Upvar`s in the
//`while`-body, not just the ones in the condition.
- self.skip = true
+ self.skip = true;
},
_ => {},
}
fn borrow(&mut self, cmt: &PlaceWithHirId<'tcx>, _: HirId, bk: ty::BorrowKind) {
if let ty::BorrowKind::MutBorrow = bk {
- self.update(&cmt)
+ self.update(cmt);
}
}
fn mutate(&mut self, cmt: &PlaceWithHirId<'tcx>, _: HirId) {
- self.update(&cmt)
+ self.update(cmt);
}
fn fake_read(&mut self, _: rustc_typeck::expr_use_visitor::Place<'tcx>, _: FakeReadCause, _: HirId) {}
}
fn visit_stmt(&mut self, stmt: &'hir hir::Stmt<'_>) {
- intravisit::walk_stmt(&mut *self.inside_stmt(true), stmt)
+ intravisit::walk_stmt(&mut *self.inside_stmt(true), stmt);
}
fn visit_expr(&mut self, expr: &'hir hir::Expr<'_>) {
}
}
+/// A type which can be visited.
pub trait Visitable<'tcx> {
- fn visit<V: Visitor<'tcx>>(self, v: &mut V);
+ /// Calls the corresponding `visit_*` function on the visitor.
+ fn visit<V: Visitor<'tcx>>(self, visitor: &mut V);
}
-impl Visitable<'tcx> for &'tcx Expr<'tcx> {
- fn visit<V: Visitor<'tcx>>(self, v: &mut V) {
- v.visit_expr(self)
- }
-}
-impl Visitable<'tcx> for &'tcx Block<'tcx> {
- fn visit<V: Visitor<'tcx>>(self, v: &mut V) {
- v.visit_block(self)
- }
-}
-impl<'tcx> Visitable<'tcx> for &'tcx Stmt<'tcx> {
- fn visit<V: Visitor<'tcx>>(self, v: &mut V) {
- v.visit_stmt(self)
- }
-}
-impl<'tcx> Visitable<'tcx> for &'tcx Body<'tcx> {
- fn visit<V: Visitor<'tcx>>(self, v: &mut V) {
- v.visit_body(self)
- }
-}
-impl<'tcx> Visitable<'tcx> for &'tcx Arm<'tcx> {
- fn visit<V: Visitor<'tcx>>(self, v: &mut V) {
- v.visit_arm(self)
- }
+macro_rules! visitable_ref {
+ ($t:ident, $f:ident) => {
+ impl Visitable<'tcx> for &'tcx $t<'tcx> {
+ fn visit<V: Visitor<'tcx>>(self, visitor: &mut V) {
+ visitor.$f(self);
+ }
+ }
+ };
}
+visitable_ref!(Block, visit_block);
/// Calls the given function for each break expression.
pub fn visit_break_exprs<'tcx>(
fn visit_expr(&mut self, e: &'tcx Expr<'_>) {
if let ExprKind::Break(dest, sub_expr) = e.kind {
- self.0(e, dest, sub_expr)
+ self.0(e, dest, sub_expr);
}
walk_expr(self, e);
}
self.found = true;
}
} else {
- walk_expr(self, e)
+ walk_expr(self, e);
}
}
}
# Assuming the current directory corresponds to the Clippy repository
$ git checkout $SHA
$ git tag rust-1.XX.0 # XX should be exchanged with the corresponding version
-$ git push upstream master --tags # `upstream` is the `rust-lang/rust-clippy` remote
+$ git push upstream rust-1.XX.0 # `upstream` is the `rust-lang/rust-clippy` remote
```
After this, the release should be available on the Clippy [release page].
+++ /dev/null
-[package]
-name = "clippy-mini-macro-test"
-version = "0.2.0"
-authors = ["The Rust Clippy Developers"]
-license = "MIT OR Apache-2.0"
-description = "A macro to test clippy's procedural macro checks"
-repository = "https://github.com/rust-lang/rust-clippy"
-edition = "2018"
-
-[lib]
-name = "clippy_mini_macro_test"
-proc-macro = true
-
-[dependencies]
+++ /dev/null
-#![feature(proc_macro_quote)]
-#![deny(rust_2018_idioms)]
-// FIXME: Remove this attribute once the weird failure is gone.
-#![allow(unused_extern_crates)]
-extern crate proc_macro;
-
-use proc_macro::{quote, TokenStream};
-
-#[proc_macro_derive(ClippyMiniMacroTest)]
-/// # Panics
-///
-/// Panics if the macro derivation fails
-pub fn mini_macro(_: TokenStream) -> TokenStream {
- quote!(
- #[allow(unused)]
- fn needless_take_by_value(s: String) {
- println!("{}", s.len());
- }
- #[allow(unused)]
- fn needless_loop(items: &[u8]) {
- for i in 0..items.len() {
- println!("{}", items[i]);
- }
- }
- fn line_wrapper() {
- println!("{}", line!());
- }
- )
-}
[toolchain]
-channel = "nightly-2021-05-20"
+channel = "nightly-2021-06-03"
components = ["llvm-tools-preview", "rustc-dev", "rust-src"]
}
#[must_use]
-pub fn get_channel() -> Option<String> {
+pub fn get_channel() -> String {
match env::var("CFG_RELEASE_CHANNEL") {
- Ok(channel) => Some(channel),
+ Ok(channel) => channel,
Err(_) => {
// if that failed, try to ask rustc -V, do some parsing and find out
match std::process::Command::new("rustc")
{
Some(rustc_output) => {
if rustc_output.contains("beta") {
- Some(String::from("beta"))
+ String::from("beta")
} else if rustc_output.contains("stable") {
- Some(String::from("stable"))
+ String::from("stable")
} else {
// default to nightly if we fail to parse
- Some(String::from("nightly"))
+ String::from("nightly")
}
},
// default to nightly
- None => Some(String::from("nightly")),
+ None => String::from("nightly"),
}
},
}
--- /dev/null
+# default config for tests, overrides clippy.toml at the project root
use compiletest_rs as compiletest;
use compiletest_rs::common::Mode as TestMode;
-use std::env::{self, set_var, var};
-use std::ffi::OsStr;
+use std::env::{self, remove_var, set_var, var_os};
+use std::ffi::{OsStr, OsString};
use std::fs;
use std::io;
use std::path::{Path, PathBuf};
config
}
-fn run_mode(cfg: &mut compiletest::Config) {
+fn run_ui(cfg: &mut compiletest::Config) {
cfg.mode = TestMode::Ui;
cfg.src_base = Path::new("tests").join("ui");
+ // use tests/clippy.toml
+ let _g = VarGuard::set("CARGO_MANIFEST_DIR", std::fs::canonicalize("tests").unwrap());
compiletest::run_tests(cfg);
}
continue;
}
let dir_path = dir.path();
- set_var("CARGO_MANIFEST_DIR", &dir_path);
+ let _g = VarGuard::set("CARGO_MANIFEST_DIR", &dir_path);
for file in fs::read_dir(&dir_path)? {
let file = file?;
let file_path = file.path();
let tests = compiletest::make_tests(config);
- let manifest_dir = var("CARGO_MANIFEST_DIR").unwrap_or_default();
let res = run_tests(config, tests);
- set_var("CARGO_MANIFEST_DIR", &manifest_dir);
match res {
Ok(true) => {},
Ok(false) => panic!("Some tests failed"),
Some("main.rs") => {},
_ => continue,
}
- set_var("CLIPPY_CONF_DIR", case.path());
+ let _g = VarGuard::set("CLIPPY_CONF_DIR", case.path());
let paths = compiletest::common::TestPaths {
file: file_path,
base: config.src_base.clone(),
let tests = compiletest::make_tests(config);
let current_dir = env::current_dir().unwrap();
- let conf_dir = var("CLIPPY_CONF_DIR").unwrap_or_default();
let res = run_tests(config, &config.filters, tests);
env::set_current_dir(current_dir).unwrap();
- set_var("CLIPPY_CONF_DIR", conf_dir);
match res {
Ok(true) => {},
fn compile_test() {
prepare_env();
let mut config = default_config();
- run_mode(&mut config);
+ run_ui(&mut config);
run_ui_toml(&mut config);
run_ui_cargo(&mut config);
run_internal_tests(&mut config);
}
+
+/// Restores an env var on drop
+#[must_use]
+struct VarGuard {
+ key: &'static str,
+ value: Option<OsString>,
+}
+
+impl VarGuard {
+ fn set(key: &'static str, val: impl AsRef<OsStr>) -> Self {
+ let value = var_os(key);
+ set_var(key, val);
+ Self { key, value }
+ }
+}
+
+impl Drop for VarGuard {
+ fn drop(&mut self) {
+ match self.value.as_deref() {
+ None => remove_var(self.key),
+ Some(value) => set_var(self.key, value),
+ }
+ }
+}
#[ignore]
#[cfg(feature = "metadata-collector-lint")]
fn run_metadata_collection_lint() {
+ use std::fs::File;
+ use std::time::SystemTime;
+
+ // Setup for validation
+ let metadata_output_path = PathBuf::from(env!("CARGO_MANIFEST_DIR")).join("util/gh-pages/metadata_collection.json");
+ let start_time = SystemTime::now();
+
+ // Run collection as is
std::env::set_var("ENABLE_METADATA_COLLECTION", "1");
run_clippy_for_project("clippy_lints");
+
+ // Check if cargo caching got in the way
+ if let Ok(file) = File::open(metadata_output_path) {
+ if let Ok(metadata) = file.metadata() {
+ if let Ok(last_modification) = metadata.modified() {
+ if last_modification > start_time {
+ // The output file has been modified. Most likely by a hungry
+ // metadata collection monster. So We'll return.
+ return;
+ }
+ }
+ }
+ }
+
+ // Force cargo to invalidate the caches
+ filetime::set_file_mtime(
+ PathBuf::from(env!("CARGO_MANIFEST_DIR")).join("clippy_lints/src/lib.rs"),
+ filetime::FileTime::now(),
+ )
+ .unwrap();
+
+ // Running the collection again
+ run_clippy_for_project("clippy_lints");
}
fn run_clippy_for_project(project: &str) {
-error: error reading Clippy's configuration file `$DIR/clippy.toml`: unknown field `foobar`, expected one of `msrv`, `blacklisted-names`, `cognitive-complexity-threshold`, `cyclomatic-complexity-threshold`, `doc-valid-idents`, `too-many-arguments-threshold`, `type-complexity-threshold`, `single-char-binding-names-threshold`, `too-large-for-stack`, `enum-variant-name-threshold`, `enum-variant-size-threshold`, `verbose-bit-mask-threshold`, `literal-representation-threshold`, `trivial-copy-size-limit`, `pass-by-value-size-limit`, `too-many-lines-threshold`, `array-size-threshold`, `vec-box-size-threshold`, `max-trait-bounds`, `max-struct-bools`, `max-fn-params-bools`, `warn-on-all-wildcard-imports`, `disallowed-methods`, `unreadable-literal-lint-fractions`, `upper-case-acronyms-aggressive`, `cargo-ignore-publish`, `third-party` at line 5 column 1
+error: error reading Clippy's configuration file `$DIR/clippy.toml`: unknown field `foobar`, expected one of `avoid-breaking-exported-api`, `msrv`, `blacklisted-names`, `cognitive-complexity-threshold`, `cyclomatic-complexity-threshold`, `doc-valid-idents`, `too-many-arguments-threshold`, `type-complexity-threshold`, `single-char-binding-names-threshold`, `too-large-for-stack`, `enum-variant-name-threshold`, `enum-variant-size-threshold`, `verbose-bit-mask-threshold`, `literal-representation-threshold`, `trivial-copy-size-limit`, `pass-by-value-size-limit`, `too-many-lines-threshold`, `array-size-threshold`, `vec-box-size-threshold`, `max-trait-bounds`, `max-struct-bools`, `max-fn-params-bools`, `warn-on-all-wildcard-imports`, `disallowed-methods`, `unreadable-literal-lint-fractions`, `upper-case-acronyms-aggressive`, `cargo-ignore-publish`, `third-party` at line 5 column 1
error: aborting due to previous error
}
}
}
+
+#[proc_macro_derive(ClippyMiniMacroTest)]
+pub fn mini_macro(_: TokenStream) -> TokenStream {
+ quote!(
+ #[allow(unused)]
+ fn needless_take_by_value(s: String) {
+ println!("{}", s.len());
+ }
+ #[allow(unused)]
+ fn needless_loop(items: &[u8]) {
+ for i in 0..items.len() {
+ println!("{}", items[i]);
+ }
+ }
+ fn line_wrapper() {
+ println!("{}", line!());
+ }
+ )
+}
--- /dev/null
+pub fn warn<T>(_: T) {}
+
+macro_rules! define_macro {
+ ($d:tt $lower:ident $upper:ident) => {
+ #[macro_export]
+ macro_rules! $upper {
+ ($arg:tt) => {
+ $crate::$lower($arg)
+ };
+ }
+ };
+}
+
+define_macro! {$ warn WARNING}
--- /dev/null
+// aux-build:ice-7272-aux.rs
+
+#![allow(clippy::no_effect)]
+
+extern crate ice_7272_aux;
+
+use ice_7272_aux::*;
+
+pub fn main() {
+ || WARNING!("Style changed!");
+ || "}{";
+}
+++ /dev/null
-#[macro_use]
-extern crate clippy_mini_macro_test;
-
-#[deny(warnings)]
-fn main() {
- let x = Foo;
- println!("{:?}", x);
-}
-
-#[derive(ClippyMiniMacroTest, Debug)]
-struct Foo;
0
}
-pub struct A;
+struct A;
impl A {
pub fn as_ref(self) -> &'static str {
#[warn(clippy::unknown_clippy_lints)]
#[warn(clippy::find_map)]
#[warn(clippy::filter_map)]
+#[warn(clippy::pub_enum_variant_names)]
+#[warn(clippy::wrong_pub_self_convention)]
fn main() {}
LL | #[warn(clippy::filter_map)]
| ^^^^^^^^^^^^^^^^^^
-error: aborting due to 14 previous errors
+error: lint `clippy::pub_enum_variant_names` has been removed: set the `avoid_breaking_exported_api` config option to `false` to enable the `enum_variant_names` lint for public items
+ --> $DIR/deprecated.rs:15:8
+ |
+LL | #[warn(clippy::pub_enum_variant_names)]
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+error: lint `clippy::wrong_pub_self_convention` has been removed: set the `avoid_breaking_exported_api` config option to `false` to enable the `wrong_self_convention` lint for public items
+ --> $DIR/deprecated.rs:16:8
+ |
+LL | #[warn(clippy::wrong_pub_self_convention)]
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+error: aborting due to 16 previous errors
-#![feature(non_ascii_idents)]
-#![warn(clippy::enum_variant_names, clippy::pub_enum_variant_names)]
+#![warn(clippy::enum_variant_names)]
#![allow(non_camel_case_types, clippy::upper_case_acronyms)]
enum FakeCallType {
WithOut,
}
-#[allow(clippy::pub_enum_variant_names)]
-mod allowed {
+#[allow(clippy::enum_variant_names)]
+pub mod allowed {
pub enum PubAllowed {
SomeThis,
SomeThat,
error: variant name ends with the enum's name
- --> $DIR/enum_variants.rs:16:5
+ --> $DIR/enum_variants.rs:15:5
|
LL | cFoo,
| ^^^^
= note: `-D clippy::enum-variant-names` implied by `-D warnings`
error: variant name starts with the enum's name
- --> $DIR/enum_variants.rs:27:5
+ --> $DIR/enum_variants.rs:26:5
|
LL | FoodGood,
| ^^^^^^^^
error: variant name starts with the enum's name
- --> $DIR/enum_variants.rs:28:5
+ --> $DIR/enum_variants.rs:27:5
|
LL | FoodMiddle,
| ^^^^^^^^^^
error: variant name starts with the enum's name
- --> $DIR/enum_variants.rs:29:5
+ --> $DIR/enum_variants.rs:28:5
|
LL | FoodBad,
| ^^^^^^^
error: all variants have the same prefix: `Food`
- --> $DIR/enum_variants.rs:26:1
+ --> $DIR/enum_variants.rs:25:1
|
LL | / enum Food {
LL | | FoodGood,
= help: remove the prefixes and use full paths to the variants instead of glob imports
error: all variants have the same prefix: `CallType`
- --> $DIR/enum_variants.rs:36:1
+ --> $DIR/enum_variants.rs:35:1
|
LL | / enum BadCallType {
LL | | CallTypeCall,
= help: remove the prefixes and use full paths to the variants instead of glob imports
error: all variants have the same prefix: `Constant`
- --> $DIR/enum_variants.rs:48:1
+ --> $DIR/enum_variants.rs:47:1
|
LL | / enum Consts {
LL | | ConstantInt,
= help: remove the prefixes and use full paths to the variants instead of glob imports
error: all variants have the same prefix: `With`
- --> $DIR/enum_variants.rs:82:1
+ --> $DIR/enum_variants.rs:81:1
|
LL | / enum Seallll {
LL | | WithOutCake,
= help: remove the prefixes and use full paths to the variants instead of glob imports
error: all variants have the same prefix: `Prefix`
- --> $DIR/enum_variants.rs:88:1
+ --> $DIR/enum_variants.rs:87:1
|
LL | / enum NonCaps {
LL | | Prefix的,
|
= help: remove the prefixes and use full paths to the variants instead of glob imports
-error: all variants have the same prefix: `With`
- --> $DIR/enum_variants.rs:94:1
- |
-LL | / pub enum PubSeall {
-LL | | WithOutCake,
-LL | | WithOutTea,
-LL | | WithOut,
-LL | | }
- | |_^
- |
- = note: `-D clippy::pub-enum-variant-names` implied by `-D warnings`
- = help: remove the prefixes and use full paths to the variants instead of glob imports
-
error: all variants have the same postfix: `IData`
- --> $DIR/enum_variants.rs:137:1
+ --> $DIR/enum_variants.rs:136:1
|
LL | / enum IDataRequest {
LL | | PutIData(String),
= help: remove the postfixes and use full paths to the variants instead of glob imports
error: all variants have the same postfix: `HIData`
- --> $DIR/enum_variants.rs:143:1
+ --> $DIR/enum_variants.rs:142:1
|
LL | / enum HIDataRequest {
LL | | PutHIData(String),
|
= help: remove the postfixes and use full paths to the variants instead of glob imports
-error: aborting due to 12 previous errors
+error: aborting due to 11 previous errors
// See #515
let a: Option<Box<dyn (::std::ops::Deref<Target = [i32]>)>> =
Some(vec![1i32, 2]).map(|v| -> Box<dyn (::std::ops::Deref<Target = [i32]>)> { Box::new(v) });
+
+ // issue #7224
+ let _: Option<Vec<u32>> = Some(0).map(|_| vec![]);
}
trait TestTrait {
// See #515
let a: Option<Box<dyn (::std::ops::Deref<Target = [i32]>)>> =
Some(vec![1i32, 2]).map(|v| -> Box<dyn (::std::ops::Deref<Target = [i32]>)> { Box::new(v) });
+
+ // issue #7224
+ let _: Option<Vec<u32>> = Some(0).map(|_| vec![]);
}
trait TestTrait {
| ^^^^^^^^^^^^^^ help: replace the closure with the function itself: `generic`
error: redundant closure
- --> $DIR/eta.rs:89:51
+ --> $DIR/eta.rs:92:51
|
LL | let e = Some(TestStruct { some_ref: &i }).map(|a| a.foo());
| ^^^^^^^^^^^ help: replace the closure with the method itself: `TestStruct::foo`
= note: `-D clippy::redundant-closure-for-method-calls` implied by `-D warnings`
error: redundant closure
- --> $DIR/eta.rs:91:51
+ --> $DIR/eta.rs:94:51
|
LL | let e = Some(TestStruct { some_ref: &i }).map(|a| a.trait_foo());
| ^^^^^^^^^^^^^^^^^ help: replace the closure with the method itself: `TestTrait::trait_foo`
error: redundant closure
- --> $DIR/eta.rs:94:42
+ --> $DIR/eta.rs:97:42
|
LL | let e = Some(&mut vec![1, 2, 3]).map(|v| v.clear());
| ^^^^^^^^^^^^^ help: replace the closure with the method itself: `std::vec::Vec::clear`
error: redundant closure
- --> $DIR/eta.rs:99:29
+ --> $DIR/eta.rs:102:29
|
LL | let e = Some("str").map(|s| s.to_string());
| ^^^^^^^^^^^^^^^^^ help: replace the closure with the method itself: `std::string::ToString::to_string`
error: redundant closure
- --> $DIR/eta.rs:101:27
+ --> $DIR/eta.rs:104:27
|
LL | let e = Some('a').map(|s| s.to_uppercase());
| ^^^^^^^^^^^^^^^^^^^^ help: replace the closure with the method itself: `char::to_uppercase`
error: redundant closure
- --> $DIR/eta.rs:104:65
+ --> $DIR/eta.rs:107:65
|
LL | let e: std::vec::Vec<char> = vec!['a', 'b', 'c'].iter().map(|c| c.to_ascii_uppercase()).collect();
| ^^^^^^^^^^^^^^^^^^^^^^^^^^ help: replace the closure with the method itself: `char::to_ascii_uppercase`
error: redundant closure
- --> $DIR/eta.rs:187:27
+ --> $DIR/eta.rs:190:27
|
LL | let a = Some(1u8).map(|a| foo_ptr(a));
| ^^^^^^^^^^^^^^ help: replace the closure with the function itself: `foo_ptr`
error: redundant closure
- --> $DIR/eta.rs:192:27
+ --> $DIR/eta.rs:195:27
|
LL | let a = Some(1u8).map(|a| closure(a));
| ^^^^^^^^^^^^^^ help: replace the closure with the function itself: `closure`
use std::collections::{BTreeMap, BTreeSet, HashMap, VecDeque};
use std::iter::FromIterator;
+struct Foo(Vec<bool>);
+
+impl FromIterator<bool> for Foo {
+ fn from_iter<T: IntoIterator<Item = bool>>(_: T) -> Self {
+ todo!()
+ }
+}
+
+impl<'a> FromIterator<&'a bool> for Foo {
+ fn from_iter<T: IntoIterator<Item = &'a bool>>(iter: T) -> Self {
+ iter.into_iter().copied().collect::<Self>()
+ }
+}
+
fn main() {
let iter_expr = std::iter::repeat(5).take(5);
let _ = iter_expr.collect::<Vec<_>>();
use std::collections::{BTreeMap, BTreeSet, HashMap, VecDeque};
use std::iter::FromIterator;
+struct Foo(Vec<bool>);
+
+impl FromIterator<bool> for Foo {
+ fn from_iter<T: IntoIterator<Item = bool>>(_: T) -> Self {
+ todo!()
+ }
+}
+
+impl<'a> FromIterator<&'a bool> for Foo {
+ fn from_iter<T: IntoIterator<Item = &'a bool>>(iter: T) -> Self {
+ <Self as FromIterator<bool>>::from_iter(iter.into_iter().copied())
+ }
+}
+
fn main() {
let iter_expr = std::iter::repeat(5).take(5);
let _ = Vec::from_iter(iter_expr);
error: usage of `FromIterator::from_iter`
- --> $DIR/from_iter_instead_of_collect.rs:11:13
+ --> $DIR/from_iter_instead_of_collect.rs:19:9
|
-LL | let _ = Vec::from_iter(iter_expr);
- | ^^^^^^^^^^^^^^^^^^^^^^^^^ help: use `.collect()` instead of `::from_iter()`: `iter_expr.collect::<Vec<_>>()`
+LL | <Self as FromIterator<bool>>::from_iter(iter.into_iter().copied())
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use `.collect()` instead of `::from_iter()`: `iter.into_iter().copied().collect::<Self>()`
|
= note: `-D clippy::from-iter-instead-of-collect` implied by `-D warnings`
error: usage of `FromIterator::from_iter`
- --> $DIR/from_iter_instead_of_collect.rs:13:13
+ --> $DIR/from_iter_instead_of_collect.rs:25:13
+ |
+LL | let _ = Vec::from_iter(iter_expr);
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^ help: use `.collect()` instead of `::from_iter()`: `iter_expr.collect::<Vec<_>>()`
+
+error: usage of `FromIterator::from_iter`
+ --> $DIR/from_iter_instead_of_collect.rs:27:13
|
LL | let _ = HashMap::<usize, &i8>::from_iter(vec![5, 5, 5, 5].iter().enumerate());
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use `.collect()` instead of `::from_iter()`: `vec![5, 5, 5, 5].iter().enumerate().collect::<HashMap<usize, &i8>>()`
error: usage of `FromIterator::from_iter`
- --> $DIR/from_iter_instead_of_collect.rs:18:19
+ --> $DIR/from_iter_instead_of_collect.rs:32:19
|
LL | assert_eq!(a, Vec::from_iter(0..3));
| ^^^^^^^^^^^^^^^^^^^^ help: use `.collect()` instead of `::from_iter()`: `(0..3).collect::<Vec<_>>()`
error: usage of `FromIterator::from_iter`
- --> $DIR/from_iter_instead_of_collect.rs:19:19
+ --> $DIR/from_iter_instead_of_collect.rs:33:19
|
LL | assert_eq!(a, Vec::<i32>::from_iter(0..3));
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use `.collect()` instead of `::from_iter()`: `(0..3).collect::<Vec<i32>>()`
error: usage of `FromIterator::from_iter`
- --> $DIR/from_iter_instead_of_collect.rs:21:17
+ --> $DIR/from_iter_instead_of_collect.rs:35:17
|
LL | let mut b = VecDeque::from_iter(0..3);
| ^^^^^^^^^^^^^^^^^^^^^^^^^ help: use `.collect()` instead of `::from_iter()`: `(0..3).collect::<VecDeque<_>>()`
error: usage of `FromIterator::from_iter`
- --> $DIR/from_iter_instead_of_collect.rs:24:17
+ --> $DIR/from_iter_instead_of_collect.rs:38:17
|
LL | let mut b = VecDeque::<i32>::from_iter(0..3);
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use `.collect()` instead of `::from_iter()`: `(0..3).collect::<VecDeque<i32>>()`
error: usage of `FromIterator::from_iter`
- --> $DIR/from_iter_instead_of_collect.rs:29:21
+ --> $DIR/from_iter_instead_of_collect.rs:43:21
|
LL | let mut b = collections::VecDeque::<i32>::from_iter(0..3);
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use `.collect()` instead of `::from_iter()`: `(0..3).collect::<collections::VecDeque<i32>>()`
error: usage of `FromIterator::from_iter`
- --> $DIR/from_iter_instead_of_collect.rs:34:14
+ --> $DIR/from_iter_instead_of_collect.rs:48:14
|
LL | let bm = BTreeMap::from_iter(values.iter().cloned());
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use `.collect()` instead of `::from_iter()`: `values.iter().cloned().collect::<BTreeMap<_, _>>()`
error: usage of `FromIterator::from_iter`
- --> $DIR/from_iter_instead_of_collect.rs:35:19
+ --> $DIR/from_iter_instead_of_collect.rs:49:19
|
LL | let mut bar = BTreeMap::from_iter(bm.range(0..2));
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use `.collect()` instead of `::from_iter()`: `bm.range(0..2).collect::<BTreeMap<_, _>>()`
error: usage of `FromIterator::from_iter`
- --> $DIR/from_iter_instead_of_collect.rs:38:19
+ --> $DIR/from_iter_instead_of_collect.rs:52:19
|
LL | let mut bts = BTreeSet::from_iter(0..3);
| ^^^^^^^^^^^^^^^^^^^^^^^^^ help: use `.collect()` instead of `::from_iter()`: `(0..3).collect::<BTreeSet<_>>()`
error: usage of `FromIterator::from_iter`
- --> $DIR/from_iter_instead_of_collect.rs:42:17
+ --> $DIR/from_iter_instead_of_collect.rs:56:17
|
LL | let _ = collections::BTreeSet::from_iter(0..3);
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use `.collect()` instead of `::from_iter()`: `(0..3).collect::<collections::BTreeSet<_>>()`
error: usage of `FromIterator::from_iter`
- --> $DIR/from_iter_instead_of_collect.rs:43:17
+ --> $DIR/from_iter_instead_of_collect.rs:57:17
|
LL | let _ = collections::BTreeSet::<u32>::from_iter(0..3);
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use `.collect()` instead of `::from_iter()`: `(0..3).collect::<collections::BTreeSet<u32>>()`
error: usage of `FromIterator::from_iter`
- --> $DIR/from_iter_instead_of_collect.rs:46:15
+ --> $DIR/from_iter_instead_of_collect.rs:60:15
|
LL | for _i in Vec::from_iter([1, 2, 3].iter()) {}
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use `.collect()` instead of `::from_iter()`: `[1, 2, 3].iter().collect::<Vec<_>>()`
error: usage of `FromIterator::from_iter`
- --> $DIR/from_iter_instead_of_collect.rs:47:15
+ --> $DIR/from_iter_instead_of_collect.rs:61:15
|
LL | for _i in Vec::<&i32>::from_iter([1, 2, 3].iter()) {}
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use `.collect()` instead of `::from_iter()`: `[1, 2, 3].iter().collect::<Vec<&i32>>()`
-error: aborting due to 14 previous errors
+error: aborting due to 15 previous errors
LL | fn bad_method(_one: u32, _two: u32, _three: &str, _four: bool, _five: f32, _six: f32, _seven: bool, _eight: ()) {}
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
-error: this public function dereferences a raw pointer but is not marked `unsafe`
+error: this public function might dereference a raw pointer but is not marked `unsafe`
--> $DIR/functions.rs:63:34
|
LL | println!("{}", unsafe { *p });
|
= note: `-D clippy::not-unsafe-ptr-arg-deref` implied by `-D warnings`
-error: this public function dereferences a raw pointer but is not marked `unsafe`
+error: this public function might dereference a raw pointer but is not marked `unsafe`
--> $DIR/functions.rs:64:35
|
LL | println!("{:?}", unsafe { p.as_ref() });
| ^
-error: this public function dereferences a raw pointer but is not marked `unsafe`
+error: this public function might dereference a raw pointer but is not marked `unsafe`
--> $DIR/functions.rs:65:33
|
LL | unsafe { std::ptr::read(p) };
| ^
-error: this public function dereferences a raw pointer but is not marked `unsafe`
+error: this public function might dereference a raw pointer but is not marked `unsafe`
--> $DIR/functions.rs:76:30
|
LL | println!("{}", unsafe { *p });
| ^
-error: this public function dereferences a raw pointer but is not marked `unsafe`
+error: this public function might dereference a raw pointer but is not marked `unsafe`
--> $DIR/functions.rs:77:31
|
LL | println!("{:?}", unsafe { p.as_ref() });
| ^
-error: this public function dereferences a raw pointer but is not marked `unsafe`
+error: this public function might dereference a raw pointer but is not marked `unsafe`
--> $DIR/functions.rs:78:29
|
LL | unsafe { std::ptr::read(p) };
| ^
-error: this public function dereferences a raw pointer but is not marked `unsafe`
+error: this public function might dereference a raw pointer but is not marked `unsafe`
--> $DIR/functions.rs:87:34
|
LL | println!("{}", unsafe { *p });
| ^
-error: this public function dereferences a raw pointer but is not marked `unsafe`
+error: this public function might dereference a raw pointer but is not marked `unsafe`
--> $DIR/functions.rs:88:35
|
LL | println!("{:?}", unsafe { p.as_ref() });
| ^
-error: this public function dereferences a raw pointer but is not marked `unsafe`
+error: this public function might dereference a raw pointer but is not marked `unsafe`
--> $DIR/functions.rs:89:33
|
LL | unsafe { std::ptr::read(p) };
// compile-flags: --edition 2018
// aux-build:macro_rules.rs
// aux-build:macro_use_helper.rs
+// aux-build:proc_macro_derive.rs
// run-rustfix
// ignore-32bit
extern crate macro_use_helper as mac;
#[macro_use]
-extern crate clippy_mini_macro_test as mini_mac;
+extern crate proc_macro_derive as mini_mac;
mod a {
use mac::{pub_macro, inner_mod_macro, function_macro, ty_macro, pub_in_private_macro};
// compile-flags: --edition 2018
// aux-build:macro_rules.rs
// aux-build:macro_use_helper.rs
+// aux-build:proc_macro_derive.rs
// run-rustfix
// ignore-32bit
extern crate macro_use_helper as mac;
#[macro_use]
-extern crate clippy_mini_macro_test as mini_mac;
+extern crate proc_macro_derive as mini_mac;
mod a {
#[macro_use]
error: `macro_use` attributes are no longer needed in the Rust 2018 edition
- --> $DIR/macro_use_imports.rs:18:5
+ --> $DIR/macro_use_imports.rs:19:5
|
LL | #[macro_use]
| ^^^^^^^^^^^^ help: remove the attribute and import the macro directly, try: `use mac::{pub_macro, inner_mod_macro, function_macro, ty_macro, pub_in_private_macro};`
= note: `-D clippy::macro-use-imports` implied by `-D warnings`
error: `macro_use` attributes are no longer needed in the Rust 2018 edition
- --> $DIR/macro_use_imports.rs:20:5
+ --> $DIR/macro_use_imports.rs:25:5
|
LL | #[macro_use]
- | ^^^^^^^^^^^^ help: remove the attribute and import the macro directly, try: `use mini_mac::ClippyMiniMacroTest;`
+ | ^^^^^^^^^^^^ help: remove the attribute and import the macro directly, try: `use mac::inner::nested::string_add;`
error: `macro_use` attributes are no longer needed in the Rust 2018 edition
- --> $DIR/macro_use_imports.rs:22:5
+ --> $DIR/macro_use_imports.rs:21:5
|
LL | #[macro_use]
- | ^^^^^^^^^^^^ help: remove the attribute and import the macro directly, try: `use mac::{inner::foofoo, inner::try_err};`
+ | ^^^^^^^^^^^^ help: remove the attribute and import the macro directly, try: `use mini_mac::ClippyMiniMacroTest;`
error: `macro_use` attributes are no longer needed in the Rust 2018 edition
- --> $DIR/macro_use_imports.rs:24:5
+ --> $DIR/macro_use_imports.rs:23:5
|
LL | #[macro_use]
- | ^^^^^^^^^^^^ help: remove the attribute and import the macro directly, try: `use mac::inner::nested::string_add;`
+ | ^^^^^^^^^^^^ help: remove the attribute and import the macro directly, try: `use mac::{inner::foofoo, inner::try_err};`
error: aborting due to 4 previous errors
--- /dev/null
+// run-rustfix
+
+#![feature(custom_inner_attributes)]
+#![warn(clippy::manual_str_repeat)]
+
+use std::borrow::Cow;
+use std::iter::{repeat, FromIterator};
+
+fn main() {
+ let _: String = "test".repeat(10);
+ let _: String = "x".repeat(10);
+ let _: String = "'".repeat(10);
+ let _: String = "\"".repeat(10);
+
+ let x = "test";
+ let count = 10;
+ let _ = x.repeat(count + 2);
+
+ macro_rules! m {
+ ($e:expr) => {{ $e }};
+ }
+ // FIXME: macro args are fine
+ let _: String = repeat(m!("test")).take(m!(count)).collect();
+
+ let x = &x;
+ let _: String = (*x).repeat(count);
+
+ macro_rules! repeat_m {
+ ($e:expr) => {{ repeat($e) }};
+ }
+ // Don't lint, repeat is from a macro.
+ let _: String = repeat_m!("test").take(count).collect();
+
+ let x: Box<str> = Box::from("test");
+ let _: String = x.repeat(count);
+
+ #[derive(Clone)]
+ struct S;
+ impl FromIterator<Box<S>> for String {
+ fn from_iter<T: IntoIterator<Item = Box<S>>>(_: T) -> Self {
+ Self::new()
+ }
+ }
+ // Don't lint, wrong box type
+ let _: String = repeat(Box::new(S)).take(count).collect();
+
+ let _: String = Cow::Borrowed("test").repeat(count);
+
+ let x = "x".to_owned();
+ let _: String = x.repeat(count);
+
+ let x = 'x';
+ // Don't lint, not char literal
+ let _: String = repeat(x).take(count).collect();
+}
+
+fn _msrv_1_15() {
+ #![clippy::msrv = "1.15"]
+ // `str::repeat` was stabilized in 1.16. Do not lint this
+ let _: String = std::iter::repeat("test").take(10).collect();
+}
+
+fn _msrv_1_16() {
+ #![clippy::msrv = "1.16"]
+ let _: String = "test".repeat(10);
+}
--- /dev/null
+// run-rustfix
+
+#![feature(custom_inner_attributes)]
+#![warn(clippy::manual_str_repeat)]
+
+use std::borrow::Cow;
+use std::iter::{repeat, FromIterator};
+
+fn main() {
+ let _: String = std::iter::repeat("test").take(10).collect();
+ let _: String = std::iter::repeat('x').take(10).collect();
+ let _: String = std::iter::repeat('\'').take(10).collect();
+ let _: String = std::iter::repeat('"').take(10).collect();
+
+ let x = "test";
+ let count = 10;
+ let _ = repeat(x).take(count + 2).collect::<String>();
+
+ macro_rules! m {
+ ($e:expr) => {{ $e }};
+ }
+ // FIXME: macro args are fine
+ let _: String = repeat(m!("test")).take(m!(count)).collect();
+
+ let x = &x;
+ let _: String = repeat(*x).take(count).collect();
+
+ macro_rules! repeat_m {
+ ($e:expr) => {{ repeat($e) }};
+ }
+ // Don't lint, repeat is from a macro.
+ let _: String = repeat_m!("test").take(count).collect();
+
+ let x: Box<str> = Box::from("test");
+ let _: String = repeat(x).take(count).collect();
+
+ #[derive(Clone)]
+ struct S;
+ impl FromIterator<Box<S>> for String {
+ fn from_iter<T: IntoIterator<Item = Box<S>>>(_: T) -> Self {
+ Self::new()
+ }
+ }
+ // Don't lint, wrong box type
+ let _: String = repeat(Box::new(S)).take(count).collect();
+
+ let _: String = repeat(Cow::Borrowed("test")).take(count).collect();
+
+ let x = "x".to_owned();
+ let _: String = repeat(x).take(count).collect();
+
+ let x = 'x';
+ // Don't lint, not char literal
+ let _: String = repeat(x).take(count).collect();
+}
+
+fn _msrv_1_15() {
+ #![clippy::msrv = "1.15"]
+ // `str::repeat` was stabilized in 1.16. Do not lint this
+ let _: String = std::iter::repeat("test").take(10).collect();
+}
+
+fn _msrv_1_16() {
+ #![clippy::msrv = "1.16"]
+ let _: String = std::iter::repeat("test").take(10).collect();
+}
--- /dev/null
+error: manual implementation of `str::repeat` using iterators
+ --> $DIR/manual_str_repeat.rs:10:21
+ |
+LL | let _: String = std::iter::repeat("test").take(10).collect();
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try this: `"test".repeat(10)`
+ |
+ = note: `-D clippy::manual-str-repeat` implied by `-D warnings`
+
+error: manual implementation of `str::repeat` using iterators
+ --> $DIR/manual_str_repeat.rs:11:21
+ |
+LL | let _: String = std::iter::repeat('x').take(10).collect();
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try this: `"x".repeat(10)`
+
+error: manual implementation of `str::repeat` using iterators
+ --> $DIR/manual_str_repeat.rs:12:21
+ |
+LL | let _: String = std::iter::repeat('/'').take(10).collect();
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try this: `"'".repeat(10)`
+
+error: manual implementation of `str::repeat` using iterators
+ --> $DIR/manual_str_repeat.rs:13:21
+ |
+LL | let _: String = std::iter::repeat('"').take(10).collect();
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try this: `"/"".repeat(10)`
+
+error: manual implementation of `str::repeat` using iterators
+ --> $DIR/manual_str_repeat.rs:17:13
+ |
+LL | let _ = repeat(x).take(count + 2).collect::<String>();
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try this: `x.repeat(count + 2)`
+
+error: manual implementation of `str::repeat` using iterators
+ --> $DIR/manual_str_repeat.rs:26:21
+ |
+LL | let _: String = repeat(*x).take(count).collect();
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try this: `(*x).repeat(count)`
+
+error: manual implementation of `str::repeat` using iterators
+ --> $DIR/manual_str_repeat.rs:35:21
+ |
+LL | let _: String = repeat(x).take(count).collect();
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try this: `x.repeat(count)`
+
+error: manual implementation of `str::repeat` using iterators
+ --> $DIR/manual_str_repeat.rs:47:21
+ |
+LL | let _: String = repeat(Cow::Borrowed("test")).take(count).collect();
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try this: `Cow::Borrowed("test").repeat(count)`
+
+error: manual implementation of `str::repeat` using iterators
+ --> $DIR/manual_str_repeat.rs:50:21
+ |
+LL | let _: String = repeat(x).take(count).collect();
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try this: `x.repeat(count)`
+
+error: manual implementation of `str::repeat` using iterators
+ --> $DIR/manual_str_repeat.rs:65:21
+ |
+LL | let _: String = std::iter::repeat("test").take(10).collect();
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try this: `"test".repeat(10)`
+
+error: aborting due to 10 previous errors
+
#![warn(clippy::missing_docs_in_private_items)]
-#![feature(external_doc)]
-#![doc(include = "../../README.md")]
+#![doc = include_str!("../../README.md")]
fn main() {}
pub fn foo() {}
/// dox
pub fn foo1() {}
- fn foo2() {}
+ #[must_use = "yep"]
+ fn foo2() -> u32 {
+ 1
+ }
#[allow(clippy::missing_docs_in_private_items)]
pub fn foo3() {}
}
| ^^^^^^^^^^^^^^^
error: missing documentation for an associated function
- --> $DIR/missing-doc-impl.rs:70:5
+ --> $DIR/missing-doc-impl.rs:71:5
|
-LL | fn foo2() {}
- | ^^^^^^^^^^^^
+LL | / fn foo2() -> u32 {
+LL | | 1
+LL | | }
+ | |_____^
error: aborting due to 15 previous errors
pub struct Foobar;
}
-#[cfg(test)]
-mod test {
- #[test]
- fn it_works() {
- assert_eq!(2 + 2, 4);
- }
-}
-
fn main() {}
let vec = Vec::new();
let vec_val = g(&vec); // should not error, because `&Vec<T>` derefs to `&[T]`
h(&"foo"); // should not error, because the `&&str` is required, due to `&Trait`
- if let Some(cake) = Some(&5) {}
let garbl = match 42 {
44 => &a,
45 => {
impl<'a> Trait for &'a str {}
fn h(_: &dyn Trait) {}
-#[warn(clippy::needless_borrow)]
-#[allow(dead_code)]
-fn issue_1432() {
- let mut v = Vec::<String>::new();
- let _ = v.iter_mut().filter(|&ref a| a.is_empty());
- let _ = v.iter().filter(|&a| a.is_empty());
-
- let _ = v.iter().filter(|&a| a.is_empty());
-}
-
-#[allow(dead_code)]
-#[warn(clippy::needless_borrow)]
-#[derive(Debug)]
-enum Foo<'a> {
- Str(&'a str),
-}
let vec = Vec::new();
let vec_val = g(&vec); // should not error, because `&Vec<T>` derefs to `&[T]`
h(&"foo"); // should not error, because the `&&str` is required, due to `&Trait`
- if let Some(ref cake) = Some(&5) {}
let garbl = match 42 {
44 => &a,
45 => {
impl<'a> Trait for &'a str {}
fn h(_: &dyn Trait) {}
-#[warn(clippy::needless_borrow)]
-#[allow(dead_code)]
-fn issue_1432() {
- let mut v = Vec::<String>::new();
- let _ = v.iter_mut().filter(|&ref a| a.is_empty());
- let _ = v.iter().filter(|&ref a| a.is_empty());
-
- let _ = v.iter().filter(|&a| a.is_empty());
-}
-
-#[allow(dead_code)]
-#[warn(clippy::needless_borrow)]
-#[derive(Debug)]
-enum Foo<'a> {
- Str(&'a str),
-}
|
= note: `-D clippy::needless-borrow` implied by `-D warnings`
-error: this pattern creates a reference to a reference
- --> $DIR/needless_borrow.rs:21:17
- |
-LL | if let Some(ref cake) = Some(&5) {}
- | ^^^^^^^^ help: change this to: `cake`
-
error: this expression borrows a reference (`&i32`) that is immediately dereferenced by the compiler
- --> $DIR/needless_borrow.rs:28:15
+ --> $DIR/needless_borrow.rs:27:15
|
LL | 46 => &&a,
| ^^^ help: change this to: `&a`
-error: this pattern creates a reference to a reference
- --> $DIR/needless_borrow.rs:51:31
- |
-LL | let _ = v.iter().filter(|&ref a| a.is_empty());
- | ^^^^^ help: change this to: `a`
-
-error: aborting due to 4 previous errors
+error: aborting due to 2 previous errors
--- /dev/null
+// edition:2018
+// FIXME: run-rustfix waiting on multi-span suggestions
+
+#![warn(clippy::needless_borrow)]
+#![allow(clippy::needless_borrowed_reference)]
+
+fn f1(_: &str) {}
+macro_rules! m1 {
+ ($e:expr) => {
+ f1($e);
+ };
+}
+macro_rules! m3 {
+ ($i:ident) => {
+ Some(ref $i)
+ };
+}
+macro_rules! if_chain {
+ (if $e:expr; $($rest:tt)*) => {
+ if $e {
+ if_chain!($($rest)*)
+ }
+ };
+
+ (if let $p:pat = $e:expr; $($rest:tt)*) => {
+ if let $p = $e {
+ if_chain!($($rest)*)
+ }
+ };
+
+ (then $b:block) => {
+ $b
+ };
+}
+
+#[allow(dead_code)]
+fn main() {
+ let x = String::new();
+
+ // Ok, reference to a String.
+ let _: &String = match Some(x.clone()) {
+ Some(ref x) => x,
+ None => return,
+ };
+
+ // Ok, reference to a &mut String
+ let _: &&mut String = match Some(&mut x.clone()) {
+ Some(ref x) => x,
+ None => return,
+ };
+
+ // Ok, the pattern is from a macro
+ let _: &String = match Some(&x) {
+ m3!(x) => x,
+ None => return,
+ };
+
+ // Err, reference to a &String
+ let _: &String = match Some(&x) {
+ Some(ref x) => x,
+ None => return,
+ };
+
+ // Err, reference to a &String.
+ let _: &String = match Some(&x) {
+ Some(ref x) => *x,
+ None => return,
+ };
+
+ // Err, reference to a &String
+ let _: &String = match Some(&x) {
+ Some(ref x) => {
+ f1(x);
+ f1(*x);
+ x
+ },
+ None => return,
+ };
+
+ // Err, reference to a &String
+ match Some(&x) {
+ Some(ref x) => m1!(x),
+ None => return,
+ };
+
+ // Err, reference to a &String
+ let _ = |&ref x: &&String| {
+ let _: &String = x;
+ };
+
+ // Err, reference to a &String
+ let (ref y,) = (&x,);
+ let _: &String = *y;
+
+ let y = &&x;
+ // Ok, different y
+ let _: &String = *y;
+
+ let x = (0, 0);
+ // Err, reference to a &u32. Don't suggest adding a reference to the field access.
+ let _: u32 = match Some(&x) {
+ Some(ref x) => x.0,
+ None => return,
+ };
+
+ enum E {
+ A(&'static u32),
+ B(&'static u32),
+ }
+ // Err, reference to &u32.
+ let _: &u32 = match E::A(&0) {
+ E::A(ref x) | E::B(ref x) => *x,
+ };
+
+ // Err, reference to &String.
+ if_chain! {
+ if true;
+ if let Some(ref x) = Some(&String::new());
+ then {
+ f1(x);
+ }
+ }
+}
+
+// Err, reference to a &String
+fn f2<'a>(&ref x: &&'a String) -> &'a String {
+ let _: &String = x;
+ *x
+}
+
+trait T1 {
+ // Err, reference to a &String
+ fn f(&ref x: &&String) {
+ let _: &String = x;
+ }
+}
+
+struct S;
+impl T1 for S {
+ // Err, reference to a &String
+ fn f(&ref x: &&String) {
+ let _: &String = *x;
+ }
+}
+
+// Ok - used to error due to rustc bug
+#[allow(dead_code)]
+#[derive(Debug)]
+enum Foo<'a> {
+ Str(&'a str),
+}
--- /dev/null
+error: this pattern creates a reference to a reference
+ --> $DIR/needless_borrow_pat.rs:60:14
+ |
+LL | Some(ref x) => x,
+ | ^^^^^ help: try this: `x`
+ |
+ = note: `-D clippy::needless-borrow` implied by `-D warnings`
+
+error: this pattern creates a reference to a reference
+ --> $DIR/needless_borrow_pat.rs:66:14
+ |
+LL | Some(ref x) => *x,
+ | ^^^^^
+ |
+help: try this
+ |
+LL | Some(x) => x,
+ | ^ ^
+
+error: this pattern creates a reference to a reference
+ --> $DIR/needless_borrow_pat.rs:72:14
+ |
+LL | Some(ref x) => {
+ | ^^^^^
+ |
+help: try this
+ |
+LL | Some(x) => {
+LL | f1(x);
+LL | f1(x);
+ |
+
+error: this pattern creates a reference to a reference
+ --> $DIR/needless_borrow_pat.rs:82:14
+ |
+LL | Some(ref x) => m1!(x),
+ | ^^^^^ help: try this: `x`
+
+error: this pattern creates a reference to a reference
+ --> $DIR/needless_borrow_pat.rs:87:15
+ |
+LL | let _ = |&ref x: &&String| {
+ | ^^^^^ help: try this: `x`
+
+error: this pattern creates a reference to a reference
+ --> $DIR/needless_borrow_pat.rs:92:10
+ |
+LL | let (ref y,) = (&x,);
+ | ^^^^^
+ |
+help: try this
+ |
+LL | let (y,) = (&x,);
+LL | let _: &String = y;
+ |
+
+error: this pattern creates a reference to a reference
+ --> $DIR/needless_borrow_pat.rs:102:14
+ |
+LL | Some(ref x) => x.0,
+ | ^^^^^ help: try this: `x`
+
+error: this pattern creates a reference to a reference
+ --> $DIR/needless_borrow_pat.rs:112:14
+ |
+LL | E::A(ref x) | E::B(ref x) => *x,
+ | ^^^^^ ^^^^^
+ |
+help: try this
+ |
+LL | E::A(x) | E::B(x) => x,
+ | ^ ^ ^
+
+error: this pattern creates a reference to a reference
+ --> $DIR/needless_borrow_pat.rs:118:21
+ |
+LL | if let Some(ref x) = Some(&String::new());
+ | ^^^^^ help: try this: `x`
+
+error: this pattern creates a reference to a reference
+ --> $DIR/needless_borrow_pat.rs:126:12
+ |
+LL | fn f2<'a>(&ref x: &&'a String) -> &'a String {
+ | ^^^^^
+ |
+help: try this
+ |
+LL | fn f2<'a>(&x: &&'a String) -> &'a String {
+LL | let _: &String = x;
+LL | x
+ |
+
+error: this pattern creates a reference to a reference
+ --> $DIR/needless_borrow_pat.rs:133:11
+ |
+LL | fn f(&ref x: &&String) {
+ | ^^^^^ help: try this: `x`
+
+error: this pattern creates a reference to a reference
+ --> $DIR/needless_borrow_pat.rs:141:11
+ |
+LL | fn f(&ref x: &&String) {
+ | ^^^^^
+ |
+help: try this
+ |
+LL | fn f(&x: &&String) {
+LL | let _: &String = x;
+ |
+
+error: aborting due to 12 previous errors
+
-use std::collections::{BinaryHeap, HashMap, LinkedList, VecDeque};
+use std::collections::{BinaryHeap, HashMap, HashSet, LinkedList, VecDeque};
fn main() {
let sample = [1; 5];
buffer.len()
}
}
+
+fn allow_test() {
+ #[allow(clippy::needless_collect)]
+ let v = [1].iter().collect::<Vec<_>>();
+ v.into_iter().collect::<HashSet<_>>();
+}
let s: String = "foo".into();
FooString { s: s };
+ #[allow(clippy::no_effect)]
+ 0;
+
// Do not warn
get_number();
unsafe { unsafe_fn() };
--- /dev/null
+// edition:2018
+// FIXME: run-rustfix waiting on multi-span suggestions
+
+#![warn(clippy::ref_binding_to_reference)]
+#![allow(clippy::needless_borrowed_reference)]
+
+fn f1(_: &str) {}
+macro_rules! m2 {
+ ($e:expr) => {
+ f1(*$e);
+ };
+}
+macro_rules! m3 {
+ ($i:ident) => {
+ Some(ref $i)
+ };
+}
+
+#[allow(dead_code)]
+fn main() {
+ let x = String::new();
+
+ // Ok, the pattern is from a macro
+ let _: &&String = match Some(&x) {
+ m3!(x) => x,
+ None => return,
+ };
+
+ // Err, reference to a &String
+ let _: &&String = match Some(&x) {
+ Some(ref x) => x,
+ None => return,
+ };
+
+ // Err, reference to a &String
+ let _: &&String = match Some(&x) {
+ Some(ref x) => {
+ f1(x);
+ f1(*x);
+ x
+ },
+ None => return,
+ };
+
+ // Err, reference to a &String
+ match Some(&x) {
+ Some(ref x) => m2!(x),
+ None => return,
+ }
+
+ // Err, reference to a &String
+ let _ = |&ref x: &&String| {
+ let _: &&String = x;
+ };
+}
+
+// Err, reference to a &String
+fn f2<'a>(&ref x: &&'a String) -> &'a String {
+ let _: &&String = x;
+ *x
+}
+
+trait T1 {
+ // Err, reference to a &String
+ fn f(&ref x: &&String) {
+ let _: &&String = x;
+ }
+}
+
+struct S;
+impl T1 for S {
+ // Err, reference to a &String
+ fn f(&ref x: &&String) {
+ let _: &&String = x;
+ }
+}
--- /dev/null
+error: this pattern creates a reference to a reference
+ --> $DIR/ref_binding_to_reference.rs:31:14
+ |
+LL | Some(ref x) => x,
+ | ^^^^^
+ |
+ = note: `-D clippy::ref-binding-to-reference` implied by `-D warnings`
+help: try this
+ |
+LL | Some(x) => &x,
+ | ^ ^^
+
+error: this pattern creates a reference to a reference
+ --> $DIR/ref_binding_to_reference.rs:37:14
+ |
+LL | Some(ref x) => {
+ | ^^^^^
+ |
+help: try this
+ |
+LL | Some(x) => {
+LL | f1(x);
+LL | f1(x);
+LL | &x
+ |
+
+error: this pattern creates a reference to a reference
+ --> $DIR/ref_binding_to_reference.rs:47:14
+ |
+LL | Some(ref x) => m2!(x),
+ | ^^^^^
+ |
+help: try this
+ |
+LL | Some(x) => m2!(&x),
+ | ^ ^^
+
+error: this pattern creates a reference to a reference
+ --> $DIR/ref_binding_to_reference.rs:52:15
+ |
+LL | let _ = |&ref x: &&String| {
+ | ^^^^^
+ |
+help: try this
+ |
+LL | let _ = |&x: &&String| {
+LL | let _: &&String = &x;
+ |
+
+error: this pattern creates a reference to a reference
+ --> $DIR/ref_binding_to_reference.rs:58:12
+ |
+LL | fn f2<'a>(&ref x: &&'a String) -> &'a String {
+ | ^^^^^
+ |
+help: try this
+ |
+LL | fn f2<'a>(&x: &&'a String) -> &'a String {
+LL | let _: &&String = &x;
+LL | x
+ |
+
+error: this pattern creates a reference to a reference
+ --> $DIR/ref_binding_to_reference.rs:65:11
+ |
+LL | fn f(&ref x: &&String) {
+ | ^^^^^
+ |
+help: try this
+ |
+LL | fn f(&x: &&String) {
+LL | let _: &&String = &x;
+ |
+
+error: this pattern creates a reference to a reference
+ --> $DIR/ref_binding_to_reference.rs:73:11
+ |
+LL | fn f(&ref x: &&String) {
+ | ^^^^^
+ |
+help: try this
+ |
+LL | fn f(&x: &&String) {
+LL | let _: &&String = &x;
+ |
+
+error: aborting due to 7 previous errors
+
let rx1: i32;
let tx_cake: i32;
let rx_cake: i32;
+
+ // names often used in win32 code (for example WindowProc)
+ let wparam: i32;
+ let lparam: i32;
}
fn foo() {
| ^^^^^^
error: binding's name is too similar to existing binding
- --> $DIR/similar_names.rs:81:16
+ --> $DIR/similar_names.rs:85:16
|
LL | bpple: sprang,
| ^^^^^^
|
note: existing binding defined here
- --> $DIR/similar_names.rs:80:16
+ --> $DIR/similar_names.rs:84:16
|
LL | apple: spring,
| ^^^^^^
x.rsplit('x');
x.split_terminator('x');
x.rsplit_terminator('x');
- x.splitn(0, 'x');
- x.rsplitn(0, 'x');
+ x.splitn(2, 'x');
+ x.rsplitn(2, 'x');
x.matches('x');
x.rmatches('x');
x.match_indices('x');
x.rsplit("x");
x.split_terminator("x");
x.rsplit_terminator("x");
- x.splitn(0, "x");
- x.rsplitn(0, "x");
+ x.splitn(2, "x");
+ x.rsplitn(2, "x");
x.matches("x");
x.rmatches("x");
x.match_indices("x");
error: single-character string constant used as pattern
--> $DIR/single_char_pattern.rs:28:17
|
-LL | x.splitn(0, "x");
+LL | x.splitn(2, "x");
| ^^^ help: try using a `char` instead: `'x'`
error: single-character string constant used as pattern
--> $DIR/single_char_pattern.rs:29:18
|
-LL | x.rsplitn(0, "x");
+LL | x.rsplitn(2, "x");
| ^^^ help: try using a `char` instead: `'x'`
error: single-character string constant used as pattern
--- /dev/null
+#![warn(clippy::suspicious_splitn)]
+
+fn main() {
+ let _ = "a,b,c".splitn(3, ',');
+ let _ = [0, 1, 2, 1, 3].splitn(3, |&x| x == 1);
+ let _ = "".splitn(0, ',');
+ let _ = [].splitn(0, |&x: &u32| x == 1);
+
+ let _ = "a,b".splitn(0, ',');
+ let _ = "a,b".rsplitn(0, ',');
+ let _ = "a,b".splitn(1, ',');
+ let _ = [0, 1, 2].splitn(0, |&x| x == 1);
+ let _ = [0, 1, 2].splitn_mut(0, |&x| x == 1);
+ let _ = [0, 1, 2].splitn(1, |&x| x == 1);
+ let _ = [0, 1, 2].rsplitn_mut(1, |&x| x == 1);
+
+ const X: usize = 0;
+ let _ = "a,b".splitn(X + 1, ',');
+ let _ = "a,b".splitn(X, ',');
+}
--- /dev/null
+error: `splitn` called with `0` splits
+ --> $DIR/suspicious_splitn.rs:9:13
+ |
+LL | let _ = "a,b".splitn(0, ',');
+ | ^^^^^^^^^^^^^^^^^^^^
+ |
+ = note: `-D clippy::suspicious-splitn` implied by `-D warnings`
+ = note: the resulting iterator will always return `None`
+
+error: `rsplitn` called with `0` splits
+ --> $DIR/suspicious_splitn.rs:10:13
+ |
+LL | let _ = "a,b".rsplitn(0, ',');
+ | ^^^^^^^^^^^^^^^^^^^^^
+ |
+ = note: the resulting iterator will always return `None`
+
+error: `splitn` called with `1` split
+ --> $DIR/suspicious_splitn.rs:11:13
+ |
+LL | let _ = "a,b".splitn(1, ',');
+ | ^^^^^^^^^^^^^^^^^^^^
+ |
+ = note: the resulting iterator will always return the entire string followed by `None`
+
+error: `splitn` called with `0` splits
+ --> $DIR/suspicious_splitn.rs:12:13
+ |
+LL | let _ = [0, 1, 2].splitn(0, |&x| x == 1);
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+ |
+ = note: the resulting iterator will always return `None`
+
+error: `splitn_mut` called with `0` splits
+ --> $DIR/suspicious_splitn.rs:13:13
+ |
+LL | let _ = [0, 1, 2].splitn_mut(0, |&x| x == 1);
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+ |
+ = note: the resulting iterator will always return `None`
+
+error: `splitn` called with `1` split
+ --> $DIR/suspicious_splitn.rs:14:13
+ |
+LL | let _ = [0, 1, 2].splitn(1, |&x| x == 1);
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+ |
+ = note: the resulting iterator will always return the entire slice followed by `None`
+
+error: `rsplitn_mut` called with `1` split
+ --> $DIR/suspicious_splitn.rs:15:13
+ |
+LL | let _ = [0, 1, 2].rsplitn_mut(1, |&x| x == 1);
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+ |
+ = note: the resulting iterator will always return the entire slice followed by `None`
+
+error: `splitn` called with `1` split
+ --> $DIR/suspicious_splitn.rs:18:13
+ |
+LL | let _ = "a,b".splitn(X + 1, ',');
+ | ^^^^^^^^^^^^^^^^^^^^^^^^
+ |
+ = note: the resulting iterator will always return the entire string followed by `None`
+
+error: `splitn` called with `0` splits
+ --> $DIR/suspicious_splitn.rs:19:13
+ |
+LL | let _ = "a,b".splitn(X, ',');
+ | ^^^^^^^^^^^^^^^^^^^^
+ |
+ = note: the resulting iterator will always return `None`
+
+error: aborting due to 9 previous errors
+
LL | fn trait_method(&self, _foo: &Foo);
| ^^^^ help: consider passing by value instead: `Foo`
-error: this argument (N byte) is passed by reference, but would be more efficient if passed by value (limit: N byte)
- --> $DIR/trivially_copy_pass_by_ref.rs:80:37
- |
-LL | fn trait_method2(&self, _color: &Color);
- | ^^^^^^ help: consider passing by value instead: `Color`
-
error: this argument (N byte) is passed by reference, but would be more efficient if passed by value (limit: N byte)
--> $DIR/trivially_copy_pass_by_ref.rs:108:21
|
LL | fn foo(x: &i32) {
| ^^^^ help: consider passing by value instead: `i32`
-error: aborting due to 17 previous errors
+error: aborting due to 16 previous errors
unimplemented!()
}
-struct A;
+pub struct A;
impl A {
// should not be linted
// run-rustfix
+// aux-build:proc_macro_derive.rs
#![warn(clippy::unseparated_literal_suffix)]
#![allow(dead_code)]
#[macro_use]
-extern crate clippy_mini_macro_test;
+extern crate proc_macro_derive;
// Test for proc-macro attribute
#[derive(ClippyMiniMacroTest)]
// run-rustfix
+// aux-build:proc_macro_derive.rs
#![warn(clippy::unseparated_literal_suffix)]
#![allow(dead_code)]
#[macro_use]
-extern crate clippy_mini_macro_test;
+extern crate proc_macro_derive;
// Test for proc-macro attribute
#[derive(ClippyMiniMacroTest)]
error: integer type suffix should be separated by an underscore
- --> $DIR/unseparated_prefix_literals.rs:23:18
+ --> $DIR/unseparated_prefix_literals.rs:24:18
|
LL | let _fail1 = 1234i32;
| ^^^^^^^ help: add an underscore: `1234_i32`
= note: `-D clippy::unseparated-literal-suffix` implied by `-D warnings`
error: integer type suffix should be separated by an underscore
- --> $DIR/unseparated_prefix_literals.rs:24:18
+ --> $DIR/unseparated_prefix_literals.rs:25:18
|
LL | let _fail2 = 1234u32;
| ^^^^^^^ help: add an underscore: `1234_u32`
error: integer type suffix should be separated by an underscore
- --> $DIR/unseparated_prefix_literals.rs:25:18
+ --> $DIR/unseparated_prefix_literals.rs:26:18
|
LL | let _fail3 = 1234isize;
| ^^^^^^^^^ help: add an underscore: `1234_isize`
error: integer type suffix should be separated by an underscore
- --> $DIR/unseparated_prefix_literals.rs:26:18
+ --> $DIR/unseparated_prefix_literals.rs:27:18
|
LL | let _fail4 = 1234usize;
| ^^^^^^^^^ help: add an underscore: `1234_usize`
error: integer type suffix should be separated by an underscore
- --> $DIR/unseparated_prefix_literals.rs:27:18
+ --> $DIR/unseparated_prefix_literals.rs:28:18
|
LL | let _fail5 = 0x123isize;
| ^^^^^^^^^^ help: add an underscore: `0x123_isize`
error: float type suffix should be separated by an underscore
- --> $DIR/unseparated_prefix_literals.rs:31:19
+ --> $DIR/unseparated_prefix_literals.rs:32:19
|
LL | let _failf1 = 1.5f32;
| ^^^^^^ help: add an underscore: `1.5_f32`
error: float type suffix should be separated by an underscore
- --> $DIR/unseparated_prefix_literals.rs:32:19
+ --> $DIR/unseparated_prefix_literals.rs:33:19
|
LL | let _failf2 = 1f32;
| ^^^^ help: add an underscore: `1_f32`
error: integer type suffix should be separated by an underscore
- --> $DIR/unseparated_prefix_literals.rs:15:9
+ --> $DIR/unseparated_prefix_literals.rs:16:9
|
LL | 42usize
| ^^^^^^^ help: add an underscore: `42_usize`
= note: this error originates in the macro `lit_from_macro` (in Nightly builds, run with -Z macro-backtrace for more info)
error: integer type suffix should be separated by an underscore
- --> $DIR/unseparated_prefix_literals.rs:40:16
+ --> $DIR/unseparated_prefix_literals.rs:41:16
|
LL | assert_eq!(4897u32, 32223);
| ^^^^^^^ help: add an underscore: `4897_u32`
// edition:2018
#![warn(clippy::wrong_self_convention)]
-#![warn(clippy::wrong_pub_self_convention)]
#![allow(dead_code)]
fn main() {}
error: methods called `from_*` usually take no `self`
- --> $DIR/wrong_self_convention.rs:18:17
+ --> $DIR/wrong_self_convention.rs:17:17
|
LL | fn from_i32(self) {}
| ^^^^
= help: consider choosing a less ambiguous name
error: methods called `from_*` usually take no `self`
- --> $DIR/wrong_self_convention.rs:24:21
+ --> $DIR/wrong_self_convention.rs:23:21
|
LL | pub fn from_i64(self) {}
| ^^^^
= help: consider choosing a less ambiguous name
error: methods called `as_*` usually take `self` by reference or `self` by mutable reference
- --> $DIR/wrong_self_convention.rs:36:15
+ --> $DIR/wrong_self_convention.rs:35:15
|
LL | fn as_i32(self) {}
| ^^^^
= help: consider choosing a less ambiguous name
error: methods called `into_*` usually take `self` by value
- --> $DIR/wrong_self_convention.rs:38:17
+ --> $DIR/wrong_self_convention.rs:37:17
|
LL | fn into_i32(&self) {}
| ^^^^^
= help: consider choosing a less ambiguous name
error: methods called `is_*` usually take `self` by reference or no `self`
- --> $DIR/wrong_self_convention.rs:40:15
+ --> $DIR/wrong_self_convention.rs:39:15
|
LL | fn is_i32(self) {}
| ^^^^
= help: consider choosing a less ambiguous name
error: methods with the following characteristics: (`to_*` and `self` type is not `Copy`) usually take `self` by reference
- --> $DIR/wrong_self_convention.rs:42:15
+ --> $DIR/wrong_self_convention.rs:41:15
|
LL | fn to_i32(self) {}
| ^^^^
= help: consider choosing a less ambiguous name
error: methods called `from_*` usually take no `self`
- --> $DIR/wrong_self_convention.rs:44:17
+ --> $DIR/wrong_self_convention.rs:43:17
|
LL | fn from_i32(self) {}
| ^^^^
= help: consider choosing a less ambiguous name
error: methods called `as_*` usually take `self` by reference or `self` by mutable reference
- --> $DIR/wrong_self_convention.rs:46:19
+ --> $DIR/wrong_self_convention.rs:45:19
|
LL | pub fn as_i64(self) {}
| ^^^^
= help: consider choosing a less ambiguous name
error: methods called `into_*` usually take `self` by value
- --> $DIR/wrong_self_convention.rs:47:21
+ --> $DIR/wrong_self_convention.rs:46:21
|
LL | pub fn into_i64(&self) {}
| ^^^^^
= help: consider choosing a less ambiguous name
error: methods called `is_*` usually take `self` by reference or no `self`
- --> $DIR/wrong_self_convention.rs:48:19
+ --> $DIR/wrong_self_convention.rs:47:19
|
LL | pub fn is_i64(self) {}
| ^^^^
= help: consider choosing a less ambiguous name
error: methods with the following characteristics: (`to_*` and `self` type is not `Copy`) usually take `self` by reference
- --> $DIR/wrong_self_convention.rs:49:19
+ --> $DIR/wrong_self_convention.rs:48:19
|
LL | pub fn to_i64(self) {}
| ^^^^
= help: consider choosing a less ambiguous name
error: methods called `from_*` usually take no `self`
- --> $DIR/wrong_self_convention.rs:50:21
+ --> $DIR/wrong_self_convention.rs:49:21
|
LL | pub fn from_i64(self) {}
| ^^^^
= help: consider choosing a less ambiguous name
error: methods called `as_*` usually take `self` by reference or `self` by mutable reference
- --> $DIR/wrong_self_convention.rs:95:19
+ --> $DIR/wrong_self_convention.rs:94:19
|
LL | fn as_i32(self) {}
| ^^^^
= help: consider choosing a less ambiguous name
error: methods called `into_*` usually take `self` by value
- --> $DIR/wrong_self_convention.rs:98:25
+ --> $DIR/wrong_self_convention.rs:97:25
|
LL | fn into_i32_ref(&self) {}
| ^^^^^
= help: consider choosing a less ambiguous name
error: methods called `is_*` usually take `self` by reference or no `self`
- --> $DIR/wrong_self_convention.rs:100:19
+ --> $DIR/wrong_self_convention.rs:99:19
|
LL | fn is_i32(self) {}
| ^^^^
= help: consider choosing a less ambiguous name
error: methods called `from_*` usually take no `self`
- --> $DIR/wrong_self_convention.rs:104:21
+ --> $DIR/wrong_self_convention.rs:103:21
|
LL | fn from_i32(self) {}
| ^^^^
= help: consider choosing a less ambiguous name
error: methods called `as_*` usually take `self` by reference or `self` by mutable reference
- --> $DIR/wrong_self_convention.rs:119:19
+ --> $DIR/wrong_self_convention.rs:118:19
|
LL | fn as_i32(self);
| ^^^^
= help: consider choosing a less ambiguous name
error: methods called `into_*` usually take `self` by value
- --> $DIR/wrong_self_convention.rs:122:25
+ --> $DIR/wrong_self_convention.rs:121:25
|
LL | fn into_i32_ref(&self);
| ^^^^^
= help: consider choosing a less ambiguous name
error: methods called `is_*` usually take `self` by reference or no `self`
- --> $DIR/wrong_self_convention.rs:124:19
+ --> $DIR/wrong_self_convention.rs:123:19
|
LL | fn is_i32(self);
| ^^^^
= help: consider choosing a less ambiguous name
error: methods called `from_*` usually take no `self`
- --> $DIR/wrong_self_convention.rs:128:21
+ --> $DIR/wrong_self_convention.rs:127:21
|
LL | fn from_i32(self);
| ^^^^
= help: consider choosing a less ambiguous name
error: methods called `into_*` usually take `self` by value
- --> $DIR/wrong_self_convention.rs:146:25
+ --> $DIR/wrong_self_convention.rs:145:25
|
LL | fn into_i32_ref(&self);
| ^^^^^
= help: consider choosing a less ambiguous name
error: methods called `from_*` usually take no `self`
- --> $DIR/wrong_self_convention.rs:152:21
+ --> $DIR/wrong_self_convention.rs:151:21
|
LL | fn from_i32(self);
| ^^^^
= help: consider choosing a less ambiguous name
error: methods with the following characteristics: (`to_*` and `self` type is `Copy`) usually take `self` by value
- --> $DIR/wrong_self_convention.rs:176:22
+ --> $DIR/wrong_self_convention.rs:175:22
|
LL | fn to_u64_v2(&self) -> u64 {
| ^^^^^
= help: consider choosing a less ambiguous name
error: methods with the following characteristics: (`to_*` and `self` type is not `Copy`) usually take `self` by reference
- --> $DIR/wrong_self_convention.rs:185:19
+ --> $DIR/wrong_self_convention.rs:184:19
|
LL | fn to_u64(self) -> u64 {
| ^^^^
// edition:2018
#![warn(clippy::wrong_self_convention)]
-#![warn(clippy::wrong_pub_self_convention)]
#![allow(dead_code)]
fn main() {}
error: methods called `from_*` usually take no `self`
- --> $DIR/wrong_self_convention2.rs:56:29
+ --> $DIR/wrong_self_convention2.rs:55:29
|
LL | pub fn from_be_self(self) -> Self {
| ^^^^
= help: consider choosing a less ambiguous name
error: methods called `from_*` usually take no `self`
- --> $DIR/wrong_self_convention2.rs:65:25
+ --> $DIR/wrong_self_convention2.rs:64:25
|
LL | fn from_be_self(self) -> Self;
| ^^^^
+++ /dev/null
-#!/usr/bin/bash
-
-# This run `kcov` on Clippy. The coverage report will be at
-# `./target/cov/index.html`.
-# `compile-test` is special. `kcov` does not work directly on it so these files
-# are compiled manually.
-
-tests=$(find tests/ -maxdepth 1 -name '*.rs' ! -name compile-test.rs -exec basename {} .rs \;)
-tmpdir=$(mktemp -d)
-
-cargo test --no-run --verbose
-
-for t in $tests; do
- kcov \
- --verify \
- --include-path="$(pwd)/src,$(pwd)/clippy_lints/src" \
- "$tmpdir/$t" \
- cargo test --test "$t"
-done
-
-for t in ./tests/compile-fail/*.rs; do
- kcov \
- --verify \
- --include-path="$(pwd)/src,$(pwd)/clippy_lints/src" \
- "$tmpdir/compile-fail-$(basename "$t")" \
- cargo run -- -L target/debug -L target/debug/deps -Z no-trans "$t"
-done
-
-for t in ./tests/run-pass/*.rs; do
- kcov \
- --verify \
- --include-path="$(pwd)/src,$(pwd)/clippy_lints/src" \
- "$tmpdir/run-pass-$(basename "$t")" \
- cargo run -- -L target/debug -L target/debug/deps -Z no-trans "$t"
-done
-
-kcov --verify --merge target/cov "$tmpdir"/*
/// whether to run `tidy` when a rustdoc test fails
pub has_tidy: bool,
+ /// The current Rust channel
+ pub channel: String,
+
// Configuration for various run-make tests frobbing things like C compilers
// or querying about various LLVM component information.
pub cc: String,
let has_msan = util::MSAN_SUPPORTED_TARGETS.contains(&&*config.target);
let has_tsan = util::TSAN_SUPPORTED_TARGETS.contains(&&*config.target);
let has_hwasan = util::HWASAN_SUPPORTED_TARGETS.contains(&&*config.target);
+ // for `-Z gcc-ld=lld`
+ let has_rust_lld = config
+ .compile_lib_path
+ .join("rustlib")
+ .join(&config.target)
+ .join("bin")
+ .join("gcc-ld")
+ .join(if config.host.contains("windows") { "ld.exe" } else { "ld" })
+ .exists();
iter_header(testfile, None, rdr, &mut |ln| {
// we should check if any only-<platform> exists and if it exists
if config.debugger == Some(Debugger::Lldb) && ignore_lldb(config, ln) {
props.ignore = true;
}
+
+ if !has_rust_lld && config.parse_name_directive(ln, "needs-rust-lld") {
+ props.ignore = true;
+ }
}
if let Some(s) = config.parse_aux_build(ln) {
if let Some(edition) = config.parse_edition(ln) {
self.compile_flags.push(format!("--edition={}", edition));
+ if edition == "2021" {
+ self.compile_flags.push("-Zunstable-options".to_string());
+ }
}
config.parse_and_update_revisions(ln, &mut self.revisions);
name == util::get_arch(&self.target) || // architecture
name == util::get_pointer_width(&self.target) || // pointer width
name == self.stage_id.split('-').next().unwrap() || // stage
+ name == self.channel || // channel
(self.target != self.host && name == "cross-compile") ||
(name == "endian-big" && util::is_big_endian(&self.target)) ||
(self.remote_test_client.is_some() && name == "remote") ||
"--llvm-components=",
"--android-cross-path=",
"--target=x86_64-unknown-linux-gnu",
+ "--channel=nightly",
];
let args = args.iter().map(ToString::to_string).collect();
crate::parse_config(args)
assert!(!parse_rs(&config, "// needs-asm-support").ignore);
}
+#[test]
+fn channel() {
+ let mut config = config();
+ config.channel = "beta".into();
+
+ assert!(parse_rs(&config, "// ignore-beta").ignore);
+ assert!(parse_rs(&config, "// only-nightly").ignore);
+ assert!(parse_rs(&config, "// only-stable").ignore);
+
+ assert!(!parse_rs(&config, "// only-beta").ignore);
+ assert!(!parse_rs(&config, "// ignore-nightly").ignore);
+ assert!(!parse_rs(&config, "// ignore-stable").ignore);
+}
+
#[test]
fn test_extract_version_range() {
use super::{extract_llvm_version, extract_version_range};
"enable this to generate a Rustfix coverage file, which is saved in \
`./<build_base>/rustfix_missing_coverage.txt`",
)
- .optflag("h", "help", "show this message");
+ .optflag("h", "help", "show this message")
+ .reqopt("", "channel", "current Rust channel", "CHANNEL");
let (argv0, args_) = args.split_first().unwrap();
if args.len() == 1 || args[1] == "-h" || args[1] == "--help" {
compare_mode: matches.opt_str("compare-mode").map(CompareMode::parse),
rustfix_coverage: matches.opt_present("rustfix-coverage"),
has_tidy,
+ channel: matches.opt_str("channel").unwrap(),
cc: matches.opt_str("cc").unwrap(),
cxx: matches.opt_str("cxx").unwrap(),
ignore,
should_panic,
allow_fail: false,
+ #[cfg(not(bootstrap))]
+ compile_fail: false,
+ #[cfg(not(bootstrap))]
+ no_run: false,
test_type: test::TestType::Unknown,
},
testfn: make_test_closure(config, testpaths, revision),
get_lib_name(&aux_path.trim_end_matches(".rs").replace('-', "_"), is_dylib);
rustc.arg("--extern").arg(format!("{}={}/{}", aux_name, aux_dir.display(), lib_name));
}
+ if !self.props.aux_crates.is_empty() {
+ rustc.arg("-Zunstable-options");
+ }
aux_dir
}
|| self.config.target.contains("nvptx")
|| self.is_vxworks_pure_static()
|| self.config.target.contains("sgx")
+ || self.config.target.contains("bpf")
{
// We primarily compile all auxiliary libraries as dynamic libraries
// to avoid code size bloat and large binaries as much as possible
{
let mut diff_output = File::create(&diff_filename).unwrap();
+ let mut wrote_data = false;
for entry in walkdir::WalkDir::new(out_dir) {
let entry = entry.expect("failed to read file");
let extension = entry.path().extension().and_then(|p| p.to_str());
if let Ok(s) = std::fs::read(&expected_path) { s } else { continue };
let actual_path = entry.path();
let actual = std::fs::read(&actual_path).unwrap();
- diff_output
- .write_all(&unified_diff::diff(
- &expected,
- &expected_path.to_string_lossy(),
- &actual,
- &actual_path.to_string_lossy(),
- 3,
- ))
- .unwrap();
+ let diff = unified_diff::diff(
+ &expected,
+ &expected_path.to_string_lossy(),
+ &actual,
+ &actual_path.to_string_lossy(),
+ 3,
+ );
+ wrote_data |= !diff.is_empty();
+ diff_output.write_all(&diff).unwrap();
}
}
+
+ if !wrote_data {
+ println!("note: diff is identical to nightly rustdoc");
+ assert!(diff_output.metadata().unwrap().len() == 0);
+ return;
+ } else if self.config.verbose {
+ eprintln!("printing diff:");
+ let mut buf = Vec::new();
+ diff_output.read_to_end(&mut buf).unwrap();
+ std::io::stderr().lock().write_all(&mut buf).unwrap();
+ }
}
match self.config.color {
let mut tested = 0;
for _ in res.stdout.split('\n').filter(|s| s.starts_with("test ")).inspect(|s| {
- let tmp: Vec<&str> = s.split(" - ").collect();
- if tmp.len() == 2 {
- let path = tmp[0].rsplit("test ").next().unwrap();
+ if let Some((left, right)) = s.split_once(" - ") {
+ let path = left.rsplit("test ").next().unwrap();
if let Some(ref mut v) = files.get_mut(&path.replace('\\', "/")) {
tested += 1;
- let mut iter = tmp[1].split("(line ");
+ let mut iter = right.split("(line ");
iter.next();
let line = iter
.next()
("armv7s", "arm"),
("asmjs", "asmjs"),
("avr", "avr"),
+ ("bpfeb", "bpf"),
+ ("bpfel", "bpf"),
("hexagon", "hexagon"),
("i386", "x86"),
("i586", "x86"),
jsonpath_lib = "0.2"
getopts = "0.2"
regex = "1.4"
-lazy_static = "1.4"
-shlex = "0.1"
-serde = "1.0"
+shlex = "1.0"
serde_json = "1.0"
fs-err = "2.5.0"
+once_cell = "1.0"
use jsonpath_lib::select;
-use lazy_static::lazy_static;
+use once_cell::sync::Lazy;
use regex::{Regex, RegexBuilder};
use serde_json::Value;
use std::borrow::Cow;
}
}
-lazy_static! {
- static ref LINE_PATTERN: Regex = RegexBuilder::new(
+static LINE_PATTERN: Lazy<Regex> = Lazy::new(|| {
+ RegexBuilder::new(
r#"
\s(?P<invalid>!?)@(?P<negated>!?)
(?P<cmd>[A-Za-z]+(?:-[A-Za-z]+)*)
(?P<args>.*)$
- "#
+ "#,
)
.ignore_whitespace(true)
.unicode(true)
.build()
- .unwrap();
-}
+ .unwrap()
+});
fn print_err(msg: &str, lineno: usize) {
eprintln!("Invalid command: {} on line {}", msg, lineno)
if [ ! -e "linkchecker/main.rs" ] || [ "$iterative" = "0" ]
then
echo "Downloading linkchecker source..."
+ nightly_hash=$(rustc +nightly -Vv | grep commit-hash | cut -f2 -d" ")
+ url="https://raw.githubusercontent.com/rust-lang/rust"
mkdir linkchecker
- curl -o linkchecker/Cargo.toml \
- https://raw.githubusercontent.com/rust-lang/rust/master/src/tools/linkchecker/Cargo.toml
- curl -o linkchecker/main.rs \
- https://raw.githubusercontent.com/rust-lang/rust/master/src/tools/linkchecker/main.rs
+ curl -o linkchecker/Cargo.toml ${url}/${nightly_hash}/src/tools/linkchecker/Cargo.toml
+ curl -o linkchecker/main.rs ${url}/${nightly_hash}/src/tools/linkchecker/main.rs
fi
echo "Building book \"$book_name\"..."
check_path="linkcheck/$book_name"
fi
echo "Running linkchecker on \"$check_path\"..."
-cargo run --manifest-path=linkchecker/Cargo.toml -- "$check_path"
+cargo run --release --manifest-path=linkchecker/Cargo.toml -- "$check_path"
if [ "$iterative" = "0" ]
then
//! A few exceptions are allowed as there's known bugs in rustdoc, but this
//! should catch the majority of "broken link" cases.
-use std::collections::hash_map::Entry;
+use std::cell::RefCell;
use std::collections::{HashMap, HashSet};
use std::env;
use std::fs;
+use std::io::ErrorKind;
use std::path::{Component, Path, PathBuf};
use std::rc::Rc;
+use std::time::Instant;
use once_cell::sync::Lazy;
use regex::Regex;
-use crate::Redirect::*;
-
// Add linkcheck exceptions here
// If at all possible you should use intra-doc links to avoid linkcheck issues. These
// are cases where that does not work
}
fn main() {
- let docs = env::args_os().nth(1).unwrap();
+ let docs = env::args_os().nth(1).expect("doc path should be first argument");
let docs = env::current_dir().unwrap().join(docs);
- let mut errors = false;
- walk(&mut HashMap::new(), &docs, &docs, &mut errors);
- if errors {
- panic!("found some broken links");
+ let mut checker = Checker { root: docs.clone(), cache: HashMap::new() };
+ let mut report = Report {
+ errors: 0,
+ start: Instant::now(),
+ html_files: 0,
+ html_redirects: 0,
+ links_checked: 0,
+ links_ignored_external: 0,
+ links_ignored_exception: 0,
+ intra_doc_exceptions: 0,
+ };
+ checker.walk(&docs, &mut report);
+ report.report();
+ if report.errors != 0 {
+ println!("found some broken links");
+ std::process::exit(1);
}
}
-#[derive(Debug)]
-pub enum LoadError {
- IOError(std::io::Error),
- BrokenRedirect(PathBuf, std::io::Error),
- IsRedirect,
+struct Checker {
+ root: PathBuf,
+ cache: Cache,
}
-enum Redirect {
- SkipRedirect,
- FromRedirect(bool),
+struct Report {
+ errors: u32,
+ start: Instant,
+ html_files: u32,
+ html_redirects: u32,
+ links_checked: u32,
+ links_ignored_external: u32,
+ links_ignored_exception: u32,
+ intra_doc_exceptions: u32,
}
-struct FileEntry {
- source: Rc<String>,
- ids: HashSet<String>,
+/// A cache entry.
+enum FileEntry {
+ /// An HTML file.
+ ///
+ /// This includes the contents of the HTML file, and an optional set of
+ /// HTML IDs. The IDs are used for checking fragments. The are computed
+ /// as-needed. The source is discarded (replaced with an empty string)
+ /// after the file has been checked, to conserve on memory.
+ HtmlFile { source: Rc<String>, ids: RefCell<HashSet<String>> },
+ /// This file is an HTML redirect to the given local path.
+ Redirect { target: PathBuf },
+ /// This is not an HTML file.
+ OtherFile,
+ /// This is a directory.
+ Dir,
+ /// The file doesn't exist.
+ Missing,
}
-type Cache = HashMap<PathBuf, FileEntry>;
+/// A cache to speed up file access.
+type Cache = HashMap<String, FileEntry>;
fn small_url_encode(s: &str) -> String {
s.replace("<", "%3C")
.replace("\"", "%22")
}
-impl FileEntry {
- fn parse_ids(&mut self, file: &Path, contents: &str, errors: &mut bool) {
- if self.ids.is_empty() {
- with_attrs_in_source(contents, " id", |fragment, i, _| {
- let frag = fragment.trim_start_matches("#").to_owned();
- let encoded = small_url_encode(&frag);
- if !self.ids.insert(frag) {
- *errors = true;
- println!("{}:{}: id is not unique: `{}`", file.display(), i, fragment);
- }
- // Just in case, we also add the encoded id.
- self.ids.insert(encoded);
- });
- }
- }
-}
-
-fn walk(cache: &mut Cache, root: &Path, dir: &Path, errors: &mut bool) {
- for entry in t!(dir.read_dir()).map(|e| t!(e)) {
- let path = entry.path();
- let kind = t!(entry.file_type());
- if kind.is_dir() {
- walk(cache, root, &path, errors);
- } else {
- let pretty_path = check(cache, root, &path, errors);
- if let Some(pretty_path) = pretty_path {
- let entry = cache.get_mut(&pretty_path).unwrap();
- // we don't need the source anymore,
- // so drop to reduce memory-usage
- entry.source = Rc::new(String::new());
+impl Checker {
+ /// Primary entry point for walking the filesystem to find HTML files to check.
+ fn walk(&mut self, dir: &Path, report: &mut Report) {
+ for entry in t!(dir.read_dir()).map(|e| t!(e)) {
+ let path = entry.path();
+ let kind = t!(entry.file_type());
+ if kind.is_dir() {
+ self.walk(&path, report);
+ } else {
+ self.check(&path, report);
}
}
}
-}
-
-fn is_intra_doc_exception(file: &Path, link: &str) -> bool {
- if let Some(entry) = INTRA_DOC_LINK_EXCEPTIONS.iter().find(|&(f, _)| file.ends_with(f)) {
- entry.1.is_empty() || entry.1.contains(&link)
- } else {
- false
- }
-}
-fn is_exception(file: &Path, link: &str) -> bool {
- if let Some(entry) = LINKCHECK_EXCEPTIONS.iter().find(|&(f, _)| file.ends_with(f)) {
- entry.1.contains(&link)
- } else {
- // FIXME(#63351): Concat trait in alloc/slice reexported in primitive page
- //
- // NOTE: This cannot be added to `LINKCHECK_EXCEPTIONS` because the resolved path
- // calculated in `check` function is outside `build/<triple>/doc` dir.
- // So the `strip_prefix` method just returns the old absolute broken path.
- if file.ends_with("std/primitive.slice.html") {
- if link.ends_with("primitive.slice.html") {
- return true;
+ /// Checks a single file.
+ fn check(&mut self, file: &Path, report: &mut Report) {
+ let (pretty_path, entry) = self.load_file(file, report);
+ let source = match entry {
+ FileEntry::Missing => panic!("missing file {:?} while walking", file),
+ FileEntry::Dir => unreachable!("never with `check` path"),
+ FileEntry::OtherFile => return,
+ FileEntry::Redirect { .. } => return,
+ FileEntry::HtmlFile { source, ids } => {
+ parse_ids(&mut ids.borrow_mut(), &pretty_path, source, report);
+ source.clone()
}
- }
- false
- }
-}
-
-fn check(cache: &mut Cache, root: &Path, file: &Path, errors: &mut bool) -> Option<PathBuf> {
- // Ignore non-HTML files.
- if file.extension().and_then(|s| s.to_str()) != Some("html") {
- return None;
- }
+ };
- let res = load_file(cache, root, file, SkipRedirect);
- let (pretty_file, contents) = match res {
- Ok(res) => res,
- Err(_) => return None,
- };
- {
- cache.get_mut(&pretty_file).unwrap().parse_ids(&pretty_file, &contents, errors);
- }
+ // Search for anything that's the regex 'href[ ]*=[ ]*".*?"'
+ with_attrs_in_source(&source, " href", |url, i, base| {
+ // Ignore external URLs
+ if url.starts_with("http:")
+ || url.starts_with("https:")
+ || url.starts_with("javascript:")
+ || url.starts_with("ftp:")
+ || url.starts_with("irc:")
+ || url.starts_with("data:")
+ {
+ report.links_ignored_external += 1;
+ return;
+ }
+ report.links_checked += 1;
+ let (url, fragment) = match url.split_once('#') {
+ None => (url, None),
+ Some((url, fragment)) => (url, Some(fragment)),
+ };
+ // NB: the `splitn` always succeeds, even if the delimiter is not present.
+ let url = url.splitn(2, '?').next().unwrap();
+
+ // Once we've plucked out the URL, parse it using our base url and
+ // then try to extract a file path.
+ let mut path = file.to_path_buf();
+ if !base.is_empty() || !url.is_empty() {
+ path.pop();
+ for part in Path::new(base).join(url).components() {
+ match part {
+ Component::Prefix(_) | Component::RootDir => {
+ // Avoid absolute paths as they make the docs not
+ // relocatable by making assumptions on where the docs
+ // are hosted relative to the site root.
+ report.errors += 1;
+ println!(
+ "{}:{}: absolute path - {}",
+ pretty_path,
+ i + 1,
+ Path::new(base).join(url).display()
+ );
+ return;
+ }
+ Component::CurDir => {}
+ Component::ParentDir => {
+ path.pop();
+ }
+ Component::Normal(s) => {
+ path.push(s);
+ }
+ }
+ }
+ }
- // Search for anything that's the regex 'href[ ]*=[ ]*".*?"'
- with_attrs_in_source(&contents, " href", |url, i, base| {
- // Ignore external URLs
- if url.starts_with("http:")
- || url.starts_with("https:")
- || url.starts_with("javascript:")
- || url.starts_with("ftp:")
- || url.starts_with("irc:")
- || url.starts_with("data:")
- {
- return;
- }
- let (url, fragment) = match url.split_once('#') {
- None => (url, None),
- Some((url, fragment)) => (url, Some(fragment)),
- };
- // NB: the `splitn` always succeeds, even if the delimiter is not present.
- let url = url.splitn(2, '?').next().unwrap();
-
- // Once we've plucked out the URL, parse it using our base url and
- // then try to extract a file path.
- let mut path = file.to_path_buf();
- if !base.is_empty() || !url.is_empty() {
- path.pop();
- for part in Path::new(base).join(url).components() {
- match part {
- Component::Prefix(_) | Component::RootDir => {
- // Avoid absolute paths as they make the docs not
- // relocatable by making assumptions on where the docs
- // are hosted relative to the site root.
- *errors = true;
+ let (target_pretty_path, target_entry) = self.load_file(&path, report);
+ let (target_source, target_ids) = match target_entry {
+ FileEntry::Missing => {
+ if is_exception(file, &target_pretty_path) {
+ report.links_ignored_exception += 1;
+ } else {
+ report.errors += 1;
println!(
- "{}:{}: absolute path - {}",
- pretty_file.display(),
+ "{}:{}: broken link - `{}`",
+ pretty_path,
i + 1,
- Path::new(base).join(url).display()
+ target_pretty_path
);
- return;
- }
- Component::CurDir => {}
- Component::ParentDir => {
- path.pop();
}
- Component::Normal(s) => {
- path.push(s);
- }
- }
- }
- }
-
- // Alright, if we've found a file name then this file had better
- // exist! If it doesn't then we register and print an error.
- if path.exists() {
- if path.is_dir() {
- // Links to directories show as directory listings when viewing
- // the docs offline so it's best to avoid them.
- *errors = true;
- let pretty_path = path.strip_prefix(root).unwrap_or(&path);
- println!(
- "{}:{}: directory link - {}",
- pretty_file.display(),
- i + 1,
- pretty_path.display()
- );
- return;
- }
- if let Some(extension) = path.extension() {
- // Ignore none HTML files.
- if extension != "html" {
return;
}
- }
- let res = load_file(cache, root, &path, FromRedirect(false));
- let (pretty_path, contents) = match res {
- Ok(res) => res,
- Err(LoadError::IOError(err)) => {
- panic!("error loading {}: {}", path.display(), err);
- }
- Err(LoadError::BrokenRedirect(target, _)) => {
- *errors = true;
+ FileEntry::Dir => {
+ // Links to directories show as directory listings when viewing
+ // the docs offline so it's best to avoid them.
+ report.errors += 1;
println!(
- "{}:{}: broken redirect to {}",
- pretty_file.display(),
+ "{}:{}: directory link to `{}` \
+ (directory links should use index.html instead)",
+ pretty_path,
i + 1,
- target.display()
+ target_pretty_path
);
return;
}
- Err(LoadError::IsRedirect) => unreachable!(),
+ FileEntry::OtherFile => return,
+ FileEntry::Redirect { target } => {
+ let t = target.clone();
+ drop(target);
+ let (target, redir_entry) = self.load_file(&t, report);
+ match redir_entry {
+ FileEntry::Missing => {
+ report.errors += 1;
+ println!(
+ "{}:{}: broken redirect from `{}` to `{}`",
+ pretty_path,
+ i + 1,
+ target_pretty_path,
+ target
+ );
+ return;
+ }
+ FileEntry::Redirect { target } => {
+ // Redirect to a redirect, this link checker
+ // currently doesn't support this, since it would
+ // require cycle checking, etc.
+ report.errors += 1;
+ println!(
+ "{}:{}: redirect from `{}` to `{}` \
+ which is also a redirect (not supported)",
+ pretty_path,
+ i + 1,
+ target_pretty_path,
+ target.display()
+ );
+ return;
+ }
+ FileEntry::Dir => {
+ report.errors += 1;
+ println!(
+ "{}:{}: redirect from `{}` to `{}` \
+ which is a directory \
+ (directory links should use index.html instead)",
+ pretty_path,
+ i + 1,
+ target_pretty_path,
+ target
+ );
+ return;
+ }
+ FileEntry::OtherFile => return,
+ FileEntry::HtmlFile { source, ids } => (source, ids),
+ }
+ }
+ FileEntry::HtmlFile { source, ids } => (source, ids),
};
+ // Alright, if we've found an HTML file for the target link. If
+ // this is a fragment link, also check that the `id` exists.
if let Some(ref fragment) = fragment {
// Fragments like `#1-6` are most likely line numbers to be
// interpreted by javascript, so we're ignoring these
return;
}
- let entry = &mut cache.get_mut(&pretty_path).unwrap();
- entry.parse_ids(&pretty_path, &contents, errors);
+ parse_ids(&mut target_ids.borrow_mut(), &pretty_path, target_source, report);
+
+ if target_ids.borrow().contains(*fragment) {
+ return;
+ }
- if !entry.ids.contains(*fragment) && !is_exception(file, &format!("#{}", fragment))
- {
- *errors = true;
- print!("{}:{}: broken link fragment ", pretty_file.display(), i + 1);
- println!("`#{}` pointing to `{}`", fragment, pretty_path.display());
+ if is_exception(file, &format!("#{}", fragment)) {
+ report.links_ignored_exception += 1;
+ } else {
+ report.errors += 1;
+ print!("{}:{}: broken link fragment ", pretty_path, i + 1);
+ println!("`#{}` pointing to `{}`", fragment, pretty_path);
};
}
- } else {
- let pretty_path = path.strip_prefix(root).unwrap_or(&path);
- if !is_exception(file, pretty_path.to_str().unwrap()) {
- *errors = true;
- print!("{}:{}: broken link - ", pretty_file.display(), i + 1);
- println!("{}", pretty_path.display());
+ });
+
+ // Search for intra-doc links that rustdoc didn't warn about
+ // FIXME(#77199, 77200) Rustdoc should just warn about these directly.
+ // NOTE: only looks at one line at a time; in practice this should find most links
+ for (i, line) in source.lines().enumerate() {
+ for broken_link in BROKEN_INTRA_DOC_LINK.captures_iter(line) {
+ if is_intra_doc_exception(file, &broken_link[1]) {
+ report.intra_doc_exceptions += 1;
+ } else {
+ report.errors += 1;
+ print!("{}:{}: broken intra-doc link - ", pretty_path, i + 1);
+ println!("{}", &broken_link[0]);
+ }
}
}
- });
-
- // Search for intra-doc links that rustdoc didn't warn about
- // FIXME(#77199, 77200) Rustdoc should just warn about these directly.
- // NOTE: only looks at one line at a time; in practice this should find most links
- for (i, line) in contents.lines().enumerate() {
- for broken_link in BROKEN_INTRA_DOC_LINK.captures_iter(line) {
- if !is_intra_doc_exception(file, &broken_link[1]) {
- *errors = true;
- print!("{}:{}: broken intra-doc link - ", pretty_file.display(), i + 1);
- println!("{}", &broken_link[0]);
- }
+ // we don't need the source anymore,
+ // so drop to reduce memory-usage
+ match self.cache.get_mut(&pretty_path).unwrap() {
+ FileEntry::HtmlFile { source, .. } => *source = Rc::new(String::new()),
+ _ => unreachable!("must be html file"),
}
}
- Some(pretty_file)
-}
-fn load_file(
- cache: &mut Cache,
- root: &Path,
- file: &Path,
- redirect: Redirect,
-) -> Result<(PathBuf, Rc<String>), LoadError> {
- let pretty_file = PathBuf::from(file.strip_prefix(root).unwrap_or(&file));
-
- let (maybe_redirect, contents) = match cache.entry(pretty_file.clone()) {
- Entry::Occupied(entry) => (None, entry.get().source.clone()),
- Entry::Vacant(entry) => {
- let contents = match fs::read_to_string(file) {
- Ok(s) => Rc::new(s),
- Err(err) => {
- return Err(if let FromRedirect(true) = redirect {
- LoadError::BrokenRedirect(file.to_path_buf(), err)
+ /// Load a file from disk, or from the cache if available.
+ fn load_file(&mut self, file: &Path, report: &mut Report) -> (String, &FileEntry) {
+ let pretty_path =
+ file.strip_prefix(&self.root).unwrap_or(&file).to_str().unwrap().to_string();
+
+ let entry =
+ self.cache.entry(pretty_path.clone()).or_insert_with(|| match fs::metadata(file) {
+ Ok(metadata) if metadata.is_dir() => FileEntry::Dir,
+ Ok(_) => {
+ if file.extension().and_then(|s| s.to_str()) != Some("html") {
+ FileEntry::OtherFile
} else {
- LoadError::IOError(err)
- });
+ report.html_files += 1;
+ load_html_file(file, report)
+ }
}
- };
-
- let maybe = maybe_redirect(&contents);
- if maybe.is_some() {
- if let SkipRedirect = redirect {
- return Err(LoadError::IsRedirect);
+ Err(e) if e.kind() == ErrorKind::NotFound => FileEntry::Missing,
+ Err(e) => {
+ panic!("unexpected read error for {}: {}", file.display(), e);
}
- } else {
- entry.insert(FileEntry { source: contents.clone(), ids: HashSet::new() });
- }
- (maybe, contents)
+ });
+ (pretty_path, entry)
+ }
+}
+
+impl Report {
+ fn report(&self) {
+ println!("checked links in: {:.1}s", self.start.elapsed().as_secs_f64());
+ println!("number of HTML files scanned: {}", self.html_files);
+ println!("number of HTML redirects found: {}", self.html_redirects);
+ println!("number of links checked: {}", self.links_checked);
+ println!("number of links ignored due to external: {}", self.links_ignored_external);
+ println!("number of links ignored due to exceptions: {}", self.links_ignored_exception);
+ println!("number of intra doc links ignored: {}", self.intra_doc_exceptions);
+ println!("errors found: {}", self.errors);
+ }
+}
+
+fn load_html_file(file: &Path, report: &mut Report) -> FileEntry {
+ let source = match fs::read_to_string(file) {
+ Ok(s) => Rc::new(s),
+ Err(err) => {
+ // This usually should not fail since `metadata` was already
+ // called successfully on this file.
+ panic!("unexpected read error for {}: {}", file.display(), err);
}
};
- match maybe_redirect.map(|url| file.parent().unwrap().join(url)) {
- Some(redirect_file) => load_file(cache, root, &redirect_file, FromRedirect(true)),
- None => Ok((pretty_file, contents)),
+ match maybe_redirect(&source) {
+ Some(target) => {
+ report.html_redirects += 1;
+ let target = file.parent().unwrap().join(target);
+ FileEntry::Redirect { target }
+ }
+ None => FileEntry::HtmlFile { source: source.clone(), ids: RefCell::new(HashSet::new()) },
+ }
+}
+
+fn is_intra_doc_exception(file: &Path, link: &str) -> bool {
+ if let Some(entry) = INTRA_DOC_LINK_EXCEPTIONS.iter().find(|&(f, _)| file.ends_with(f)) {
+ entry.1.is_empty() || entry.1.contains(&link)
+ } else {
+ false
}
}
+fn is_exception(file: &Path, link: &str) -> bool {
+ if let Some(entry) = LINKCHECK_EXCEPTIONS.iter().find(|&(f, _)| file.ends_with(f)) {
+ entry.1.contains(&link)
+ } else {
+ // FIXME(#63351): Concat trait in alloc/slice reexported in primitive page
+ //
+ // NOTE: This cannot be added to `LINKCHECK_EXCEPTIONS` because the resolved path
+ // calculated in `check` function is outside `build/<triple>/doc` dir.
+ // So the `strip_prefix` method just returns the old absolute broken path.
+ if file.ends_with("std/primitive.slice.html") {
+ if link.ends_with("primitive.slice.html") {
+ return true;
+ }
+ }
+ false
+ }
+}
+
+/// If the given HTML file contents is an HTML redirect, this returns the
+/// destination path given in the redirect.
fn maybe_redirect(source: &str) -> Option<String> {
const REDIRECT: &str = "<p>Redirecting to <a href=";
let mut lines = source.lines();
- let redirect_line = lines.nth(6)?;
+ let redirect_line = lines.nth(7)?;
redirect_line.find(REDIRECT).map(|i| {
let rest = &redirect_line[(i + REDIRECT.len() + 1)..];
})
}
-fn with_attrs_in_source<F: FnMut(&str, usize, &str)>(contents: &str, attr: &str, mut f: F) {
+fn with_attrs_in_source<F: FnMut(&str, usize, &str)>(source: &str, attr: &str, mut f: F) {
let mut base = "";
- for (i, mut line) in contents.lines().enumerate() {
+ for (i, mut line) in source.lines().enumerate() {
while let Some(j) = line.find(attr) {
let rest = &line[j + attr.len()..];
// The base tag should always be the first link in the document so
}
}
}
+
+fn parse_ids(ids: &mut HashSet<String>, file: &str, source: &str, report: &mut Report) {
+ if ids.is_empty() {
+ with_attrs_in_source(source, " id", |fragment, i, _| {
+ let frag = fragment.trim_start_matches("#").to_owned();
+ let encoded = small_url_encode(&frag);
+ if !ids.insert(frag) {
+ report.errors += 1;
+ println!("{}:{}: id is not unique: `{}`", file, i, fragment);
+ }
+ // Just in case, we also add the encoded id.
+ ids.insert(encoded);
+ });
+ }
+}
--- /dev/null
+<html>
+<body>
+<a href="bar.html">test</a>
+</body>
+</html>
--- /dev/null
+<html>
+<body>
+<a href="#somefrag">test</a>
+</body>
+</html>
--- /dev/null
+<html>
+<body>
+</body>
+</html>
--- /dev/null
+<html>
+<body>
+<a href="../bar.html#somefrag">test</a>
+</body>
+</html>
--- /dev/null
+<html>
+<body>
+ <a href="redir-bad.html">bad redir</a>
+</body>
+</html>
--- /dev/null
+<!DOCTYPE html>
+<html lang="en">
+<head>
+ <meta http-equiv="refresh" content="0;URL=sometarget">
+</head>
+<body>
+ <p>Redirecting to <a href="sometarget">sometarget</a>...</p>
+ <script>location.replace("sometarget" + location.search + location.hash);</script>
+</body>
+</html>
--- /dev/null
+use std::path::Path;
+use std::process::{Command, ExitStatus};
+
+fn run(dirname: &str) -> (ExitStatus, String, String) {
+ let output = Command::new(env!("CARGO_BIN_EXE_linkchecker"))
+ .current_dir(Path::new(env!("CARGO_MANIFEST_DIR")).join("tests"))
+ .arg(dirname)
+ .output()
+ .unwrap();
+ let stdout = String::from_utf8(output.stdout).unwrap();
+ let stderr = String::from_utf8(output.stderr).unwrap();
+ (output.status, stdout, stderr)
+}
+
+fn broken_test(dirname: &str, expected: &str) {
+ let (status, stdout, stderr) = run(dirname);
+ assert!(!status.success());
+ if !stdout.contains(expected) {
+ panic!(
+ "stdout did not contain expected text: {}\n\
+ --- stdout:\n\
+ {}\n\
+ --- stderr:\n\
+ {}\n",
+ expected, stdout, stderr
+ );
+ }
+}
+
+fn valid_test(dirname: &str) {
+ let (status, stdout, stderr) = run(dirname);
+ if !status.success() {
+ panic!(
+ "test did not succeed as expected\n\
+ --- stdout:\n\
+ {}\n\
+ --- stderr:\n\
+ {}\n",
+ stdout, stderr
+ );
+ }
+}
+
+#[test]
+fn valid() {
+ valid_test("valid/inner");
+}
+
+#[test]
+fn basic_broken() {
+ broken_test("basic_broken", "bar.html");
+}
+
+#[test]
+fn broken_fragment_local() {
+ broken_test("broken_fragment_local", "#somefrag");
+}
+
+#[test]
+fn broken_fragment_remote() {
+ broken_test("broken_fragment_remote/inner", "#somefrag");
+}
+
+#[test]
+fn broken_redir() {
+ broken_test("broken_redir", "sometarget");
+}
+
+#[test]
+fn directory_link() {
+ broken_test("directory_link", "somedir");
+}
+
+#[test]
+fn redirect_loop() {
+ broken_test("redirect_loop", "redir-bad.html");
+}
--- /dev/null
+<html>
+<body>
+ <a href="somedir">dir link</a>
+</body>
+</html>
--- /dev/null
+<html>
+<body>
+</body>
+</html>
--- /dev/null
+<html>
+<body>
+ <a href="redir-bad.html">loop link</a>
+</body>
+</html>
--- /dev/null
+<!DOCTYPE html>
+<html lang="en">
+<head>
+ <meta http-equiv="refresh" content="0;URL=redir-bad.html">
+</head>
+<body>
+ <p>Redirecting to <a href="redir-bad.html">redir-bad.html</a>...</p>
+ <script>location.replace("redir-bad.html" + location.search + location.hash);</script>
+</body>
+</html>
--- /dev/null
+<html>
+<body>
+
+ <h2 id="barfrag">Bar</h2>
+
+</body>
+</html>
--- /dev/null
+<html>
+<body>
+ <a href="#localfrag">test local frag</a>
+ <a href="../outer.html">remote link</a>
+ <a href="../outer.html#somefrag">remote link with fragment</a>
+ <a href="bar.html">this book</a>
+ <a href="bar.html#barfrag">this book with fragment</a>
+ <a href="https://example.com/doesnotexist">external links not validated</a>
+ <a href="redir.html#redirfrag">Redirect</a>
+
+ <h2 id="localfrag">Local</h2>
+
+</body>
+</html>
--- /dev/null
+<!DOCTYPE html>
+<html lang="en">
+<head>
+ <meta http-equiv="refresh" content="0;URL=xxx">
+</head>
+<body>
+ <p>Redirecting to <a href="xxx">xxx</a>...</p>
+ <script>location.replace("xxx" + location.search + location.hash);</script>
+ These files are skipped, but probably shouldn't be.
+</body>
+</html>
--- /dev/null
+<html>
+<body>
+ <h2 id="redirfrag">Redir</h2>
+</body>
+</html>
--- /dev/null
+<!DOCTYPE html>
+<html lang="en">
+<head>
+ <meta http-equiv="refresh" content="0;URL=redir-target.html">
+</head>
+<body>
+ <p>Redirecting to <a href="redir-target.html">redir-target.html</a>...</p>
+ <script>location.replace("redir-target.html" + location.search + location.hash);</script>
+</body>
+</html>
--- /dev/null
+<html>
+<body>
+<a id="somefrag"></a>
+</body>
+</html>
-Subproject commit 3a249581280ea0181cf3ae0d2028ee8b88d3d1e4
+Subproject commit 35af23b6a94459da538ee1479e863c7699620f84
-Subproject commit 097d8908339e20435078233a55a1a3335fe7c2eb
+Subproject commit 517e9d62c095a04fa497d6b6d3c63b31696a88b4
-Subproject commit 3022a2c3a255db2ac31c6183971ed8ba6e88f82c
+Subproject commit f0618a8f06a464840079f30b3e25bcdcca3922a3
function showHelp() {
console.log("rustdoc-js options:");
console.log(" --doc-folder [PATH] : location of the generated doc folder");
+ console.log(" --file [PATH] : file to run (can be repeated)");
console.log(" --help : show this message then quit");
console.log(" --tests-folder [PATH] : location of the .GOML tests folder");
}
var opts = {
"doc_folder": "",
"tests_folder": "",
+ "files": [],
};
var correspondances = {
"--doc-folder": "doc_folder",
for (var i = 0; i < args.length; ++i) {
if (args[i] === "--doc-folder"
- || args[i] === "--tests-folder") {
+ || args[i] === "--tests-folder"
+ || args[i] === "--file") {
i += 1;
if (i >= args.length) {
console.log("Missing argument after `" + args[i - 1] + "` option.");
return null;
}
- opts[correspondances[args[i - 1]]] = args[i];
+ if (args[i - 1] !== "--file") {
+ opts[correspondances[args[i - 1]]] = args[i];
+ } else {
+ opts["files"].push(args[i]);
+ }
} else if (args[i] === "--help") {
showHelp();
process.exit(0);
// This is more convenient that setting fields one by one.
options.parseArguments([
"--no-screenshot",
+ // This option shows what puppeteer "code" is run
+ // "--debug",
+ // This option disable the headless mode, allowing you to see what's going on.
+ // "--no-headless",
+ // The text isn't rendered by default because of a lot of small differences
+ // between hosts.
+ // "--show-text",
"--variable", "DOC_PATH", opts["doc_folder"],
]);
} catch (error) {
}
let failed = false;
- let files = fs.readdirSync(opts["tests_folder"]).filter(file => path.extname(file) == ".goml");
+ let files;
+ if (opts["files"].length === 0) {
+ files = fs.readdirSync(opts["tests_folder"]).filter(file => path.extname(file) == ".goml");
+ } else {
+ files = opts["files"].filter(file => path.extname(file) == ".goml");
+ }
files.sort();
for (var i = 0; i < files.length; ++i) {
}
ast::ExprKind::Unary(op, ref subexpr) => rewrite_unary_op(context, op, subexpr, shape),
ast::ExprKind::Struct(ref struct_expr) => {
- let ast::StructExpr { fields, path, rest } = &**struct_expr;
+ let ast::StructExpr {
+ fields, path, rest, ..
+ } = &**struct_expr;
rewrite_struct_lit(context, path, fields, rest, &expr.attrs, expr.span, shape)
}
ast::ExprKind::Tup(ref items) => {
| ast::PatKind::Path(..)
| ast::PatKind::Range(..) => false,
ast::PatKind::Tuple(ref subpats) => subpats.len() <= 1,
- ast::PatKind::TupleStruct(ref path, ref subpats) => {
+ ast::PatKind::TupleStruct(_, ref path, ref subpats) => {
path.segments.len() <= 1 && subpats.len() <= 1
}
ast::PatKind::Box(ref p) | ast::PatKind::Ref(ref p, _) | ast::PatKind::Paren(ref p) => {
PatKind::Path(ref q_self, ref path) => {
rewrite_path(context, PathContext::Expr, q_self.as_ref(), path, shape)
}
- PatKind::TupleStruct(ref path, ref pat_vec) => {
+ PatKind::TupleStruct(_, ref path, ref pat_vec) => {
let path_str = rewrite_path(context, PathContext::Expr, None, path, shape)?;
rewrite_tuple_pat(pat_vec, Some(path_str), self.span, context, shape)
}
.collect();
Some(format!("[{}]", rw.join(", ")))
}
- PatKind::Struct(ref path, ref fields, ellipsis) => {
+ PatKind::Struct(_, ref path, ref fields, ellipsis) => {
rewrite_struct_pat(path, fields, ellipsis, self.span, context, shape)
}
PatKind::MacCall(ref mac) => {
"ar",
"autocfg",
"bitflags",
- "byteorder",
"cfg-if",
"cranelift-bforest",
"cranelift-codegen",
"cranelift-native",
"cranelift-object",
"crc32fast",
- "errno",
- "errno-dragonfly",
- "gcc",
"gimli",
"hashbrown",
"indexmap",
"log",
"mach",
"object",
- "proc-macro2",
- "quote",
"regalloc",
"region",
"rustc-hash",
"smallvec",
- "syn",
"target-lexicon",
- "thiserror",
- "thiserror-impl",
- "unicode-xid",
"winapi",
"winapi-i686-pc-windows-gnu",
"winapi-x86_64-pc-windows-gnu",
// A few of those error codes can't be tested but all the others can and *should* be tested!
const EXEMPTED_FROM_TEST: &[&str] = &[
- "E0183", "E0227", "E0279", "E0280", "E0311", "E0313", "E0314", "E0315", "E0377", "E0461",
- "E0462", "E0464", "E0465", "E0472", "E0473", "E0474", "E0475", "E0476", "E0479", "E0480",
- "E0481", "E0482", "E0483", "E0484", "E0485", "E0486", "E0487", "E0488", "E0489", "E0514",
- "E0519", "E0523", "E0553", "E0554", "E0570", "E0629", "E0630", "E0640", "E0717", "E0727",
- "E0729",
+ "E0227", "E0279", "E0280", "E0313", "E0314", "E0315", "E0377", "E0461", "E0462", "E0464",
+ "E0465", "E0473", "E0474", "E0475", "E0476", "E0479", "E0480", "E0481", "E0482", "E0483",
+ "E0484", "E0485", "E0486", "E0487", "E0488", "E0489", "E0514", "E0519", "E0523", "E0553",
+ "E0554", "E0570", "E0629", "E0630", "E0640", "E0717", "E0729",
];
// Some error codes don't have any tests apparently...
-const IGNORE_EXPLANATION_CHECK: &[&str] = &["E0570", "E0601", "E0602", "E0639", "E0729"];
+const IGNORE_EXPLANATION_CHECK: &[&str] = &["E0570", "E0601", "E0602", "E0729"];
fn check_error_code_explanation(
f: &str,
.expect("failed to canonicalize error explanation file path");
match read_to_string(&path) {
Ok(content) => {
- if !IGNORE_EXPLANATION_CHECK.contains(&err_code.as_str())
- && !check_if_error_code_is_test_in_explanation(&content, &err_code)
- {
+ let has_test = check_if_error_code_is_test_in_explanation(&content, &err_code);
+ if !has_test && !IGNORE_EXPLANATION_CHECK.contains(&err_code.as_str()) {
errors.push(format!(
"`{}` doesn't use its own error code in compile_fail example",
path.display(),
));
+ } else if has_test && IGNORE_EXPLANATION_CHECK.contains(&err_code.as_str()) {
+ errors.push(format!(
+ "`{}` has a compile_fail example with its own error code, it shouldn't \
+ be listed in IGNORE_EXPLANATION_CHECK!",
+ path.display(),
+ ));
}
if check_error_code_explanation(&content, error_codes, err_code) {
errors.push(format!(
for (err_code, nb) in &error_codes {
if !*nb && !EXEMPTED_FROM_TEST.contains(&err_code.as_str()) {
errors.push(format!("Error code {} needs to have at least one UI test!", err_code));
+ } else if *nb && EXEMPTED_FROM_TEST.contains(&err_code.as_str()) {
+ errors.push(format!(
+ "Error code {} has a UI test, it shouldn't be listed into EXEMPTED_FROM_TEST!",
+ err_code
+ ));
}
}
}
const ENTRY_LIMIT: usize = 1000;
// FIXME: The following limits should be reduced eventually.
const ROOT_ENTRY_LIMIT: usize = 1371;
-const ISSUES_ENTRY_LIMIT: usize = 2558;
+const ISSUES_ENTRY_LIMIT: usize = 2559;
fn check_entries(path: &Path, bad: &mut bool) {
let dirs = walkdir::WalkDir::new(&path.join("test/ui"))
let doc_targets_md = std::fs::read_to_string(&src).expect("failed to read input source");
let doc_targets: HashSet<_> = doc_targets_md
.lines()
- .filter(|line| line.starts_with('`') && line.contains('|'))
+ .filter(|line| line.starts_with(&['`', '['][..]) && line.contains('|'))
.map(|line| line.split('`').skip(1).next().expect("expected target code span"))
.collect();
"regression-from-stable-to-stable",
"regression-from-stable-to-beta",
"regression-from-stable-to-nightly",
- "I-unsound 💥",
+ "I-unsound",
]
exclude_labels = [
"P-*",