"url 2.1.1",
]
-[[package]]
-name = "annotate-snippets"
-version = "0.6.1"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "c7021ce4924a3f25f802b2cccd1af585e39ea1a363a1aa2e72afe54b67a3a7a7"
-dependencies = [
- "ansi_term 0.11.0",
-]
-
[[package]]
name = "annotate-snippets"
version = "0.8.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d78ea013094e5ea606b1c05fe35f1dd7ea1eb1ea259908d040b25bd5ec677ee5"
+dependencies = [
+ "yansi-term",
+]
[[package]]
name = "ansi_term"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "8f8cb5d814eb646a863c4f24978cff2880c4be96ad8cde2c0f0678732902e271"
-[[package]]
-name = "arrayvec"
-version = "0.5.2"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "23b62fc65de8e4e7f52534fb52b0f3ed04746ae267519eef2a83941e8085068b"
-
[[package]]
name = "arrayvec"
version = "0.7.0"
[[package]]
name = "racer"
-version = "2.1.45"
+version = "2.1.46"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "15408926f6207643150e0fc2c54a75a689b192df03ac6c59d42ea99c6782c7f7"
+checksum = "e7cbda48a9124ed2e83766d2c15e3725710d344abca35fad8cf52341a55883b1"
dependencies = [
"bitflags",
"clap",
[[package]]
name = "rustc-ap-rustc_arena"
-version = "712.0.0"
+version = "718.0.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "259cca0e975ecb05fd289ace45280c30ff792efc04e856a7f18b7fc86a3cb610"
+checksum = "526610f47139efa440178239553b59ea805ff57a532b4e295c71d2a9b18fd676"
dependencies = [
"rustc-ap-rustc_data_structures",
"smallvec",
[[package]]
name = "rustc-ap-rustc_ast"
-version = "712.0.0"
+version = "718.0.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "bb9be435d50c88e94bbad6ea468c8680b52c5043bb298ab8058d05251717f8f8"
+checksum = "cf6a9dda0804a7243b0282e3b75a8cf4654c7a61f033e587751941e1fe39391b"
dependencies = [
"bitflags",
"rustc-ap-rustc_data_structures",
"tracing",
]
-[[package]]
-name = "rustc-ap-rustc_ast_passes"
-version = "712.0.0"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "75246dd1a95a57f7767e53bde3971baa2d948078e180564709f5ea46cf863ddd"
-dependencies = [
- "itertools 0.9.0",
- "rustc-ap-rustc_ast",
- "rustc-ap-rustc_ast_pretty",
- "rustc-ap-rustc_attr",
- "rustc-ap-rustc_data_structures",
- "rustc-ap-rustc_errors",
- "rustc-ap-rustc_feature",
- "rustc-ap-rustc_parse",
- "rustc-ap-rustc_session",
- "rustc-ap-rustc_span",
- "tracing",
-]
-
[[package]]
name = "rustc-ap-rustc_ast_pretty"
-version = "712.0.0"
+version = "718.0.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "79bede0b44bed453fd0034b7ba492840391f6486bf3e17a1af12922f0b98d4cc"
+checksum = "82f5019be8b41a58664169fd2f4b1a37fe82705681db394b76419e4e87d40ab1"
dependencies = [
"rustc-ap-rustc_ast",
"rustc-ap-rustc_span",
"tracing",
]
-[[package]]
-name = "rustc-ap-rustc_attr"
-version = "712.0.0"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "84a92a4a34b996694ca2dab70361c60d2d48c07adce57e8155b7ec75e069e3ea"
-dependencies = [
- "rustc-ap-rustc_ast",
- "rustc-ap-rustc_ast_pretty",
- "rustc-ap-rustc_data_structures",
- "rustc-ap-rustc_errors",
- "rustc-ap-rustc_feature",
- "rustc-ap-rustc_lexer",
- "rustc-ap-rustc_macros",
- "rustc-ap-rustc_serialize",
- "rustc-ap-rustc_session",
- "rustc-ap-rustc_span",
-]
-
[[package]]
name = "rustc-ap-rustc_data_structures"
-version = "712.0.0"
+version = "718.0.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "9cbfa7f82517a1b2efe7106c864c3f930b1da8aff07a27fd317af2f36522fd2e"
+checksum = "a701717fb14549331085756b9741ae3b4bf35808489f1887d72c1d0e0fe52b77"
dependencies = [
- "arrayvec 0.5.2",
+ "arrayvec",
"bitflags",
"cfg-if 0.1.10",
- "crossbeam-utils 0.7.2",
+ "crossbeam-utils 0.8.3",
"ena",
"indexmap",
"jobserver",
"libc",
"measureme",
+ "memmap2",
"parking_lot",
"rustc-ap-rustc_graphviz",
"rustc-ap-rustc_index",
[[package]]
name = "rustc-ap-rustc_errors"
-version = "712.0.0"
+version = "718.0.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "58a272a5101843bcb40900cc9ccf80ecfec62830bb1f4a242986da4a34c0da89"
+checksum = "e3182ce85e8bfc96443475547f2f5aa2b5e67655d9b88721795f36f0ba9e265a"
dependencies = [
- "annotate-snippets 0.8.0",
+ "annotate-snippets",
"atty",
"rustc-ap-rustc_data_structures",
"rustc-ap-rustc_lint_defs",
"winapi 0.3.9",
]
-[[package]]
-name = "rustc-ap-rustc_expand"
-version = "712.0.0"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "3bc7988f3facf2402fe057405ef0f7fbacc7e7a483da25e35a35ac09491fbbfb"
-dependencies = [
- "rustc-ap-rustc_ast",
- "rustc-ap-rustc_ast_passes",
- "rustc-ap-rustc_ast_pretty",
- "rustc-ap-rustc_attr",
- "rustc-ap-rustc_data_structures",
- "rustc-ap-rustc_errors",
- "rustc-ap-rustc_feature",
- "rustc-ap-rustc_lexer",
- "rustc-ap-rustc_lint_defs",
- "rustc-ap-rustc_macros",
- "rustc-ap-rustc_parse",
- "rustc-ap-rustc_serialize",
- "rustc-ap-rustc_session",
- "rustc-ap-rustc_span",
- "smallvec",
- "tracing",
-]
-
[[package]]
name = "rustc-ap-rustc_feature"
-version = "712.0.0"
+version = "718.0.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "5e931cd1580ae60c5737d3fa57633034935e885414e794d83b3e52a81021985c"
+checksum = "eed033b93270126ef60963c3ebbd0e026bf53b985172b6366c7b0e7881c9d507"
dependencies = [
"rustc-ap-rustc_data_structures",
"rustc-ap-rustc_span",
[[package]]
name = "rustc-ap-rustc_fs_util"
-version = "712.0.0"
+version = "718.0.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "8fe9422e10d5b441d2a78202667bc85d7cf713a087b9ae6cdea0dfc825d79f07"
+checksum = "28ee6531986a205101e09fd143d7bf31897388f33b1814d4bcc45fd62211dca6"
[[package]]
name = "rustc-ap-rustc_graphviz"
-version = "712.0.0"
+version = "718.0.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "ffffffdef9fd51db69c1d4c045ced8aaab999be5627f2d3a0ce020d74c1f1e50"
+checksum = "3398fddc0e23d2db89c036f8952ddf78cadc597f7059752116e69483e164a5b6"
[[package]]
name = "rustc-ap-rustc_index"
-version = "712.0.0"
+version = "718.0.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "7f6f53afc4f7111c82295cb7ea3878f520bbac6a2c5a12e125b4ca9156498cff"
+checksum = "dca4e27eb5b701f6bbd47d8fc9d242378fca3e4107a519a28415c2989c4a3bd3"
dependencies = [
- "arrayvec 0.5.2",
+ "arrayvec",
"rustc-ap-rustc_macros",
"rustc-ap-rustc_serialize",
]
[[package]]
name = "rustc-ap-rustc_lexer"
-version = "712.0.0"
+version = "718.0.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "8056b05346dff7e39164d0434c6ec443a14ab5fbf6221bd1a56e5abbeae5f60c"
+checksum = "786bbfe9d4d5264294c1819dbf1497a2480b583d5eda1ca9ae22e12d6661f5df"
dependencies = [
"unicode-xid",
]
[[package]]
name = "rustc-ap-rustc_lint_defs"
-version = "712.0.0"
+version = "718.0.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "364c3fb7b3cbdfe3fbb21d4078ff2cb3c58df63cda27995f8b064d21ee6dede5"
+checksum = "be2f045e2b999c154ec505d5fea69c994b742f3ebd2f552d11a6c81723921e47"
dependencies = [
"rustc-ap-rustc_ast",
"rustc-ap-rustc_data_structures",
[[package]]
name = "rustc-ap-rustc_macros"
-version = "712.0.0"
+version = "718.0.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "4607d6879cae3bae4d0369ca4b3a7510fd6295ac32eec088ac975208ba96ca45"
+checksum = "27789cd26d6b9e2fdfa68a262a20664d79ca67d31a3886d40fb88ebf6935869c"
dependencies = [
"proc-macro2",
"quote",
[[package]]
name = "rustc-ap-rustc_parse"
-version = "712.0.0"
+version = "718.0.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "78d22889bff7ca2346037c9df7ea55c66ffb714f5b50fb62b41975f8ac7a2d70"
+checksum = "1dc331f4958350679679e619d63a891e8d5d34ef99087068c89aa9e657d52caa"
dependencies = [
"bitflags",
"rustc-ap-rustc_ast",
[[package]]
name = "rustc-ap-rustc_serialize"
-version = "712.0.0"
+version = "718.0.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "d33c710120953c0214f47a6caf42064d7e241003b4af36c98a6d6156e70335f1"
+checksum = "e9a6824a462c4c1a379e911b0faf86d303a54bcf8673d4cc445195085966a4a4"
dependencies = [
"indexmap",
"smallvec",
[[package]]
name = "rustc-ap-rustc_session"
-version = "712.0.0"
+version = "718.0.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "6d35919041429a90713c8f704fa5209ba159cb554ce74d95722cbc18ac4b4c6f"
+checksum = "a782a5f6ada0dbe089c6416ad0104f0b8a8bdb4bd26ea95e5fefaec67aed5e8a"
dependencies = [
"bitflags",
"getopts",
[[package]]
name = "rustc-ap-rustc_span"
-version = "712.0.0"
+version = "718.0.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "73b12170c69603c0bf4b50e5c25fd348aae13b8c6465aa0ef4389c9eaa568e51"
+checksum = "a257546cb264b250c7abdb81239bb02f18a274a966211755a3ea89411b122214"
dependencies = [
"cfg-if 0.1.10",
"md-5",
[[package]]
name = "rustc-ap-rustc_target"
-version = "712.0.0"
+version = "718.0.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "0a8329d92e7dc24b974f759e6c6e97e2bbc47b18d0573343028f8135ca367200"
+checksum = "b5a72dd689421bcb5750f3ed0dedf367076e714ef0ba56c02ed391b9a8582862"
dependencies = [
"bitflags",
"rustc-ap-rustc_data_structures",
name = "rustc_data_structures"
version = "0.0.0"
dependencies = [
- "arrayvec 0.7.0",
+ "arrayvec",
"bitflags",
"cfg-if 0.1.10",
"crossbeam-utils 0.8.3",
name = "rustc_errors"
version = "0.0.0"
dependencies = [
- "annotate-snippets 0.8.0",
+ "annotate-snippets",
"atty",
"rustc_data_structures",
"rustc_lint_defs",
name = "rustc_index"
version = "0.0.0"
dependencies = [
- "arrayvec 0.7.0",
+ "arrayvec",
"rustc_macros",
"rustc_serialize",
]
name = "rustdoc"
version = "0.0.0"
dependencies = [
- "arrayvec 0.7.0",
+ "arrayvec",
"expect-test",
"itertools 0.9.0",
"minifier",
name = "rustfmt-nightly"
version = "1.4.37"
dependencies = [
- "annotate-snippets 0.6.1",
+ "annotate-snippets",
"anyhow",
"bytecount",
"cargo_metadata 0.8.2",
"lazy_static",
"log",
"regex",
- "rustc-ap-rustc_ast",
- "rustc-ap-rustc_ast_pretty",
- "rustc-ap-rustc_data_structures",
- "rustc-ap-rustc_errors",
- "rustc-ap-rustc_expand",
- "rustc-ap-rustc_parse",
- "rustc-ap-rustc_session",
- "rustc-ap-rustc_span",
"rustc-workspace-hack",
"rustfmt-config_proc_macro",
"serde",
dependencies = [
"linked-hash-map",
]
+
+[[package]]
+name = "yansi-term"
+version = "0.1.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "fe5c30ade05e61656247b2e334a031dfd0cc466fadef865bdcdea8d537951bf1"
+dependencies = [
+ "winapi 0.3.9",
+]
+Version 1.52.0 (2021-05-06)
+============================
+
+Language
+--------
+- [Added the `unsafe_op_in_unsafe_fn` lint, which checks whether the unsafe code
+ in an `unsafe fn` is wrapped in a `unsafe` block.][79208] This lint
+ is allowed by default, and may become a warning or hard error in a
+ future edition.
+- [You can now cast mutable references to arrays to a pointer of the same type as
+ the element.][81479]
+
+Compiler
+--------
+- [Upgraded the default LLVM to LLVM 12.][81451]
+
+Added tier 3\* support for the following targets.
+
+- [`s390x-unknown-linux-musl`][82166]
+- [`riscv32gc-unknown-linux-musl` & `riscv64gc-unknown-linux-musl`][82202]
+- [`powerpc-unknown-openbsd`][82733]
+
+\* Refer to Rust's [platform support page][platform-support-doc] for more
+information on Rust's tiered platform support.
+
+Libraries
+---------
+- [`OsString` now implements `Extend` and `FromIterator`.][82121]
+- [`cmp::Reverse` now has `#[repr(transparent)]` representation.][81879]
+- [`Arc<impl Error>` now implements `error::Error`.][80553]
+- [All integer division and remainder operations are now `const`.][80962]
+
+Stabilised APIs
+-------------
+- [`Arguments::as_str`]
+- [`char::MAX`]
+- [`char::REPLACEMENT_CHARACTER`]
+- [`char::UNICODE_VERSION`]
+- [`char::decode_utf16`]
+- [`char::from_digit`]
+- [`char::from_u32_unchecked`]
+- [`char::from_u32`]
+- [`slice::partition_point`]
+- [`str::rsplit_once`]
+- [`str::split_once`]
+
+The following previously stable APIs are now `const`.
+
+- [`char::len_utf8`]
+- [`char::len_utf16`]
+- [`char::to_ascii_uppercase`]
+- [`char::to_ascii_lowercase`]
+- [`char::eq_ignore_ascii_case`]
+- [`u8::to_ascii_uppercase`]
+- [`u8::to_ascii_lowercase`]
+- [`u8::eq_ignore_ascii_case`]
+
+Rustdoc
+-------
+- [Rustdoc lints are now treated as a tool lint, meaning that
+ lints are now prefixed with `rustdoc::` (e.g. `#[warn(rustdoc::non_autolinks)]`).][80527]
+ Using the old style is still allowed, and will become a warning in
+ a future release.
+- [Rustdoc now supports argument files.][82261]
+- [Rustdoc now generates smart punctuation for documentation.][79423]
+- [You can now use "task lists" in Rustdoc Markdown.][81766] E.g.
+ ```markdown
+ - [x] Complete
+ - [ ] Todo
+ ```
+
+Misc
+----
+- [You can now pass multiple filters to tests.][81356] E.g.
+ `cargo test -- foo bar` will run all tests that match `foo` and `bar`.
+- [Rustup now distributes PDB symbols for the `std` library on Windows,
+ allowing you to see `std` symbols when debugging.][82218]
+
+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.
+
+- [Check the result cache before the DepGraph when ensuring queries][81855]
+- [Try fast_reject::simplify_type in coherence before doing full check][81744]
+- [Only store a LocalDefId in some HIR nodes][81611]
+- [Store HIR attributes in a side table][79519]
+
+Compatibility Notes
+-------------------
+- [Cargo build scripts are now forbidden from setting `RUSTC_BOOTSTRAP`.][cargo/9181]
+- [Removed support for the `x86_64-rumprun-netbsd` target.][82594]
+- [Deprecated the `x86_64-sun-solaris` target in favor of `x86_64-pc-solaris`.][82216]
+- [Rustdoc now only accepts `,`, ` `, and `\t` as delimiters for specifying
+ languages in code blocks.][78429]
+- [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]
+
+[84136]: https://github.com/rust-lang/rust/issues/84136
+[80763]: https://github.com/rust-lang/rust/pull/80763
+[82166]: https://github.com/rust-lang/rust/pull/82166
+[82121]: https://github.com/rust-lang/rust/pull/82121
+[81879]: https://github.com/rust-lang/rust/pull/81879
+[82261]: https://github.com/rust-lang/rust/pull/82261
+[82218]: https://github.com/rust-lang/rust/pull/82218
+[82216]: https://github.com/rust-lang/rust/pull/82216
+[82202]: https://github.com/rust-lang/rust/pull/82202
+[81855]: https://github.com/rust-lang/rust/pull/81855
+[81766]: https://github.com/rust-lang/rust/pull/81766
+[81744]: https://github.com/rust-lang/rust/pull/81744
+[81611]: https://github.com/rust-lang/rust/pull/81611
+[81479]: https://github.com/rust-lang/rust/pull/81479
+[81451]: https://github.com/rust-lang/rust/pull/81451
+[81356]: https://github.com/rust-lang/rust/pull/81356
+[80962]: https://github.com/rust-lang/rust/pull/80962
+[80553]: https://github.com/rust-lang/rust/pull/80553
+[80527]: https://github.com/rust-lang/rust/pull/80527
+[79519]: https://github.com/rust-lang/rust/pull/79519
+[79423]: https://github.com/rust-lang/rust/pull/79423
+[79208]: https://github.com/rust-lang/rust/pull/79208
+[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
+[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
+[`char::UNICODE_VERSION`]: https://doc.rust-lang.org/std/primitive.char.html#associatedconstant.UNICODE_VERSION
+[`char::decode_utf16`]: https://doc.rust-lang.org/std/primitive.char.html#method.decode_utf16
+[`char::from_u32`]: https://doc.rust-lang.org/std/primitive.char.html#method.from_u32
+[`char::from_u32_unchecked`]: https://doc.rust-lang.org/std/primitive.char.html#method.from_u32_unchecked
+[`char::from_digit`]: https://doc.rust-lang.org/std/primitive.char.html#method.from_digit
+[`Peekable::next_if`]: https://doc.rust-lang.org/stable/std/iter/struct.Peekable.html#method.next_if
+[`Peekable::next_if_eq`]: https://doc.rust-lang.org/stable/std/iter/struct.Peekable.html#method.next_if_eq
+[`Arguments::as_str`]: https://doc.rust-lang.org/stable/std/fmt/struct.Arguments.html#method.as_str
+[`str::split_once`]: https://doc.rust-lang.org/stable/std/primitive.str.html#method.split_once
+[`str::rsplit_once`]: https://doc.rust-lang.org/stable/std/primitive.str.html#method.rsplit_once
+[`slice::partition_point`]: https://doc.rust-lang.org/stable/std/primitive.slice.html#method.partition_point
+[`char::len_utf8`]: https://doc.rust-lang.org/stable/std/primitive.char.html#method.len_utf8
+[`char::len_utf16`]: https://doc.rust-lang.org/stable/std/primitive.char.html#method.len_utf16
+[`char::to_ascii_uppercase`]: https://doc.rust-lang.org/stable/std/primitive.char.html#method.to_ascii_uppercase
+[`char::to_ascii_lowercase`]: https://doc.rust-lang.org/stable/std/primitive.char.html#method.to_ascii_lowercase
+[`char::eq_ignore_ascii_case`]: https://doc.rust-lang.org/stable/std/primitive.char.html#method.eq_ignore_ascii_case
+[`u8::to_ascii_uppercase`]: https://doc.rust-lang.org/stable/std/primitive.u8.html#method.to_ascii_uppercase
+[`u8::to_ascii_lowercase`]: https://doc.rust-lang.org/stable/std/primitive.u8.html#method.to_ascii_lowercase
+[`u8::eq_ignore_ascii_case`]: https://doc.rust-lang.org/stable/std/primitive.u8.html#method.eq_ignore_ascii_case
+
Version 1.51.0 (2021-03-25)
============================
let mut generic_args = vec![];
for (idx, arg) in args.into_iter().enumerate() {
if legacy_args_idx.contains(&idx) {
- let parent_def_id = self.current_hir_id_owner.last().unwrap().0;
+ let parent_def_id = self.current_hir_id_owner.0;
let node_id = self.resolver.next_node_id();
// Add a definition for the in-band const def.
use rustc_data_structures::captures::Captures;
use rustc_data_structures::fx::FxHashSet;
use rustc_data_structures::sync::Lrc;
-use rustc_errors::struct_span_err;
+use rustc_errors::{struct_span_err, Applicability};
use rustc_hir as hir;
use rustc_hir::def::{DefKind, Namespace, PartialRes, PerNS, Res};
use rustc_hir::def_id::{DefId, DefIdMap, LocalDefId, CRATE_DEF_ID};
use rustc_session::lint::{BuiltinLintDiagnostics, LintBuffer};
use rustc_session::utils::{FlattenNonterminals, NtToTokenstream};
use rustc_session::Session;
+use rustc_span::edition::Edition;
use rustc_span::hygiene::ExpnId;
use rustc_span::source_map::{respan, DesugaringKind};
use rustc_span::symbol::{kw, sym, Ident, Symbol};
type_def_lifetime_params: DefIdMap<usize>,
- current_hir_id_owner: Vec<(LocalDefId, u32)>,
+ current_hir_id_owner: (LocalDefId, u32),
item_local_id_counters: NodeMap<u32>,
node_id_to_hir_id: IndexVec<NodeId, Option<hir::HirId>>,
anonymous_lifetime_mode: AnonymousLifetimeMode::PassThrough,
type_def_lifetime_params: Default::default(),
current_module: CRATE_DEF_ID,
- current_hir_id_owner: vec![(CRATE_DEF_ID, 0)],
+ current_hir_id_owner: (CRATE_DEF_ID, 0),
item_local_id_counters: Default::default(),
node_id_to_hir_id: IndexVec::new(),
generator_kind: None,
.insert(owner, HIR_ID_COUNTER_LOCKED)
.unwrap_or_else(|| panic!("no `item_local_id_counters` entry for {:?}", owner));
let def_id = self.resolver.local_def_id(owner);
- self.current_hir_id_owner.push((def_id, counter));
+ let old_owner = std::mem::replace(&mut self.current_hir_id_owner, (def_id, counter));
let ret = f(self);
- let (new_def_id, new_counter) = self.current_hir_id_owner.pop().unwrap();
+ let (new_def_id, new_counter) =
+ std::mem::replace(&mut self.current_hir_id_owner, old_owner);
debug_assert!(def_id == new_def_id);
debug_assert!(new_counter >= counter);
/// properly. Calling the method twice with the same `NodeId` is fine though.
fn lower_node_id(&mut self, ast_node_id: NodeId) -> hir::HirId {
self.lower_node_id_generic(ast_node_id, |this| {
- let &mut (owner, ref mut local_id_counter) =
- this.current_hir_id_owner.last_mut().unwrap();
+ let &mut (owner, ref mut local_id_counter) = &mut this.current_hir_id_owner;
let local_id = *local_id_counter;
*local_id_counter += 1;
hir::HirId { owner, local_id: hir::ItemLocalId::from_u32(local_id) }
// wouldn't have been added yet.
let generics = this.lower_generics_mut(
generics,
- ImplTraitContext::Universal(
- &mut params,
- this.current_hir_id_owner.last().unwrap().0,
- ),
+ ImplTraitContext::Universal(&mut params, this.current_hir_id_owner.0),
);
let res = f(this, &mut params);
(params, (generics, res))
}
AssocTyConstraintKind::Bound { ref bounds } => {
let mut capturable_lifetimes;
- let mut parent_def_id = self.current_hir_id_owner.last().unwrap().0;
+ let mut parent_def_id = self.current_hir_id_owner.0;
// Piggy-back on the `impl Trait` context to figure out the correct behavior.
let (desugar_to_impl_trait, itctx) = match itctx {
// We are in the return position:
// Construct a AnonConst where the expr is the "ty"'s path.
- let parent_def_id = self.current_hir_id_owner.last().unwrap().0;
+ let parent_def_id = self.current_hir_id_owner.0;
let node_id = self.resolver.next_node_id();
// Add a definition for the in-band const def.
if let Some((_, ibty)) = &mut in_band_ty_params {
this.lower_ty_direct(
¶m.ty,
- ImplTraitContext::Universal(
- ibty,
- this.current_hir_id_owner.last().unwrap().0,
- ),
+ ImplTraitContext::Universal(ibty, this.current_hir_id_owner.0),
)
} else {
this.lower_ty_direct(¶m.ty, ImplTraitContext::disallowed())
.map(|snippet| snippet.starts_with("#["))
.unwrap_or(true);
if !is_macro_callsite {
- self.resolver.lint_buffer().buffer_lint_with_diagnostic(
- BARE_TRAIT_OBJECTS,
- id,
- span,
- "trait objects without an explicit `dyn` are deprecated",
- BuiltinLintDiagnostics::BareTraitObject(span, is_global),
- )
+ if span.edition() < Edition::Edition2021 {
+ self.resolver.lint_buffer().buffer_lint_with_diagnostic(
+ BARE_TRAIT_OBJECTS,
+ id,
+ span,
+ "trait objects without an explicit `dyn` are deprecated",
+ BuiltinLintDiagnostics::BareTraitObject(span, is_global),
+ )
+ } else {
+ let msg = "trait objects must include the `dyn` keyword";
+ let label = "add `dyn` keyword before this trait";
+ let mut err = struct_span_err!(self.sess, span, E0782, "{}", msg,);
+ err.span_suggestion_verbose(
+ span.shrink_to_lo(),
+ label,
+ String::from("dyn "),
+ Applicability::MachineApplicable,
+ );
+ err.emit();
+ }
}
}
self.print_either_attributes(attrs, ast::AttrStyle::Inner, false, true)
}
- fn print_inner_attributes_no_trailing_hardbreak(&mut self, attrs: &[ast::Attribute]) {
- self.print_either_attributes(attrs, ast::AttrStyle::Inner, false, false)
- }
-
fn print_outer_attributes(&mut self, attrs: &[ast::Attribute]) {
self.print_either_attributes(attrs, ast::AttrStyle::Outer, false, true)
}
}
}
- fn print_expr_vec(&mut self, exprs: &[P<ast::Expr>], attrs: &[ast::Attribute]) {
+ fn print_expr_vec(&mut self, exprs: &[P<ast::Expr>]) {
self.ibox(INDENT_UNIT);
self.s.word("[");
- self.print_inner_attributes_inline(attrs);
self.commasep_exprs(Inconsistent, exprs);
self.s.word("]");
self.end();
}
- fn print_expr_anon_const(&mut self, expr: &ast::AnonConst, attrs: &[ast::Attribute]) {
+ fn print_expr_anon_const(&mut self, expr: &ast::AnonConst) {
self.ibox(INDENT_UNIT);
self.s.word("const");
- self.print_inner_attributes_inline(attrs);
self.print_expr(&expr.value);
self.end();
}
- fn print_expr_repeat(
- &mut self,
- element: &ast::Expr,
- count: &ast::AnonConst,
- attrs: &[ast::Attribute],
- ) {
+ fn print_expr_repeat(&mut self, element: &ast::Expr, count: &ast::AnonConst) {
self.ibox(INDENT_UNIT);
self.s.word("[");
- self.print_inner_attributes_inline(attrs);
self.print_expr(element);
self.word_space(";");
self.print_expr(&count.value);
path: &ast::Path,
fields: &[ast::ExprField],
rest: &ast::StructRest,
- attrs: &[ast::Attribute],
) {
self.print_path(path, true, 0);
self.s.word("{");
- self.print_inner_attributes_inline(attrs);
self.commasep_cmnt(
Consistent,
fields,
self.s.word("}");
}
- fn print_expr_tup(&mut self, exprs: &[P<ast::Expr>], attrs: &[ast::Attribute]) {
+ fn print_expr_tup(&mut self, exprs: &[P<ast::Expr>]) {
self.popen();
- self.print_inner_attributes_inline(attrs);
self.commasep_exprs(Inconsistent, exprs);
if exprs.len() == 1 {
self.s.word(",");
self.print_expr_maybe_paren(expr, parser::PREC_PREFIX);
}
ast::ExprKind::Array(ref exprs) => {
- self.print_expr_vec(&exprs[..], attrs);
+ self.print_expr_vec(exprs);
}
ast::ExprKind::ConstBlock(ref anon_const) => {
- self.print_expr_anon_const(anon_const, attrs);
+ self.print_expr_anon_const(anon_const);
}
ast::ExprKind::Repeat(ref element, ref count) => {
- self.print_expr_repeat(element, count, attrs);
+ self.print_expr_repeat(element, count);
}
ast::ExprKind::Struct(ref se) => {
- self.print_expr_struct(&se.path, &se.fields, &se.rest, attrs);
+ self.print_expr_struct(&se.path, &se.fields, &se.rest);
}
ast::ExprKind::Tup(ref exprs) => {
- self.print_expr_tup(&exprs[..], attrs);
+ self.print_expr_tup(exprs);
}
ast::ExprKind::Call(ref func, ref args) => {
self.print_expr_call(func, &args[..]);
self.print_expr_as_cond(expr);
self.s.space();
self.bopen();
- self.print_inner_attributes_no_trailing_hardbreak(attrs);
for arm in arms {
self.print_arm(arm);
}
ast::ExprKind::MacCall(ref m) => self.print_mac(m),
ast::ExprKind::Paren(ref e) => {
self.popen();
- self.print_inner_attributes_inline(attrs);
self.print_expr(e);
self.pclose();
}
with:
name: cg_clif-${{ runner.os }}
path: cg_clif.tar.xz
+
+ - name: Upload prebuilt cg_clif (cross compile)
+ if: matrix.env.TARGET_TRIPLE == 'x86_64-pc-windows-gnu'
+ uses: actions/upload-artifact@v2
+ with:
+ name: cg_clif-${{ runner.os }}-cross-x86_64-mingw
+ path: cg_clif.tar.xz
{
// source for rustc_* is not included in the rust-src component; disable the errors about this
- "rust-analyzer.diagnostics.disabled": ["unresolved-extern-crate", "macro-error"],
+ "rust-analyzer.diagnostics.disabled": ["unresolved-extern-crate", "unresolved-macro-call"],
"rust-analyzer.assist.importMergeBehavior": "last",
"rust-analyzer.cargo.runBuildScripts": true,
"rust-analyzer.linkedProjects": [
[[package]]
name = "cranelift-bforest"
-version = "0.72.0"
-source = "git+https://github.com/bytecodealliance/wasmtime/?branch=main#8e43e96410a14143d368273cf1e708f8094bb8e0"
+version = "0.73.0"
+source = "git+https://github.com/bytecodealliance/wasmtime/?branch=main#45bee40f338c631bff4a799288101ba328c7ad36"
dependencies = [
"cranelift-entity",
]
[[package]]
name = "cranelift-codegen"
-version = "0.72.0"
-source = "git+https://github.com/bytecodealliance/wasmtime/?branch=main#8e43e96410a14143d368273cf1e708f8094bb8e0"
+version = "0.73.0"
+source = "git+https://github.com/bytecodealliance/wasmtime/?branch=main#45bee40f338c631bff4a799288101ba328c7ad36"
dependencies = [
"byteorder",
"cranelift-bforest",
[[package]]
name = "cranelift-codegen-meta"
-version = "0.72.0"
-source = "git+https://github.com/bytecodealliance/wasmtime/?branch=main#8e43e96410a14143d368273cf1e708f8094bb8e0"
+version = "0.73.0"
+source = "git+https://github.com/bytecodealliance/wasmtime/?branch=main#45bee40f338c631bff4a799288101ba328c7ad36"
dependencies = [
"cranelift-codegen-shared",
"cranelift-entity",
[[package]]
name = "cranelift-codegen-shared"
-version = "0.72.0"
-source = "git+https://github.com/bytecodealliance/wasmtime/?branch=main#8e43e96410a14143d368273cf1e708f8094bb8e0"
+version = "0.73.0"
+source = "git+https://github.com/bytecodealliance/wasmtime/?branch=main#45bee40f338c631bff4a799288101ba328c7ad36"
[[package]]
name = "cranelift-entity"
-version = "0.72.0"
-source = "git+https://github.com/bytecodealliance/wasmtime/?branch=main#8e43e96410a14143d368273cf1e708f8094bb8e0"
+version = "0.73.0"
+source = "git+https://github.com/bytecodealliance/wasmtime/?branch=main#45bee40f338c631bff4a799288101ba328c7ad36"
[[package]]
name = "cranelift-frontend"
-version = "0.72.0"
-source = "git+https://github.com/bytecodealliance/wasmtime/?branch=main#8e43e96410a14143d368273cf1e708f8094bb8e0"
+version = "0.73.0"
+source = "git+https://github.com/bytecodealliance/wasmtime/?branch=main#45bee40f338c631bff4a799288101ba328c7ad36"
dependencies = [
"cranelift-codegen",
"log",
[[package]]
name = "cranelift-jit"
-version = "0.72.0"
-source = "git+https://github.com/bytecodealliance/wasmtime/?branch=main#8e43e96410a14143d368273cf1e708f8094bb8e0"
+version = "0.73.0"
+source = "git+https://github.com/bytecodealliance/wasmtime/?branch=main#45bee40f338c631bff4a799288101ba328c7ad36"
dependencies = [
"anyhow",
"cranelift-codegen",
[[package]]
name = "cranelift-module"
-version = "0.72.0"
-source = "git+https://github.com/bytecodealliance/wasmtime/?branch=main#8e43e96410a14143d368273cf1e708f8094bb8e0"
+version = "0.73.0"
+source = "git+https://github.com/bytecodealliance/wasmtime/?branch=main#45bee40f338c631bff4a799288101ba328c7ad36"
dependencies = [
"anyhow",
"cranelift-codegen",
[[package]]
name = "cranelift-native"
-version = "0.72.0"
-source = "git+https://github.com/bytecodealliance/wasmtime/?branch=main#8e43e96410a14143d368273cf1e708f8094bb8e0"
+version = "0.73.0"
+source = "git+https://github.com/bytecodealliance/wasmtime/?branch=main#45bee40f338c631bff4a799288101ba328c7ad36"
dependencies = [
"cranelift-codegen",
"target-lexicon",
[[package]]
name = "cranelift-object"
-version = "0.72.0"
-source = "git+https://github.com/bytecodealliance/wasmtime/?branch=main#8e43e96410a14143d368273cf1e708f8094bb8e0"
+version = "0.73.0"
+source = "git+https://github.com/bytecodealliance/wasmtime/?branch=main#45bee40f338c631bff4a799288101ba328c7ad36"
dependencies = [
"anyhow",
"cranelift-codegen",
"cranelift-frontend",
"cranelift-jit",
"cranelift-module",
+ "cranelift-native",
"cranelift-object",
"gimli",
"indexmap",
[[package]]
name = "target-lexicon"
-version = "0.11.2"
+version = "0.12.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "422045212ea98508ae3d28025bc5aaa2bd4a9cdaecd442a08da2ee620ee9ea95"
+checksum = "64ae3b39281e4b14b8123bdbaddd472b7dfe215e444181f2f9d2443c2444f834"
[[package]]
name = "thiserror"
[dependencies]
# These have to be in sync with each other
-cranelift-codegen = { git = "https://github.com/bytecodealliance/wasmtime/", branch = "main", features = ["unwind", "x64"] }
+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" }
-target-lexicon = "0.11.0"
+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"] }
#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-jit = { path = "../wasmtime/cranelift/jit" }
#cranelift-object = { path = "../wasmtime/cranelift/object" }
For additional ways to use rustc_codegen_cranelift like the JIT mode see [usage.md](docs/usage.md).
-## Env vars
+## Configuration
-See [env_vars.md](docs/env_vars.md) for all env vars used by rustc_codegen_cranelift.
+See the documentation on the `BackendConfig` struct in [config.rs](src/config.rs) for all
+configuration options.
## Not yet supported
[[package]]
name = "compiler_builtins"
-version = "0.1.39"
+version = "0.1.40"
dependencies = [
"rustc-std-workspace-core",
]
[[package]]
name = "libc"
-version = "0.2.91"
+version = "0.2.94"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "8916b1f6ca17130ec6568feccee27c156ad12037880833a3b842a823236502e7"
+checksum = "18794a8ad5b29321f790b55d93dfba91e125cb1a9edbd4f8e3150acc771c1a5e"
dependencies = [
"rustc-std-workspace-core",
]
name = "panic_abort"
version = "0.0.0"
dependencies = [
+ "alloc",
"cfg-if",
"compiler_builtins",
"core",
"panic_abort",
"panic_unwind",
"rustc-demangle",
+ "std_detect",
"unwind",
"wasi",
]
+[[package]]
+name = "std_detect"
+version = "0.1.5"
+dependencies = [
+ "cfg-if",
+ "compiler_builtins",
+ "libc",
+ "rustc-std-workspace-alloc",
+ "rustc-std-workspace-core",
+]
+
[[package]]
name = "sysroot"
version = "0.0.0"
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.39
+git checkout 0.1.40
git apply ../../crate_patches/000*-compiler-builtins-*.patch
popd
fn wrapping_shr(self, other: u32) -> Self;
- fn rotate_left(self, other: u32) -> Self;
fn overflowing_add(self, other: Self) -> (Self, bool);
- fn aborting_div(self, other: Self) -> Self;
- fn aborting_rem(self, other: Self) -> Self;
+ fn leading_zeros(self) -> u32;
+ }
@@ -209,10 +208,6 @@ macro_rules! int_impl_common {
<Self>::wrapping_shr(self, other)
}
+++ /dev/null
-# List of env vars recognized by cg_clif
-
-<dl>
- <dt>CG_CLIF_JIT_ARGS</dt>
- <dd>When JIT mode is enable pass these arguments to the program.</dd>
- <dt>CG_CLIF_INCR_CACHE_DISABLED</dt>
- <dd>Don't cache object files in the incremental cache. Useful during development of cg_clif
- to make it possible to use incremental mode for all analyses performed by rustc without caching
- object files when their content should have been changed by a change to cg_clif.</dd>
- <dt>CG_CLIF_DISPLAY_CG_TIME</dt>
- <dd>If "1", display the time it took to perform codegen for a crate.</dd>
- <dt>CG_CLIF_ENABLE_VERIFIER</dt>
- <dd>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.</dt>
-</dl>
puts(s);
}
+macro_rules! assert {
+ ($e:expr) => {
+ if !$e {
+ panic(stringify!(! $e));
+ }
+ };
+}
+
+macro_rules! assert_eq {
+ ($l:expr, $r: expr) => {
+ if $l != $r {
+ panic(stringify!($l != $r));
+ }
+ }
+}
+
#[lang = "termination"]
trait Termination {
fn report(self) -> i32;
fn report(self) -> i32 {
unsafe {
NUM = 6 * 7 + 1 + (1u8 == 1u8) as u8; // 44
- *NUM_REF as i32
+ assert_eq!(*NUM_REF as i32, 44);
}
+ 0
}
}
unsafe { puts(*((argv as usize + 2 * intrinsics::size_of::<*const u8>()) as *const *const i8)); }
}
- main().report();
- 0
+ main().report() as isize
}
static mut NUM: u8 = 6 * 7;
static NUM_REF: &'static u8 = unsafe { &NUM };
-macro_rules! assert {
- ($e:expr) => {
- if !$e {
- panic(stringify!(! $e));
- }
- };
-}
-
-macro_rules! assert_eq {
- ($l:expr, $r: expr) => {
- if $l != $r {
- panic(stringify!($l != $r));
- }
- }
-}
-
struct Unique<T: ?Sized> {
pointer: *const T,
_marker: PhantomData<T>,
unsafe {
global_asm_test();
}
+
+ // Both statics have a reference that points to the same anonymous allocation.
+ static REF1: &u8 = &42;
+ static REF2: &u8 = REF1;
+ assert_eq!(*REF1, *REF2);
}
#[cfg(all(not(jit), target_os = "linux"))]
assert_eq!(2.3f32.copysign(-1.0), -2.3f32);
println!("{}", 2.3f32.powf(2.0));
+ assert_eq!(i64::MAX.checked_mul(2), None);
+
assert_eq!(-128i8, (-128i8).saturating_sub(1));
assert_eq!(127i8, 127i8.saturating_sub(-128));
assert_eq!(-128i8, (-128i8).saturating_add(-128));
assert_eq!(houndred_i128 as f64, 100.0);
assert_eq!(houndred_f32 as i128, 100);
assert_eq!(houndred_f64 as i128, 100);
+ assert_eq!(1u128.rotate_left(2), 4);
// Test signed 128bit comparing
let max = usize::MAX as i128;
[toolchain]
-channel = "nightly-2021-03-29"
+channel = "nightly-2021-04-28"
components = ["rust-src", "rustc-dev", "llvm-tools-preview"]
set -e
export CG_CLIF_DISPLAY_CG_TIME=1
-export CG_CLIF_INCR_CACHE_DISABLED=1
+export CG_CLIF_DISABLE_INCR_CACHE=1
export HOST_TRIPLE=$(rustc -vV | grep host | cut -d: -f2 | tr -d " ")
export TARGET_TRIPLE=${TARGET_TRIPLE:-$HOST_TRIPLE}
[dependencies]
core = { path = "../core" }
-compiler_builtins = { version = "0.1.39", features = ['rustc-dep-of-std'] }
-+compiler_builtins = { version = "0.1.39", features = ['rustc-dep-of-std', 'no-asm'] }
++compiler_builtins = { version = "0.1.40", features = ['rustc-dep-of-std', 'no-asm'] }
[dev-dependencies]
rand = "0.7"
rm src/test/ui/numbers-arithmetic/int-abs-overflow.rs
rm src/test/ui/drop/drop-trait-enum.rs
rm src/test/ui/numbers-arithmetic/issue-8460.rs
+rm src/test/incremental/change_crate_dep_kind.rs # requires -Cpanic=unwind
rm src/test/ui/issues/issue-28950.rs # depends on stack size optimizations
rm src/test/ui/init-large-type.rs # same
rm src/test/ui/numbers-arithmetic/saturating-float-casts.rs # intrinsic gives different but valid result
rm src/test/ui/mir/mir_misc_casts.rs # depends on deduplication of constants
rm src/test/ui/mir/mir_raw_fat_ptr.rs # same
+rm src/test/ui/consts/issue-33537.rs # same
rm src/test/ui/async-await/async-fn-size-moved-locals.rs # -Cpanic=abort shrinks some generator by one byte
rm src/test/ui/async-await/async-fn-size-uninit-locals.rs # same
rm src/test/ui/generator/size-moved-locals.rs # same
rm src/test/incremental/hashes/inline_asm.rs # inline asm
rm src/test/incremental/issue-72386.rs # same
-rm src/test/incremental/change_crate_dep_kind.rs # requires -Cpanic=unwind
rm src/test/incremental/issue-49482.rs # same
rm src/test/incremental/issue-54059.rs # same
rm src/test/incremental/lto.rs # requires lto
+rm -r src/test/run-make/emit-shared-files # requires the rustdoc executable in build/bin/
+rm -r src/test/run-make/unstable-flag-required # same
+
rm src/test/pretty/asm.rs # inline asm
rm src/test/pretty/raw-str-nonexpr.rs # same
rm src/test/ui/json-bom-plus-crlf-multifile.rs # differing warning
rm src/test/ui/json-bom-plus-crlf.rs # same
+rm src/test/ui/match/issue-82392.rs # differing error
rm src/test/ui/type-alias-impl-trait/cross_crate_ice*.rs # requires removed aux dep
rm src/test/ui/allocator/no_std-alloc-error-handler-default.rs # missing rust_oom definition
module: &mut dyn Module,
inst: Instance<'tcx>,
) -> FuncId {
- let name = tcx.symbol_name(inst).name.to_string();
+ let name = tcx.symbol_name(inst).name;
let sig = get_function_sig(tcx, module.isa().triple(), inst);
- module.declare_function(&name, Linkage::Import, &sig).unwrap()
+ module.declare_function(name, Linkage::Import, &sig).unwrap()
}
impl<'tcx> FunctionCx<'_, '_, 'tcx> {
/// Instance must be monomorphized
pub(crate) fn get_function_ref(&mut self, inst: Instance<'tcx>) -> FuncRef {
- let func_id = import_function(self.tcx, self.cx.module, inst);
- let func_ref = self.cx.module.declare_func_in_func(func_id, &mut self.bcx.func);
+ let func_id = import_function(self.tcx, self.module, inst);
+ let func_ref = self.module.declare_func_in_func(func_id, &mut self.bcx.func);
if self.clif_comments.enabled() {
self.add_comment(func_ref, format!("{:?}", inst));
args: &[Value],
) -> &[Value] {
let sig = Signature { params, returns, call_conv: CallConv::triple_default(self.triple()) };
- let func_id = self.cx.module.declare_function(&name, Linkage::Import, &sig).unwrap();
- let func_ref = self.cx.module.declare_func_in_func(func_id, &mut self.bcx.func);
+ let func_id = self.module.declare_function(name, Linkage::Import, &sig).unwrap();
+ let func_ref = self.module.declare_func_in_func(func_id, &mut self.bcx.func);
let call_inst = self.bcx.ins().call(func_ref, args);
if self.clif_comments.enabled() {
self.add_comment(call_inst, format!("easy_call {}", name));
pub(crate) fn codegen_terminator_call<'tcx>(
fx: &mut FunctionCx<'_, '_, 'tcx>,
span: Span,
- current_block: Block,
func: &Operand<'tcx>,
args: &[Operand<'tcx>],
destination: Option<(Place<'tcx>, BasicBlock)>,
.map(|inst| fx.tcx.codegen_fn_attrs(inst.def_id()).flags.contains(CodegenFnAttrFlags::COLD))
.unwrap_or(false);
if is_cold {
- fx.cold_blocks.insert(current_block);
+ // FIXME Mark current_block block as cold once Cranelift supports it
}
// Unpack arguments tuple for closures
pub(crate) fn codegen(
tcx: TyCtxt<'_>,
module: &mut impl Module,
- unwind_context: &mut UnwindContext<'_>,
+ unwind_context: &mut UnwindContext,
) -> bool {
let any_dynamic_crate = tcx.dependency_formats(LOCAL_CRATE).iter().any(|(_, list)| {
use rustc_middle::middle::dependency_format::Linkage;
fn codegen_inner(
module: &mut impl Module,
- unwind_context: &mut UnwindContext<'_>,
+ unwind_context: &mut UnwindContext,
kind: AllocatorKind,
) {
let usize_ty = module.target_config().pointer_type();
use rustc_data_structures::fx::FxHashMap;
use rustc_session::Session;
+use cranelift_codegen::isa::TargetIsa;
use cranelift_module::FuncId;
+use cranelift_object::{ObjectBuilder, ObjectModule, ObjectProduct};
use object::write::*;
use object::{RelocationEncoding, SectionKind, SymbolFlags};
-use cranelift_object::{ObjectBuilder, ObjectModule, ObjectProduct};
-
use gimli::SectionId;
use crate::debuginfo::{DebugReloc, DebugRelocName};
pub(crate) trait WriteMetadata {
- fn add_rustc_section(&mut self, symbol_name: String, data: Vec<u8>, is_like_osx: bool);
+ fn add_rustc_section(&mut self, symbol_name: String, data: Vec<u8>);
}
impl WriteMetadata for object::write::Object {
- fn add_rustc_section(&mut self, symbol_name: String, data: Vec<u8>, _is_like_osx: bool) {
+ fn add_rustc_section(&mut self, symbol_name: String, data: Vec<u8>) {
let segment = self.segment_name(object::write::StandardSegment::Data).to_vec();
let section_id = self.add_section(segment, b".rustc".to_vec(), object::SectionKind::Data);
let offset = self.append_section_data(section_id, &data, 1);
}
pub(crate) fn with_object(sess: &Session, name: &str, f: impl FnOnce(&mut Object)) -> Vec<u8> {
- let triple = crate::build_isa(sess).triple().clone();
+ let triple = crate::target_triple(sess);
let binary_format = match triple.binary_format {
target_lexicon::BinaryFormat::Elf => object::BinaryFormat::Elf,
metadata_object.write().unwrap()
}
-pub(crate) fn make_module(sess: &Session, name: String) -> ObjectModule {
- let mut builder = ObjectBuilder::new(
- crate::build_isa(sess),
- name + ".o",
- cranelift_module::default_libcall_names(),
- )
- .unwrap();
+pub(crate) fn make_module(sess: &Session, isa: Box<dyn TargetIsa>, name: String) -> ObjectModule {
+ let mut builder =
+ ObjectBuilder::new(isa, name + ".o", cranelift_module::default_libcall_names()).unwrap();
// Unlike cg_llvm, cg_clif defaults to disabling -Zfunction-sections. For cg_llvm binary size
// is important, while cg_clif cares more about compilation times. Enabling -Zfunction-sections
// can easily double the amount of time necessary to perform linking.
use rustc_middle::ty::layout::FnAbiExt;
use rustc_target::abi::call::FnAbi;
+use crate::constant::ConstantCx;
use crate::prelude::*;
-pub(crate) fn codegen_fn<'tcx>(cx: &mut crate::CodegenCx<'_, 'tcx>, instance: Instance<'tcx>) {
+pub(crate) fn codegen_fn<'tcx>(
+ cx: &mut crate::CodegenCx<'tcx>,
+ module: &mut dyn Module,
+ instance: Instance<'tcx>,
+) {
let tcx = cx.tcx;
let _inst_guard =
let mir = tcx.instance_mir(instance.def);
// Declare function
- let name = tcx.symbol_name(instance).name.to_string();
- let sig = get_function_sig(tcx, cx.module.isa().triple(), instance);
- let func_id = cx.module.declare_function(&name, Linkage::Local, &sig).unwrap();
+ let symbol_name = tcx.symbol_name(instance);
+ let sig = get_function_sig(tcx, module.isa().triple(), instance);
+ let func_id = module.declare_function(symbol_name.name, Linkage::Local, &sig).unwrap();
cx.cached_context.clear();
(0..mir.basic_blocks().len()).map(|_| bcx.create_block()).collect();
// Make FunctionCx
- let pointer_type = cx.module.target_config().pointer_type();
+ let pointer_type = module.target_config().pointer_type();
let clif_comments = crate::pretty_clif::CommentWriter::new(tcx, instance);
let mut fx = FunctionCx {
cx,
+ module,
tcx,
pointer_type,
+ vtables: FxHashMap::default(),
+ constants_cx: ConstantCx::new(),
instance,
+ symbol_name,
mir,
fn_abi: Some(FnAbi::of_instance(&RevealAllLayoutCx(tcx), instance, &[])),
block_map,
local_map: IndexVec::with_capacity(mir.local_decls.len()),
caller_location: None, // set by `codegen_fn_prelude`
- cold_blocks: EntitySet::new(),
clif_comments,
source_info_set: indexmap::IndexSet::new(),
let mut clif_comments = fx.clif_comments;
let source_info_set = fx.source_info_set;
let local_map = fx.local_map;
- let cold_blocks = fx.cold_blocks;
+
+ fx.constants_cx.finalize(fx.tcx, &mut *fx.module);
// Store function in context
let context = &mut cx.cached_context;
// Perform rust specific optimizations
tcx.sess.time("optimize clif ir", || {
- crate::optimize::optimize_function(
- tcx,
- instance,
- context,
- &cold_blocks,
- &mut clif_comments,
- );
+ 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();
context.compute_domtree();
- context.eliminate_unreachable_code(cx.module.isa()).unwrap();
- context.dce(cx.module.isa()).unwrap();
+ context.eliminate_unreachable_code(module.isa()).unwrap();
+ context.dce(module.isa()).unwrap();
// Some Cranelift optimizations expect the domtree to not yet be computed and as such don't
// invalidate it when it would change.
context.domtree.clear();
context.want_disasm = crate::pretty_clif::should_write_ir(tcx);
// Define function
- let module = &mut cx.module;
tcx.sess.time("define function", || {
module
.define_function(func_id, context, &mut NullTrapSink {}, &mut NullStackMapSink {})
crate::pretty_clif::write_clif_file(
tcx,
"opt",
- Some(cx.module.isa()),
+ Some(module.isa()),
instance,
&context,
&clif_comments,
if let Some(disasm) = &context.mach_compile_result.as_ref().unwrap().disasm {
crate::pretty_clif::write_ir_file(
tcx,
- &format!("{}.vcode", tcx.symbol_name(instance).name),
+ || format!("{}.vcode", tcx.symbol_name(instance).name),
|file| file.write_all(disasm.as_bytes()),
)
}
// Define debuginfo for function
- let isa = cx.module.isa();
+ let isa = module.isa();
let debug_context = &mut cx.debug_context;
let unwind_context = &mut cx.unwind_context;
tcx.sess.time("generate debug info", || {
debug_context.define_function(
instance,
func_id,
- &name,
+ symbol_name.name,
isa,
context,
&source_info_set,
// Unwinding after panicking is not supported
continue;
- // FIXME once unwinding is supported uncomment next lines
- // // Unwinding is unlikely to happen, so mark cleanup block's as cold.
- // fx.cold_blocks.insert(block);
+ // FIXME Once unwinding is supported and Cranelift supports marking blocks as cold, do
+ // so for cleanup blocks.
}
fx.bcx.ins().nop();
let target = fx.get_block(*target);
let failure = fx.bcx.create_block();
- fx.cold_blocks.insert(failure);
+ // FIXME Mark failure block as cold once Cranelift supports it
if *expected {
fx.bcx.ins().brz(cond, failure, &[]);
from_hir_call: _,
} => {
fx.tcx.sess.time("codegen call", || {
- crate::abi::codegen_terminator_call(
- fx,
- *fn_span,
- block,
- func,
- args,
- *destination,
- )
+ crate::abi::codegen_terminator_call(fx, *fn_span, func, args, *destination)
});
}
TerminatorKind::InlineAsm {
// FIXME use emit_small_memset where possible
let addr = lval.to_ptr().get_addr(fx);
let val = operand.load_scalar(fx);
- fx.bcx.call_memset(fx.cx.module.target_config(), addr, val, times);
+ fx.bcx.call_memset(fx.module.target_config(), addr, val, times);
} else {
let loop_block = fx.bcx.create_block();
let loop_block2 = fx.bcx.create_block();
| StatementKind::AscribeUserType(..) => {}
StatementKind::LlvmInlineAsm(asm) => {
- use rustc_span::symbol::Symbol;
- let LlvmInlineAsm { asm, outputs, inputs } = &**asm;
- let rustc_hir::LlvmInlineAsmInner {
- asm: asm_code, // Name
- outputs: output_names, // Vec<LlvmInlineAsmOutput>
- inputs: input_names, // Vec<Name>
- clobbers, // Vec<Name>
- volatile, // bool
- alignstack, // bool
- dialect: _,
- asm_str_style: _,
- } = asm;
- match asm_code.as_str().trim() {
+ match asm.asm.asm.as_str().trim() {
"" => {
// Black box
}
- "mov %rbx, %rsi\n cpuid\n xchg %rbx, %rsi" => {
- assert_eq!(input_names, &[Symbol::intern("{eax}"), Symbol::intern("{ecx}")]);
- assert_eq!(output_names.len(), 4);
- for (i, c) in (&["={eax}", "={esi}", "={ecx}", "={edx}"]).iter().enumerate() {
- assert_eq!(&output_names[i].constraint.as_str(), c);
- assert!(!output_names[i].is_rw);
- assert!(!output_names[i].is_indirect);
- }
-
- assert_eq!(clobbers, &[]);
-
- assert!(!volatile);
- assert!(!alignstack);
-
- assert_eq!(inputs.len(), 2);
- let leaf = codegen_operand(fx, &inputs[0].1).load_scalar(fx); // %eax
- let subleaf = codegen_operand(fx, &inputs[1].1).load_scalar(fx); // %ecx
-
- let (eax, ebx, ecx, edx) =
- crate::intrinsics::codegen_cpuid_call(fx, leaf, subleaf);
-
- assert_eq!(outputs.len(), 4);
- codegen_place(fx, outputs[0])
- .write_cvalue(fx, CValue::by_val(eax, fx.layout_of(fx.tcx.types.u32)));
- codegen_place(fx, outputs[1])
- .write_cvalue(fx, CValue::by_val(ebx, fx.layout_of(fx.tcx.types.u32)));
- codegen_place(fx, outputs[2])
- .write_cvalue(fx, CValue::by_val(ecx, fx.layout_of(fx.tcx.types.u32)));
- codegen_place(fx, outputs[3])
- .write_cvalue(fx, CValue::by_val(edx, fx.layout_of(fx.tcx.types.u32)));
- }
- "xgetbv" => {
- assert_eq!(input_names, &[Symbol::intern("{ecx}")]);
-
- assert_eq!(output_names.len(), 2);
- for (i, c) in (&["={eax}", "={edx}"]).iter().enumerate() {
- assert_eq!(&output_names[i].constraint.as_str(), c);
- assert!(!output_names[i].is_rw);
- assert!(!output_names[i].is_indirect);
- }
-
- assert_eq!(clobbers, &[]);
-
- assert!(!volatile);
- assert!(!alignstack);
-
- crate::trap::trap_unimplemented(fx, "_xgetbv arch intrinsic is not supported");
- }
- // ___chkstk, ___chkstk_ms and __alloca are only used on Windows
- _ if fx.tcx.symbol_name(fx.instance).name.starts_with("___chkstk") => {
- crate::trap::trap_unimplemented(fx, "Stack probes are not supported");
- }
- _ if fx.tcx.symbol_name(fx.instance).name == "__alloca" => {
- crate::trap::trap_unimplemented(fx, "Alloca is not supported");
- }
- // Used in sys::windows::abort_internal
- "int $$0x29" => {
- crate::trap::trap_unimplemented(fx, "Windows abort");
- }
- _ => fx
- .tcx
- .sess
- .span_fatal(stmt.source_info.span, "Inline assembly is not supported"),
+ _ => fx.tcx.sess.span_fatal(
+ stmt.source_info.span,
+ "Legacy `llvm_asm!` inline assembly is not supported. \
+ Try using the new `asm!` instead.",
+ ),
}
}
StatementKind::Coverage { .. } => fx.tcx.sess.fatal("-Zcoverage is unimplemented"),
let elem_size: u64 = pointee.size.bytes();
let bytes =
if elem_size != 1 { fx.bcx.ins().imul_imm(count, elem_size as i64) } else { count };
- fx.bcx.call_memcpy(fx.cx.module.target_config(), dst, src, bytes);
+ fx.bcx.call_memcpy(fx.module.target_config(), dst, src, bytes);
}
}
}
use rustc_index::vec::IndexVec;
+use rustc_middle::ty::SymbolName;
use rustc_target::abi::call::FnAbi;
use rustc_target::abi::{Integer, Primitive};
use rustc_target::spec::{HasTargetSpec, Target};
+use crate::constant::ConstantCx;
use crate::prelude::*;
pub(crate) fn pointer_ty(tcx: TyCtxt<'_>) -> types::Type {
}
}
-pub(crate) struct FunctionCx<'m, 'clif, 'tcx> {
- pub(crate) cx: &'clif mut crate::CodegenCx<'m, 'tcx>,
+pub(crate) struct FunctionCx<'m, 'clif, 'tcx: 'm> {
+ pub(crate) cx: &'clif mut crate::CodegenCx<'tcx>,
+ pub(crate) module: &'m mut dyn Module,
pub(crate) tcx: TyCtxt<'tcx>,
pub(crate) pointer_type: Type, // Cached from module
+ pub(crate) vtables: FxHashMap<(Ty<'tcx>, Option<ty::PolyExistentialTraitRef<'tcx>>), DataId>,
+ pub(crate) constants_cx: ConstantCx,
pub(crate) instance: Instance<'tcx>,
+ pub(crate) symbol_name: SymbolName<'tcx>,
pub(crate) mir: &'tcx Body<'tcx>,
pub(crate) fn_abi: Option<FnAbi<'tcx, Ty<'tcx>>>,
/// When `#[track_caller]` is used, the implicit caller location is stored in this variable.
pub(crate) caller_location: Option<CValue<'tcx>>,
- /// See [`crate::optimize::code_layout`] for more information.
- pub(crate) cold_blocks: EntitySet<Block>,
-
pub(crate) clif_comments: crate::pretty_clif::CommentWriter,
pub(crate) source_info_set: indexmap::IndexSet<SourceInfo>,
}
pub(crate) fn triple(&self) -> &target_lexicon::Triple {
- self.cx.module.isa().triple()
+ self.module.isa().triple()
}
pub(crate) fn anonymous_str(&mut self, prefix: &str, msg: &str) -> Value {
let mut data_ctx = DataContext::new();
data_ctx.define(msg.as_bytes().to_vec().into_boxed_slice());
let msg_id = self
- .cx
.module
.declare_data(&format!("__{}_{:08x}", prefix, msg_hash), Linkage::Local, false, false)
.unwrap();
// Ignore DuplicateDefinition error, as the data will be the same
- let _ = self.cx.module.define_data(msg_id, &data_ctx);
+ let _ = self.module.define_data(msg_id, &data_ctx);
- let local_msg_id = self.cx.module.declare_data_in_func(msg_id, self.bcx.func);
+ let local_msg_id = self.module.declare_data_in_func(msg_id, self.bcx.func);
if self.clif_comments.enabled() {
self.add_comment(local_msg_id, msg);
}
--- /dev/null
+use std::env;
+use std::str::FromStr;
+
+fn bool_env_var(key: &str) -> bool {
+ env::var(key).as_ref().map(|val| &**val) == Ok("1")
+}
+
+/// The mode to use for compilation.
+#[derive(Copy, Clone, Debug)]
+pub enum CodegenMode {
+ /// AOT compile the crate. This is the default.
+ Aot,
+ /// JIT compile and execute the crate.
+ Jit,
+ /// JIT compile and execute the crate, but only compile functions the first time they are used.
+ JitLazy,
+}
+
+impl FromStr for CodegenMode {
+ type Err = String;
+
+ fn from_str(s: &str) -> Result<Self, Self::Err> {
+ match s {
+ "aot" => Ok(CodegenMode::Aot),
+ "jit" => Ok(CodegenMode::Jit),
+ "jit-lazy" => Ok(CodegenMode::JitLazy),
+ _ => Err(format!("Unknown codegen mode `{}`", s)),
+ }
+ }
+}
+
+/// Configuration of cg_clif as passed in through `-Cllvm-args` and various env vars.
+#[derive(Clone, Debug)]
+pub struct BackendConfig {
+ /// Should the crate be AOT compiled or JIT executed.
+ ///
+ /// Defaults to AOT compilation. Can be set using `-Cllvm-args=mode=...`.
+ pub codegen_mode: CodegenMode,
+
+ /// When JIT mode is enable pass these arguments to the program.
+ ///
+ /// Defaults to the value of `CG_CLIF_JIT_ARGS`.
+ pub jit_args: Vec<String>,
+
+ /// Display the time it took to perform codegen for a crate.
+ ///
+ /// Defaults to true when the `CG_CLIF_DISPLAY_CG_TIME` env var is set to 1 or false otherwise.
+ /// Can be set using `-Cllvm-args=display_cg_time=...`.
+ pub display_cg_time: bool,
+
+ /// 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.
+ ///
+ /// Defaults to true when the `CG_CLIF_ENABLE_VERIFIER` env var is set to 1 or when cg_clif is
+ /// compiled with debug assertions enabled or false otherwise. Can be set using
+ /// `-Cllvm-args=enable_verifier=...`.
+ pub enable_verifier: bool,
+
+ /// Don't cache object files in the incremental cache. Useful during development of cg_clif
+ /// to make it possible to use incremental mode for all analyses performed by rustc without
+ /// caching object files when their content should have been changed by a change to cg_clif.
+ ///
+ /// Defaults to true when the `CG_CLIF_DISABLE_INCR_CACHE` env var is set to 1 or false
+ /// otherwise. Can be set using `-Cllvm-args=disable_incr_cache=...`.
+ pub disable_incr_cache: bool,
+}
+
+impl Default for BackendConfig {
+ fn default() -> Self {
+ BackendConfig {
+ codegen_mode: CodegenMode::Aot,
+ jit_args: {
+ let args = std::env::var("CG_CLIF_JIT_ARGS").unwrap_or_else(|_| String::new());
+ args.split(' ').map(|arg| arg.to_string()).collect()
+ },
+ display_cg_time: bool_env_var("CG_CLIF_DISPLAY_CG_TIME"),
+ enable_verifier: cfg!(debug_assertions) || bool_env_var("CG_CLIF_ENABLE_VERIFIER"),
+ disable_incr_cache: bool_env_var("CG_CLIF_DISABLE_INCR_CACHE"),
+ }
+ }
+}
+
+impl BackendConfig {
+ /// Parse the configuration passed in using `-Cllvm-args`.
+ pub fn from_opts(opts: &[String]) -> Result<Self, String> {
+ fn parse_bool(name: &str, value: &str) -> Result<bool, String> {
+ value.parse().map_err(|_| format!("failed to parse value `{}` for {}", value, name))
+ }
+
+ let mut config = BackendConfig::default();
+ for opt in opts {
+ if let Some((name, value)) = opt.split_once('=') {
+ match name {
+ "mode" => config.codegen_mode = value.parse()?,
+ "display_cg_time" => config.display_cg_time = parse_bool(name, value)?,
+ "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)),
+ }
+ } else {
+ return Err(format!("Invalid option `{}`", opt));
+ }
+ }
+
+ Ok(config)
+ }
+}
use rustc_span::DUMMY_SP;
-use rustc_data_structures::fx::FxHashSet;
+use rustc_data_structures::fx::{FxHashMap, FxHashSet};
use rustc_errors::ErrorReported;
use rustc_middle::middle::codegen_fn_attrs::CodegenFnAttrFlags;
use rustc_middle::mir::interpret::{
use crate::prelude::*;
-#[derive(Default)]
pub(crate) struct ConstantCx {
todo: Vec<TodoItem>,
done: FxHashSet<DataId>,
+ anon_allocs: FxHashMap<AllocId, DataId>,
}
#[derive(Copy, Clone, Debug)]
}
impl ConstantCx {
+ pub(crate) fn new() -> Self {
+ ConstantCx { todo: vec![], done: FxHashSet::default(), anon_allocs: FxHashMap::default() }
+ }
+
pub(crate) fn finalize(mut self, tcx: TyCtxt<'_>, module: &mut dyn Module) {
//println!("todo {:?}", self.todo);
define_all_allocs(tcx, module, &mut self);
all_constants_ok
}
-pub(crate) fn codegen_static(constants_cx: &mut ConstantCx, def_id: DefId) {
+pub(crate) fn codegen_static(tcx: TyCtxt<'_>, module: &mut dyn Module, def_id: DefId) {
+ let mut constants_cx = ConstantCx::new();
constants_cx.todo.push(TodoItem::Static(def_id));
+ constants_cx.finalize(tcx, module);
}
pub(crate) fn codegen_tls_ref<'tcx>(
def_id: DefId,
layout: TyAndLayout<'tcx>,
) -> CValue<'tcx> {
- let data_id = data_id_for_static(fx.tcx, fx.cx.module, def_id, false);
- let local_data_id = fx.cx.module.declare_data_in_func(data_id, &mut fx.bcx.func);
+ let data_id = data_id_for_static(fx.tcx, fx.module, def_id, false);
+ let local_data_id = fx.module.declare_data_in_func(data_id, &mut fx.bcx.func);
if fx.clif_comments.enabled() {
fx.add_comment(local_data_id, format!("tls {:?}", def_id));
}
def_id: DefId,
layout: TyAndLayout<'tcx>,
) -> CPlace<'tcx> {
- let data_id = data_id_for_static(fx.tcx, fx.cx.module, def_id, false);
- let local_data_id = fx.cx.module.declare_data_in_func(data_id, &mut fx.bcx.func);
+ let data_id = data_id_for_static(fx.tcx, fx.module, def_id, false);
+ let local_data_id = fx.module.declare_data_in_func(data_id, &mut fx.bcx.func);
if fx.clif_comments.enabled() {
fx.add_comment(local_data_id, format!("{:?}", def_id));
}
let alloc_kind = fx.tcx.get_global_alloc(ptr.alloc_id);
let base_addr = match alloc_kind {
Some(GlobalAlloc::Memory(alloc)) => {
- fx.cx.constants_cx.todo.push(TodoItem::Alloc(ptr.alloc_id));
- let data_id =
- data_id_for_alloc_id(fx.cx.module, ptr.alloc_id, alloc.mutability);
+ fx.constants_cx.todo.push(TodoItem::Alloc(ptr.alloc_id));
+ let data_id = data_id_for_alloc_id(
+ &mut fx.constants_cx,
+ fx.module,
+ ptr.alloc_id,
+ alloc.mutability,
+ );
let local_data_id =
- fx.cx.module.declare_data_in_func(data_id, &mut fx.bcx.func);
+ fx.module.declare_data_in_func(data_id, &mut fx.bcx.func);
if fx.clif_comments.enabled() {
fx.add_comment(local_data_id, format!("{:?}", ptr.alloc_id));
}
fx.bcx.ins().global_value(fx.pointer_type, local_data_id)
}
Some(GlobalAlloc::Function(instance)) => {
- let func_id =
- crate::abi::import_function(fx.tcx, fx.cx.module, instance);
+ let func_id = crate::abi::import_function(fx.tcx, fx.module, instance);
let local_func_id =
- fx.cx.module.declare_func_in_func(func_id, &mut fx.bcx.func);
+ fx.module.declare_func_in_func(func_id, &mut fx.bcx.func);
fx.bcx.ins().func_addr(fx.pointer_type, local_func_id)
}
Some(GlobalAlloc::Static(def_id)) => {
assert!(fx.tcx.is_static(def_id));
- let data_id = data_id_for_static(fx.tcx, fx.cx.module, def_id, false);
+ let data_id = data_id_for_static(fx.tcx, fx.module, def_id, false);
let local_data_id =
- fx.cx.module.declare_data_in_func(data_id, &mut fx.bcx.func);
+ fx.module.declare_data_in_func(data_id, &mut fx.bcx.func);
if fx.clif_comments.enabled() {
fx.add_comment(local_data_id, format!("{:?}", def_id));
}
alloc: &'tcx Allocation,
) -> crate::pointer::Pointer {
let alloc_id = fx.tcx.create_memory_alloc(alloc);
- fx.cx.constants_cx.todo.push(TodoItem::Alloc(alloc_id));
- let data_id = data_id_for_alloc_id(fx.cx.module, alloc_id, alloc.mutability);
+ fx.constants_cx.todo.push(TodoItem::Alloc(alloc_id));
+ let data_id =
+ data_id_for_alloc_id(&mut fx.constants_cx, &mut *fx.module, alloc_id, alloc.mutability);
- let local_data_id = fx.cx.module.declare_data_in_func(data_id, &mut fx.bcx.func);
+ let local_data_id = fx.module.declare_data_in_func(data_id, &mut fx.bcx.func);
if fx.clif_comments.enabled() {
fx.add_comment(local_data_id, format!("{:?}", alloc_id));
}
}
fn data_id_for_alloc_id(
+ cx: &mut ConstantCx,
module: &mut dyn Module,
alloc_id: AllocId,
mutability: rustc_hir::Mutability,
) -> DataId {
- module
- .declare_data(
- &format!(".L__alloc_{:x}", alloc_id.0),
- Linkage::Local,
- mutability == rustc_hir::Mutability::Mut,
- false,
- )
- .unwrap()
+ *cx.anon_allocs.entry(alloc_id).or_insert_with(|| {
+ module.declare_anonymous_data(mutability == rustc_hir::Mutability::Mut, false).unwrap()
+ })
}
fn data_id_for_static(
GlobalAlloc::Memory(alloc) => alloc,
GlobalAlloc::Function(_) | GlobalAlloc::Static(_) => unreachable!(),
};
- let data_id = data_id_for_alloc_id(module, alloc_id, alloc.mutability);
+ let data_id = data_id_for_alloc_id(cx, module, alloc_id, alloc.mutability);
(data_id, alloc, None)
}
TodoItem::Static(def_id) => {
}
GlobalAlloc::Memory(target_alloc) => {
cx.todo.push(TodoItem::Alloc(reloc));
- data_id_for_alloc_id(module, reloc, target_alloc.mutability)
+ data_id_for_alloc_id(cx, module, reloc, target_alloc.mutability)
}
GlobalAlloc::Static(def_id) => {
if tcx.codegen_fn_attrs(def_id).flags.contains(CodegenFnAttrFlags::THREAD_LOCAL)
data_ctx.write_data_addr(offset.bytes() as u32, global_value, addend as i64);
}
- // FIXME don't duplicate definitions in lazy jit mode
- let _ = module.define_data(data_id, &data_ctx);
+ module.define_data(data_id, &data_ctx).unwrap();
cx.done.insert(data_id);
}
use cranelift_codegen::isa::{unwind::UnwindInfo, TargetIsa};
use gimli::write::{Address, CieId, EhFrame, FrameTable, Section};
+use gimli::RunTimeEndian;
use crate::backend::WriteDebugInfo;
-pub(crate) struct UnwindContext<'tcx> {
- tcx: TyCtxt<'tcx>,
+pub(crate) struct UnwindContext {
+ endian: RunTimeEndian,
frame_table: FrameTable,
cie_id: Option<CieId>,
}
-impl<'tcx> UnwindContext<'tcx> {
- pub(crate) fn new(tcx: TyCtxt<'tcx>, isa: &dyn TargetIsa, pic_eh_frame: bool) -> Self {
+impl UnwindContext {
+ pub(crate) fn new(tcx: TyCtxt<'_>, isa: &dyn TargetIsa, pic_eh_frame: bool) -> Self {
+ let endian = super::target_endian(tcx);
let mut frame_table = FrameTable::default();
let cie_id = if let Some(mut cie) = isa.create_systemv_cie() {
None
};
- UnwindContext { tcx, frame_table, cie_id }
+ UnwindContext { endian, frame_table, cie_id }
}
pub(crate) fn add_function(&mut self, func_id: FuncId, context: &Context, isa: &dyn TargetIsa) {
}
pub(crate) fn emit<P: WriteDebugInfo>(self, product: &mut P) {
- let mut eh_frame =
- EhFrame::from(super::emit::WriterRelocate::new(super::target_endian(self.tcx)));
+ let mut eh_frame = EhFrame::from(super::emit::WriterRelocate::new(self.endian));
self.frame_table.write_eh_frame(&mut eh_frame).unwrap();
if !eh_frame.0.writer.slice().is_empty() {
}
}
- #[cfg(feature = "jit")]
- pub(crate) unsafe fn register_jit(
- self,
- jit_module: &cranelift_jit::JITModule,
- ) -> Option<UnwindRegistry> {
- let mut eh_frame =
- EhFrame::from(super::emit::WriterRelocate::new(super::target_endian(self.tcx)));
+ #[cfg(all(feature = "jit", windows))]
+ pub(crate) unsafe fn register_jit(self, _jit_module: &cranelift_jit::JITModule) {}
+
+ #[cfg(all(feature = "jit", not(windows)))]
+ pub(crate) unsafe fn register_jit(self, jit_module: &cranelift_jit::JITModule) {
+ let mut eh_frame = EhFrame::from(super::emit::WriterRelocate::new(self.endian));
self.frame_table.write_eh_frame(&mut eh_frame).unwrap();
if eh_frame.0.writer.slice().is_empty() {
- return None;
+ return;
}
let mut eh_frame = eh_frame.0.relocate_for_jit(jit_module);
// GCC expects a terminating "empty" length, so write a 0 length at the end of the table.
eh_frame.extend(&[0, 0, 0, 0]);
- let mut registrations = Vec::new();
+ // FIXME support unregistering unwind tables once cranelift-jit supports deallocating
+ // individual functions
+ #[allow(unused_variables)]
+ let (eh_frame, eh_frame_len, _) = Vec::into_raw_parts(eh_frame);
// =======================================================================
// Everything after this line up to the end of the file is loosly based on
#[cfg(target_os = "macos")]
{
// On macOS, `__register_frame` takes a pointer to a single FDE
- let start = eh_frame.as_ptr();
- let end = start.add(eh_frame.len());
+ let start = eh_frame;
+ let end = start.add(eh_frame_len);
let mut current = start;
// Walk all of the entries in the frame table and register them
// Skip over the CIE
if current != start {
__register_frame(current);
- registrations.push(current as usize);
}
// Move to the next table entry (+4 because the length itself is not inclusive)
#[cfg(not(target_os = "macos"))]
{
// On other platforms, `__register_frame` will walk the FDEs until an entry of length 0
- let ptr = eh_frame.as_ptr();
- __register_frame(ptr);
- registrations.push(ptr as usize);
+ __register_frame(eh_frame);
}
-
- Some(UnwindRegistry { _frame_table: eh_frame, registrations })
}
}
-/// Represents a registry of function unwind information for System V ABI.
-pub(crate) struct UnwindRegistry {
- _frame_table: Vec<u8>,
- registrations: Vec<usize>,
-}
-
extern "C" {
// libunwind import
fn __register_frame(fde: *const u8);
- fn __deregister_frame(fde: *const u8);
-}
-
-impl Drop for UnwindRegistry {
- fn drop(&mut self) {
- unsafe {
- // libgcc stores the frame entries as a linked list in decreasing sort order
- // based on the PC value of the registered entry.
- //
- // As we store the registrations in increasing order, it would be O(N^2) to
- // deregister in that order.
- //
- // To ensure that we just pop off the first element in the list upon every
- // deregistration, walk our list of registrations backwards.
- for fde in self.registrations.iter().rev() {
- __deregister_frame(*fde as *const _);
- }
- }
- }
}
use crate::{prelude::*, BackendConfig};
-fn new_module(tcx: TyCtxt<'_>, name: String) -> ObjectModule {
- let module = crate::backend::make_module(tcx.sess, name);
- assert_eq!(pointer_ty(tcx), module.target_config().pointer_type());
- module
-}
-
struct ModuleCodegenResult(CompiledModule, Option<(WorkProductId, WorkProduct)>);
impl<HCX> HashStable<HCX> for ModuleCodegenResult {
fn emit_module(
tcx: TyCtxt<'_>,
+ backend_config: &BackendConfig,
name: String,
kind: ModuleKind,
module: ObjectModule,
debug: Option<DebugContext<'_>>,
- unwind_context: UnwindContext<'_>,
+ unwind_context: UnwindContext,
) -> ModuleCodegenResult {
let mut product = module.finish();
tcx.sess.fatal(&format!("error writing object file: {}", err));
}
- let work_product = if std::env::var("CG_CLIF_INCR_CACHE_DISABLED").is_ok() {
+ let work_product = if backend_config.disable_incr_cache {
None
} else {
rustc_incremental::copy_cgu_workproduct_to_incr_comp_cache_dir(
let cgu = tcx.codegen_unit(cgu_name);
let mono_items = cgu.items_in_deterministic_order(tcx);
- let mut module = new_module(tcx, cgu_name.as_str().to_string());
+ let isa = crate::build_isa(tcx.sess, &backend_config);
+ let mut module = crate::backend::make_module(tcx.sess, isa, cgu_name.as_str().to_string());
let mut cx = crate::CodegenCx::new(
tcx,
- backend_config,
- &mut module,
+ backend_config.clone(),
+ module.isa(),
tcx.sess.opts.debuginfo != DebugInfo::None,
);
- super::predefine_mono_items(&mut cx, &mono_items);
+ super::predefine_mono_items(tcx, &mut module, &mono_items);
for (mono_item, _) in mono_items {
match mono_item {
MonoItem::Fn(inst) => {
- cx.tcx.sess.time("codegen fn", || crate::base::codegen_fn(&mut cx, inst));
- }
- MonoItem::Static(def_id) => {
- crate::constant::codegen_static(&mut cx.constants_cx, def_id)
+ cx.tcx
+ .sess
+ .time("codegen fn", || crate::base::codegen_fn(&mut cx, &mut module, inst));
}
+ MonoItem::Static(def_id) => crate::constant::codegen_static(tcx, &mut module, def_id),
MonoItem::GlobalAsm(item_id) => {
let item = cx.tcx.hir().item(item_id);
if let rustc_hir::ItemKind::GlobalAsm(rustc_hir::GlobalAsm { asm }) = item.kind {
}
}
}
- let (global_asm, debug, mut unwind_context) =
- tcx.sess.time("finalize CodegenCx", || cx.finalize());
- crate::main_shim::maybe_create_entry_wrapper(tcx, &mut module, &mut unwind_context);
+ crate::main_shim::maybe_create_entry_wrapper(tcx, &mut module, &mut cx.unwind_context, false);
- let codegen_result = emit_module(
- tcx,
- cgu.name().as_str().to_string(),
- ModuleKind::Regular,
- module,
- debug,
- unwind_context,
- );
+ let debug_context = cx.debug_context;
+ let unwind_context = cx.unwind_context;
+ let codegen_result = tcx.sess.time("write object file", || {
+ emit_module(
+ tcx,
+ &backend_config,
+ cgu.name().as_str().to_string(),
+ ModuleKind::Regular,
+ module,
+ debug_context,
+ unwind_context,
+ )
+ });
- codegen_global_asm(tcx, &cgu.name().as_str(), &global_asm);
+ codegen_global_asm(tcx, &cgu.name().as_str(), &cx.global_asm);
codegen_result
}
-pub(super) fn run_aot(
+pub(crate) fn run_aot(
tcx: TyCtxt<'_>,
backend_config: BackendConfig,
metadata: EncodedMetadata,
}
}
- let modules = super::time(tcx, "codegen mono items", || {
+ let modules = super::time(tcx, backend_config.display_cg_time, "codegen mono items", || {
cgus.iter()
.map(|cgu| {
let cgu_reuse = determine_cgu_reuse(tcx, cgu);
tcx.sess.cgu_reuse_tracker.set_actual_reuse(&cgu.name().as_str(), cgu_reuse);
match cgu_reuse {
- _ if std::env::var("CG_CLIF_INCR_CACHE_DISABLED").is_ok() => {}
+ _ if backend_config.disable_incr_cache => {}
CguReuse::No => {}
CguReuse::PreLto => {
return reuse_workproduct_for_cgu(tcx, &*cgu, &mut work_products);
let (ModuleCodegenResult(module, work_product), _) = tcx.dep_graph.with_task(
dep_node,
tcx,
- (backend_config, cgu.name()),
+ (backend_config.clone(), cgu.name()),
module_codegen,
rustc_middle::dep_graph::hash_result,
);
tcx.sess.abort_if_errors();
- let mut allocator_module = new_module(tcx, "allocator_shim".to_string());
+ let isa = crate::build_isa(tcx.sess, &backend_config);
+ let mut allocator_module =
+ crate::backend::make_module(tcx.sess, isa, "allocator_shim".to_string());
+ assert_eq!(pointer_ty(tcx), allocator_module.target_config().pointer_type());
let mut allocator_unwind_context = UnwindContext::new(tcx, allocator_module.isa(), true);
let created_alloc_shim =
crate::allocator::codegen(tcx, &mut allocator_module, &mut allocator_unwind_context);
let allocator_module = if created_alloc_shim {
let ModuleCodegenResult(module, work_product) = emit_module(
tcx,
+ &backend_config,
"allocator_shim".to_string(),
ModuleKind::Allocator,
allocator_module,
-//! The JIT driver uses [`cranelift_simplejit`] to JIT execute programs without writing any object
+//! The JIT driver uses [`cranelift_jit`] to JIT execute programs without writing any object
//! files.
use std::cell::RefCell;
use crate::{prelude::*, BackendConfig};
use crate::{CodegenCx, CodegenMode};
-thread_local! {
- pub static BACKEND_CONFIG: RefCell<Option<BackendConfig>> = RefCell::new(None);
- pub static CURRENT_MODULE: RefCell<Option<JITModule>> = RefCell::new(None);
+struct JitState {
+ backend_config: BackendConfig,
+ jit_module: JITModule,
}
-pub(super) fn run_jit(tcx: TyCtxt<'_>, backend_config: BackendConfig) -> ! {
- if !tcx.sess.opts.output_types.should_codegen() {
- tcx.sess.fatal("JIT mode doesn't work with `cargo check`.");
- }
+thread_local! {
+ static LAZY_JIT_STATE: RefCell<Option<JitState>> = RefCell::new(None);
+}
+fn create_jit_module<'tcx>(
+ tcx: TyCtxt<'tcx>,
+ backend_config: &BackendConfig,
+ hotswap: bool,
+) -> (JITModule, CodegenCx<'tcx>) {
let imported_symbols = load_imported_symbols_for_jit(tcx);
- let mut jit_builder =
- JITBuilder::with_isa(crate::build_isa(tcx.sess), cranelift_module::default_libcall_names());
- jit_builder.hotswap(matches!(backend_config.codegen_mode, CodegenMode::JitLazy));
+ let isa = crate::build_isa(tcx.sess, backend_config);
+ let mut jit_builder = JITBuilder::with_isa(isa, cranelift_module::default_libcall_names());
+ jit_builder.hotswap(hotswap);
crate::compiler_builtins::register_functions_for_jit(&mut jit_builder);
jit_builder.symbols(imported_symbols);
let mut jit_module = JITModule::new(jit_builder);
- assert_eq!(pointer_ty(tcx), jit_module.target_config().pointer_type());
+
+ let mut cx = crate::CodegenCx::new(tcx, backend_config.clone(), jit_module.isa(), false);
+
+ crate::allocator::codegen(tcx, &mut jit_module, &mut cx.unwind_context);
+ crate::main_shim::maybe_create_entry_wrapper(
+ tcx,
+ &mut jit_module,
+ &mut cx.unwind_context,
+ true,
+ );
+
+ (jit_module, cx)
+}
+
+pub(crate) fn run_jit(tcx: TyCtxt<'_>, backend_config: BackendConfig) -> ! {
+ if !tcx.sess.opts.output_types.should_codegen() {
+ tcx.sess.fatal("JIT mode doesn't work with `cargo check`");
+ }
+
+ if !tcx.sess.crate_types().contains(&rustc_session::config::CrateType::Executable) {
+ tcx.sess.fatal("can't jit non-executable crate");
+ }
+
+ let (mut jit_module, mut cx) = create_jit_module(
+ tcx,
+ &backend_config,
+ matches!(backend_config.codegen_mode, CodegenMode::JitLazy),
+ );
let (_, cgus) = tcx.collect_and_partition_mono_items(LOCAL_CRATE);
let mono_items = cgus
.into_iter()
.collect::<Vec<(_, (_, _))>>();
- let mut cx = crate::CodegenCx::new(tcx, backend_config, &mut jit_module, false);
-
- super::time(tcx, "codegen mono items", || {
- super::predefine_mono_items(&mut cx, &mono_items);
+ super::time(tcx, backend_config.display_cg_time, "codegen mono items", || {
+ super::predefine_mono_items(tcx, &mut jit_module, &mono_items);
for (mono_item, _) in mono_items {
match mono_item {
MonoItem::Fn(inst) => match backend_config.codegen_mode {
CodegenMode::Aot => unreachable!(),
CodegenMode::Jit => {
- cx.tcx.sess.time("codegen fn", || crate::base::codegen_fn(&mut cx, inst));
+ cx.tcx.sess.time("codegen fn", || {
+ crate::base::codegen_fn(&mut cx, &mut jit_module, inst)
+ });
}
- CodegenMode::JitLazy => codegen_shim(&mut cx, inst),
+ CodegenMode::JitLazy => codegen_shim(&mut cx, &mut jit_module, inst),
},
MonoItem::Static(def_id) => {
- crate::constant::codegen_static(&mut cx.constants_cx, def_id);
+ crate::constant::codegen_static(tcx, &mut jit_module, def_id);
}
MonoItem::GlobalAsm(item_id) => {
- let item = cx.tcx.hir().item(item_id);
+ let item = tcx.hir().item(item_id);
tcx.sess.span_fatal(item.span, "Global asm is not supported in JIT mode");
}
}
}
});
- let (global_asm, _debug, mut unwind_context) =
- tcx.sess.time("finalize CodegenCx", || cx.finalize());
- jit_module.finalize_definitions();
-
- if !global_asm.is_empty() {
+ if !cx.global_asm.is_empty() {
tcx.sess.fatal("Inline asm is not supported in JIT mode");
}
- crate::allocator::codegen(tcx, &mut jit_module, &mut unwind_context);
-
tcx.sess.abort_if_errors();
jit_module.finalize_definitions();
- let _unwind_register_guard = unsafe { unwind_context.register_jit(&jit_module) };
+ unsafe { cx.unwind_context.register_jit(&jit_module) };
println!(
"Rustc codegen cranelift will JIT run the executable, because -Cllvm-args=mode=jit was passed"
);
- let args = ::std::env::var("CG_CLIF_JIT_ARGS").unwrap_or_else(|_| String::new());
let args = std::iter::once(&*tcx.crate_name(LOCAL_CRATE).as_str().to_string())
- .chain(args.split(' '))
+ .chain(backend_config.jit_args.iter().map(|arg| &**arg))
.map(|arg| CString::new(arg).unwrap())
.collect::<Vec<_>>();
let mut argv = args.iter().map(|arg| arg.as_ptr()).collect::<Vec<_>>();
// useful as some dynamic linkers use it as a marker to jump over.
argv.push(std::ptr::null());
- BACKEND_CONFIG.with(|tls_backend_config| {
- assert!(tls_backend_config.borrow_mut().replace(backend_config).is_none())
+ let start_sig = Signature {
+ params: vec![
+ AbiParam::new(jit_module.target_config().pointer_type()),
+ AbiParam::new(jit_module.target_config().pointer_type()),
+ ],
+ returns: vec![AbiParam::new(jit_module.target_config().pointer_type() /*isize*/)],
+ call_conv: CallConv::triple_default(&crate::target_triple(tcx.sess)),
+ };
+ let start_func_id = jit_module.declare_function("main", Linkage::Import, &start_sig).unwrap();
+ let finalized_start: *const u8 = jit_module.get_finalized_function(start_func_id);
+
+ LAZY_JIT_STATE.with(|lazy_jit_state| {
+ let mut lazy_jit_state = lazy_jit_state.borrow_mut();
+ assert!(lazy_jit_state.is_none());
+ *lazy_jit_state = Some(JitState { backend_config, jit_module });
});
- let (main_def_id, entry_ty) = tcx.entry_fn(LOCAL_CRATE).unwrap();
- let instance = Instance::mono(tcx, main_def_id).polymorphize(tcx);
-
- match entry_ty {
- EntryFnType::Main => {
- // FIXME set program arguments somehow
-
- let main_sig = Signature {
- params: vec![],
- returns: vec![],
- call_conv: CallConv::triple_default(&crate::target_triple(tcx.sess)),
- };
- let main_func_id = jit_module
- .declare_function(tcx.symbol_name(instance).name, Linkage::Import, &main_sig)
- .unwrap();
- let finalized_main: *const u8 = jit_module.get_finalized_function(main_func_id);
-
- CURRENT_MODULE.with(|current_module| {
- assert!(current_module.borrow_mut().replace(jit_module).is_none())
- });
-
- let f: extern "C" fn() = unsafe { ::std::mem::transmute(finalized_main) };
- f();
- std::process::exit(0);
- }
- EntryFnType::Start => {
- let start_sig = Signature {
- params: vec![
- AbiParam::new(jit_module.target_config().pointer_type()),
- AbiParam::new(jit_module.target_config().pointer_type()),
- ],
- returns: vec![AbiParam::new(
- jit_module.target_config().pointer_type(), /*isize*/
- )],
- call_conv: CallConv::triple_default(&crate::target_triple(tcx.sess)),
- };
- let start_func_id = jit_module
- .declare_function(tcx.symbol_name(instance).name, Linkage::Import, &start_sig)
- .unwrap();
- let finalized_start: *const u8 = jit_module.get_finalized_function(start_func_id);
-
- CURRENT_MODULE.with(|current_module| {
- assert!(current_module.borrow_mut().replace(jit_module).is_none())
- });
-
- let f: extern "C" fn(c_int, *const *const c_char) -> c_int =
- unsafe { ::std::mem::transmute(finalized_start) };
- let ret = f(args.len() as c_int, argv.as_ptr());
- std::process::exit(ret);
- }
- }
+ let f: extern "C" fn(c_int, *const *const c_char) -> c_int =
+ unsafe { ::std::mem::transmute(finalized_start) };
+ let ret = f(args.len() as c_int, argv.as_ptr());
+ std::process::exit(ret);
}
#[no_mangle]
// lift is used to ensure the correct lifetime for instance.
let instance = tcx.lift(unsafe { *instance_ptr }).unwrap();
- CURRENT_MODULE.with(|jit_module| {
- let mut jit_module = jit_module.borrow_mut();
- let jit_module = jit_module.as_mut().unwrap();
- let backend_config =
- BACKEND_CONFIG.with(|backend_config| backend_config.borrow().clone().unwrap());
+ LAZY_JIT_STATE.with(|lazy_jit_state| {
+ let mut lazy_jit_state = lazy_jit_state.borrow_mut();
+ let lazy_jit_state = lazy_jit_state.as_mut().unwrap();
+ let jit_module = &mut lazy_jit_state.jit_module;
+ let backend_config = lazy_jit_state.backend_config.clone();
- let name = tcx.symbol_name(instance).name.to_string();
+ let name = tcx.symbol_name(instance).name;
let sig = crate::abi::get_function_sig(tcx, jit_module.isa().triple(), instance);
- let func_id = jit_module.declare_function(&name, Linkage::Export, &sig).unwrap();
+ let func_id = jit_module.declare_function(name, Linkage::Export, &sig).unwrap();
jit_module.prepare_for_function_redefine(func_id).unwrap();
- let mut cx = crate::CodegenCx::new(tcx, backend_config, jit_module, false);
- tcx.sess.time("codegen fn", || crate::base::codegen_fn(&mut cx, instance));
+ let mut cx = crate::CodegenCx::new(tcx, backend_config, jit_module.isa(), false);
+ tcx.sess.time("codegen fn", || crate::base::codegen_fn(&mut cx, jit_module, instance));
- let (global_asm, _debug_context, unwind_context) = cx.finalize();
- assert!(global_asm.is_empty());
+ assert!(cx.global_asm.is_empty());
jit_module.finalize_definitions();
- std::mem::forget(unsafe { unwind_context.register_jit(&jit_module) });
+ unsafe { cx.unwind_context.register_jit(&jit_module) };
jit_module.get_finalized_function(func_id)
})
})
imported_symbols
}
-fn codegen_shim<'tcx>(cx: &mut CodegenCx<'_, 'tcx>, inst: Instance<'tcx>) {
+fn codegen_shim<'tcx>(cx: &mut CodegenCx<'tcx>, module: &mut JITModule, inst: Instance<'tcx>) {
let tcx = cx.tcx;
- let pointer_type = cx.module.target_config().pointer_type();
+ let pointer_type = module.target_config().pointer_type();
- let name = tcx.symbol_name(inst).name.to_string();
- let sig = crate::abi::get_function_sig(tcx, cx.module.isa().triple(), inst);
- let func_id = cx.module.declare_function(&name, Linkage::Export, &sig).unwrap();
+ let name = tcx.symbol_name(inst).name;
+ let sig = crate::abi::get_function_sig(tcx, module.isa().triple(), inst);
+ let func_id = module.declare_function(name, Linkage::Export, &sig).unwrap();
let instance_ptr = Box::into_raw(Box::new(inst));
- let jit_fn = cx
- .module
+ let jit_fn = module
.declare_function(
"__clif_jit_fn",
Linkage::Import,
&Signature {
- call_conv: cx.module.target_config().default_call_conv,
+ call_conv: module.target_config().default_call_conv,
params: vec![AbiParam::new(pointer_type)],
returns: vec![AbiParam::new(pointer_type)],
},
)
.unwrap();
- let mut trampoline = Function::with_name_signature(ExternalName::default(), sig.clone());
+ cx.cached_context.clear();
+ let trampoline = &mut cx.cached_context.func;
+ trampoline.signature = sig.clone();
+
let mut builder_ctx = FunctionBuilderContext::new();
- let mut trampoline_builder = FunctionBuilder::new(&mut trampoline, &mut builder_ctx);
+ let mut trampoline_builder = FunctionBuilder::new(trampoline, &mut builder_ctx);
- let jit_fn = cx.module.declare_func_in_func(jit_fn, trampoline_builder.func);
+ let jit_fn = module.declare_func_in_func(jit_fn, trampoline_builder.func);
let sig_ref = trampoline_builder.func.import_signature(sig);
let entry_block = trampoline_builder.create_block();
let ret_vals = trampoline_builder.func.dfg.inst_results(call_inst).to_vec();
trampoline_builder.ins().return_(&ret_vals);
- cx.module
+ module
.define_function(
func_id,
- &mut Context::for_function(trampoline),
+ &mut cx.cached_context,
&mut NullTrapSink {},
&mut NullStackMapSink {},
)
-//! Drivers are responsible for calling [`codegen_mono_item`] and performing any further actions
-//! like JIT executing or writing object files.
+//! Drivers are responsible for calling [`codegen_fn`] or [`codegen_static`] for each mono item and
+//! performing any further actions like JIT executing or writing object files.
+//!
+//! [`codegen_fn`]: crate::base::codegen_fn
+//! [`codegen_static`]: crate::constant::codegen_static
-use std::any::Any;
-
-use rustc_middle::middle::cstore::EncodedMetadata;
use rustc_middle::mir::mono::{Linkage as RLinkage, MonoItem, Visibility};
use crate::prelude::*;
-use crate::CodegenMode;
-mod aot;
+pub(crate) mod aot;
#[cfg(feature = "jit")]
-mod jit;
-
-pub(crate) fn codegen_crate(
- tcx: TyCtxt<'_>,
- metadata: EncodedMetadata,
- need_metadata_module: bool,
- backend_config: crate::BackendConfig,
-) -> Box<dyn Any> {
- tcx.sess.abort_if_errors();
-
- match backend_config.codegen_mode {
- CodegenMode::Aot => aot::run_aot(tcx, backend_config, metadata, need_metadata_module),
- CodegenMode::Jit | CodegenMode::JitLazy => {
- let is_executable =
- tcx.sess.crate_types().contains(&rustc_session::config::CrateType::Executable);
- if !is_executable {
- tcx.sess.fatal("can't jit non-executable crate");
- }
-
- #[cfg(feature = "jit")]
- let _: ! = jit::run_jit(tcx, backend_config);
-
- #[cfg(not(feature = "jit"))]
- tcx.sess.fatal("jit support was disabled when compiling rustc_codegen_cranelift");
- }
- }
-}
+pub(crate) mod jit;
fn predefine_mono_items<'tcx>(
- cx: &mut crate::CodegenCx<'_, 'tcx>,
+ tcx: TyCtxt<'tcx>,
+ module: &mut dyn Module,
mono_items: &[(MonoItem<'tcx>, (RLinkage, Visibility))],
) {
- cx.tcx.sess.time("predefine functions", || {
- let is_compiler_builtins = cx.tcx.is_compiler_builtins(LOCAL_CRATE);
+ tcx.sess.time("predefine functions", || {
+ let is_compiler_builtins = tcx.is_compiler_builtins(LOCAL_CRATE);
for &(mono_item, (linkage, visibility)) in mono_items {
match mono_item {
MonoItem::Fn(instance) => {
- let name = cx.tcx.symbol_name(instance).name.to_string();
+ let name = tcx.symbol_name(instance).name;
let _inst_guard = crate::PrintOnPanic(|| format!("{:?} {}", instance, name));
- let sig = get_function_sig(cx.tcx, cx.module.isa().triple(), instance);
+ let sig = get_function_sig(tcx, module.isa().triple(), instance);
let linkage = crate::linkage::get_clif_linkage(
mono_item,
linkage,
visibility,
is_compiler_builtins,
);
- cx.module.declare_function(&name, linkage, &sig).unwrap();
+ module.declare_function(name, linkage, &sig).unwrap();
}
MonoItem::Static(_) | MonoItem::GlobalAsm(_) => {}
}
});
}
-fn time<R>(tcx: TyCtxt<'_>, name: &'static str, f: impl FnOnce() -> R) -> R {
- if std::env::var("CG_CLIF_DISPLAY_CG_TIME").as_ref().map(|val| &**val) == Ok("1") {
+fn time<R>(tcx: TyCtxt<'_>, display: bool, name: &'static str, f: impl FnOnce() -> R) -> R {
+ if display {
println!("[{:<30}: {}] start", tcx.crate_name(LOCAL_CRATE), name);
let before = std::time::Instant::now();
let res = tcx.sess.time(name, f);
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())
+ {
+ assert_eq!(operands.len(), 4);
+ let (leaf, eax_place) = match operands[0] {
+ InlineAsmOperand::InOut { reg, late: true, ref in_value, out_place } => {
+ let reg = expect_reg(reg);
+ assert_eq!(reg, InlineAsmReg::X86(X86InlineAsmReg::ax));
+ (
+ crate::base::codegen_operand(fx, in_value).load_scalar(fx),
+ crate::base::codegen_place(fx, out_place.unwrap()),
+ )
+ }
+ _ => unreachable!(),
+ };
+ let ebx_place = match operands[1] {
+ InlineAsmOperand::Out { reg, late: true, place } => {
+ let reg = expect_reg(reg);
+ assert_eq!(reg, InlineAsmReg::X86(X86InlineAsmReg::si));
+ crate::base::codegen_place(fx, place.unwrap())
+ }
+ _ => unreachable!(),
+ };
+ let (sub_leaf, ecx_place) = match operands[2] {
+ InlineAsmOperand::InOut { reg, late: true, ref in_value, out_place } => {
+ let reg = expect_reg(reg);
+ assert_eq!(reg, InlineAsmReg::X86(X86InlineAsmReg::cx));
+ (
+ crate::base::codegen_operand(fx, in_value).load_scalar(fx),
+ crate::base::codegen_place(fx, out_place.unwrap()),
+ )
+ }
+ _ => unreachable!(),
+ };
+ let edx_place = match operands[3] {
+ InlineAsmOperand::Out { reg, late: true, place } => {
+ let reg = expect_reg(reg);
+ assert_eq!(reg, InlineAsmReg::X86(X86InlineAsmReg::dx));
+ crate::base::codegen_place(fx, place.unwrap())
+ }
+ _ => unreachable!(),
+ };
+
+ let (eax, ebx, ecx, edx) = crate::intrinsics::codegen_cpuid_call(fx, leaf, sub_leaf);
+
+ eax_place.write_cvalue(fx, CValue::by_val(eax, fx.layout_of(fx.tcx.types.u32)));
+ ebx_place.write_cvalue(fx, CValue::by_val(ebx, fx.layout_of(fx.tcx.types.u32)));
+ ecx_place.write_cvalue(fx, CValue::by_val(ecx, fx.layout_of(fx.tcx.types.u32)));
+ edx_place.write_cvalue(fx, CValue::by_val(edx, fx.layout_of(fx.tcx.types.u32)));
+ return;
+ } else if fx.tcx.symbol_name(fx.instance).name.starts_with("___chkstk") {
+ // ___chkstk, ___chkstk_ms and __alloca are only used on Windows
+ crate::trap::trap_unimplemented(fx, "Stack probes are not supported");
+ } else if fx.tcx.symbol_name(fx.instance).name == "__alloca" {
+ crate::trap::trap_unimplemented(fx, "Alloca is not supported");
}
let mut slot_size = Size::from_bytes(0);
let inline_asm_index = fx.inline_asm_index;
fx.inline_asm_index += 1;
- let asm_name =
- format!("{}__inline_asm_{}", fx.tcx.symbol_name(fx.instance).name, inline_asm_index);
+ let asm_name = format!("{}__inline_asm_{}", fx.symbol_name, inline_asm_index);
let generated_asm = generate_asm_wrapper(
&asm_name,
}
let inline_asm_func = fx
- .cx
.module
.declare_function(
asm_name,
},
)
.unwrap();
- let inline_asm_func = fx.cx.module.declare_func_in_func(inline_asm_func, &mut fx.bcx.func);
+ let inline_asm_func = fx.module.declare_func_in_func(inline_asm_func, &mut fx.bcx.func);
if fx.clif_comments.enabled() {
fx.add_comment(inline_asm_func, asm_name);
}
pub(crate) fn codegen_cpuid_call<'tcx>(
fx: &mut FunctionCx<'_, '_, 'tcx>,
leaf: Value,
- _subleaf: Value,
+ _sub_leaf: Value,
) -> (Value, Value, Value, Value) {
let leaf_0 = fx.bcx.create_block();
let leaf_1 = fx.bcx.create_block();
};
// Used by `_mm_movemask_epi8` and `_mm256_movemask_epi8`
- llvm.x86.sse2.pmovmskb.128 | llvm.x86.avx2.pmovmskb | llvm.x86.sse2.movmsk.pd, (c a) {
+ "llvm.x86.sse2.pmovmskb.128" | "llvm.x86.avx2.pmovmskb" | "llvm.x86.sse2.movmsk.pd", (c a) {
let (lane_count, lane_ty) = a.layout().ty.simd_size_and_type(fx.tcx);
let lane_ty = fx.clif_type(lane_ty).unwrap();
assert!(lane_count <= 32);
let res = CValue::by_val(res, fx.layout_of(fx.tcx.types.i32));
ret.write_cvalue(fx, res);
};
- llvm.x86.sse2.cmp.ps | llvm.x86.sse2.cmp.pd, (c x, c y, o kind) {
+ "llvm.x86.sse2.cmp.ps" | "llvm.x86.sse2.cmp.pd", (c x, c y, o kind) {
let kind_const = crate::constant::mir_operand_get_const_val(fx, kind).expect("llvm.x86.sse2.cmp.* kind not const");
let flt_cc = match kind_const.try_to_bits(Size::from_bytes(1)).unwrap_or_else(|| panic!("kind not scalar: {:?}", kind_const)) {
0 => FloatCC::Equal,
bool_to_zero_or_max_uint(fx, res_lane_layout, res_lane)
});
};
- llvm.x86.sse2.psrli.d, (c a, o imm8) {
+ "llvm.x86.sse2.psrli.d", (c a, o imm8) {
let imm8 = crate::constant::mir_operand_get_const_val(fx, imm8).expect("llvm.x86.sse2.psrli.d imm8 not const");
simd_for_each_lane(fx, a, ret, |fx, _lane_layout, res_lane_layout, lane| {
let res_lane = match imm8.try_to_bits(Size::from_bytes(4)).unwrap_or_else(|| panic!("imm8 not scalar: {:?}", imm8)) {
CValue::by_val(res_lane, res_lane_layout)
});
};
- llvm.x86.sse2.pslli.d, (c a, o imm8) {
+ "llvm.x86.sse2.pslli.d", (c a, o imm8) {
let imm8 = crate::constant::mir_operand_get_const_val(fx, imm8).expect("llvm.x86.sse2.psrli.d imm8 not const");
simd_for_each_lane(fx, a, ret, |fx, _lane_layout, res_lane_layout, lane| {
let res_lane = match imm8.try_to_bits(Size::from_bytes(4)).unwrap_or_else(|| panic!("imm8 not scalar: {:?}", imm8)) {
CValue::by_val(res_lane, res_lane_layout)
});
};
- llvm.x86.sse2.storeu.dq, (v mem_addr, c a) {
+ "llvm.x86.sse2.storeu.dq", (v mem_addr, c a) {
// FIXME correctly handle the unalignment
let dest = CPlace::for_ptr(Pointer::new(mem_addr), a.layout());
dest.write_cvalue(fx, a);
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 crate::prelude::*;
use cranelift_codegen::ir::AtomicRmwOp;
-use rustc_middle::ty::print::with_no_trimmed_paths;
macro intrinsic_pat {
(_) => {
_
},
($name:ident) => {
- stringify!($name)
+ sym::$name
+ },
+ (kw.$name:ident) => {
+ kw::$name
},
($name:literal) => {
- stringify!($name)
+ $name
},
- ($x:ident . $($xs:tt).*) => {
- concat!(stringify!($x), ".", intrinsic_pat!($($xs).*))
- }
}
macro intrinsic_arg {
)*) => {
match $intrinsic {
$(
- stringify!($name) => {
+ sym::$name => {
assert!($substs.is_noop());
if let [$(ref $arg),*] = *$args {
let ($($arg,)*) = (
let def_id = instance.def_id();
let substs = instance.substs;
- let intrinsic = fx.tcx.item_name(def_id).as_str();
- let intrinsic = &intrinsic[..];
+ let intrinsic = fx.tcx.item_name(def_id);
let ret = match destination {
Some((place, _)) => place,
None => {
// Insert non returning intrinsics here
match intrinsic {
- "abort" => {
+ sym::abort => {
trap_abort(fx, "Called intrinsic::abort.");
}
- "transmute" => {
+ sym::transmute => {
crate::base::codegen_panic(fx, "Transmuting to uninhabited type.", span);
}
_ => unimplemented!("unsupported instrinsic {}", intrinsic),
}
};
- if intrinsic.starts_with("simd_") {
+ if intrinsic.as_str().starts_with("simd_") {
self::simd::codegen_simd_intrinsic_call(fx, instance, args, ret, span);
let ret_block = fx.get_block(destination.expect("SIMD intrinsics don't diverge").1);
fx.bcx.ins().jump(ret_block, &[]);
sinf64(flt) -> f64 => sin,
cosf32(flt) -> f32 => cosf,
cosf64(flt) -> f64 => cos,
- tanf32(flt) -> f32 => tanf,
- tanf64(flt) -> f64 => tan,
}
intrinsic_match! {
count
};
- if intrinsic.contains("nonoverlapping") {
+ if intrinsic == sym::copy_nonoverlapping {
// FIXME emit_small_memcpy
- fx.bcx.call_memcpy(fx.cx.module.target_config(), dst, src, byte_amount);
+ fx.bcx.call_memcpy(fx.module.target_config(), dst, src, byte_amount);
} else {
// FIXME emit_small_memmove
- fx.bcx.call_memmove(fx.cx.module.target_config(), dst, src, byte_amount);
+ fx.bcx.call_memmove(fx.module.target_config(), dst, src, byte_amount);
}
};
// NOTE: the volatile variants have src and dst swapped
};
// FIXME make the copy actually volatile when using emit_small_mem{cpy,move}
- if intrinsic.contains("nonoverlapping") {
+ if intrinsic == sym::volatile_copy_nonoverlapping_memory {
// FIXME emit_small_memcpy
- fx.bcx.call_memcpy(fx.cx.module.target_config(), dst, src, byte_amount);
+ fx.bcx.call_memcpy(fx.module.target_config(), dst, src, byte_amount);
} else {
// FIXME emit_small_memmove
- fx.bcx.call_memmove(fx.cx.module.target_config(), dst, src, byte_amount);
+ fx.bcx.call_memmove(fx.module.target_config(), dst, src, byte_amount);
}
};
size_of_val, <T> (c ptr) {
ret.write_cvalue(fx, CValue::by_val(align, usize_layout));
};
- _ if intrinsic.starts_with("unchecked_") || intrinsic == "exact_div", (c x, c y) {
+ unchecked_add | unchecked_sub | unchecked_div | exact_div | unchecked_rem
+ | unchecked_shl | unchecked_shr, (c x, c y) {
// FIXME trap on overflow
let bin_op = match intrinsic {
- "unchecked_add" => BinOp::Add,
- "unchecked_sub" => BinOp::Sub,
- "unchecked_div" | "exact_div" => BinOp::Div,
- "unchecked_rem" => BinOp::Rem,
- "unchecked_shl" => BinOp::Shl,
- "unchecked_shr" => BinOp::Shr,
- _ => unreachable!("intrinsic {}", intrinsic),
+ sym::unchecked_add => BinOp::Add,
+ sym::unchecked_sub => BinOp::Sub,
+ sym::unchecked_div | sym::exact_div => BinOp::Div,
+ sym::unchecked_rem => BinOp::Rem,
+ sym::unchecked_shl => BinOp::Shl,
+ sym::unchecked_shr => BinOp::Shr,
+ _ => unreachable!(),
};
let res = crate::num::codegen_int_binop(fx, bin_op, x, y);
ret.write_cvalue(fx, res);
};
- _ if intrinsic.ends_with("_with_overflow"), (c x, c y) {
+ add_with_overflow | sub_with_overflow | mul_with_overflow, (c x, c y) {
assert_eq!(x.layout().ty, y.layout().ty);
let bin_op = match intrinsic {
- "add_with_overflow" => BinOp::Add,
- "sub_with_overflow" => BinOp::Sub,
- "mul_with_overflow" => BinOp::Mul,
- _ => unreachable!("intrinsic {}", intrinsic),
+ sym::add_with_overflow => BinOp::Add,
+ sym::sub_with_overflow => BinOp::Sub,
+ sym::mul_with_overflow => BinOp::Mul,
+ _ => unreachable!(),
};
let res = crate::num::codegen_checked_int_binop(
);
ret.write_cvalue(fx, res);
};
- _ if intrinsic.starts_with("saturating_"), <T> (c lhs, c rhs) {
+ saturating_add | saturating_sub, <T> (c lhs, c rhs) {
assert_eq!(lhs.layout().ty, rhs.layout().ty);
let bin_op = match intrinsic {
- "saturating_add" => BinOp::Add,
- "saturating_sub" => BinOp::Sub,
- _ => unreachable!("intrinsic {}", intrinsic),
+ sym::saturating_add => BinOp::Add,
+ sym::saturating_sub => BinOp::Sub,
+ _ => unreachable!(),
};
let signed = type_sign(T);
let (min, max) = type_min_max_value(&mut fx.bcx, clif_ty, signed);
let val = match (intrinsic, signed) {
- ("saturating_add", false) => fx.bcx.ins().select(has_overflow, max, val),
- ("saturating_sub", false) => fx.bcx.ins().select(has_overflow, min, val),
- ("saturating_add", true) => {
+ (sym::saturating_add, false) => fx.bcx.ins().select(has_overflow, max, val),
+ (sym::saturating_sub, false) => fx.bcx.ins().select(has_overflow, min, val),
+ (sym::saturating_add, true) => {
let rhs = rhs.load_scalar(fx);
let rhs_ge_zero = fx.bcx.ins().icmp_imm(IntCC::SignedGreaterThanOrEqual, rhs, 0);
let sat_val = fx.bcx.ins().select(rhs_ge_zero, max, min);
fx.bcx.ins().select(has_overflow, sat_val, val)
}
- ("saturating_sub", true) => {
+ (sym::saturating_sub, true) => {
let rhs = rhs.load_scalar(fx);
let rhs_ge_zero = fx.bcx.ins().icmp_imm(IntCC::SignedGreaterThanOrEqual, rhs, 0);
let sat_val = fx.bcx.ins().select(rhs_ge_zero, min, max);
};
rotate_left, <T>(v x, v y) {
let layout = fx.layout_of(T);
+ let y = if fx.bcx.func.dfg.value_type(y) == types::I128 {
+ fx.bcx.ins().ireduce(types::I64, y)
+ } else {
+ y
+ };
let res = fx.bcx.ins().rotl(x, y);
ret.write_cvalue(fx, CValue::by_val(res, layout));
};
rotate_right, <T>(v x, v y) {
let layout = fx.layout_of(T);
+ let y = if fx.bcx.func.dfg.value_type(y) == types::I128 {
+ fx.bcx.ins().ireduce(types::I64, y)
+ } else {
+ y
+ };
let res = fx.bcx.ins().rotr(x, y);
ret.write_cvalue(fx, CValue::by_val(res, layout));
};
let dst_ptr = dst.load_scalar(fx);
// FIXME make the memset actually volatile when switching to emit_small_memset
// FIXME use emit_small_memset
- fx.bcx.call_memset(fx.cx.module.target_config(), dst_ptr, val, count);
+ fx.bcx.call_memset(fx.module.target_config(), dst_ptr, val, count);
};
ctlz | ctlz_nonzero, <T> (v arg) {
// FIXME trap on `ctlz_nonzero` with zero arg.
return;
}
- if intrinsic == "assert_zero_valid" && !layout.might_permit_raw_init(fx, /*zero:*/ true).unwrap() {
+ if intrinsic == sym::assert_zero_valid && !layout.might_permit_raw_init(fx, /*zero:*/ true).unwrap() {
with_no_trimmed_paths(|| crate::base::codegen_panic(
fx,
&format!("attempted to zero-initialize type `{}`, which is invalid", T),
return;
}
- if intrinsic == "assert_uninit_valid" && !layout.might_permit_raw_init(fx, /*zero:*/ false).unwrap() {
+ if intrinsic == sym::assert_uninit_valid && !layout.might_permit_raw_init(fx, /*zero:*/ false).unwrap() {
with_no_trimmed_paths(|| crate::base::codegen_panic(
fx,
&format!("attempted to leave type `{}` uninitialized, which is invalid", T),
volatile_load | unaligned_volatile_load, (c ptr) {
// Cranelift treats loads as volatile by default
- // FIXME ignore during stack2reg optimization
// FIXME correctly handle unaligned_volatile_load
let inner_layout =
fx.layout_of(ptr.layout().ty.builtin_deref(true).unwrap().ty);
};
volatile_store | unaligned_volatile_store, (v ptr, c val) {
// Cranelift treats stores as volatile by default
- // FIXME ignore during stack2reg optimization
// FIXME correctly handle unaligned_volatile_store
let dest = CPlace::for_ptr(Pointer::new(ptr), val.layout());
dest.write_cvalue(fx, val);
ret.write_cvalue(fx, caller_location);
};
- _ if intrinsic.starts_with("atomic_fence"), () {
+ _ if intrinsic.as_str().starts_with("atomic_fence"), () {
fx.bcx.ins().fence();
};
- _ if intrinsic.starts_with("atomic_singlethreadfence"), () {
+ _ if intrinsic.as_str().starts_with("atomic_singlethreadfence"), () {
// FIXME use a compiler fence once Cranelift supports it
fx.bcx.ins().fence();
};
- _ if intrinsic.starts_with("atomic_load"), <T> (v ptr) {
+ _ if intrinsic.as_str().starts_with("atomic_load"), <T> (v ptr) {
validate_atomic_type!(fx, intrinsic, span, T);
let ty = fx.clif_type(T).unwrap();
let val = CValue::by_val(val, fx.layout_of(T));
ret.write_cvalue(fx, val);
};
- _ if intrinsic.starts_with("atomic_store"), (v ptr, c val) {
+ _ if intrinsic.as_str().starts_with("atomic_store"), (v ptr, c val) {
validate_atomic_type!(fx, intrinsic, span, val.layout().ty);
let val = val.load_scalar(fx);
fx.bcx.ins().atomic_store(MemFlags::trusted(), val, ptr);
};
- _ if intrinsic.starts_with("atomic_xchg"), (v ptr, c new) {
+ _ if intrinsic.as_str().starts_with("atomic_xchg"), (v ptr, c new) {
let layout = new.layout();
validate_atomic_type!(fx, intrinsic, span, layout.ty);
let ty = fx.clif_type(layout.ty).unwrap();
let old = CValue::by_val(old, layout);
ret.write_cvalue(fx, old);
};
- _ if intrinsic.starts_with("atomic_cxchg"), (v ptr, c test_old, c new) { // both atomic_cxchg_* and atomic_cxchgweak_*
+ _ if intrinsic.as_str().starts_with("atomic_cxchg"), (v ptr, c test_old, c new) { // both atomic_cxchg_* and atomic_cxchgweak_*
let layout = new.layout();
validate_atomic_type!(fx, intrinsic, span, layout.ty);
ret.write_cvalue(fx, ret_val)
};
- _ if intrinsic.starts_with("atomic_xadd"), (v ptr, c amount) {
+ _ if intrinsic.as_str().starts_with("atomic_xadd"), (v ptr, c amount) {
let layout = amount.layout();
validate_atomic_type!(fx, intrinsic, span, layout.ty);
let ty = fx.clif_type(layout.ty).unwrap();
let old = CValue::by_val(old, layout);
ret.write_cvalue(fx, old);
};
- _ if intrinsic.starts_with("atomic_xsub"), (v ptr, c amount) {
+ _ if intrinsic.as_str().starts_with("atomic_xsub"), (v ptr, c amount) {
let layout = amount.layout();
validate_atomic_type!(fx, intrinsic, span, layout.ty);
let ty = fx.clif_type(layout.ty).unwrap();
let old = CValue::by_val(old, layout);
ret.write_cvalue(fx, old);
};
- _ if intrinsic.starts_with("atomic_and"), (v ptr, c src) {
+ _ if intrinsic.as_str().starts_with("atomic_and"), (v ptr, c src) {
let layout = src.layout();
validate_atomic_type!(fx, intrinsic, span, layout.ty);
let ty = fx.clif_type(layout.ty).unwrap();
let old = CValue::by_val(old, layout);
ret.write_cvalue(fx, old);
};
- _ if intrinsic.starts_with("atomic_or"), (v ptr, c src) {
+ _ if intrinsic.as_str().starts_with("atomic_or"), (v ptr, c src) {
let layout = src.layout();
validate_atomic_type!(fx, intrinsic, span, layout.ty);
let ty = fx.clif_type(layout.ty).unwrap();
let old = CValue::by_val(old, layout);
ret.write_cvalue(fx, old);
};
- _ if intrinsic.starts_with("atomic_xor"), (v ptr, c src) {
+ _ if intrinsic.as_str().starts_with("atomic_xor"), (v ptr, c src) {
let layout = src.layout();
validate_atomic_type!(fx, intrinsic, span, layout.ty);
let ty = fx.clif_type(layout.ty).unwrap();
};
// FIXME https://github.com/bytecodealliance/wasmtime/issues/2647
- _ if intrinsic.starts_with("atomic_nand"), (v ptr, c src) {
+ _ if intrinsic.as_str().starts_with("atomic_nand"), (v ptr, c src) {
let layout = src.layout();
validate_atomic_type!(fx, intrinsic, span, layout.ty);
let ty = fx.clif_type(layout.ty).unwrap();
let old = CValue::by_val(old, layout);
ret.write_cvalue(fx, old);
};
- _ if intrinsic.starts_with("atomic_max"), (v ptr, c src) {
+ _ if intrinsic.as_str().starts_with("atomic_max"), (v ptr, c src) {
let layout = src.layout();
validate_atomic_type!(fx, intrinsic, span, layout.ty);
let ty = fx.clif_type(layout.ty).unwrap();
let old = CValue::by_val(old, layout);
ret.write_cvalue(fx, old);
};
- _ if intrinsic.starts_with("atomic_umax"), (v ptr, c src) {
+ _ if intrinsic.as_str().starts_with("atomic_umax"), (v ptr, c src) {
let layout = src.layout();
validate_atomic_type!(fx, intrinsic, span, layout.ty);
let ty = fx.clif_type(layout.ty).unwrap();
let old = CValue::by_val(old, layout);
ret.write_cvalue(fx, old);
};
- _ if intrinsic.starts_with("atomic_min"), (v ptr, c src) {
+ _ if intrinsic.as_str().starts_with("atomic_min"), (v ptr, c src) {
let layout = src.layout();
validate_atomic_type!(fx, intrinsic, span, layout.ty);
let ty = fx.clif_type(layout.ty).unwrap();
let old = CValue::by_val(old, layout);
ret.write_cvalue(fx, old);
};
- _ if intrinsic.starts_with("atomic_umin"), (v ptr, c src) {
+ _ if intrinsic.as_str().starts_with("atomic_umin"), (v ptr, c src) {
let layout = src.layout();
validate_atomic_type!(fx, intrinsic, span, layout.ty);
let ty = fx.clif_type(layout.ty).unwrap();
ret.write_cvalue(fx, val);
};
- try, (v f, v data, v _catch_fn) {
+ kw.Try, (v f, v data, v _catch_fn) {
// FIXME once unwinding is supported, change this to actually catch panics
let f_sig = fx.bcx.func.import_signature(Signature {
call_conv: CallConv::triple_default(fx.triple()),
fadd_fast | fsub_fast | fmul_fast | fdiv_fast | frem_fast, (c x, c y) {
let res = crate::num::codegen_float_binop(fx, match intrinsic {
- "fadd_fast" => BinOp::Add,
- "fsub_fast" => BinOp::Sub,
- "fmul_fast" => BinOp::Mul,
- "fdiv_fast" => BinOp::Div,
- "frem_fast" => BinOp::Rem,
+ sym::fadd_fast => BinOp::Add,
+ sym::fsub_fast => BinOp::Sub,
+ sym::fmul_fast => BinOp::Mul,
+ sym::fdiv_fast => BinOp::Div,
+ sym::frem_fast => BinOp::Rem,
_ => unreachable!(),
}, x, y);
ret.write_cvalue(fx, res);
let def_id = instance.def_id();
let substs = instance.substs;
- let intrinsic = fx.tcx.item_name(def_id).as_str();
- let intrinsic = &intrinsic[..];
+ let intrinsic = fx.tcx.item_name(def_id);
intrinsic_match! {
fx, intrinsic, substs, args,
};
// simd_shuffle32<T, U>(x: T, y: T, idx: [u32; 32]) -> U
- _ if intrinsic.starts_with("simd_shuffle"), (c x, c y, o idx) {
+ _ if intrinsic.as_str().starts_with("simd_shuffle"), (c x, c y, o idx) {
validate_simd_type!(fx, intrinsic, span, x.layout().ty);
- let n: u16 = intrinsic["simd_shuffle".len()..].parse().unwrap();
+ let n: u16 = intrinsic.as_str()["simd_shuffle".len()..].parse().unwrap();
assert_eq!(x.layout(), y.layout());
let layout = x.layout();
-#![feature(rustc_private, decl_macro, never_type, hash_drain_filter)]
+#![feature(rustc_private, decl_macro, never_type, hash_drain_filter, vec_into_raw_parts)]
#![warn(rust_2018_idioms)]
#![warn(unused_lifetimes)]
#![warn(unreachable_pub)]
extern crate rustc_driver;
use std::any::Any;
-use std::str::FromStr;
use rustc_codegen_ssa::traits::CodegenBackend;
use rustc_codegen_ssa::CodegenResults;
use rustc_session::config::OutputFilenames;
use rustc_session::Session;
+use cranelift_codegen::isa::TargetIsa;
use cranelift_codegen::settings::{self, Configurable};
-use crate::constant::ConstantCx;
+pub use crate::config::*;
use crate::prelude::*;
mod abi;
mod codegen_i128;
mod common;
mod compiler_builtins;
+mod config;
mod constant;
mod debuginfo;
mod discriminant;
pub(crate) use rustc_index::vec::Idx;
- pub(crate) use cranelift_codegen::entity::EntitySet;
pub(crate) use cranelift_codegen::ir::condcodes::{FloatCC, IntCC};
pub(crate) use cranelift_codegen::ir::function::Function;
pub(crate) use cranelift_codegen::ir::types;
}
}
-struct CodegenCx<'m, 'tcx: 'm> {
+/// The codegen context holds any information shared between the codegen of individual functions
+/// inside a single codegen unit with the exception of the Cranelift [`Module`](cranelift_module::Module).
+struct CodegenCx<'tcx> {
tcx: TyCtxt<'tcx>,
- module: &'m mut dyn Module,
global_asm: String,
- constants_cx: ConstantCx,
cached_context: Context,
- vtables: FxHashMap<(Ty<'tcx>, Option<ty::PolyExistentialTraitRef<'tcx>>), DataId>,
debug_context: Option<DebugContext<'tcx>>,
- unwind_context: UnwindContext<'tcx>,
+ unwind_context: UnwindContext,
}
-impl<'m, 'tcx> CodegenCx<'m, 'tcx> {
+impl<'tcx> CodegenCx<'tcx> {
fn new(
tcx: TyCtxt<'tcx>,
backend_config: BackendConfig,
- module: &'m mut dyn Module,
+ isa: &dyn TargetIsa,
debug_info: bool,
) -> Self {
- let unwind_context = UnwindContext::new(
- tcx,
- module.isa(),
- matches!(backend_config.codegen_mode, CodegenMode::Aot),
- );
- let debug_context =
- if debug_info { Some(DebugContext::new(tcx, module.isa())) } else { None };
+ assert_eq!(pointer_ty(tcx), isa.pointer_type());
+
+ let unwind_context =
+ UnwindContext::new(tcx, isa, matches!(backend_config.codegen_mode, CodegenMode::Aot));
+ let debug_context = if debug_info { Some(DebugContext::new(tcx, isa)) } else { None };
CodegenCx {
tcx,
- module,
global_asm: String::new(),
- constants_cx: ConstantCx::default(),
cached_context: Context::new(),
- vtables: FxHashMap::default(),
debug_context,
unwind_context,
}
}
-
- fn finalize(self) -> (String, Option<DebugContext<'tcx>>, UnwindContext<'tcx>) {
- self.constants_cx.finalize(self.tcx, self.module);
- (self.global_asm, self.debug_context, self.unwind_context)
- }
-}
-
-#[derive(Copy, Clone, Debug)]
-pub enum CodegenMode {
- Aot,
- Jit,
- JitLazy,
-}
-
-impl Default for CodegenMode {
- fn default() -> Self {
- CodegenMode::Aot
- }
-}
-
-impl FromStr for CodegenMode {
- type Err = String;
-
- fn from_str(s: &str) -> Result<Self, Self::Err> {
- match s {
- "aot" => Ok(CodegenMode::Aot),
- "jit" => Ok(CodegenMode::Jit),
- "jit-lazy" => Ok(CodegenMode::JitLazy),
- _ => Err(format!("Unknown codegen mode `{}`", s)),
- }
- }
-}
-
-#[derive(Copy, Clone, Debug, Default)]
-pub struct BackendConfig {
- pub codegen_mode: CodegenMode,
-}
-
-impl BackendConfig {
- fn from_opts(opts: &[String]) -> Result<Self, String> {
- let mut config = BackendConfig::default();
- for opt in opts {
- if let Some((name, value)) = opt.split_once('=') {
- match name {
- "mode" => config.codegen_mode = value.parse()?,
- _ => return Err(format!("Unknown option `{}`", name)),
- }
- } else {
- return Err(format!("Invalid option `{}`", opt));
- }
- }
- Ok(config)
- }
}
pub struct CraneliftCodegenBackend {
metadata: EncodedMetadata,
need_metadata_module: bool,
) -> Box<dyn Any> {
- let config = if let Some(config) = self.config {
+ tcx.sess.abort_if_errors();
+ let config = if let Some(config) = self.config.clone() {
config
} else {
BackendConfig::from_opts(&tcx.sess.opts.cg.llvm_args)
.unwrap_or_else(|err| tcx.sess.fatal(&err))
};
- driver::codegen_crate(tcx, metadata, need_metadata_module, config)
+ match config.codegen_mode {
+ CodegenMode::Aot => driver::aot::run_aot(tcx, config, metadata, need_metadata_module),
+ CodegenMode::Jit | CodegenMode::JitLazy => {
+ #[cfg(feature = "jit")]
+ let _: ! = driver::jit::run_jit(tcx, config);
+
+ #[cfg(not(feature = "jit"))]
+ tcx.sess.fatal("jit support was disabled when compiling rustc_codegen_cranelift");
+ }
+ }
}
fn join_codegen(
sess.target.llvm_target.parse().unwrap()
}
-fn build_isa(sess: &Session) -> Box<dyn isa::TargetIsa + 'static> {
+fn build_isa(sess: &Session, backend_config: &BackendConfig) -> Box<dyn isa::TargetIsa + 'static> {
use target_lexicon::BinaryFormat;
let target_triple = crate::target_triple(sess);
let mut flags_builder = settings::builder();
flags_builder.enable("is_pic").unwrap();
flags_builder.set("enable_probestack", "false").unwrap(); // __cranelift_probestack is not provided
- let enable_verifier =
- cfg!(debug_assertions) || std::env::var("CG_CLIF_ENABLE_VERIFIER").is_ok();
- flags_builder.set("enable_verifier", if enable_verifier { "true" } else { "false" }).unwrap();
+ let enable_verifier = if backend_config.enable_verifier { "true" } else { "false" };
+ flags_builder.set("enable_verifier", enable_verifier).unwrap();
let tls_model = match target_triple.binary_format {
BinaryFormat::Elf => "elf_gd",
let flags = settings::Flags::new(flags_builder);
let variant = cranelift_codegen::isa::BackendVariant::MachInst;
- let mut isa_builder = cranelift_codegen::isa::lookup_variant(target_triple, variant).unwrap();
- // Don't use "haswell", as it implies `has_lzcnt`.macOS CI is still at Ivy Bridge EP, so `lzcnt`
- // is interpreted as `bsr`.
- isa_builder.enable("nehalem").unwrap();
+
+ let isa_builder = match sess.opts.cg.target_cpu.as_deref() {
+ Some("native") => {
+ let builder = cranelift_native::builder_with_options(variant, true).unwrap();
+ builder
+ }
+ Some(value) => {
+ 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();
+ // 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)
}
(RLinkage::External, Visibility::Default) => Linkage::Export,
(RLinkage::Internal, Visibility::Default) => Linkage::Local,
(RLinkage::External, Visibility::Hidden) => Linkage::Hidden,
+ (RLinkage::WeakAny, Visibility::Default) => Linkage::Preemptible,
_ => panic!("{:?} = {:?} {:?}", mono_item, linkage, visibility),
}
}
use cranelift_codegen::binemit::{NullStackMapSink, NullTrapSink};
use rustc_hir::LangItem;
+use rustc_middle::ty::subst::GenericArg;
+use rustc_middle::ty::AssocKind;
use rustc_session::config::EntryFnType;
+use rustc_span::symbol::Ident;
use crate::prelude::*;
pub(crate) fn maybe_create_entry_wrapper(
tcx: TyCtxt<'_>,
module: &mut impl Module,
- unwind_context: &mut UnwindContext<'_>,
+ unwind_context: &mut UnwindContext,
+ is_jit: bool,
) {
- let (main_def_id, use_start_lang_item) = match tcx.entry_fn(LOCAL_CRATE) {
+ let (main_def_id, is_main_fn) = match tcx.entry_fn(LOCAL_CRATE) {
Some((def_id, entry_ty)) => (
def_id,
match entry_ty {
};
let instance = Instance::mono(tcx, main_def_id).polymorphize(tcx);
- if module.get_name(&*tcx.symbol_name(instance).name).is_none() {
+ if !is_jit && module.get_name(&*tcx.symbol_name(instance).name).is_none() {
return;
}
- create_entry_fn(tcx, module, unwind_context, main_def_id, use_start_lang_item);
+ create_entry_fn(tcx, module, unwind_context, main_def_id, is_jit, is_main_fn);
fn create_entry_fn(
tcx: TyCtxt<'_>,
m: &mut impl Module,
- unwind_context: &mut UnwindContext<'_>,
+ unwind_context: &mut UnwindContext,
rust_main_def_id: DefId,
- use_start_lang_item: bool,
+ ignore_lang_start_wrapper: bool,
+ is_main_fn: bool,
) {
let main_ret_ty = tcx.fn_sig(rust_main_def_id).output();
// Given that `main()` has no arguments,
let instance = Instance::mono(tcx, rust_main_def_id).polymorphize(tcx);
- let main_name = tcx.symbol_name(instance).name.to_string();
+ let main_name = tcx.symbol_name(instance).name;
let main_sig = get_function_sig(tcx, m.isa().triple(), instance);
- let main_func_id = m.declare_function(&main_name, Linkage::Import, &main_sig).unwrap();
+ let main_func_id = m.declare_function(main_name, Linkage::Import, &main_sig).unwrap();
let mut ctx = Context::new();
ctx.func = Function::with_name_signature(ExternalName::user(0, 0), cmain_sig);
let main_func_ref = m.declare_func_in_func(main_func_id, &mut bcx.func);
- let call_inst = if use_start_lang_item {
+ let result = if is_main_fn && ignore_lang_start_wrapper {
+ // regular main fn, but ignoring #[lang = "start"] as we are running in the jit
+ // FIXME set program arguments somehow
+ let call_inst = bcx.ins().call(main_func_ref, &[]);
+ let call_results = bcx.func.dfg.inst_results(call_inst).to_owned();
+
+ let termination_trait = tcx.require_lang_item(LangItem::Termination, None);
+ let report = tcx
+ .associated_items(termination_trait)
+ .find_by_name_and_kind(
+ tcx,
+ Ident::from_str("report"),
+ AssocKind::Fn,
+ termination_trait,
+ )
+ .unwrap();
+ let report = Instance::resolve(
+ tcx,
+ ParamEnv::reveal_all(),
+ report.def_id,
+ tcx.mk_substs([GenericArg::from(main_ret_ty)].iter()),
+ )
+ .unwrap()
+ .unwrap();
+
+ let report_name = tcx.symbol_name(report).name;
+ let report_sig = get_function_sig(tcx, m.isa().triple(), report);
+ let report_func_id =
+ m.declare_function(report_name, Linkage::Import, &report_sig).unwrap();
+ let report_func_ref = m.declare_func_in_func(report_func_id, &mut bcx.func);
+
+ // FIXME do proper abi handling instead of expecting the pass mode to be identical
+ // for returns and arguments.
+ let report_call_inst = bcx.ins().call(report_func_ref, &call_results);
+ let res = bcx.func.dfg.inst_results(report_call_inst)[0];
+ match m.target_config().pointer_type() {
+ types::I32 => res,
+ types::I64 => bcx.ins().sextend(types::I64, res),
+ _ => unimplemented!("16bit systems are not yet supported"),
+ }
+ } else if is_main_fn {
let start_def_id = tcx.require_lang_item(LangItem::Start, None);
let start_instance = Instance::resolve(
tcx,
let main_val = bcx.ins().func_addr(m.target_config().pointer_type(), main_func_ref);
let func_ref = m.declare_func_in_func(start_func_id, &mut bcx.func);
- bcx.ins().call(func_ref, &[main_val, arg_argc, arg_argv])
+ let call_inst = bcx.ins().call(func_ref, &[main_val, arg_argc, arg_argv]);
+ bcx.inst_results(call_inst)[0]
} else {
// using user-defined start fn
- bcx.ins().call(main_func_ref, &[arg_argc, arg_argv])
+ let call_inst = bcx.ins().call(main_func_ref, &[arg_argc, arg_argv]);
+ bcx.inst_results(call_inst)[0]
};
- let result = bcx.inst_results(call_inst)[0];
bcx.ins().return_(&[result]);
bcx.seal_all_blocks();
bcx.finalize();
use rustc_data_structures::owning_ref::OwningRef;
use rustc_data_structures::rustc_erase_owner;
use rustc_data_structures::sync::MetadataRef;
-use rustc_middle::middle::cstore::{EncodedMetadata, MetadataLoader};
+use rustc_middle::middle::cstore::MetadataLoader;
use rustc_middle::ty::TyCtxt;
-use rustc_session::config;
use rustc_target::spec::Target;
use crate::backend::WriteMetadata;
+/// The metadata loader used by cg_clif.
+///
+/// The metadata is stored in the same format as cg_llvm.
+///
+/// # Metadata location
+///
+/// <dl>
+/// <dt>rlib</dt>
+/// <dd>The metadata can be found in the `lib.rmeta` file inside of the ar archive.</dd>
+/// <dt>dylib</dt>
+/// <dd>The metadata can be found in the `.rustc` section of the shared library.</dd>
+/// </dl>
pub(crate) struct CraneliftMetadataLoader;
fn load_metadata_with(
}
// Adapted from https://github.com/rust-lang/rust/blob/da573206f87b5510de4b0ee1a9c044127e409bd3/src/librustc_codegen_llvm/base.rs#L47-L112
-pub(crate) fn write_metadata<P: WriteMetadata>(
- tcx: TyCtxt<'_>,
- product: &mut P,
-) -> EncodedMetadata {
+pub(crate) fn write_metadata<O: WriteMetadata>(tcx: TyCtxt<'_>, object: &mut O) {
use snap::write::FrameEncoder;
use std::io::Write;
- #[derive(PartialEq, Eq, PartialOrd, Ord)]
- enum MetadataKind {
- None,
- Uncompressed,
- Compressed,
- }
-
- let kind = tcx
- .sess
- .crate_types()
- .iter()
- .map(|ty| match *ty {
- config::CrateType::Executable
- | config::CrateType::Staticlib
- | config::CrateType::Cdylib => MetadataKind::None,
-
- config::CrateType::Rlib => MetadataKind::Uncompressed,
-
- config::CrateType::Dylib | config::CrateType::ProcMacro => MetadataKind::Compressed,
- })
- .max()
- .unwrap_or(MetadataKind::None);
-
- if kind == MetadataKind::None {
- return EncodedMetadata::new();
- }
-
let metadata = tcx.encode_metadata();
- if kind == MetadataKind::Uncompressed {
- return metadata;
- }
-
- assert!(kind == MetadataKind::Compressed);
let mut compressed = tcx.metadata_encoding_version();
FrameEncoder::new(&mut compressed).write_all(&metadata.raw_data).unwrap();
- product.add_rustc_section(
+ object.add_rustc_section(
rustc_middle::middle::exported_symbols::metadata_symbol_name(tcx),
compressed,
- tcx.sess.target.is_like_osx,
);
-
- metadata
}
let val_hi = fx.bcx.ins().umulhi(lhs, rhs);
fx.bcx.ins().icmp_imm(IntCC::NotEqual, val_hi, 0)
} else {
+ // Based on LLVM's instruction sequence for compiling
+ // a.checked_mul(b).is_some() to riscv64gc:
+ // mulh a2, a0, a1
+ // mul a0, a0, a1
+ // srai a0, a0, 63
+ // xor a0, a0, a2
+ // snez a0, a0
let val_hi = fx.bcx.ins().smulhi(lhs, rhs);
- let not_all_zero = fx.bcx.ins().icmp_imm(IntCC::NotEqual, val_hi, 0);
- let not_all_ones = fx.bcx.ins().icmp_imm(
- IntCC::NotEqual,
- val_hi,
- u64::try_from((1u128 << ty.bits()) - 1).unwrap() as i64,
- );
- fx.bcx.ins().band(not_all_zero, not_all_ones)
+ let val_sign = fx.bcx.ins().sshr_imm(val, i64::from(ty.bits() - 1));
+ let xor = fx.bcx.ins().bxor(val_hi, val_sign);
+ fx.bcx.ins().icmp_imm(IntCC::NotEqual, xor, 0)
};
(val, has_overflow)
}
+++ /dev/null
-//! This optimization moves cold code to the end of the function.
-//!
-//! Some code is executed much less often than other code. For example panicking or the
-//! landingpads for unwinding. By moving this cold code to the end of the function the average
-//! amount of jumps is reduced and the code locality is improved.
-//!
-//! # Undefined behaviour
-//!
-//! This optimization doesn't assume anything that isn't already assumed by Cranelift itself.
-
-use crate::prelude::*;
-
-pub(super) fn optimize_function(ctx: &mut Context, cold_blocks: &EntitySet<Block>) {
- // FIXME Move the block in place instead of remove and append once
- // bytecodealliance/cranelift#1339 is implemented.
-
- let mut block_insts = FxHashMap::default();
- for block in cold_blocks.keys().filter(|&block| cold_blocks.contains(block)) {
- let insts = ctx.func.layout.block_insts(block).collect::<Vec<_>>();
- for &inst in &insts {
- ctx.func.layout.remove_inst(inst);
- }
- block_insts.insert(block, insts);
- ctx.func.layout.remove_block(block);
- }
-
- // And then append them at the back again.
- for block in cold_blocks.keys().filter(|&block| cold_blocks.contains(block)) {
- ctx.func.layout.append_block(block);
- for inst in block_insts.remove(&block).unwrap() {
- ctx.func.layout.append_inst(inst, block);
- }
- }
-}
use crate::prelude::*;
-mod code_layout;
pub(crate) mod peephole;
-mod stack2reg;
pub(crate) fn optimize_function<'tcx>(
tcx: TyCtxt<'tcx>,
instance: Instance<'tcx>,
ctx: &mut Context,
- cold_blocks: &EntitySet<Block>,
clif_comments: &mut crate::pretty_clif::CommentWriter,
) {
- // The code_layout optimization is very cheap.
- self::code_layout::optimize_function(ctx, cold_blocks);
+ // FIXME classify optimizations over opt levels once we have more
- if tcx.sess.opts.optimize == rustc_session::config::OptLevel::No {
- return; // FIXME classify optimizations over opt levels
- }
-
- // FIXME(#1142) stack2reg miscompiles lewton
- if false {
- self::stack2reg::optimize_function(ctx, clif_comments);
- }
-
- crate::pretty_clif::write_clif_file(tcx, "stack2reg", None, instance, &ctx, &*clif_comments);
+ crate::pretty_clif::write_clif_file(tcx, "preopt", None, instance, &ctx, &*clif_comments);
crate::base::verify_func(tcx, &*clif_comments, &ctx.func);
}
+++ /dev/null
-//! This optimization replaces stack accesses with SSA variables and removes dead stores when possible.
-//!
-//! # Undefined behaviour
-//!
-//! This optimization is based on the assumption that stack slots which don't have their address
-//! leaked through `stack_addr` are only accessed using `stack_load` and `stack_store` in the
-//! function which has the stack slots. This optimization also assumes that stack slot accesses
-//! are never out of bounds. If these assumptions are not correct, then this optimization may remove
-//! `stack_store` instruction incorrectly, or incorrectly use a previously stored value as the value
-//! being loaded by a `stack_load`.
-
-use std::collections::BTreeMap;
-use std::fmt;
-use std::ops::Not;
-
-use rustc_data_structures::fx::FxHashSet;
-
-use cranelift_codegen::cursor::{Cursor, FuncCursor};
-use cranelift_codegen::ir::immediates::Offset32;
-use cranelift_codegen::ir::{InstructionData, Opcode, ValueDef};
-
-use crate::prelude::*;
-
-/// Workaround for `StackSlot` not implementing `Ord`.
-#[derive(Copy, Clone, PartialEq, Eq)]
-struct OrdStackSlot(StackSlot);
-
-impl fmt::Debug for OrdStackSlot {
- fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
- write!(f, "{:?}", self.0)
- }
-}
-
-impl PartialOrd for OrdStackSlot {
- fn partial_cmp(&self, rhs: &Self) -> Option<std::cmp::Ordering> {
- self.0.as_u32().partial_cmp(&rhs.0.as_u32())
- }
-}
-
-impl Ord for OrdStackSlot {
- fn cmp(&self, rhs: &Self) -> std::cmp::Ordering {
- self.0.as_u32().cmp(&rhs.0.as_u32())
- }
-}
-
-#[derive(Debug, Default)]
-struct StackSlotUsage {
- stack_addr: FxHashSet<Inst>,
- stack_load: FxHashSet<Inst>,
- stack_store: FxHashSet<Inst>,
-}
-
-impl StackSlotUsage {
- fn potential_stores_for_load(&self, ctx: &Context, load: Inst) -> Vec<Inst> {
- self.stack_store
- .iter()
- .cloned()
- .filter(|&store| {
- match spatial_overlap(&ctx.func, store, load) {
- SpatialOverlap::No => false, // Can never be the source of the loaded value.
- SpatialOverlap::Partial | SpatialOverlap::Full => true,
- }
- })
- .filter(|&store| {
- match temporal_order(ctx, store, load) {
- TemporalOrder::NeverBefore => false, // Can never be the source of the loaded value.
- TemporalOrder::MaybeBefore | TemporalOrder::DefinitivelyBefore => true,
- }
- })
- .collect::<Vec<Inst>>()
- }
-
- fn potential_loads_of_store(&self, ctx: &Context, store: Inst) -> Vec<Inst> {
- self.stack_load
- .iter()
- .cloned()
- .filter(|&load| {
- match spatial_overlap(&ctx.func, store, load) {
- SpatialOverlap::No => false, // Can never be the source of the loaded value.
- SpatialOverlap::Partial | SpatialOverlap::Full => true,
- }
- })
- .filter(|&load| {
- match temporal_order(ctx, store, load) {
- TemporalOrder::NeverBefore => false, // Can never be the source of the loaded value.
- TemporalOrder::MaybeBefore | TemporalOrder::DefinitivelyBefore => true,
- }
- })
- .collect::<Vec<Inst>>()
- }
-
- fn remove_unused_stack_addr(func: &mut Function, inst: Inst) {
- func.dfg.detach_results(inst);
- func.dfg.replace(inst).nop();
- }
-
- fn remove_unused_load(func: &mut Function, load: Inst) {
- func.dfg.detach_results(load);
- func.dfg.replace(load).nop();
- }
-
- fn remove_dead_store(&mut self, func: &mut Function, store: Inst) {
- func.dfg.replace(store).nop();
- self.stack_store.remove(&store);
- }
-
- fn change_load_to_alias(&mut self, func: &mut Function, load: Inst, value: Value) {
- let loaded_value = func.dfg.inst_results(load)[0];
- let loaded_type = func.dfg.value_type(loaded_value);
-
- if func.dfg.value_type(value) == loaded_type {
- func.dfg.detach_results(load);
- func.dfg.replace(load).nop();
- func.dfg.change_to_alias(loaded_value, value);
- } else {
- func.dfg.replace(load).bitcast(loaded_type, value);
- }
-
- self.stack_load.remove(&load);
- }
-}
-
-struct OptimizeContext<'a> {
- ctx: &'a mut Context,
- stack_slot_usage_map: BTreeMap<OrdStackSlot, StackSlotUsage>,
-}
-
-impl<'a> OptimizeContext<'a> {
- fn for_context(ctx: &'a mut Context) -> Self {
- ctx.flowgraph(); // Compute cfg and domtree.
-
- // Record all stack_addr, stack_load and stack_store instructions.
- let mut stack_slot_usage_map = BTreeMap::<OrdStackSlot, StackSlotUsage>::new();
-
- let mut cursor = FuncCursor::new(&mut ctx.func);
- while let Some(_block) = cursor.next_block() {
- while let Some(inst) = cursor.next_inst() {
- match cursor.func.dfg[inst] {
- InstructionData::StackLoad {
- opcode: Opcode::StackAddr,
- stack_slot,
- offset: _,
- } => {
- stack_slot_usage_map
- .entry(OrdStackSlot(stack_slot))
- .or_insert_with(StackSlotUsage::default)
- .stack_addr
- .insert(inst);
- }
- InstructionData::StackLoad {
- opcode: Opcode::StackLoad,
- stack_slot,
- offset: _,
- } => {
- stack_slot_usage_map
- .entry(OrdStackSlot(stack_slot))
- .or_insert_with(StackSlotUsage::default)
- .stack_load
- .insert(inst);
- }
- InstructionData::StackStore {
- opcode: Opcode::StackStore,
- arg: _,
- stack_slot,
- offset: _,
- } => {
- stack_slot_usage_map
- .entry(OrdStackSlot(stack_slot))
- .or_insert_with(StackSlotUsage::default)
- .stack_store
- .insert(inst);
- }
- _ => {}
- }
- }
- }
-
- OptimizeContext { ctx, stack_slot_usage_map }
- }
-}
-
-pub(super) fn optimize_function(
- ctx: &mut Context,
- clif_comments: &mut crate::pretty_clif::CommentWriter,
-) {
- combine_stack_addr_with_load_store(&mut ctx.func);
-
- let mut opt_ctx = OptimizeContext::for_context(ctx);
-
- // FIXME Repeat following instructions until fixpoint.
-
- remove_unused_stack_addr_and_stack_load(&mut opt_ctx);
-
- if clif_comments.enabled() {
- for (&OrdStackSlot(stack_slot), usage) in &opt_ctx.stack_slot_usage_map {
- clif_comments.add_comment(stack_slot, format!("used by: {:?}", usage));
- }
- }
-
- for (stack_slot, users) in opt_ctx.stack_slot_usage_map.iter_mut() {
- if users.stack_addr.is_empty().not() {
- // Stack addr leaked; there may be unknown loads and stores.
- // FIXME use stacked borrows to optimize
- continue;
- }
-
- for load in users.stack_load.clone().into_iter() {
- let potential_stores = users.potential_stores_for_load(&opt_ctx.ctx, load);
-
- if clif_comments.enabled() {
- for &store in &potential_stores {
- clif_comments.add_comment(
- load,
- format!(
- "Potential store -> load forwarding {} -> {} ({:?}, {:?})",
- opt_ctx.ctx.func.dfg.display_inst(store, None),
- opt_ctx.ctx.func.dfg.display_inst(load, None),
- spatial_overlap(&opt_ctx.ctx.func, store, load),
- temporal_order(&opt_ctx.ctx, store, load),
- ),
- );
- }
- }
-
- match *potential_stores {
- [] => {
- if clif_comments.enabled() {
- clif_comments
- .add_comment(load, "[BUG?] Reading uninitialized memory".to_string());
- }
- }
- [store]
- if spatial_overlap(&opt_ctx.ctx.func, store, load) == SpatialOverlap::Full
- && temporal_order(&opt_ctx.ctx, store, load)
- == TemporalOrder::DefinitivelyBefore =>
- {
- // Only one store could have been the origin of the value.
- let stored_value = opt_ctx.ctx.func.dfg.inst_args(store)[0];
-
- if clif_comments.enabled() {
- clif_comments.add_comment(
- load,
- format!("Store to load forward {} -> {}", store, load),
- );
- }
-
- users.change_load_to_alias(&mut opt_ctx.ctx.func, load, stored_value);
- }
- _ => {} // FIXME implement this
- }
- }
-
- for store in users.stack_store.clone().into_iter() {
- let potential_loads = users.potential_loads_of_store(&opt_ctx.ctx, store);
-
- if clif_comments.enabled() {
- for &load in &potential_loads {
- clif_comments.add_comment(
- store,
- format!(
- "Potential load from store {} <- {} ({:?}, {:?})",
- opt_ctx.ctx.func.dfg.display_inst(load, None),
- opt_ctx.ctx.func.dfg.display_inst(store, None),
- spatial_overlap(&opt_ctx.ctx.func, store, load),
- temporal_order(&opt_ctx.ctx, store, load),
- ),
- );
- }
- }
-
- if potential_loads.is_empty() {
- // Never loaded; can safely remove all stores and the stack slot.
- // FIXME also remove stores when there is always a next store before a load.
-
- if clif_comments.enabled() {
- clif_comments.add_comment(
- store,
- format!(
- "Remove dead stack store {} of {}",
- opt_ctx.ctx.func.dfg.display_inst(store, None),
- stack_slot.0
- ),
- );
- }
-
- users.remove_dead_store(&mut opt_ctx.ctx.func, store);
- }
- }
-
- if users.stack_store.is_empty() && users.stack_load.is_empty() {
- opt_ctx.ctx.func.stack_slots[stack_slot.0].size = 0;
- }
- }
-}
-
-fn combine_stack_addr_with_load_store(func: &mut Function) {
- // Turn load and store into stack_load and stack_store when possible.
- let mut cursor = FuncCursor::new(func);
- while let Some(_block) = cursor.next_block() {
- while let Some(inst) = cursor.next_inst() {
- match cursor.func.dfg[inst] {
- InstructionData::Load { opcode: Opcode::Load, arg: addr, flags: _, offset } => {
- if cursor.func.dfg.ctrl_typevar(inst) == types::I128
- || cursor.func.dfg.ctrl_typevar(inst).is_vector()
- {
- continue; // WORKAROUD: stack_load.i128 not yet implemented
- }
- if let Some((stack_slot, stack_addr_offset)) =
- try_get_stack_slot_and_offset_for_addr(cursor.func, addr)
- {
- if let Some(combined_offset) = offset.try_add_i64(stack_addr_offset.into())
- {
- let ty = cursor.func.dfg.ctrl_typevar(inst);
- cursor.func.dfg.replace(inst).stack_load(
- ty,
- stack_slot,
- combined_offset,
- );
- }
- }
- }
- InstructionData::Store {
- opcode: Opcode::Store,
- args: [value, addr],
- flags: _,
- offset,
- } => {
- if cursor.func.dfg.ctrl_typevar(inst) == types::I128
- || cursor.func.dfg.ctrl_typevar(inst).is_vector()
- {
- continue; // WORKAROUND: stack_store.i128 not yet implemented
- }
- if let Some((stack_slot, stack_addr_offset)) =
- try_get_stack_slot_and_offset_for_addr(cursor.func, addr)
- {
- if let Some(combined_offset) = offset.try_add_i64(stack_addr_offset.into())
- {
- cursor.func.dfg.replace(inst).stack_store(
- value,
- stack_slot,
- combined_offset,
- );
- }
- }
- }
- _ => {}
- }
- }
- }
-}
-
-fn remove_unused_stack_addr_and_stack_load(opt_ctx: &mut OptimizeContext<'_>) {
- // FIXME incrementally rebuild on each call?
- let mut stack_addr_load_insts_users = FxHashMap::<Inst, FxHashSet<Inst>>::default();
-
- let mut cursor = FuncCursor::new(&mut opt_ctx.ctx.func);
- while let Some(_block) = cursor.next_block() {
- while let Some(inst) = cursor.next_inst() {
- for &arg in cursor.func.dfg.inst_args(inst) {
- if let ValueDef::Result(arg_origin, 0) = cursor.func.dfg.value_def(arg) {
- match cursor.func.dfg[arg_origin].opcode() {
- Opcode::StackAddr | Opcode::StackLoad => {
- stack_addr_load_insts_users
- .entry(arg_origin)
- .or_insert_with(FxHashSet::default)
- .insert(inst);
- }
- _ => {}
- }
- }
- }
- }
- }
-
- #[cfg(debug_assertions)]
- for inst in stack_addr_load_insts_users.keys() {
- let mut is_recorded_stack_addr_or_stack_load = false;
- for stack_slot_users in opt_ctx.stack_slot_usage_map.values() {
- is_recorded_stack_addr_or_stack_load |= stack_slot_users.stack_addr.contains(inst)
- || stack_slot_users.stack_load.contains(inst);
- }
- assert!(is_recorded_stack_addr_or_stack_load);
- }
-
- // Replace all unused stack_addr and stack_load instructions with nop.
- let mut func = &mut opt_ctx.ctx.func;
-
- for stack_slot_users in opt_ctx.stack_slot_usage_map.values_mut() {
- stack_slot_users
- .stack_addr
- .drain_filter(|inst| {
- stack_addr_load_insts_users.get(inst).map(|users| users.is_empty()).unwrap_or(true)
- })
- .for_each(|inst| StackSlotUsage::remove_unused_stack_addr(&mut func, inst));
-
- stack_slot_users
- .stack_load
- .drain_filter(|inst| {
- stack_addr_load_insts_users.get(inst).map(|users| users.is_empty()).unwrap_or(true)
- })
- .for_each(|inst| StackSlotUsage::remove_unused_load(&mut func, inst));
- }
-}
-
-fn try_get_stack_slot_and_offset_for_addr(
- func: &Function,
- addr: Value,
-) -> Option<(StackSlot, Offset32)> {
- if let ValueDef::Result(addr_inst, 0) = func.dfg.value_def(addr) {
- if let InstructionData::StackLoad { opcode: Opcode::StackAddr, stack_slot, offset } =
- func.dfg[addr_inst]
- {
- return Some((stack_slot, offset));
- }
- }
- None
-}
-
-#[derive(Copy, Clone, Debug, PartialEq, Eq)]
-enum SpatialOverlap {
- No,
- Partial,
- Full,
-}
-
-fn spatial_overlap(func: &Function, src: Inst, dest: Inst) -> SpatialOverlap {
- fn inst_info(func: &Function, inst: Inst) -> (StackSlot, Offset32, u32) {
- match func.dfg[inst] {
- InstructionData::StackLoad { opcode: Opcode::StackAddr, stack_slot, offset }
- | InstructionData::StackLoad { opcode: Opcode::StackLoad, stack_slot, offset }
- | InstructionData::StackStore {
- opcode: Opcode::StackStore,
- stack_slot,
- offset,
- arg: _,
- } => (stack_slot, offset, func.dfg.ctrl_typevar(inst).bytes()),
- _ => unreachable!("{:?}", func.dfg[inst]),
- }
- }
-
- debug_assert_ne!(src, dest);
-
- let (src_ss, src_offset, src_size) = inst_info(func, src);
- let (dest_ss, dest_offset, dest_size) = inst_info(func, dest);
-
- if src_ss != dest_ss {
- return SpatialOverlap::No;
- }
-
- if src_offset == dest_offset && src_size == dest_size {
- return SpatialOverlap::Full;
- }
-
- let src_end: i64 = src_offset.try_add_i64(i64::from(src_size)).unwrap().into();
- let dest_end: i64 = dest_offset.try_add_i64(i64::from(dest_size)).unwrap().into();
- if src_end <= dest_offset.into() || dest_end <= src_offset.into() {
- return SpatialOverlap::No;
- }
-
- SpatialOverlap::Partial
-}
-
-#[derive(Copy, Clone, Debug, PartialEq, Eq)]
-enum TemporalOrder {
- /// `src` will never be executed before `dest`.
- NeverBefore,
-
- /// `src` may be executed before `dest`.
- MaybeBefore,
-
- /// `src` will always be executed before `dest`.
- /// There may still be other instructions in between.
- DefinitivelyBefore,
-}
-
-fn temporal_order(ctx: &Context, src: Inst, dest: Inst) -> TemporalOrder {
- debug_assert_ne!(src, dest);
-
- if ctx.domtree.dominates(src, dest, &ctx.func.layout) {
- TemporalOrder::DefinitivelyBefore
- } else if ctx.domtree.dominates(src, dest, &ctx.func.layout) {
- TemporalOrder::NeverBefore
- } else {
- TemporalOrder::MaybeBefore
- }
-}
pub(crate) fn write_ir_file(
tcx: TyCtxt<'_>,
- name: &str,
+ name: impl FnOnce() -> String,
write: impl FnOnce(&mut dyn Write) -> std::io::Result<()>,
) {
if !should_write_ir(tcx) {
res @ Err(_) => res.unwrap(),
}
- let clif_file_name = clif_output_dir.join(name);
+ let clif_file_name = clif_output_dir.join(name());
let res = std::fs::File::create(clif_file_name).and_then(|mut file| write(&mut file));
if let Err(err) = res {
context: &cranelift_codegen::Context,
mut clif_comments: &CommentWriter,
) {
- write_ir_file(tcx, &format!("{}.{}.clif", tcx.symbol_name(instance).name, postfix), |file| {
- let value_ranges =
- isa.map(|isa| context.build_value_labels_ranges(isa).expect("value location ranges"));
+ write_ir_file(
+ tcx,
+ || format!("{}.{}.clif", tcx.symbol_name(instance).name, postfix),
+ |file| {
+ let value_ranges = isa
+ .map(|isa| context.build_value_labels_ranges(isa).expect("value location ranges"));
- let mut clif = String::new();
- cranelift_codegen::write::decorate_function(
- &mut clif_comments,
- &mut clif,
- &context.func,
- &DisplayFunctionAnnotations {
- isa: Some(&*crate::build_isa(tcx.sess)),
- value_ranges: value_ranges.as_ref(),
- },
- )
- .unwrap();
+ let mut clif = String::new();
+ cranelift_codegen::write::decorate_function(
+ &mut clif_comments,
+ &mut clif,
+ &context.func,
+ &DisplayFunctionAnnotations { isa, value_ranges: value_ranges.as_ref() },
+ )
+ .unwrap();
- writeln!(file, "test compile")?;
- writeln!(file, "set is_pic")?;
- writeln!(file, "set enable_simd")?;
- writeln!(file, "target {} haswell", crate::target_triple(tcx.sess))?;
- writeln!(file)?;
- file.write_all(clif.as_bytes())?;
- Ok(())
- });
+ writeln!(file, "test compile")?;
+ writeln!(file, "set is_pic")?;
+ writeln!(file, "set enable_simd")?;
+ writeln!(file, "target {} haswell", crate::target_triple(tcx.sess))?;
+ writeln!(file)?;
+ file.write_all(clif.as_bytes())?;
+ Ok(())
+ },
+ );
}
impl fmt::Debug for FunctionCx<'_, '_, '_> {
fn codegen_print(fx: &mut FunctionCx<'_, '_, '_>, msg: &str) {
let puts = fx
- .cx
.module
.declare_function(
"puts",
},
)
.unwrap();
- let puts = fx.cx.module.declare_func_in_func(puts, &mut fx.bcx.func);
+ let puts = fx.module.declare_func_in_func(puts, &mut fx.bcx.func);
if fx.clif_comments.enabled() {
fx.add_comment(puts, "puts");
}
- let symbol_name = fx.tcx.symbol_name(fx.instance);
- let real_msg = format!("trap at {:?} ({}): {}\0", fx.instance, symbol_name, msg);
+ let real_msg = format!("trap at {:?} ({}): {}\0", fx.instance, fx.symbol_name, msg);
let msg_ptr = fx.anonymous_str("trap", &real_msg);
fx.bcx.ins().call(puts, &[msg_ptr]);
}
let src_align = src_layout.align.abi.bytes() as u8;
let dst_align = dst_layout.align.abi.bytes() as u8;
fx.bcx.emit_small_memory_copy(
- fx.cx.module.target_config(),
+ fx.module.target_config(),
to_addr,
from_addr,
size,
layout: TyAndLayout<'tcx>,
trait_ref: Option<ty::PolyExistentialTraitRef<'tcx>>,
) -> Value {
- let data_id = if let Some(data_id) = fx.cx.vtables.get(&(layout.ty, trait_ref)) {
+ let data_id = if let Some(data_id) = fx.vtables.get(&(layout.ty, trait_ref)) {
*data_id
} else {
let data_id = build_vtable(fx, layout, trait_ref);
- fx.cx.vtables.insert((layout.ty, trait_ref), data_id);
+ fx.vtables.insert((layout.ty, trait_ref), data_id);
data_id
};
- let local_data_id = fx.cx.module.declare_data_in_func(data_id, &mut fx.bcx.func);
+ let local_data_id = fx.module.declare_data_in_func(data_id, &mut fx.bcx.func);
fx.bcx.ins().global_value(fx.pointer_type, local_data_id)
}
let drop_in_place_fn = import_function(
tcx,
- fx.cx.module,
+ fx.module,
Instance::resolve_drop_in_place(tcx, layout.ty).polymorphize(fx.tcx),
);
opt_mth.map(|(def_id, substs)| {
import_function(
tcx,
- fx.cx.module,
+ fx.module,
Instance::resolve_for_vtable(tcx, ParamEnv::reveal_all(), def_id, substs)
.unwrap()
.polymorphize(fx.tcx),
for (i, component) in components.into_iter().enumerate() {
if let Some(func_id) = component {
- let func_ref = fx.cx.module.declare_func_in_data(func_id, &mut data_ctx);
+ 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);
}
}
data_ctx.set_align(fx.tcx.data_layout.pointer_align.pref.bytes());
- let data_id = fx
- .cx
- .module
- .declare_data(
- &format!(
- "__vtable.{}.for.{:?}.{}",
- trait_ref
- .as_ref()
- .map(|trait_ref| format!("{:?}", trait_ref.skip_binder()).into())
- .unwrap_or(std::borrow::Cow::Borrowed("???")),
- layout.ty,
- fx.cx.vtables.len(),
- ),
- Linkage::Local,
- false,
- false,
- )
- .unwrap();
-
- // FIXME don't duplicate definitions in lazy jit mode
- let _ = fx.cx.module.define_data(data_id, &data_ctx);
+ let data_id = fx.module.declare_anonymous_data(false, false).unwrap();
+
+ fx.module.define_data(data_id, &data_ctx).unwrap();
data_id
}
unfinished_type,
member_holding_stub,
member_descriptions,
+ None,
);
MetadataCreationResult::new(metadata_stub, true)
}
layout: TyAndLayout<'tcx>,
tag_type_metadata: Option<&'ll DIType>,
containing_scope: &'ll DIScope,
+ common_members: Vec<Option<&'ll DIType>>,
span: Span,
}
} else {
type_metadata(cx, self.enum_type, self.span)
};
- let flags = match self.enum_type.kind() {
- ty::Generator(..) => DIFlags::FlagArtificial,
- _ => DIFlags::FlagZero,
- };
match self.layout.variants {
Variants::Single { index } => {
self.enum_type,
variant_type_metadata,
member_descriptions,
+ Some(&self.common_members),
);
vec![MemberDescription {
name: if fallback { String::new() } else { variant_info.variant_name() },
offset: Size::ZERO,
size: self.layout.size,
align: self.layout.align.abi,
- flags,
+ flags: DIFlags::FlagZero,
discriminant: None,
source_info: variant_info.source_info(cx),
}]
self.enum_type,
variant_type_metadata,
member_descriptions,
+ Some(&self.common_members),
);
MemberDescription {
offset: Size::ZERO,
size: self.layout.size,
align: self.layout.align.abi,
- flags,
+ flags: DIFlags::FlagZero,
discriminant: Some(
self.layout.ty.discriminant_for_variant(cx.tcx, i).unwrap().val
as u64,
self.enum_type,
variant_type_metadata,
variant_member_descriptions,
+ Some(&self.common_members),
);
// Encode the information about the null variant in the union
offset: Size::ZERO,
size: variant.size,
align: variant.align.abi,
- flags,
+ flags: DIFlags::FlagZero,
discriminant: None,
source_info: variant_info.source_info(cx),
}]
self.enum_type,
variant_type_metadata,
member_descriptions,
+ Some(&self.common_members),
);
let niche_value = if i == dataful_variant {
offset: Size::ZERO,
size: self.layout.size,
align: self.layout.align.abi,
- flags,
+ flags: DIFlags::FlagZero,
discriminant: niche_value,
source_info: variant_info.source_info(cx),
}
}
None
}
-
- fn is_artificial(&self) -> bool {
- match self {
- VariantInfo::Generator { .. } => true,
- VariantInfo::Adt(..) => false,
- }
- }
}
/// Returns a tuple of (1) `type_metadata_stub` of the variant, (2) a
&variant_name,
unique_type_id,
Some(containing_scope),
- // FIXME(tmandry): This doesn't seem to have any effect.
- if variant.is_artificial() { DIFlags::FlagArtificial } else { DIFlags::FlagZero },
+ DIFlags::FlagZero,
)
});
) -> RecursiveTypeDescription<'ll, 'tcx> {
let tcx = cx.tcx;
let enum_name = compute_debuginfo_type_name(tcx, enum_type, false);
- // FIXME(tmandry): This doesn't seem to have any effect.
- let enum_flags = match enum_type.kind() {
- ty::Generator(..) => DIFlags::FlagArtificial,
- _ => DIFlags::FlagZero,
- };
let containing_scope = get_namespace_for_item(cx, enum_def_id);
// FIXME: This should emit actual file metadata for the enum, but we
UNKNOWN_LINE_NUMBER,
layout.size.bits(),
layout.align.abi.bits() as u32,
- enum_flags,
+ DIFlags::FlagZero,
None,
0, // RuntimeLang
unique_type_id_str.as_ptr().cast(),
layout,
tag_type_metadata: discriminant_type_metadata,
containing_scope,
+ common_members: vec![],
span,
}),
);
}
};
- let mut outer_fields = match layout.variants {
+ let outer_fields = match layout.variants {
Variants::Single { .. } => vec![],
Variants::Multiple { .. } => {
let tuple_mdf = TupleMemberDescriptionFactory {
UNKNOWN_LINE_NUMBER,
layout.size.bits(),
layout.align.abi.bits() as u32,
- enum_flags,
+ DIFlags::FlagZero,
discriminator_metadata,
empty_array,
variant_part_unique_type_id_str.as_ptr().cast(),
variant_part_unique_type_id_str.len(),
)
};
- outer_fields.push(Some(variant_part));
let struct_wrapper = {
// The variant part must be wrapped in a struct according to DWARF.
- let type_array = create_DIArray(DIB(cx), &outer_fields);
+ // All fields except the discriminant (including `outer_fields`)
+ // should be put into structures inside the variant part, which gives
+ // an equivalent layout but offers us much better integration with
+ // debuggers.
+ let type_array = create_DIArray(DIB(cx), &[Some(variant_part)]);
let type_map = debug_context(cx).type_map.borrow();
let unique_type_id_str = type_map.get_unique_type_id_as_string(unique_type_id);
UNKNOWN_LINE_NUMBER,
layout.size.bits(),
layout.align.abi.bits() as u32,
- enum_flags,
+ DIFlags::FlagZero,
None,
type_array,
0,
layout,
tag_type_metadata: None,
containing_scope,
+ common_members: outer_fields,
span,
}),
)
DIFlags::FlagZero,
);
// ... and immediately create and add the member descriptions.
- set_members_of_composite_type(cx, composite_type, composite_type_metadata, member_descriptions);
+ set_members_of_composite_type(
+ cx,
+ composite_type,
+ composite_type_metadata,
+ member_descriptions,
+ None,
+ );
composite_type_metadata
}
composite_type: Ty<'tcx>,
composite_type_metadata: &'ll DICompositeType,
member_descriptions: Vec<MemberDescription<'ll>>,
+ common_members: Option<&Vec<Option<&'ll DIType>>>,
) {
// In some rare cases LLVM metadata uniquing would lead to an existing type
// description being used instead of a new one created in
}
}
- let member_metadata: Vec<_> = member_descriptions
+ let mut member_metadata: Vec<_> = member_descriptions
.into_iter()
.map(|desc| Some(desc.into_metadata(cx, composite_type_metadata)))
.collect();
+ if let Some(other_members) = common_members {
+ member_metadata.extend(other_members.iter());
+ }
let type_params = compute_type_parameters(cx, composite_type);
unsafe {
let mut name_buf = None;
let name_len = llvm::LLVMRustGetSectionName(si.llsi, &mut name_buf);
let name = name_buf.map_or_else(
- String::new, // We got a NULL ptr, ignore `name_len`.
+ String::new, // We got a null ptr, ignore `name_len`.
|buf| {
String::from_utf8(
slice::from_raw_parts(buf.as_ptr() as *const u8, name_len as usize)
codegen_results.crate_info.used_libraries.iter().filter(|l| relevant_lib(sess, l));
let search_path = archive_search_paths(sess);
+ let mut last = (NativeLibKind::Unspecified, None);
for lib in relevant_libs {
+ // Skip if this library is the same as the last.
+ last = if (lib.kind, lib.name) == last { continue } else { (lib.kind, lib.name) };
+
let name = match lib.name {
Some(l) => l,
None => continue,
.expect("failed to find crate type in dependency format list");
let crates = &codegen_results.crate_info.used_crates_static;
+ let mut last = (NativeLibKind::Unspecified, None);
for &(cnum, _) in crates {
for lib in codegen_results.crate_info.native_libraries[&cnum].iter() {
+ // Skip if this library is the same as the last.
+ last = if (lib.kind, lib.name) == last { continue } else { (lib.kind, lib.name) };
+
let name = match lib.name {
Some(l) => l,
None => continue,
E0779: include_str!("./error_codes/E0779.md"),
E0780: include_str!("./error_codes/E0780.md"),
E0781: include_str!("./error_codes/E0781.md"),
+E0782: include_str!("./error_codes/E0782.md"),
+E0783: include_str!("./error_codes/E0783.md"),
;
// E0006, // merged with E0005
// E0008, // cannot bind by-move into a pattern guard
--- /dev/null
+Trait objects must include the `dyn` keyword.
+
+Erroneous code example:
+
+```edition2021,compile_fail,E0782
+trait Foo {}
+fn test(arg: Box<Foo>) {} // error!
+```
+
+Trait objects are a way to call methods on types that are not known until
+runtime but conform to some trait.
+
+Trait objects should be formed with `Box<dyn Foo>`, but in the code above
+`dyn` is left off.
+
+This makes it harder to see that `arg` is a trait object and not a
+simply a heap allocated type called `Foo`.
+
+To fix this issue, add `dyn` before the trait name.
+
+```edition2021
+trait Foo {}
+fn test(arg: Box<dyn Foo>) {} // ok!
+```
+
+This used to be allowed before edition 2021, but is now an error.
--- /dev/null
+The range pattern `...` is no longer allowed.
+
+Erroneous code example:
+
+```edition2021,compile_fail,E0783
+match 2u8 {
+ 0...9 => println!("Got a number less than 10"), // error!
+ _ => println!("Got a number 10 or more"),
+}
+```
+
+Older Rust code using previous editions allowed `...` to stand for exclusive
+ranges which are now signified using `..=`.
+
+To make this code compile replace the `...` with `..=`.
+
+```edition2021
+match 2u8 {
+ 0..=9 => println!("Got a number less than 10"), // ok!
+ _ => println!("Got a number 10 or more"),
+}
+```
CircularInclusion(Vec<PathBuf>),
ModInBlock(Option<Ident>),
FileNotFound(Ident, PathBuf),
- MultipleCandidates(Ident, String, String),
+ MultipleCandidates(Ident, PathBuf, PathBuf),
ParserError(DiagnosticBuilder<'a>),
}
dir_ownership: DirOwnership::Owned { relative: None },
}),
(false, false) => Err(ModError::FileNotFound(ident, default_path)),
- (true, true) => {
- Err(ModError::MultipleCandidates(ident, default_path_str, secondary_path_str))
- }
+ (true, true) => Err(ModError::MultipleCandidates(ident, default_path, secondary_path)),
}
}
));
err
}
- ModError::MultipleCandidates(ident, default_path_short, secondary_path_short) => {
+ ModError::MultipleCandidates(ident, default_path, secondary_path) => {
let mut err = struct_span_err!(
diag,
span,
E0761,
- "file for module `{}` found at both {} and {}",
+ "file for module `{}` found at both \"{}\" and \"{}\"",
ident,
- default_path_short,
- secondary_path_short,
+ default_path.display(),
+ secondary_path.display(),
);
err.help("delete or rename one of them to remove the ambiguity");
err
hash
}
- /// Used by librustdoc for fake DefIds.
- pub fn num_def_ids(&self) -> usize {
- self.index_to_key.len()
- }
-
pub fn enumerated_keys_and_path_hashes(
&self,
) -> impl Iterator<Item = (DefIndex, &DefKey, &DefPathHash)> + '_ {
Op: Fn(Word, Word) -> Word,
{
assert_eq!(out_vec.len(), in_vec.len());
- let mut changed = false;
+ let mut changed = 0;
for (out_elem, in_elem) in iter::zip(out_vec, in_vec) {
let old_val = *out_elem;
let new_val = op(old_val, *in_elem);
*out_elem = new_val;
- changed |= old_val != new_val;
+ // This is essentially equivalent to a != with changed being a bool, but
+ // in practice this code gets auto-vectorized by the compiler for most
+ // operators. Using != here causes us to generate quite poor code as the
+ // compiler tries to go back to a boolean on each loop iteration.
+ changed |= old_val ^ new_val;
}
- changed
+ changed != 0
}
const SPARSE_MAX: usize = 8;
/// [`..` range expression]: https://doc.rust-lang.org/reference/expressions/range-expr.html
pub ELLIPSIS_INCLUSIVE_RANGE_PATTERNS,
Warn,
- "`...` range patterns are deprecated"
+ "`...` range patterns are deprecated",
+ @future_incompatible = FutureIncompatibleInfo {
+ reference: "issue #80165 <https://github.com/rust-lang/rust/issues/80165>",
+ edition: Some(Edition::Edition2021),
+ };
}
#[derive(Default)]
let suggestion = "use `..=` for an inclusive range";
if parenthesise {
self.node_id = Some(pat.id);
- cx.struct_span_lint(ELLIPSIS_INCLUSIVE_RANGE_PATTERNS, pat.span, |lint| {
- let end = expr_to_string(&end);
- let replace = match start {
- Some(start) => format!("&({}..={})", expr_to_string(&start), end),
- None => format!("&(..={})", end),
- };
- lint.build(msg)
- .span_suggestion(
- pat.span,
- suggestion,
- replace,
- Applicability::MachineApplicable,
- )
- .emit();
- });
+ let end = expr_to_string(&end);
+ let replace = match start {
+ Some(start) => format!("&({}..={})", expr_to_string(&start), end),
+ None => format!("&(..={})", end),
+ };
+ if join.edition() >= Edition::Edition2021 {
+ let mut err =
+ rustc_errors::struct_span_err!(cx.sess, pat.span, E0783, "{}", msg,);
+ err.span_suggestion(
+ pat.span,
+ suggestion,
+ replace,
+ Applicability::MachineApplicable,
+ )
+ .emit();
+ } else {
+ cx.struct_span_lint(ELLIPSIS_INCLUSIVE_RANGE_PATTERNS, pat.span, |lint| {
+ lint.build(msg)
+ .span_suggestion(
+ pat.span,
+ suggestion,
+ replace,
+ Applicability::MachineApplicable,
+ )
+ .emit();
+ });
+ }
} else {
- cx.struct_span_lint(ELLIPSIS_INCLUSIVE_RANGE_PATTERNS, join, |lint| {
- lint.build(msg)
- .span_suggestion_short(
- join,
- suggestion,
- "..=".to_owned(),
- Applicability::MachineApplicable,
- )
- .emit();
- });
+ let replace = "..=".to_owned();
+ if join.edition() >= Edition::Edition2021 {
+ let mut err =
+ rustc_errors::struct_span_err!(cx.sess, pat.span, E0783, "{}", msg,);
+ err.span_suggestion_short(
+ join,
+ suggestion,
+ replace,
+ Applicability::MachineApplicable,
+ )
+ .emit();
+ } else {
+ cx.struct_span_lint(ELLIPSIS_INCLUSIVE_RANGE_PATTERNS, join, |lint| {
+ lint.build(msg)
+ .span_suggestion_short(
+ join,
+ suggestion,
+ replace,
+ Applicability::MachineApplicable,
+ )
+ .emit();
+ });
+ }
};
}
}
declare_lint! {
/// The `invalid_value` lint detects creating a value that is not valid,
- /// such as a NULL reference.
+ /// such as a null reference.
///
/// ### Example
///
/// [undefined behavior]: https://doc.rust-lang.org/reference/behavior-considered-undefined.html
pub INVALID_VALUE,
Warn,
- "an invalid value is being created (such as a NULL reference)"
+ "an invalid value is being created (such as a null reference)"
}
declare_lint_pass!(InvalidValue => [INVALID_VALUE]);
/// [`impl Trait`]: https://doc.rust-lang.org/book/ch10-02-traits.html#traits-as-parameters
pub BARE_TRAIT_OBJECTS,
Warn,
- "suggest using `dyn Trait` for trait objects"
+ "suggest using `dyn Trait` for trait objects",
+ @future_incompatible = FutureIncompatibleInfo {
+ reference: "issue #80165 <https://github.com/rust-lang/rust/issues/80165>",
+ edition: Some(Edition::Edition2021),
+ };
}
declare_lint! {
std::string ErrorInfo;
std::error_code EC;
- raw_fd_ostream OS(Path, EC, sys::fs::F_None);
+ raw_fd_ostream OS(Path, EC, sys::fs::OF_None);
if (EC)
ErrorInfo = EC.message();
if (ErrorInfo != "") {
buffer_ostream BOS(OS);
if (DwoPath) {
- raw_fd_ostream DOS(DwoPath, EC, sys::fs::F_None);
+ raw_fd_ostream DOS(DwoPath, EC, sys::fs::OF_None);
EC.clear();
if (EC)
ErrorInfo = EC.message();
LLVMRustPrintModule(LLVMModuleRef M, const char *Path, DemangleFn Demangle) {
std::string ErrorInfo;
std::error_code EC;
- raw_fd_ostream OS(Path, EC, sys::fs::F_None);
+ raw_fd_ostream OS(Path, EC, sys::fs::OF_None);
if (EC)
ErrorInfo = EC.message();
if (ErrorInfo != "") {
return Ok(ret.cast());
}
- // A NULL return from `dlopen` indicates that an error has definitely occurred, so if
+ // A null return from `dlopen` indicates that an error has definitely occurred, so if
// nothing is in `dlerror`, we are racing with another thread that has stolen our error
// message. See the explanation on the `dl::error` module for more information.
dlerror.get().and_then(|()| Err("Unknown error".to_string()))
) -> Result<*mut u8, String> {
let mut dlerror = error::lock();
- // Unlike `dlopen`, it's possible for `dlsym` to return NULL without overwriting `dlerror`.
+ // Unlike `dlopen`, it's possible for `dlsym` to return null without overwriting `dlerror`.
// Because of this, we clear `dlerror` before calling `dlsym` to avoid picking up a stale
// error message by accident.
dlerror.clear();
return Ok(ret.cast());
}
- // If `dlsym` returns NULL but there is nothing in `dlerror` it means one of two things:
+ // If `dlsym` returns null but there is nothing in `dlerror` it means one of two things:
// - We tried to load a symbol mapped to address 0. This is not technically an error but is
// unlikely to occur in practice and equally unlikely to be handled correctly by calling
// code. Therefore we treat it as an error anyway.
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 }
}
self.get_crate_data(def_id.krate).module_expansion(def_id.index, sess)
}
- pub fn num_def_ids(&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()
}
[] predicates: rustc_middle::ty::PredicateInner<$tcx>,
// HIR query types
- [few] indexed_hir: rustc_middle::hir::map::IndexedHir<$tcx>,
+ [few] indexed_hir: rustc_middle::hir::IndexedHir<$tcx>,
[few] hir_definitions: rustc_hir::definitions::Definitions,
[] hir_owner: rustc_middle::hir::Owner<$tcx>,
[] hir_owner_nodes: rustc_middle::hir::OwnerNodes<$tcx>,
use crate::arena::Arena;
-use crate::hir::map::{Entry, HirOwnerData, Map};
-use crate::hir::{Owner, OwnerNodes, ParentedNode};
+use crate::hir::map::{HirOwnerData, Map};
+use crate::hir::{IndexedHir, Owner, OwnerNodes, ParentedNode};
use crate::ich::StableHashingContext;
-use crate::middle::cstore::CrateStore;
use rustc_data_structures::fingerprint::Fingerprint;
use rustc_data_structures::fx::FxHashMap;
use rustc_data_structures::stable_hasher::{HashStable, StableHasher};
-use rustc_data_structures::svh::Svh;
use rustc_hir as hir;
+use rustc_hir::def_id::LocalDefId;
use rustc_hir::def_id::CRATE_DEF_INDEX;
-use rustc_hir::def_id::{LocalDefId, LOCAL_CRATE};
-use rustc_hir::definitions::{self, DefPathHash};
+use rustc_hir::definitions;
use rustc_hir::intravisit::{self, NestedVisitorMap, Visitor};
use rustc_hir::*;
use rustc_index::vec::{Idx, IndexVec};
-use rustc_session::{CrateDisambiguator, Session};
+use rustc_session::Session;
use rustc_span::source_map::SourceMap;
-use rustc_span::{Span, Symbol, DUMMY_SP};
+use rustc_span::{Span, DUMMY_SP};
use std::iter::repeat;
source_map: &'a SourceMap,
map: IndexVec<LocalDefId, HirOwnerData<'hir>>,
+ parenting: FxHashMap<LocalDefId, HirId>,
/// The parent of this node
parent_node: hir::HirId,
definitions: &'a definitions::Definitions,
hcx: StableHashingContext<'a>,
-
- // We are collecting HIR hashes here so we can compute the
- // crate hash from them later on.
- hir_body_nodes: Vec<(DefPathHash, Fingerprint)>,
}
fn insert_vec_map<K: Idx, V: Clone>(map: &mut IndexVec<K, Option<V>>, k: K, v: V) {
fn hash_body(
hcx: &mut StableHashingContext<'_>,
- def_path_hash: DefPathHash,
item_like: impl for<'a> HashStable<StableHashingContext<'a>>,
- hir_body_nodes: &mut Vec<(DefPathHash, Fingerprint)>,
) -> Fingerprint {
- let hash = {
- let mut stable_hasher = StableHasher::new();
- hcx.while_hashing_hir_bodies(true, |hcx| {
- item_like.hash_stable(hcx, &mut stable_hasher);
- });
- stable_hasher.finish()
- };
- hir_body_nodes.push((def_path_hash, hash));
- hash
+ let mut stable_hasher = StableHasher::new();
+ hcx.while_hashing_hir_bodies(true, |hcx| {
+ item_like.hash_stable(hcx, &mut stable_hasher);
+ });
+ stable_hasher.finish()
}
-fn upstream_crates(cstore: &dyn CrateStore) -> Vec<(Symbol, Fingerprint, Svh)> {
- let mut upstream_crates: Vec<_> = cstore
- .crates_untracked()
- .iter()
- .map(|&cnum| {
- let name = cstore.crate_name_untracked(cnum);
- let disambiguator = cstore.crate_disambiguator_untracked(cnum).to_fingerprint();
- let hash = cstore.crate_hash_untracked(cnum);
- (name, disambiguator, hash)
- })
- .collect();
- upstream_crates.sort_unstable_by_key(|&(name, dis, _)| (name.as_str(), dis));
- upstream_crates
+/// Represents an entry and its parent `HirId`.
+#[derive(Copy, Clone, Debug)]
+pub struct Entry<'hir> {
+ parent: HirId,
+ node: Node<'hir>,
}
impl<'a, 'hir> NodeCollector<'a, 'hir> {
definitions: &'a definitions::Definitions,
mut hcx: StableHashingContext<'a>,
) -> NodeCollector<'a, 'hir> {
- let root_mod_def_path_hash =
- definitions.def_path_hash(LocalDefId { local_def_index: CRATE_DEF_INDEX });
-
- let mut hir_body_nodes = Vec::new();
-
let hash = {
let Crate {
ref item,
attrs: _,
} = *krate;
- hash_body(&mut hcx, root_mod_def_path_hash, item, &mut hir_body_nodes)
+ hash_body(&mut hcx, item)
};
let mut collector = NodeCollector {
current_dep_node_owner: LocalDefId { local_def_index: CRATE_DEF_INDEX },
definitions,
hcx,
- hir_body_nodes,
map: (0..definitions.def_index_count())
.map(|_| HirOwnerData { signature: None, with_bodies: None })
.collect(),
+ parenting: FxHashMap::default(),
};
collector.insert_entry(
hir::CRATE_HIR_ID,
collector
}
- pub(super) fn finalize_and_compute_crate_hash(
- mut self,
- crate_disambiguator: CrateDisambiguator,
- cstore: &dyn CrateStore,
- commandline_args_hash: u64,
- ) -> (IndexVec<LocalDefId, HirOwnerData<'hir>>, Svh) {
+ 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;
assert!(bodies.insert(id.hir_id.local_id, body).is_none());
}
-
- self.hir_body_nodes.sort_unstable_by_key(|bn| bn.0);
-
- let node_hashes = self.hir_body_nodes.iter().fold(
- Fingerprint::ZERO,
- |combined_fingerprint, &(def_path_hash, fingerprint)| {
- combined_fingerprint.combine(def_path_hash.0.combine(fingerprint))
- },
- );
-
- let upstream_crates = upstream_crates(cstore);
-
- // We hash the final, remapped names of all local source files so we
- // don't have to include the path prefix remapping commandline args.
- // If we included the full mapping in the SVH, we could only have
- // reproducible builds by compiling from the same directory. So we just
- // hash the result of the mapping instead of the mapping itself.
- let mut source_file_names: Vec<_> = self
- .source_map
- .files()
- .iter()
- .filter(|source_file| source_file.cnum == LOCAL_CRATE)
- .map(|source_file| source_file.name_hash)
- .collect();
-
- source_file_names.sort_unstable();
-
- let crate_hash_input = (
- ((node_hashes, upstream_crates), source_file_names),
- (commandline_args_hash, crate_disambiguator.to_fingerprint()),
- );
-
- let mut stable_hasher = StableHasher::new();
- crate_hash_input.hash_stable(&mut self.hcx, &mut stable_hasher);
- let crate_hash: Fingerprint = stable_hasher.finish();
-
- let svh = Svh::new(crate_hash.to_smaller_hash());
- (self.map, svh)
+ IndexedHir { map: self.map, parenting: self.parenting }
}
fn insert_entry(&mut self, id: HirId, entry: Entry<'hir>, hash: Fingerprint) {
nodes.hash = hash;
debug_assert!(data.signature.is_none());
- data.signature =
- Some(self.arena.alloc(Owner { parent: entry.parent, node: entry.node }));
+ 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 {
id.owner, dk_parent, entry.parent,
)
}
+
+ debug_assert_eq!(self.parenting.get(&id.owner), Some(&entry.parent));
}
} else {
assert_eq!(entry.parent.owner, id.owner);
f: F,
) {
let prev_owner = self.current_dep_node_owner;
-
- let def_path_hash = self.definitions.def_path_hash(dep_node_owner);
-
- let hash = hash_body(&mut self.hcx, def_path_hash, item_like, &mut self.hir_body_nodes);
+ let hash = hash_body(&mut self.hcx, item_like);
self.current_dep_node_owner = dep_node_owner;
f(self, hash);
self.current_dep_node_owner = prev_owner;
}
+
+ fn insert_nested(&mut self, item: LocalDefId) {
+ #[cfg(debug_assertions)]
+ {
+ let dk_parent = self.definitions.def_key(item).parent.unwrap();
+ let dk_parent = LocalDefId { local_def_index: dk_parent };
+ let dk_parent = self.definitions.local_def_id_to_hir_id(dk_parent);
+ debug_assert_eq!(
+ dk_parent.owner, self.parent_node.owner,
+ "Different parents for {:?}",
+ item
+ )
+ }
+
+ assert_eq!(self.parenting.insert(item, self.parent_node), None);
+ }
}
impl<'a, 'hir> Visitor<'hir> for NodeCollector<'a, 'hir> {
fn visit_nested_item(&mut self, item: ItemId) {
debug!("visit_nested_item: {:?}", item);
+ self.insert_nested(item.def_id);
self.visit_item(self.krate.item(item));
}
fn visit_nested_trait_item(&mut self, item_id: TraitItemId) {
+ self.insert_nested(item_id.def_id);
self.visit_trait_item(self.krate.trait_item(item_id));
}
fn visit_nested_impl_item(&mut self, item_id: ImplItemId) {
+ self.insert_nested(item_id.def_id);
self.visit_impl_item(self.krate.impl_item(item_id));
}
fn visit_nested_foreign_item(&mut self, foreign_id: ForeignItemId) {
+ self.insert_nested(foreign_id.def_id);
self.visit_foreign_item(self.krate.foreign_item(foreign_id));
}
self.definitions.local_def_id_to_hir_id(LocalDefId { local_def_index })
});
self.with_parent(parent, |this| {
+ this.insert_nested(macro_def.def_id);
this.with_dep_node_owner(macro_def.def_id, macro_def, |this, hash| {
this.insert_with_hash(
macro_def.span,
use self::collector::NodeCollector;
-use crate::hir::{Owner, OwnerNodes};
+use crate::hir::{HirOwnerData, IndexedHir};
+use crate::middle::cstore::CrateStore;
use crate::ty::TyCtxt;
use rustc_ast as ast;
+use rustc_data_structures::fingerprint::Fingerprint;
+use rustc_data_structures::stable_hasher::{HashStable, StableHasher};
use rustc_data_structures::svh::Svh;
use rustc_hir::def::{DefKind, Res};
use rustc_hir::def_id::{CrateNum, DefId, LocalDefId, CRATE_DEF_INDEX, LOCAL_CRATE};
use rustc_hir::intravisit::Visitor;
use rustc_hir::itemlikevisit::ItemLikeVisitor;
use rustc_hir::*;
-use rustc_index::vec::IndexVec;
+use rustc_index::vec::Idx;
use rustc_span::hygiene::MacroKind;
use rustc_span::source_map::Spanned;
use rustc_span::symbol::{kw, Ident, Symbol};
pub mod blocks;
mod collector;
-/// Represents an entry and its parent `HirId`.
-#[derive(Copy, Clone, Debug)]
-pub struct Entry<'hir> {
- parent: HirId,
- node: Node<'hir>,
-}
-
-impl<'hir> Entry<'hir> {
- fn parent_node(self) -> Option<HirId> {
- match self.node {
- Node::Crate(_) => None,
- _ => Some(self.parent),
- }
- }
-}
-
fn fn_decl<'hir>(node: Node<'hir>) -> Option<&'hir FnDecl<'hir>> {
match node {
Node::Item(Item { kind: ItemKind::Fn(sig, _, _), .. })
}
}
-#[derive(Debug)]
-pub(super) struct HirOwnerData<'hir> {
- pub(super) signature: Option<&'hir Owner<'hir>>,
- pub(super) with_bodies: Option<&'hir mut OwnerNodes<'hir>>,
-}
-
-#[derive(Debug)]
-pub struct IndexedHir<'hir> {
- /// The SVH of the local crate.
- pub crate_hash: Svh,
-
- pub(super) map: IndexVec<LocalDefId, HirOwnerData<'hir>>,
-}
-
#[derive(Copy, Clone)]
pub struct Map<'hir> {
pub(super) tcx: TyCtxt<'hir>,
}
self.current_id = parent_id;
- if let Some(entry) = self.map.find_entry(parent_id) {
- return Some((parent_id, entry.node));
+ if let Some(node) = self.map.find(parent_id) {
+ return Some((parent_id, node));
+ }
+ // If this `HirId` doesn't have an entry, skip it and look for its `parent_id`.
+ }
+ }
+}
+
+/// An iterator that walks up the ancestor tree of a given `HirId`.
+/// Constructed using `tcx.hir().parent_owner_iter(hir_id)`.
+pub struct ParentOwnerIterator<'map, 'hir> {
+ current_id: HirId,
+ map: &'map Map<'hir>,
+}
+
+impl<'hir> Iterator for ParentOwnerIterator<'_, 'hir> {
+ type Item = (HirId, Node<'hir>);
+
+ fn next(&mut self) -> Option<Self::Item> {
+ if self.current_id.local_id.index() != 0 {
+ self.current_id.local_id = ItemLocalId::new(0);
+ if let Some(node) = self.map.find(self.current_id) {
+ return Some((self.current_id, node));
+ }
+ }
+ if self.current_id == CRATE_HIR_ID {
+ return None;
+ }
+ loop {
+ // There are nodes that do not have entries, so we need to skip them.
+ let parent_id = self.map.def_key(self.current_id.owner).parent;
+
+ let parent_id = parent_id.map_or(CRATE_HIR_ID.owner, |local_def_index| {
+ let def_id = LocalDefId { local_def_index };
+ self.map.local_def_id_to_hir_id(def_id).owner
+ });
+ self.current_id = HirId::make_owner(parent_id);
+
+ // If this `HirId` doesn't have an entry, skip it and look for its `parent_id`.
+ if let Some(node) = self.map.find(self.current_id) {
+ return Some((self.current_id, node));
}
- // If this `HirId` doesn't have an `Entry`, skip it and look for its `parent_id`.
}
}
}
bug!(
"local_def_id: no entry for `{:?}`, which has a map of `{:?}`",
hir_id,
- self.find_entry(hir_id)
+ self.find(hir_id)
)
})
}
.unwrap_or_else(|| bug!("def_kind: unsupported node: {:?}", local_def_id))
}
- fn find_entry(&self, id: HirId) -> Option<Entry<'hir>> {
+ pub fn find_parent_node(&self, id: HirId) -> Option<HirId> {
if id.local_id == ItemLocalId::from_u32(0) {
- let owner = self.tcx.hir_owner(id.owner);
- owner.map(|owner| Entry { parent: owner.parent, node: owner.node })
+ Some(self.tcx.hir_owner_parent(id.owner))
} else {
- let owner = self.tcx.hir_owner_nodes(id.owner);
- owner.and_then(|owner| {
- let node = owner.nodes[id.local_id].as_ref();
- // FIXME(eddyb) use a single generic type instead of having both
- // `Entry` and `ParentedNode`, which are effectively the same.
- // Alternatively, rewrite code using `Entry` to use `ParentedNode`.
- node.map(|node| Entry {
- parent: HirId { owner: id.owner, local_id: node.parent },
- node: node.node,
- })
- })
+ let owner = self.tcx.hir_owner_nodes(id.owner)?;
+ let node = owner.nodes[id.local_id].as_ref()?;
+ let hir_id = HirId { owner: id.owner, local_id: node.parent };
+ Some(hir_id)
+ }
+ }
+
+ pub fn get_parent_node(&self, hir_id: HirId) -> HirId {
+ self.find_parent_node(hir_id).unwrap_or(CRATE_HIR_ID)
+ }
+
+ /// Retrieves the `Node` corresponding to `id`, returning `None` if cannot be found.
+ pub fn find(&self, id: HirId) -> Option<Node<'hir>> {
+ if id.local_id == ItemLocalId::from_u32(0) {
+ let owner = self.tcx.hir_owner(id.owner)?;
+ Some(owner.node)
+ } else {
+ let owner = self.tcx.hir_owner_nodes(id.owner)?;
+ let node = owner.nodes[id.local_id].as_ref()?;
+ Some(node.node)
}
}
- fn get_entry(&self, id: HirId) -> Entry<'hir> {
- self.find_entry(id).unwrap()
+ /// Retrieves the `Node` corresponding to `id`, panicking if it cannot be found.
+ pub fn get(&self, id: HirId) -> Node<'hir> {
+ self.find(id).unwrap_or_else(|| bug!("couldn't find hir id {} in the HIR map", id))
+ }
+
+ pub fn get_if_local(&self, id: DefId) -> Option<Node<'hir>> {
+ id.as_local().and_then(|id| self.find(self.local_def_id_to_hir_id(id)))
+ }
+
+ pub fn get_generics(&self, id: DefId) -> Option<&'hir Generics<'hir>> {
+ self.get_if_local(id).and_then(|node| match &node {
+ Node::ImplItem(impl_item) => Some(&impl_item.generics),
+ Node::TraitItem(trait_item) => Some(&trait_item.generics),
+ Node::Item(Item {
+ kind:
+ ItemKind::Fn(_, generics, _)
+ | ItemKind::TyAlias(_, generics)
+ | ItemKind::Enum(_, generics)
+ | ItemKind::Struct(_, generics)
+ | ItemKind::Union(_, generics)
+ | ItemKind::Trait(_, _, generics, ..)
+ | ItemKind::TraitAlias(generics, _)
+ | ItemKind::Impl(Impl { generics, .. }),
+ ..
+ }) => Some(generics),
+ _ => None,
+ })
}
pub fn item(&self, id: ItemId) -> &'hir Item<'hir> {
pub fn get_module(&self, module: LocalDefId) -> (&'hir Mod<'hir>, Span, HirId) {
let hir_id = self.local_def_id_to_hir_id(module);
- match self.get_entry(hir_id).node {
+ match self.get(hir_id) {
Node::Item(&Item { span, kind: ItemKind::Mod(ref m), .. }) => (m, span, hir_id),
Node::Crate(item) => (&item, item.inner, hir_id),
node => panic!("not a module: {:?}", node),
}
}
- /// Retrieves the `Node` corresponding to `id`, panicking if it cannot be found.
- pub fn get(&self, id: HirId) -> Node<'hir> {
- self.find(id).unwrap_or_else(|| bug!("couldn't find hir id {} in the HIR map", id))
- }
-
- pub fn get_if_local(&self, id: DefId) -> Option<Node<'hir>> {
- id.as_local().and_then(|id| self.find(self.local_def_id_to_hir_id(id)))
- }
-
- pub fn get_generics(&self, id: DefId) -> Option<&'hir Generics<'hir>> {
- self.get_if_local(id).and_then(|node| match &node {
- Node::ImplItem(impl_item) => Some(&impl_item.generics),
- Node::TraitItem(trait_item) => Some(&trait_item.generics),
- Node::Item(Item {
- kind:
- ItemKind::Fn(_, generics, _)
- | ItemKind::TyAlias(_, generics)
- | ItemKind::Enum(_, generics)
- | ItemKind::Struct(_, generics)
- | ItemKind::Union(_, generics)
- | ItemKind::Trait(_, _, generics, ..)
- | ItemKind::TraitAlias(generics, _)
- | ItemKind::Impl(Impl { generics, .. }),
- ..
- }) => Some(generics),
- _ => None,
- })
- }
-
- /// Retrieves the `Node` corresponding to `id`, returning `None` if cannot be found.
- pub fn find(&self, hir_id: HirId) -> Option<Node<'hir>> {
- self.find_entry(hir_id).map(|entry| entry.node)
- }
-
- /// Similar to `get_parent`; returns the parent HIR Id, or just `hir_id` if there
- /// is no parent. Note that the parent may be `CRATE_HIR_ID`, which is not itself
- /// present in the map, so passing the return value of `get_parent_node` to
- /// `get` may in fact panic.
- /// This function returns the immediate parent in the HIR, whereas `get_parent`
- /// returns the enclosing item. Note that this might not be the actual parent
- /// node in the HIR -- some kinds of nodes are not in the map and these will
- /// never appear as the parent node. Thus, you can always walk the parent nodes
- /// from a node to the root of the HIR (unless you get back the same ID here,
- /// which can happen if the ID is not in the map itself or is just weird).
- pub fn get_parent_node(&self, hir_id: HirId) -> HirId {
- self.get_entry(hir_id).parent_node().unwrap_or(hir_id)
- }
-
/// Returns an iterator for the nodes in the ancestor tree of the `current_id`
/// until the crate root is reached. Prefer this over your own loop using `get_parent_node`.
pub fn parent_iter(&self, current_id: HirId) -> ParentHirIterator<'_, 'hir> {
ParentHirIterator { current_id, map: self }
}
+ /// Returns an iterator for the nodes in the ancestor tree of the `current_id`
+ /// until the crate root is reached. Prefer this over your own loop using `get_parent_node`.
+ pub fn parent_owner_iter(&self, current_id: HirId) -> ParentOwnerIterator<'_, 'hir> {
+ ParentOwnerIterator { current_id, map: self }
+ }
+
/// Checks if the node is left-hand side of an assignment.
pub fn is_lhs(&self, id: HirId) -> bool {
match self.find(self.get_parent_node(id)) {
/// Whether `hir_id` corresponds to a `mod` or a crate.
pub fn is_hir_id_module(&self, hir_id: HirId) -> bool {
matches!(
- self.get_entry(hir_id).node,
+ self.get(hir_id),
Node::Item(Item { kind: ItemKind::Mod(_), .. }) | Node::Crate(..)
)
}
pub fn get_return_block(&self, id: HirId) -> Option<HirId> {
let mut iter = self.parent_iter(id).peekable();
let mut ignore_tail = false;
- if let Some(entry) = self.find_entry(id) {
- if let Node::Expr(Expr { kind: ExprKind::Ret(_), .. }) = entry.node {
+ if let Some(node) = self.find(id) {
+ if let Node::Expr(Expr { kind: ExprKind::Ret(_), .. }) = node {
// When dealing with `return` statements, we don't care about climbing only tail
// expressions.
ignore_tail = true;
/// in the HIR which is recorded by the map and is an item, either an item
/// in a module, trait, or impl.
pub fn get_parent_item(&self, hir_id: HirId) -> HirId {
- for (hir_id, node) in self.parent_iter(hir_id) {
- match node {
- Node::Crate(_)
- | Node::Item(_)
- | Node::ForeignItem(_)
- | Node::TraitItem(_)
- | Node::ImplItem(_) => return hir_id,
- _ => {}
+ for (hir_id, node) in self.parent_owner_iter(hir_id) {
+ if let Node::Crate(_)
+ | Node::Item(_)
+ | Node::ForeignItem(_)
+ | Node::TraitItem(_)
+ | Node::ImplItem(_) = node
+ {
+ return hir_id;
}
}
- hir_id
+ CRATE_HIR_ID
}
/// Returns the `HirId` of `id`'s nearest module parent, or `id` itself if no
/// module parent is in this map.
pub(super) fn get_module_parent_node(&self, hir_id: HirId) -> HirId {
- for (hir_id, node) in self.parent_iter(hir_id) {
+ for (hir_id, node) in self.parent_owner_iter(hir_id) {
if let Node::Item(&Item { kind: ItemKind::Mod(_), .. }) = node {
return hir_id;
}
pub fn get_foreign_abi(&self, hir_id: HirId) -> Abi {
let parent = self.get_parent_item(hir_id);
- if let Some(entry) = self.find_entry(parent) {
- if let Entry {
- node: Node::Item(Item { kind: ItemKind::ForeignMod { abi, .. }, .. }),
- ..
- } = entry
- {
+ if let Some(node) = self.find(parent) {
+ if let Node::Item(Item { kind: ItemKind::ForeignMod { abi, .. }, .. }) = node {
return *abi;
}
}
}
pub fn opt_span(&self, hir_id: HirId) -> Option<Span> {
- let span = match self.find_entry(hir_id)?.node {
+ let span = match self.find(hir_id)? {
Node::Param(param) => param.span,
Node::Item(item) => match &item.kind {
ItemKind::Fn(sig, _, _) => sig.span,
/// Like `hir.span()`, but includes the body of function items
/// (instead of just the function header)
pub fn span_with_body(&self, hir_id: HirId) -> Span {
- match self.find_entry(hir_id).map(|entry| entry.node) {
+ match self.find(hir_id) {
Some(Node::TraitItem(item)) => item.span,
Some(Node::ImplItem(impl_item)) => impl_item.span,
Some(Node::Item(item)) => item.span,
let _prof_timer = tcx.sess.prof.generic_activity("build_hir_map");
- let (map, crate_hash) = {
- let hcx = tcx.create_stable_hashing_context();
+ let hcx = tcx.create_stable_hashing_context();
+ let mut collector =
+ NodeCollector::root(tcx.sess, &**tcx.arena, tcx.untracked_crate, &tcx.definitions, hcx);
+ intravisit::walk_crate(&mut collector, tcx.untracked_crate);
- let mut collector =
- NodeCollector::root(tcx.sess, &**tcx.arena, tcx.untracked_crate, &tcx.definitions, hcx);
- intravisit::walk_crate(&mut collector, tcx.untracked_crate);
+ let map = collector.finalize_and_compute_crate_hash();
+ tcx.arena.alloc(map)
+}
- let crate_disambiguator = tcx.sess.local_crate_disambiguator();
- let cmdline_args = tcx.sess.opts.dep_tracking_hash(true);
- collector.finalize_and_compute_crate_hash(crate_disambiguator, &*tcx.cstore, cmdline_args)
- };
+pub(super) fn crate_hash(tcx: TyCtxt<'_>, crate_num: CrateNum) -> Svh {
+ let mut hir_body_nodes: Vec<_> = tcx
+ .index_hir(crate_num)
+ .map
+ .iter_enumerated()
+ .filter_map(|(def_id, hod)| {
+ let def_path_hash = tcx.definitions.def_path_hash(def_id);
+ let hash = hod.with_bodies.as_ref()?.hash;
+ Some((def_path_hash, hash))
+ })
+ .collect();
+ hir_body_nodes.sort_unstable_by_key(|bn| bn.0);
- tcx.arena.alloc(IndexedHir { crate_hash, map })
+ let node_hashes = hir_body_nodes.iter().fold(
+ Fingerprint::ZERO,
+ |combined_fingerprint, &(def_path_hash, fingerprint)| {
+ combined_fingerprint.combine(def_path_hash.0.combine(fingerprint))
+ },
+ );
+
+ let upstream_crates = upstream_crates(&*tcx.cstore);
+
+ // We hash the final, remapped names of all local source files so we
+ // don't have to include the path prefix remapping commandline args.
+ // If we included the full mapping in the SVH, we could only have
+ // reproducible builds by compiling from the same directory. So we just
+ // hash the result of the mapping instead of the mapping itself.
+ let mut source_file_names: Vec<_> = tcx
+ .sess
+ .source_map()
+ .files()
+ .iter()
+ .filter(|source_file| source_file.cnum == LOCAL_CRATE)
+ .map(|source_file| source_file.name_hash)
+ .collect();
+
+ source_file_names.sort_unstable();
+
+ let mut hcx = tcx.create_stable_hashing_context();
+ let mut stable_hasher = StableHasher::new();
+ node_hashes.hash_stable(&mut hcx, &mut stable_hasher);
+ upstream_crates.hash_stable(&mut hcx, &mut stable_hasher);
+ source_file_names.hash_stable(&mut hcx, &mut stable_hasher);
+ tcx.sess.opts.dep_tracking_hash(true).hash_stable(&mut hcx, &mut stable_hasher);
+ tcx.sess.local_crate_disambiguator().to_fingerprint().hash_stable(&mut hcx, &mut stable_hasher);
+
+ let crate_hash: Fingerprint = stable_hasher.finish();
+ Svh::new(crate_hash.to_smaller_hash())
+}
+
+fn upstream_crates(cstore: &dyn CrateStore) -> Vec<(Symbol, Fingerprint, Svh)> {
+ let mut upstream_crates: Vec<_> = cstore
+ .crates_untracked()
+ .iter()
+ .map(|&cnum| {
+ let name = cstore.crate_name_untracked(cnum);
+ let disambiguator = cstore.crate_disambiguator_untracked(cnum).to_fingerprint();
+ let hash = cstore.crate_hash_untracked(cnum);
+ (name, disambiguator, hash)
+ })
+ .collect();
+ upstream_crates.sort_unstable_by_key(|&(name, dis, _)| (name.as_str(), dis));
+ upstream_crates
}
fn hir_id_to_string(map: &Map<'_>, id: HirId) -> String {
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>>,
+}
+
+#[derive(Debug)]
+pub struct IndexedHir<'hir> {
+ map: IndexVec<LocalDefId, HirOwnerData<'hir>>,
+ parenting: FxHashMap<LocalDefId, HirId>,
+}
+
#[derive(Debug)]
pub struct Owner<'tcx> {
- parent: HirId,
node: Node<'tcx>,
}
impl<'a, 'tcx> HashStable<StableHashingContext<'a>> for Owner<'tcx> {
fn hash_stable(&self, hcx: &mut StableHashingContext<'a>, hasher: &mut StableHasher) {
- let Owner { parent, node } = self;
- hcx.while_hashing_hir_bodies(false, |hcx| {
- parent.hash_stable(hcx, hasher);
- node.hash_stable(hcx, hasher);
- });
+ let Owner { node } = self;
+ hcx.while_hashing_hir_bodies(false, |hcx| node.hash_stable(hcx, hasher));
}
}
};
providers.hir_crate = |tcx, _| tcx.untracked_crate;
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(LOCAL_CRATE).map[id].signature;
providers.hir_owner_nodes = |tcx, id| tcx.index_hir(LOCAL_CRATE).map[id].with_bodies.as_deref();
+ providers.hir_owner_parent = |tcx, id| {
+ let index = tcx.index_hir(LOCAL_CRATE);
+ index.parenting.get(&id).copied().unwrap_or(CRATE_HIR_ID)
+ };
providers.hir_attrs = |tcx, id| AttributeMap { map: &tcx.untracked_crate.attrs, prefix: id };
providers.def_span = |tcx, def_id| tcx.hir().span_if_local(def_id).unwrap_or(DUMMY_SP);
providers.fn_arg_names = |tcx, id| {
#![feature(control_flow_enum)]
#![feature(associated_type_defaults)]
#![feature(iter_zip)]
+#![feature(thread_local_const_init)]
#![recursion_limit = "512"]
#[macro_use]
// emit shouldn't be automatically fixed by rustfix.
err.allow_suggestions(false);
- // If this is a future incompatible lint it'll become a hard error, so
- // we have to emit *something*. Also, if this lint occurs in the
- // expansion of a macro from an external crate, allow individual lints
- // to opt-out from being reported.
- if future_incompatible.is_none() && !lint.report_in_external_macro {
+ // If this is a future incompatible that is not an edition fixing lint
+ // it'll become a hard error, so we have to emit *something*. Also,
+ // if this lint occurs in the expansion of a macro from an external crate,
+ // allow individual lints to opt-out from being reported.
+ let not_future_incompatible =
+ future_incompatible.map(|f| f.edition.is_some()).unwrap_or(true);
+ if not_future_incompatible && !lint.report_in_external_macro {
err.cancel();
// Don't continue further, since we don't want to have
// `diag_span_note_once` called for a diagnostic that isn't emitted.
"{}",
match *self {
CheckInAllocMsg::MemoryAccessTest => "memory access",
- CheckInAllocMsg::NullPointerTest => "NULL pointer test",
+ CheckInAllocMsg::NullPointerTest => "null pointer test",
CheckInAllocMsg::PointerArithmeticTest => "pointer arithmetic",
CheckInAllocMsg::InboundsTest => "inbounds test",
}
allocation_size.bytes()
),
DanglingIntPointer(_, CheckInAllocMsg::NullPointerTest) => {
- write!(f, "NULL pointer is not allowed for this operation")
+ write!(f, "null pointer is not allowed for this operation")
}
DanglingIntPointer(i, msg) => {
write!(f, "{} failed: 0x{:x} is not a valid pointer", msg, i)
BorrowKind::Mut { allow_two_phase_borrow } => allow_two_phase_borrow,
}
}
+
+ pub fn describe_mutability(&self) -> String {
+ match *self {
+ BorrowKind::Shared | BorrowKind::Shallow | BorrowKind::Unique => {
+ "immutable".to_string()
+ }
+ BorrowKind::Mut { .. } => "mutable".to_string(),
+ }
+ }
}
///////////////////////////////////////////////////////////////////////////
}
/// Format the message arguments for the `assert(cond, msg..)` terminator in MIR printing.
- fn fmt_assert_args<W: Write>(&self, f: &mut W) -> fmt::Result
+ pub fn fmt_assert_args<W: Write>(&self, f: &mut W) -> fmt::Result
where
O: Debug,
{
};
let mut struct_fmt = fmt.debug_struct(&name);
+ // FIXME(project-rfc-2229#48): This should be a list of capture names/places
if let Some(upvars) = tcx.upvars_mentioned(def_id) {
for (&var_id, place) in iter::zip(upvars.keys(), places) {
let var_name = tcx.hir().name(var_id);
let name = format!("[generator@{:?}]", tcx.hir().span(hir_id));
let mut struct_fmt = fmt.debug_struct(&name);
+ // FIXME(project-rfc-2229#48): This should be a list of capture names/places
if let Some(upvars) = tcx.upvars_mentioned(def_id) {
for (&var_id, place) in iter::zip(upvars.keys(), places) {
let var_name = tcx.hir().name(var_id);
),
DerefOfRawPointer => (
"dereference of raw pointer",
- "raw pointers may be NULL, dangling or unaligned; they can violate aliasing rules \
+ "raw pointers may be null, dangling or unaligned; they can violate aliasing rules \
and cause data races: all of these are undefined behavior",
),
AssignToDroppingUnionField => (
/// The indexed HIR. This can be conveniently accessed by `tcx.hir()`.
/// Avoid calling this query directly.
- query index_hir(_: CrateNum) -> &'tcx map::IndexedHir<'tcx> {
+ query index_hir(_: CrateNum) -> &'tcx crate::hir::IndexedHir<'tcx> {
eval_always
no_hash
desc { "index HIR" }
desc { |tcx| "HIR owner of `{}`", tcx.def_path_str(key.to_def_id()) }
}
+ /// Gives access to the HIR node's parent for the HIR owner `key`.
+ ///
+ /// This can be conveniently accessed by methods on `tcx.hir()`.
+ /// Avoid calling this query directly.
+ query hir_owner_parent(key: LocalDefId) -> hir::HirId {
+ eval_always
+ desc { |tcx| "HIR parent of `{}`", tcx.def_path_str(key.to_def_id()) }
+ }
+
/// Gives access to the HIR nodes and bodies inside the HIR owner `key`.
///
/// This can be conveniently accessed by methods on `tcx.hir()`.
}
impl CapturedPlace<'tcx> {
+ pub fn to_string(&self, tcx: TyCtxt<'tcx>) -> String {
+ place_to_string_for_capture(tcx, &self.place)
+ }
+
/// Returns the hir-id of the root variable for the captured place.
/// e.g., if `a.b.c` was captured, would return the hir-id for `a`.
pub fn get_root_variable(&self) -> hir::HirId {
}
}
+ /// Return span pointing to use that resulted in selecting the captured path
+ pub fn get_path_span(&self, tcx: TyCtxt<'tcx>) -> Span {
+ if let Some(path_expr_id) = self.info.path_expr_id {
+ tcx.hir().span(path_expr_id)
+ } else if let Some(capture_kind_expr_id) = self.info.capture_kind_expr_id {
+ tcx.hir().span(capture_kind_expr_id)
+ } else {
+ // Fallback on upvars mentioned if neither path or capture expr id is captured
+
+ // Safe to unwrap since we know this place is captured by the closure, therefore the closure must have upvars.
+ tcx.upvars_mentioned(self.get_closure_local_def_id()).unwrap()
+ [&self.get_root_variable()]
+ .span
+ }
+ }
+
/// Return span pointing to use that resulted in selecting the current capture kind
pub fn get_capture_kind_span(&self, tcx: TyCtxt<'tcx>) -> Span {
if let Some(capture_kind_expr_id) = self.info.capture_kind_expr_id {
#[cfg(not(parallel_compiler))]
thread_local! {
/// A thread local variable that stores a pointer to the current `ImplicitCtxt`.
- static TLV: Cell<usize> = Cell::new(0);
+ static TLV: Cell<usize> = const { Cell::new(0) };
}
/// Sets TLV to `value` during the call to `f`.
&ty::Infer(infer) => {
self.add_flags(TypeFlags::STILL_FURTHER_SPECIALIZABLE);
match infer {
- ty::FreshTy(_) | ty::FreshIntTy(_) | ty::FreshFloatTy(_) => {}
+ ty::FreshTy(_) | ty::FreshIntTy(_) | ty::FreshFloatTy(_) => {
+ self.add_flags(TypeFlags::HAS_TY_FRESH)
+ }
ty::TyVar(_) | ty::IntVar(_) | ty::FloatVar(_) => {
self.add_flags(TypeFlags::HAS_TY_INFER)
ty::ConstKind::Infer(infer) => {
self.add_flags(TypeFlags::STILL_FURTHER_SPECIALIZABLE);
match infer {
- InferConst::Fresh(_) => {}
+ InferConst::Fresh(_) => self.add_flags(TypeFlags::HAS_CT_FRESH),
InferConst::Var(_) => self.add_flags(TypeFlags::HAS_CT_INFER),
}
}
}
thread_local! {
- static FORCE_IMPL_FILENAME_LINE: Cell<bool> = Cell::new(false);
- static SHOULD_PREFIX_WITH_CRATE: Cell<bool> = Cell::new(false);
- static NO_TRIMMED_PATH: Cell<bool> = Cell::new(false);
- static NO_QUERIES: Cell<bool> = Cell::new(false);
+ static FORCE_IMPL_FILENAME_LINE: Cell<bool> = const { Cell::new(false) };
+ static SHOULD_PREFIX_WITH_CRATE: Cell<bool> = const { Cell::new(false) };
+ static NO_TRIMMED_PATH: Cell<bool> = const { Cell::new(false) };
+ static NO_QUERIES: Cell<bool> = const { Cell::new(false) };
}
/// Avoids running any queries during any prints that occur
use crate::dep_graph;
use crate::hir::exports::Export;
-use crate::hir::map;
use crate::infer::canonical::{self, Canonical};
use crate::lint::LintLevelMap;
use crate::middle::codegen_fn_attrs::CodegenFnAttrs;
);
err.span_label(span, format!("use of possibly-uninitialized {}", item_msg));
- use_spans.var_span_label(
+ use_spans.var_span_label_path_only(
&mut err,
format!("{} occurs due to use{}", desired_action.as_noun(), use_spans.describe()),
);
partially_str,
move_spans.describe()
),
+ "moved",
);
}
}
}
}
- use_spans.var_span_label(
+ use_spans.var_span_label_path_only(
&mut err,
format!("{} occurs due to use{}", desired_action.as_noun(), use_spans.describe()),
);
err.span_label(borrow_span, format!("borrow of {} occurs here", borrow_msg));
err.span_label(span, format!("move out of {} occurs here", value_msg));
- borrow_spans.var_span_label(
+ borrow_spans.var_span_label_path_only(
&mut err,
format!("borrow occurs due to use{}", borrow_spans.describe()),
);
- move_spans
- .var_span_label(&mut err, format!("move occurs due to use{}", move_spans.describe()));
+ move_spans.var_span_label(
+ &mut err,
+ format!("move occurs due to use{}", move_spans.describe()),
+ "moved",
+ );
self.explain_why_borrow_contains_point(location, borrow, None)
.add_explanation_to_diagnostic(
let use_spans = self.move_spans(place.as_ref(), location);
let span = use_spans.var_or_use();
+ // If the attempted use is in a closure then we do not care about the path span of the place we are currently trying to use
+ // we call `var_span_label` on `borrow_spans` to annotate if the existing borrow was in a closure
let mut err = self.cannot_use_when_mutably_borrowed(
span,
&self.describe_any_place(place.as_ref()),
&self.describe_any_place(borrow.borrowed_place.as_ref()),
);
- borrow_spans.var_span_label(&mut err, {
- let place = &borrow.borrowed_place;
- let desc_place = self.describe_any_place(place.as_ref());
- format!("borrow occurs due to use of {}{}", desc_place, borrow_spans.describe())
- });
+ borrow_spans.var_span_label(
+ &mut err,
+ {
+ let place = &borrow.borrowed_place;
+ let desc_place = self.describe_any_place(place.as_ref());
+ format!("borrow occurs due to use of {}{}", desc_place, borrow_spans.describe())
+ },
+ "mutable",
+ );
self.explain_why_borrow_contains_point(location, borrow, None)
.add_explanation_to_diagnostic(
desc_place,
borrow_spans.describe(),
),
+ "immutable",
);
return err;
if issued_spans == borrow_spans {
borrow_spans.var_span_label(
&mut err,
- format!("borrows occur due to use of {}{}", desc_place, borrow_spans.describe()),
+ format!("borrows occur due to use of {}{}", desc_place, borrow_spans.describe(),),
+ gen_borrow_kind.describe_mutability(),
);
} else {
let borrow_place = &issued_borrow.borrowed_place;
borrow_place_desc,
issued_spans.describe(),
),
+ issued_borrow.kind.describe_mutability(),
);
borrow_spans.var_span_label(
desc_place,
borrow_spans.describe(),
),
+ gen_borrow_kind.describe_mutability(),
);
}
self.prefixes(borrow.borrowed_place.as_ref(), PrefixSet::All).last().unwrap();
let borrow_spans = self.retrieve_borrow_spans(borrow);
- let borrow_span = borrow_spans.var_or_use();
+ let borrow_span = borrow_spans.var_or_use_path_span();
assert!(root_place.projection.is_empty());
let proper_span = self.body.local_decls[root_place.local].source_info.span;
location, name, borrow, drop_span, borrow_spans
);
- let borrow_span = borrow_spans.var_or_use();
+ let borrow_span = borrow_spans.var_or_use_path_span();
if let BorrowExplanation::MustBeValidFor {
category,
span,
loan_spans.var_span_label(
&mut err,
format!("borrow occurs due to use{}", loan_spans.describe()),
+ loan.kind.describe_mutability(),
);
err.buffer(&mut self.errors_buffer);
let mut err = self.cannot_assign_to_borrowed(span, loan_span, &descr_place);
- loan_spans
- .var_span_label(&mut err, format!("borrow occurs due to use{}", loan_spans.describe()));
+ loan_spans.var_span_label(
+ &mut err,
+ format!("borrow occurs due to use{}", loan_spans.describe()),
+ loan.kind.describe_mutability(),
+ );
self.explain_why_borrow_contains_point(location, loan, None).add_explanation_to_diagnostic(
self.infcx.tcx,
#[derive(Debug)]
pub(in crate::borrow_check) enum BorrowExplanation {
- UsedLater(LaterUseKind, Span),
- UsedLaterInLoop(LaterUseKind, Span),
+ UsedLater(LaterUseKind, Span, Option<Span>),
+ UsedLaterInLoop(LaterUseKind, Span, Option<Span>),
UsedLaterWhenDropped {
drop_loc: Location,
dropped_local: Local,
borrow_span: Option<Span>,
) {
match *self {
- BorrowExplanation::UsedLater(later_use_kind, var_or_use_span) => {
+ BorrowExplanation::UsedLater(later_use_kind, var_or_use_span, path_span) => {
let message = match later_use_kind {
LaterUseKind::TraitCapture => "captured here by trait object",
LaterUseKind::ClosureCapture => "captured here by closure",
LaterUseKind::FakeLetRead => "stored here",
LaterUseKind::Other => "used here",
};
- if !borrow_span.map_or(false, |sp| sp.overlaps(var_or_use_span)) {
- err.span_label(
- var_or_use_span,
- format!("{}borrow later {}", borrow_desc, message),
- );
+ // We can use `var_or_use_span` if either `path_span` is not present, or both spans are the same
+ if path_span.map(|path_span| path_span == var_or_use_span).unwrap_or(true) {
+ if borrow_span.map(|sp| !sp.overlaps(var_or_use_span)).unwrap_or(true) {
+ err.span_label(
+ var_or_use_span,
+ format!("{}borrow later {}", borrow_desc, message),
+ );
+ }
+ } else {
+ // path_span must be `Some` as otherwise the if condition is true
+ let path_span = path_span.unwrap();
+ // path_span is only present in the case of closure capture
+ assert!(matches!(later_use_kind, LaterUseKind::ClosureCapture));
+ if !borrow_span.map_or(false, |sp| sp.overlaps(var_or_use_span)) {
+ let path_label = "used here by closure";
+ let capture_kind_label = message;
+ err.span_label(
+ var_or_use_span,
+ format!("{}borrow later {}", borrow_desc, capture_kind_label),
+ );
+ err.span_label(path_span, path_label);
+ }
}
}
- BorrowExplanation::UsedLaterInLoop(later_use_kind, var_or_use_span) => {
+ BorrowExplanation::UsedLaterInLoop(later_use_kind, var_or_use_span, path_span) => {
let message = match later_use_kind {
LaterUseKind::TraitCapture => {
"borrow captured here by trait object, in later iteration of loop"
LaterUseKind::FakeLetRead => "borrow later stored here",
LaterUseKind::Other => "borrow used here, in later iteration of loop",
};
- err.span_label(var_or_use_span, format!("{}{}", borrow_desc, message));
+ // We can use `var_or_use_span` if either `path_span` is not present, or both spans are the same
+ if path_span.map(|path_span| path_span == var_or_use_span).unwrap_or(true) {
+ err.span_label(var_or_use_span, format!("{}{}", borrow_desc, message));
+ } else {
+ // path_span must be `Some` as otherwise the if condition is true
+ let path_span = path_span.unwrap();
+ // path_span is only present in the case of closure capture
+ assert!(matches!(later_use_kind, LaterUseKind::ClosureCapture));
+ if borrow_span.map(|sp| !sp.overlaps(var_or_use_span)).unwrap_or(true) {
+ let path_label = "used here by closure";
+ let capture_kind_label = message;
+ err.span_label(
+ var_or_use_span,
+ format!("{}borrow later {}", borrow_desc, capture_kind_label),
+ );
+ err.span_label(path_span, path_label);
+ }
+ }
}
BorrowExplanation::UsedLaterWhenDropped {
drop_loc,
let borrow_location = location;
if self.is_use_in_later_iteration_of_loop(borrow_location, location) {
let later_use = self.later_use_kind(borrow, spans, location);
- BorrowExplanation::UsedLaterInLoop(later_use.0, later_use.1)
+ BorrowExplanation::UsedLaterInLoop(later_use.0, later_use.1, later_use.2)
} else {
// Check if the location represents a `FakeRead`, and adapt the error
// message to the `FakeReadCause` it is from: in particular,
// the ones inserted in optimized `let var = <expr>` patterns.
let later_use = self.later_use_kind(borrow, spans, location);
- BorrowExplanation::UsedLater(later_use.0, later_use.1)
+ BorrowExplanation::UsedLater(later_use.0, later_use.1, later_use.2)
}
}
}
/// Determine how the borrow was later used.
+ /// First span returned points to the location of the conflicting use
+ /// Second span if `Some` is returned in the case of closures and points
+ /// to the use of the path
fn later_use_kind(
&self,
borrow: &BorrowData<'tcx>,
use_spans: UseSpans<'tcx>,
location: Location,
- ) -> (LaterUseKind, Span) {
+ ) -> (LaterUseKind, Span, Option<Span>) {
match use_spans {
- UseSpans::ClosureUse { var_span, .. } => {
+ UseSpans::ClosureUse { capture_kind_span, path_span, .. } => {
// Used in a closure.
- (LaterUseKind::ClosureCapture, var_span)
+ (LaterUseKind::ClosureCapture, capture_kind_span, Some(path_span))
}
UseSpans::PatUse(span)
| UseSpans::OtherUse(span)
}
}
};
- return (LaterUseKind::Call, function_span);
+ return (LaterUseKind::Call, function_span, None);
} else {
LaterUseKind::Other
}
LaterUseKind::Other
};
- (kind, span)
+ (kind, span, None)
}
}
}
Span,
};
use rustc_target::abi::VariantIdx;
-use std::iter;
use super::borrow_set::BorrowData;
use super::MirBorrowckCtxt;
PlaceRef { local, projection: [proj_base @ .., elem] } => {
match elem {
ProjectionElem::Deref => {
- // FIXME(project-rfc_2229#36): print capture precisely here.
let upvar_field_projection = self.is_upvar_field_projection(place);
if let Some(field) = upvar_field_projection {
let var_index = field.index();
- let name = self.upvars[var_index].name.to_string();
+ let name = self.upvars[var_index].place.to_string(self.infcx.tcx);
if self.upvars[var_index].by_ref {
buf.push_str(&name);
} else {
let upvar_field_projection = self.is_upvar_field_projection(place);
if let Some(field) = upvar_field_projection {
let var_index = field.index();
- let name = self.upvars[var_index].name.to_string();
+ let name = self.upvars[var_index].place.to_string(self.infcx.tcx);
buf.push_str(&name);
} else {
let field_name = self
/// The span of the args of the closure, including the `move` keyword if
/// it's present.
args_span: Span,
- /// The span of the first use of the captured variable inside the closure.
- var_span: Span,
+ /// The span of the use resulting in capture kind
+ /// Check `ty::CaptureInfo` for more details
+ capture_kind_span: Span,
+ /// The span of the use resulting in the captured path
+ /// Check `ty::CaptureInfo` for more details
+ path_span: Span,
},
/// The access is caused by using a variable as the receiver of a method
/// that takes 'self'
}
}
+ /// Returns the span of `self`, in the case of a `ClosureUse` returns the `path_span`
+ pub(super) fn var_or_use_path_span(self) -> Span {
+ match self {
+ UseSpans::ClosureUse { path_span: span, .. }
+ | UseSpans::PatUse(span)
+ | UseSpans::OtherUse(span) => span,
+ UseSpans::FnSelfUse {
+ fn_call_span, kind: FnSelfUseKind::DerefCoercion { .. }, ..
+ } => fn_call_span,
+ UseSpans::FnSelfUse { var_span, .. } => var_span,
+ }
+ }
+
+ /// Returns the span of `self`, in the case of a `ClosureUse` returns the `capture_kind_span`
pub(super) fn var_or_use(self) -> Span {
match self {
- UseSpans::ClosureUse { var_span: span, .. }
+ UseSpans::ClosureUse { capture_kind_span: span, .. }
| UseSpans::PatUse(span)
| UseSpans::OtherUse(span) => span,
UseSpans::FnSelfUse {
}
}
+ // Add a span label to the use of the captured variable, if it exists.
+ // only adds label to the `path_span`
+ pub(super) fn var_span_label_path_only(
+ self,
+ err: &mut DiagnosticBuilder<'_>,
+ message: impl Into<String>,
+ ) {
+ if let UseSpans::ClosureUse { path_span, .. } = self {
+ err.span_label(path_span, message);
+ }
+ }
+
// Add a span label to the use of the captured variable, if it exists.
pub(super) fn var_span_label(
self,
err: &mut DiagnosticBuilder<'_>,
message: impl Into<String>,
+ kind_desc: impl Into<String>,
) {
- if let UseSpans::ClosureUse { var_span, .. } = self {
- err.span_label(var_span, message);
+ if let UseSpans::ClosureUse { capture_kind_span, path_span, .. } = self {
+ if capture_kind_span == path_span {
+ err.span_label(capture_kind_span, message);
+ } else {
+ let capture_kind_label =
+ format!("capture is {} because of use here", kind_desc.into());
+ let path_label = message;
+ err.span_label(capture_kind_span, capture_kind_label);
+ err.span_label(path_span, path_label);
+ }
}
}
box AggregateKind::Closure(def_id, _)
| box AggregateKind::Generator(def_id, _, _) => {
debug!("move_spans: def_id={:?} places={:?}", def_id, places);
- if let Some((args_span, generator_kind, var_span)) =
+ if let Some((args_span, generator_kind, capture_kind_span, path_span)) =
self.closure_span(*def_id, moved_place, places)
{
- return ClosureUse { generator_kind, args_span, var_span };
+ return ClosureUse {
+ generator_kind,
+ args_span,
+ capture_kind_span,
+ path_span,
+ };
}
}
_ => {}
| FakeReadCause::ForLet(Some(closure_def_id)) => {
debug!("move_spans: def_id={:?} place={:?}", closure_def_id, place);
let places = &[Operand::Move(*place)];
- if let Some((args_span, generator_kind, var_span)) =
+ if let Some((args_span, generator_kind, capture_kind_span, path_span)) =
self.closure_span(closure_def_id, moved_place, places)
{
- return ClosureUse { generator_kind, args_span, var_span };
+ return ClosureUse {
+ generator_kind,
+ args_span,
+ capture_kind_span,
+ path_span,
+ };
}
}
_ => {}
"borrow_spans: def_id={:?} is_generator={:?} places={:?}",
def_id, is_generator, places
);
- if let Some((args_span, generator_kind, var_span)) =
+ if let Some((args_span, generator_kind, capture_kind_span, path_span)) =
self.closure_span(*def_id, Place::from(target).as_ref(), places)
{
- return ClosureUse { generator_kind, args_span, var_span };
+ return ClosureUse { generator_kind, args_span, capture_kind_span, path_span };
} else {
return OtherUse(use_span);
}
OtherUse(use_span)
}
- /// Finds the span of a captured variable within a closure or generator.
+ /// Finds the spans of a captured place within a closure or generator.
+ /// The first span is the location of the use resulting in the capture kind of the capture
+ /// The second span is the location the use resulting in the captured path of the capture
fn closure_span(
&self,
def_id: DefId,
target_place: PlaceRef<'tcx>,
places: &[Operand<'tcx>],
- ) -> Option<(Span, Option<GeneratorKind>, Span)> {
+ ) -> Option<(Span, Option<GeneratorKind>, Span, Span)> {
debug!(
"closure_span: def_id={:?} target_place={:?} places={:?}",
def_id, target_place, places
let expr = &self.infcx.tcx.hir().expect_expr(hir_id).kind;
debug!("closure_span: hir_id={:?} expr={:?}", hir_id, expr);
if let hir::ExprKind::Closure(.., body_id, args_span, _) = expr {
- for (captured_place, place) in iter::zip(
- self.infcx.tcx.typeck(def_id.expect_local()).closure_min_captures_flattened(def_id),
- places,
- ) {
- let upvar_hir_id = captured_place.get_root_variable();
- //FIXME(project-rfc-2229#8): Use better span from captured_place
- let span = self.infcx.tcx.upvars_mentioned(local_did)?[&upvar_hir_id].span;
+ for (captured_place, place) in self
+ .infcx
+ .tcx
+ .typeck(def_id.expect_local())
+ .closure_min_captures_flattened(def_id)
+ .zip(places)
+ {
match place {
Operand::Copy(place) | Operand::Move(place)
if target_place == place.as_ref() =>
let body = self.infcx.tcx.hir().body(*body_id);
let generator_kind = body.generator_kind();
- // If we have a more specific span available, point to that.
- // We do this even though this span might be part of a borrow error
- // message rather than a move error message. Our goal is to point
- // to a span that shows why the upvar is used in the closure,
- // so a move-related span is as good as any (and potentially better,
- // if the overall error is due to a move of the upvar).
-
- let usage_span = match captured_place.info.capture_kind {
- ty::UpvarCapture::ByValue(Some(span)) => span,
- _ => span,
- };
- return Some((*args_span, generator_kind, usage_span));
+ return Some((
+ *args_span,
+ generator_kind,
+ captured_place.get_capture_kind_span(self.infcx.tcx),
+ captured_place.get_path_span(self.infcx.tcx),
+ ));
}
_ => {}
}
};
let upvar = &self.upvars[upvar_field.unwrap().index()];
- // FIXME(project-rfc-2229#8): Improve borrow-check diagnostics in case of precise
- // capture.
let upvar_hir_id = upvar.place.get_root_variable();
- let upvar_name = upvar.name;
+ let upvar_name = upvar.place.to_string(self.infcx.tcx);
let upvar_span = self.infcx.tcx.hir().span(upvar_hir_id);
let place_name = self.describe_any_place(move_place.as_ref());
self.note_type_does_not_implement_copy(err, &place_desc, place_ty, Some(span), "");
use_spans.args_span_label(err, format!("move out of {} occurs here", place_desc));
- use_spans
- .var_span_label(err, format!("move occurs due to use{}", use_spans.describe()));
+ use_spans.var_span_label(
+ err,
+ format!("move occurs due to use{}", use_spans.describe()),
+ "moved",
+ );
}
}
}
if self.is_upvar_field_projection(access_place.as_ref()).is_some() {
reason = ", as it is not declared as mutable".to_string();
} else {
- let name = self.upvars[upvar_index.index()].name;
+ let name = self.upvars[upvar_index.index()].place.to_string(self.infcx.tcx);
reason = format!(", as `{}` is not declared as mutable", name);
}
}
"mutable borrow occurs due to use of {} in closure",
self.describe_any_place(access_place.as_ref()),
),
+ "mutable",
);
borrow_span
}
diag.span_label(*span, message);
+ // FIXME(project-rfc-2229#48): This should store a captured_place not a hir id
if let ReturnConstraint::ClosureUpvar(upvar) = kind {
let def_id = match self.regioncx.universal_regions().defining_ty {
DefiningTy::Closure(def_id, _) => def_id,
// FIXME(eddyb) perhaps move this somewhere more centrally.
#[derive(Debug)]
crate struct Upvar<'tcx> {
- // FIXME(project-rfc_2229#36): print capture precisely here.
- name: Symbol,
-
place: CapturedPlace<'tcx>,
/// If true, the capture is behind a reference.
let upvars: Vec<_> = tables
.closure_min_captures_flattened(def.did.to_def_id())
.map(|captured_place| {
- let var_hir_id = captured_place.get_root_variable();
let capture = captured_place.info.capture_kind;
let by_ref = match capture {
ty::UpvarCapture::ByValue(_) => false,
ty::UpvarCapture::ByRef(..) => true,
};
- Upvar { name: tcx.hir().name(var_hir_id), place: captured_place.clone(), by_ref }
+ Upvar { place: captured_place.clone(), by_ref }
})
.collect();
let b = self.read_immediate(&args[1])?.to_scalar()?;
// Special case: if both scalars are *equal integers*
- // and not NULL, we pretend there is an allocation of size 0 right there,
- // and their offset is 0. (There's never a valid object at NULL, making it an
+ // and not null, we pretend there is an allocation of size 0 right there,
+ // and their offset is 0. (There's never a valid object at null, making it an
// exception from the exception.)
// This is the dual to the special exception for offset-by-0
// in the inbounds pointer offset operation (see the Miri code, `src/operator.rs`).
/// Offsets a pointer by some multiple of its type, returning an error if the pointer leaves its
/// allocation. For integer pointers, we consider each of them their own tiny allocation of size
- /// 0, so offset-by-0 (and only 0) is okay -- except that NULL cannot be offset by _any_ value.
+ /// 0, so offset-by-0 (and only 0) is okay -- except that null cannot be offset by _any_ value.
pub fn ptr_offset_inbounds(
&self,
ptr: Scalar<M::PointerTag>,
// pointers to be properly aligned (unlike a read/write operation).
let min_ptr = if offset_bytes >= 0 { ptr } else { offset_ptr };
let size = offset_bytes.unsigned_abs();
- // This call handles checking for integer/NULL pointers.
+ // This call handles checking for integer/null pointers.
self.memory.check_ptr_access_align(
min_ptr,
Size::from_bytes(size),
//!
//! Generally, we use `Pointer` to denote memory addresses. However, some operations
//! have a "size"-like parameter, and they take `Scalar` for the address because
-//! if the size is 0, then the pointer can also be a (properly aligned, non-NULL)
+//! if the size is 0, then the pointer can also be a (properly aligned, non-null)
//! integer. It is crucial that these operations call `check_align` *before*
//! short-circuiting the empty case!
/// Map for "extra" function pointers.
extra_fn_ptr_map: FxHashMap<AllocId, M::ExtraFnVal>,
- /// To be able to compare pointers with NULL, and to check alignment for accesses
+ /// To be able to compare pointers with null, and to check alignment for accesses
/// to ZSTs (where pointers may dangle), we keep track of the size even for allocations
/// that do not exist any more.
// FIXME: this should not be public, but interning currently needs access to it
Ok(bits) => {
let bits = u64::try_from(bits).unwrap(); // it's ptr-sized
assert!(size.bytes() == 0);
- // Must be non-NULL.
+ // Must be non-null.
if bits == 0 {
throw_ub!(DanglingIntPointer(0, msg))
}
Err(ptr) => {
let (allocation_size, alloc_align) =
self.get_size_and_align(ptr.alloc_id, AllocCheck::Dereferenceable)?;
- // Test bounds. This also ensures non-NULL.
+ // Test bounds. This also ensures non-null.
// It is sufficient to check this for the end pointer. The addition
// checks for overflow.
let end_ptr = ptr.offset(size, self)?;
})
}
- /// Test if the pointer might be NULL.
+ /// Test if the pointer might be null.
pub fn ptr_may_be_null(&self, ptr: Pointer<M::PointerTag>) -> bool {
let (size, _align) = self
.get_size_and_align(ptr.alloc_id, AllocCheck::MaybeDead)
assert!(place.mplace.align <= align, "dynamic alignment less strict than static one?");
// Check (stricter) dynamic alignment, unless forced otherwise.
place.mplace.align = force_align.unwrap_or(align);
- // When dereferencing a pointer, it must be non-NULL, aligned, and live.
+ // When dereferencing a pointer, it must be non-null, aligned, and live.
if let Some(ptr) = self.check_mplace_access(&place, Some(size))? {
place.mplace.ptr = ptr.into();
}
has.bytes()
},
err_ub!(DanglingIntPointer(0, _)) =>
- { "a NULL {}", kind },
+ { "a null {}", kind },
err_ub!(DanglingIntPointer(i, _)) =>
{ "a dangling {} (address 0x{:x} is unallocated)", kind, i },
err_ub!(PointerOutOfBounds { .. }) =>
let bits = match value.to_bits_or_ptr(op.layout.size, self.ecx) {
Err(ptr) => {
if lo == 1 && hi == max_hi {
- // Only NULL is the niche. So make sure the ptr is NOT NULL.
+ // Only null is the niche. So make sure the ptr is NOT null.
if self.ecx.memory.ptr_may_be_null(ptr) {
throw_validation_failure!(self.path,
- { "a potentially NULL pointer" }
+ { "a potentially null pointer" }
expected {
"something that cannot possibly fail to be {}",
wrapping_range_format(valid_range, max_hi)
use rustc_middle::ty::TyCtxt;
use rustc_span::source_map::original_sp;
-use rustc_span::{BytePos, Span};
+use rustc_span::{BytePos, ExpnKind, MacroKind, Span, Symbol};
+use std::cell::RefCell;
use std::cmp::Ordering;
#[derive(Debug, Copy, Clone)]
#[derive(Debug, Clone)]
pub(super) struct CoverageSpan {
pub span: Span,
+ pub expn_span: Span,
+ pub current_macro_or_none: RefCell<Option<Option<Symbol>>>,
pub bcb: BasicCoverageBlock,
pub coverage_statements: Vec<CoverageStatement>,
pub is_closure: bool,
impl CoverageSpan {
pub fn for_fn_sig(fn_sig_span: Span) -> Self {
- Self { span: fn_sig_span, bcb: START_BCB, coverage_statements: vec![], is_closure: false }
+ Self {
+ span: fn_sig_span,
+ expn_span: fn_sig_span,
+ current_macro_or_none: Default::default(),
+ bcb: START_BCB,
+ coverage_statements: vec![],
+ is_closure: false,
+ }
}
pub fn for_statement(
statement: &Statement<'tcx>,
span: Span,
+ expn_span: Span,
bcb: BasicCoverageBlock,
bb: BasicBlock,
stmt_index: usize,
Self {
span,
+ expn_span,
+ current_macro_or_none: Default::default(),
bcb,
coverage_statements: vec![CoverageStatement::Statement(bb, span, stmt_index)],
is_closure,
}
}
- pub fn for_terminator(span: Span, bcb: BasicCoverageBlock, bb: BasicBlock) -> Self {
+ pub fn for_terminator(
+ span: Span,
+ expn_span: Span,
+ bcb: BasicCoverageBlock,
+ bb: BasicBlock,
+ ) -> Self {
Self {
span,
+ expn_span,
+ current_macro_or_none: Default::default(),
bcb,
coverage_statements: vec![CoverageStatement::Terminator(bb, span)],
is_closure: false,
.collect::<Vec<_>>()
.join("\n")
}
+
+ /// If the span is part of a macro, returns the macro name symbol.
+ pub fn current_macro(&self) -> Option<Symbol> {
+ self.current_macro_or_none
+ .borrow_mut()
+ .get_or_insert_with(|| {
+ if let ExpnKind::Macro(MacroKind::Bang, current_macro) =
+ self.expn_span.ctxt().outer_expn_data().kind
+ {
+ return Some(current_macro);
+ }
+ None
+ })
+ .map(|symbol| symbol)
+ }
+
+ /// If the span is part of a macro, and the macro is visible (expands directly to the given
+ /// body_span), returns the macro name symbol.
+ pub fn visible_macro(&self, body_span: Span) -> Option<Symbol> {
+ if let Some(current_macro) = self.current_macro() {
+ if self.expn_span.parent().unwrap_or_else(|| bug!("macro must have a parent")).ctxt()
+ == body_span.ctxt()
+ {
+ return Some(current_macro);
+ }
+ }
+ None
+ }
+
+ pub fn is_macro_expansion(&self) -> bool {
+ self.current_macro().is_some()
+ }
}
/// Converts the initial set of `CoverageSpan`s (one per MIR `Statement` or `Terminator`) into a
/// iteration.
some_curr: Option<CoverageSpan>,
- /// The original `span` for `curr`, in case the `curr` span is modified.
+ /// The original `span` for `curr`, in case `curr.span()` is modified. The `curr_original_span`
+ /// **must not be mutated** (except when advancing to the next `curr`), even if `curr.span()`
+ /// is mutated.
curr_original_span: Span,
/// The CoverageSpan from a prior iteration; typically assigned from that iteration's `curr`.
/// If that `curr` was discarded, `prev` retains its value from the previous iteration.
some_prev: Option<CoverageSpan>,
- /// Assigned from `curr_original_span` from the previous iteration.
+ /// Assigned from `curr_original_span` from the previous iteration. The `prev_original_span`
+ /// **must not be mutated** (except when advancing to the next `prev`), even if `prev.span()`
+ /// is mutated.
prev_original_span: Span,
+ /// A copy of the expn_span from the prior iteration.
+ prev_expn_span: Option<Span>,
+
/// One or more `CoverageSpan`s with the same `Span` but different `BasicCoverageBlock`s, and
/// no `BasicCoverageBlock` in this list dominates another `BasicCoverageBlock` in the list.
/// If a new `curr` span also fits this criteria (compared to an existing list of
curr_original_span: Span::with_root_ctxt(BytePos(0), BytePos(0)),
some_prev: None,
prev_original_span: Span::with_root_ctxt(BytePos(0), BytePos(0)),
+ prev_expn_span: None,
pending_dups: Vec::new(),
};
let sorted_spans = coverage_spans.mir_to_initial_sorted_coverage_spans();
coverage_spans.sorted_spans_iter = Some(sorted_spans.into_iter());
- coverage_spans.some_prev = coverage_spans.sorted_spans_iter.as_mut().unwrap().next();
- coverage_spans.prev_original_span =
- coverage_spans.some_prev.as_ref().expect("at least one span").span;
coverage_spans.to_refined_spans()
}
/// de-duplicated `CoverageSpan`s.
fn to_refined_spans(mut self) -> Vec<CoverageSpan> {
while self.next_coverage_span() {
- if self.curr().is_mergeable(self.prev()) {
+ if self.some_prev.is_none() {
+ debug!(" initial span");
+ self.check_invoked_macro_name_span();
+ } else if self.curr().is_mergeable(self.prev()) {
debug!(" same bcb (and neither is a closure), merge with prev={:?}", self.prev());
let prev = self.take_prev();
self.curr_mut().merge_from(prev);
+ self.check_invoked_macro_name_span();
// Note that curr.span may now differ from curr_original_span
} else if self.prev_ends_before_curr() {
debug!(
self.prev()
);
let prev = self.take_prev();
- self.refined_spans.push(prev);
+ self.push_refined_span(prev);
+ self.check_invoked_macro_name_span();
} else if self.prev().is_closure {
// drop any equal or overlapping span (`curr`) and keep `prev` to test again in the
// next iter
} else if self.curr().is_closure {
self.carve_out_span_for_closure();
} else if self.prev_original_span == self.curr().span {
- // Note that this compares the new span to `prev_original_span`, which may not
- // be the full `prev.span` (if merged during the previous iteration).
- self.hold_pending_dups_unless_dominated();
+ // Note that this compares the new (`curr`) span to `prev_original_span`.
+ // In this branch, the actual span byte range of `prev_original_span` is not
+ // important. What is important is knowing whether the new `curr` span was
+ // **originally** the same as the original span of `prev()`. The original spans
+ // reflect their original sort order, and for equal spans, conveys a partial
+ // ordering based on CFG dominator priority.
+ if self.prev().is_macro_expansion() && self.curr().is_macro_expansion() {
+ // Macros that expand to include branching (such as
+ // `assert_eq!()`, `assert_ne!()`, `info!()`, `debug!()`, or
+ // `trace!()) typically generate callee spans with identical
+ // ranges (typically the full span of the macro) for all
+ // `BasicBlocks`. This makes it impossible to distinguish
+ // the condition (`if val1 != val2`) from the optional
+ // branched statements (such as the call to `panic!()` on
+ // assert failure). In this case it is better (or less
+ // worse) to drop the optional branch bcbs and keep the
+ // non-conditional statements, to count when reached.
+ debug!(
+ " curr and prev are part of a macro expansion, and curr has the same span \
+ as prev, but is in a different bcb. Drop curr and keep prev for next iter. \
+ prev={:?}",
+ self.prev()
+ );
+ self.take_curr();
+ } else {
+ self.hold_pending_dups_unless_dominated();
+ }
} else {
self.cutoff_prev_at_overlapping_curr();
+ self.check_invoked_macro_name_span();
}
}
debug!(" AT END, adding last prev={:?}", self.prev());
let prev = self.take_prev();
- let CoverageSpans { pending_dups, mut refined_spans, .. } = self;
+ let pending_dups = self.pending_dups.split_off(0);
for dup in pending_dups {
debug!(" ...adding at least one pending dup={:?}", dup);
- refined_spans.push(dup);
+ self.push_refined_span(dup);
}
// Async functions wrap a closure that implements the body to be executed. The enclosing
// excluded. The closure's `Return` is the only one that will be counted. This provides
// adequate coverage, and more intuitive counts. (Avoids double-counting the closing brace
// of the function body.)
- let body_ends_with_closure = if let Some(last_covspan) = refined_spans.last() {
+ let body_ends_with_closure = if let Some(last_covspan) = self.refined_spans.last() {
last_covspan.is_closure && last_covspan.span.hi() == self.body_span.hi()
} else {
false
};
if !body_ends_with_closure {
- refined_spans.push(prev);
+ self.push_refined_span(prev);
}
// Remove `CoverageSpan`s derived from closures, originally added to ensure the coverage
// regions for the current function leave room for the closure's own coverage regions
// (injected separately, from the closure's own MIR).
- refined_spans.retain(|covspan| !covspan.is_closure);
- refined_spans
+ self.refined_spans.retain(|covspan| !covspan.is_closure);
+ self.refined_spans
+ }
+
+ fn push_refined_span(&mut self, covspan: CoverageSpan) {
+ let len = self.refined_spans.len();
+ if len > 0 {
+ let last = &mut self.refined_spans[len - 1];
+ if last.is_mergeable(&covspan) {
+ debug!(
+ "merging new refined span with last refined span, last={:?}, covspan={:?}",
+ last, covspan
+ );
+ last.merge_from(covspan);
+ return;
+ }
+ }
+ self.refined_spans.push(covspan)
+ }
+
+ fn check_invoked_macro_name_span(&mut self) {
+ if let Some(visible_macro) = self.curr().visible_macro(self.body_span) {
+ if self.prev_expn_span.map_or(true, |prev_expn_span| {
+ self.curr().expn_span.ctxt() != prev_expn_span.ctxt()
+ }) {
+ let merged_prefix_len = self.curr_original_span.lo() - self.curr().span.lo();
+ let after_macro_bang =
+ merged_prefix_len + BytePos(visible_macro.as_str().bytes().count() as u32 + 1);
+ let mut macro_name_cov = self.curr().clone();
+ self.curr_mut().span =
+ self.curr().span.with_lo(self.curr().span.lo() + after_macro_bang);
+ macro_name_cov.span =
+ macro_name_cov.span.with_hi(macro_name_cov.span.lo() + after_macro_bang);
+ debug!(
+ " and curr starts a new macro expansion, so add a new span just for \
+ the macro `{}!`, new span={:?}",
+ visible_macro, macro_name_cov
+ );
+ self.push_refined_span(macro_name_cov);
+ }
+ }
}
// Generate a set of `CoverageSpan`s from the filtered set of `Statement`s and `Terminator`s of
.iter()
.enumerate()
.filter_map(move |(index, statement)| {
- filtered_statement_span(statement, self.body_span).map(|span| {
- CoverageSpan::for_statement(statement, span, bcb, bb, index)
- })
+ filtered_statement_span(statement, self.body_span).map(
+ |(span, expn_span)| {
+ CoverageSpan::for_statement(
+ statement, span, expn_span, bcb, bb, index,
+ )
+ },
+ )
})
- .chain(
- filtered_terminator_span(data.terminator(), self.body_span)
- .map(|span| CoverageSpan::for_terminator(span, bcb, bb)),
- )
+ .chain(filtered_terminator_span(data.terminator(), self.body_span).map(
+ |(span, expn_span)| CoverageSpan::for_terminator(span, expn_span, bcb, bb),
+ ))
})
.collect()
}
let pending_dups = self.pending_dups.split_off(0);
for dup in pending_dups.into_iter() {
debug!(" ...adding at least one pending={:?}", dup);
- self.refined_spans.push(dup);
+ self.push_refined_span(dup);
}
} else {
self.pending_dups.clear();
/// Advance `prev` to `curr` (if any), and `curr` to the next `CoverageSpan` in sorted order.
fn next_coverage_span(&mut self) -> bool {
if let Some(curr) = self.some_curr.take() {
+ self.prev_expn_span = Some(curr.expn_span);
self.some_prev = Some(curr);
self.prev_original_span = self.curr_original_span;
}
while let Some(curr) = self.sorted_spans_iter.as_mut().unwrap().next() {
debug!("FOR curr={:?}", curr);
- if self.prev_starts_after_next(&curr) {
+ if self.some_prev.is_some() && self.prev_starts_after_next(&curr) {
debug!(
" prev.span starts after curr.span, so curr will be dropped (skipping past \
closure?); prev={:?}",
for mut dup in pending_dups.iter().cloned() {
dup.span = dup.span.with_hi(left_cutoff);
debug!(" ...and at least one pre_closure dup={:?}", dup);
- self.refined_spans.push(dup);
+ self.push_refined_span(dup);
}
}
- self.refined_spans.push(pre_closure);
+ self.push_refined_span(pre_closure);
}
if has_post_closure_span {
- // Update prev.span to start after the closure (and discard curr)
+ // Mutate `prev.span()` to start after the closure (and discard curr).
+ // (**NEVER** update `prev_original_span` because it affects the assumptions
+ // about how the `CoverageSpan`s are ordered.)
self.prev_mut().span = self.prev().span.with_lo(right_cutoff);
- self.prev_original_span = self.prev().span;
+ debug!(" Mutated prev.span to start after the closure. prev={:?}", self.prev());
for dup in pending_dups.iter_mut() {
+ debug!(" ...and at least one overlapping dup={:?}", dup);
dup.span = dup.span.with_lo(right_cutoff);
}
self.pending_dups.append(&mut pending_dups);
let closure_covspan = self.take_curr();
- self.refined_spans.push(closure_covspan); // since self.prev() was already updated
+ self.push_refined_span(closure_covspan); // since self.prev() was already updated
} else {
pending_dups.clear();
}
}
/// Called if `curr.span` equals `prev_original_span` (and potentially equal to all
- /// `pending_dups` spans, if any); but keep in mind, `prev.span` may start at a `Span.lo()` that
- /// is less than (further left of) `prev_original_span.lo()`.
+ /// `pending_dups` spans, if any). Keep in mind, `prev.span()` may have been changed.
+ /// If prev.span() was merged into other spans (with matching BCB, for instance),
+ /// `prev.span.hi()` will be greater than (further right of) `prev_original_span.hi()`.
+ /// If prev.span() was split off to the right of a closure, prev.span().lo() will be
+ /// greater than prev_original_span.lo(). The actual span of `prev_original_span` is
+ /// not as important as knowing that `prev()` **used to have the same span** as `curr(),
+ /// which means their sort order is still meaningful for determinating the dominator
+ /// relationship.
///
/// When two `CoverageSpan`s have the same `Span`, dominated spans can be discarded; but if
/// neither `CoverageSpan` dominates the other, both (or possibly more than two) are held,
} else {
debug!(" ... adding modified prev={:?}", self.prev());
let prev = self.take_prev();
- self.refined_spans.push(prev);
+ self.push_refined_span(prev);
}
} else {
// with `pending_dups`, `prev` cannot have any statements that don't overlap
}
}
+/// See `function_source_span()` for a description of the two returned spans.
+/// If the MIR `Statement` is not contributive to computing coverage spans,
+/// returns `None`.
pub(super) fn filtered_statement_span(
statement: &'a Statement<'tcx>,
body_span: Span,
-) -> Option<Span> {
+) -> Option<(Span, Span)> {
match statement.kind {
// These statements have spans that are often outside the scope of the executed source code
// for their parent `BasicBlock`.
}
}
+/// See `function_source_span()` for a description of the two returned spans.
+/// If the MIR `Terminator` is not contributive to computing coverage spans,
+/// returns `None`.
pub(super) fn filtered_terminator_span(
terminator: &'a Terminator<'tcx>,
body_span: Span,
-) -> Option<Span> {
+) -> Option<(Span, Span)> {
match terminator.kind {
// These terminators have spans that don't positively contribute to computing a reasonable
// span of actually executed source code. (For example, SwitchInt terminators extracted from
}
}
+/// Returns two spans from the given span (the span associated with a
+/// `Statement` or `Terminator`):
+///
+/// 1. An extrapolated span (pre-expansion[^1]) corresponding to a range within
+/// the function's body source. This span is guaranteed to be contained
+/// within, or equal to, the `body_span`. If the extrapolated span is not
+/// contained within the `body_span`, the `body_span` is returned.
+/// 2. The actual `span` value from the `Statement`, before expansion.
+///
+/// Only the first span is used when computing coverage code regions. The second
+/// span is useful if additional expansion data is needed (such as to look up
+/// the macro name for a composed span within that macro).)
+///
+/// [^1]Expansions result from Rust syntax including macros, syntactic
+/// sugar, etc.).
#[inline]
-fn function_source_span(span: Span, body_span: Span) -> Span {
- let span = original_sp(span, body_span).with_ctxt(body_span.ctxt());
- if body_span.contains(span) { span } else { body_span }
+fn function_source_span(span: Span, body_span: Span) -> (Span, Span) {
+ let original_span = original_sp(span, body_span).with_ctxt(body_span.ctxt());
+ (if body_span.contains(original_span) { original_span } else { body_span }, span)
}
//! This crate hosts a selection of "unit tests" for components of the `InstrumentCoverage` MIR
//! pass.
//!
+//! ```shell
+//! ./x.py test --keep-stage 1 compiler/rustc_mir --test-args '--show-output coverage'
+//! ```
+//!
//! The tests construct a few "mock" objects, as needed, to support the `InstrumentCoverage`
//! functions and algorithms. Mocked objects include instances of `mir::Body`; including
//! `Terminator`s of various `kind`s, and `Span` objects. Some functions used by or used on
let mut basic_coverage_blocks = graph::CoverageGraph::from_mir(&mir_body);
let mut coverage_spans = Vec::new();
for (bcb, data) in basic_coverage_blocks.iter_enumerated() {
- if let Some(span) =
+ if let Some((span, expn_span)) =
spans::filtered_terminator_span(data.terminator(&mir_body), body_span)
{
- coverage_spans.push(spans::CoverageSpan::for_terminator(span, bcb, data.last_bb()));
+ coverage_spans.push(spans::CoverageSpan::for_terminator(
+ span,
+ expn_span,
+ bcb,
+ data.last_bb(),
+ ));
}
}
let mut coverage_counters = counters::CoverageCounters::new(0);
W: Write,
{
let def_id = body.source.def_id();
- let body_span = hir_body(tcx, def_id).value.span;
+ let hir_body = hir_body(tcx, def_id);
+ if hir_body.is_none() {
+ return Ok(());
+ }
+ let body_span = hir_body.unwrap().value.span;
let mut span_viewables = Vec::new();
for (bb, data) in body.basic_blocks().iter_enumerated() {
match spanview {
let hir_id =
tcx.hir().local_def_id_to_hir_id(def_id.as_local().expect("expected DefId is local"));
let fn_decl_span = tcx.hir().span(hir_id);
- let body_span = hir_body(tcx, def_id).value.span;
- if fn_decl_span.ctxt() == body_span.ctxt() {
- fn_decl_span.to(body_span)
+ if let Some(body_span) = hir_body(tcx, def_id).map(|hir_body| hir_body.value.span) {
+ if fn_decl_span.ctxt() == body_span.ctxt() { fn_decl_span.to(body_span) } else { body_span }
} else {
- // This probably occurs for functions defined via macros
- body_span
+ fn_decl_span
}
}
-fn hir_body<'tcx>(tcx: TyCtxt<'tcx>, def_id: DefId) -> &'tcx rustc_hir::Body<'tcx> {
+fn hir_body<'tcx>(tcx: TyCtxt<'tcx>, def_id: DefId) -> Option<&'tcx rustc_hir::Body<'tcx>> {
let hir_node = tcx.hir().get_if_local(def_id).expect("expected DefId is local");
- let fn_body_id = hir::map::associated_body(hir_node).expect("HIR node is a function with body");
- tcx.hir().body(fn_body_id)
+ hir::map::associated_body(hir_node).map(|fn_body_id| tcx.hir().body(fn_body_id))
}
fn escape_html(s: &str) -> String {
}
}
- fn parse_tuple_parens_expr(&mut self, mut attrs: AttrVec) -> PResult<'a, P<Expr>> {
+ fn parse_tuple_parens_expr(&mut self, attrs: AttrVec) -> PResult<'a, P<Expr>> {
let lo = self.token.span;
self.expect(&token::OpenDelim(token::Paren))?;
- attrs.extend(self.parse_inner_attributes()?); // `(#![foo] a, b, ...)` is OK.
let (es, trailing_comma) = match self.parse_seq_to_end(
&token::CloseDelim(token::Paren),
SeqSep::trailing_allowed(token::Comma),
self.maybe_recover_from_bad_qpath(expr, true)
}
- fn parse_array_or_repeat_expr(&mut self, mut attrs: AttrVec) -> PResult<'a, P<Expr>> {
+ fn parse_array_or_repeat_expr(&mut self, attrs: AttrVec) -> PResult<'a, P<Expr>> {
let lo = self.token.span;
self.bump(); // `[`
- attrs.extend(self.parse_inner_attributes()?);
-
let close = &token::CloseDelim(token::Bracket);
let kind = if self.eat(close) {
// Empty vector
}
/// Parses a `match ... { ... }` expression (`match` token already eaten).
- fn parse_match_expr(&mut self, mut attrs: AttrVec) -> PResult<'a, P<Expr>> {
+ fn parse_match_expr(&mut self, attrs: AttrVec) -> PResult<'a, P<Expr>> {
let match_span = self.prev_token.span;
let lo = self.prev_token.span;
let scrutinee = self.parse_expr_res(Restrictions::NO_STRUCT_LITERAL, None)?;
}
return Err(e);
}
- attrs.extend(self.parse_inner_attributes()?);
let mut arms: Vec<Arm> = Vec::new();
while self.token != token::CloseDelim(token::Brace) {
pub(super) fn parse_struct_expr(
&mut self,
pth: ast::Path,
- mut attrs: AttrVec,
+ attrs: AttrVec,
recover: bool,
) -> PResult<'a, P<Expr>> {
let mut fields = Vec::new();
let mut base = ast::StructRest::None;
let mut recover_async = false;
- attrs.extend(self.parse_inner_attributes()?);
-
let mut async_block_err = |e: &mut DiagnosticBuilder<'_>, span: Span| {
recover_async = true;
e.span_label(span, "`async` blocks are only allowed in Rust 2018 or later");
// We use try_lock_shards here since we are called from the
// deadlock handler, and this shouldn't be locked.
let shards = self.shards.try_lock_shards()?;
- let shards = shards.iter().enumerate();
- jobs.extend(shards.flat_map(|(shard_id, shard)| {
- shard.active.iter().filter_map(move |(k, v)| {
+ for (shard_id, shard) in shards.iter().enumerate() {
+ for (k, v) in shard.active.iter() {
if let QueryResult::Started(ref job) = *v {
let id = QueryJobId::new(job.id, shard_id, kind);
let info = QueryInfo { span: job.span, query: make_query(tcx, k.clone()) };
- Some((id, QueryJobInfo { info, job: job.clone() }))
- } else {
- None
+ jobs.insert(id, QueryJobInfo { info, job: job.clone() });
}
- })
- }));
+ }
+ }
Some(())
}
_ => false,
};
+ let find_span = |source: &PathSource<'_>, err: &mut DiagnosticBuilder<'_>| {
+ match source {
+ PathSource::Expr(Some(Expr { span, kind: ExprKind::Call(_, _), .. }))
+ | PathSource::TupleStruct(span, _) => {
+ // We want the main underline to cover the suggested code as well for
+ // cleaner output.
+ err.set_span(*span);
+ *span
+ }
+ _ => span,
+ }
+ };
+
let mut bad_struct_syntax_suggestion = |def_id: DefId| {
let (followed_by_brace, closing_brace) = self.followed_by_brace(span);
}
}
PathSource::Expr(_) | PathSource::TupleStruct(..) | PathSource::Pat => {
- let span = match &source {
- PathSource::Expr(Some(Expr {
- span, kind: ExprKind::Call(_, _), ..
- }))
- | PathSource::TupleStruct(span, _) => {
- // We want the main underline to cover the suggested code as well for
- // cleaner output.
- err.set_span(*span);
- *span
- }
- _ => span,
- };
+ let span = find_span(&source, err);
if let Some(span) = self.def_span(def_id) {
err.span_label(span, &format!("`{}` defined here", path_str));
}
) if ns == ValueNS => {
bad_struct_syntax_suggestion(def_id);
}
+ (Res::Def(DefKind::Ctor(_, CtorKind::Const), def_id), _) if ns == ValueNS => {
+ match source {
+ PathSource::Expr(_) | PathSource::TupleStruct(..) | PathSource::Pat => {
+ let span = find_span(&source, err);
+ if let Some(span) = self.def_span(def_id) {
+ err.span_label(span, &format!("`{}` defined here", path_str));
+ }
+ err.span_suggestion(
+ span,
+ &format!("use this syntax instead"),
+ format!("{path_str}"),
+ Applicability::MaybeIncorrect,
+ );
+ }
+ _ => return false,
+ }
+ }
(Res::Def(DefKind::Ctor(_, CtorKind::Fn), def_id), _) if ns == ValueNS => {
if let Some(span) = self.def_span(def_id) {
err.span_label(span, &format!("`{}` defined here", path_str));
ret.reserve(6); // the minimum number of insertions
// Target bindings.
ret.insert((sym::target_os, Some(Symbol::intern(os))));
- if let Some(ref fam) = sess.target.os_family {
+ for fam in &sess.target.families {
ret.insert((sym::target_family, Some(Symbol::intern(fam))));
if fam == "windows" {
ret.insert((sym::windows, None));
macro_rules! options {
($struct_name:ident, $setter_name:ident, $defaultfn:ident,
$buildfn:ident, $prefix:expr, $outputname:expr,
- $stat:ident, $mod_desc:ident, $mod_set:ident,
+ $stat:ident,
$($( #[$attr:meta] )* $opt:ident : $t:ty = (
$init:expr,
$parse:ident,
pub type $setter_name = fn(&mut $struct_name, v: Option<&str>) -> bool;
pub const $stat: &[(&str, $setter_name, &str, &str)] =
- &[ $( (stringify!($opt), $mod_set::$opt, $mod_desc::$parse, $desc) ),* ];
-
- #[allow(non_upper_case_globals, dead_code)]
- mod $mod_desc {
- pub const parse_no_flag: &str = "no value";
- pub const parse_bool: &str = "one of: `y`, `yes`, `on`, `n`, `no`, or `off`";
- pub const parse_opt_bool: &str = parse_bool;
- pub const parse_string: &str = "a string";
- pub const parse_opt_string: &str = parse_string;
- pub const parse_string_push: &str = parse_string;
- pub const parse_opt_pathbuf: &str = "a path";
- pub const parse_pathbuf_push: &str = parse_opt_pathbuf;
- pub const parse_list: &str = "a space-separated list of strings";
- pub const parse_opt_list: &str = parse_list;
- pub const parse_opt_comma_list: &str = "a comma-separated list of strings";
- pub const parse_number: &str = "a number";
- pub const parse_opt_number: &str = parse_number;
- pub const parse_threads: &str = parse_number;
- pub const parse_passes: &str = "a space-separated list of passes, or `all`";
- pub const parse_panic_strategy: &str = "either `unwind` or `abort`";
- pub const parse_relro_level: &str = "one of: `full`, `partial`, or `off`";
- pub const parse_sanitizers: &str = "comma separated list of sanitizers: `address`, `hwaddress`, `leak`, `memory` or `thread`";
- pub const parse_sanitizer_memory_track_origins: &str = "0, 1, or 2";
- pub const parse_cfguard: &str =
- "either a boolean (`yes`, `no`, `on`, `off`, etc), `checks`, or `nochecks`";
- pub const parse_strip: &str = "either `none`, `debuginfo`, or `symbols`";
- pub const parse_linker_flavor: &str = ::rustc_target::spec::LinkerFlavor::one_of();
- pub const parse_optimization_fuel: &str = "crate=integer";
- pub const parse_mir_spanview: &str = "`statement` (default), `terminator`, or `block`";
- pub const parse_instrument_coverage: &str = "`all` (default), `except-unused-generics`, `except-unused-functions`, or `off`";
- pub const parse_unpretty: &str = "`string` or `string=string`";
- pub const parse_treat_err_as_bug: &str = "either no value or a number bigger than 0";
- pub const parse_lto: &str =
- "either a boolean (`yes`, `no`, `on`, `off`, etc), `thin`, `fat`, or omitted";
- pub const parse_linker_plugin_lto: &str =
- "either a boolean (`yes`, `no`, `on`, `off`, etc), or the path to the linker plugin";
- pub const parse_switch_with_opt_path: &str =
- "an optional path to the profiling data output directory";
- pub const parse_merge_functions: &str = "one of: `disabled`, `trampolines`, or `aliases`";
- pub const parse_symbol_mangling_version: &str = "either `legacy` or `v0` (RFC 2603)";
- pub const parse_src_file_hash: &str = "either `md5` or `sha1`";
- pub const parse_relocation_model: &str =
- "one of supported relocation models (`rustc --print relocation-models`)";
- pub const parse_code_model: &str =
- "one of supported code models (`rustc --print code-models`)";
- pub const parse_tls_model: &str =
- "one of supported TLS models (`rustc --print tls-models`)";
- 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`)";
+ &[ $( (stringify!($opt), $crate::options::parse::$opt, $crate::options::desc::$parse, $desc) ),* ];
+
+ // Sometimes different options need to build a common structure.
+ // That structure can kept in one of the options' fields, the others become dummy.
+ macro_rules! redirect_field {
+ ($cg:ident.link_arg) => { $cg.link_args };
+ ($cg:ident.pre_link_arg) => { $cg.pre_link_args };
+ ($cg:ident.$field:ident) => { $cg.$field };
}
- #[allow(dead_code)]
- mod $mod_set {
- use super::*;
- use std::str::FromStr;
-
- // Sometimes different options need to build a common structure.
- // That structure can kept in one of the options' fields, the others become dummy.
- macro_rules! redirect_field {
- ($cg:ident.link_arg) => { $cg.link_args };
- ($cg:ident.pre_link_arg) => { $cg.pre_link_args };
- ($cg:ident.$field:ident) => { $cg.$field };
+ $(
+ pub fn $opt(cg: &mut $struct_name, v: Option<&str>) -> bool {
+ $crate::options::parse::$parse(&mut redirect_field!(cg.$opt), v)
}
+ )*
- $(
- pub fn $opt(cg: &mut $struct_name, v: Option<&str>) -> bool {
- $parse(&mut redirect_field!(cg.$opt), v)
- }
- )*
-
- /// This is for boolean options that don't take a value and start with
- /// `no-`. This style of option is deprecated.
- fn parse_no_flag(slot: &mut bool, v: Option<&str>) -> bool {
- match v {
- None => { *slot = true; true }
- Some(_) => false,
- }
- }
+) }
- /// Use this for any boolean option that has a static default.
- fn parse_bool(slot: &mut bool, v: Option<&str>) -> bool {
- match v {
- Some("y") | Some("yes") | Some("on") | None => { *slot = true; true }
- Some("n") | Some("no") | Some("off") => { *slot = false; true }
- _ => false,
- }
- }
+#[allow(non_upper_case_globals)]
+mod desc {
+ pub const parse_no_flag: &str = "no value";
+ pub const parse_bool: &str = "one of: `y`, `yes`, `on`, `n`, `no`, or `off`";
+ pub const parse_opt_bool: &str = parse_bool;
+ pub const parse_string: &str = "a string";
+ pub const parse_opt_string: &str = parse_string;
+ pub const parse_string_push: &str = parse_string;
+ pub const parse_opt_pathbuf: &str = "a path";
+ pub const parse_list: &str = "a space-separated list of strings";
+ pub const parse_opt_comma_list: &str = "a comma-separated list of strings";
+ pub const parse_number: &str = "a number";
+ pub const parse_opt_number: &str = parse_number;
+ pub const parse_threads: &str = parse_number;
+ pub const parse_passes: &str = "a space-separated list of passes, or `all`";
+ pub const parse_panic_strategy: &str = "either `unwind` or `abort`";
+ pub const parse_relro_level: &str = "one of: `full`, `partial`, or `off`";
+ pub const parse_sanitizers: &str =
+ "comma separated list of sanitizers: `address`, `hwaddress`, `leak`, `memory` or `thread`";
+ pub const parse_sanitizer_memory_track_origins: &str = "0, 1, or 2";
+ pub const parse_cfguard: &str =
+ "either a boolean (`yes`, `no`, `on`, `off`, etc), `checks`, or `nochecks`";
+ pub const parse_strip: &str = "either `none`, `debuginfo`, or `symbols`";
+ pub const parse_linker_flavor: &str = ::rustc_target::spec::LinkerFlavor::one_of();
+ pub const parse_optimization_fuel: &str = "crate=integer";
+ pub const parse_mir_spanview: &str = "`statement` (default), `terminator`, or `block`";
+ pub const parse_instrument_coverage: &str =
+ "`all` (default), `except-unused-generics`, `except-unused-functions`, or `off`";
+ pub const parse_unpretty: &str = "`string` or `string=string`";
+ pub const parse_treat_err_as_bug: &str = "either no value or a number bigger than 0";
+ pub const parse_lto: &str =
+ "either a boolean (`yes`, `no`, `on`, `off`, etc), `thin`, `fat`, or omitted";
+ pub const parse_linker_plugin_lto: &str =
+ "either a boolean (`yes`, `no`, `on`, `off`, etc), or the path to the linker plugin";
+ pub const parse_switch_with_opt_path: &str =
+ "an optional path to the profiling data output directory";
+ pub const parse_merge_functions: &str = "one of: `disabled`, `trampolines`, or `aliases`";
+ pub const parse_symbol_mangling_version: &str = "either `legacy` or `v0` (RFC 2603)";
+ pub const parse_src_file_hash: &str = "either `md5` or `sha1`";
+ pub const parse_relocation_model: &str =
+ "one of supported relocation models (`rustc --print relocation-models`)";
+ pub const parse_code_model: &str = "one of supported code models (`rustc --print code-models`)";
+ pub const parse_tls_model: &str = "one of supported TLS models (`rustc --print tls-models`)";
+ 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`)";
+}
+
+mod parse {
+ crate use super::*;
+ use std::str::FromStr;
- /// Use this for any boolean option that lacks a static default. (The
- /// actions taken when such an option is not specified will depend on
- /// other factors, such as other options, or target options.)
- fn parse_opt_bool(slot: &mut Option<bool>, v: Option<&str>) -> bool {
- match v {
- Some("y") | Some("yes") | Some("on") | None => { *slot = Some(true); true }
- Some("n") | Some("no") | Some("off") => { *slot = Some(false); true }
- _ => false,
+ /// This is for boolean options that don't take a value and start with
+ /// `no-`. This style of option is deprecated.
+ crate fn parse_no_flag(slot: &mut bool, v: Option<&str>) -> bool {
+ match v {
+ None => {
+ *slot = true;
+ true
}
+ Some(_) => false,
}
+ }
- /// Use this for any string option that has a static default.
- fn parse_string(slot: &mut String, v: Option<&str>) -> bool {
- match v {
- Some(s) => { *slot = s.to_string(); true },
- None => false,
+ /// Use this for any boolean option that has a static default.
+ crate fn parse_bool(slot: &mut bool, v: Option<&str>) -> bool {
+ match v {
+ Some("y") | Some("yes") | Some("on") | None => {
+ *slot = true;
+ true
}
+ Some("n") | Some("no") | Some("off") => {
+ *slot = false;
+ true
+ }
+ _ => false,
}
+ }
- /// Use this for any string option that lacks a static default.
- fn parse_opt_string(slot: &mut Option<String>, v: Option<&str>) -> bool {
- match v {
- Some(s) => { *slot = Some(s.to_string()); true },
- None => false,
+ /// Use this for any boolean option that lacks a static default. (The
+ /// actions taken when such an option is not specified will depend on
+ /// other factors, such as other options, or target options.)
+ crate fn parse_opt_bool(slot: &mut Option<bool>, v: Option<&str>) -> bool {
+ match v {
+ Some("y") | Some("yes") | Some("on") | None => {
+ *slot = Some(true);
+ true
+ }
+ Some("n") | Some("no") | Some("off") => {
+ *slot = Some(false);
+ true
}
+ _ => false,
}
+ }
- fn parse_opt_pathbuf(slot: &mut Option<PathBuf>, v: Option<&str>) -> bool {
- match v {
- Some(s) => { *slot = Some(PathBuf::from(s)); true },
- None => false,
+ /// Use this for any string option that has a static default.
+ crate fn parse_string(slot: &mut String, v: Option<&str>) -> bool {
+ match v {
+ Some(s) => {
+ *slot = s.to_string();
+ true
}
+ None => false,
}
+ }
- fn parse_string_push(slot: &mut Vec<String>, v: Option<&str>) -> bool {
- match v {
- Some(s) => { slot.push(s.to_string()); true },
- None => false,
+ /// Use this for any string option that lacks a static default.
+ crate fn parse_opt_string(slot: &mut Option<String>, v: Option<&str>) -> bool {
+ match v {
+ Some(s) => {
+ *slot = Some(s.to_string());
+ true
}
+ None => false,
}
+ }
- fn parse_pathbuf_push(slot: &mut Vec<PathBuf>, v: Option<&str>) -> bool {
- match v {
- Some(s) => { slot.push(PathBuf::from(s)); true },
- None => false,
+ crate fn parse_opt_pathbuf(slot: &mut Option<PathBuf>, v: Option<&str>) -> bool {
+ match v {
+ Some(s) => {
+ *slot = Some(PathBuf::from(s));
+ true
}
+ None => false,
}
+ }
- fn parse_list(slot: &mut Vec<String>, v: Option<&str>)
- -> bool {
- match v {
- Some(s) => {
- slot.extend(s.split_whitespace().map(|s| s.to_string()));
- true
- },
- None => false,
+ crate fn parse_string_push(slot: &mut Vec<String>, v: Option<&str>) -> bool {
+ match v {
+ Some(s) => {
+ slot.push(s.to_string());
+ true
}
+ None => false,
}
+ }
- fn parse_opt_list(slot: &mut Option<Vec<String>>, v: Option<&str>)
- -> bool {
- match v {
- Some(s) => {
- let v = s.split_whitespace().map(|s| s.to_string()).collect();
- *slot = Some(v);
- true
- },
- None => false,
+ crate fn parse_list(slot: &mut Vec<String>, v: Option<&str>) -> bool {
+ match v {
+ Some(s) => {
+ slot.extend(s.split_whitespace().map(|s| s.to_string()));
+ true
}
+ None => false,
}
+ }
- fn parse_opt_comma_list(slot: &mut Option<Vec<String>>, v: Option<&str>)
- -> bool {
- match v {
- Some(s) => {
- let v = s.split(',').map(|s| s.to_string()).collect();
- *slot = Some(v);
- true
- },
- None => false,
+ crate fn parse_opt_comma_list(slot: &mut Option<Vec<String>>, v: Option<&str>) -> bool {
+ match v {
+ Some(s) => {
+ let mut v: Vec<_> = s.split(',').map(|s| s.to_string()).collect();
+ v.sort_unstable();
+ *slot = Some(v);
+ true
}
+ None => false,
}
+ }
- fn parse_threads(slot: &mut usize, v: Option<&str>) -> bool {
- match v.and_then(|s| s.parse().ok()) {
- Some(0) => { *slot = ::num_cpus::get(); true },
- Some(i) => { *slot = i; true },
- None => false
+ crate fn parse_threads(slot: &mut usize, v: Option<&str>) -> bool {
+ match v.and_then(|s| s.parse().ok()) {
+ Some(0) => {
+ *slot = ::num_cpus::get();
+ true
+ }
+ Some(i) => {
+ *slot = i;
+ true
}
+ None => false,
}
+ }
- /// Use this for any numeric option that has a static default.
- fn parse_number<T: Copy + FromStr>(slot: &mut T, v: Option<&str>) -> bool {
- match v.and_then(|s| s.parse().ok()) {
- Some(i) => { *slot = i; true },
- None => false
+ /// Use this for any numeric option that has a static default.
+ crate fn parse_number<T: Copy + FromStr>(slot: &mut T, v: Option<&str>) -> bool {
+ match v.and_then(|s| s.parse().ok()) {
+ Some(i) => {
+ *slot = i;
+ true
}
+ None => false,
}
+ }
- /// Use this for any numeric option that lacks a static default.
- fn parse_opt_number<T: Copy + FromStr>(slot: &mut Option<T>, v: Option<&str>) -> bool {
- match v {
- Some(s) => { *slot = s.parse().ok(); slot.is_some() }
- None => false
+ /// Use this for any numeric option that lacks a static default.
+ crate fn parse_opt_number<T: Copy + FromStr>(slot: &mut Option<T>, v: Option<&str>) -> bool {
+ match v {
+ Some(s) => {
+ *slot = s.parse().ok();
+ slot.is_some()
}
+ None => false,
}
+ }
- fn parse_passes(slot: &mut Passes, v: Option<&str>) -> bool {
- match v {
- Some("all") => {
- *slot = Passes::All;
+ crate fn parse_passes(slot: &mut Passes, v: Option<&str>) -> bool {
+ match v {
+ Some("all") => {
+ *slot = Passes::All;
+ true
+ }
+ v => {
+ let mut passes = vec![];
+ if parse_list(&mut passes, v) {
+ *slot = Passes::Some(passes);
true
- }
- v => {
- let mut passes = vec![];
- if parse_list(&mut passes, v) {
- *slot = Passes::Some(passes);
- true
- } else {
- false
- }
+ } else {
+ false
}
}
}
+ }
- fn parse_panic_strategy(slot: &mut Option<PanicStrategy>, v: Option<&str>) -> bool {
- match v {
- Some("unwind") => *slot = Some(PanicStrategy::Unwind),
- Some("abort") => *slot = Some(PanicStrategy::Abort),
- _ => return false
- }
- true
+ crate fn parse_panic_strategy(slot: &mut Option<PanicStrategy>, v: Option<&str>) -> bool {
+ match v {
+ Some("unwind") => *slot = Some(PanicStrategy::Unwind),
+ Some("abort") => *slot = Some(PanicStrategy::Abort),
+ _ => return false,
}
+ true
+ }
- fn parse_relro_level(slot: &mut Option<RelroLevel>, v: Option<&str>) -> bool {
- match v {
- Some(s) => {
- match s.parse::<RelroLevel>() {
- Ok(level) => *slot = Some(level),
- _ => return false
- }
- },
- _ => return false
- }
- true
+ crate fn parse_relro_level(slot: &mut Option<RelroLevel>, v: Option<&str>) -> bool {
+ match v {
+ Some(s) => match s.parse::<RelroLevel>() {
+ Ok(level) => *slot = Some(level),
+ _ => return false,
+ },
+ _ => return false,
}
+ true
+ }
- fn parse_sanitizers(slot: &mut SanitizerSet, v: Option<&str>) -> bool {
- if let Some(v) = v {
- for s in v.split(',') {
- *slot |= match s {
- "address" => SanitizerSet::ADDRESS,
- "leak" => SanitizerSet::LEAK,
- "memory" => SanitizerSet::MEMORY,
- "thread" => SanitizerSet::THREAD,
- "hwaddress" => SanitizerSet::HWADDRESS,
- _ => return false,
- }
+ crate fn parse_sanitizers(slot: &mut SanitizerSet, v: Option<&str>) -> bool {
+ if let Some(v) = v {
+ for s in v.split(',') {
+ *slot |= match s {
+ "address" => SanitizerSet::ADDRESS,
+ "leak" => SanitizerSet::LEAK,
+ "memory" => SanitizerSet::MEMORY,
+ "thread" => SanitizerSet::THREAD,
+ "hwaddress" => SanitizerSet::HWADDRESS,
+ _ => return false,
}
- true
- } else {
- false
}
+ true
+ } else {
+ false
}
+ }
- fn parse_sanitizer_memory_track_origins(slot: &mut usize, v: Option<&str>) -> bool {
- match v {
- Some("2") | None => { *slot = 2; true }
- Some("1") => { *slot = 1; true }
- Some("0") => { *slot = 0; true }
- Some(_) => false,
+ crate fn parse_sanitizer_memory_track_origins(slot: &mut usize, v: Option<&str>) -> bool {
+ match v {
+ Some("2") | None => {
+ *slot = 2;
+ true
+ }
+ Some("1") => {
+ *slot = 1;
+ true
+ }
+ Some("0") => {
+ *slot = 0;
+ true
}
+ Some(_) => false,
}
+ }
- fn parse_strip(slot: &mut Strip, v: Option<&str>) -> bool {
- match v {
- Some("none") => *slot = Strip::None,
- Some("debuginfo") => *slot = Strip::Debuginfo,
- Some("symbols") => *slot = Strip::Symbols,
- _ => return false,
- }
- true
+ crate fn parse_strip(slot: &mut Strip, v: Option<&str>) -> bool {
+ match v {
+ Some("none") => *slot = Strip::None,
+ Some("debuginfo") => *slot = Strip::Debuginfo,
+ Some("symbols") => *slot = Strip::Symbols,
+ _ => return false,
}
+ true
+ }
- fn parse_cfguard(slot: &mut CFGuard, v: Option<&str>) -> bool {
- if v.is_some() {
- let mut bool_arg = None;
- if parse_opt_bool(&mut bool_arg, v) {
- *slot = if bool_arg.unwrap() {
- CFGuard::Checks
- } else {
- CFGuard::Disabled
- };
- return true
- }
+ crate fn parse_cfguard(slot: &mut CFGuard, v: Option<&str>) -> bool {
+ if v.is_some() {
+ let mut bool_arg = None;
+ if parse_opt_bool(&mut bool_arg, v) {
+ *slot = if bool_arg.unwrap() { CFGuard::Checks } else { CFGuard::Disabled };
+ return true;
}
-
- *slot = match v {
- None => CFGuard::Checks,
- Some("checks") => CFGuard::Checks,
- Some("nochecks") => CFGuard::NoChecks,
- Some(_) => return false,
- };
- true
}
- fn parse_linker_flavor(slote: &mut Option<LinkerFlavor>, v: Option<&str>) -> bool {
- match v.and_then(LinkerFlavor::from_str) {
- Some(lf) => *slote = Some(lf),
- _ => return false,
- }
- true
+ *slot = match v {
+ None => CFGuard::Checks,
+ Some("checks") => CFGuard::Checks,
+ Some("nochecks") => CFGuard::NoChecks,
+ Some(_) => return false,
+ };
+ true
+ }
+
+ crate fn parse_linker_flavor(slote: &mut Option<LinkerFlavor>, v: Option<&str>) -> bool {
+ match v.and_then(LinkerFlavor::from_str) {
+ Some(lf) => *slote = Some(lf),
+ _ => return false,
}
+ true
+ }
- fn parse_optimization_fuel(slot: &mut Option<(String, u64)>, v: Option<&str>) -> bool {
- match v {
- None => false,
- Some(s) => {
- let parts = s.split('=').collect::<Vec<_>>();
- if parts.len() != 2 { return false; }
- let crate_name = parts[0].to_string();
- let fuel = parts[1].parse::<u64>();
- if fuel.is_err() { return false; }
- *slot = Some((crate_name, fuel.unwrap()));
- true
+ crate fn parse_optimization_fuel(slot: &mut Option<(String, u64)>, v: Option<&str>) -> bool {
+ match v {
+ None => false,
+ Some(s) => {
+ let parts = s.split('=').collect::<Vec<_>>();
+ if parts.len() != 2 {
+ return false;
+ }
+ let crate_name = parts[0].to_string();
+ let fuel = parts[1].parse::<u64>();
+ if fuel.is_err() {
+ return false;
}
+ *slot = Some((crate_name, fuel.unwrap()));
+ true
}
}
+ }
- fn parse_unpretty(slot: &mut Option<String>, v: Option<&str>) -> bool {
- match v {
- None => false,
- Some(s) if s.split('=').count() <= 2 => {
- *slot = Some(s.to_string());
- true
- }
- _ => false,
+ crate fn parse_unpretty(slot: &mut Option<String>, v: Option<&str>) -> bool {
+ match v {
+ None => false,
+ Some(s) if s.split('=').count() <= 2 => {
+ *slot = Some(s.to_string());
+ true
}
+ _ => false,
}
+ }
- fn parse_mir_spanview(slot: &mut Option<MirSpanview>, v: Option<&str>) -> bool {
- if v.is_some() {
- let mut bool_arg = None;
- if parse_opt_bool(&mut bool_arg, v) {
- *slot = if bool_arg.unwrap() {
- Some(MirSpanview::Statement)
- } else {
- None
- };
- return true
- }
+ crate fn parse_mir_spanview(slot: &mut Option<MirSpanview>, v: Option<&str>) -> bool {
+ if v.is_some() {
+ let mut bool_arg = None;
+ if parse_opt_bool(&mut bool_arg, v) {
+ *slot = if bool_arg.unwrap() { Some(MirSpanview::Statement) } else { None };
+ return true;
}
-
- let v = match v {
- None => {
- *slot = Some(MirSpanview::Statement);
- return true;
- }
- Some(v) => v,
- };
-
- *slot = Some(match v.trim_end_matches("s") {
- "statement" | "stmt" => MirSpanview::Statement,
- "terminator" | "term" => MirSpanview::Terminator,
- "block" | "basicblock" => MirSpanview::Block,
- _ => return false,
- });
- true
}
- fn parse_instrument_coverage(slot: &mut Option<InstrumentCoverage>, v: Option<&str>) -> bool {
- if v.is_some() {
- let mut bool_arg = None;
- if parse_opt_bool(&mut bool_arg, v) {
- *slot = if bool_arg.unwrap() {
- Some(InstrumentCoverage::All)
- } else {
- None
- };
- return true
- }
+ let v = match v {
+ None => {
+ *slot = Some(MirSpanview::Statement);
+ return true;
}
+ Some(v) => v,
+ };
+
+ *slot = Some(match v.trim_end_matches("s") {
+ "statement" | "stmt" => MirSpanview::Statement,
+ "terminator" | "term" => MirSpanview::Terminator,
+ "block" | "basicblock" => MirSpanview::Block,
+ _ => return false,
+ });
+ true
+ }
- let v = match v {
- None => {
- *slot = Some(InstrumentCoverage::All);
- return true;
- }
- Some(v) => v,
- };
-
- *slot = Some(match v {
- "all" => InstrumentCoverage::All,
- "except-unused-generics" | "except_unused_generics" => {
- InstrumentCoverage::ExceptUnusedGenerics
- }
- "except-unused-functions" | "except_unused_functions" => {
- InstrumentCoverage::ExceptUnusedFunctions
- }
- "off" | "no" | "n" | "false" | "0" => InstrumentCoverage::Off,
- _ => return false,
- });
- true
+ crate fn parse_instrument_coverage(
+ slot: &mut Option<InstrumentCoverage>,
+ v: Option<&str>,
+ ) -> bool {
+ if v.is_some() {
+ let mut bool_arg = None;
+ if parse_opt_bool(&mut bool_arg, v) {
+ *slot = if bool_arg.unwrap() { Some(InstrumentCoverage::All) } else { None };
+ return true;
+ }
}
- fn parse_treat_err_as_bug(slot: &mut Option<NonZeroUsize>, v: Option<&str>) -> bool {
- match v {
- Some(s) => { *slot = s.parse().ok(); slot.is_some() }
- None => { *slot = NonZeroUsize::new(1); true }
+ let v = match v {
+ None => {
+ *slot = Some(InstrumentCoverage::All);
+ return true;
}
- }
+ Some(v) => v,
+ };
- fn parse_lto(slot: &mut LtoCli, v: Option<&str>) -> bool {
- if v.is_some() {
- let mut bool_arg = None;
- if parse_opt_bool(&mut bool_arg, v) {
- *slot = if bool_arg.unwrap() {
- LtoCli::Yes
- } else {
- LtoCli::No
- };
- return true
- }
+ *slot = Some(match v {
+ "all" => InstrumentCoverage::All,
+ "except-unused-generics" | "except_unused_generics" => {
+ InstrumentCoverage::ExceptUnusedGenerics
}
+ "except-unused-functions" | "except_unused_functions" => {
+ InstrumentCoverage::ExceptUnusedFunctions
+ }
+ "off" | "no" | "n" | "false" | "0" => InstrumentCoverage::Off,
+ _ => return false,
+ });
+ true
+ }
- *slot = match v {
- None => LtoCli::NoParam,
- Some("thin") => LtoCli::Thin,
- Some("fat") => LtoCli::Fat,
- Some(_) => return false,
- };
- true
+ crate fn parse_treat_err_as_bug(slot: &mut Option<NonZeroUsize>, v: Option<&str>) -> bool {
+ match v {
+ Some(s) => {
+ *slot = s.parse().ok();
+ slot.is_some()
+ }
+ None => {
+ *slot = NonZeroUsize::new(1);
+ true
+ }
}
+ }
- fn parse_linker_plugin_lto(slot: &mut LinkerPluginLto, v: Option<&str>) -> bool {
- if v.is_some() {
- let mut bool_arg = None;
- if parse_opt_bool(&mut bool_arg, v) {
- *slot = if bool_arg.unwrap() {
- LinkerPluginLto::LinkerPluginAuto
- } else {
- LinkerPluginLto::Disabled
- };
- return true
- }
+ crate fn parse_lto(slot: &mut LtoCli, v: Option<&str>) -> bool {
+ if v.is_some() {
+ let mut bool_arg = None;
+ if parse_opt_bool(&mut bool_arg, v) {
+ *slot = if bool_arg.unwrap() { LtoCli::Yes } else { LtoCli::No };
+ return true;
}
-
- *slot = match v {
- None => LinkerPluginLto::LinkerPluginAuto,
- Some(path) => LinkerPluginLto::LinkerPlugin(PathBuf::from(path)),
- };
- true
}
- fn parse_switch_with_opt_path(slot: &mut SwitchWithOptPath, v: Option<&str>) -> bool {
- *slot = match v {
- None => SwitchWithOptPath::Enabled(None),
- Some(path) => SwitchWithOptPath::Enabled(Some(PathBuf::from(path))),
- };
- true
- }
+ *slot = match v {
+ None => LtoCli::NoParam,
+ Some("thin") => LtoCli::Thin,
+ Some("fat") => LtoCli::Fat,
+ Some(_) => return false,
+ };
+ true
+ }
- fn parse_merge_functions(slot: &mut Option<MergeFunctions>, v: Option<&str>) -> bool {
- match v.and_then(|s| MergeFunctions::from_str(s).ok()) {
- Some(mergefunc) => *slot = Some(mergefunc),
- _ => return false,
+ crate fn parse_linker_plugin_lto(slot: &mut LinkerPluginLto, v: Option<&str>) -> bool {
+ if v.is_some() {
+ let mut bool_arg = None;
+ if parse_opt_bool(&mut bool_arg, v) {
+ *slot = if bool_arg.unwrap() {
+ LinkerPluginLto::LinkerPluginAuto
+ } else {
+ LinkerPluginLto::Disabled
+ };
+ return true;
}
- true
}
- fn parse_relocation_model(slot: &mut Option<RelocModel>, v: Option<&str>) -> bool {
- match v.and_then(|s| RelocModel::from_str(s).ok()) {
- Some(relocation_model) => *slot = Some(relocation_model),
- None if v == Some("default") => *slot = None,
- _ => return false,
- }
- true
+ *slot = match v {
+ None => LinkerPluginLto::LinkerPluginAuto,
+ Some(path) => LinkerPluginLto::LinkerPlugin(PathBuf::from(path)),
+ };
+ true
+ }
+
+ crate fn parse_switch_with_opt_path(slot: &mut SwitchWithOptPath, v: Option<&str>) -> bool {
+ *slot = match v {
+ None => SwitchWithOptPath::Enabled(None),
+ Some(path) => SwitchWithOptPath::Enabled(Some(PathBuf::from(path))),
+ };
+ true
+ }
+
+ crate fn parse_merge_functions(slot: &mut Option<MergeFunctions>, v: Option<&str>) -> bool {
+ match v.and_then(|s| MergeFunctions::from_str(s).ok()) {
+ Some(mergefunc) => *slot = Some(mergefunc),
+ _ => return false,
}
+ true
+ }
- fn parse_code_model(slot: &mut Option<CodeModel>, v: Option<&str>) -> bool {
- match v.and_then(|s| CodeModel::from_str(s).ok()) {
- Some(code_model) => *slot = Some(code_model),
- _ => return false,
- }
- true
+ crate fn parse_relocation_model(slot: &mut Option<RelocModel>, v: Option<&str>) -> bool {
+ match v.and_then(|s| RelocModel::from_str(s).ok()) {
+ Some(relocation_model) => *slot = Some(relocation_model),
+ None if v == Some("default") => *slot = None,
+ _ => return false,
}
+ true
+ }
- fn parse_tls_model(slot: &mut Option<TlsModel>, v: Option<&str>) -> bool {
- match v.and_then(|s| TlsModel::from_str(s).ok()) {
- Some(tls_model) => *slot = Some(tls_model),
- _ => return false,
- }
- true
+ crate fn parse_code_model(slot: &mut Option<CodeModel>, v: Option<&str>) -> bool {
+ match v.and_then(|s| CodeModel::from_str(s).ok()) {
+ Some(code_model) => *slot = Some(code_model),
+ _ => return false,
}
+ true
+ }
- fn parse_symbol_mangling_version(
- slot: &mut Option<SymbolManglingVersion>,
- v: Option<&str>,
- ) -> bool {
- *slot = match v {
- Some("legacy") => Some(SymbolManglingVersion::Legacy),
- Some("v0") => Some(SymbolManglingVersion::V0),
- _ => return false,
- };
- true
+ crate fn parse_tls_model(slot: &mut Option<TlsModel>, v: Option<&str>) -> bool {
+ match v.and_then(|s| TlsModel::from_str(s).ok()) {
+ Some(tls_model) => *slot = Some(tls_model),
+ _ => return false,
}
+ true
+ }
- fn parse_src_file_hash(slot: &mut Option<SourceFileHashAlgorithm>, v: Option<&str>) -> bool {
- match v.and_then(|s| SourceFileHashAlgorithm::from_str(s).ok()) {
- Some(hash_kind) => *slot = Some(hash_kind),
- _ => return false,
- }
- true
+ crate fn parse_symbol_mangling_version(
+ slot: &mut Option<SymbolManglingVersion>,
+ v: Option<&str>,
+ ) -> bool {
+ *slot = match v {
+ Some("legacy") => Some(SymbolManglingVersion::Legacy),
+ Some("v0") => Some(SymbolManglingVersion::V0),
+ _ => return false,
+ };
+ true
+ }
+
+ crate fn parse_src_file_hash(
+ slot: &mut Option<SourceFileHashAlgorithm>,
+ v: Option<&str>,
+ ) -> bool {
+ match v.and_then(|s| SourceFileHashAlgorithm::from_str(s).ok()) {
+ Some(hash_kind) => *slot = Some(hash_kind),
+ _ => return false,
}
+ true
+ }
- fn parse_target_feature(slot: &mut String, v: Option<&str>) -> bool {
- match v {
- Some(s) => {
- if !slot.is_empty() {
- slot.push_str(",");
- }
- slot.push_str(s);
- true
+ crate fn parse_target_feature(slot: &mut String, v: Option<&str>) -> bool {
+ match v {
+ Some(s) => {
+ if !slot.is_empty() {
+ slot.push_str(",");
}
- None => false,
+ slot.push_str(s);
+ true
}
+ None => false,
}
+ }
- fn parse_wasi_exec_model(slot: &mut Option<WasiExecModel>, v: Option<&str>) -> bool {
- match v {
- Some("command") => *slot = Some(WasiExecModel::Command),
- Some("reactor") => *slot = Some(WasiExecModel::Reactor),
- _ => return false,
- }
- true
+ crate fn parse_wasi_exec_model(slot: &mut Option<WasiExecModel>, v: Option<&str>) -> bool {
+ match v {
+ Some("command") => *slot = Some(WasiExecModel::Command),
+ Some("reactor") => *slot = Some(WasiExecModel::Reactor),
+ _ => return false,
}
+ true
+ }
- fn parse_split_debuginfo(slot: &mut Option<SplitDebuginfo>, v: Option<&str>) -> bool {
- match v.and_then(|s| SplitDebuginfo::from_str(s).ok()) {
- Some(e) => *slot = Some(e),
- _ => return false,
- }
- true
+ crate fn parse_split_debuginfo(slot: &mut Option<SplitDebuginfo>, v: Option<&str>) -> bool {
+ match v.and_then(|s| SplitDebuginfo::from_str(s).ok()) {
+ Some(e) => *slot = Some(e),
+ _ => return false,
}
+ true
}
-) }
+}
options! {CodegenOptions, CodegenSetter, basic_codegen_options,
build_codegen_options, "C", "codegen",
- CG_OPTIONS, cg_type_desc, cgsetters,
+ CG_OPTIONS,
// This list is in alphabetical order.
//
options! {DebuggingOptions, DebuggingSetter, basic_debugging_options,
build_debugging_options, "Z", "debugging",
- DB_OPTIONS, db_type_desc, dbsetters,
+ DB_OPTIONS,
// This list is in alphabetical order.
//
// This cache is only used by `DummyHashStableContext`,
// so we won't pollute the cache values of the normal `StableHashingContext`
thread_local! {
- static CACHE: ExpnIdCache = Default::default();
+ static CACHE: ExpnIdCache = const { ExpnIdCache::new(Vec::new()) };
}
&CACHE
#![feature(negative_impls)]
#![feature(nll)]
#![feature(min_specialization)]
+#![feature(thread_local_const_init)]
#[macro_use]
extern crate rustc_macros;
x15: reg = ["x15", "w15"],
x16: reg = ["x16", "w16"],
x17: reg = ["x17", "w17"],
- x18: reg = ["x18", "w18"],
- x19: reg = ["x19", "w19"],
x20: reg = ["x20", "w20"],
x21: reg = ["x21", "w21"],
x22: reg = ["x22", "w22"],
x26: reg = ["x26", "w26"],
x27: reg = ["x27", "w27"],
x28: reg = ["x28", "w28"],
- x30: reg = ["x30", "w30", "lr"],
+ x30: reg = ["x30", "w30", "lr", "wlr"],
v0: vreg, vreg_low16 = ["v0", "b0", "h0", "s0", "d0", "q0"],
v1: vreg, vreg_low16 = ["v1", "b1", "h1", "s1", "d1", "q1"],
v2: vreg, vreg_low16 = ["v2", "b2", "h2", "s2", "d2", "q2"],
v29: vreg = ["v29", "b29", "h29", "s29", "d29", "q29"],
v30: vreg = ["v30", "b30", "h30", "s30", "d30", "q30"],
v31: vreg = ["v31", "b31", "h31", "s31", "d31", "q31"],
- #error = ["x29", "fp"] =>
+ #error = ["x18", "w18"] =>
+ "x18 is used as a reserved register on some targets and cannot be used as an operand for inline asm",
+ #error = ["x19", "w19"] =>
+ "x19 is used internally by LLVM and cannot be used as an operand for inline asm",
+ #error = ["x29", "w29", "fp", "wfp"] =>
"the frame pointer cannot be used as an operand for inline asm",
#error = ["sp", "wsp"] =>
"the stack pointer cannot be used as an operand for inline asm",
r5: reg, reg_thumb = ["r5", "v2"],
r7: reg, reg_thumb = ["r7", "v4"] % frame_pointer_r7,
r8: reg = ["r8", "v5"],
- r9: reg = ["r9", "v6", "rfp"],
r10: reg = ["r10", "sl"],
r11: reg = ["r11", "fp"] % frame_pointer_r11,
r12: reg = ["r12", "ip"],
q15: qreg = ["q15"],
#error = ["r6", "v3"] =>
"r6 is used internally by LLVM and cannot be used as an operand for inline asm",
+ #error = ["r9", "v6", "rfp"] =>
+ "r9 is used internally by LLVM and cannot be used as an operand for inline asm",
#error = ["r13", "sp"] =>
"the stack pointer cannot be used as an operand for inline asm",
#error = ["r15", "pc"] =>
r16: reg = ["r16"],
r17: reg = ["r17"],
r18: reg = ["r18"],
- r19: reg = ["r19"],
r20: reg = ["r20"],
r21: reg = ["r21"],
r22: reg = ["r22"],
r26: reg = ["r26"],
r27: reg = ["r27"],
r28: reg = ["r28"],
+ #error = ["r19"] =>
+ "r19 is used internally by LLVM and cannot be used as an operand for inline asm",
#error = ["r29", "sp"] =>
"the stack pointer cannot be used as an operand for inline asm",
#error = ["r30", "fr"] =>
x5: reg = ["x5", "t0"],
x6: reg = ["x6", "t1"],
x7: reg = ["x7", "t2"],
- x9: reg = ["x9", "s1"],
x10: reg = ["x10", "a0"],
x11: reg = ["x11", "a1"],
x12: reg = ["x12", "a2"],
f29: freg = ["f29", "ft9"],
f30: freg = ["f30", "ft10"],
f31: freg = ["f31", "ft11"],
+ #error = ["x9", "s1"] =>
+ "s1 is used internally by LLVM and cannot be used as an operand for inline asm",
#error = ["x8", "s0", "fp"] =>
"the frame pointer cannot be used as an operand for inline asm",
#error = ["x2", "sp"] =>
}
}
+fn rbx_reserved(
+ arch: InlineAsmArch,
+ _has_feature: impl FnMut(&str) -> bool,
+ _target: &Target,
+) -> Result<(), &'static str> {
+ match arch {
+ InlineAsmArch::X86 => Ok(()),
+ InlineAsmArch::X86_64 => {
+ Err("rbx is used internally by LLVM and cannot be used as an operand for inline asm")
+ }
+ _ => unreachable!(),
+ }
+}
+
+fn esi_reserved(
+ arch: InlineAsmArch,
+ _has_feature: impl FnMut(&str) -> bool,
+ _target: &Target,
+) -> Result<(), &'static str> {
+ match arch {
+ InlineAsmArch::X86 => {
+ Err("esi is used internally by LLVM and cannot be used as an operand for inline asm")
+ }
+ InlineAsmArch::X86_64 => Ok(()),
+ _ => unreachable!(),
+ }
+}
+
def_regs! {
X86 X86InlineAsmReg X86InlineAsmRegClass {
ax: reg, reg_abcd = ["ax", "eax", "rax"],
- bx: reg, reg_abcd = ["bx", "ebx", "rbx"],
+ bx: reg, reg_abcd = ["bx", "ebx", "rbx"] % rbx_reserved,
cx: reg, reg_abcd = ["cx", "ecx", "rcx"],
dx: reg, reg_abcd = ["dx", "edx", "rdx"],
- si: reg = ["si", "esi", "rsi"],
+ si: reg = ["si", "esi", "rsi"] % esi_reserved,
di: reg = ["di", "edi", "rdi"],
r8: reg = ["r8", "r8w", "r8d"] % x86_64_only,
r9: reg = ["r9", "r9w", "r9d"] % x86_64_only,
function_sections: false,
dynamic_linking: true,
executables: true,
- os_family: Some("unix".to_string()),
+ families: vec!["unix".to_string()],
is_like_osx: true,
dwarf_version: Some(2),
has_rpath: true,
os: "dragonfly".to_string(),
dynamic_linking: true,
executables: true,
- os_family: Some("unix".to_string()),
+ families: vec!["unix".to_string()],
linker_is_gnu: true,
has_rpath: true,
position_independent_executables: true,
os: "freebsd".to_string(),
dynamic_linking: true,
executables: true,
- os_family: Some("unix".to_string()),
+ families: vec!["unix".to_string()],
linker_is_gnu: true,
has_rpath: true,
position_independent_executables: true,
linker: Some("rust-lld".to_owned()),
dynamic_linking: true,
executables: true,
- os_family: Some("unix".to_string()),
+ families: vec!["unix".to_string()],
is_like_fuchsia: true,
linker_is_gnu: true,
pre_link_args,
os: "haiku".to_string(),
dynamic_linking: true,
executables: true,
- os_family: Some("unix".to_string()),
+ families: vec!["unix".to_string()],
relro_level: RelroLevel::Full,
linker_is_gnu: true,
..Default::default()
dynamic_linking: true,
executables: true,
has_rpath: true,
- os_family: Some("unix".to_string()),
+ families: vec!["unix".to_string()],
is_like_solaris: true,
limit_rdylib_exports: false, // Linker doesn't support this
eliminate_frame_pointer: false,
executables: true,
panic_strategy: PanicStrategy::Abort,
linker: Some("ld".to_string()),
- os_family: Some("unix".to_string()),
+ families: vec!["unix".to_string()],
..Default::default()
}
}
os: "linux".to_string(),
dynamic_linking: true,
executables: true,
- os_family: Some("unix".to_string()),
+ families: vec!["unix".to_string()],
linker_is_gnu: true,
has_rpath: true,
position_independent_executables: true,
pub staticlib_prefix: String,
/// String to append to the name of every static library. Defaults to ".a".
pub staticlib_suffix: String,
- /// OS family to use for conditional compilation. Valid options: "unix", "windows".
- pub os_family: Option<String>,
+ /// Values of the `target_family` cfg set for this target.
+ ///
+ /// Common options are: "unix", "windows". Defaults to no families.
+ ///
+ /// See <https://doc.rust-lang.org/reference/conditional-compilation.html#target_family>.
+ pub families: Vec<String>,
/// Whether the target toolchain's ABI supports returning small structs as an integer.
pub abi_return_struct_as_int: bool,
/// Whether the target toolchain is like macOS's. Only useful for compiling against iOS/macOS,
exe_suffix: String::new(),
staticlib_prefix: "lib".to_string(),
staticlib_suffix: ".a".to_string(),
- os_family: None,
+ families: Vec::new(),
abi_return_struct_as_int: false,
is_like_osx: false,
is_like_solaris: false,
.map(|s| s.to_string() );
}
} );
- ($key_name:ident = $json_name:expr, optional) => ( {
- let name = $json_name;
- if let Some(o) = obj.find(name) {
- base.$key_name = o
- .as_string()
- .map(|s| s.to_string() );
- }
- } );
($key_name:ident, LldFlavor) => ( {
let name = (stringify!($key_name)).replace("_", "-");
obj.find(&name[..]).and_then(|o| o.as_string().and_then(|s| {
Some(Ok(()))
})).unwrap_or(Ok(()))
} );
+ ($key_name:ident, TargetFamilies) => ( {
+ let value = obj.find("target-family");
+ if let Some(v) = value.and_then(Json::as_array) {
+ base.$key_name = v.iter()
+ .map(|a| a.as_string().unwrap().to_string())
+ .collect();
+ } else if let Some(v) = value.and_then(Json::as_string) {
+ base.$key_name = vec![v.to_string()];
+ }
+ } );
}
if let Some(s) = obj.find("target-endian").and_then(Json::as_string) {
key!(exe_suffix);
key!(staticlib_prefix);
key!(staticlib_suffix);
- key!(os_family = "target-family", optional);
+ key!(families, TargetFamilies);
key!(abi_return_struct_as_int, bool);
key!(is_like_osx, bool);
key!(is_like_solaris, bool);
target_option_val!(exe_suffix);
target_option_val!(staticlib_prefix);
target_option_val!(staticlib_suffix);
- target_option_val!(os_family, "target-family");
+ target_option_val!(families, "target-family");
target_option_val!(abi_return_struct_as_int);
target_option_val!(is_like_osx);
target_option_val!(is_like_solaris);
os: "netbsd".to_string(),
dynamic_linking: true,
executables: true,
- os_family: Some("unix".to_string()),
+ families: vec!["unix".to_string()],
linker_is_gnu: true,
no_default_libraries: false,
has_rpath: true,
os: "openbsd".to_string(),
dynamic_linking: true,
executables: true,
- os_family: Some("unix".to_string()),
+ families: vec!["unix".to_string()],
linker_is_gnu: true,
has_rpath: true,
abi_return_struct_as_int: true,
env: "relibc".to_string(),
dynamic_linking: true,
executables: true,
- os_family: Some("unix".to_string()),
+ families: vec!["unix".to_string()],
linker_is_gnu: true,
has_rpath: true,
position_independent_executables: true,
dynamic_linking: true,
executables: true,
has_rpath: true,
- os_family: Some("unix".to_string()),
+ families: vec!["unix".to_string()],
is_like_solaris: true,
limit_rdylib_exports: false, // Linker doesn't support this
eh_frame_header: false,
exe_suffix: ".vxe".to_string(),
dynamic_linking: true,
executables: true,
- os_family: Some("unix".to_string()),
+ families: vec!["unix".to_string()],
linker_is_gnu: true,
has_rpath: true,
has_elf_tls: true,
is_like_emscripten: true,
panic_strategy: PanicStrategy::Unwind,
post_link_args,
- os_family: Some("unix".to_string()),
+ families: vec!["unix".to_string()],
..options
};
Target {
TargetOptions {
is_like_wasm: true,
+ families: vec!["wasm".to_string()],
// we allow dynamic linking, but only cdylibs. Basically we allow a
// final library artifact that exports some symbols (a wasm module) but
dll_prefix: String::new(),
dll_suffix: ".dll".to_string(),
exe_suffix: ".exe".to_string(),
- os_family: Some("windows".to_string()),
+ families: vec!["windows".to_string()],
is_like_windows: true,
allows_weak_linkage: false,
pre_link_args,
exe_suffix: ".exe".to_string(),
staticlib_prefix: String::new(),
staticlib_suffix: ".lib".to_string(),
- os_family: Some("windows".to_string()),
+ families: vec!["windows".to_string()],
crt_static_allows_dylibs: true,
crt_static_respected: true,
requires_uwtable: true,
use rustc_data_structures::fx::FxIndexSet;
-use rustc_data_structures::svh::Svh;
use rustc_hir as hir;
use rustc_hir::def_id::{CrateNum, DefId, LocalDefId, LOCAL_CRATE};
use rustc_middle::hir::map as hir_map;
tcx.crate_name
}
-fn crate_hash(tcx: TyCtxt<'_>, crate_num: CrateNum) -> Svh {
- tcx.index_hir(crate_num).crate_hash
-}
-
fn instance_def_size_estimate<'tcx>(
tcx: TyCtxt<'tcx>,
instance_def: ty::InstanceDef<'tcx>,
trait_of_item,
crate_disambiguator,
original_crate_name,
- crate_hash,
instance_def_size_estimate,
issue33140_self_ty,
impl_defaultness,
| TypeFlags::HAS_CT_INFER.bits
| TypeFlags::HAS_TY_PLACEHOLDER.bits
| TypeFlags::HAS_CT_PLACEHOLDER.bits
+ // We consider 'freshened' types and constants
+ // to depend on a particular fn.
+ // The freshening process throws away information,
+ // which can make things unsuitable for use in a global
+ // cache. Note that there is no 'fresh lifetime' flag -
+ // freshening replaces all lifetimes with `ReErased`,
+ // which is different from how types/const are freshened.
+ | TypeFlags::HAS_TY_FRESH.bits
+ | TypeFlags::HAS_CT_FRESH.bits
| TypeFlags::HAS_FREE_LOCAL_REGIONS.bits;
/// Does this have `Projection`?
/// Does this value have parameters/placeholders/inference variables which could be
/// replaced later, in a way that would change the results of `impl` specialization?
const STILL_FURTHER_SPECIALIZABLE = 1 << 17;
+
+ /// Does this value have `InferTy::FreshTy/FreshIntTy/FreshFloatTy`?
+ const HAS_TY_FRESH = 1 << 18;
+
+ /// Does this value have `InferConst::Fresh`?
+ const HAS_CT_FRESH = 1 << 19;
}
}
// another. This is an error. However, if we already know that
// the arguments don't match up with the parameters, we won't issue
// an additional error, as the user already knows what's wrong.
- if arg_count.correct.is_ok()
- && arg_count.explicit_late_bound == ExplicitLateBound::No
- {
+ if arg_count.correct.is_ok() {
// We're going to iterate over the parameters to sort them out, and
// show that order to the user as a possible order for the parameters
let mut param_types_present = defs
}
if silent {
- return false;
+ return true;
}
if provided > expected_max {
use rustc_session::lint;
use rustc_session::lint::builtin::BARE_TRAIT_OBJECTS;
use rustc_session::parse::feature_err;
+use rustc_span::edition::Edition;
use rustc_span::source_map::{original_sp, DUMMY_SP};
use rustc_span::symbol::{kw, sym, Ident};
use rustc_span::{self, BytePos, MultiSpan, Span};
if let TyKind::TraitObject([poly_trait_ref, ..], _, TraitObjectSyntax::None) =
self_ty.kind
{
- self.tcx.struct_span_lint_hir(BARE_TRAIT_OBJECTS, hir_id, self_ty.span, |lint| {
- let mut db = lint
- .build(&format!("trait objects without an explicit `dyn` are deprecated"));
- let (sugg, app) = match self.tcx.sess.source_map().span_to_snippet(self_ty.span)
- {
- Ok(s) if poly_trait_ref.trait_ref.path.is_global() => {
- (format!("<dyn ({})>", s), Applicability::MachineApplicable)
- }
- Ok(s) => (format!("<dyn {}>", s), Applicability::MachineApplicable),
- Err(_) => ("<dyn <type>>".to_string(), Applicability::HasPlaceholders),
- };
- db.span_suggestion(self_ty.span, "use `dyn`", sugg, app);
- db.emit()
- });
+ let msg = "trait objects without an explicit `dyn` are deprecated";
+ let (sugg, app) = match self.tcx.sess.source_map().span_to_snippet(self_ty.span) {
+ Ok(s) if poly_trait_ref.trait_ref.path.is_global() => {
+ (format!("<dyn ({})>", s), Applicability::MachineApplicable)
+ }
+ Ok(s) => (format!("<dyn {}>", s), Applicability::MachineApplicable),
+ Err(_) => ("<dyn <type>>".to_string(), Applicability::HasPlaceholders),
+ };
+ let replace = String::from("use `dyn`");
+ if self.sess().edition() >= Edition::Edition2021 {
+ let mut err = rustc_errors::struct_span_err!(
+ self.sess(),
+ self_ty.span,
+ E0783,
+ "{}",
+ msg,
+ );
+ err.span_suggestion(
+ self_ty.span,
+ &sugg,
+ replace,
+ Applicability::MachineApplicable,
+ )
+ .emit();
+ } else {
+ self.tcx.struct_span_lint_hir(
+ BARE_TRAIT_OBJECTS,
+ hir_id,
+ self_ty.span,
+ |lint| {
+ let mut db = lint.build(msg);
+ db.span_suggestion(self_ty.span, &replace, sugg, app);
+ db.emit()
+ },
+ );
+ }
}
}
}
let mut infer_args_for_err = FxHashSet::default();
+ let mut explicit_late_bound = ExplicitLateBound::No;
for &PathSeg(def_id, index) in &path_segs {
let seg = &segments[index];
let generics = tcx.generics_of(def_id);
// parameter internally, but we don't allow users to specify the
// parameter's value explicitly, so we have to do some error-
// checking here.
- if let GenericArgCountResult {
- correct: Err(GenericArgCountMismatch { reported: Some(_), .. }),
- ..
- } = <dyn AstConv<'_>>::check_generic_arg_count_for_call(
+ let arg_count = <dyn AstConv<'_>>::check_generic_arg_count_for_call(
tcx,
span,
def_id,
&generics,
seg,
IsMethodCall::No,
- ) {
+ );
+
+ if let ExplicitLateBound::Yes = arg_count.explicit_late_bound {
+ explicit_late_bound = ExplicitLateBound::Yes;
+ }
+
+ if let Err(GenericArgCountMismatch { reported: Some(_), .. }) = arg_count.correct {
infer_args_for_err.insert(index);
self.set_tainted_by_errors(); // See issue #53251.
}
let ty = tcx.type_of(def_id);
let arg_count = GenericArgCountResult {
- explicit_late_bound: ExplicitLateBound::No,
+ explicit_late_bound,
correct: if infer_args_for_err.is_empty() {
Ok(())
} else {
match param.name {
hir::ParamName::Error => {}
- _ => report_bivariance(tcx, param.span, param.name.ident().name),
+ _ => report_bivariance(tcx, param),
}
}
}
-fn report_bivariance(tcx: TyCtxt<'_>, span: Span, param_name: Symbol) {
+fn report_bivariance(tcx: TyCtxt<'_>, param: &rustc_hir::GenericParam<'_>) {
+ let span = param.span;
+ let param_name = param.name.ident().name;
let mut err = error_392(tcx, span, param_name);
let suggested_marker_id = tcx.lang_items().phantom_data();
format!("consider removing `{}` or referring to it in a field", param_name)
};
err.help(&msg);
- err.emit();
+
+ if matches!(param.kind, rustc_hir::GenericParamKind::Type { .. }) {
+ err.help(&format!(
+ "if you intended `{0}` to be a const parameter, use `const {0}: usize` instead",
+ param_name
+ ));
+ }
+ err.emit()
}
/// Feature gates RFC 2056 -- trivial bounds, checking for global bounds that
PlaceBase::Local(*var_hir_id)
};
let place_with_id = PlaceWithHirId::new(
- capture_info.path_expr_id.unwrap_or(closure_expr.hir_id),
+ capture_info.path_expr_id.unwrap_or(
+ capture_info.capture_kind_expr_id.unwrap_or(closure_expr.hir_id),
+ ),
place.base_ty,
place_base,
place.projections.clone(),
//! /* Returns ownership to the caller */
//! struct Foo* foo_new(void);
//!
-//! /* Takes ownership from the caller; no-op when invoked with NULL */
+//! /* Takes ownership from the caller; no-op when invoked with null */
//! void foo_delete(struct Foo*);
//! ```
//!
}
}
+#[stable(feature = "u8_to_string_specialization", since = "1.54.0")]
+impl ToString for u8 {
+ #[inline]
+ fn to_string(&self) -> String {
+ let mut buf = String::with_capacity(3);
+ let mut n = *self;
+ if n >= 10 {
+ if n >= 100 {
+ buf.push((b'0' + n / 100) as char);
+ n %= 100;
+ }
+ buf.push((b'0' + n / 10) as char);
+ n %= 10;
+ }
+ buf.push((b'0' + n) as char);
+ buf
+ }
+}
+
+#[stable(feature = "i8_to_string_specialization", since = "1.54.0")]
+impl ToString for i8 {
+ #[inline]
+ fn to_string(&self) -> String {
+ let mut buf = String::with_capacity(4);
+ if self.is_negative() {
+ buf.push('-');
+ }
+ let mut n = self.unsigned_abs();
+ if n >= 10 {
+ if n >= 100 {
+ buf.push('1');
+ n -= 100;
+ }
+ buf.push((b'0' + n / 10) as char);
+ n %= 10;
+ }
+ buf.push((b'0' + n) as char);
+ buf
+ }
+}
+
#[stable(feature = "str_to_string_specialization", since = "1.9.0")]
impl ToString for str {
#[inline]
#[cfg(target_arch = "aarch64")]
{
// SAFETY: the `cfg` attr ensures that we only execute this on aarch64 targets.
- unsafe { crate::arch::aarch64::__yield() };
+ unsafe { crate::arch::aarch64::__isb(crate::arch::aarch64::SY) };
}
#[cfg(target_arch = "arm")]
{
/// [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.
+ /// `0`, the pointers must be non-null and properly aligned.
///
/// [`read`]: crate::ptr::read
/// [read-ownership]: crate::ptr::read#ownership-of-the-returned-value
/// [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.
+ /// `0`, the pointers must be non-null and properly aligned.
///
/// [`read`]: crate::ptr::read
/// [read-ownership]: crate::ptr::read#ownership-of-the-returned-value
/// invalid value of `T` is undefined behavior.
///
/// Note that even if the effectively copied size (`count * size_of::<T>()`) is
-/// `0`, the pointer must be non-NULL and properly aligned.
+/// `0`, the pointer must be non-null and properly aligned.
///
/// [valid]: crate::ptr#safety
///
///
/// The compiler, in general, assumes that a variable is properly initialized
/// according to the requirements of the variable's type. For example, a variable of
-/// reference type must be aligned and non-NULL. This is an invariant that must
+/// reference type must be aligned and non-null. This is an invariant that must
/// *always* be upheld, even in unsafe code. As a consequence, zero-initializing a
/// variable of reference type causes instantaneous [undefined behavior][ub],
/// no matter whether that reference ever gets used to access memory:
pub fn from_small(v: $ty) -> $name {
let mut base = [0; $n];
base[0] = v;
- $name { size: 1, base: base }
+ $name { size: 1, base }
}
/// Makes a bignum from `u64` value.
v >>= <$ty>::BITS;
sz += 1;
}
- $name { size: sz, base: base }
+ $name { size: sz, base }
}
/// Returns the internal digits as a slice `[a, b, c, ...]` such that the numeric
///
/// # Safety
///
- /// When calling this method, you have to ensure that *either* the pointer is NULL *or*
+ /// When calling this method, you have to ensure that *either* the pointer is null *or*
/// all of the following is true:
///
/// * The pointer must be properly aligned.
///
/// # Safety
///
- /// When calling this method, you have to ensure that *either* the pointer is NULL *or*
+ /// When calling this method, you have to ensure that *either* the pointer is null *or*
/// all of the following is true:
///
/// * The pointer must be properly aligned.
///
/// # Safety
///
- /// When calling this method, you have to ensure that *either* the pointer is NULL *or*
+ /// When calling this method, you have to ensure that *either* the pointer is null *or*
/// all of the following is true:
///
/// * The pointer must be [valid] for reads for `ptr.len() * mem::size_of::<T>()` many bytes,
/// again. [`write()`] can be used to overwrite data without causing it to be
/// dropped.
///
-/// Note that even if `T` has size `0`, the pointer must be non-NULL and properly aligned.
+/// Note that even if `T` has size `0`, the pointer must be non-null and properly aligned.
///
/// [valid]: self#safety
///
///
/// * Both `x` and `y` must be properly aligned.
///
-/// Note that even if `T` has size `0`, the pointers must be non-NULL and properly aligned.
+/// Note that even if `T` has size `0`, the pointers must be non-null and properly aligned.
///
/// [valid]: self#safety
///
/// beginning at `y` with the same size.
///
/// Note that even if the effectively copied size (`count * size_of::<T>()`) is `0`,
-/// the pointers must be non-NULL and properly aligned.
+/// the pointers must be non-null and properly aligned.
///
/// [valid]: self#safety
///
///
/// * `dst` must point to a properly initialized value of type `T`.
///
-/// Note that even if `T` has size `0`, the pointer must be non-NULL and properly aligned.
+/// Note that even if `T` has size `0`, the pointer must be non-null and properly aligned.
///
/// [valid]: self#safety
///
///
/// * `src` must point to a properly initialized value of type `T`.
///
-/// Note that even if `T` has size `0`, the pointer must be non-NULL and properly aligned.
+/// Note that even if `T` has size `0`, the pointer must be non-null and properly aligned.
///
/// # Examples
///
/// whether `T` is [`Copy`]. If `T` is not [`Copy`], using both the returned
/// value and the value at `*src` can [violate memory safety][read-ownership].
///
-/// Note that even if `T` has size `0`, the pointer must be non-NULL.
+/// Note that even if `T` has size `0`, the pointer must be non-null.
///
/// [read-ownership]: read#ownership-of-the-returned-value
/// [valid]: self#safety
///
/// ## On `packed` structs
///
-/// It is currently impossible to create raw pointers to unaligned fields
-/// of a packed struct.
-///
/// Attempting to create a raw pointer to an `unaligned` struct field with
/// an expression such as `&packed.unaligned as *const FieldType` creates an
/// intermediate unaligned reference before converting that to a raw pointer.
/// As a result, using `&packed.unaligned as *const FieldType` causes immediate
/// *undefined behavior* in your program.
///
+/// Instead you must use the [`ptr::addr_of!`](addr_of) macro to
+/// create the pointer. You may use that returned pointer together with this
+/// function.
+///
/// An example of what not to do and how this relates to `read_unaligned` is:
///
-/// ```no_run
+/// ```
/// #[repr(packed, C)]
/// struct Packed {
/// _padding: u8,
/// unaligned: 0x01020304,
/// };
///
-/// #[allow(unaligned_references)]
-/// let v = unsafe {
-/// // Here we attempt to take the address of a 32-bit integer which is not aligned.
-/// let unaligned =
-/// // A temporary unaligned reference is created here which results in
-/// // undefined behavior regardless of whether the reference is used or not.
-/// &packed.unaligned
-/// // Casting to a raw pointer doesn't help; the mistake already happened.
-/// as *const u32;
+/// // Take the address of a 32-bit integer which is not aligned.
+/// // In contrast to `&packed.unaligned as *const _`, this has no undefined behavior.
+/// let unaligned = std::ptr::addr_of!(packed.unaligned);
///
-/// let v = std::ptr::read_unaligned(unaligned);
-///
-/// v
-/// };
+/// let v = unsafe { std::ptr::read_unaligned(unaligned) };
+/// assert_eq!(v, 0x01020304);
/// ```
///
/// Accessing unaligned fields directly with e.g. `packed.unaligned` is safe however.
-// FIXME: Update docs based on outcome of RFC #2582 and friends.
///
/// # Examples
///
/// * `dst` must be properly aligned. Use [`write_unaligned`] if this is not the
/// case.
///
-/// Note that even if `T` has size `0`, the pointer must be non-NULL and properly aligned.
+/// Note that even if `T` has size `0`, the pointer must be non-null and properly aligned.
///
/// [valid]: self#safety
///
///
/// * `dst` must be [valid] for writes.
///
-/// Note that even if `T` has size `0`, the pointer must be non-NULL.
+/// Note that even if `T` has size `0`, the pointer must be non-null.
///
/// [valid]: self#safety
///
/// ## On `packed` structs
///
-/// It is currently impossible to create raw pointers to unaligned fields
-/// of a packed struct.
-///
/// Attempting to create a raw pointer to an `unaligned` struct field with
/// an expression such as `&packed.unaligned as *const FieldType` creates an
/// intermediate unaligned reference before converting that to a raw pointer.
/// As a result, using `&packed.unaligned as *const FieldType` causes immediate
/// *undefined behavior* in your program.
///
-/// An example of what not to do and how this relates to `write_unaligned` is:
+/// Instead you must use the [`ptr::addr_of_mut!`](addr_of_mut)
+/// macro to create the pointer. You may use that returned pointer together with
+/// this function.
+///
+/// An example of how to do it and how this relates to `write_unaligned` is:
///
-/// ```no_run
+/// ```
/// #[repr(packed, C)]
/// struct Packed {
/// _padding: u8,
/// unaligned: u32,
/// }
///
-/// let v = 0x01020304;
/// let mut packed: Packed = unsafe { std::mem::zeroed() };
///
-/// #[allow(unaligned_references)]
-/// let v = unsafe {
-/// // Here we attempt to take the address of a 32-bit integer which is not aligned.
-/// let unaligned =
-/// // A temporary unaligned reference is created here which results in
-/// // undefined behavior regardless of whether the reference is used or not.
-/// &mut packed.unaligned
-/// // Casting to a raw pointer doesn't help; the mistake already happened.
-/// as *mut u32;
+/// // Take the address of a 32-bit integer which is not aligned.
+/// // In contrast to `&packed.unaligned as *mut _`, this has no undefined behavior.
+/// let unaligned = std::ptr::addr_of_mut!(packed.unaligned);
///
-/// std::ptr::write_unaligned(unaligned, v);
+/// unsafe { std::ptr::write_unaligned(unaligned, 42) };
///
-/// v
-/// };
+/// assert_eq!({packed.unaligned}, 42); // `{...}` forces copying the field instead of creating a reference.
/// ```
///
-/// Accessing unaligned fields directly with e.g. `packed.unaligned` is safe however.
-// FIXME: Update docs based on outcome of RFC #2582 and friends.
+/// Accessing unaligned fields directly with e.g. `packed.unaligned` is safe however
+/// (as can be seen in the `assert_eq!` above).
///
/// # Examples
///
/// However, storing non-[`Copy`] types in volatile memory is almost certainly
/// incorrect.
///
-/// Note that even if `T` has size `0`, the pointer must be non-NULL and properly aligned.
+/// Note that even if `T` has size `0`, the pointer must be non-null and properly aligned.
///
/// [valid]: self#safety
/// [read-ownership]: read#ownership-of-the-returned-value
///
/// * `dst` must be properly aligned.
///
-/// Note that even if `T` has size `0`, the pointer must be non-NULL and properly aligned.
+/// Note that even if `T` has size `0`, the pointer must be non-null and properly aligned.
///
/// [valid]: self#safety
///
///
/// Note, however, that the `expr` in `addr_of!(expr)` is still subject to all
/// the usual rules. In particular, `addr_of!(*ptr::null())` is Undefined
-/// Behavior because it dereferences a NULL pointer.
+/// Behavior because it dereferences a null pointer.
///
/// # Example
///
///
/// Note, however, that the `expr` in `addr_of_mut!(expr)` is still subject to all
/// the usual rules. In particular, `addr_of_mut!(*ptr::null_mut())` is Undefined
-/// Behavior because it dereferences a NULL pointer.
+/// Behavior because it dereferences a null pointer.
///
/// # Examples
///
///
/// # Safety
///
- /// When calling this method, you have to ensure that *either* the pointer is NULL *or*
+ /// When calling this method, you have to ensure that *either* the pointer is null *or*
/// all of the following is true:
///
/// * The pointer must be properly aligned.
///
/// # Safety
///
- /// When calling this method, you have to ensure that *either* the pointer is NULL *or*
+ /// When calling this method, you have to ensure that *either* the pointer is null *or*
/// all of the following is true:
///
/// * The pointer must be properly aligned.
///
/// # Safety
///
- /// When calling this method, you have to ensure that *either* the pointer is NULL *or*
+ /// When calling this method, you have to ensure that *either* the pointer is null *or*
/// all of the following is true:
///
/// * The pointer must be properly aligned.
///
/// # Safety
///
- /// When calling this method, you have to ensure that *either* the pointer is NULL *or*
+ /// When calling this method, you have to ensure that *either* the pointer is null *or*
/// all of the following is true:
///
/// * The pointer must be properly aligned.
///
/// # Safety
///
- /// When calling this method, you have to ensure that *either* the pointer is NULL *or*
+ /// When calling this method, you have to ensure that *either* the pointer is null *or*
/// all of the following is true:
///
/// * The pointer must be [valid] for reads for `ptr.len() * mem::size_of::<T>()` many bytes,
///
/// # Safety
///
- /// When calling this method, you have to ensure that *either* the pointer is NULL *or*
+ /// When calling this method, you have to ensure that *either* the pointer is null *or*
/// all of the following is true:
///
/// * The pointer must be [valid] for reads and writes for `ptr.len() * mem::size_of::<T>()`
I: SliceIndex<[T]>,
{
// SAFETY: the caller ensures that `self` is dereferencable and `index` in-bounds.
- // As a consequence, the resulting pointer cannot be NULL.
+ // As a consequence, the resulting pointer cannot be null.
unsafe { NonNull::new_unchecked(self.as_ptr().get_unchecked_mut(index)) }
}
}
}
pub unsafe fn cleanup(payload: *mut u8) -> Box<dyn Any + Send> {
- // A NULL payload here means that we got here from the catch (...) of
+ // A null payload here means that we got here from the catch (...) of
// __rust_try. This happens when a non-Rust foreign exception is caught.
if payload.is_null() {
super::__rust_foreign_exception();
/// assert!(env::set_current_dir(&root).is_ok());
/// println!("Successfully changed working directory to {}!", root.display());
/// ```
+#[doc(alias = "chdir")]
#[stable(feature = "env", since = "1.0.0")]
pub fn set_current_dir<P: AsRef<Path>>(path: P) -> io::Result<()> {
os_imp::chdir(path.as_ref())
/// Failure to call [`CString::from_raw`] will lead to a memory leak.
///
/// The C side must **not** modify the length of the string (by writing a
- /// `NULL` somewhere inside the string or removing the final one) before
+ /// `null` somewhere inside the string or removing the final one) before
/// it makes it back into Rust using [`CString::from_raw`]. See the safety section
/// in [`CString::from_raw`].
///
/// This means that the operation can never succeed.
#[stable(feature = "unsupported_error", since = "1.53.0")]
Unsupported,
+
+ /// An operation could not be completed, because it failed
+ /// to allocate enough memory.
+ #[stable(feature = "out_of_memory_error", since = "1.54.0")]
+ OutOfMemory,
}
impl ErrorKind {
ErrorKind::Other => "other os error",
ErrorKind::UnexpectedEof => "unexpected end of file",
ErrorKind::Unsupported => "unsupported",
+ ErrorKind::OutOfMemory => "out of memory",
}
}
}
/// This will return an error when the IP version of the local socket
/// does not match that returned from [`ToSocketAddrs`].
///
- /// See issue #34202 for more details.
+ /// See [Issue #34202] for more details.
///
/// # Examples
///
/// let socket = UdpSocket::bind("127.0.0.1:34254").expect("couldn't bind to address");
/// socket.send_to(&[0; 10], "127.0.0.1:4242").expect("couldn't send data");
/// ```
+ ///
+ /// [Issue #34202]: https://github.com/rust-lang/rust/issues/34202
#[stable(feature = "rust1", since = "1.0.0")]
pub fn send_to<A: ToSocketAddrs>(&self, buf: &[u8], addr: A) -> io::Result<usize> {
match addr.to_socket_addrs()?.next() {
/// Note that here the call to [`drop`] is for clarity - it indicates
/// that we are done with the given value and it should be destroyed.
///
-/// ## 3. Get it from C.
+/// ## 3. Create it using `ptr::addr_of!`
+///
+/// Instead of coercing a reference to a raw pointer, you can use the macros
+/// [`ptr::addr_of!`] (for `*const T`) and [`ptr::addr_of_mut!`] (for `*mut T`).
+/// These macros allow you to create raw pointers to fields to which you cannot
+/// create a reference (without causing undefined behaviour), such as an
+/// unaligned field. This might be necessary if packed structs or uninitialized
+/// memory is involved.
+///
+/// ```
+/// #[derive(Debug, Default, Copy, Clone)]
+/// #[repr(C, packed)]
+/// struct S {
+/// aligned: u8,
+/// unaligned: u32,
+/// }
+/// let s = S::default();
+/// let p = std::ptr::addr_of!(s.unaligned); // not allowed with coercion
+/// ```
+///
+/// ## 4. Get it from C.
///
/// ```
/// # #![feature(rustc_private)]
let error;
asm!(
+ // rbx is reserved by LLVM
+ "xchg {0}, rbx",
"enclu",
+ "mov rbx, {0}",
+ inout(reg) request => _,
inlateout("eax") ENCLU_EGETKEY => error,
- in("rbx") request,
in("rcx") out.as_mut_ptr(),
options(nostack),
);
let mut report = MaybeUninit::uninit();
asm!(
+ // rbx is reserved by LLVM
+ "xchg {0}, rbx",
"enclu",
+ "mov rbx, {0}",
+ inout(reg) targetinfo => _,
in("eax") ENCLU_EREPORT,
- in("rbx") targetinfo,
in("rcx") reportdata,
in("rdx") report.as_mut_ptr(),
options(preserves_flags, nostack),
msg.msg_controllen = ancillary.buffer.len() as libc::socklen_t;
}
}
- // macos requires that the control pointer is NULL when the len is 0.
+ // macos requires that the control pointer is null when the len is 0.
if msg.msg_controllen > 0 {
msg.msg_control = ancillary.buffer.as_mut_ptr().cast();
}
msg.msg_controllen = ancillary.length as libc::socklen_t;
}
}
- // macos requires that the control pointer is NULL when the len is 0.
+ // macos requires that the control pointer is null when the len is 0.
if msg.msg_controllen > 0 {
msg.msg_control = ancillary.buffer.as_mut_ptr().cast();
}
match STATX_STATE.load(Ordering::Relaxed) {
0 => {
- // It is a trick to call `statx` with NULL pointers to check if the syscall
+ // It is a trick to call `statx` with null pointers to check if the syscall
// is available. According to the manual, it is expected to fail with EFAULT.
// We do this mainly for performance, since it is nearly hundreds times
// faster than a normal successful call.
super::os::set_errno(0);
let entry_ptr = libc::readdir(self.inner.dirp.0);
if entry_ptr.is_null() {
- // NULL can mean either the end is reached or an error occurred.
+ // null can mean either the end is reached or an error occurred.
// So we had to clear errno beforehand to check for an error now.
return match super::os::errno() {
0 => None,
libc::ETIMEDOUT => ErrorKind::TimedOut,
libc::EEXIST => ErrorKind::AlreadyExists,
libc::ENOSYS => ErrorKind::Unsupported,
+ libc::ENOMEM => ErrorKind::OutOfMemory,
// These two constants can have the same value on some systems,
// but different values on others, so we can't use a match
}
pub fn arg(&mut self, arg: &OsStr) {
- // Overwrite the trailing NULL pointer in `argv` and then add a new null
+ // Overwrite the trailing null pointer in `argv` and then add a new null
// pointer.
let arg = os2c(arg, &mut self.saw_nul);
self.argv.0[self.args.len()] = arg.as_ptr();
wasi::ERRNO_EXIST => AlreadyExists,
wasi::ERRNO_AGAIN => WouldBlock,
wasi::ERRNO_NOSYS => Unsupported,
+ wasi::ERRNO_NOMEM => OutOfMemory,
_ => Other,
}
}
pub const ERROR_PATH_NOT_FOUND: DWORD = 3;
pub const ERROR_ACCESS_DENIED: DWORD = 5;
pub const ERROR_INVALID_HANDLE: DWORD = 6;
+pub const ERROR_NOT_ENOUGH_MEMORY: DWORD = 8;
+pub const ERROR_OUTOFMEMORY: DWORD = 14;
pub const ERROR_NO_MORE_FILES: DWORD = 18;
pub const ERROR_HANDLE_EOF: DWORD = 38;
pub const ERROR_FILE_EXISTS: DWORD = 80;
c::ERROR_PATH_NOT_FOUND => return ErrorKind::NotFound,
c::ERROR_NO_DATA => return ErrorKind::BrokenPipe,
c::ERROR_INVALID_PARAMETER => return ErrorKind::InvalidInput,
+ c::ERROR_NOT_ENOUGH_MEMORY | c::ERROR_OUTOFMEMORY => return ErrorKind::OutOfMemory,
c::ERROR_SEM_TIMEOUT
| c::WAIT_TIMEOUT
| c::ERROR_DRIVER_CANCEL_TIMEOUT
unsafe extern "C" fn destroy_value<T: 'static>(ptr: *mut u8) {
// SAFETY:
//
- // The OS TLS ensures that this key contains a NULL value when this
+ // The OS TLS ensures that this key contains a null value when this
// destructor starts to run. We set it back to a sentinel value of 1 to
// ensure that any future calls to `get` for this thread will return
// `None`.
filename = "rustc-{}-{}{}".format(rustc_channel, self.build,
tarball_suffix)
self._download_component_helper(filename, "rustc", tarball_suffix, stage0)
- filename = "cargo-{}-{}{}".format(rustc_channel, self.build,
- tarball_suffix)
- self._download_component_helper(filename, "cargo", tarball_suffix)
- if not stage0:
+ # download-rustc doesn't need its own cargo, it can just use beta's.
+ if stage0:
+ filename = "cargo-{}-{}{}".format(rustc_channel, self.build,
+ tarball_suffix)
+ self._download_component_helper(filename, "cargo", tarball_suffix)
+ self.fix_bin_or_dylib("{}/bin/cargo".format(bin_root))
+ else:
filename = "rustc-dev-{}-{}{}".format(rustc_channel, self.build, tarball_suffix)
self._download_component_helper(
filename, "rustc-dev", tarball_suffix, stage0
self.fix_bin_or_dylib("{}/bin/rustc".format(bin_root))
self.fix_bin_or_dylib("{}/bin/rustdoc".format(bin_root))
- self.fix_bin_or_dylib("{}/bin/cargo".format(bin_root))
lib_dir = "{}/lib".format(bin_root)
for lib in os.listdir(lib_dir):
if lib.endswith(".so"):
builder.info(&format!("doc tests for: {}", markdown.display()));
let mut cmd = builder.rustdoc_cmd(compiler);
builder.add_rust_test_threads(&mut cmd);
+ // allow for unstable options such as new editions
+ cmd.arg("-Z");
+ cmd.arg("unstable-options");
cmd.arg("--test");
cmd.arg(markdown);
cmd.env("RUSTC_BOOTSTRAP", "1");
let compiler = builder.compiler(builder.top_stage.saturating_sub(1), builder.config.build);
let mut cmd = Command::new(builder.ensure(ErrorIndex { compiler }));
add_dylib_path(
- vec![PathBuf::from(&builder.sysroot_libdir(compiler, compiler.host))],
+ vec![
+ PathBuf::from(&builder.sysroot_libdir(compiler, compiler.host)),
+ PathBuf::from(builder.rustc_libdir(compiler)),
+ ],
&mut cmd,
);
cmd
source "$(cd "$(dirname "$0")" && pwd)/../shared.sh"
# Update both macOS's and Windows's tarballs when bumping the version here.
-LLVM_VERSION="10.0.0"
+LLVM_VERSION="12.0.0"
if isMacOS; then
# If the job selects a specific Xcode version, use that instead of
# clang has an output mode compatible with MinGW that we need. If it does we
# should switch to clang for MinGW as well!
#
- # Note that the LLVM installer is an NSIS installer
- #
- # Original downloaded here came from:
- #
- # https://github.com/llvm/llvm-project/releases/download/llvmorg-10.0.0/LLVM-10.0.0-win64.exe
- #
- # That installer was run through `wine ./installer.exe /S /NCRC` on Linux
- # and then the resulting installation directory (found in
- # `$HOME/.wine/drive_c/Program Files/LLVM`) was packaged up into a tarball.
- # We've had issues otherwise that the installer will randomly hang, provide
- # not a lot of useful information, pollute global state, etc. In general the
- # tarball is just more confined and easier to deal with when working with
- # various CI environments.
+ # The LLVM installer is an NSIS installer, which we can extract with 7z. We
+ # don't want to run the installer directly; extracting it is more reliable
+ # in CI environments.
- mkdir -p citools
+ mkdir -p citools/clang-rust
cd citools
- curl -f "${MIRRORS_BASE}/LLVM-${LLVM_VERSION}-win64.tar.gz" | tar xzf -
+ curl -f "${MIRRORS_BASE}/LLVM-${LLVM_VERSION}-win64.exe" -o "LLVM-${LLVM_VERSION}-win64.exe"
+ 7z x -oclang-rust/ "LLVM-${LLVM_VERSION}-win64.exe"
ciCommandSetEnv RUST_CONFIGURE_ARGS \
"${RUST_CONFIGURE_ARGS} --set llvm.clang-cl=$(pwd)/clang-rust/bin/clang-cl.exe"
fi
}
</style>
-Support for different platforms are organized into three tiers, each with a
-different set of guarantees. For more information on the policies for targets
-at each tier, see the [Target Tier Policy](target-tier-policy.md).
+Support for different platforms ("targets") are organized into three tiers,
+each with a different set of guarantees. For more information on the policies
+for targets at each tier, see the [Target Tier Policy](target-tier-policy.md).
-Platforms are identified by their "target triple" which is the string to
-inform the compiler what kind of output should be produced. The columns in the
-tables below have the following meanings:
+Targets are identified by their "target triple" which is the string to inform
+the compiler what kind of output should be produced.
-* std:
- * ✓ indicates the full standard library is available.
- * \* indicates the target only supports [`no_std`] development.
- * ? indicates the standard library support is unknown or a work-in-progress.
-* host: A ✓ indicates that `rustc` and `cargo` can run on the host platform.
+## Tier 1 with Host Tools
-[`no_std`]: https://rust-embedded.github.io/book/intro/no-std.html
-
-## Tier 1
+Tier 1 targets can be thought of as "guaranteed to work". The Rust project
+builds official binary releases for each tier 1 target, and automated testing
+ensures that each tier 1 target builds and passes tests after each change.
-Tier 1 platforms can be thought of as "guaranteed to work".
-Specifically they will each satisfy the following requirements:
+Tier 1 targets with host tools additionally support running tools like `rustc`
+and `cargo` natively on the target, and automated testing ensures that tests
+pass for the host tools as well. This allows the target to be used as a
+development platform, not just a compilation target. For the full requirements,
+see [Tier 1 with Host Tools](target-tier-policy.md#tier-1-with-host-tools) in
+the Target Tier Policy.
-* Official binary releases are provided for the platform.
-* Automated testing is set up to run tests for the platform.
-* Landing changes to the `rust-lang/rust` repository's master branch is gated
- on tests passing.
-* Documentation for how to use and how to build the platform is available.
+All tier 1 targets with host tools support the full standard library.
-target | std | host | notes
--------|-----|------|-------
-`aarch64-unknown-linux-gnu` | ✓ | ✓ | ARM64 Linux (kernel 4.2, glibc 2.17+) [^missing-stack-probes]
-`i686-pc-windows-gnu` | ✓ | ✓ | 32-bit MinGW (Windows 7+)
-`i686-pc-windows-msvc` | ✓ | ✓ | 32-bit MSVC (Windows 7+)
-`i686-unknown-linux-gnu` | ✓ | ✓ | 32-bit Linux (kernel 2.6.32+, glibc 2.11+)
-`x86_64-apple-darwin` | ✓ | ✓ | 64-bit macOS (10.7+, Lion+)
-`x86_64-pc-windows-gnu` | ✓ | ✓ | 64-bit MinGW (Windows 7+)
-`x86_64-pc-windows-msvc` | ✓ | ✓ | 64-bit MSVC (Windows 7+)
-`x86_64-unknown-linux-gnu` | ✓ | ✓ | 64-bit Linux (kernel 2.6.32+, glibc 2.11+)
+target | notes
+-------|-------
+`aarch64-unknown-linux-gnu` | ARM64 Linux (kernel 4.2, glibc 2.17+) [^missing-stack-probes]
+`i686-pc-windows-gnu` | 32-bit MinGW (Windows 7+)
+`i686-pc-windows-msvc` | 32-bit MSVC (Windows 7+)
+`i686-unknown-linux-gnu` | 32-bit Linux (kernel 2.6.32+, glibc 2.11+)
+`x86_64-apple-darwin` | 64-bit macOS (10.7+, Lion+)
+`x86_64-pc-windows-gnu` | 64-bit MinGW (Windows 7+)
+`x86_64-pc-windows-msvc` | 64-bit MSVC (Windows 7+)
+`x86_64-unknown-linux-gnu` | 64-bit Linux (kernel 2.6.32+, glibc 2.11+)
[^missing-stack-probes]: Stack probes support is missing on
`aarch64-unknown-linux-gnu`, but it's planned to be implemented in the near
[77071]: https://github.com/rust-lang/rust/issues/77071
+## Tier 1
+
+Tier 1 targets can be thought of as "guaranteed to work". The Rust project
+builds official binary releases for each tier 1 target, and automated testing
+ensures that each tier 1 target builds and passes tests after each change. For
+the full requirements, see [Tier 1 target
+policy](target-tier-policy.md#tier-1-target-policy) in the Target Tier Policy.
+
+At this time, all Tier 1 targets are [Tier 1 with Host
+Tools](#tier-1-with-host-tools).
+
+## Tier 2 with Host Tools
+
+Tier 2 targets can be thought of as "guaranteed to build". The Rust project
+builds official binary releases for each tier 2 target, and automated builds
+ensure that each tier 2 target builds after each change. Automated tests are
+not always run so it's not guaranteed to produce a working build, but tier 2
+targets often work to quite a good degree and patches are always welcome!
+
+Tier 2 targets with host tools additionally support running tools like `rustc`
+and `cargo` natively on the target, and automated builds ensure that the host
+tools build as well. This allows the target to be used as a development
+platform, not just a compilation target. For the full requirements, see [Tier 2
+with Host Tools](target-tier-policy.md#tier-2-with-host-tools) in the Target
+Tier Policy.
+
+All tier 2 targets with host tools support the full standard library.
+
+target | notes
+-------|-------
+`aarch64-apple-darwin` | ARM64 macOS (11.0+, Big Sur+)
+`aarch64-pc-windows-msvc` | ARM64 Windows MSVC
+`aarch64-unknown-linux-musl` | ARM64 Linux with MUSL
+`arm-unknown-linux-gnueabi` | ARMv6 Linux (kernel 3.2, glibc 2.17)
+`arm-unknown-linux-gnueabihf` | ARMv6 Linux, hardfloat (kernel 3.2, glibc 2.17)
+`armv7-unknown-linux-gnueabihf` | ARMv7 Linux, hardfloat (kernel 3.2, glibc 2.17)
+`mips-unknown-linux-gnu` | MIPS Linux (kernel 4.4, glibc 2.23)
+`mips64-unknown-linux-gnuabi64` | MIPS64 Linux, n64 ABI (kernel 4.4, glibc 2.23)
+`mips64el-unknown-linux-gnuabi64` | MIPS64 (LE) Linux, n64 ABI (kernel 4.4, glibc 2.23)
+`mipsel-unknown-linux-gnu` | MIPS (LE) Linux (kernel 4.4, glibc 2.23)
+`powerpc-unknown-linux-gnu` | PowerPC Linux (kernel 2.6.32, glibc 2.11)
+`powerpc64-unknown-linux-gnu` | PPC64 Linux (kernel 2.6.32, glibc 2.11)
+`powerpc64le-unknown-linux-gnu` | PPC64LE Linux (kernel 3.10, glibc 2.17)
+`riscv64gc-unknown-linux-gnu` | RISC-V Linux (kernel 4.20, glibc 2.29)
+`s390x-unknown-linux-gnu` | S390x Linux (kernel 2.6.32, glibc 2.11)
+`x86_64-unknown-freebsd` | 64-bit FreeBSD
+`x86_64-unknown-illumos` | illumos
+`x86_64-unknown-linux-musl` | 64-bit Linux with MUSL
+`x86_64-unknown-netbsd` | NetBSD/amd64
+
## Tier 2
-Tier 2 platforms can be thought of as "guaranteed to build". Automated tests
-are not run so it's not guaranteed to produce a working build, but platforms
-often work to quite a good degree and patches are always welcome!
-Specifically, these platforms are required to have each of the following:
+Tier 2 targets can be thought of as "guaranteed to build". The Rust project
+builds official binary releases for each tier 2 target, and automated builds
+ensure that each tier 2 target builds after each change. Automated tests are
+not always run so it's not guaranteed to produce a working build, but tier 2
+targets often work to quite a good degree and patches are always welcome! For
+the full requirements, see [Tier 2 target
+policy](target-tier-policy.md#tier-2-target-policy) in the Target Tier Policy.
-* Official binary releases are provided for the platform.
-* Automated building is set up, but may not be running tests.
-* Landing changes to the `rust-lang/rust` repository's master branch is gated on
- platforms **building**. For some platforms only the standard library is
- compiled, but for others `rustc` and `cargo` are too.
+The `std` column in the table below has the following meanings:
-target | std | host | notes
--------|-----|------|-------
-`aarch64-apple-darwin` | ✓ | ✓ | ARM64 macOS (11.0+, Big Sur+)
-`aarch64-apple-ios` | ✓ | | ARM64 iOS
-`aarch64-fuchsia` | ✓ | | ARM64 Fuchsia
-`aarch64-linux-android` | ✓ | | ARM64 Android
-`aarch64-pc-windows-msvc` | ✓ | ✓ | ARM64 Windows MSVC
-`aarch64-unknown-linux-musl` | ✓ | ✓ | ARM64 Linux with MUSL
-`aarch64-unknown-none` | * | | Bare ARM64, hardfloat
-`aarch64-unknown-none-softfloat` | * | | Bare ARM64, softfloat
-`arm-linux-androideabi` | ✓ | | ARMv7 Android
-`arm-unknown-linux-gnueabi` | ✓ | ✓ | ARMv6 Linux (kernel 3.2, glibc 2.17)
-`arm-unknown-linux-gnueabihf` | ✓ | ✓ | ARMv6 Linux, hardfloat (kernel 3.2, glibc 2.17)
-`arm-unknown-linux-musleabi` | ✓ | | ARMv6 Linux with MUSL
-`arm-unknown-linux-musleabihf` | ✓ | | ARMv6 Linux with MUSL, hardfloat
-`armebv7r-none-eabi` | * | | Bare ARMv7-R, Big Endian
-`armebv7r-none-eabihf` | * | | Bare ARMv7-R, Big Endian, hardfloat
-`armv5te-unknown-linux-gnueabi` | ✓ | | ARMv5TE Linux (kernel 4.4, glibc 2.23)
-`armv5te-unknown-linux-musleabi` | ✓ | | ARMv5TE Linux with MUSL
-`armv7-linux-androideabi` | ✓ | | ARMv7a Android
-`armv7a-none-eabi` | * | | Bare ARMv7-A
-`armv7r-none-eabi` | * | | Bare ARMv7-R
-`armv7r-none-eabihf` | * | | Bare ARMv7-R, hardfloat
-`armv7-unknown-linux-gnueabi` | ✓ | | ARMv7 Linux (kernel 4.15, glibc 2.27)
-`armv7-unknown-linux-gnueabihf` | ✓ | ✓ | ARMv7 Linux, hardfloat (kernel 3.2, glibc 2.17)
-`armv7-unknown-linux-musleabi` | ✓ | | ARMv7 Linux, MUSL
-`armv7-unknown-linux-musleabihf` | ✓ | | ARMv7 Linux with MUSL
-`asmjs-unknown-emscripten` | ✓ | | asm.js via Emscripten
-`i586-pc-windows-msvc` | ✓ | | 32-bit Windows w/o SSE
-`i586-unknown-linux-gnu` | ✓ | | 32-bit Linux w/o SSE (kernel 4.4, glibc 2.23)
-`i586-unknown-linux-musl` | ✓ | | 32-bit Linux w/o SSE, MUSL
-`i686-linux-android` | ✓ | | 32-bit x86 Android
-`i686-unknown-freebsd` | ✓ | | 32-bit FreeBSD
-`i686-unknown-linux-musl` | ✓ | | 32-bit Linux with MUSL
-`mips-unknown-linux-gnu` | ✓ | ✓ | MIPS Linux (kernel 4.4, glibc 2.23)
-`mips-unknown-linux-musl` | ✓ | | MIPS Linux with MUSL
-`mips64-unknown-linux-gnuabi64` | ✓ | ✓ | MIPS64 Linux, n64 ABI (kernel 4.4, glibc 2.23)
-`mips64-unknown-linux-muslabi64` | ✓ | | MIPS64 Linux, n64 ABI, MUSL
-`mips64el-unknown-linux-gnuabi64` | ✓ | ✓ | MIPS64 (LE) Linux, n64 ABI (kernel 4.4, glibc 2.23)
-`mips64el-unknown-linux-muslabi64` | ✓ | | MIPS64 (LE) Linux, n64 ABI, MUSL
-`mipsel-unknown-linux-gnu` | ✓ | ✓ | MIPS (LE) Linux (kernel 4.4, glibc 2.23)
-`mipsel-unknown-linux-musl` | ✓ | | MIPS (LE) Linux with MUSL
-`nvptx64-nvidia-cuda` | ✓ | | --emit=asm generates PTX code that [runs on NVIDIA GPUs]
-`powerpc-unknown-linux-gnu` | ✓ | ✓ | PowerPC Linux (kernel 2.6.32, glibc 2.11)
-`powerpc64-unknown-linux-gnu` | ✓ | ✓ | PPC64 Linux (kernel 2.6.32, glibc 2.11)
-`powerpc64le-unknown-linux-gnu` | ✓ | ✓ | PPC64LE Linux (kernel 3.10, glibc 2.17)
-`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)
-`riscv64gc-unknown-linux-gnu` | ✓ | ✓ | RISC-V Linux (kernel 4.20, glibc 2.29)
-`riscv64gc-unknown-none-elf` | * | | Bare RISC-V (RV64IMAFDC ISA)
-`riscv64imac-unknown-none-elf` | * | | Bare RISC-V (RV64IMAC ISA)
-`s390x-unknown-linux-gnu` | ✓ | ✓ | S390x Linux (kernel 2.6.32, glibc 2.11)
-`sparc64-unknown-linux-gnu` | ✓ | | SPARC Linux (kernel 4.4, glibc 2.23)
-`sparcv9-sun-solaris` | ✓ | | SPARC Solaris 10/11, illumos
-`thumbv6m-none-eabi` | * | | Bare Cortex-M0, M0+, M1
-`thumbv7em-none-eabi` | * | | Bare Cortex-M4, M7
-`thumbv7em-none-eabihf` | * | | Bare Cortex-M4F, M7F, FPU, hardfloat
-`thumbv7m-none-eabi` | * | | Bare Cortex-M3
-`thumbv7neon-linux-androideabi` | ✓ | | Thumb2-mode ARMv7a Android with NEON
-`thumbv7neon-unknown-linux-gnueabihf` | ✓ | | Thumb2-mode ARMv7a Linux with NEON (kernel 4.4, glibc 2.23)
-`thumbv8m.base-none-eabi` | * | | ARMv8-M Baseline
-`thumbv8m.main-none-eabi` | * | | ARMv8-M Mainline
-`thumbv8m.main-none-eabihf` | * | | ARMv8-M Mainline, hardfloat
-`wasm32-unknown-emscripten` | ✓ | | WebAssembly via Emscripten
-`wasm32-unknown-unknown` | ✓ | | WebAssembly
-`wasm32-wasi` | ✓ | | WebAssembly with WASI
-`x86_64-apple-ios` | ✓ | | 64-bit x86 iOS
-`x86_64-fortanix-unknown-sgx` | ✓ | | [Fortanix ABI] for 64-bit Intel SGX
-`x86_64-fuchsia` | ✓ | | 64-bit Fuchsia
-`x86_64-linux-android` | ✓ | | 64-bit x86 Android
-`x86_64-pc-solaris` | ✓ | | 64-bit Solaris 10/11, illumos
-`x86_64-unknown-freebsd` | ✓ | ✓ | 64-bit FreeBSD
-`x86_64-unknown-illumos` | ✓ | ✓ | illumos
-`x86_64-unknown-linux-gnux32` | ✓ | | 64-bit Linux (x32 ABI) (kernel 4.15, glibc 2.27)
-`x86_64-unknown-linux-musl` | ✓ | ✓ | 64-bit Linux with MUSL
-`x86_64-unknown-netbsd` | ✓ | ✓ | NetBSD/amd64
-`x86_64-unknown-redox` | ✓ | | Redox OS
+* ✓ indicates the full standard library is available.
+* \* indicates the target only supports [`no_std`] development.
+
+[`no_std`]: https://rust-embedded.github.io/book/intro/no-std.html
+
+target | std | notes
+-------|-----|-------
+`aarch64-apple-ios` | ✓ | ARM64 iOS
+`aarch64-fuchsia` | ✓ | ARM64 Fuchsia
+`aarch64-linux-android` | ✓ | ARM64 Android
+`aarch64-unknown-none-softfloat` | * | Bare ARM64, softfloat
+`aarch64-unknown-none` | * | Bare ARM64, hardfloat
+`arm-linux-androideabi` | ✓ | ARMv7 Android
+`arm-unknown-linux-musleabi` | ✓ | ARMv6 Linux with MUSL
+`arm-unknown-linux-musleabihf` | ✓ | ARMv6 Linux with MUSL, hardfloat
+`armebv7r-none-eabi` | * | Bare ARMv7-R, Big Endian
+`armebv7r-none-eabihf` | * | Bare ARMv7-R, Big Endian, hardfloat
+`armv5te-unknown-linux-gnueabi` | ✓ | ARMv5TE Linux (kernel 4.4, glibc 2.23)
+`armv5te-unknown-linux-musleabi` | ✓ | ARMv5TE Linux with MUSL
+`armv7-linux-androideabi` | ✓ | ARMv7a Android
+`armv7-unknown-linux-gnueabi` | ✓ |ARMv7 Linux (kernel 4.15, glibc 2.27)
+`armv7-unknown-linux-musleabi` | ✓ |ARMv7 Linux, MUSL
+`armv7-unknown-linux-musleabihf` | ✓ | ARMv7 Linux with MUSL
+`armv7a-none-eabi` | * | Bare ARMv7-A
+`armv7r-none-eabi` | * | Bare ARMv7-R
+`armv7r-none-eabihf` | * | Bare ARMv7-R, hardfloat
+`asmjs-unknown-emscripten` | ✓ | asm.js via Emscripten
+`i586-pc-windows-msvc` | ✓ | 32-bit Windows w/o SSE
+`i586-unknown-linux-gnu` | ✓ | 32-bit Linux w/o SSE (kernel 4.4, glibc 2.23)
+`i586-unknown-linux-musl` | ✓ | 32-bit Linux w/o SSE, MUSL
+`i686-linux-android` | ✓ | 32-bit x86 Android
+`i686-unknown-freebsd` | ✓ | 32-bit FreeBSD
+`i686-unknown-linux-musl` | ✓ | 32-bit Linux with MUSL
+`mips-unknown-linux-musl` | ✓ | MIPS Linux with MUSL
+`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]
+`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)
+`riscv64gc-unknown-none-elf` | * | Bare RISC-V (RV64IMAFDC ISA)
+`riscv64imac-unknown-none-elf` | * | Bare RISC-V (RV64IMAC ISA)
+`sparc64-unknown-linux-gnu` | ✓ | SPARC Linux (kernel 4.4, glibc 2.23)
+`sparcv9-sun-solaris` | ✓ | SPARC Solaris 10/11, illumos
+`thumbv6m-none-eabi` | * | Bare Cortex-M0, M0+, M1
+`thumbv7em-none-eabi` | * | Bare Cortex-M4, M7
+`thumbv7em-none-eabihf` | * | Bare Cortex-M4F, M7F, FPU, hardfloat
+`thumbv7m-none-eabi` | * | Bare Cortex-M3
+`thumbv7neon-linux-androideabi` | ✓ | Thumb2-mode ARMv7a Android with NEON
+`thumbv7neon-unknown-linux-gnueabihf` | ✓ | Thumb2-mode ARMv7a Linux with NEON (kernel 4.4, glibc 2.23)
+`thumbv8m.base-none-eabi` | * | ARMv8-M Baseline
+`thumbv8m.main-none-eabi` | * | ARMv8-M Mainline
+`thumbv8m.main-none-eabihf` | * | ARMv8-M Mainline, hardfloat
+`wasm32-unknown-emscripten` | ✓ | WebAssembly via Emscripten
+`wasm32-unknown-unknown` | ✓ | WebAssembly
+`wasm32-wasi` | ✓ | WebAssembly with WASI
+`x86_64-apple-ios` | ✓ | 64-bit x86 iOS
+`x86_64-fortanix-unknown-sgx` | ✓ | [Fortanix ABI] for 64-bit Intel SGX
+`x86_64-fuchsia` | ✓ | 64-bit Fuchsia
+`x86_64-linux-android` | ✓ | 64-bit x86 Android
+`x86_64-pc-solaris` | ✓ | 64-bit Solaris 10/11, illumos
+`x86_64-unknown-linux-gnux32` | ✓ | 64-bit Linux (x32 ABI) (kernel 4.15, glibc 2.27)
+`x86_64-unknown-redox` | ✓ | Redox OS
[Fortanix ABI]: https://edp.fortanix.com/
## Tier 3
-Tier 3 platforms are those which the Rust codebase has support for, but which
-are not built or tested automatically, and may not work. Official builds are
-not available.
+Tier 3 targets are those which the Rust codebase has support for, but which the
+Rust project does not build or test automatically, so they may or may not work.
+Official builds are not available. For the full requirements, see [Tier 3
+target policy](target-tier-policy.md#tier-3-target-policy) in the Target Tier
+Policy.
+
+The `std` column in the table below has the following meanings:
+
+* ✓ indicates the full standard library is available.
+* \* indicates the target only supports [`no_std`] development.
+* ? indicates the standard library support is unknown or a work-in-progress.
+
+[`no_std`]: https://rust-embedded.github.io/book/intro/no-std.html
+
+The `host` column indicates whether the codebase includes support for building
+host tools.
target | std | host | notes
-------|-----|------|-------
`aarch64-unknown-redox` | ? | | ARM64 Redox OS
`aarch64-uwp-windows-msvc` | ? | |
`aarch64-wrs-vxworks` | ? | |
-`aarch64_be-unknown-linux-gnu` | ✓ | ✓ | ARM64 Linux (big-endian)
`aarch64_be-unknown-linux-gnu_ilp32` | ✓ | ✓ | ARM64 Linux (big-endian, ILP32 ABI)
+`aarch64_be-unknown-linux-gnu` | ✓ | ✓ | ARM64 Linux (big-endian)
`armv4t-unknown-linux-gnueabi` | ? | |
`armv5te-unknown-linux-uclibceabi` | ? | | ARMv5TE Linux with uClibc
`armv6-unknown-freebsd` | ✓ | ✓ | ARMv6 FreeBSD
`armv7-wrs-vxworks-eabihf` | ? | |
`armv7a-none-eabihf` | * | | ARM Cortex-A, hardfloat
`armv7s-apple-ios` | ✓ | |
-`avr-unknown-gnu-atmega328` | ✗ | | AVR. Requires `-Z build-std=core`
+`avr-unknown-gnu-atmega328` | * | | AVR. Requires `-Z build-std=core`
`hexagon-unknown-linux-musl` | ? | |
`i386-apple-ios` | ✓ | | 32-bit x86 iOS
`i686-apple-darwin` | ✓ | ✓ | 32-bit macOS (10.7+, Lion+)
`i686-pc-windows-msvc` | ✓ | | 32-bit Windows XP support
-`i686-unknown-uefi` | * | | 32-bit UEFI
`i686-unknown-haiku` | ✓ | ✓ | 32-bit Haiku
`i686-unknown-netbsd` | ✓ | ✓ | NetBSD/i386 with SSE2
`i686-unknown-openbsd` | ✓ | ✓ | 32-bit OpenBSD
+`i686-unknown-uefi` | * | | 32-bit UEFI
`i686-uwp-windows-gnu` | ? | |
`i686-uwp-windows-msvc` | ? | |
`i686-wrs-vxworks` | ? | |
`mips-unknown-linux-uclibc` | ✓ | | MIPS Linux with uClibc
+`mipsel-sony-psp` | * | | MIPS (LE) Sony PlayStation Portable (PSP)
`mipsel-unknown-linux-uclibc` | ✓ | | MIPS (LE) Linux with uClibc
`mipsel-unknown-none` | * | | Bare MIPS (LE) softfloat
-`mipsel-sony-psp` | * | | MIPS (LE) Sony PlayStation Portable (PSP)
`mipsisa32r6-unknown-linux-gnu` | ? | |
`mipsisa32r6el-unknown-linux-gnu` | ? | |
`mipsisa64r6-unknown-linux-gnuabi64` | ? | |
`powerpc-unknown-linux-musl` | ? | |
`powerpc-unknown-netbsd` | ✓ | ✓ |
`powerpc-unknown-openbsd` | ? | |
-`powerpc-wrs-vxworks` | ? | |
`powerpc-wrs-vxworks-spe` | ? | |
+`powerpc-wrs-vxworks` | ? | |
`powerpc64-unknown-freebsd` | ✓ | ✓ | PPC64 FreeBSD (ELFv1 and ELFv2)
`powerpc64-unknown-linux-musl` | ? | |
`powerpc64-wrs-vxworks` | ? | |
`powerpc64le-unknown-linux-musl` | ? | |
-`riscv64gc-unknown-linux-musl` | | | RISC-V Linux (kernel 4.20, musl 1.2.0)
`riscv32gc-unknown-linux-gnu` | | | RISC-V Linux (kernel 5.4, glibc 2.33)
`riscv32gc-unknown-linux-musl` | | | RISC-V Linux (kernel 5.4, musl + RISCV32 support patches)
+`riscv64gc-unknown-linux-musl` | | | RISC-V Linux (kernel 4.20, musl 1.2.0)
`s390x-unknown-linux-musl` | | | S390x Linux (kernel 2.6.32, MUSL)
`sparc-unknown-linux-gnu` | ✓ | | 32-bit SPARC Linux
`sparc64-unknown-netbsd` | ✓ | ✓ | NetBSD/sparc64
`sparc64-unknown-openbsd` | ? | |
+`thumbv4t-none-eabi` | * | | ARMv4T T32
`thumbv7a-pc-windows-msvc` | ? | |
`thumbv7a-uwp-windows-msvc` | ✓ | |
`thumbv7neon-unknown-linux-musleabihf` | ? | | Thumb2-mode ARMv7a Linux with NEON, MUSL
-`thumbv4t-none-eabi` | * | | ARMv4T T32
`wasm64-unknown-unknown` | * | | WebAssembly
`x86_64-apple-ios-macabi` | ✓ | | Apple Catalyst on x86_64
`x86_64-apple-tvos` | * | | x86 64-bit tvOS
-`x86_64-unknown-none-linuxkernel` | * | | Linux kernel modules
-`x86_64-sun-solaris` | ? | | Deprecated target for 64-bit Solaris 10/11, illumos
`x86_64-pc-windows-msvc` | ✓ | | 64-bit Windows XP support
+`x86_64-sun-solaris` | ? | | Deprecated target for 64-bit Solaris 10/11, illumos
`x86_64-unknown-dragonfly` | ✓ | ✓ | 64-bit DragonFlyBSD
`x86_64-unknown-haiku` | ✓ | ✓ | 64-bit Haiku
`x86_64-unknown-hermit` | ? | |
-`x86_64-unknown-none-hermitkernel` | ? | | HermitCore kernel
`x86_64-unknown-l4re-uclibc` | ? | |
+`x86_64-unknown-none-hermitkernel` | ? | | HermitCore kernel
+`x86_64-unknown-none-linuxkernel` | * | | Linux kernel modules
`x86_64-unknown-openbsd` | ✓ | ✓ | 64-bit OpenBSD
`x86_64-unknown-uefi` | * | | 64-bit UEFI
`x86_64-uwp-windows-gnu` | ✓ | |
# Target Tier Policy
+## Table of Contents
+
+* [General](#general)
+* [Tier 3 target policy](#tier-3-target-policy)
+* [Tier 2 target policy](#tier-2-target-policy)
+ * [Tier 2 with host tools](#tier-2-with-host-tools)
+* [Tier 1 target policy](#tier-1-target-policy)
+ * [Tier 1 with host tools](#tier-1-with-host-tools)
+
+## General
+
Rust provides three tiers of target support:
- Rust provides no guarantees about tier 3 targets; they exist in the codebase,
A proposed new tier 3 target must be reviewed and approved by a member of the
compiler team based on these requirements. The reviewer may choose to gauge
-broader compiler team consensus via a Major Change Proposal (MCP).
+broader compiler team consensus via a [Major Change Proposal (MCP)][MCP].
A proposed target or target-specific patch that substantially changes code
shared with other targets (not just target-specific code) must be reviewed and
the target will not block forward progress of the Rust project.
A proposed new tier 2 target must be reviewed and approved by the compiler team
-based on these requirements. Such review and approval may occur via a Major
-Change Proposal (MCP).
+based on these requirements. Such review and approval may occur via a [Major
+Change Proposal (MCP)][MCP].
In addition, the infrastructure team must approve the integration of the target
into Continuous Integration (CI), and the tier 2 CI-related requirements. This
A proposed new tier 2 target with host tools must be reviewed and approved by
the compiler team based on these requirements. Such review and approval may
-occur via a Major Change Proposal (MCP).
+occur via a [Major Change Proposal (MCP)][MCP].
In addition, the infrastructure team must approve the integration of the
target's host tools into Continuous Integration (CI), and the CI-related
RFC process, with approval by the compiler and release teams. Any such proposal
will be communicated widely to the Rust community, both when initially proposed
and before being dropped from a stable release.
+
+[MCP]: https://forge.rust-lang.org/compiler/mcp.html
test result: ok. 31 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out
```
-You should have one ore more `.profraw` files now, one for each test binary. Run the `profdata` tool to merge them:
+You should have one or more `.profraw` files now, one for each test binary. Run the `profdata` tool to merge them:
```shell
$ cargo profdata -- merge \
| Architecture | Register class | Registers | LLVM constraint code |
| ------------ | -------------- | --------- | -------------------- |
-| x86 | `reg` | `ax`, `bx`, `cx`, `dx`, `si`, `di`, `r[8-15]` (x86-64 only) | `r` |
+| x86 | `reg` | `ax`, `bx`, `cx`, `dx`, `si`, `di`, `bp`, `r[8-15]` (x86-64 only) | `r` |
| x86 | `reg_abcd` | `ax`, `bx`, `cx`, `dx` | `Q` |
| x86-32 | `reg_byte` | `al`, `bl`, `cl`, `dl`, `ah`, `bh`, `ch`, `dh` | `q` |
-| x86-64 | `reg_byte`\* | `al`, `bl`, `cl`, `dl`, `sil`, `dil`, `r[8-15]b` | `q` |
+| x86-64 | `reg_byte`\* | `al`, `bl`, `cl`, `dl`, `sil`, `dil`, `bpl`, `r[8-15]b` | `q` |
| x86 | `xmm_reg` | `xmm[0-7]` (x86) `xmm[0-15]` (x86-64) | `x` |
| x86 | `ymm_reg` | `ymm[0-7]` (x86) `ymm[0-15]` (x86-64) | `x` |
| x86 | `zmm_reg` | `zmm[0-7]` (x86) `zmm[0-31]` (x86-64) | `v` |
| x86 | `kreg` | `k[1-7]` | `Yk` |
-| AArch64 | `reg` | `x[0-28]`, `x30` | `r` |
+| AArch64 | `reg` | `x[0-30]` | `r` |
| AArch64 | `vreg` | `v[0-31]` | `w` |
| AArch64 | `vreg_low16` | `v[0-15]` | `x` |
-| ARM | `reg` | `r[0-5]` `r7`\*, `r[8-10]`, `r11`\*, `r12`, `r14` | `r` |
+| ARM | `reg` | `r[0-12]`, `r14` | `r` |
| ARM (Thumb) | `reg_thumb` | `r[0-r7]` | `l` |
-| ARM (ARM) | `reg_thumb` | `r[0-r10]`, `r12`, `r14` | `l` |
+| ARM (ARM) | `reg_thumb` | `r[0-r12]`, `r14` | `l` |
| ARM | `sreg` | `s[0-31]` | `t` |
| ARM | `sreg_low16` | `s[0-15]` | `x` |
| ARM | `dreg` | `d[0-31]` | `w` |
>
> Note #3: NVPTX doesn't have a fixed register set, so named registers are not supported.
>
-> Note #4: On ARM the frame pointer is either `r7` or `r11` depending on the platform.
->
-> Note #5: WebAssembly doesn't have registers, so named registers are not supported.
+> Note #4: WebAssembly doesn't have registers, so named registers are not supported.
Additional register classes may be added in the future based on demand (e.g. MMX, x87, etc).
| All | `sp` | The stack pointer must be restored to its original value at the end of an asm code block. |
| All | `bp` (x86), `x29` (AArch64), `x8` (RISC-V), `fr` (Hexagon), `$fp` (MIPS) | The frame pointer cannot be used as an input or output. |
| ARM | `r7` or `r11` | On ARM the frame pointer can be either `r7` or `r11` depending on the target. The frame pointer cannot be used as an input or output. |
-| ARM | `r6` | `r6` is used internally by LLVM as a base pointer and therefore cannot be used as an input or output. |
+| All | `si` (x86-32), `bx` (x86-64), `r6` (ARM), `x19` (AArch64), `r19` (Hexagon), `x9` (RISC-V) | This is used internally by LLVM as a "base pointer" for functions with complex stack frames. |
| x86 | `k0` | This is a constant zero register which can't be modified. |
| x86 | `ip` | This is the program counter, not a real register. |
| x86 | `mm[0-7]` | MMX registers are not currently supported (but may be in the future). |
| x86 | `st([0-7])` | x87 registers are not currently supported (but may be in the future). |
| AArch64 | `xzr` | This is a constant zero register which can't be modified. |
| ARM | `pc` | This is the program counter, not a real register. |
+| ARM | `r9` | This is a reserved register on some ARM targets. |
| MIPS | `$0` or `$zero` | This is a constant zero register which can't be modified. |
| MIPS | `$1` or `$at` | Reserved for assembler. |
| MIPS | `$26`/`$k0`, `$27`/`$k1` | OS-reserved registers. |
| RISC-V | `gp`, `tp` | These registers are reserved and cannot be used as inputs or outputs. |
| Hexagon | `lr` | This is the link register which cannot be used as an input or output. |
-In some cases LLVM will allocate a "reserved register" for `reg` operands even though this register cannot be explicitly specified. Assembly code making use of reserved registers should be careful since `reg` operands may alias with those registers. Reserved registers are:
-- The frame pointer on all architectures.
-- `r6` on ARM.
+In some cases LLVM will allocate a "reserved register" for `reg` operands even though this register cannot be explicitly specified. Assembly code making use of reserved registers should be careful since `reg` operands may alias with those registers. Reserved registers are the frame pointer and base pointer
+- The frame pointer and LLVM base pointer on all architectures.
+- `r9` on ARM.
+- `x18` on AArch64.
## Template modifiers
name: None,
attrs: Default::default(),
visibility: Inherited,
- def_id: self.cx.next_def_id(item_def_id.krate),
+ def_id: FakeDefId::new_fake(item_def_id.krate),
kind: box ImplItem(Impl {
span: Span::dummy(),
unsafety: hir::Unsafety::Normal,
generics: new_generics,
- provided_trait_methods: Default::default(),
trait_: Some(trait_ref.clean(self.cx).get_trait_type().unwrap()),
for_: ty.clean(self.cx),
items: Vec::new(),
}
self.cx.generated_synthetics.insert((ty, trait_def_id));
- let provided_trait_methods = self
- .cx
- .tcx
- .provided_trait_methods(trait_def_id)
- .map(|meth| meth.ident.name)
- .collect();
impls.push(Item {
name: None,
attrs: Default::default(),
visibility: Inherited,
- def_id: self.cx.next_def_id(impl_def_id.krate),
+ def_id: FakeDefId::new_fake(item_def_id.krate),
kind: box ImplItem(Impl {
span: self.cx.tcx.def_span(impl_def_id).clean(self.cx),
unsafety: hir::Unsafety::Normal,
self.cx.tcx.explicit_predicates_of(impl_def_id),
)
.clean(self.cx),
- provided_trait_methods,
// FIXME(eddyb) compute both `trait_` and `for_` from
// the post-inference `trait_ref`, as it's more accurate.
trait_: Some(trait_ref.clean(self.cx).get_trait_type().unwrap()),
use rustc_span::symbol::{kw, sym, Symbol};
use rustc_span::Span;
-use crate::clean::{self, Attributes, AttributesExt, GetDefId, ToSource};
+use crate::clean::{self, Attributes, AttributesExt, FakeDefId, GetDefId, ToSource};
use crate::core::DocContext;
use crate::formats::item_type::ItemType;
-use super::Clean;
+use super::{Clean, Visibility};
type Attrs<'hir> = rustc_middle::ty::Attributes<'hir>;
};
let (attrs, cfg) = merge_attrs(cx, Some(parent_module), load_attrs(cx, did), attrs_clone);
- cx.inlined.insert(did);
+ cx.inlined.insert(did.into());
ret.push(clean::Item::from_def_id_and_attrs_and_parts(
did,
Some(name),
if did.is_local() {
cx.cache.exact_paths.insert(did, fqn);
} else {
- cx.cache.external_paths.insert(did, (fqn, ItemType::from(kind)));
+ cx.cache.external_paths.insert(did, (fqn, kind));
}
}
crate fn build_external_trait(cx: &mut DocContext<'_>, did: DefId) -> clean::Trait {
- let trait_items =
- cx.tcx.associated_items(did).in_definition_order().map(|item| item.clean(cx)).collect();
+ let trait_items = cx
+ .tcx
+ .associated_items(did)
+ .in_definition_order()
+ .map(|item| {
+ // When building an external trait, the cleaned trait will have all items public,
+ // which causes methods to have a `pub` prefix, which is invalid since items in traits
+ // can not have a visibility prefix. Thus we override the visibility here manually.
+ // See https://github.com/rust-lang/rust/issues/81274
+ clean::Item { visibility: Visibility::Inherited, ..item.clean(cx) }
+ })
+ .collect();
let predicates = cx.tcx.predicates_of(did);
let generics = (cx.tcx.generics_of(did), predicates).clean(cx);
attrs: Option<Attrs<'_>>,
ret: &mut Vec<clean::Item>,
) {
- if !cx.inlined.insert(did) {
+ if !cx.inlined.insert(did.into()) {
return;
}
record_extern_trait(cx, trait_did);
}
- let provided = trait_
- .def_id()
- .map(|did| tcx.provided_trait_methods(did).map(|meth| meth.ident.name).collect())
- .unwrap_or_default();
-
- debug!("build_impl: impl {:?} for {:?}", trait_.def_id(), for_.def_id());
-
let (merged_attrs, cfg) = merge_attrs(cx, parent_module.into(), load_attrs(cx, did), attrs);
debug!("merged_attrs={:?}", merged_attrs);
+ debug!("build_impl: impl {:?} for {:?}", trait_.def_id(), for_.def_id());
ret.push(clean::Item::from_def_id_and_attrs_and_parts(
did,
None,
span: clean::types::rustc_span(did, cx.tcx),
unsafety: hir::Unsafety::Normal,
generics,
- provided_trait_methods: provided,
trait_,
for_,
items: trait_items,
items.push(clean::Item {
name: None,
attrs: box clean::Attributes::default(),
- def_id: cx.next_def_id(did.krate),
+ def_id: FakeDefId::new_fake(did.krate),
visibility: clean::Public,
kind: box clean::ImportItem(clean::Import::new_simple(
item.ident.name,
use rustc_hir::def_id::{CrateNum, DefId, CRATE_DEF_INDEX, LOCAL_CRATE};
use rustc_index::vec::{Idx, IndexVec};
use rustc_infer::infer::region_constraints::{Constraint, RegionConstraintData};
-use rustc_middle::bug;
use rustc_middle::middle::resolve_lifetime as rl;
use rustc_middle::ty::fold::TypeFolder;
use rustc_middle::ty::subst::{InternalSubsts, Subst};
use rustc_middle::ty::{self, AdtKind, Lift, Ty, TyCtxt};
+use rustc_middle::{bug, span_bug};
use rustc_mir::const_eval::{is_const_fn, is_unstable_const_fn};
use rustc_span::hygiene::{AstPass, MacroKind};
use rustc_span::symbol::{kw, sym, Ident, Symbol};
// determine if we should display the inner contents or
// the outer `mod` item for the source code.
let span = Span::from_rustc_span({
+ let where_outer = self.where_outer(cx.tcx);
let sm = cx.sess().source_map();
- let outer = sm.lookup_char_pos(self.where_outer.lo());
+ let outer = sm.lookup_char_pos(where_outer.lo());
let inner = sm.lookup_char_pos(self.where_inner.lo());
if outer.file.start_pos == inner.file.start_pos {
// mod foo { ... }
- self.where_outer
+ where_outer
} else {
// mod foo; (and a separate SourceFile for the contents)
self.where_inner
impl Clean<Type> for (ty::TraitRef<'_>, &[TypeBinding]) {
fn clean(&self, cx: &mut DocContext<'_>) -> Type {
let (trait_ref, bounds) = *self;
- inline::record_extern_fqn(cx, trait_ref.def_id, ItemType::Trait);
+ let kind = cx.tcx.def_kind(trait_ref.def_id).into();
+ if !matches!(kind, ItemType::Trait | ItemType::TraitAlias) {
+ span_bug!(
+ cx.tcx.def_span(trait_ref.def_id),
+ "`TraitRef` had unexpected kind {:?}",
+ kind
+ );
+ }
+ inline::record_extern_fqn(cx, trait_ref.def_id, kind);
let path = external_path(
cx,
cx.tcx.item_name(trait_ref.def_id),
match param.kind {
GenericParamDefKind::Lifetime => unreachable!(),
GenericParamDefKind::Type { did, ref bounds, .. } => {
- cx.impl_trait_bounds.insert(did.into(), bounds.clone());
+ cx.impl_trait_bounds
+ .insert(FakeDefId::new_real(did).into(), bounds.clone());
}
GenericParamDefKind::Const { .. } => unreachable!(),
}
.collect::<Vec<GenericParamDef>>();
// param index -> [(DefId of trait, associated type name, type)]
- let mut impl_trait_proj = FxHashMap::<u32, Vec<(DefId, Symbol, Ty<'tcx>)>>::default();
+ let mut impl_trait_proj = FxHashMap::<u32, Vec<(FakeDefId, Symbol, Ty<'tcx>)>>::default();
let where_predicates = preds
.predicates
if let Some(((_, trait_did, name), rhs)) =
proj.as_ref().and_then(|(lhs, rhs)| Some((lhs.projection()?, rhs)))
{
- impl_trait_proj
- .entry(param_idx)
- .or_default()
- .push((trait_did, name, rhs));
+ impl_trait_proj.entry(param_idx).or_default().push((
+ trait_did.into(),
+ name,
+ rhs,
+ ));
}
return None;
if let Some(proj) = impl_trait_proj.remove(&idx) {
for (trait_did, name, rhs) in proj {
let rhs = rhs.clean(cx);
- simplify::merge_bounds(cx, &mut bounds, trait_did, name, &rhs);
+ simplify::merge_bounds(
+ cx,
+ &mut bounds,
+ trait_did.expect_real(),
+ name,
+ &rhs,
+ );
}
}
} else {
if let Some(new_ty) = cx.ty_substs.get(&did).cloned() {
return new_ty;
}
- if let Some(bounds) = cx.impl_trait_bounds.remove(&did.into()) {
+ if let Some(bounds) = cx.impl_trait_bounds.remove(&FakeDefId::new_real(did).into())
+ {
return ImplTrait(bounds);
}
}
build_deref_target_impls(cx, &items, &mut ret);
}
- let provided: FxHashSet<Symbol> = trait_
- .def_id()
- .map(|did| tcx.provided_trait_methods(did).map(|meth| meth.ident.name).collect())
- .unwrap_or_default();
-
let for_ = impl_.self_ty.clean(cx);
let type_alias = for_.def_id().and_then(|did| match tcx.def_kind(did) {
DefKind::TyAlias => Some(tcx.type_of(did).clean(cx)),
span: types::rustc_span(tcx.hir().local_def_id(hir_id).to_def_id(), tcx),
unsafety: impl_.unsafety,
generics: impl_.generics.clean(cx),
- provided_trait_methods: provided.clone(),
trait_,
for_,
items,
vec![Item {
name: Some(name),
attrs: box attrs.clean(cx),
- def_id: crate_def_id,
+ def_id: crate_def_id.into(),
visibility: krate.vis.clean(cx),
kind: box ExternCrateItem { src: orig_name },
cfg: attrs.cfg(cx.sess().diagnostic()),
-use std::cell::RefCell;
+use std::cell::{Cell, RefCell};
use std::default::Default;
-use std::fmt;
use std::hash::{Hash, Hasher};
use std::iter::FromIterator;
use std::lazy::SyncOnceCell as OnceCell;
+use std::path::PathBuf;
use std::rc::Rc;
use std::sync::Arc;
use std::{slice, vec};
use rustc_data_structures::thin_vec::ThinVec;
use rustc_hir as hir;
use rustc_hir::def::{CtorKind, DefKind, Res};
-use rustc_hir::def_id::{CrateNum, DefId, DefIndex, CRATE_DEF_INDEX};
+use rustc_hir::def_id::{CrateNum, DefId, DefIndex, LocalDefId, CRATE_DEF_INDEX, LOCAL_CRATE};
use rustc_hir::lang_items::LangItem;
use rustc_hir::{BodyId, Mutability};
use rustc_index::vec::IndexVec;
use self::SelfTy::*;
use self::Type::*;
-thread_local!(crate static MAX_DEF_IDX: RefCell<FxHashMap<CrateNum, DefIndex>> = Default::default());
+crate type FakeDefIdSet = FxHashSet<FakeDefId>;
+
+#[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord, Hash, Copy)]
+crate enum FakeDefId {
+ Real(DefId),
+ Fake(DefIndex, CrateNum),
+}
+
+impl FakeDefId {
+ #[cfg(parallel_compiler)]
+ crate fn new_fake(crate: CrateNum) -> Self {
+ unimplemented!("")
+ }
+
+ #[cfg(not(parallel_compiler))]
+ crate fn new_fake(krate: CrateNum) -> Self {
+ thread_local!(static FAKE_DEF_ID_COUNTER: Cell<usize> = Cell::new(0));
+ let id = FAKE_DEF_ID_COUNTER.with(|id| {
+ let tmp = id.get();
+ id.set(tmp + 1);
+ tmp
+ });
+ Self::Fake(DefIndex::from(id), krate)
+ }
+
+ crate fn new_real(id: DefId) -> Self {
+ Self::Real(id)
+ }
+
+ #[inline]
+ crate fn is_local(self) -> bool {
+ match self {
+ FakeDefId::Real(id) => id.is_local(),
+ FakeDefId::Fake(_, krate) => krate == LOCAL_CRATE,
+ }
+ }
+
+ #[inline]
+ crate fn as_local(self) -> Option<LocalDefId> {
+ match self {
+ FakeDefId::Real(id) => id.as_local(),
+ FakeDefId::Fake(idx, krate) => {
+ (krate == LOCAL_CRATE).then(|| LocalDefId { local_def_index: idx })
+ }
+ }
+ }
+
+ #[inline]
+ crate fn expect_local(self) -> LocalDefId {
+ self.as_local()
+ .unwrap_or_else(|| panic!("FakeDefId::expect_local: `{:?}` isn't local", self))
+ }
+
+ #[inline]
+ crate fn expect_real(self) -> rustc_hir::def_id::DefId {
+ self.as_real().unwrap_or_else(|| panic!("FakeDefId::expect_real: `{:?}` isn't real", self))
+ }
+
+ #[inline]
+ crate fn as_real(self) -> Option<DefId> {
+ match self {
+ FakeDefId::Real(id) => Some(id),
+ FakeDefId::Fake(_, _) => None,
+ }
+ }
+
+ #[inline]
+ crate fn krate(self) -> CrateNum {
+ match self {
+ FakeDefId::Real(id) => id.krate,
+ FakeDefId::Fake(_, krate) => krate,
+ }
+ }
+
+ #[inline]
+ crate fn index(self) -> Option<DefIndex> {
+ match self {
+ FakeDefId::Real(id) => Some(id.index),
+ FakeDefId::Fake(_, _) => None,
+ }
+ }
+}
+
+impl From<DefId> for FakeDefId {
+ fn from(id: DefId) -> Self {
+ Self::Real(id)
+ }
+}
#[derive(Clone, Debug)]
crate struct Crate {
tcx.crate_name(self.crate_num)
}
+ crate fn src_root(&self, tcx: TyCtxt<'_>) -> PathBuf {
+ match self.src(tcx) {
+ FileName::Real(ref p) => match p.local_path().parent() {
+ Some(p) => p.to_path_buf(),
+ None => PathBuf::new(),
+ },
+ _ => PathBuf::new(),
+ }
+ }
+
+ /// Attempts to find where an external crate is located, given that we're
+ /// rendering in to the specified source destination.
+ crate fn location(
+ &self,
+ extern_url: Option<&str>,
+ dst: &std::path::Path,
+ tcx: TyCtxt<'_>,
+ ) -> ExternalLocation {
+ use ExternalLocation::*;
+
+ fn to_remote(url: impl ToString) -> ExternalLocation {
+ let mut url = url.to_string();
+ if !url.ends_with('/') {
+ url.push('/');
+ }
+ Remote(url)
+ }
+
+ // See if there's documentation generated into the local directory
+ // WARNING: since rustdoc creates these directories as it generates documentation, this check is only accurate before rendering starts.
+ // Make sure to call `location()` by that time.
+ let local_location = dst.join(&*self.name(tcx).as_str());
+ if local_location.is_dir() {
+ return Local;
+ }
+
+ if let Some(url) = extern_url {
+ return to_remote(url);
+ }
+
+ // Failing that, see if there's an attribute specifying where to find this
+ // external crate
+ let did = DefId { krate: self.crate_num, index: CRATE_DEF_INDEX };
+ tcx.get_attrs(did)
+ .lists(sym::doc)
+ .filter(|a| a.has_name(sym::html_root_url))
+ .filter_map(|a| a.value_str())
+ .map(to_remote)
+ .next()
+ .unwrap_or(Unknown) // Well, at least we tried.
+ }
+
crate fn keywords(&self, tcx: TyCtxt<'_>) -> ThinVec<(DefId, Symbol)> {
let root = self.def_id();
/// Anything with a source location and set of attributes and, optionally, a
/// name. That is, anything that can be documented. This doesn't correspond
/// directly to the AST's concept of an item; it's a strict superset.
-#[derive(Clone)]
+#[derive(Clone, Debug)]
crate struct Item {
/// The name of this item.
/// Optional because not every item has a name, e.g. impls.
/// Information about this item that is specific to what kind of item it is.
/// E.g., struct vs enum vs function.
crate kind: Box<ItemKind>,
- crate def_id: DefId,
+ crate def_id: FakeDefId,
crate cfg: Option<Arc<Cfg>>,
}
#[cfg(all(target_arch = "x86_64", target_pointer_width = "64"))]
rustc_data_structures::static_assert_size!(Item, 48);
-impl fmt::Debug for Item {
- fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result {
- let def_id: &dyn fmt::Debug = if self.is_fake() { &"**FAKE**" } else { &self.def_id };
-
- fmt.debug_struct("Item")
- .field("name", &self.name)
- .field("attrs", &self.attrs)
- .field("kind", &self.kind)
- .field("visibility", &self.visibility)
- .field("def_id", def_id)
- .field("cfg", &self.cfg)
- .finish()
- }
-}
-
crate fn rustc_span(def_id: DefId, tcx: TyCtxt<'_>) -> Span {
Span::from_rustc_span(def_id.as_local().map_or_else(
|| tcx.def_span(def_id),
impl Item {
crate fn stability<'tcx>(&self, tcx: TyCtxt<'tcx>) -> Option<&'tcx Stability> {
- if self.is_fake() { None } else { tcx.lookup_stability(self.def_id) }
+ if self.is_fake() { None } else { tcx.lookup_stability(self.def_id.expect_real()) }
}
crate fn const_stability<'tcx>(&self, tcx: TyCtxt<'tcx>) -> Option<&'tcx ConstStability> {
- if self.is_fake() { None } else { tcx.lookup_const_stability(self.def_id) }
+ if self.is_fake() { None } else { tcx.lookup_const_stability(self.def_id.expect_real()) }
}
crate fn deprecation(&self, tcx: TyCtxt<'_>) -> Option<Deprecation> {
- if self.is_fake() { None } else { tcx.lookup_deprecation(self.def_id) }
+ if self.is_fake() { None } else { tcx.lookup_deprecation(self.def_id.expect_real()) }
}
crate fn inner_docs(&self, tcx: TyCtxt<'_>) -> bool {
- if self.is_fake() { false } else { tcx.get_attrs(self.def_id).inner_docs() }
+ if self.is_fake() { false } else { tcx.get_attrs(self.def_id.expect_real()).inner_docs() }
}
crate fn span(&self, tcx: TyCtxt<'_>) -> Span {
} else if self.is_fake() {
Span::dummy()
} else {
- rustc_span(self.def_id, tcx)
+ rustc_span(self.def_id.expect_real(), tcx)
}
}
debug!("name={:?}, def_id={:?}", name, def_id);
Item {
- def_id,
+ def_id: def_id.into(),
kind: box kind,
name,
attrs,
.map_or(&[][..], |v| v.as_slice())
.iter()
.filter_map(|ItemLink { link: s, link_text, did, ref fragment }| {
- match *did {
+ match did {
Some(did) => {
- if let Some((mut href, ..)) = href(did, cx) {
+ if let Some((mut href, ..)) = href(did.expect_real(), cx) {
if let Some(ref fragment) = *fragment {
href.push('#');
href.push_str(fragment);
None => {
let relative_to = &cx.current;
if let Some(ref fragment) = *fragment {
- let url = match cx.cache().extern_locations.get(&self.def_id.krate) {
- Some(&(_, _, ExternalLocation::Local)) => {
+ let url = match cx.cache().extern_locations.get(&self.def_id.krate()) {
+ Some(&ExternalLocation::Local) => {
if relative_to[0] == "std" {
let depth = relative_to.len() - 1;
"../".repeat(depth)
format!("{}std/", "../".repeat(depth))
}
}
- Some(&(_, _, ExternalLocation::Remote(ref s))) => {
+ Some(ExternalLocation::Remote(ref s)) => {
format!("{}/std/", s.trim_end_matches('/'))
}
- Some(&(_, _, ExternalLocation::Unknown)) | None => format!(
+ Some(ExternalLocation::Unknown) | None => format!(
"https://doc.rust-lang.org/{}/std/",
crate::doc_rust_lang_org_channel(),
),
}
crate fn is_crate(&self) -> bool {
- self.is_mod() && self.def_id.index == CRATE_DEF_INDEX
+ self.is_mod() && self.def_id.as_real().map_or(false, |did| did.index == CRATE_DEF_INDEX)
}
crate fn is_mod(&self) -> bool {
}
}
- /// See the documentation for [`next_def_id()`].
- ///
- /// [`next_def_id()`]: DocContext::next_def_id()
crate fn is_fake(&self) -> bool {
- MAX_DEF_IDX.with(|m| {
- m.borrow().get(&self.def_id.krate).map(|&idx| idx <= self.def_id.index).unwrap_or(false)
- })
+ matches!(self.def_id, FakeDefId::Fake(_, _))
}
}
| KeywordItem(_) => [].iter(),
}
}
-
- crate fn is_type_alias(&self) -> bool {
- matches!(self, ItemKind::TypedefItem(..) | ItemKind::AssocTypeItem(..))
- }
}
#[derive(Clone, Debug)]
/// This may not be the same as `link` if there was a disambiguator
/// in an intra-doc link (e.g. \[`fn@f`\])
pub(crate) link_text: String,
- pub(crate) did: Option<DefId>,
+ pub(crate) did: Option<FakeDefId>,
/// The url fragment to append to the link
pub(crate) fragment: Option<String>,
}
}
}
- let clean_attr = |(attr, parent_module): (&ast::Attribute, _)| {
+ let clean_attr = |(attr, parent_module): (&ast::Attribute, Option<DefId>)| {
if let Some(value) = attr.doc_str() {
trace!("got doc_str={:?}", value);
let value = beautify_doc_string(value);
impl Type {
fn inner_def_id(&self, cache: Option<&Cache>) -> Option<DefId> {
let t: PrimitiveType = match *self {
- ResolvedPath { did, .. } => return Some(did),
+ ResolvedPath { did, .. } => return Some(did.into()),
Primitive(p) => return cache.and_then(|c| c.primitive_locations.get(&p).cloned()),
BorrowedRef { type_: box Generic(..), .. } => PrimitiveType::Reference,
BorrowedRef { ref type_, .. } => return type_.inner_def_id(cache),
crate span: Span,
crate unsafety: hir::Unsafety,
crate generics: Generics,
- crate provided_trait_methods: FxHashSet<Symbol>,
crate trait_: Option<Type>,
crate for_: Type,
crate items: Vec<Item>,
crate blanket_impl: Option<Type>,
}
+impl Impl {
+ crate fn provided_trait_methods(&self, tcx: TyCtxt<'_>) -> FxHashSet<Symbol> {
+ self.trait_
+ .def_id()
+ .map(|did| tcx.provided_trait_methods(did).map(|meth| meth.ident.name).collect())
+ .unwrap_or_default()
+ }
+}
+
#[derive(Clone, Debug)]
crate struct Import {
crate kind: ImportKind,
use rustc_span::symbol::{kw, sym, Symbol};
use std::mem;
+#[cfg(test)]
+mod tests;
+
crate fn krate(cx: &mut DocContext<'_>) -> Crate {
use crate::visit_lib::LibEmbargoVisitor;
// `#[doc(masked)]` to the injected `extern crate` because it's unstable.
if it.is_extern_crate()
&& (it.attrs.has_doc_flag(sym::masked)
- || cx.tcx.is_compiler_builtins(it.def_id.krate))
+ || cx.tcx.is_compiler_builtins(it.def_id.krate()))
{
- cx.cache.masked_crates.insert(it.def_id.krate);
+ cx.cache.masked_crates.insert(it.def_id.krate());
}
}
}
fn format_integer_with_underscore_sep(num: &str) -> String {
let num_chars: Vec<_> = num.chars().collect();
- let num_start_index = if num_chars.get(0) == Some(&'-') { 1 } else { 0 };
+ let mut num_start_index = if num_chars.get(0) == Some(&'-') { 1 } else { 0 };
+ let chunk_size = match num[num_start_index..].as_bytes() {
+ [b'0', b'b' | b'x', ..] => {
+ num_start_index += 2;
+ 4
+ }
+ [b'0', b'o', ..] => {
+ num_start_index += 2;
+ let remaining_chars = num_chars.len() - num_start_index;
+ if remaining_chars <= 6 {
+ // don't add underscores to Unix permissions like 0755 or 100755
+ return num.to_string();
+ }
+ 3
+ }
+ _ => 3,
+ };
num_chars[..num_start_index]
.iter()
- .chain(num_chars[num_start_index..].rchunks(3).rev().intersperse(&['_']).flatten())
+ .chain(num_chars[num_start_index..].rchunks(chunk_size).rev().intersperse(&['_']).flatten())
.collect()
}
}
/// Find the nearest parent module of a [`DefId`].
-///
-/// **Panics if the item it belongs to [is fake][Item::is_fake].**
crate fn find_nearest_parent_module(tcx: TyCtxt<'_>, def_id: DefId) -> Option<DefId> {
if def_id.is_top_level_module() {
// The crate root has no parent. Use it as the root instead.
--- /dev/null
+use super::*;
+
+#[test]
+fn int_format_decimal() {
+ assert_eq!(format_integer_with_underscore_sep("12345678"), "12_345_678");
+ assert_eq!(format_integer_with_underscore_sep("123"), "123");
+ assert_eq!(format_integer_with_underscore_sep("123459"), "123_459");
+ assert_eq!(format_integer_with_underscore_sep("-12345678"), "-12_345_678");
+ assert_eq!(format_integer_with_underscore_sep("-123"), "-123");
+ assert_eq!(format_integer_with_underscore_sep("-123459"), "-123_459");
+}
+
+#[test]
+fn int_format_hex() {
+ assert_eq!(format_integer_with_underscore_sep("0xab3"), "0xab3");
+ assert_eq!(format_integer_with_underscore_sep("0xa2345b"), "0xa2_345b");
+ assert_eq!(format_integer_with_underscore_sep("0xa2e6345b"), "0xa2e6_345b");
+ assert_eq!(format_integer_with_underscore_sep("-0xab3"), "-0xab3");
+ assert_eq!(format_integer_with_underscore_sep("-0xa2345b"), "-0xa2_345b");
+ assert_eq!(format_integer_with_underscore_sep("-0xa2e6345b"), "-0xa2e6_345b");
+}
+
+#[test]
+fn int_format_binary() {
+ assert_eq!(format_integer_with_underscore_sep("0o12345671"), "0o12_345_671");
+ assert_eq!(format_integer_with_underscore_sep("0o123"), "0o123");
+ assert_eq!(format_integer_with_underscore_sep("0o123451"), "0o123451");
+ assert_eq!(format_integer_with_underscore_sep("-0o12345671"), "-0o12_345_671");
+ assert_eq!(format_integer_with_underscore_sep("-0o123"), "-0o123");
+ assert_eq!(format_integer_with_underscore_sep("-0o123451"), "-0o123451");
+}
+
+#[test]
+fn int_format_octal() {
+ assert_eq!(format_integer_with_underscore_sep("0b101"), "0b101");
+ assert_eq!(format_integer_with_underscore_sep("0b101101011"), "0b1_0110_1011");
+ assert_eq!(format_integer_with_underscore_sep("0b01101011"), "0b0110_1011");
+ assert_eq!(format_integer_with_underscore_sep("-0b101"), "-0b101");
+ assert_eq!(format_integer_with_underscore_sep("-0b101101011"), "-0b1_0110_1011");
+ assert_eq!(format_integer_with_underscore_sep("-0b01101011"), "-0b0110_1011");
+}
/// For example, using ignore-foo to ignore running the doctest on any target that
/// contains "foo" as a substring
crate enable_per_target_ignores: bool,
+ /// Do not run doctests, compile them if should_test is active.
+ crate no_run: bool,
/// The path to a rustc-like binary to build tests with. If not set, we
/// default to loading from `$sysroot/bin/rustc`.
.field("runtool_args", &self.runtool_args)
.field("enable-per-target-ignores", &self.enable_per_target_ignores)
.field("run_check", &self.run_check)
+ .field("no_run", &self.no_run)
.finish()
}
}
test_args.iter().flat_map(|s| s.split_whitespace()).map(|s| s.to_string()).collect();
let should_test = matches.opt_present("test");
+ let no_run = matches.opt_present("no-run");
+
+ if !should_test && no_run {
+ diag.err("the `--test` flag must be passed to enable `--no-run`");
+ return Err(1);
+ }
let output =
matches.opt_str("o").map(|s| PathBuf::from(&s)).unwrap_or_else(|| PathBuf::from("doc"));
enable_per_target_ignores,
test_builder,
run_check,
+ no_run,
render_options: RenderOptions {
output,
external_html,
use rustc_errors::json::JsonEmitter;
use rustc_feature::UnstableFeatures;
use rustc_hir::def::Res;
-use rustc_hir::def_id::{CrateNum, DefId, DefIndex, LocalDefId, LOCAL_CRATE};
+use rustc_hir::def_id::{DefId, LocalDefId, LOCAL_CRATE};
use rustc_hir::HirId;
use rustc_hir::{
intravisit::{self, NestedVisitorMap, Visitor},
use rustc_span::Span;
use std::cell::RefCell;
-use std::collections::hash_map::Entry;
use std::mem;
use std::rc::Rc;
-use crate::clean;
use crate::clean::inline::build_external_trait;
-use crate::clean::{TraitWithExtraInfo, MAX_DEF_IDX};
+use crate::clean::{self, FakeDefId, TraitWithExtraInfo};
use crate::config::{Options as RustdocOptions, OutputFormat, RenderOptions};
use crate::formats::cache::Cache;
use crate::passes::{self, Condition::*, ConditionalPass};
crate ct_substs: FxHashMap<DefId, clean::Constant>,
/// Table synthetic type parameter for `impl Trait` in argument position -> bounds
crate impl_trait_bounds: FxHashMap<ImplTraitParam, Vec<clean::GenericBound>>,
- crate fake_def_ids: FxHashMap<CrateNum, DefIndex>,
/// Auto-trait or blanket impls processed so far, as `(self_ty, trait_def_id)`.
// FIXME(eddyb) make this a `ty::TraitRef<'tcx>` set.
crate generated_synthetics: FxHashSet<(Ty<'tcx>, DefId)>,
/// This same cache is used throughout rustdoc, including in [`crate::html::render`].
crate cache: Cache,
/// Used by [`clean::inline`] to tell if an item has already been inlined.
- crate inlined: FxHashSet<DefId>,
+ crate inlined: FxHashSet<FakeDefId>,
/// Used by `calculate_doc_coverage`.
crate output_format: OutputFormat,
}
r
}
- /// Create a new "fake" [`DefId`].
- ///
- /// This is an ugly hack, but it's the simplest way to handle synthetic impls without greatly
- /// refactoring either rustdoc or [`rustc_middle`]. In particular, allowing new [`DefId`]s
- /// to be registered after the AST is constructed would require storing the [`DefId`] mapping
- /// in a [`RefCell`], decreasing the performance for normal compilation for very little gain.
- ///
- /// Instead, we construct "fake" [`DefId`]s, which start immediately after the last `DefId`.
- /// In the [`Debug`] impl for [`clean::Item`], we explicitly check for fake `DefId`s,
- /// as we'll end up with a panic if we use the `DefId` `Debug` impl for fake `DefId`s.
- ///
- /// [`RefCell`]: std::cell::RefCell
- /// [`Debug`]: std::fmt::Debug
- /// [`clean::Item`]: crate::clean::types::Item
- crate fn next_def_id(&mut self, crate_num: CrateNum) -> DefId {
- let def_index = match self.fake_def_ids.entry(crate_num) {
- Entry::Vacant(e) => {
- let num_def_idx = {
- let num_def_idx = if crate_num == LOCAL_CRATE {
- self.tcx.hir().definitions().def_path_table().num_def_ids()
- } else {
- self.resolver.borrow_mut().access(|r| r.cstore().num_def_ids(crate_num))
- };
-
- DefIndex::from_usize(num_def_idx)
- };
-
- MAX_DEF_IDX.with(|m| {
- m.borrow_mut().insert(crate_num, num_def_idx);
- });
- e.insert(num_def_idx)
- }
- Entry::Occupied(e) => e.into_mut(),
- };
- *def_index = *def_index + 1;
-
- DefId { krate: crate_num, index: *def_index }
- }
-
/// Like `hir().local_def_id_to_hir_id()`, but skips calling it on fake DefIds.
/// (This avoids a slice-index-out-of-bounds panic.)
- crate fn as_local_hir_id(tcx: TyCtxt<'_>, def_id: DefId) -> Option<HirId> {
- if MAX_DEF_IDX.with(|m| {
- m.borrow().get(&def_id.krate).map(|&idx| idx <= def_id.index).unwrap_or(false)
- }) {
- None
- } else {
- def_id.as_local().map(|def_id| tcx.hir().local_def_id_to_hir_id(def_id))
+ crate fn as_local_hir_id(tcx: TyCtxt<'_>, def_id: FakeDefId) -> Option<HirId> {
+ match def_id {
+ FakeDefId::Real(real_id) => {
+ real_id.as_local().map(|def_id| tcx.hir().local_def_id_to_hir_id(def_id))
+ }
+ FakeDefId::Fake(_, _) => None,
}
}
}
lt_substs: Default::default(),
ct_substs: Default::default(),
impl_trait_bounds: Default::default(),
- fake_def_ids: Default::default(),
generated_synthetics: Default::default(),
auto_traits: tcx
.all_traits(LOCAL_CRATE)
/// for `impl Trait` in argument position.
#[derive(Clone, Copy, PartialEq, Eq, Hash, PartialOrd, Ord)]
crate enum ImplTraitParam {
- DefId(DefId),
+ DefId(FakeDefId),
ParamIndex(u32),
}
-impl From<DefId> for ImplTraitParam {
- fn from(did: DefId) -> Self {
+impl From<FakeDefId> for ImplTraitParam {
+ fn from(did: FakeDefId) -> Self {
ImplTraitParam::DefId(did)
}
}
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,
line,
options,
config.should_panic,
- config.no_run,
+ no_run,
config.test_harness,
runtool,
runtool_args,
//! This module is used to store stuff from Rust's AST in a more convenient
//! manner (and with prettier names) before cleaning.
+use rustc_middle::ty::TyCtxt;
use rustc_span::{self, Span, Symbol};
use rustc_hir as hir;
crate struct Module<'hir> {
crate name: Symbol,
- crate where_outer: Span,
crate where_inner: Span,
crate mods: Vec<Module<'hir>>,
crate id: hir::HirId,
}
impl Module<'hir> {
- crate fn new(name: Symbol) -> Module<'hir> {
+ crate fn new(name: Symbol, id: hir::HirId, where_inner: Span) -> Module<'hir> {
Module {
name,
- id: hir::CRATE_HIR_ID,
- where_outer: rustc_span::DUMMY_SP,
- where_inner: rustc_span::DUMMY_SP,
+ id,
+ where_inner,
mods: Vec::new(),
items: Vec::new(),
foreigns: Vec::new(),
macros: Vec::new(),
}
}
+
+ crate fn where_outer(&self, tcx: TyCtxt<'_>) -> Span {
+ tcx.hir().span(self.id)
+ }
}
use std::collections::BTreeMap;
use std::mem;
-use std::path::{Path, PathBuf};
+use std::path::Path;
use rustc_data_structures::fx::{FxHashMap, FxHashSet};
use rustc_hir::def_id::{CrateNum, DefId, CRATE_DEF_INDEX};
use rustc_middle::middle::privacy::AccessLevels;
use rustc_middle::ty::TyCtxt;
-use rustc_span::source_map::FileName;
use rustc_span::symbol::sym;
-use rustc_span::Symbol;
-use crate::clean::{self, GetDefId};
+use crate::clean::{self, FakeDefId, GetDefId};
use crate::fold::DocFolder;
use crate::formats::item_type::ItemType;
use crate::formats::Impl;
use crate::html::markdown::short_markdown_summary;
-use crate::html::render::cache::{extern_location, get_index_search_type, ExternalLocation};
+use crate::html::render::cache::{get_index_search_type, ExternalLocation};
use crate::html::render::IndexItem;
/// This cache is used to store information about the [`clean::Crate`] being
/// When rendering traits, it's often useful to be able to list all
/// implementors of the trait, and this mapping is exactly, that: a mapping
/// of trait ids to the list of known implementors of the trait
- crate implementors: FxHashMap<DefId, Vec<Impl>>,
+ crate implementors: FxHashMap<FakeDefId, Vec<Impl>>,
/// Cache of where external crate documentation can be found.
- crate extern_locations: FxHashMap<CrateNum, (Symbol, PathBuf, ExternalLocation)>,
+ crate extern_locations: FxHashMap<CrateNum, ExternalLocation>,
/// Cache of where documentation for primitives can be found.
crate primitive_locations: FxHashMap<clean::PrimitiveType, DefId>,
/// All intra-doc links resolved so far.
///
/// Links are indexed by the DefId of the item they document.
- crate intra_doc_links: BTreeMap<DefId, Vec<clean::ItemLink>>,
+ crate intra_doc_links: BTreeMap<FakeDefId, Vec<clean::ItemLink>>,
}
/// This struct is used to wrap the `cache` and `tcx` in order to run `DocFolder`.
// Cache where all our extern crates are located
// FIXME: this part is specific to HTML so it'd be nice to remove it from the common code
for &(n, ref e) in &krate.externs {
- let src_root = match e.src(tcx) {
- FileName::Real(ref p) => match p.local_path().parent() {
- Some(p) => p.to_path_buf(),
- None => PathBuf::new(),
- },
- _ => PathBuf::new(),
- };
let name = e.name(tcx);
let extern_url = extern_html_root_urls.get(&*name.as_str()).map(|u| &**u);
let did = DefId { krate: n, index: CRATE_DEF_INDEX };
- self.extern_locations.insert(
- n,
- (name, src_root, extern_location(e, extern_url, tcx.get_attrs(did), &dst, tcx)),
- );
-
+ self.extern_locations.insert(n, e.location(extern_url, &dst, tcx));
self.external_paths.insert(did, (vec![name.to_string()], ItemType::Module));
}
// If the impl is from a masked crate or references something from a
// masked crate then remove it completely.
if let clean::ImplItem(ref i) = *item.kind {
- if self.cache.masked_crates.contains(&item.def_id.krate)
+ if self.cache.masked_crates.contains(&item.def_id.krate())
|| i.trait_.def_id().map_or(false, |d| self.cache.masked_crates.contains(&d.krate))
|| i.for_.def_id().map_or(false, |d| self.cache.masked_crates.contains(&d.krate))
{
// Propagate a trait method's documentation to all implementors of the
// trait.
if let clean::TraitItem(ref t) = *item.kind {
- self.cache.traits.entry(item.def_id).or_insert_with(|| clean::TraitWithExtraInfo {
- trait_: t.clone(),
- is_notable: item.attrs.has_doc_flag(sym::notable_trait),
+ self.cache.traits.entry(item.def_id.expect_real()).or_insert_with(|| {
+ clean::TraitWithExtraInfo {
+ trait_: t.clone(),
+ is_notable: item.attrs.has_doc_flag(sym::notable_trait),
+ }
});
}
if i.blanket_impl.is_none() {
self.cache
.implementors
- .entry(did)
+ .entry(did.into())
.or_default()
.push(Impl { impl_item: item.clone() });
}
// A crate has a module at its root, containing all items,
// which should not be indexed. The crate-item itself is
// inserted later on when serializing the search-index.
- if item.def_id.index != CRATE_DEF_INDEX {
+ if item.def_id.index().map_or(false, |idx| idx != CRATE_DEF_INDEX) {
self.cache.search_index.push(IndexItem {
ty: item.type_(),
name: s.to_string(),
desc: item
.doc_value()
.map_or_else(String::new, |x| short_markdown_summary(&x.as_str())),
- parent,
+ parent: parent.map(FakeDefId::new_real),
parent_idx: None,
search_type: get_index_search_type(&item, &self.empty_cache, self.tcx),
aliases: item.attrs.get_doc_aliases(),
| clean::EnumItem(..)
| clean::TypedefItem(..)
| clean::TraitItem(..)
+ | clean::TraitAliasItem(..)
| clean::FunctionItem(..)
| clean::ModuleItem(..)
| clean::ForeignFunctionItem(..)
| clean::ForeignTypeItem
| clean::MacroItem(..)
| clean::ProcMacroItem(..)
- | clean::VariantItem(..)
- if !self.cache.stripped_mod =>
- {
- // Re-exported items mean that the same id can show up twice
- // in the rustdoc ast that we're looking at. We know,
- // however, that a re-exported item doesn't show up in the
- // `public_items` map, so we can skip inserting into the
- // paths map if there was already an entry present and we're
- // not a public item.
- if !self.cache.paths.contains_key(&item.def_id)
- || self.cache.access_levels.is_public(item.def_id)
- {
- self.cache.paths.insert(item.def_id, (self.cache.stack.clone(), item.type_()));
+ | clean::VariantItem(..) => {
+ if !self.cache.stripped_mod {
+ // Re-exported items mean that the same id can show up twice
+ // in the rustdoc ast that we're looking at. We know,
+ // however, that a re-exported item doesn't show up in the
+ // `public_items` map, so we can skip inserting into the
+ // paths map if there was already an entry present and we're
+ // not a public item.
+ if !self.cache.paths.contains_key(&item.def_id.expect_real())
+ || self.cache.access_levels.is_public(item.def_id.expect_real())
+ {
+ self.cache.paths.insert(
+ item.def_id.expect_real(),
+ (self.cache.stack.clone(), item.type_()),
+ );
+ }
}
}
clean::PrimitiveItem(..) => {
- self.cache.paths.insert(item.def_id, (self.cache.stack.clone(), item.type_()));
+ self.cache
+ .paths
+ .insert(item.def_id.expect_real(), (self.cache.stack.clone(), item.type_()));
}
- _ => {}
+ clean::ExternCrateItem { .. }
+ | clean::ImportItem(..)
+ | clean::OpaqueTyItem(..)
+ | clean::ImplItem(..)
+ | clean::TyMethodItem(..)
+ | clean::MethodItem(..)
+ | clean::StructFieldItem(..)
+ | clean::AssocConstItem(..)
+ | clean::AssocTypeItem(..)
+ | clean::StrippedItem(..)
+ | clean::KeywordItem(..) => {
+ // FIXME: Do these need handling?
+ // The person writing this comment doesn't know.
+ // So would rather leave them to an expert,
+ // as at least the list is better than `_ => {}`.
+ }
}
// Maintain the parent stack
| clean::StructItem(..)
| clean::UnionItem(..)
| clean::VariantItem(..) => {
- self.cache.parent_stack.push(item.def_id);
+ self.cache.parent_stack.push(item.def_id.expect_real());
self.cache.parent_is_trait_impl = false;
true
}
crate mod item_type;
crate mod renderer;
-crate use renderer::{run_format, FormatRenderer};
+use rustc_hir::def_id::DefId;
-use rustc_span::def_id::DefId;
+crate use renderer::{run_format, FormatRenderer};
use crate::clean;
use crate::clean::types::GetDefId;
use rustc_data_structures::captures::Captures;
use rustc_data_structures::fx::FxHashSet;
use rustc_hir as hir;
+use rustc_hir::def_id::DefId;
use rustc_middle::ty::TyCtxt;
-use rustc_span::def_id::{DefId, CRATE_DEF_INDEX};
+use rustc_span::def_id::CRATE_DEF_INDEX;
use rustc_target::spec::abi::Abi;
-use crate::clean::{self, utils::find_nearest_parent_module, PrimitiveType};
+use crate::clean::{
+ self, utils::find_nearest_parent_module, ExternalCrate, FakeDefId, PrimitiveType,
+};
use crate::formats::item_type::ItemType;
use crate::html::escape::Escape;
use crate::html::render::cache::ExternalLocation;
fqp,
shortty,
match cache.extern_locations[&did.krate] {
- (.., ExternalLocation::Remote(ref s)) => {
+ ExternalLocation::Remote(ref s) => {
let s = s.trim_end_matches('/');
let mut s = vec![&s[..]];
s.extend(module_fqp[..].iter().map(String::as_str));
s
}
- (.., ExternalLocation::Local) => href_relative_parts(module_fqp, relative_to),
- (.., ExternalLocation::Unknown) => return None,
+ ExternalLocation::Local => href_relative_parts(module_fqp, relative_to),
+ ExternalLocation::Unknown => return None,
},
)
}
Some(&def_id) => {
let cname_str;
let loc = match m.extern_locations[&def_id.krate] {
- (ref cname, _, ExternalLocation::Remote(ref s)) => {
- cname_str = cname.as_str();
+ ExternalLocation::Remote(ref s) => {
+ cname_str =
+ ExternalCrate { crate_num: def_id.krate }.name(cx.tcx()).as_str();
Some(vec![s.trim_end_matches('/'), &cname_str[..]])
}
- (ref cname, _, ExternalLocation::Local) => {
- cname_str = cname.as_str();
+ ExternalLocation::Local => {
+ cname_str =
+ ExternalCrate { crate_num: def_id.krate }.name(cx.tcx()).as_str();
Some(if cx.current.first().map(|x| &x[..]) == Some(&cname_str[..]) {
iter::repeat("..").take(cx.current.len() - 1).collect()
} else {
iter::repeat("..").take(cx.current.len()).chain(cname).collect()
})
}
- (.., ExternalLocation::Unknown) => None,
+ ExternalLocation::Unknown => None,
};
if let Some(loc) = loc {
write!(
text: &'a str,
cx: &'cx Context<'_>,
) -> impl fmt::Display + 'a {
- let parts = href(did, cx);
+ let parts = href(did.into(), cx);
display_fn(move |f| {
if let Some((url, short_ty, fqp)) = parts {
write!(
// everything comes in as a fully resolved QPath (hard to
// look at).
box clean::ResolvedPath { did, ref param_names, .. } => {
- match href(did, cx) {
+ match href(did.into(), cx) {
Some((ref url, _, ref path)) if !f.alternate() => {
write!(
f,
impl clean::Visibility {
crate fn print_with_space<'a, 'tcx: 'a>(
self,
- item_did: DefId,
+ item_did: FakeDefId,
cx: &'a Context<'tcx>,
) -> impl fmt::Display + 'a + Captures<'tcx> {
let to_print = match self {
// FIXME(camelid): This may not work correctly if `item_did` is a module.
// However, rustdoc currently never displays a module's
// visibility, so it shouldn't matter.
- let parent_module = find_nearest_parent_module(cx.tcx(), item_did);
+ let parent_module = find_nearest_parent_module(cx.tcx(), item_did.expect_real());
if vis_did.index == CRATE_DEF_INDEX {
"pub(crate) ".to_owned()
}
fn write_header(out: &mut Buffer, class: Option<&str>) {
- write!(out, "<div class=\"example-wrap\"><pre class=\"rust {}\">\n", class.unwrap_or_default());
+ writeln!(out, "<div class=\"example-wrap\"><pre class=\"rust {}\">", class.unwrap_or_default());
}
fn write_code(out: &mut Buffer, src: &str, edition: Edition) {
}
fn write_footer(out: &mut Buffer, playground_button: Option<&str>) {
- write!(out, "</pre>{}</div>\n", playground_button.unwrap_or_default());
+ writeln!(out, "</pre>{}</div>", playground_button.unwrap_or_default());
}
/// How a span of text is classified. Mostly corresponds to token kinds.
use std::collections::BTreeMap;
-use std::path::Path;
-use rustc_ast::ast;
use rustc_data_structures::fx::{FxHashMap, FxHashSet};
use rustc_middle::ty::TyCtxt;
-use rustc_span::symbol::{sym, Symbol};
+use rustc_span::symbol::Symbol;
use serde::ser::{Serialize, SerializeStruct, Serializer};
use crate::clean;
use crate::clean::types::{
- AttributesExt, FnDecl, FnRetTy, GenericBound, Generics, GetDefId, Type, WherePredicate,
+ FakeDefId, FnDecl, FnRetTy, GenericBound, Generics, GetDefId, Type, WherePredicate,
};
use crate::formats::cache::Cache;
use crate::formats::item_type::ItemType;
Unknown,
}
-/// Attempts to find where an external crate is located, given that we're
-/// rendering in to the specified source destination.
-crate fn extern_location(
- e: &clean::ExternalCrate,
- extern_url: Option<&str>,
- ast_attrs: &[ast::Attribute],
- dst: &Path,
- tcx: TyCtxt<'_>,
-) -> ExternalLocation {
- use ExternalLocation::*;
- // See if there's documentation generated into the local directory
- let local_location = dst.join(&*e.name(tcx).as_str());
- if local_location.is_dir() {
- return Local;
- }
-
- if let Some(url) = extern_url {
- let mut url = url.to_string();
- if !url.ends_with('/') {
- url.push('/');
- }
- return Remote(url);
- }
-
- // Failing that, see if there's an attribute specifying where to find this
- // external crate
- ast_attrs
- .lists(sym::doc)
- .filter(|a| a.has_name(sym::html_root_url))
- .filter_map(|a| a.value_str())
- .map(|url| {
- let mut url = url.to_string();
- if !url.ends_with('/') {
- url.push('/')
- }
- Remote(url)
- })
- .next()
- .unwrap_or(Unknown) // Well, at least we tried.
-}
-
/// Builds the search index from the collected metadata
crate fn build_index<'tcx>(krate: &clean::Crate, cache: &mut Cache, tcx: TyCtxt<'tcx>) -> String {
let mut defid_to_pathid = FxHashMap::default();
name: item.name.unwrap().to_string(),
path: fqp[..fqp.len() - 1].join("::"),
desc: item.doc_value().map_or_else(String::new, |s| short_markdown_summary(&s)),
- parent: Some(did),
+ parent: Some(did.into()),
parent_idx: None,
search_type: get_index_search_type(&item, cache, tcx),
aliases: item.attrs.get_doc_aliases(),
defid_to_pathid.insert(defid, pathid);
lastpathid += 1;
- if let Some(&(ref fqp, short)) = paths.get(&defid) {
+ if let Some(&(ref fqp, short)) = paths.get(&defid.expect_real()) {
crate_paths.push((short, fqp.last().unwrap().clone()));
Some(pathid)
} else {
fn get_index_type(clean_type: &clean::Type, cache: &Cache) -> RenderType {
RenderType {
- ty: clean_type.def_id_full(cache),
+ ty: clean_type.def_id_full(cache).map(FakeDefId::new_real),
idx: None,
name: get_index_type_name(clean_type, true).map(|s| s.as_str().to_ascii_lowercase()),
generics: get_generics(clean_type, cache),
.filter_map(|t| {
get_index_type_name(t, false).map(|name| Generic {
name: name.as_str().to_ascii_lowercase(),
- defid: t.def_id_full(cache),
+ defid: t.def_id_full(cache).map(FakeDefId::new_real),
idx: None,
})
})
use super::{print_sidebar, settings, AllTypes, NameDoc, StylePath, BASIC_KEYWORDS};
use crate::clean;
+use crate::clean::ExternalCrate;
use crate::config::RenderOptions;
use crate::docfs::{DocFS, PathError};
use crate::error::Error;
&self.shared.style_files,
)
} else {
- if let Some(&(ref names, ty)) = self.cache.paths.get(&it.def_id) {
+ if let Some(&(ref names, ty)) = self.cache.paths.get(&it.def_id.expect_real()) {
let mut path = String::new();
for name in &names[..names.len() - 1] {
path.push_str(name);
}
} else {
let (krate, src_root) = match *self.cache.extern_locations.get(&cnum)? {
- (name, ref src, ExternalLocation::Local) => (name, src),
- (name, ref src, ExternalLocation::Remote(ref s)) => {
+ ExternalLocation::Local => {
+ let e = ExternalCrate { crate_num: cnum };
+ (e.name(self.tcx()), e.src_root(self.tcx()))
+ }
+ ExternalLocation::Remote(ref s) => {
root = s.to_string();
- (name, src)
+ let e = ExternalCrate { crate_num: cnum };
+ (e.name(self.tcx()), e.src_root(self.tcx()))
}
- (_, _, ExternalLocation::Unknown) => return None,
+ ExternalLocation::Unknown => return None,
};
sources::clean_path(&src_root, file, false, |component| {
use serde::ser::SerializeSeq;
use serde::{Serialize, Serializer};
-use crate::clean::{self, GetDefId, RenderedLink, SelfTy};
+use crate::clean::{self, FakeDefId, GetDefId, RenderedLink, SelfTy};
use crate::docfs::PathError;
use crate::error::Error;
use crate::formats::cache::Cache;
crate name: String,
crate path: String,
crate desc: String,
- crate parent: Option<DefId>,
+ crate parent: Option<FakeDefId>,
crate parent_idx: Option<usize>,
crate search_type: Option<IndexItemFunctionType>,
crate aliases: Box<[String]>,
/// A type used for the search index.
#[derive(Debug)]
crate struct RenderType {
- ty: Option<DefId>,
+ ty: Option<FakeDefId>,
idx: Option<usize>,
name: Option<String>,
generics: Option<Vec<Generic>>,
#[derive(Debug)]
crate struct Generic {
name: String,
- defid: Option<DefId>,
+ defid: Option<FakeDefId>,
idx: Option<usize>,
}
if let Some(ref name) = item.name {
info!("Documenting {}", name);
}
- document_item_info(w, cx, item, false, parent);
- document_full(w, item, cx, false);
+ document_item_info(w, cx, item, parent);
+ document_full(w, item, cx);
}
/// Render md_text as markdown.
-fn render_markdown(
- w: &mut Buffer,
- cx: &Context<'_>,
- md_text: &str,
- links: Vec<RenderedLink>,
- is_hidden: bool,
-) {
+fn render_markdown(w: &mut Buffer, cx: &Context<'_>, md_text: &str, links: Vec<RenderedLink>) {
let mut ids = cx.id_map.borrow_mut();
write!(
w,
- "<div class=\"docblock{}\">{}</div>",
- if is_hidden { " hidden" } else { "" },
+ "<div class=\"docblock\">{}</div>",
Markdown(
md_text,
&links,
item: &clean::Item,
cx: &Context<'_>,
link: AssocItemLink<'_>,
- is_hidden: bool,
parent: &clean::Item,
show_def_docs: bool,
) {
- document_item_info(w, cx, item, is_hidden, Some(parent));
+ document_item_info(w, cx, item, Some(parent));
if !show_def_docs {
return;
}
}
}
- write!(
- w,
- "<div class='docblock{}'>{}</div>",
- if is_hidden { " hidden" } else { "" },
- summary_html,
- );
+ write!(w, "<div class='docblock'>{}</div>", summary_html,);
}
}
-fn document_full(w: &mut Buffer, item: &clean::Item, cx: &Context<'_>, is_hidden: bool) {
+fn document_full(w: &mut Buffer, item: &clean::Item, cx: &Context<'_>) {
if let Some(s) = cx.shared.maybe_collapsed_doc_value(item) {
debug!("Doc block: =====\n{}\n=====", s);
- render_markdown(w, cx, &s, item.links(cx), is_hidden);
+ render_markdown(w, cx, &s, item.links(cx));
}
}
w: &mut Buffer,
cx: &Context<'_>,
item: &clean::Item,
- is_hidden: bool,
parent: Option<&clean::Item>,
) {
let item_infos = short_item_info(item, cx, parent);
if !item_infos.is_empty() {
- if is_hidden {
- w.write_str("<div class=\"item-info hidden\">");
- } else {
- w.write_str("<div class=\"item-info\">");
- }
+ w.write_str("<div class=\"item-info\">");
for info in item_infos {
w.write_str(&info);
}
.iter()
.map(|i| {
let did = i.trait_did_full(cache).unwrap();
- let assoc_link = AssocItemLink::GotoSource(did, &i.inner_impl().provided_trait_methods);
+ let provided_trait_methods = i.inner_impl().provided_trait_methods(tcx);
+ let assoc_link = AssocItemLink::GotoSource(did.into(), &provided_trait_methods);
let mut buffer = if w.is_for_html() { Buffer::html() } else { Buffer::new() };
render_impl(
&mut buffer,
AssocItemLink::Anchor(Some(ref id)) => format!("#{}", id),
AssocItemLink::Anchor(None) => anchor,
AssocItemLink::GotoSource(did, _) => {
- href(did, cx).map(|p| format!("{}{}", p.0, anchor)).unwrap_or(anchor)
+ href(did.expect_real(), cx).map(|p| format!("{}{}", p.0, anchor)).unwrap_or(anchor)
}
}
}
ItemType::TyMethod
};
- href(did, cx)
+ href(did.expect_real(), cx)
.map(|p| format!("{}#{}.{}", p.0, ty, name))
.unwrap_or_else(|| format!("#{}.{}", ty, name))
}
// a whitespace prefix and newline.
fn render_attributes_in_pre(w: &mut Buffer, it: &clean::Item, prefix: &str) {
for a in attributes(it) {
- write!(w, "{}{}\n", prefix, a);
+ writeln!(w, "{}{}", prefix, a);
}
}
#[derive(Copy, Clone)]
enum AssocItemLink<'a> {
Anchor(Option<&'a str>),
- GotoSource(DefId, &'a FxHashSet<Symbol>),
+ GotoSource(FakeDefId, &'a FxHashSet<Symbol>),
}
impl<'a> AssocItemLink<'a> {
it,
&[],
Some(&tydef.type_),
- AssocItemLink::GotoSource(t_did, &FxHashSet::default()),
+ AssocItemLink::GotoSource(t_did.into(), &FxHashSet::default()),
"",
cx,
);
let trait_ = i.trait_did_full(cache).map(|did| &traits[&did]);
let mut close_tags = String::new();
+ // For trait implementations, the `interesting` output contains all methods that have doc
+ // comments, and the `boring` output contains all methods that do not. The distinction is
+ // used to allow hiding the boring methods.
fn doc_impl_item(
- w: &mut Buffer,
+ boring: &mut Buffer,
+ interesting: &mut Buffer,
cx: &Context<'_>,
item: &clean::Item,
parent: &clean::Item,
}
};
- let (is_hidden, extra_class) =
- if (trait_.is_none() || item.doc_value().is_some() || item.kind.is_type_alias())
- && !is_default_item
- {
- (false, "")
- } else {
- (true, " hidden")
- };
let in_trait_class = if trait_.is_some() { " trait-impl" } else { "" };
+
+ let mut doc_buffer = Buffer::empty_from(boring);
+ let mut info_buffer = Buffer::empty_from(boring);
+ let mut short_documented = true;
+
+ if render_method_item {
+ if !is_default_item {
+ if let Some(t) = trait_ {
+ // The trait item may have been stripped so we might not
+ // find any documentation or stability for it.
+ if let Some(it) = t.items.iter().find(|i| i.name == item.name) {
+ // We need the stability of the item from the trait
+ // because impls can't have a stability.
+ if item.doc_value().is_some() {
+ document_item_info(&mut info_buffer, cx, it, Some(parent));
+ document_full(&mut doc_buffer, item, cx);
+ short_documented = false;
+ } else {
+ // In case the item isn't documented,
+ // provide short documentation from the trait.
+ document_short(&mut doc_buffer, it, cx, link, parent, show_def_docs);
+ }
+ }
+ } else {
+ document_item_info(&mut info_buffer, cx, item, Some(parent));
+ if show_def_docs {
+ document_full(&mut doc_buffer, item, cx);
+ short_documented = false;
+ }
+ }
+ } else {
+ document_short(&mut doc_buffer, item, cx, link, parent, show_def_docs);
+ }
+ }
+ let w = if short_documented && trait_.is_some() { interesting } else { boring };
+
+ if !doc_buffer.is_empty() {
+ w.write_str("<details class=\"rustdoc-toggle\" open><summary>");
+ }
match *item.kind {
clean::MethodItem(..) | clean::TyMethodItem(_) => {
// Only render when the method is not static or we allow static methods
})
})
.map(|item| format!("{}.{}", item.type_(), name));
- write!(
- w,
- "<h4 id=\"{}\" class=\"{}{}{}\">",
- id, item_type, extra_class, in_trait_class,
- );
+ write!(w, "<h4 id=\"{}\" class=\"{}{}\">", id, item_type, in_trait_class,);
w.write_str("<code>");
render_assoc_item(
w,
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, extra_class, in_trait_class
- );
+ write!(w, "<h4 id=\"{}\" class=\"{}{}\"><code>", id, item_type, in_trait_class);
assoc_type(
w,
item,
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, extra_class, in_trait_class
- );
+ write!(w, "<h4 id=\"{}\" class=\"{}{}\"><code>", id, item_type, in_trait_class);
assoc_const(
w,
item,
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, extra_class, in_trait_class
- );
+ write!(w, "<h4 id=\"{}\" class=\"{}{}\"><code>", id, item_type, in_trait_class);
assoc_type(
w,
item,
_ => panic!("can't make docs for trait item with name {:?}", item.name),
}
- if render_method_item {
- if !is_default_item {
- if let Some(t) = trait_ {
- // The trait item may have been stripped so we might not
- // find any documentation or stability for it.
- if let Some(it) = t.items.iter().find(|i| i.name == item.name) {
- // We need the stability of the item from the trait
- // because impls can't have a stability.
- if item.doc_value().is_some() {
- document_item_info(w, cx, it, is_hidden, Some(parent));
- document_full(w, item, cx, is_hidden);
- } else {
- // In case the item isn't documented,
- // provide short documentation from the trait.
- document_short(w, it, cx, link, is_hidden, parent, show_def_docs);
- }
- }
- } else {
- document_item_info(w, cx, item, is_hidden, Some(parent));
- if show_def_docs {
- document_full(w, item, cx, is_hidden);
- }
- }
- } else {
- document_short(w, item, cx, link, is_hidden, parent, show_def_docs);
- }
+ w.push_buffer(info_buffer);
+ if !doc_buffer.is_empty() {
+ w.write_str("</summary>");
+ w.push_buffer(doc_buffer);
+ w.push_str("</details>");
}
}
let mut impl_items = Buffer::empty_from(w);
+ let mut default_impl_items = Buffer::empty_from(w);
+
for trait_item in &i.inner_impl().items {
doc_impl_item(
+ &mut default_impl_items,
&mut impl_items,
cx,
trait_item,
}
fn render_default_items(
- w: &mut Buffer,
+ boring: &mut Buffer,
+ interesting: &mut Buffer,
cx: &Context<'_>,
t: &clean::Trait,
i: &clean::Impl,
continue;
}
let did = i.trait_.as_ref().unwrap().def_id_full(cx.cache()).unwrap();
- let assoc_link = AssocItemLink::GotoSource(did, &i.provided_trait_methods);
+ let provided_methods = i.provided_trait_methods(cx.tcx());
+ let assoc_link = AssocItemLink::GotoSource(did.into(), &provided_methods);
doc_impl_item(
- w,
+ boring,
+ interesting,
cx,
trait_item,
parent,
if show_default_items {
if let Some(t) = trait_ {
render_default_items(
+ &mut default_impl_items,
&mut impl_items,
cx,
&t.trait_,
);
}
}
- let details_str = if impl_items.is_empty() {
- ""
- } else {
- "<details class=\"rustdoc-toggle implementors-toggle\" open><summary>"
+ let toggled = !impl_items.is_empty() || !default_impl_items.is_empty();
+ let open_details = |close_tags: &mut String| {
+ if toggled {
+ close_tags.insert_str(0, "</details>");
+ "<details class=\"rustdoc-toggle implementors-toggle\" open><summary>"
+ } else {
+ ""
+ }
};
if render_mode == RenderMode::Normal {
let id = cx.derive_id(match i.inner_impl().trait_ {
write!(
w,
"{}<h3 id=\"{}\" class=\"impl\"{}><code class=\"in-band\">",
- details_str, id, aliases
+ open_details(&mut close_tags),
+ id,
+ aliases
);
- if !impl_items.is_empty() {
- close_tags.insert_str(0, "</details>");
- }
write!(w, "{}", i.inner_impl().print(use_absolute, cx));
if show_def_docs {
for it in &i.inner_impl().items {
write!(
w,
"{}<h3 id=\"{}\" class=\"impl\"{}><code class=\"in-band\">{}</code>",
- details_str,
+ open_details(&mut close_tags),
id,
aliases,
i.inner_impl().print(false, cx)
);
- if !impl_items.is_empty() {
- close_tags.insert_str(0, "</details>");
- }
}
write!(w, "<a href=\"#{}\" class=\"anchor\"></a>", id);
render_stability_since_raw(
outer_const_version,
);
write_srclink(cx, &i.impl_item, w);
- if impl_items.is_empty() {
+ if !toggled {
w.write_str("</h3>");
} else {
w.write_str("</h3></summary>");
);
}
}
- if !impl_items.is_empty() {
+ if toggled {
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>");
}
}
fn sidebar_assoc_items(cx: &Context<'_>, out: &mut Buffer, it: &clean::Item) {
- if let Some(v) = cx.cache.impls.get(&it.def_id) {
+ let did = it.def_id.expect_real();
+ if let Some(v) = cx.cache.impls.get(&did) {
let mut used_links = FxHashSet::default();
let cache = cx.cache();
w,
"<tr><td><code>{}extern crate {} as {};",
myitem.visibility.print_with_space(myitem.def_id, cx),
- anchor(myitem.def_id, &*src.as_str(), cx),
+ anchor(myitem.def_id.expect_real(), &*src.as_str(), cx),
myitem.name.as_ref().unwrap(),
),
None => write!(
w,
"<tr><td><code>{}extern crate {};",
myitem.visibility.print_with_space(myitem.def_id, cx),
- anchor(myitem.def_id, &*myitem.name.as_ref().unwrap().as_str(), cx),
+ anchor(
+ myitem.def_id.expect_real(),
+ &*myitem.name.as_ref().unwrap().as_str(),
+ cx
+ ),
),
}
w.write_str("</code></td></tr>");
// Just need an item with the correct def_id and attrs
let import_item = clean::Item {
- def_id: import_def_id,
+ def_id: import_def_id.into(),
attrs: import_attrs,
cfg: ast_attrs.cfg(cx.tcx().sess.diagnostic()),
..myitem.clone()
}
// If there are methods directly on this trait object, render them here.
- render_assoc_items(w, cx, it, it.def_id, AssocItemRender::All);
+ render_assoc_items(w, cx, it, it.def_id.expect_real(), AssocItemRender::All);
if let Some(implementors) = cx.cache.implementors.get(&it.def_id) {
// The DefId is for the first Type found with that name. The bool is
write_small_section_header(w, "foreign-impls", "Implementations on Foreign Types", "");
for implementor in foreign {
- let assoc_link = AssocItemLink::GotoSource(
- implementor.impl_item.def_id,
- &implementor.inner_impl().provided_trait_methods,
- );
+ let provided_methods = implementor.inner_impl().provided_trait_methods(cx.tcx());
+ let assoc_link =
+ AssocItemLink::GotoSource(implementor.impl_item.def_id, &provided_methods);
render_impl(
w,
cx,
path = if it.def_id.is_local() {
cx.current.join("/")
} else {
- let (ref path, _) = cx.cache.external_paths[&it.def_id];
+ let (ref path, _) = cx.cache.external_paths[&it.def_id.expect_real()];
path[..path.len() - 1].join("/")
},
ty = it.type_(),
// won't be visible anywhere in the docs. It would be nice to also show
// associated items from the aliased type (see discussion in #32077), but
// we need #14072 to make sense of the generics.
- render_assoc_items(w, cx, it, it.def_id, AssocItemRender::All)
+ render_assoc_items(w, cx, it, it.def_id.expect_real(), AssocItemRender::All)
}
fn item_opaque_ty(w: &mut Buffer, cx: &Context<'_>, it: &clean::Item, t: &clean::OpaqueTy) {
// won't be visible anywhere in the docs. It would be nice to also show
// associated items from the aliased type (see discussion in #32077), but
// we need #14072 to make sense of the generics.
- render_assoc_items(w, cx, it, it.def_id, AssocItemRender::All)
+ render_assoc_items(w, cx, it, it.def_id.expect_real(), AssocItemRender::All)
}
fn item_typedef(w: &mut Buffer, cx: &Context<'_>, it: &clean::Item, t: &clean::Typedef) {
// won't be visible anywhere in the docs. It would be nice to also show
// associated items from the aliased type (see discussion in #32077), but
// we need #14072 to make sense of the generics.
- render_assoc_items(w, cx, it, it.def_id, AssocItemRender::All)
+ render_assoc_items(w, cx, it, it.def_id.expect_real(), AssocItemRender::All)
}
fn item_union(w: &mut Buffer, cx: &Context<'_>, it: &clean::Item, s: &clean::Union) {
document(w, cx, field, Some(it));
}
}
- render_assoc_items(w, cx, it, it.def_id, AssocItemRender::All)
+ render_assoc_items(w, cx, it, it.def_id.expect_real(), AssocItemRender::All)
}
fn item_enum(w: &mut Buffer, cx: &Context<'_>, it: &clean::Item, e: &clean::Enum) {
render_stability_since(w, variant, it, cx.tcx());
}
}
- render_assoc_items(w, cx, it, it.def_id, AssocItemRender::All)
+ render_assoc_items(w, cx, it, it.def_id.expect_real(), AssocItemRender::All)
}
fn item_macro(w: &mut Buffer, cx: &Context<'_>, it: &clean::Item, t: &clean::Macro) {
fn item_primitive(w: &mut Buffer, cx: &Context<'_>, it: &clean::Item) {
document(w, cx, it, None);
- render_assoc_items(w, cx, it, it.def_id, AssocItemRender::All)
+ render_assoc_items(w, cx, it, it.def_id.expect_real(), AssocItemRender::All)
}
fn item_constant(w: &mut Buffer, cx: &Context<'_>, it: &clean::Item, c: &clean::Constant) {
}
}
}
- render_assoc_items(w, cx, it, it.def_id, AssocItemRender::All)
+ render_assoc_items(w, cx, it, it.def_id.expect_real(), AssocItemRender::All)
}
fn item_static(w: &mut Buffer, cx: &Context<'_>, it: &clean::Item, s: &clean::Static) {
document(w, cx, it, None);
- render_assoc_items(w, cx, it, it.def_id, AssocItemRender::All)
+ render_assoc_items(w, cx, it, it.def_id.expect_real(), AssocItemRender::All)
}
fn item_keyword(w: &mut Buffer, cx: &Context<'_>, it: &clean::Item) {
// Update the list of all implementors for traits
let dst = cx.dst.join("implementors");
for (&did, imps) in &cx.cache.implementors {
+ let did = did.expect_real();
+
// Private modules can leak through to this phase of rustdoc, which
// could contain implementations for otherwise private types. In some
// rare cases we could find an implementation for an item which wasn't
//
// If the implementation is from another crate then that crate
// should add it.
- if imp.impl_item.def_id.krate == did.krate || !imp.impl_item.def_id.is_local() {
+ if imp.impl_item.def_id.krate() == did.krate || !imp.impl_item.def_id.is_local() {
None
} else {
Some(Implementor {
}
buf.write_str("<pre class=\"line-numbers\">");
for i in 1..=lines {
- write!(buf, "<span id=\"{0}\">{0:1$}</span>\n", i, cols);
+ writeln!(buf, "<span id=\"{0}\">{0:1$}</span>", i, cols);
}
buf.write_str("</pre>");
highlight::render_with_highlighting(s, buf, None, None, None, edition);
var hideMethodDocs = getSettingValue("auto-hide-method-docs") === "true";
var hideImplementors = getSettingValue("auto-collapse-implementors") !== "false";
var hideLargeItemContents = getSettingValue("auto-hide-large-items") !== "false";
- var hideTraitImplementations =
- getSettingValue("auto-hide-trait-implementations") !== "false";
var impl_list = document.getElementById("trait-implementations-list");
if (impl_list !== null) {
});
}
- var func = function(e) {
- var next = e.nextElementSibling;
- if (next && hasClass(next, "item-info")) {
- next = next.nextElementSibling;
- }
- if (!next) {
- return;
- }
- if (hasClass(next, "docblock")) {
- var newToggle = toggle.cloneNode(true);
- insertAfter(newToggle, e.childNodes[e.childNodes.length - 1]);
- if (hideMethodDocs === true && hasClass(e, "method") === true) {
- collapseDocs(newToggle, "hide");
+ if (hideMethodDocs === true) {
+ onEachLazy(document.getElementsByClassName("method"), function(e) {
+ var toggle = e.parentNode;
+ if (toggle) {
+ toggle = toggle.parentNode;
}
- }
- };
-
- var funcImpl = function(e) {
- var next = e.nextElementSibling;
- if (next && hasClass(next, "item-info")) {
- next = next.nextElementSibling;
- }
- if (next && hasClass(next, "docblock")) {
- next = next.nextElementSibling;
- }
- if (!next) {
- return;
- }
- };
+ if (toggle && toggle.tagName === "DETAILS") {
+ toggle.open = false;
+ }
+ });
+ }
- onEachLazy(document.getElementsByClassName("method"), func);
- onEachLazy(document.getElementsByClassName("associatedconstant"), func);
- var impl_call = function() {};
onEachLazy(document.getElementsByTagName("details"), function (e) {
var showLargeItem = !hideLargeItemContents && hasClass(e, "type-contents-toggle");
var showImplementor = !hideImplementors && hasClass(e, "implementors-toggle");
e.open = true;
}
});
- if (hideMethodDocs === true) {
- impl_call = function(e, newToggle) {
- if (e.id.match(/^impl(?:-\d+)?$/) === null) {
- // Automatically minimize all non-inherent impls
- if (hasClass(e, "impl") === true) {
- collapseDocs(newToggle, "hide");
- }
- }
- };
- }
- var newToggle = document.createElement("a");
- newToggle.href = "javascript:void(0)";
- newToggle.className = "collapse-toggle hidden-default collapsed";
- newToggle.innerHTML = "[<span class=\"inner\">" + labelForToggleButton(true) +
- "</span>] Show hidden undocumented items";
- function toggleClicked() {
- if (hasClass(this, "collapsed")) {
- removeClass(this, "collapsed");
- onEachLazy(this.parentNode.getElementsByClassName("hidden"), function(x) {
- if (hasClass(x, "content") === false) {
- removeClass(x, "hidden");
- addClass(x, "x");
- }
- }, true);
- this.innerHTML = "[<span class=\"inner\">" + labelForToggleButton(false) +
- "</span>] Hide undocumented items";
- } else {
- addClass(this, "collapsed");
- onEachLazy(this.parentNode.getElementsByClassName("x"), function(x) {
- if (hasClass(x, "content") === false) {
- addClass(x, "hidden");
- removeClass(x, "x");
- }
- }, true);
- this.innerHTML = "[<span class=\"inner\">" + labelForToggleButton(true) +
- "</span>] Show hidden undocumented items";
- }
- }
- onEachLazy(document.getElementsByClassName("impl-items"), function(e) {
- onEachLazy(e.getElementsByClassName("associatedconstant"), func);
- // We transform the DOM iterator into a vec of DOM elements to prevent performance
- // issues on webkit browsers.
- var hiddenElems = Array.prototype.slice.call(e.getElementsByClassName("hidden"));
- var needToggle = hiddenElems.some(function(hiddenElem) {
- return hasClass(hiddenElem, "content") === false &&
- hasClass(hiddenElem, "docblock") === false;
- });
- if (needToggle === true) {
- var inner_toggle = newToggle.cloneNode(true);
- inner_toggle.onclick = toggleClicked;
- e.insertBefore(inner_toggle, e.firstChild);
- impl_call(e.previousSibling, inner_toggle);
- }
- });
var currentType = document.getElementsByClassName("type-decl")[0];
var className = null;
searchState.setup();
}());
-function copy_path(but) {
- var parent = but.parentElement;
- var path = [];
+(function () {
+ var reset_button_timeout = null;
- onEach(parent.childNodes, function(child) {
- if (child.tagName === 'A') {
- path.push(child.textContent);
- }
- });
+ window.copy_path = function(but) {
+ var parent = but.parentElement;
+ var path = [];
- var el = document.createElement('textarea');
- el.value = 'use ' + path.join('::') + ';';
- el.setAttribute('readonly', '');
- // To not make it appear on the screen.
- el.style.position = 'absolute';
- el.style.left = '-9999px';
+ onEach(parent.childNodes, function(child) {
+ if (child.tagName === 'A') {
+ path.push(child.textContent);
+ }
+ });
- document.body.appendChild(el);
- el.select();
- document.execCommand('copy');
- document.body.removeChild(el);
+ var el = document.createElement('textarea');
+ el.value = 'use ' + path.join('::') + ';';
+ el.setAttribute('readonly', '');
+ // To not make it appear on the screen.
+ el.style.position = 'absolute';
+ el.style.left = '-9999px';
- but.textContent = '✓';
-}
+ document.body.appendChild(el);
+ el.select();
+ document.execCommand('copy');
+ document.body.removeChild(el);
+
+ but.textContent = '✓';
+
+ if (reset_button_timeout !== null) {
+ window.clearTimeout(reset_button_timeout);
+ }
+
+ function reset_button() {
+ but.textContent = '⎘';
+ reset_button_timeout = null;
+ }
+
+ reset_button_timeout = window.setTimeout(reset_button, 1000);
+ };
+}());
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) {
+h4:not(.method):not(.type):not(.tymethod):not(.associatedconstant):not(.associatedtype) {
font-weight: 500;
margin: 20px 0 15px 0;
padding-bottom: 6px;
text-decoration: underline;
}
h2, h3:not(.impl):not(.method):not(.type):not(.tymethod),
-h4:not(.method):not(.type):not(.tymethod):not(.associatedconstant) {
+h4:not(.method):not(.type):not(.tymethod):not(.associatedconstant):not(.associatedtype) {
border-bottom: 1px solid;
}
-h3.impl, h3.method, h4.method, h3.type, h4.type, h4.associatedconstant {
+h3.impl, h3.method, h4.method, h3.type, h4.type, h4.associatedconstant, h4.associatedtype {
flex-basis: 100%;
font-weight: 600;
margin-top: 16px;
position: relative;
}
h3.impl, h3.method, h4.method.trait-impl, h3.type,
-h4.type.trait-impl, h4.associatedconstant.trait-impl {
+h4.type.trait-impl, h4.associatedconstant.trait-impl, h4.associatedtype.trait-impl {
padding-left: 15px;
}
.sidebar, a.source, .search-input, .content table td:first-child > a,
.collapse-toggle, div.item-list .out-of-band,
#source-sidebar, #sidebar-toggle,
+details.rustdoc-toggle > summary::before,
+details.undocumented > summary::before,
+.content ul.crate a.crate,
/* This selector is for the items listed in the "all items" page. */
#main > ul.docblock > li > a {
font-family: "Fira Sans", Arial, sans-serif;
.content ul.crate a.crate {
font-size: 16px/1.6;
- font-family: "Fira Sans", Arial, sans-serif;
}
ol, ul {
left: -19px;
}
-.content .impl-items .method, .content .impl-items > .type, .impl-items > .associatedconstant {
+.content .impl-items .method, .content .impl-items > .type, .impl-items > .associatedconstant,
+.impl-items > .associatedtype, .content .impl-items details > summary > .type,
+.impl-items details > summary > .associatedconstant,
+.impl-items details > summary > .associatedtype {
margin-left: 20px;
}
}
.in-band:hover > .anchor, .impl:hover > .anchor, .method.trait-impl:hover > .anchor,
-.type.trait-impl:hover > .anchor, .associatedconstant.trait-impl:hover > .anchor {
+.type.trait-impl:hover > .anchor, .associatedconstant.trait-impl:hover > .anchor,
+.associatedtype.trait-impl:hover > .anchor {
display: inline-block;
position: absolute;
}
margin-left: 0;
}
- .content .impl-items .method, .content .impl-items > .type, .impl-items > .associatedconstant {
+ .content .impl-items .method, .content .impl-items > .type, .impl-items > .associatedconstant,
+ .impl-items > .associatedtype {
display: flex;
}
cursor: pointer;
}
-details.rustdoc-toggle > summary::-webkit-details-marker {
+details.rustdoc-toggle > summary::-webkit-details-marker,
+details.rustdoc-toggle > summary::marker,
+details.undocumented > summary::-webkit-details-marker,
+details.undocumented > summary::marker {
display: none;
}
details.rustdoc-toggle > summary:not(.hideme)::before {
position: absolute;
left: -23px;
+ top: initial;
+}
+
+.impl-items > details.rustdoc-toggle > summary:not(.hideme)::before,
+.undocumented > details.rustdoc-toggle > summary:not(.hideme)::before {
+ position: absolute;
+ top: 3px;
+ left: -2px;
}
/* When a "hideme" summary is open and the "Expand description" or "Show
position: absolute;
}
-details.rustdoc-toggle[open] {
+details.rustdoc-toggle, details.undocumented {
position: relative;
}
content: "[−]";
display: inline;
}
+
+details.undocumented > summary::before {
+ content: "[+] Show hidden undocumented items";
+ cursor: pointer;
+ font-size: 16px;
+ font-weight: 300;
+}
+
+details.undocumented[open] > summary::before {
+ content: "[-] Hide undocumented items";
+}
.collapse-toggle,
details.rustdoc-toggle > summary.hideme > span,
-details.rustdoc-toggle > summary::before {
+details.rustdoc-toggle > summary::before,
+details.undocumented > summary::before {
color: #999;
}
.collapse-toggle,
details.rustdoc-toggle > summary.hideme > span,
-details.rustdoc-toggle > summary::before {
+details.rustdoc-toggle > summary::before,
+details.undocumented > summary::before {
color: #999;
}
.collapse-toggle,
details.rustdoc-toggle > summary.hideme > span,
-details.rustdoc-toggle > summary::before {
+details.rustdoc-toggle > summary::before,
+details.undocumented > summary::before {
color: #999;
}
use rustc_ast::ast;
use rustc_hir::def::CtorKind;
use rustc_middle::ty::TyCtxt;
-use rustc_span::def_id::{DefId, CRATE_DEF_INDEX};
+use rustc_span::def_id::CRATE_DEF_INDEX;
use rustc_span::Pos;
use rustdoc_json_types::*;
use crate::clean;
use crate::clean::utils::print_const_expr;
+use crate::clean::FakeDefId;
use crate::formats::item_type::ItemType;
use crate::json::JsonRenderer;
use std::collections::HashSet;
};
Some(Item {
id: from_def_id(def_id),
- crate_id: def_id.krate.as_u32(),
+ crate_id: def_id.krate().as_u32(),
name: name.map(|sym| sym.to_string()),
span: self.convert_span(span),
visibility: self.convert_visibility(visibility),
Inherited => Visibility::Default,
Restricted(did) if did.index == CRATE_DEF_INDEX => Visibility::Crate,
Restricted(did) => Visibility::Restricted {
- parent: from_def_id(did),
+ parent: from_def_id(did.into()),
path: self.tcx.def_path(did).to_string_no_crate_verbose(),
},
}
}
}
-crate fn from_def_id(did: DefId) -> Id {
- Id(format!("{}:{}", did.krate.as_u32(), u32::from(did.index)))
+crate fn from_def_id(did: FakeDefId) -> Id {
+ match did {
+ FakeDefId::Real(did) => Id(format!("{}:{}", did.krate.as_u32(), u32::from(did.index))),
+ // We need to differentiate real and fake ids, because the indices might overlap for fake
+ // and real DefId's, which would cause two different Id's treated as they were the same.
+ FakeDefId::Fake(idx, krate) => Id(format!("F{}:{}", krate.as_u32(), u32::from(idx))),
+ }
}
fn from_clean_item(item: clean::Item, tcx: TyCtxt<'_>) -> ItemEnum {
match ty {
ResolvedPath { path, param_names, did, is_generic: _ } => Type::ResolvedPath {
name: path.whole_name(),
- id: from_def_id(did),
+ id: from_def_id(did.into()),
args: path.segments.last().map(|args| Box::new(args.clone().args.into_tcx(tcx))),
param_names: param_names
.map(|v| v.into_iter().map(|x| x.into_tcx(tcx)).collect())
impl FromWithTcx<clean::Impl> for Impl {
fn from_tcx(impl_: clean::Impl, tcx: TyCtxt<'_>) -> Self {
+ let provided_trait_methods = impl_.provided_trait_methods(tcx);
let clean::Impl {
unsafety,
generics,
- provided_trait_methods,
trait_,
for_,
items,
Simple(s) => Import {
source: import.source.path.whole_name(),
name: s.to_string(),
- id: import.source.did.map(from_def_id),
+ id: import.source.did.map(FakeDefId::from).map(from_def_id),
glob: false,
},
Glob => Import {
source: import.source.path.whole_name(),
name: import.source.path.last_name().to_string(),
- id: import.source.did.map(from_def_id),
+ id: import.source.did.map(FakeDefId::from).map(from_def_id),
glob: true,
},
}
use rustdoc_json_types as types;
use crate::clean;
+use crate::clean::{ExternalCrate, FakeDefId};
use crate::config::RenderOptions;
use crate::error::Error;
use crate::formats::cache::Cache;
self.tcx.sess
}
- fn get_trait_implementors(&mut self, id: rustc_span::def_id::DefId) -> Vec<types::Id> {
+ fn get_trait_implementors(&mut self, id: FakeDefId) -> Vec<types::Id> {
Rc::clone(&self.cache)
.implementors
.get(&id)
.unwrap_or_default()
}
- fn get_impls(&mut self, id: rustc_span::def_id::DefId) -> Vec<types::Id> {
+ fn get_impls(&mut self, id: FakeDefId) -> Vec<types::Id> {
Rc::clone(&self.cache)
.impls
- .get(&id)
+ .get(&id.expect_real())
.map(|impls| {
impls
.iter()
let trait_item = &trait_item.trait_;
trait_item.items.clone().into_iter().for_each(|i| self.item(i).unwrap());
Some((
- from_def_id(id),
+ from_def_id(id.into()),
types::Item {
- id: from_def_id(id),
+ id: from_def_id(id.into()),
crate_id: id.krate.as_u32(),
name: self
.cache
.chain(self.cache.external_paths.clone().into_iter())
.map(|(k, (path, kind))| {
(
- from_def_id(k),
+ from_def_id(k.into()),
types::ItemSummary {
crate_id: k.krate.as_u32(),
path,
.cache
.extern_locations
.iter()
- .map(|(k, v)| {
+ .map(|(crate_num, external_location)| {
+ let e = ExternalCrate { crate_num: *crate_num };
(
- k.as_u32(),
+ crate_num.as_u32(),
types::ExternalCrate {
- name: v.0.to_string(),
- html_root_url: match &v.2 {
+ name: e.name(self.tcx).to_string(),
+ html_root_url: match external_location {
ExternalLocation::Remote(s) => Some(s.clone()),
_ => None,
},
"[unversioned-shared-resources,toolchain-shared-resources,invocation-specific]",
)
}),
+ unstable("no-run", |o| o.optflag("", "no-run", "Compile doctests without running them")),
]
}
fn fold_item(&mut self, item: clean::Item) -> Option<clean::Item> {
if let Some(dox) = &item.attrs.collapsed_doc_value() {
let sp = item.attr_span(self.cx.tcx);
- let extra = crate::html::markdown::ExtraInfo::new_did(self.cx.tcx, item.def_id, sp);
+ let extra = crate::html::markdown::ExtraInfo::new_did(
+ self.cx.tcx,
+ item.def_id.expect_real(),
+ sp,
+ );
for code_block in markdown::rust_code_blocks(&dox, &extra) {
self.check_rust_syntax(&item, &dox, code_block);
}
use std::mem;
use std::ops::Range;
-use crate::clean::{self, utils::find_nearest_parent_module, Crate, Item, ItemLink, PrimitiveType};
+use crate::clean::{
+ self, utils::find_nearest_parent_module, Crate, FakeDefId, Item, ItemLink, PrimitiveType,
+};
use crate::core::DocContext;
use crate::fold::DocFolder;
use crate::html::markdown::{markdown_links, MarkdownLink};
#[derive(Clone, Debug, Hash, PartialEq, Eq)]
struct ResolutionInfo {
- module_id: DefId,
+ module_id: FakeDefId,
dis: Option<Disambiguator>,
path_str: String,
extra_fragment: Option<String>,
///
/// The last module will be used if the parent scope of the current item is
/// unknown.
- mod_ids: Vec<DefId>,
+ mod_ids: Vec<FakeDefId>,
/// This is used to store the kind of associated items,
/// because `clean` and the disambiguator code expect them to be different.
/// See the code for associated items on inherent impls for details.
) -> Result<(Res, Option<String>), ErrorKind<'path>> {
let tcx = self.cx.tcx;
let no_res = || ResolutionFailure::NotResolved {
- module_id,
+ module_id: module_id.into(),
partial_res: None,
unresolved: path_str.into(),
};
// but the disambiguator logic expects the associated item.
// Store the kind in a side channel so that only the disambiguator logic looks at it.
if let Some((kind, id)) = side_channel {
- self.kind_side_channel.set(Some((kind, id)));
+ self.kind_side_channel.set(Some((kind, id.into())));
}
Ok((res, Some(fragment)))
};
let parent_node = if item.is_fake() {
None
} else {
- find_nearest_parent_module(self.cx.tcx, item.def_id)
+ find_nearest_parent_module(self.cx.tcx, item.def_id.expect_real())
};
if parent_node.is_some() {
let self_id = if item.is_fake() {
None
// Checking if the item is a field in an enum variant
- } else if (matches!(self.cx.tcx.def_kind(item.def_id), DefKind::Field)
+ } else if (matches!(self.cx.tcx.def_kind(item.def_id.expect_real()), DefKind::Field)
&& matches!(
- self.cx.tcx.def_kind(self.cx.tcx.parent(item.def_id).unwrap()),
+ self.cx.tcx.def_kind(self.cx.tcx.parent(item.def_id.expect_real()).unwrap()),
DefKind::Variant
))
{
- self.cx.tcx.parent(item.def_id).and_then(|item_id| self.cx.tcx.parent(item_id))
+ self.cx
+ .tcx
+ .parent(item.def_id.expect_real())
+ .and_then(|item_id| self.cx.tcx.parent(item_id))
} else if matches!(
- self.cx.tcx.def_kind(item.def_id),
+ self.cx.tcx.def_kind(item.def_id.expect_real()),
DefKind::AssocConst
| DefKind::AssocFn
| DefKind::AssocTy
| DefKind::Variant
| DefKind::Field
) {
- self.cx.tcx.parent(item.def_id)
+ self.cx.tcx.parent(item.def_id.expect_real())
// HACK(jynelson): `clean` marks associated types as `TypedefItem`, not as `AssocTypeItem`.
// Fixing this breaks `fn render_deref_methods`.
// As a workaround, see if the parent of the item is an `impl`; if so this must be an associated item,
// regardless of what rustdoc wants to call it.
- } else if let Some(parent) = self.cx.tcx.parent(item.def_id) {
+ } else if let Some(parent) = self.cx.tcx.parent(item.def_id.expect_real()) {
let parent_kind = self.cx.tcx.def_kind(parent);
- Some(if parent_kind == DefKind::Impl { parent } else { item.def_id })
+ Some(if parent_kind == DefKind::Impl { parent } else { item.def_id.expect_real() })
} else {
- Some(item.def_id)
+ Some(item.def_id.expect_real())
};
// FIXME(jynelson): this shouldn't go through stringification, rustdoc should just use the DefId directly
let (krate, parent_node) = if let Some(id) = parent_module {
(id.krate, Some(id))
} else {
- (item.def_id.krate, parent_node)
+ (item.def_id.krate(), parent_node)
};
// NOTE: if there are links that start in one crate and end in another, this will not resolve them.
// This is a degenerate case and it's not supported by rustdoc.
// we've already pushed this node onto the resolution stack but
// for outer comments we explicitly try and resolve against the
// parent_node first.
- let base_node =
- if item.is_mod() && inner_docs { self.mod_ids.last().copied() } else { parent_node };
+ let base_node = if item.is_mod() && inner_docs {
+ self.mod_ids.last().copied()
+ } else {
+ parent_node.map(|id| FakeDefId::new_real(id))
+ };
let mut module_id = if let Some(id) = base_node {
id
resolved_self = format!("self::{}", &path_str["crate::".len()..]);
path_str = &resolved_self;
}
- module_id = DefId { krate, index: CRATE_DEF_INDEX };
+ module_id = FakeDefId::new_real(DefId { krate, index: CRATE_DEF_INDEX });
}
let (mut res, mut fragment) = self.resolve_with_disambiguator_cached(
report_diagnostic(self.cx.tcx, BROKEN_INTRA_DOC_LINKS, &msg, &diag_info, callback);
};
- let verify = |kind: DefKind, id: DefId| {
- let (kind, id) = self.kind_side_channel.take().unwrap_or((kind, id));
+ let verify = |kind: DefKind, id: FakeDefId| {
+ let (kind, id) = self.kind_side_channel.take().unwrap_or((kind, id.expect_real()));
debug!("intra-doc link to {} resolved to {:?} (id: {:?})", path_str, res, id);
// Disallow e.g. linking to enums with `struct@`
// doesn't allow statements like `use str::trim;`, making this a (hopefully)
// valid omission. See https://github.com/rust-lang/rust/pull/80660#discussion_r551585677
// for discussion on the matter.
- verify(kind, id)?;
+ verify(kind, id.into())?;
// FIXME: it would be nice to check that the feature gate was enabled in the original crate, not just ignore it altogether.
// However I'm not sure how to check that across crates.
Some(ItemLink { link: ori_link.link, link_text, did: None, fragment })
}
Res::Def(kind, id) => {
- verify(kind, id)?;
+ verify(kind, id.into())?;
let id = clean::register_res(self.cx, rustc_hir::def::Res::Def(kind, id));
- Some(ItemLink { link: ori_link.link, link_text, did: Some(id), fragment })
+ Some(ItemLink { link: ori_link.link, link_text, did: Some(id.into()), fragment })
}
}
}
match disambiguator.map(Disambiguator::ns) {
Some(expected_ns @ (ValueNS | TypeNS)) => {
- match self.resolve(path_str, expected_ns, base_node, extra_fragment) {
+ match self.resolve(path_str, expected_ns, base_node.expect_real(), extra_fragment) {
Ok(res) => Some(res),
Err(ErrorKind::Resolve(box mut kind)) => {
// We only looked in one namespace. Try to give a better error if possible.
// 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] {
- if let Some(res) =
- self.check_full_res(new_ns, path_str, base_node, extra_fragment)
- {
+ if let Some(res) = self.check_full_res(
+ new_ns,
+ path_str,
+ base_node.expect_real(),
+ extra_fragment,
+ ) {
kind = ResolutionFailure::WrongNamespace { res, expected_ns };
break;
}
// Try everything!
let mut candidates = PerNS {
macro_ns: self
- .resolve_macro(path_str, base_node)
+ .resolve_macro(path_str, base_node.expect_real())
.map(|res| (res, extra_fragment.clone())),
- type_ns: match self.resolve(path_str, TypeNS, base_node, extra_fragment) {
+ type_ns: match self.resolve(
+ path_str,
+ TypeNS,
+ base_node.expect_real(),
+ extra_fragment,
+ ) {
Ok(res) => {
debug!("got res in TypeNS: {:?}", res);
Ok(res)
}
Err(ErrorKind::Resolve(box kind)) => Err(kind),
},
- value_ns: match self.resolve(path_str, ValueNS, base_node, extra_fragment) {
+ value_ns: match self.resolve(
+ path_str,
+ ValueNS,
+ base_node.expect_real(),
+ extra_fragment,
+ ) {
Ok(res) => Ok(res),
Err(ErrorKind::AnchorFailure(msg)) => {
anchor_failure(self.cx, diag, msg);
}
if len == 1 {
- Some(candidates.into_iter().filter_map(|res| res.ok()).next().unwrap())
+ Some(candidates.into_iter().find_map(|res| res.ok()).unwrap())
} else if len == 2 && is_derive_trait_collision(&candidates) {
Some(candidates.type_ns.unwrap())
} else {
}
}
Some(MacroNS) => {
- match self.resolve_macro(path_str, base_node) {
+ match self.resolve_macro(path_str, base_node.expect_real()) {
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] {
- if let Some(res) =
- self.check_full_res(ns, path_str, base_node, extra_fragment)
- {
+ if let Some(res) = self.check_full_res(
+ ns,
+ path_str,
+ base_node.expect_real(),
+ extra_fragment,
+ ) {
kind =
ResolutionFailure::WrongNamespace { res, expected_ns: MacroNS };
break;
name = start;
for &ns in &[TypeNS, ValueNS, MacroNS] {
if let Some(res) =
- collector.check_full_res(ns, &start, module_id, &None)
+ collector.check_full_res(ns, &start, module_id.into(), &None)
{
debug!("found partial_res={:?}", res);
*partial_res = Some(res);
// FIXME(eddyb) is this `doc(hidden)` check needed?
if !cx.tcx.get_attrs(def_id).lists(sym::doc).has_word(sym::hidden) {
- let impls = get_auto_trait_and_blanket_impls(cx, def_id);
+ let impls = get_auto_trait_and_blanket_impls(cx, def_id.into());
new_items.extend(impls.filter(|i| cx.inlined.insert(i.def_id)));
}
});
// Avoid infinite cycles
return;
}
- cleaner.items.insert(target_did);
- add_deref_target(map, cleaner, &target_did);
+ cleaner.items.insert(target_did.into());
+ add_deref_target(map, cleaner, &target_did.into());
}
}
}
// 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(type_did) {
+ if cleaner.keep_impl_with_def_id(&FakeDefId::new_real(*type_did)) {
add_deref_target(&type_did_to_deref_target, &mut cleaner, type_did);
}
}
fn fold_item(&mut self, i: Item) -> Option<Item> {
if i.is_struct() || i.is_enum() || i.is_union() {
// FIXME(eddyb) is this `doc(hidden)` check needed?
- if !self.cx.tcx.get_attrs(i.def_id).lists(sym::doc).has_word(sym::hidden) {
- self.impls.extend(get_auto_trait_and_blanket_impls(self.cx, i.def_id));
+ if !self.cx.tcx.get_attrs(i.def_id.expect_real()).lists(sym::doc).has_word(sym::hidden)
+ {
+ self.impls
+ .extend(get_auto_trait_and_blanket_impls(self.cx, i.def_id.expect_real()));
}
}
#[derive(Default)]
struct ItemCollector {
- items: FxHashSet<DefId>,
+ items: FxHashSet<FakeDefId>,
}
impl ItemCollector {
struct BadImplStripper {
prims: FxHashSet<PrimitiveType>,
- items: FxHashSet<DefId>,
+ items: FxHashSet<FakeDefId>,
}
impl BadImplStripper {
} else if let Some(prim) = ty.primitive_type() {
self.prims.contains(&prim)
} else if let Some(did) = ty.def_id() {
- self.keep_impl_with_def_id(&did)
+ self.keep_impl_with_def_id(&did.into())
} else {
false
}
}
- fn keep_impl_with_def_id(&self, did: &DefId) -> bool {
+ fn keep_impl_with_def_id(&self, did: &FakeDefId) -> bool {
self.items.contains(did)
}
}
}
crate fn should_have_doc_example(cx: &DocContext<'_>, item: &clean::Item) -> bool {
- if !cx.cache.access_levels.is_public(item.def_id)
+ if !cx.cache.access_levels.is_public(item.def_id.expect_real())
|| matches!(
*item.kind,
clean::StructFieldItem(_)
|lint| lint.build("missing code example in this documentation").emit(),
);
}
- } else if tests.found_tests > 0 && !cx.cache.access_levels.is_public(item.def_id) {
+ } else if tests.found_tests > 0 && !cx.cache.access_levels.is_public(item.def_id.expect_real())
+ {
cx.tcx.struct_span_lint_hir(
crate::lint::PRIVATE_DOC_TESTS,
hir_id,
-use rustc_hir::def_id::DefIdSet;
use rustc_span::symbol::sym;
use std::mem;
use crate::clean;
-use crate::clean::{Item, NestedAttributesExt};
+use crate::clean::{FakeDefIdSet, Item, NestedAttributesExt};
use crate::core::DocContext;
use crate::fold::{DocFolder, StripItem};
use crate::passes::{ImplStripper, Pass};
/// Strip items marked `#[doc(hidden)]`
crate fn strip_hidden(krate: clean::Crate, _: &mut DocContext<'_>) -> clean::Crate {
- let mut retained = DefIdSet::default();
+ let mut retained = FakeDefIdSet::default();
// strip all #[doc(hidden)] items
let krate = {
}
struct Stripper<'a> {
- retained: &'a mut DefIdSet,
+ retained: &'a mut FakeDefIdSet,
update_retained: bool,
}
-use rustc_hir::def_id::DefIdSet;
-
-use crate::clean;
+use crate::clean::{self, FakeDefIdSet};
use crate::core::DocContext;
use crate::fold::DocFolder;
use crate::passes::{ImplStripper, ImportStripper, Pass, Stripper};
/// crate, specified by the `xcrate` flag.
crate fn strip_private(mut krate: clean::Crate, cx: &mut DocContext<'_>) -> clean::Crate {
// This stripper collects all *retained* nodes.
- let mut retained = DefIdSet::default();
+ let mut retained = FakeDefIdSet::default();
// strip all private items
{
-use rustc_hir::def_id::{DefId, DefIdSet};
+use rustc_hir::def_id::DefId;
use rustc_middle::middle::privacy::AccessLevels;
use std::mem;
-use crate::clean::{self, GetDefId, Item};
+use crate::clean::{self, FakeDefIdSet, GetDefId, Item};
use crate::fold::{DocFolder, StripItem};
crate struct Stripper<'a> {
- crate retained: &'a mut DefIdSet,
+ crate retained: &'a mut FakeDefIdSet,
crate access_levels: &'a AccessLevels<DefId>,
crate update_retained: bool,
}
| clean::TraitAliasItem(..)
| clean::ForeignTypeItem => {
if i.def_id.is_local() {
- if !self.access_levels.is_exported(i.def_id) {
+ if !self.access_levels.is_exported(i.def_id.expect_real()) {
debug!("Stripper: stripping {:?} {:?}", i.type_(), i.name);
return None;
}
/// This stripper discards all impls which reference stripped items
crate struct ImplStripper<'a> {
- crate retained: &'a DefIdSet,
+ crate retained: &'a FakeDefIdSet,
}
impl<'a> DocFolder for ImplStripper<'a> {
return None;
}
if let Some(did) = imp.for_.def_id() {
- if did.is_local() && !imp.for_.is_generic() && !self.retained.contains(&did) {
+ if did.is_local() && !imp.for_.is_generic() && !self.retained.contains(&did.into())
+ {
debug!("ImplStripper: impl item for stripped type; removing");
return None;
}
}
if let Some(did) = imp.trait_.def_id() {
- if did.is_local() && !self.retained.contains(&did) {
+ if did.is_local() && !self.retained.contains(&did.into()) {
debug!("ImplStripper: impl item for stripped trait; removing");
return None;
}
if let Some(generics) = imp.trait_.as_ref().and_then(|t| t.generics()) {
for typaram in generics {
if let Some(did) = typaram.def_id() {
- if did.is_local() && !self.retained.contains(&did) {
+ if did.is_local() && !self.retained.contains(&did.into()) {
debug!(
"ImplStripper: stripped item in trait's generics; removing impl"
);
// This PartialEq implementation IS NOT COMMUTATIVE!!!
//
// The order is very important: the second object must have all first's rules.
-// However, the first doesn't require to have all second's rules.
+// However, the first is not required to have all of the second's rules.
impl PartialEq for CssPath {
fn eq(&self, other: &CssPath) -> bool {
if self.name != other.name {
use rustc_hir::Node;
use rustc_middle::middle::privacy::AccessLevel;
use rustc_middle::ty::TyCtxt;
+use rustc_span;
use rustc_span::source_map::Spanned;
use rustc_span::symbol::{kw, sym, Symbol};
-use rustc_span::{self, Span};
use std::mem;
crate fn visit(mut self, krate: &'tcx hir::Crate<'_>) -> Module<'tcx> {
let span = krate.item.inner;
let mut top_level_module = self.visit_mod_contents(
- span,
&Spanned { span, node: hir::VisibilityKind::Public },
hir::CRATE_HIR_ID,
&krate.item,
fn visit_mod_contents(
&mut self,
- span: Span,
vis: &hir::Visibility<'_>,
id: hir::HirId,
m: &'tcx hir::Mod<'tcx>,
name: Symbol,
) -> Module<'tcx> {
- let mut om = Module::new(name);
- om.where_outer = span;
- om.where_inner = m.inner;
- om.id = id;
+ let mut om = Module::new(name, id, m.inner);
// Keep track of if there were any private modules in the path.
let orig_inside_public_path = self.inside_public_path;
self.inside_public_path &= vis.node.is_pub();
} else {
// All items need to be handled here in case someone wishes to link
// to them with intra-doc links
- self.cx.cache.access_levels.map.insert(did, AccessLevel::Public);
+ self.cx.cache.access_levels.map.insert(did.into(), AccessLevel::Public);
}
}
}
None => return false,
};
- let is_private = !self.cx.cache.access_levels.is_public(res_did);
+ let is_private = !self.cx.cache.access_levels.is_public(res_did.into());
let is_hidden = inherits_doc_hidden(self.cx.tcx, res_hir_id);
// Only inline if requested or if the item would otherwise be stripped.
om.items.push((item, renamed))
}
hir::ItemKind::Mod(ref m) => {
- om.mods.push(self.visit_mod_contents(item.span, &item.vis, item.hir_id(), m, name));
+ om.mods.push(self.visit_mod_contents(&item.vis, item.hir_id(), m, name));
}
hir::ItemKind::Fn(..)
| hir::ItemKind::ExternCrate(..)
#[no_mangle]
pub unsafe fn pure(x: i32) {
let y: i32;
- asm!("", out("ax") y, in("bx") x, options(pure), options(nomem));
+ asm!("", out("ax") y, in("cx") x, options(pure), options(nomem));
}
pub static mut VAR: i32 = 0;
#[no_mangle]
pub unsafe fn pure(x: i32) {
let y: i32;
- asm!("", out("ax") y, in("bx") x, options(pure, nomem));
+ asm!("", out("ax") y, in("cx") x, options(pure, nomem));
}
// CHECK-LABEL: @noreturn
// Verify debuginfo for generators:
// - Each variant points to the file and line of its yield point
-// - The generator types and variants are marked artificial
-// - Captured vars from the source are not marked artificial
+// - The discriminants are marked artificial
+// - Other fields are not marked artificial
//
//
// compile-flags: -C debuginfo=2 --edition=2018
// 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]], {{.*}}flags: DIFlagArtificial
+// CHECK-DAG: [[GEN:!.*]] = !DICompositeType(tag: DW_TAG_union_type, name: "generator-0", scope: [[ASYNC_FN]]
// CHECK: {{!.*}} = !DIDerivedType(tag: DW_TAG_member, 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-SAME: flags: DIFlagArtificial
+// CHECK-NOT: flags: DIFlagArtificial
+// CHECK-SAME: )
// CHECK: {{!.*}} = !DIDerivedType(tag: DW_TAG_member, scope: [[GEN]],
// CHECK-SAME: file: [[FILE]], line: 15,
-// CHECK-SAME: flags: DIFlagArtificial
+// CHECK-NOT: flags: DIFlagArtificial
+// CHECK-SAME: )
// CHECK: {{!.*}} = !DIDerivedType(tag: DW_TAG_member, scope: [[GEN]],
// CHECK-SAME: file: [[FILE]], line: 15,
-// CHECK-SAME: flags: DIFlagArtificial
+// CHECK-NOT: flags: DIFlagArtificial
+// CHECK-SAME: )
// CHECK: {{!.*}} = !DIDerivedType(tag: DW_TAG_member, scope: [[GEN]],
// CHECK-SAME: file: [[FILE]], line: 12,
-// CHECK-SAME: flags: DIFlagArtificial
+// CHECK-NOT: flags: DIFlagArtificial
+// CHECK-SAME: )
// CHECK: {{!.*}} = !DIDerivedType(tag: DW_TAG_member, scope: [[GEN]],
// CHECK-SAME: file: [[FILE]], line: 14,
// CHECK-SAME: baseType: [[VARIANT:![0-9]*]]
-// CHECK-SAME: flags: DIFlagArtificial
+// CHECK-NOT: flags: DIFlagArtificial
+// CHECK-SAME: )
// CHECK: [[S1:!.*]] = !DICompositeType(tag: DW_TAG_structure_type, name: "Suspend1", scope: [[ASYNC_FN]],
-// CHECK-SAME: flags: DIFlagArtificial
+// CHECK-NOT: flags: DIFlagArtificial
+// CHECK-SAME: )
// CHECK: {{!.*}} = !DIDerivedType(tag: DW_TAG_member, name: "RUST$ENUM$DISR", scope: [[S1]],
// CHECK-SAME: flags: DIFlagArtificial
// CHECK: {{!.*}} = !DIDerivedType(tag: DW_TAG_member, name: "s", scope: [[S1]]
// Verify debuginfo for async fn:
// - Each variant points to the file and line of its yield point
-// - The generator types and variants are marked artificial
-// - Captured vars from the source are not marked artificial
+// - The discriminants are marked artificial
+// - Other fields are not marked artificial
//
//
// compile-flags: -C debuginfo=2 --edition=2018
// FIXME: No way to reliably check the filename.
// CHECK-DAG: [[ASYNC_FN:!.*]] = !DINamespace(name: "async_fn_test"
-// CHECK-DAG: [[GEN:!.*]] = !DICompositeType(tag: DW_TAG_structure_type, name: "generator-0", scope: [[ASYNC_FN]], {{.*}}flags: DIFlagArtificial
+// CHECK-DAG: [[GEN:!.*]] = !DICompositeType(tag: DW_TAG_structure_type, name: "generator-0", scope: [[ASYNC_FN]]
// CHECK: [[VARIANT:!.*]] = !DICompositeType(tag: DW_TAG_variant_part, scope: [[ASYNC_FN]],
-// CHECK-SAME: flags: DIFlagArtificial
+// CHECK-NOT: flags: DIFlagArtificial
// CHECK-SAME: discriminator: [[DISC:![0-9]*]]
// CHECK: {{!.*}} = !DIDerivedType(tag: DW_TAG_member, name: "0", scope: [[VARIANT]],
// CHECK-SAME: file: [[FILE:![0-9]*]], line: 11,
-// CHECK-SAME: flags: DIFlagArtificial
+// CHECK-NOT: flags: DIFlagArtificial
+// CHECK-SAME: )
// CHECK: {{!.*}} = !DICompositeType(tag: DW_TAG_structure_type, name: "Unresumed", scope: [[GEN]],
-// CHECK-SAME: flags: DIFlagArtificial
+// CHECK-NOT: flags: DIFlagArtificial
+// CHECK-SAME: )
// CHECK: {{!.*}} = !DIDerivedType(tag: DW_TAG_member, name: "1", scope: [[VARIANT]],
// CHECK-SAME: file: [[FILE]], line: 15,
-// CHECK-SAME: flags: DIFlagArtificial
+// CHECK-NOT: flags: DIFlagArtificial
+// CHECK-SAME: )
// CHECK: {{!.*}} = !DIDerivedType(tag: DW_TAG_member, name: "2", scope: [[VARIANT]],
// CHECK-SAME: file: [[FILE]], line: 15,
-// CHECK-SAME: flags: DIFlagArtificial
+// CHECK-NOT: flags: DIFlagArtificial
+// CHECK-SAME: )
// CHECK: {{!.*}} = !DIDerivedType(tag: DW_TAG_member, name: "3", scope: [[VARIANT]],
// CHECK-SAME: file: [[FILE]], line: 12,
-// CHECK-SAME: flags: DIFlagArtificial
+// CHECK-NOT: flags: DIFlagArtificial
+// CHECK-SAME: )
// CHECK: {{!.*}} = !DIDerivedType(tag: DW_TAG_member, name: "4", scope: [[VARIANT]],
// CHECK-SAME: file: [[FILE]], line: 14,
-// CHECK-SAME: flags: DIFlagArtificial
+// CHECK-NOT: flags: DIFlagArtificial
+// CHECK-SAME: )
// CHECK: [[S1:!.*]] = !DICompositeType(tag: DW_TAG_structure_type, name: "Suspend1", scope: [[GEN]],
-// CHECK-SAME: flags: DIFlagArtificial
+// CHECK-NOT: flags: DIFlagArtificial
+// CHECK-SAME: )
// CHECK: {{!.*}} = !DIDerivedType(tag: DW_TAG_member, name: "s", scope: [[S1]]
// CHECK-NOT: flags: DIFlagArtificial
// CHECK-SAME: )
// Verify debuginfo for generators:
// - Each variant points to the file and line of its yield point
-// - The generator types and variants are marked artificial
-// - Captured vars from the source are not marked artificial
+// - The discriminants are marked artificial
+// - Other fields are not marked artificial
//
//
// compile-flags: -C debuginfo=2
// 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]], {{.*}}flags: DIFlagArtificial
+// CHECK-DAG: [[GEN:!.*]] = !DICompositeType(tag: DW_TAG_union_type, name: "generator-0", scope: [[GEN_FN]]
// CHECK: {{!.*}} = !DIDerivedType(tag: DW_TAG_member, 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-SAME: flags: DIFlagArtificial
+// CHECK-NOT: flags: DIFlagArtificial
+// CHECK-SAME: )
// CHECK: {{!.*}} = !DIDerivedType(tag: DW_TAG_member, scope: [[GEN]],
// CHECK-SAME: file: [[FILE]], line: 18,
-// CHECK-SAME: flags: DIFlagArtificial
+// CHECK-NOT: flags: DIFlagArtificial
+// CHECK-SAME: )
// CHECK: {{!.*}} = !DIDerivedType(tag: DW_TAG_member, scope: [[GEN]],
// CHECK-SAME: file: [[FILE]], line: 18,
-// CHECK-SAME: flags: DIFlagArtificial
+// CHECK-NOT: flags: DIFlagArtificial
+// CHECK-SAME: )
// CHECK: {{!.*}} = !DIDerivedType(tag: DW_TAG_member, scope: [[GEN]],
// CHECK-SAME: file: [[FILE]], line: 15,
-// CHECK-SAME: flags: DIFlagArtificial
+// CHECK-NOT: flags: DIFlagArtificial
+// CHECK-SAME: )
// CHECK: {{!.*}} = !DIDerivedType(tag: DW_TAG_member, scope: [[GEN]],
// CHECK-SAME: file: [[FILE]], line: 17,
// CHECK-SAME: baseType: [[VARIANT:![0-9]*]]
-// CHECK-SAME: flags: DIFlagArtificial
+// CHECK-NOT: flags: DIFlagArtificial
+// CHECK-SAME: )
// CHECK: [[S1:!.*]] = !DICompositeType(tag: DW_TAG_structure_type, name: "Suspend1", scope: [[GEN_FN]],
-// CHECK-SAME: flags: DIFlagArtificial
+// CHECK-NOT: flags: DIFlagArtificial
+// CHECK-SAME: )
// CHECK: {{!.*}} = !DIDerivedType(tag: DW_TAG_member, name: "RUST$ENUM$DISR", scope: [[S1]],
// CHECK-SAME: flags: DIFlagArtificial
// CHECK: {{!.*}} = !DIDerivedType(tag: DW_TAG_member, name: "s", scope: [[S1]]
// Verify debuginfo for generators:
// - Each variant points to the file and line of its yield point
-// - The generator types and variants are marked artificial
-// - Captured vars from the source are not marked artificial
+// - The discriminants are marked artificial
+// - Other fields are not marked artificial
//
//
// compile-flags: -C debuginfo=2 --edition=2018
// FIXME: No way to reliably check the filename.
// CHECK-DAG: [[GEN_FN:!.*]] = !DINamespace(name: "generator_test"
-// CHECK-DAG: [[GEN:!.*]] = !DICompositeType(tag: DW_TAG_structure_type, name: "generator-0", scope: [[GEN_FN]], {{.*}}flags: DIFlagArtificial
+// CHECK-DAG: [[GEN:!.*]] = !DICompositeType(tag: DW_TAG_structure_type, name: "generator-0", scope: [[GEN_FN]]
// CHECK: [[VARIANT:!.*]] = !DICompositeType(tag: DW_TAG_variant_part, scope: [[GEN_FN]],
-// CHECK-SAME: flags: DIFlagArtificial
+// CHECK-NOT: flags: DIFlagArtificial
// CHECK-SAME: discriminator: [[DISC:![0-9]*]]
// CHECK: {{!.*}} = !DIDerivedType(tag: DW_TAG_member, name: "0", scope: [[VARIANT]],
// CHECK-SAME: file: [[FILE:![0-9]*]], line: 14,
-// CHECK-SAME: flags: DIFlagArtificial
+// CHECK-NOT: flags: DIFlagArtificial
+// CHECK-SAME: )
// CHECK: {{!.*}} = !DICompositeType(tag: DW_TAG_structure_type, name: "Unresumed", scope: [[GEN]],
-// CHECK-SAME: flags: DIFlagArtificial
+// CHECK-NOT: flags: DIFlagArtificial
+// CHECK-SAME: )
// CHECK: {{!.*}} = !DIDerivedType(tag: DW_TAG_member, name: "1", scope: [[VARIANT]],
// CHECK-SAME: file: [[FILE]], line: 18,
-// CHECK-SAME: flags: DIFlagArtificial
+// CHECK-NOT: flags: DIFlagArtificial
+// CHECK-SAME: )
// CHECK: {{!.*}} = !DIDerivedType(tag: DW_TAG_member, name: "2", scope: [[VARIANT]],
// CHECK-SAME: file: [[FILE]], line: 18,
-// CHECK-SAME: flags: DIFlagArtificial
+// CHECK-NOT: flags: DIFlagArtificial
+// CHECK-SAME: )
// CHECK: {{!.*}} = !DIDerivedType(tag: DW_TAG_member, name: "3", scope: [[VARIANT]],
// CHECK-SAME: file: [[FILE]], line: 15,
-// CHECK-SAME: flags: DIFlagArtificial
+// CHECK-NOT: flags: DIFlagArtificial
+// CHECK-SAME: )
// CHECK: {{!.*}} = !DIDerivedType(tag: DW_TAG_member, name: "4", scope: [[VARIANT]],
// CHECK-SAME: file: [[FILE]], line: 17,
-// CHECK-SAME: flags: DIFlagArtificial
+// CHECK-NOT: flags: DIFlagArtificial
+// CHECK-SAME: )
// CHECK: [[S1:!.*]] = !DICompositeType(tag: DW_TAG_structure_type, name: "Suspend1", scope: [[GEN]],
-// CHECK-SAME: flags: DIFlagArtificial
+// CHECK-NOT: flags: DIFlagArtificial
+// CHECK-SAME: )
// CHECK: {{!.*}} = !DIDerivedType(tag: DW_TAG_member, name: "s", scope: [[S1]]
// CHECK-NOT: flags: DIFlagArtificial
// CHECK-SAME: )
// Require a gdb that can read DW_TAG_variant_part.
// min-gdb-version: 8.2
+// LLDB without native Rust support cannot read DW_TAG_variant_part,
+// so it prints nothing for generators. But those tests are kept to
+// ensure that LLDB won't crash at least (like #57822).
+
// compile-flags:-g
// === GDB TESTS ===================================================================================
// gdb-command:run
// gdb-command:print b
-// gdb-check:$1 = generator_objects::main::generator-0 {__0: 0x[...], <<variant>>: {__state: 0, 0: generator_objects::main::generator-0::Unresumed, 1: generator_objects::main::generator-0::Returned, 2: generator_objects::main::generator-0::Panicked, 3: generator_objects::main::generator-0::Suspend0 {[...]}, 4: generator_objects::main::generator-0::Suspend1 {[...]}}}
+// gdb-check:$1 = generator_objects::main::generator-0::Unresumed(0x[...])
// gdb-command:continue
// gdb-command:print b
-// gdb-check:$2 = generator_objects::main::generator-0 {__0: 0x[...], <<variant>>: {__state: 3, 0: generator_objects::main::generator-0::Unresumed, 1: generator_objects::main::generator-0::Returned, 2: generator_objects::main::generator-0::Panicked, 3: generator_objects::main::generator-0::Suspend0 {c: 6, d: 7}, 4: generator_objects::main::generator-0::Suspend1 {[...]}}}
+// gdb-check:$2 = generator_objects::main::generator-0::Suspend0{c: 6, d: 7, __0: 0x[...]}
// gdb-command:continue
// gdb-command:print b
-// gdb-check:$3 = generator_objects::main::generator-0 {__0: 0x[...], <<variant>>: {__state: 4, 0: generator_objects::main::generator-0::Unresumed, 1: generator_objects::main::generator-0::Returned, 2: generator_objects::main::generator-0::Panicked, 3: generator_objects::main::generator-0::Suspend0 {[...]}, 4: generator_objects::main::generator-0::Suspend1 {c: 7, d: 8}}}
+// gdb-check:$3 = generator_objects::main::generator-0::Suspend1{c: 7, d: 8, __0: 0x[...]}
// gdb-command:continue
// gdb-command:print b
-// gdb-check:$4 = generator_objects::main::generator-0 {__0: 0x[...], <<variant>>: {__state: 1, 0: generator_objects::main::generator-0::Unresumed, 1: generator_objects::main::generator-0::Returned, 2: generator_objects::main::generator-0::Panicked, 3: generator_objects::main::generator-0::Suspend0 {[...]}, 4: generator_objects::main::generator-0::Suspend1 {[...]}}}
+// gdb-check:$4 = generator_objects::main::generator-0::Returned(0x[...])
// === LLDB TESTS ==================================================================================
// lldb-command:run
// lldb-command:print b
-// lldbg-check:(generator_objects::main::generator-0) $0 = { 0 = 0x[...] }
+// lldbg-check:(generator_objects::main::generator-0) $0 =
// lldb-command:continue
// lldb-command:print b
-// lldbg-check:(generator_objects::main::generator-0) $1 = { 0 = 0x[...] }
+// lldbg-check:(generator_objects::main::generator-0) $1 =
// lldb-command:continue
// lldb-command:print b
-// lldbg-check:(generator_objects::main::generator-0) $2 = { 0 = 0x[...] }
+// lldbg-check:(generator_objects::main::generator-0) $2 =
// lldb-command:continue
// lldb-command:print b
-// lldbg-check:(generator_objects::main::generator-0) $3 = { 0 = 0x[...] }
+// lldbg-check:(generator_objects::main::generator-0) $3 =
#![feature(omit_gdb_pretty_printer_section, generators, generator_trait)]
#![omit_gdb_pretty_printer_section]
// gdb-check:$1 = issue_57822::main::closure-1 (issue_57822::main::closure-0 (1))
// gdb-command:print b
-// gdb-check:$2 = issue_57822::main::generator-3 {__0: issue_57822::main::generator-2 {__0: 2, <<variant>>: {[...]}}, <<variant>>: {[...]}}
+// gdb-check:$2 = issue_57822::main::generator-3::Unresumed(issue_57822::main::generator-2::Unresumed(2))
// === LLDB TESTS ==================================================================================
// lldbg-check:(issue_57822::main::closure-1) $0 = { 0 = { 0 = 1 } }
// lldb-command:print b
-// lldbg-check:(issue_57822::main::generator-3) $1 = { 0 = { 0 = 2 } }
+// lldbg-check:(issue_57822::main::generator-3) $1 =
#![feature(omit_gdb_pretty_printer_section, generators, generator_trait)]
#![omit_gdb_pretty_printer_section]
}
#[cfg(not(cfail1))]
-#[rustc_clean(cfg="cfail2", except="hir_owner,hir_owner_nodes,associated_item_def_ids")]
+#[rustc_clean(cfg="cfail2", except="hir_owner,associated_item_def_ids")]
#[rustc_clean(cfg="cfail3")]
impl Foo {
#[rustc_clean(cfg="cfail3")]
}
#[cfg(not(cfail1))]
-#[rustc_clean(cfg="cfail2", except="hir_owner,hir_owner_nodes")]
+#[rustc_clean(cfg="cfail2", except="hir_owner")]
#[rustc_clean(cfg="cfail3")]
impl Foo {
#[rustc_clean(cfg="cfail2", except="associated_item,hir_owner,hir_owner_nodes")]
}
#[cfg(not(cfail1))]
-#[rustc_clean(cfg="cfail2", except="hir_owner,hir_owner_nodes")]
+#[rustc_clean(cfg="cfail2", except="hir_owner")]
#[rustc_clean(cfg="cfail3")]
impl Foo {
#[rustc_dirty(cfg="cfail2", except="type_of,predicates_of,promoted_mir")]
}
#[cfg(not(cfail1))]
-#[rustc_clean(cfg="cfail2", except="hir_owner,hir_owner_nodes,associated_item_def_ids")]
+#[rustc_clean(cfg="cfail2", except="hir_owner,associated_item_def_ids")]
#[rustc_clean(cfg="cfail3")]
impl Foo {
#[rustc_clean(cfg="cfail2")]
}
#[cfg(not(cfail1))]
-#[rustc_clean(cfg="cfail2", except="hir_owner,hir_owner_nodes")]
+#[rustc_clean(cfg="cfail2", except="hir_owner")]
#[rustc_clean(cfg="cfail3")]
impl Bar<u64> {
#[rustc_clean(cfg="cfail2", except="fn_sig,optimized_mir,typeck")]
type ChangePrimitiveType = i32;
#[cfg(not(cfail1))]
-#[rustc_clean(cfg="cfail2", except="hir_owner,hir_owner_nodes")]
+#[rustc_clean(cfg="cfail2", except="hir_owner")]
#[rustc_clean(cfg="cfail3")]
type ChangePrimitiveType = i64;
type ChangeMutability = &'static i32;
#[cfg(not(cfail1))]
-#[rustc_clean(cfg="cfail2", except="hir_owner,hir_owner_nodes")]
+#[rustc_clean(cfg="cfail2", except="hir_owner")]
#[rustc_clean(cfg="cfail3")]
type ChangeMutability = &'static mut i32;
type ChangeTypeStruct = Struct1;
#[cfg(not(cfail1))]
-#[rustc_clean(cfg="cfail2", except="hir_owner,hir_owner_nodes")]
+#[rustc_clean(cfg="cfail2", except="hir_owner")]
#[rustc_clean(cfg="cfail3")]
type ChangeTypeStruct = Struct2;
type ChangeTypeTuple = (u32, u64);
#[cfg(not(cfail1))]
-#[rustc_clean(cfg="cfail2", except="hir_owner,hir_owner_nodes")]
+#[rustc_clean(cfg="cfail2", except="hir_owner")]
#[rustc_clean(cfg="cfail3")]
type ChangeTypeTuple = (u32, i64);
type ChangeTypeEnum = Enum1;
#[cfg(not(cfail1))]
-#[rustc_clean(cfg="cfail2", except="hir_owner,hir_owner_nodes")]
+#[rustc_clean(cfg="cfail2", except="hir_owner")]
#[rustc_clean(cfg="cfail3")]
type ChangeTypeEnum = Enum2;
type AddTupleField = (i32, i64);
#[cfg(not(cfail1))]
-#[rustc_clean(cfg="cfail2", except="hir_owner,hir_owner_nodes")]
+#[rustc_clean(cfg="cfail2", except="hir_owner")]
#[rustc_clean(cfg="cfail3")]
type AddTupleField = (i32, i64, i16);
type ChangeNestedTupleField = (i32, (i64, i16));
#[cfg(not(cfail1))]
-#[rustc_clean(cfg="cfail2", except="hir_owner,hir_owner_nodes")]
+#[rustc_clean(cfg="cfail2", except="hir_owner")]
#[rustc_clean(cfg="cfail3")]
type ChangeNestedTupleField = (i32, (i64, i8));
#[cfg(cfail1)]
pub fn baz() {} // order is different...
- // FIXME: Make "hir_owner" use `rustc_clean` here. Currently "hir_owner" includes a reference to
- // the parent node, which is the statement holding this item. Changing the position of
- // `bar` in `foo` will update that reference and make `hir_owner(bar)` dirty.
- #[rustc_dirty(label = "hir_owner", cfg = "cfail2")]
+ #[rustc_clean(label = "hir_owner", cfg = "cfail2")]
#[rustc_clean(label = "hir_owner_nodes", cfg = "cfail2")]
pub fn bar() {} // but that doesn't matter.
asm!("{0}", out(reg) a);
asm!("{0}", inout(reg) b);
asm!("{0} {1}", out(reg) _, inlateout(reg) b => _);
- asm!("", out("al") _, lateout("rbx") _);
+ asm!("", out("al") _, lateout("rcx") _);
asm!("inst1\ninst2");
asm!("inst1 {0}, 42\ninst2 {1}, 24", in(reg) a, out(reg) b);
asm!("inst2 {1}, 24\ninst1 {0}, 42", in(reg) a, out(reg) b);
asm!("{0}", out(reg) a);
asm!("{name}", name = inout(reg) b);
asm!("{} {}", out(reg) _, inlateout(reg) b => _);
- asm!("", out("al") _, lateout("rbx") _);
+ asm!("", out("al") _, lateout("rcx") _);
asm!("inst1", "inst2");
asm!("inst1 {}, 42", "inst2 {}, 24", in(reg) a, out(reg) b);
asm!("inst2 {1}, 24", "inst1 {0}, 42", in(reg) a, out(reg) b);
#[cfg(FALSE)]
fn syntax() {
let _ = #[attr] box 0;
- let _ = #[attr] [#![attr] ];
- let _ = #[attr] [#![attr] 0];
- let _ = #[attr] [#![attr] 0; 0];
- let _ = #[attr] [#![attr] 0, 0, 0];
+ let _ = #[attr] [];
+ let _ = #[attr] [0];
+ let _ = #[attr] [0; 0];
+ let _ = #[attr] [0, 0, 0];
let _ = #[attr] foo();
let _ = #[attr] x.foo();
- let _ = #[attr] (#![attr] );
- let _ = #[attr] (#![attr] #[attr] 0,);
- let _ = #[attr] (#![attr] #[attr] 0, 0);
+ let _ = #[attr] ();
+ let _ = #[attr] (#[attr] 0,);
+ let _ = #[attr] (#[attr] 0, 0);
let _ = #[attr] 0 + #[attr] 0;
let _ = #[attr] 0 / #[attr] 0;
let _ = #[attr] 0 & #[attr] 0;
#![attr]
};
let _ =
- #[attr] match true {
- #![attr]
- #[attr]
- _ => false,
+ #[attr] match true
+ {
+ #[attr]
+ _ => false,
};
let _ = #[attr] || #[attr] foo;
let _ = #[attr] move || #[attr] foo;
let _ = #[attr] foo![# ! [attr]];
let _ = #[attr] foo! { };
let _ = #[attr] foo! { # ! [attr] };
- let _ = #[attr] Foo{#![attr] bar: baz,};
- let _ = #[attr] Foo{#![attr] ..foo};
- let _ = #[attr] Foo{#![attr] bar: baz, ..foo};
- let _ = #[attr] (#![attr] 0);
+ let _ = #[attr] Foo{bar: baz,};
+ let _ = #[attr] Foo{..foo};
+ let _ = #[attr] Foo{bar: baz, ..foo};
+ let _ = #[attr] (0);
{
#[attr]
fn _4() {
#[rustc_dummy]
- match () {
- #![rustc_dummy]
- _ => (),
- }
+ match () { _ => (), }
- let _ =
- #[rustc_dummy] match () {
- #![rustc_dummy]
- () => (),
- };
+ let _ = #[rustc_dummy] match () { () => (), };
}
fn _5() {
fn _6() {
#[rustc_dummy]
- [#![rustc_dummy] 1, 2, 3];
+ [1, 2, 3];
- let _ = #[rustc_dummy] [#![rustc_dummy] 1, 2, 3];
+ let _ = #[rustc_dummy] [1, 2, 3];
#[rustc_dummy]
- [#![rustc_dummy] 1; 4];
+ [1; 4];
- let _ = #[rustc_dummy] [#![rustc_dummy] 1; 4];
+ let _ = #[rustc_dummy] [1; 4];
}
struct Foo {
fn _7() {
#[rustc_dummy]
- Foo{#![rustc_dummy] data: (),};
+ Foo{data: (),};
- let _ = #[rustc_dummy] Foo{#![rustc_dummy] data: (),};
+ let _ = #[rustc_dummy] Foo{data: (),};
}
fn _8() {
#[rustc_dummy]
- (#![rustc_dummy] );
+ ();
#[rustc_dummy]
- (#![rustc_dummy] 0);
+ (0);
#[rustc_dummy]
- (#![rustc_dummy] 0,);
+ (0,);
#[rustc_dummy]
- (#![rustc_dummy] 0, 1);
+ (0, 1);
}
fn _9() {
fn _11() {
let _ = #[rustc_dummy] box 0;
- let _: [(); 0] = #[rustc_dummy] [#![rustc_dummy] ];
- let _ = #[rustc_dummy] [#![rustc_dummy] 0, 0];
- let _ = #[rustc_dummy] [#![rustc_dummy] 0; 0];
+ let _: [(); 0] = #[rustc_dummy] [];
+ let _ = #[rustc_dummy] [0, 0];
+ let _ = #[rustc_dummy] [0; 0];
let _ = #[rustc_dummy] foo();
let _ = #[rustc_dummy] 1i32.clone();
- let _ = #[rustc_dummy] (#![rustc_dummy] );
- let _ = #[rustc_dummy] (#![rustc_dummy] 0);
- let _ = #[rustc_dummy] (#![rustc_dummy] 0,);
- let _ = #[rustc_dummy] (#![rustc_dummy] 0, 0);
+ let _ = #[rustc_dummy] ();
+ let _ = #[rustc_dummy] (0);
+ let _ = #[rustc_dummy] (0,);
+ let _ = #[rustc_dummy] (0, 0);
let _ = #[rustc_dummy] 0 + #[rustc_dummy] 0;
let _ = #[rustc_dummy] !0;
let _ = #[rustc_dummy] -0i32;
#[rustc_dummy] loop {
#![rustc_dummy]
};
- let _ =
- #[rustc_dummy] match false {
- #![rustc_dummy]
- _ => (),
- };
+ let _ = #[rustc_dummy] match false { _ => (), };
let _ = #[rustc_dummy] || #[rustc_dummy] ();
let _ = #[rustc_dummy] move || #[rustc_dummy] ();
let _ =
let _ = #[rustc_dummy] expr_mac!();
let _ = #[rustc_dummy] expr_mac![];
let _ = #[rustc_dummy] expr_mac! { };
- let _ = #[rustc_dummy] Foo{#![rustc_dummy] data: (),};
- let _ = #[rustc_dummy] Foo{#![rustc_dummy] ..s};
- let _ = #[rustc_dummy] Foo{#![rustc_dummy] data: (), ..s};
- let _ = #[rustc_dummy] (#![rustc_dummy] 0);
+ let _ = #[rustc_dummy] Foo{data: (),};
+ let _ = #[rustc_dummy] Foo{..s};
+ let _ = #[rustc_dummy] Foo{data: (), ..s};
+ let _ = #[rustc_dummy] (0);
}
fn _12() {
--- /dev/null
+ 1| |// compile-flags: --edition=2018
+ 2| |#![feature(no_coverage)]
+ 3| |
+ 4| |macro_rules! bail {
+ 5| | ($msg:literal $(,)?) => {
+ 6| | if $msg.len() > 0 {
+ 7| | println!("no msg");
+ 8| | } else {
+ 9| | println!($msg);
+ 10| | }
+ 11| | return Err(String::from($msg));
+ 12| | };
+ 13| |}
+ 14| |
+ 15| |macro_rules! on_error {
+ 16| | ($value:expr, $error_message:expr) => {
+ 17| 0| $value.or_else(|e| {
+ 18| 0| let message = format!($error_message, e);
+ 19| 0| if message.len() > 0 {
+ 20| 0| println!("{}", message);
+ 21| 0| Ok(String::from("ok"))
+ 22| | } else {
+ 23| 0| bail!("error");
+ 24| | }
+ 25| 0| })
+ 26| | };
+ 27| |}
+ 28| |
+ 29| 1|fn load_configuration_files() -> Result<String, String> {
+ 30| 1| Ok(String::from("config"))
+ 31| 1|}
+ 32| |
+ 33| 1|pub fn main() -> Result<(), String> {
+ 34| 1| println!("Starting service");
+ 35| 1| let config = on_error!(load_configuration_files(), "Error loading configs: {}")?;
+ ^0
+ 36| |
+ 37| 1| let startup_delay_duration = String::from("arg");
+ 38| 1| let _ = (config, startup_delay_duration);
+ 39| 1| Ok(())
+ 40| 1|}
+
--- /dev/null
+ 1| |// compile-flags: --edition=2018
+ 2| |#![feature(no_coverage)]
+ 3| |
+ 4| |macro_rules! bail {
+ 5| | ($msg:literal $(,)?) => {
+ 6| | if $msg.len() > 0 {
+ 7| | println!("no msg");
+ 8| | } else {
+ 9| | println!($msg);
+ 10| | }
+ 11| | return Err(String::from($msg));
+ 12| | };
+ 13| |}
+ 14| |
+ 15| |macro_rules! on_error {
+ 16| | ($value:expr, $error_message:expr) => {
+ 17| 0| $value.or_else(|e| {
+ 18| 0| let message = format!($error_message, e);
+ 19| 0| if message.len() > 0 {
+ 20| 0| println!("{}", message);
+ 21| 0| Ok(String::from("ok"))
+ 22| | } else {
+ 23| 0| bail!("error");
+ 24| | }
+ 25| 0| })
+ 26| | };
+ 27| |}
+ 28| |
+ 29| 1|fn load_configuration_files() -> Result<String, String> {
+ 30| 1| Ok(String::from("config"))
+ 31| 1|}
+ 32| |
+ 33| 1|pub async fn test() -> Result<(), String> {
+ 34| 1| println!("Starting service");
+ 35| 1| let config = on_error!(load_configuration_files(), "Error loading configs: {}")?;
+ ^0
+ 36| |
+ 37| 1| let startup_delay_duration = String::from("arg");
+ 38| 1| let _ = (config, startup_delay_duration);
+ 39| 1| Ok(())
+ 40| 1|}
+ 41| |
+ 42| |#[no_coverage]
+ 43| |fn main() {
+ 44| | executor::block_on(test());
+ 45| |}
+ 46| |
+ 47| |mod executor {
+ 48| | use core::{
+ 49| | future::Future,
+ 50| | pin::Pin,
+ 51| | task::{Context, Poll, RawWaker, RawWakerVTable, Waker},
+ 52| | };
+ 53| |
+ 54| | #[no_coverage]
+ 55| | pub fn block_on<F: Future>(mut future: F) -> F::Output {
+ 56| | let mut future = unsafe { Pin::new_unchecked(&mut future) };
+ 57| | use std::hint::unreachable_unchecked;
+ 58| | static VTABLE: RawWakerVTable = RawWakerVTable::new(
+ 59| |
+ 60| | #[no_coverage]
+ 61| | |_| unsafe { unreachable_unchecked() }, // clone
+ 62| |
+ 63| | #[no_coverage]
+ 64| | |_| unsafe { unreachable_unchecked() }, // wake
+ 65| |
+ 66| | #[no_coverage]
+ 67| | |_| unsafe { unreachable_unchecked() }, // wake_by_ref
+ 68| |
+ 69| | #[no_coverage]
+ 70| | |_| (),
+ 71| | );
+ 72| | let waker = unsafe { Waker::from_raw(RawWaker::new(core::ptr::null(), &VTABLE)) };
+ 73| | let mut context = Context::from_waker(&waker);
+ 74| |
+ 75| | loop {
+ 76| | if let Poll::Ready(val) = future.as_mut().poll(&mut context) {
+ 77| | break val;
+ 78| | }
+ 79| | }
+ 80| | }
+ 81| |}
+
1| |#![allow(unused_assignments, unused_variables, dead_code)]
2| |
3| 1|fn main() {
- 4| | // Initialize test constants in a way that cannot be determined at compile time, to ensure
- 5| | // rustc and LLVM cannot optimize out statements (or coverage counters) downstream from
- 6| | // dependent conditions.
+ 4| 1| // Initialize test constants in a way that cannot be determined at compile time, to ensure
+ 5| 1| // rustc and LLVM cannot optimize out statements (or coverage counters) downstream from
+ 6| 1| // dependent conditions.
7| 1| let is_true = std::env::args().len() == 1;
8| 1|
9| 1| let mut countdown = 0;
5| |
6| 1|fn main() {
7| 1| let bar = Foo(1);
- 8| 0| assert_eq!(bar, Foo(1));
+ 8| 1| assert_eq!(bar, Foo(1));
9| 1| let baz = Foo(0);
- 10| 0| assert_ne!(baz, Foo(1));
+ 10| 1| assert_ne!(baz, Foo(1));
11| 1| println!("{:?}", Foo(1));
12| 1| println!("{:?}", bar);
13| 1| println!("{:?}", baz);
--- /dev/null
+ 1| |// This demonstrated Issue #84561: function-like macros produce unintuitive coverage results.
+ 2| |
+ 3| |// expect-exit-status-101
+ 4| 21|#[derive(PartialEq, Eq)]
+ ------------------
+ | <issue_84561::Foo as core::cmp::PartialEq>::eq:
+ | 4| 21|#[derive(PartialEq, Eq)]
+ ------------------
+ | Unexecuted instantiation: <issue_84561::Foo as core::cmp::PartialEq>::ne
+ ------------------
+ 5| |struct Foo(u32);
+ 6| 1|fn test3() {
+ 7| 1| let is_true = std::env::args().len() == 1;
+ 8| 1| let bar = Foo(1);
+ 9| 1| assert_eq!(bar, Foo(1));
+ 10| 1| let baz = Foo(0);
+ 11| 1| assert_ne!(baz, Foo(1));
+ 12| 1| println!("{:?}", Foo(1));
+ 13| 1| println!("{:?}", bar);
+ 14| 1| println!("{:?}", baz);
+ 15| 1|
+ 16| 1| assert_eq!(Foo(1), Foo(1));
+ 17| 1| assert_ne!(Foo(0), Foo(1));
+ 18| 1| assert_eq!(Foo(2), Foo(2));
+ 19| 1| let bar = Foo(0);
+ 20| 1| assert_ne!(bar, Foo(3));
+ 21| 1| assert_ne!(Foo(0), Foo(4));
+ 22| 1| assert_eq!(Foo(3), Foo(3), "with a message");
+ ^0
+ 23| 1| println!("{:?}", bar);
+ 24| 1| println!("{:?}", Foo(1));
+ 25| 1|
+ 26| 1| assert_ne!(Foo(0), Foo(5), "{}", if is_true { "true message" } else { "false message" });
+ ^0 ^0 ^0
+ 27| 1| assert_ne!(
+ 28| | Foo(0)
+ 29| | ,
+ 30| | Foo(5)
+ 31| | ,
+ 32| 0| "{}"
+ 33| 0| ,
+ 34| 0| if
+ 35| 0| is_true
+ 36| | {
+ 37| 0| "true message"
+ 38| | } else {
+ 39| 0| "false message"
+ 40| | }
+ 41| | );
+ 42| |
+ 43| 1| let is_true = std::env::args().len() == 1;
+ 44| 1|
+ 45| 1| assert_eq!(
+ 46| 1| Foo(1),
+ 47| 1| Foo(1)
+ 48| 1| );
+ 49| 1| assert_ne!(
+ 50| 1| Foo(0),
+ 51| 1| Foo(1)
+ 52| 1| );
+ 53| 1| assert_eq!(
+ 54| 1| Foo(2),
+ 55| 1| Foo(2)
+ 56| 1| );
+ 57| 1| let bar = Foo(1);
+ 58| 1| assert_ne!(
+ 59| 1| bar,
+ 60| 1| Foo(3)
+ 61| 1| );
+ 62| 1| if is_true {
+ 63| 1| assert_ne!(
+ 64| 1| Foo(0),
+ 65| 1| Foo(4)
+ 66| 1| );
+ 67| | } else {
+ 68| 0| assert_eq!(
+ 69| 0| Foo(3),
+ 70| 0| Foo(3)
+ 71| 0| );
+ 72| | }
+ 73| 1| if is_true {
+ 74| 1| assert_ne!(
+ 75| | Foo(0),
+ 76| | Foo(4),
+ 77| 0| "with a message"
+ 78| | );
+ 79| | } else {
+ 80| 0| assert_eq!(
+ 81| | Foo(3),
+ 82| | Foo(3),
+ 83| 0| "with a message"
+ 84| | );
+ 85| | }
+ 86| 1| assert_ne!(
+ 87| 1| if is_true {
+ 88| 1| Foo(0)
+ 89| | } else {
+ 90| 0| Foo(1)
+ 91| | },
+ 92| | Foo(5)
+ 93| | );
+ 94| 1| assert_ne!(
+ 95| 1| Foo(5),
+ 96| 1| if is_true {
+ 97| 1| Foo(0)
+ 98| | } else {
+ 99| 0| Foo(1)
+ 100| | }
+ 101| | );
+ 102| 1| assert_ne!(
+ 103| 1| if is_true {
+ 104| 1| assert_eq!(
+ 105| 1| Foo(3),
+ 106| 1| Foo(3)
+ 107| 1| );
+ 108| 1| Foo(0)
+ 109| | } else {
+ 110| 0| assert_ne!(
+ 111| 0| if is_true {
+ 112| 0| Foo(0)
+ 113| | } else {
+ 114| 0| Foo(1)
+ 115| | },
+ 116| | Foo(5)
+ 117| | );
+ 118| 0| Foo(1)
+ 119| | },
+ 120| | Foo(5),
+ 121| 0| "with a message"
+ 122| | );
+ 123| 1| assert_eq!(
+ 124| | Foo(1),
+ 125| | Foo(3),
+ 126| 1| "this assert should fail"
+ 127| | );
+ 128| 0| assert_eq!(
+ 129| | Foo(3),
+ 130| | Foo(3),
+ 131| 0| "this assert should not be reached"
+ 132| | );
+ 133| 0|}
+ 134| |
+ 135| |impl std::fmt::Debug for Foo {
+ 136| | fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
+ 137| 7| write!(f, "try and succeed")?;
+ ^0
+ 138| 7| Ok(())
+ 139| 7| }
+ 140| |}
+ 141| |
+ 142| |static mut DEBUG_LEVEL_ENABLED: bool = false;
+ 143| |
+ 144| |macro_rules! debug {
+ 145| | ($($arg:tt)+) => (
+ 146| | if unsafe { DEBUG_LEVEL_ENABLED } {
+ 147| | println!($($arg)+);
+ 148| | }
+ 149| | );
+ 150| |}
+ 151| |
+ 152| 1|fn test1() {
+ 153| 1| debug!("debug is enabled");
+ ^0
+ 154| 1| debug!("debug is enabled");
+ ^0
+ 155| 1| let _ = 0;
+ 156| 1| debug!("debug is enabled");
+ ^0
+ 157| 1| unsafe {
+ 158| 1| DEBUG_LEVEL_ENABLED = true;
+ 159| 1| }
+ 160| 1| debug!("debug is enabled");
+ 161| 1|}
+ 162| |
+ 163| |macro_rules! call_debug {
+ 164| | ($($arg:tt)+) => (
+ 165| 1| fn call_print(s: &str) {
+ 166| 1| print!("{}", s);
+ 167| 1| }
+ 168| |
+ 169| | call_print("called from call_debug: ");
+ 170| | debug!($($arg)+);
+ 171| | );
+ 172| |}
+ 173| |
+ 174| 1|fn test2() {
+ 175| 1| call_debug!("debug is enabled");
+ 176| 1|}
+ 177| |
+ 178| 1|fn main() {
+ 179| 1| test1();
+ 180| 1| test2();
+ 181| 1| test3();
+ 182| 1|}
+
3| |use std::fmt::Debug;
4| |
5| 1|pub fn used_function() {
- 6| | // Initialize test constants in a way that cannot be determined at compile time, to ensure
- 7| | // rustc and LLVM cannot optimize out statements (or coverage counters) downstream from
- 8| | // dependent conditions.
+ 6| 1| // Initialize test constants in a way that cannot be determined at compile time, to ensure
+ 7| 1| // rustc and LLVM cannot optimize out statements (or coverage counters) downstream from
+ 8| 1| // dependent conditions.
9| 1| let is_true = std::env::args().len() == 1;
10| 1| let mut countdown = 0;
11| 1| if is_true {
22| 2| println!("used_only_from_this_lib_crate_generic_function with {:?}", arg);
23| 2|}
------------------
- | used_crate::used_only_from_this_lib_crate_generic_function::<&str>:
+ | used_crate::used_only_from_this_lib_crate_generic_function::<alloc::vec::Vec<i32>>:
| 21| 1|pub fn used_only_from_this_lib_crate_generic_function<T: Debug>(arg: T) {
| 22| 1| println!("used_only_from_this_lib_crate_generic_function with {:?}", arg);
| 23| 1|}
------------------
- | used_crate::used_only_from_this_lib_crate_generic_function::<alloc::vec::Vec<i32>>:
+ | used_crate::used_only_from_this_lib_crate_generic_function::<&str>:
| 21| 1|pub fn used_only_from_this_lib_crate_generic_function<T: Debug>(arg: T) {
| 22| 1| println!("used_only_from_this_lib_crate_generic_function with {:?}", arg);
| 23| 1|}
5| |use std::fmt::Debug;
6| |
7| 1|pub fn used_function() {
- 8| | // Initialize test constants in a way that cannot be determined at compile time, to ensure
- 9| | // rustc and LLVM cannot optimize out statements (or coverage counters) downstream from
- 10| | // dependent conditions.
+ 8| 1| // Initialize test constants in a way that cannot be determined at compile time, to ensure
+ 9| 1| // rustc and LLVM cannot optimize out statements (or coverage counters) downstream from
+ 10| 1| // dependent conditions.
11| 1| let is_true = std::env::args().len() == 1;
12| 1| let mut countdown = 0;
13| 1| if is_true {
18| |
19| |#[inline(always)]
20| 1|pub fn used_inline_function() {
- 21| | // Initialize test constants in a way that cannot be determined at compile time, to ensure
- 22| | // rustc and LLVM cannot optimize out statements (or coverage counters) downstream from
- 23| | // dependent conditions.
+ 21| 1| // Initialize test constants in a way that cannot be determined at compile time, to ensure
+ 22| 1| // rustc and LLVM cannot optimize out statements (or coverage counters) downstream from
+ 23| 1| // dependent conditions.
24| 1| let is_true = std::env::args().len() == 1;
25| 1| let mut countdown = 0;
26| 1| if is_true {
--- /dev/null
+// compile-flags: --edition=2018
+#![feature(no_coverage)]
+
+macro_rules! bail {
+ ($msg:literal $(,)?) => {
+ if $msg.len() > 0 {
+ println!("no msg");
+ } else {
+ println!($msg);
+ }
+ return Err(String::from($msg));
+ };
+}
+
+macro_rules! on_error {
+ ($value:expr, $error_message:expr) => {
+ $value.or_else(|e| {
+ let message = format!($error_message, e);
+ if message.len() > 0 {
+ println!("{}", message);
+ Ok(String::from("ok"))
+ } else {
+ bail!("error");
+ }
+ })
+ };
+}
+
+fn load_configuration_files() -> Result<String, String> {
+ Ok(String::from("config"))
+}
+
+pub fn main() -> Result<(), String> {
+ println!("Starting service");
+ let config = on_error!(load_configuration_files(), "Error loading configs: {}")?;
+
+ let startup_delay_duration = String::from("arg");
+ let _ = (config, startup_delay_duration);
+ Ok(())
+}
--- /dev/null
+// compile-flags: --edition=2018
+#![feature(no_coverage)]
+
+macro_rules! bail {
+ ($msg:literal $(,)?) => {
+ if $msg.len() > 0 {
+ println!("no msg");
+ } else {
+ println!($msg);
+ }
+ return Err(String::from($msg));
+ };
+}
+
+macro_rules! on_error {
+ ($value:expr, $error_message:expr) => {
+ $value.or_else(|e| {
+ let message = format!($error_message, e);
+ if message.len() > 0 {
+ println!("{}", message);
+ Ok(String::from("ok"))
+ } else {
+ bail!("error");
+ }
+ })
+ };
+}
+
+fn load_configuration_files() -> Result<String, String> {
+ Ok(String::from("config"))
+}
+
+pub async fn test() -> Result<(), String> {
+ println!("Starting service");
+ let config = on_error!(load_configuration_files(), "Error loading configs: {}")?;
+
+ let startup_delay_duration = String::from("arg");
+ let _ = (config, startup_delay_duration);
+ Ok(())
+}
+
+#[no_coverage]
+fn main() {
+ executor::block_on(test());
+}
+
+mod executor {
+ use core::{
+ future::Future,
+ pin::Pin,
+ task::{Context, Poll, RawWaker, RawWakerVTable, Waker},
+ };
+
+ #[no_coverage]
+ pub fn block_on<F: Future>(mut future: F) -> F::Output {
+ let mut future = unsafe { Pin::new_unchecked(&mut future) };
+ use std::hint::unreachable_unchecked;
+ static VTABLE: RawWakerVTable = RawWakerVTable::new(
+
+ #[no_coverage]
+ |_| unsafe { unreachable_unchecked() }, // clone
+
+ #[no_coverage]
+ |_| unsafe { unreachable_unchecked() }, // wake
+
+ #[no_coverage]
+ |_| unsafe { unreachable_unchecked() }, // wake_by_ref
+
+ #[no_coverage]
+ |_| (),
+ );
+ let waker = unsafe { Waker::from_raw(RawWaker::new(core::ptr::null(), &VTABLE)) };
+ let mut context = Context::from_waker(&waker);
+
+ loop {
+ if let Poll::Ready(val) = future.as_mut().poll(&mut context) {
+ break val;
+ }
+ }
+ }
+}
--- /dev/null
+// This demonstrated Issue #84561: function-like macros produce unintuitive coverage results.
+
+// expect-exit-status-101
+#[derive(PartialEq, Eq)]
+struct Foo(u32);
+fn test3() {
+ let is_true = std::env::args().len() == 1;
+ let bar = Foo(1);
+ assert_eq!(bar, Foo(1));
+ let baz = Foo(0);
+ assert_ne!(baz, Foo(1));
+ println!("{:?}", Foo(1));
+ println!("{:?}", bar);
+ println!("{:?}", baz);
+
+ assert_eq!(Foo(1), Foo(1));
+ assert_ne!(Foo(0), Foo(1));
+ assert_eq!(Foo(2), Foo(2));
+ let bar = Foo(0);
+ assert_ne!(bar, Foo(3));
+ assert_ne!(Foo(0), Foo(4));
+ assert_eq!(Foo(3), Foo(3), "with a message");
+ println!("{:?}", bar);
+ println!("{:?}", Foo(1));
+
+ assert_ne!(Foo(0), Foo(5), "{}", if is_true { "true message" } else { "false message" });
+ assert_ne!(
+ Foo(0)
+ ,
+ Foo(5)
+ ,
+ "{}"
+ ,
+ if
+ is_true
+ {
+ "true message"
+ } else {
+ "false message"
+ }
+ );
+
+ let is_true = std::env::args().len() == 1;
+
+ assert_eq!(
+ Foo(1),
+ Foo(1)
+ );
+ assert_ne!(
+ Foo(0),
+ Foo(1)
+ );
+ assert_eq!(
+ Foo(2),
+ Foo(2)
+ );
+ let bar = Foo(1);
+ assert_ne!(
+ bar,
+ Foo(3)
+ );
+ if is_true {
+ assert_ne!(
+ Foo(0),
+ Foo(4)
+ );
+ } else {
+ assert_eq!(
+ Foo(3),
+ Foo(3)
+ );
+ }
+ if is_true {
+ assert_ne!(
+ Foo(0),
+ Foo(4),
+ "with a message"
+ );
+ } else {
+ assert_eq!(
+ Foo(3),
+ Foo(3),
+ "with a message"
+ );
+ }
+ assert_ne!(
+ if is_true {
+ Foo(0)
+ } else {
+ Foo(1)
+ },
+ Foo(5)
+ );
+ assert_ne!(
+ Foo(5),
+ if is_true {
+ Foo(0)
+ } else {
+ Foo(1)
+ }
+ );
+ assert_ne!(
+ if is_true {
+ assert_eq!(
+ Foo(3),
+ Foo(3)
+ );
+ Foo(0)
+ } else {
+ assert_ne!(
+ if is_true {
+ Foo(0)
+ } else {
+ Foo(1)
+ },
+ Foo(5)
+ );
+ Foo(1)
+ },
+ Foo(5),
+ "with a message"
+ );
+ assert_eq!(
+ Foo(1),
+ Foo(3),
+ "this assert should fail"
+ );
+ assert_eq!(
+ Foo(3),
+ Foo(3),
+ "this assert should not be reached"
+ );
+}
+
+impl std::fmt::Debug for Foo {
+ fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
+ write!(f, "try and succeed")?;
+ Ok(())
+ }
+}
+
+static mut DEBUG_LEVEL_ENABLED: bool = false;
+
+macro_rules! debug {
+ ($($arg:tt)+) => (
+ if unsafe { DEBUG_LEVEL_ENABLED } {
+ println!($($arg)+);
+ }
+ );
+}
+
+fn test1() {
+ debug!("debug is enabled");
+ debug!("debug is enabled");
+ let _ = 0;
+ debug!("debug is enabled");
+ unsafe {
+ DEBUG_LEVEL_ENABLED = true;
+ }
+ debug!("debug is enabled");
+}
+
+macro_rules! call_debug {
+ ($($arg:tt)+) => (
+ fn call_print(s: &str) {
+ print!("{}", s);
+ }
+
+ call_print("called from call_debug: ");
+ debug!($($arg)+);
+ );
+}
+
+fn test2() {
+ call_debug!("debug is enabled");
+}
+
+fn main() {
+ test1();
+ test2();
+ test3();
+}
--- /dev/null
+// test the behavior of the --no-run flag without the --test flag
+
+// compile-flags:-Z unstable-options --no-run --test-args=--test-threads=1
+// error-pattern: the `--test` flag must be passed
+
+pub fn f() {}
--- /dev/null
+error: the `--test` flag must be passed to enable `--no-run`
+
--- /dev/null
+// test the behavior of the --no-run flag
+
+// check-pass
+// compile-flags:-Z unstable-options --test --no-run --test-args=--test-threads=1
+// 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!
+/// ```
+/// Ok the test does not run
+/// ```
+/// panic!()
+/// ```
+/// Ok the test does not run
+/// ```should_panic
+/// loop {
+/// println!("Hello, world");
+/// panic!()
+/// }
+/// ```
+pub fn f() {}
--- /dev/null
+
+running 7 tests
+test $DIR/no-run-flag.rs - f (line 11) ... 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 result: ok. 6 passed; 0 failed; 1 ignored; 0 measured; 0 filtered out; finished in $TIME
+
/// Docs for QUX1 in impl.
const QUX1: i8 = 5;
// @has - '//*[@id="associatedconstant.QUX_DEFAULT0"]' 'const QUX_DEFAULT0: u16'
- // @has - '//*[@class="docblock hidden"]' "Docs for QUX_DEFAULT12 in trait."
+ // @!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."
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 - '//*[@class="docblock hidden"]' "Docs for QUX_DEFAULT2 in trait."
+ // @!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."
}
--- /dev/null
+#![feature(trait_alias)]
+
+pub trait SomeAlias = std::fmt::Debug + std::marker::Copy;
--- /dev/null
+pub trait Bar {
+ fn foo();
+}
// @has - '//*[@id="associatedconstant.ConstNoDefault"]' 'const ConstNoDefault: i16'
// @has - '//*[@class="docblock"]' 'dox for ConstNoDefault'
// @has - '//*[@id="associatedconstant.ConstWithDefault"]' 'const ConstWithDefault: u16'
-// @has - '//*[@class="docblock hidden"]' 'docs for ConstWithDefault'
+// @!has - '//details[@open=""]/details/div[@class="docblock"]' 'docs for ConstWithDefault'
+// @has - '//details/details/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 - '//*[@class="docblock hidden"]' 'docs for TypeWithDefault'
+// @!has - '//details[@open=""]/details/div[@class="docblock"]' 'docs for TypeWithDefault'
+// @has - '//details/details/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 - '//*[@class="docblock hidden"]' 'docs for 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'
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 - '//*[@class="docblock hidden"]' 'docs for 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'
pub use impl_inline_without_trait::MyStruct;
// @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 - '//*[@class="docblock hidden"]' 'Docs associated with the trait b_method definition.'
-// @has - '//*[@class="docblock hidden"]' '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"]/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 - '//*[@class="docblock"]' 'There is another line'
-// @has - '//*[@class="docblock hidden"]' 'Read more'
+// @!has - '//div[@class="impl-items"]/details[@open=""]//div[@class="docblock"]' 'Read more'
+// @has - '//div[@class="impl-items"]/details//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 - '//*[@class="docblock"]' 'Docs associated with the trait a_method definition.'
-// @!has - '//*[@class="docblock"]' 'Docs associated with the trait c_method definition.'
-// @has - '//*[@class="docblock hidden"]' 'Docs associated with the trait b_method definition.'
+// @!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.'
pub struct S2(usize);
/// Docs associated with the S2 trait implementation.
}
// @has manual_impl/struct.S3.html '//*[@class="trait"]' 'T'
-// @has - '//*[@class="docblock"]' 'Docs associated with the S3 trait implementation.'
-// @has - '//*[@class="docblock"]' 'Docs associated with the S3 trait b_method implementation.'
-// @has - '//*[@class="docblock hidden"]' 'Docs associated with the trait a_method definition.'
+// @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.'
pub struct S3(usize);
/// Docs associated with the S3 trait implementation.
--- /dev/null
+// aux-build:trait-alias-mention.rs
+// build-aux-docs
+
+#![crate_name = "foo"]
+
+extern crate trait_alias_mention;
+
+// @has foo/fn.mention_alias_in_bounds.html '//a[@href="../trait_alias_mention/traitalias.SomeAlias.html"]' 'SomeAlias'
+pub fn mention_alias_in_bounds<T: trait_alias_mention::SomeAlias>() {
+}
pub struct Struct;
impl Trait for Struct {
- // @has trait_impl/struct.Struct.html '//*[@id="method.a"]/../div/p' 'Some long docs'
- // @!has - '//*[@id="method.a"]/../div/p' 'link will be added'
- // @has - '//*[@id="method.a"]/../div/p/a' 'Read more'
- // @has - '//*[@id="method.a"]/../div/p/a/@href' 'trait.Trait.html'
+ // @has trait_impl/struct.Struct.html '//*[@id="method.a"]/../../div[@class="docblock"]/p' 'Some long docs'
+ // @!has - '//*[@id="method.a"]/../../div[@class="docblock"]/p' 'link will be added'
+ // @has - '//*[@id="method.a"]/../../div[@class="docblock"]/p/a' 'Read more'
+ // @has - '//*[@id="method.a"]/../../div[@class="docblock"]/p/a/@href' 'trait.Trait.html#tymethod.a'
fn a() {}
- // @has trait_impl/struct.Struct.html '//*[@id="method.b"]/../div/p' 'These docs contain'
- // @has - '//*[@id="method.b"]/../div/p/a' 'reference link'
- // @has - '//*[@id="method.b"]/../div/p/a/@href' 'https://example.com'
- // @has - '//*[@id="method.b"]/../div/p/a' 'Read more'
- // @has - '//*[@id="method.b"]/../div/p/a/@href' 'trait.Trait.html'
+ // @has - '//*[@id="method.b"]/../../div[@class="docblock"]/p' 'These docs contain'
+ // @has - '//*[@id="method.b"]/../../div[@class="docblock"]/p/a' 'reference link'
+ // @has - '//*[@id="method.b"]/../../div[@class="docblock"]/p/a/@href' 'https://example.com'
+ // @has - '//*[@id="method.b"]/../../div[@class="docblock"]/p/a' 'Read more'
+ // @has - '//*[@id="method.b"]/../../div[@class="docblock"]/p/a/@href' 'trait.Trait.html#tymethod.b'
fn b() {}
- // @!has trait_impl/struct.Struct.html '//*[@id="method.c"]/../div/p' 'code block'
- // @has - '//*[@id="method.c"]/../div/p/a' 'Read more'
- // @has - '//*[@id="method.c"]/../div/p/a/@href' 'trait.Trait.html'
+ // @!has - '//*[@id="method.c"]/../../div[@class="docblock"]/p' 'code block'
+ // @has - '//*[@id="method.c"]/../../div[@class="docblock"]/a' 'Read more'
+ // @has - '//*[@id="method.c"]/../../div[@class="docblock"]/a/@href' 'trait.Trait.html#tymethod.c'
fn c() {}
- // @has trait_impl/struct.Struct.html '//*[@id="method.d"]/../div/p' \
- // 'Escaped formatting a*b*c* works'
- // @!has trait_impl/struct.Struct.html '//*[@id="method.d"]/../div/p/em'
+ // @has - '//*[@id="method.d"]/../../div[@class="docblock"]/p' 'Escaped formatting a*b*c* works'
+ // @!has - '//*[@id="method.d"]/../../div[@class="docblock"]/p/em'
fn d() {}
+
+ // @has - '//*[@id="impl-Trait"]/code/a/@href' 'trait.Trait.html'
}
--- /dev/null
+// aux-build:trait-visibility.rs
+
+#![crate_name = "foo"]
+
+extern crate trait_visibility;
+
+// @has foo/trait.Bar.html '//a[@href="#tymethod.foo"]/..' "fn foo()"
+pub use trait_visibility::Bar;
pub trait Alias2 = Copy + Debug;
// @has foo/traitalias.Foo.html '//section[@id="main"]/pre' 'trait Foo<T> = Into<T> + Debug;'
pub trait Foo<T> = Into<T> + Debug;
+// @has foo/fn.bar.html '//a[@href="traitalias.Alias2.html"]' 'Alias2'
+pub fn bar<T>() where T: Alias2 {}
--> $DIR/async-borrowck-escaping-block-error.rs:11:11
|
LL | async { *x }
- | ^^^-^^
- | | |
- | | `x` is borrowed here
+ | ^^--^^
+ | | |
+ | | `x` is borrowed here
| may outlive borrowed value `x`
|
note: async block is returned here
--> $DIR/borrowck-closures-mut-and-imm.rs:57:5
|
LL | let c1 = || get(&*x);
- | -- - borrow occurs due to use in closure
+ | -- -- borrow occurs due to use in closure
| |
| borrow of `*x` occurs here
LL | *x = 5;
--> $DIR/borrowck-closures-mut-and-imm.rs:69:5
|
LL | let c1 = || get(&*x.f);
- | -- - borrow occurs due to use in closure
+ | -- ---- borrow occurs due to use in closure
| |
| borrow of `*x.f` occurs here
LL | *x.f = 5;
--> $DIR/borrowck-closures-mut-and-imm.rs:81:14
|
LL | let c1 = || get(&*x.f);
- | -- - first borrow occurs due to use of `x` in closure
+ | -- ---- first borrow occurs due to use of `x` in closure
| |
| immutable borrow occurs here
LL | let c2 = || *x.f = 5;
- | ^^ - second borrow occurs due to use of `x` in closure
+ | ^^ ---- second borrow occurs due to use of `x` in closure
| |
| mutable borrow occurs here
LL |
--> $DIR/borrowck-closures-mut-of-imm.rs:11:18
|
LL | let mut c1 = || set(&mut *x);
- | -- - first borrow occurs due to use of `x` in closure
+ | -- -- first borrow occurs due to use of `x` in closure
| |
| first closure is constructed here
LL |
LL | let mut c2 = || set(&mut *x);
- | ^^ - second borrow occurs due to use of `x` in closure
+ | ^^ -- second borrow occurs due to use of `x` in closure
| |
| second closure is constructed here
...
--> $DIR/borrowck-closures-mut-of-mut.rs:14:18
|
LL | let mut c1 = || set(&mut *x);
- | -- - first borrow occurs due to use of `x` in closure
+ | -- -- first borrow occurs due to use of `x` in closure
| |
| first closure is constructed here
LL | let mut c2 = || set(&mut *x);
- | ^^ - second borrow occurs due to use of `x` in closure
+ | ^^ -- second borrow occurs due to use of `x` in closure
| |
| second closure is constructed here
LL |
LL | let f = || {
| -- immutable borrow occurs here
LL | let [ref y, ref z @ ..] = *x;
- | - first borrow occurs due to use of `x` in closure
+ | -- first borrow occurs due to use of `x` in closure
LL | };
LL | let r = &mut *x;
| ^^^^^^^ mutable borrow occurs here
LL | let mut f = || {
| -- closure construction occurs here
LL | let [ref mut y, ref mut z @ ..] = *x;
- | - first borrow occurs due to use of `x` in closure
+ | -- first borrow occurs due to use of `x` in closure
LL | };
LL | let r = &x;
| ^^ second borrow occurs here
LL | let f = || {
| -- immutable borrow occurs here
LL | if let [ref y, ref z @ ..] = *x {}
- | - first borrow occurs due to use of `x` in closure
+ | -- first borrow occurs due to use of `x` in closure
LL | };
LL | let r = &mut *x;
| ^^^^^^^ mutable borrow occurs here
LL | let mut f = || {
| -- closure construction occurs here
LL | if let [ref mut y, ref mut z @ ..] = *x {}
- | - first borrow occurs due to use of `x` in closure
+ | -- first borrow occurs due to use of `x` in closure
LL | };
LL | let r = &x;
| ^^ second borrow occurs here
--> $DIR/borrowck-closures-two-mut-fail.rs:53:24
|
LL | let c1 = to_fn_mut(|| set(&mut *x.f));
- | -- - first borrow occurs due to use of `x` in closure
+ | -- ---- first borrow occurs due to use of `x` in closure
| |
| first mutable borrow occurs here
LL | let c2 = to_fn_mut(|| set(&mut *x.f));
- | ^^ - second borrow occurs due to use of `x` in closure
+ | ^^ ---- second borrow occurs due to use of `x` in closure
| |
| second mutable borrow occurs here
LL |
--> $DIR/borrowck-closures-two-mut.rs:49:24
|
LL | let c1 = to_fn_mut(|| set(&mut *x.f));
- | -- - first borrow occurs due to use of `x` in closure
+ | -- ---- first borrow occurs due to use of `x` in closure
| |
| first mutable borrow occurs here
LL | let c2 = to_fn_mut(|| set(&mut *x.f));
- | ^^ - second borrow occurs due to use of `x` in closure
+ | ^^ ---- second borrow occurs due to use of `x` in closure
| |
| second mutable borrow occurs here
LL |
| |
| borrow occurs here
LL | let c2 = || { get(x); set(x); };
- | ^^ - second borrow occurs due to use of `x` in closure
+ | ^^ - second borrow occurs due to use of `x` in closure
| |
| closure construction occurs here
LL | c1;
LL | let mut test = |foo: &Foo| {
| ----------- mutable borrow occurs here
LL | ptr = box Foo { x: ptr.x + 1 };
- | --- first borrow occurs due to use of `ptr` in closure
+ | --- first borrow occurs due to use of `ptr` in closure
LL | };
LL | test(&*ptr);
| ---- ^^^^^ immutable borrow occurs here
LL | | |a| {
| | --- closure construction occurs here
LL | | f.n.insert(*a);
- | | - first borrow occurs due to use of `f` in closure
+ | | --- first borrow occurs due to use of `f` in closure
LL | | })
| |__________^ second borrow occurs here
LL | |a| {
| ^^^ closure construction occurs here
LL | f.n.insert(*a);
- | - second borrow occurs due to use of `f` in closure
+ | --- second borrow occurs due to use of `f` in closure
error: aborting due to 2 previous errors
| ^^^^^^ move out of `v` occurs here
LL |
LL | println!("v={}", *v);
- | - move occurs due to use in closure
+ | -- move occurs due to use in closure
LL | });
LL | w.use_ref();
| - borrow later used here
| ^^^^^^ move out of `v` occurs here
LL |
LL | println!("v={}", *v);
- | - move occurs due to use in closure
+ | -- move occurs due to use in closure
LL | });
LL | w.use_ref();
| - borrow later used here
| | immutable borrow later used by call
| immutable borrow occurs here
LL | p.x = 10;
- | - second borrow occurs due to use of `p` in closure
+ | --- second borrow occurs due to use of `p` in closure
error[E0502]: cannot borrow `p` as immutable because it is also borrowed as mutable
--> $DIR/borrowck-loan-rcvr.rs:34:5
| --- captured outer variable
LL | let _g = to_fn_mut(|| {
LL | let _h = to_fn_once(move || -> isize { *bar });
- | ^^^^^^^^^^^^^^^^ ---
- | | |
- | | move occurs because `bar` has type `Box<isize>`, which does not implement the `Copy` trait
- | | move occurs due to use in closure
+ | ^^^^^^^^^^^^^^^^ ----
+ | | |
+ | | move occurs because `bar` has type `Box<isize>`, which does not implement the `Copy` trait
+ | | move occurs due to use in closure
| move out of `bar` occurs here
error: aborting due to previous error
| - move occurs because `t` has type `Box<isize>`, which does not implement the `Copy` trait
LL |
LL | call_f(move|| { *t + 1 });
- | ------ - variable moved due to use in closure
+ | ------ -- variable moved due to use in closure
| |
| value moved into closure here
LL | call_f(move|| { *t + 1 });
- | ^^^^^^ - use occurs due to use in closure
+ | ^^^^^^ -- use occurs due to use in closure
| |
| value used here after move
| - value is immutable in match guard
...
LL | (|| { *x = None; drop(force_fn_once); })();
- | ^^ - borrow occurs due to use of `x` in closure
+ | ^^ -- borrow occurs due to use of `x` in closure
| |
| cannot mutably borrow
--> $DIR/issue-27282-reborrow-ref-mut-in-guard.rs:12:25
|
LL | ref mut r if { (|| { let bar = &mut *r; **bar = false; })();
- | ^^ - mutable borrow occurs due to use of `r` in closure
+ | ^^ -- mutable borrow occurs due to use of `r` in closure
| |
| cannot borrow as mutable
|
-// run-pass
+// build-pass
// pretty-expanded FIXME #23616
-// ignore-wasm32-bare no target_family
+// ignore-wasm32-bare no bare family
// ignore-sgx
#[cfg(windows)]
-// run-pass
-// ignore-wasm32-bare no target_family
+// build-pass
// ignore-sgx
// pretty-expanded FIXME #23616
#[cfg(target_family = "unix")]
pub fn main() {
}
+
+#[cfg(target_family="wasm")]
+pub fn main() {
+}
--- /dev/null
+#![feature(capture_disjoint_fields)]
+//~^ WARNING: the feature `capture_disjoint_fields` is incomplete
+
+#[derive(Debug)]
+struct Point {
+ x: i32,
+ y: i32,
+}
+fn main() {
+ let mut p = Point {x: 1, y: 2 };
+
+ let y = &mut p.y;
+ let mut c = || {
+ //~^ ERROR cannot borrow `p` as mutable more than once at a time
+ let x = &mut p.x;
+ println!("{:?}", p);
+ };
+ c();
+ *y+=1;
+}
--- /dev/null
+warning: the feature `capture_disjoint_fields` is incomplete and may not be safe to use and/or cause compiler crashes
+ --> $DIR/borrowck-1.rs:1:12
+ |
+LL | #![feature(capture_disjoint_fields)]
+ | ^^^^^^^^^^^^^^^^^^^^^^^
+ |
+ = note: `#[warn(incomplete_features)]` on by default
+ = note: see issue #53488 <https://github.com/rust-lang/rust/issues/53488> for more information
+
+error[E0499]: cannot borrow `p` as mutable more than once at a time
+ --> $DIR/borrowck-1.rs:13:17
+ |
+LL | let y = &mut p.y;
+ | -------- first mutable borrow occurs here
+LL | let mut c = || {
+ | ^^ second mutable borrow occurs here
+LL |
+LL | let x = &mut p.x;
+ | --- capture is mutable because of use here
+LL | println!("{:?}", p);
+ | - second borrow occurs due to use of `p` in closure
+...
+LL | *y+=1;
+ | ----- first borrow later used here
+
+error: aborting due to previous error; 1 warning emitted
+
+For more information about this error, try `rustc --explain E0499`.
--- /dev/null
+#![feature(capture_disjoint_fields)]
+//~^ WARNING: the feature `capture_disjoint_fields` is incomplete
+
+#[derive(Debug)]
+struct Point {
+ x: i32,
+ y: i32,
+}
+fn main() {
+ let mut p = Point {x: 1, y: 2 };
+
+ let y = &p.y;
+ let mut c = || {
+ //~^ ERROR cannot borrow `p` as mutable because it is also borrowed as immutable
+ println!("{:?}", p);
+ let x = &mut p.x;
+ };
+ c();
+ println!("{}", y);
+}
--- /dev/null
+warning: the feature `capture_disjoint_fields` is incomplete and may not be safe to use and/or cause compiler crashes
+ --> $DIR/borrowck-2.rs:1:12
+ |
+LL | #![feature(capture_disjoint_fields)]
+ | ^^^^^^^^^^^^^^^^^^^^^^^
+ |
+ = note: `#[warn(incomplete_features)]` on by default
+ = note: see issue #53488 <https://github.com/rust-lang/rust/issues/53488> for more information
+
+error[E0502]: cannot borrow `p` as mutable because it is also borrowed as immutable
+ --> $DIR/borrowck-2.rs:13:17
+ |
+LL | let y = &p.y;
+ | ---- immutable borrow occurs here
+LL | let mut c = || {
+ | ^^ mutable borrow occurs here
+LL |
+LL | println!("{:?}", p);
+ | - second borrow occurs due to use of `p` in closure
+LL | let x = &mut p.x;
+ | --- capture is mutable because of use here
+...
+LL | println!("{}", y);
+ | - immutable borrow later used here
+
+error: aborting due to previous error; 1 warning emitted
+
+For more information about this error, try `rustc --explain E0502`.
--- /dev/null
+#![feature(capture_disjoint_fields)]
+//~^ WARNING: the feature `capture_disjoint_fields` is incomplete
+
+#[derive(Debug)]
+struct Point {
+ x: String,
+ y: String,
+}
+fn main() {
+ let mut c = {
+ let mut p = Point {x: "1".to_string(), y: "2".to_string() };
+ || {
+ let x = &mut p.x;
+ println!("{:?}", p);
+ //~^ ERROR `p` does not live long enough
+ }
+ };
+ c();
+}
--- /dev/null
+warning: the feature `capture_disjoint_fields` is incomplete and may not be safe to use and/or cause compiler crashes
+ --> $DIR/borrowck-3.rs:1:12
+ |
+LL | #![feature(capture_disjoint_fields)]
+ | ^^^^^^^^^^^^^^^^^^^^^^^
+ |
+ = note: `#[warn(incomplete_features)]` on by default
+ = note: see issue #53488 <https://github.com/rust-lang/rust/issues/53488> for more information
+
+error[E0597]: `p` does not live long enough
+ --> $DIR/borrowck-3.rs:14:29
+ |
+LL | let mut c = {
+ | ----- borrow later stored here
+LL | let mut p = Point {x: "1".to_string(), y: "2".to_string() };
+LL | || {
+ | -- value captured here
+LL | let x = &mut p.x;
+LL | println!("{:?}", p);
+ | ^ borrowed value does not live long enough
+...
+LL | };
+ | - `p` dropped here while still borrowed
+
+error: aborting due to previous error; 1 warning emitted
+
+For more information about this error, try `rustc --explain E0597`.
--- /dev/null
+#![feature(capture_disjoint_fields)]
+//~^ WARNING: the feature `capture_disjoint_fields` is incomplete
+
+#[derive(Debug)]
+struct Point {
+ x: i32,
+ y: i32,
+}
+fn foo () -> impl FnMut()->() {
+ let mut p = Point {x: 1, y: 2 };
+ let mut c = || {
+ //~^ ERROR closure may outlive the current function, but it borrows `p`
+ p.x+=5;
+ println!("{:?}", p);
+ };
+ c
+}
+fn main() {
+ let c = foo();
+ c();
+}
--- /dev/null
+warning: the feature `capture_disjoint_fields` is incomplete and may not be safe to use and/or cause compiler crashes
+ --> $DIR/borrowck-4.rs:1:12
+ |
+LL | #![feature(capture_disjoint_fields)]
+ | ^^^^^^^^^^^^^^^^^^^^^^^
+ |
+ = note: `#[warn(incomplete_features)]` on by default
+ = note: see issue #53488 <https://github.com/rust-lang/rust/issues/53488> for more information
+
+error[E0373]: closure may outlive the current function, but it borrows `p`, which is owned by the current function
+ --> $DIR/borrowck-4.rs:11:17
+ |
+LL | let mut c = || {
+ | ^^ may outlive borrowed value `p`
+...
+LL | println!("{:?}", p);
+ | - `p` is borrowed here
+ |
+note: closure is returned here
+ --> $DIR/borrowck-4.rs:9:14
+ |
+LL | fn foo () -> impl FnMut()->() {
+ | ^^^^^^^^^^^^^^^^
+help: to force the closure to take ownership of `p` (and any other referenced variables), use the `move` keyword
+ |
+LL | let mut c = move || {
+ | ^^^^^^^
+
+error: aborting due to previous error; 1 warning emitted
+
+For more information about this error, try `rustc --explain E0373`.
--- /dev/null
+// Tests that two closures cannot simultaneously have mutable
+// and immutable access to the variable. Issue #6801.
+
+#![feature(capture_disjoint_fields)]
+//~^ WARNING: the feature `capture_disjoint_fields` is incomplete
+#![feature(box_syntax)]
+
+#[derive(Debug)]
+struct Point {
+ x: i32,
+ y: i32,
+}
+
+fn a() {
+ let mut p = Point {x: 3, y:4};
+ let c2 = || p.y * 5;
+ let c1 = || {
+ //~^ ERROR cannot borrow `p` as mutable because it is also borrowed as immutable
+ dbg!(&p);
+ p.x = 4;
+ };
+ drop(c2);
+}
+
+fn main() {
+}
--- /dev/null
+warning: the feature `capture_disjoint_fields` is incomplete and may not be safe to use and/or cause compiler crashes
+ --> $DIR/borrowck-closures-mut-and-imm.rs:4:12
+ |
+LL | #![feature(capture_disjoint_fields)]
+ | ^^^^^^^^^^^^^^^^^^^^^^^
+ |
+ = note: `#[warn(incomplete_features)]` on by default
+ = note: see issue #53488 <https://github.com/rust-lang/rust/issues/53488> for more information
+
+error[E0502]: cannot borrow `p` as mutable because it is also borrowed as immutable
+ --> $DIR/borrowck-closures-mut-and-imm.rs:17:14
+ |
+LL | let c2 = || p.y * 5;
+ | -- --- first borrow occurs due to use of `p.y` in closure
+ | |
+ | immutable borrow occurs here
+LL | let c1 = || {
+ | ^^ mutable borrow occurs here
+LL |
+LL | dbg!(&p);
+ | - second borrow occurs due to use of `p` in closure
+LL | p.x = 4;
+ | --- capture is mutable because of use here
+LL | };
+LL | drop(c2);
+ | -- immutable borrow later used here
+
+error: aborting due to previous error; 1 warning emitted
+
+For more information about this error, try `rustc --explain E0502`.
LL | let mut c = || {
| -- borrow of `e.0.0.m.x` occurs here
LL | e.0.0.m.x = format!("not-x");
- | - borrow occurs due to use in closure
+ | --------- borrow occurs due to use in closure
...
LL | e.0.0.m.x = format!("not-x");
| ^^^^^^^^^ assignment to borrowed `e.0.0.m.x` occurs here
LL | let mut c = || {
| -- mutable borrow occurs here
LL | e.0.0.m.x = format!("not-x");
- | - first borrow occurs due to use of `e.0.0.m.x` in closure
+ | --------- first borrow occurs due to use of `e.0.0.m.x` in closure
...
LL | println!("{}", e.0.0.m.x);
| ^^^^^^^^^ immutable borrow occurs here
LL | let c = || {
| -- borrow of `e.0.0.m.x` occurs here
LL | println!("{}", e.0.0.m.x);
- | - borrow occurs due to use in closure
+ | --------- borrow occurs due to use in closure
...
LL | e.0.0.m.x = format!("not-x");
| ^^^^^^^^^ assignment to borrowed `e.0.0.m.x` occurs here
| ^^ cannot borrow as mutable
LL |
LL | z.0.0.0 = format!("X1");
- | - mutable borrow occurs due to use of `z.0.0.0` in closure
+ | ------- mutable borrow occurs due to use of `z.0.0.0` in closure
error: aborting due to previous error; 1 warning emitted
let mut c = || {
z.0.0.0 = 20;
- //~^ ERROR: cannot assign to `z`, as it is not declared as mutable
+ //~^ ERROR: cannot assign to `z.0.0.0`, as it is not declared as mutable
};
c();
let mut c = || {
bx.0 = 20;
- //~^ ERROR: cannot assign to `bx`, as it is not declared as mutable
+ //~^ ERROR: cannot assign to `*bx.0`, as it is not declared as mutable
};
c();
= note: `#[warn(incomplete_features)]` on by default
= note: see issue #53488 <https://github.com/rust-lang/rust/issues/53488> for more information
-error[E0594]: cannot assign to `z`, as it is not declared as mutable
+error[E0594]: cannot assign to `z.0.0.0`, as it is not declared as mutable
--> $DIR/cant-mutate-imm.rs:13:9
|
LL | let z = (y, 10);
LL | z.0.0.0 = 20;
| ^^^^^^^^^^^^ cannot assign
-error[E0594]: cannot assign to `bx`, as it is not declared as mutable
+error[E0594]: cannot assign to `*bx.0`, as it is not declared as mutable
--> $DIR/cant-mutate-imm.rs:25:9
|
LL | let bx = Box::new(x);
LL | let mut c = || {
| -- first mutable borrow occurs here
LL | w.p.x += 20;
- | - first borrow occurs due to use of `w.p.x` in closure
+ | ----- first borrow occurs due to use of `w.p.x` in closure
...
LL | let py = &mut w.p.x;
| ^^^^^^^^^^ second mutable borrow occurs here
| ^^ `ref_mref_x` is a `&` reference, so the data it refers to cannot be borrowed as mutable
LL |
LL | **ref_mref_x = y;
- | ---------- mutable borrow occurs due to use of `**ref_mref_x` in closure
+ | ------------ mutable borrow occurs due to use of `**ref_mref_x` in closure
error[E0596]: cannot borrow `**mref_ref_x` as mutable, as it is behind a `&` reference
--> $DIR/mut_ref.rs:27:13
| ^^ cannot borrow as mutable
LL |
LL | **mref_ref_x = y;
- | ---------- mutable borrow occurs due to use of `**mref_ref_x` in closure
+ | ------------ mutable borrow occurs due to use of `**mref_ref_x` in closure
error: aborting due to 2 previous errors; 1 warning emitted
LL | let mut c = || {
| -- mutable borrow occurs here
LL | p.x += 10;
- | - first borrow occurs due to use of `p` in closure
+ | --- capture is mutable because of use here
+LL | println!("{:?}", p);
+ | - first borrow occurs due to use of `p` in closure
...
LL | println!("{:?}", p);
| ^ immutable borrow occurs here
| ^ unused parameter
|
= help: consider removing `T`, referring to it in a field, or using a marker such as `PhantomData`
+ = help: if you intended `T` to be a const parameter, use `const T: usize` instead
error: aborting due to 2 previous errors
| ^ unused parameter
|
= help: consider removing `T`, referring to it in a field, or using a marker such as `PhantomData`
+ = help: if you intended `T` to be a const parameter, use `const T: usize` instead
error: aborting due to 2 previous errors
| ^ unused parameter
|
= help: consider removing `T`, referring to it in a field, or using a marker such as `PhantomData`
+ = help: if you intended `T` to be a const parameter, use `const T: usize` instead
error: aborting due to previous error; 1 warning emitted
| ^ unused parameter
|
= help: consider removing `T`, referring to it in a field, or using a marker such as `PhantomData`
+ = help: if you intended `T` to be a const parameter, use `const T: usize` instead
error: aborting due to 2 previous errors
| ^ unused parameter
|
= help: consider removing `S`, referring to it in a field, or using a marker such as `PhantomData`
+ = help: if you intended `S` to be a const parameter, use `const S: usize` instead
error: aborting due to 2 previous errors
| ^ unused parameter
|
= help: consider removing `S`, referring to it in a field, or using a marker such as `PhantomData`
+ = help: if you intended `S` to be a const parameter, use `const S: usize` instead
error: aborting due to 3 previous errors
| ^ unused parameter
|
= help: consider removing `S`, referring to it in a field, or using a marker such as `PhantomData`
+ = help: if you intended `S` to be a const parameter, use `const S: usize` instead
error: aborting due to 2 previous errors
| ^ unused parameter
|
= help: consider removing `S`, referring to it in a field, or using a marker such as `PhantomData`
+ = help: if you intended `S` to be a const parameter, use `const S: usize` instead
error: aborting due to 3 previous errors
--- /dev/null
+// regression test for #83466- tests that generic arg mismatch errors between
+// consts and types are not supressed when there are explicit late bound lifetimes
+
+struct S;
+impl S {
+ fn func<'a, U>(self) -> U {
+ todo!()
+ }
+}
+fn dont_crash<'a, U>() {
+ S.func::<'a, 10_u32>()
+ //~^ WARNING cannot specify lifetime arguments explicitly if late bound lifetime parameters are present
+ //~^^ WARNING this was previously accepted by
+ //~^^^ ERROR constant provided when a type was expected [E0747]
+}
+
+fn main() {}
--- /dev/null
+warning: cannot specify lifetime arguments explicitly if late bound lifetime parameters are present
+ --> $DIR/issue-83466.rs:11:14
+ |
+LL | fn func<'a, U>(self) -> U {
+ | -- the late bound lifetime parameter is introduced here
+...
+LL | S.func::<'a, 10_u32>()
+ | ^^
+ |
+ = note: `#[warn(late_bound_lifetime_arguments)]` 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 #42868 <https://github.com/rust-lang/rust/issues/42868>
+
+error[E0747]: constant provided when a type was expected
+ --> $DIR/issue-83466.rs:11:18
+ |
+LL | S.func::<'a, 10_u32>()
+ | ^^^^^^
+
+error: aborting due to previous error; 1 warning emitted
+
+For more information about this error, try `rustc --explain E0747`.
//~| ERROR expected trait, found constant `BAR`
//~| ERROR type provided when a constant was expected
//~| WARN trait objects without an explicit `dyn` are deprecated
+ //~| WARN this was previously accepted by the compiler
}
fn c() {
foo::<3 + 3>(); //~ ERROR expressions must be enclosed in braces
| ^ ^
error: expressions must be enclosed in braces to be used as const generic arguments
- --> $DIR/const-expression-suggest-missing-braces.rs:18:11
+ --> $DIR/const-expression-suggest-missing-braces.rs:19:11
|
LL | foo::<3 + 3>();
| ^^^^^
| ^ ^
error: expected one of `,` or `>`, found `-`
- --> $DIR/const-expression-suggest-missing-braces.rs:21:15
+ --> $DIR/const-expression-suggest-missing-braces.rs:22:15
|
LL | foo::<BAR - 3>();
| ^ expected one of `,` or `>`
| ^ ^
error: expected one of `,` or `>`, found `-`
- --> $DIR/const-expression-suggest-missing-braces.rs:24:15
+ --> $DIR/const-expression-suggest-missing-braces.rs:25:15
|
LL | foo::<BAR - BAR>();
| ^ expected one of `,` or `>`
| ^ ^
error: expressions must be enclosed in braces to be used as const generic arguments
- --> $DIR/const-expression-suggest-missing-braces.rs:27:11
+ --> $DIR/const-expression-suggest-missing-braces.rs:28:11
|
LL | foo::<100 - BAR>();
| ^^^^^^^^^
| ^ ^
error: expected one of `,` or `>`, found `(`
- --> $DIR/const-expression-suggest-missing-braces.rs:30:19
+ --> $DIR/const-expression-suggest-missing-braces.rs:31:19
|
LL | foo::<bar<i32>()>();
| ^ expected one of `,` or `>`
| ^ ^
error: expected one of `,` or `>`, found `(`
- --> $DIR/const-expression-suggest-missing-braces.rs:33:21
+ --> $DIR/const-expression-suggest-missing-braces.rs:34:21
|
LL | foo::<bar::<i32>()>();
| ^ expected one of `,` or `>`
| ^ ^
error: expected one of `,` or `>`, found `(`
- --> $DIR/const-expression-suggest-missing-braces.rs:36:21
+ --> $DIR/const-expression-suggest-missing-braces.rs:37:21
|
LL | foo::<bar::<i32>() + BAR>();
| ^ expected one of `,` or `>`
| ^ ^
error: expected one of `,` or `>`, found `(`
- --> $DIR/const-expression-suggest-missing-braces.rs:39:21
+ --> $DIR/const-expression-suggest-missing-braces.rs:40:21
|
LL | foo::<bar::<i32>() - BAR>();
| ^ expected one of `,` or `>`
| ^ ^
error: expected one of `,` or `>`, found `-`
- --> $DIR/const-expression-suggest-missing-braces.rs:42:15
+ --> $DIR/const-expression-suggest-missing-braces.rs:43:15
|
LL | foo::<BAR - bar::<i32>()>();
| ^ expected one of `,` or `>`
| ^ ^
error: expected one of `,` or `>`, found `-`
- --> $DIR/const-expression-suggest-missing-braces.rs:45:15
+ --> $DIR/const-expression-suggest-missing-braces.rs:46:15
|
LL | foo::<BAR - bar::<i32>()>();
| ^ expected one of `,` or `>`
| ^^^^^^^^^ help: use `dyn`: `dyn BAR + BAR`
|
= note: `#[warn(bare_trait_objects)]` on by default
+ = 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>
error[E0747]: type provided when a constant was expected
--> $DIR/const-expression-suggest-missing-braces.rs:11:11
--- /dev/null
+#![crate_type="lib"]
+
+struct Example<N>;
+//~^ ERROR parameter
--- /dev/null
+error[E0392]: parameter `N` is never used
+ --> $DIR/unused-type-param-suggestion.rs:3:16
+ |
+LL | struct Example<N>;
+ | ^ unused parameter
+ |
+ = help: consider removing `N`, referring to it in a field, or using a marker such as `PhantomData`
+ = help: if you intended `N` to be a const parameter, use `const N: usize` instead
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0392`.
|
LL | / const OUT_OF_BOUNDS_PTR: NonNull<u8> = { unsafe {
LL | | let ptr: &[u8; 256] = mem::transmute(&0u8); // &0 gets promoted so it does not dangle
-LL | | // Use address-of-element for pointer arithmetic. This could wrap around to NULL!
+LL | | // Use address-of-element for pointer arithmetic. This could wrap around to null!
LL | | let out_of_bounds_ptr = &ptr[255];
| | ^^^^^^^^ memory access failed: pointer must be in-bounds at offset 256, but is outside bounds of alloc10 which has size 1
LL | |
|
LL | / const OUT_OF_BOUNDS_PTR: NonNull<u8> = { unsafe {
LL | | let ptr: &[u8; 256] = mem::transmute(&0u8); // &0 gets promoted so it does not dangle
-LL | | // Use address-of-element for pointer arithmetic. This could wrap around to NULL!
+LL | | // Use address-of-element for pointer arithmetic. This could wrap around to null!
LL | | let out_of_bounds_ptr = &ptr[255];
| | ^^^^^^^^ memory access failed: pointer must be in-bounds at offset 256, but is outside bounds of alloc10 which has size 1
LL | |
#[deny(const_err)] // this triggers a `const_err` so validation does not even happen
const OUT_OF_BOUNDS_PTR: NonNull<u8> = { unsafe {
let ptr: &[u8; 256] = mem::transmute(&0u8); // &0 gets promoted so it does not dangle
- // Use address-of-element for pointer arithmetic. This could wrap around to NULL!
+ // Use address-of-element for pointer arithmetic. This could wrap around to null!
let out_of_bounds_ptr = &ptr[255]; //~ ERROR any use of this value will cause an error
//~| WARN this was previously accepted by the compiler but is being phased out
mem::transmute(out_of_bounds_ptr)
--> $DIR/ub-ref-ptr.rs:21:1
|
LL | const NULL: &u16 = unsafe { mem::transmute(0usize) };
- | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type validation failed: encountered a NULL reference
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type validation failed: 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: 4, align: 4) {
--> $DIR/ub-ref-ptr.rs:24:1
|
LL | const NULL_BOX: Box<u16> = unsafe { mem::transmute(0usize) };
- | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type validation failed: encountered a NULL box
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type validation failed: encountered a null box
|
= 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:21:1
|
LL | const NULL: &u16 = unsafe { mem::transmute(0usize) };
- | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type validation failed: encountered a NULL reference
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type validation failed: 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: 8) {
--> $DIR/ub-ref-ptr.rs:24:1
|
LL | const NULL_BOX: Box<u16> = unsafe { mem::transmute(0usize) };
- | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type validation failed: encountered a NULL box
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type validation failed: encountered a null box
|
= 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) {
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: encountered a null reference at .<deref>.<dyn-downcast>.<captured-var(bad_ref)>
|
= 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: encountered a null reference at .<deref>.<dyn-downcast>.<captured-var(bad_ref)>
|
= 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) {
--- /dev/null
+// edition:2018
+#[deny(bare_trait_objects)]
+
+fn function(x: &SomeTrait, y: Box<SomeTrait>) {
+ //~^ ERROR trait objects without an explicit `dyn` are deprecated
+ //~| WARN this was previously accepted
+ //~| ERROR trait objects without an explicit `dyn` are deprecated
+ //~| WARN this was previously accepted
+ let _x: &SomeTrait = todo!();
+ //~^ ERROR trait objects without an explicit `dyn` are deprecated
+ //~| WARN this was previously accepted
+}
+
+trait SomeTrait {}
+
+fn main() {}
--- /dev/null
+error: trait objects without an explicit `dyn` are deprecated
+ --> $DIR/dyn-2018-edition-lint.rs:4:17
+ |
+LL | fn function(x: &SomeTrait, y: Box<SomeTrait>) {
+ | ^^^^^^^^^ help: use `dyn`: `dyn SomeTrait`
+ |
+note: the lint level is defined here
+ --> $DIR/dyn-2018-edition-lint.rs:2:8
+ |
+LL | #[deny(bare_trait_objects)]
+ | ^^^^^^^^^^^^^^^^^^
+ = 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>
+
+error: trait objects without an explicit `dyn` are deprecated
+ --> $DIR/dyn-2018-edition-lint.rs:4:35
+ |
+LL | fn function(x: &SomeTrait, y: Box<SomeTrait>) {
+ | ^^^^^^^^^ help: use `dyn`: `dyn SomeTrait`
+ |
+ = 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>
+
+error: trait objects without an explicit `dyn` are deprecated
+ --> $DIR/dyn-2018-edition-lint.rs:9:14
+ |
+LL | let _x: &SomeTrait = todo!();
+ | ^^^^^^^^^ help: use `dyn`: `dyn SomeTrait`
+ |
+ = 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>
+
+error: aborting due to 3 previous errors
+
--- /dev/null
+// edition:2021
+
+fn function(x: &SomeTrait, y: Box<SomeTrait>) {
+ //~^ ERROR trait objects must include the `dyn` keyword
+ //~| ERROR trait objects must include the `dyn` keyword
+ let _x: &SomeTrait = todo!();
+ //~^ ERROR trait objects must include the `dyn` keyword
+}
+
+trait SomeTrait {}
+
+fn main() {}
--- /dev/null
+error[E0782]: trait objects must include the `dyn` keyword
+ --> $DIR/dyn-2021-edition-error.rs:6:14
+ |
+LL | let _x: &SomeTrait = todo!();
+ | ^^^^^^^^^
+ |
+help: add `dyn` keyword before this trait
+ |
+LL | let _x: &dyn SomeTrait = todo!();
+ | ^^^
+
+error[E0782]: trait objects must include the `dyn` keyword
+ --> $DIR/dyn-2021-edition-error.rs:3:17
+ |
+LL | fn function(x: &SomeTrait, y: Box<SomeTrait>) {
+ | ^^^^^^^^^
+ |
+help: add `dyn` keyword before this trait
+ |
+LL | fn function(x: &dyn SomeTrait, y: Box<SomeTrait>) {
+ | ^^^
+
+error[E0782]: trait objects must include the `dyn` keyword
+ --> $DIR/dyn-2021-edition-error.rs:3:35
+ |
+LL | fn function(x: &SomeTrait, y: Box<SomeTrait>) {
+ | ^^^^^^^^^
+ |
+help: add `dyn` keyword before this trait
+ |
+LL | fn function(x: &SomeTrait, y: Box<dyn SomeTrait>) {
+ | ^^^
+
+error: aborting due to 3 previous errors
+
+For more information about this error, try `rustc --explain E0782`.
error[E0532]: expected tuple struct or tuple variant, found unit struct `Empty2`
--> $DIR/empty-struct-unit-pat.rs:21:9
|
+LL | struct Empty2;
+ | -------------- `Empty2` defined here
+...
LL | Empty2() => ()
- | ^^^^^^ help: a tuple struct with a similar name exists: `XEmpty6`
+ | ^^^^^^^^
|
::: $DIR/auxiliary/empty-struct.rs:3:1
|
LL | pub struct XEmpty6();
| --------------------- similarly named tuple struct `XEmpty6` defined here
+ |
+help: use this syntax instead
+ |
+LL | Empty2 => ()
+ | ^^^^^^
+help: a tuple struct with a similar name exists
+ |
+LL | XEmpty6() => ()
+ | ^^^^^^^
error[E0532]: expected tuple struct or tuple variant, found unit struct `XEmpty2`
--> $DIR/empty-struct-unit-pat.rs:24:9
|
LL | XEmpty2() => ()
- | ^^^^^^^ help: a tuple struct with a similar name exists: `XEmpty6`
+ | ^^^^^^^^^
|
- ::: $DIR/auxiliary/empty-struct.rs:3:1
+ ::: $DIR/auxiliary/empty-struct.rs:2:1
|
+LL | pub struct XEmpty2;
+ | ------------------- `XEmpty2` defined here
LL | pub struct XEmpty6();
| --------------------- similarly named tuple struct `XEmpty6` defined here
+ |
+help: use this syntax instead
+ |
+LL | XEmpty2 => ()
+ | ^^^^^^^
+help: a tuple struct with a similar name exists
+ |
+LL | XEmpty6() => ()
+ | ^^^^^^^
error[E0532]: expected tuple struct or tuple variant, found unit struct `Empty2`
--> $DIR/empty-struct-unit-pat.rs:28:9
|
+LL | struct Empty2;
+ | -------------- `Empty2` defined here
+...
LL | Empty2(..) => ()
- | ^^^^^^ help: a tuple struct with a similar name exists: `XEmpty6`
+ | ^^^^^^^^^^
|
::: $DIR/auxiliary/empty-struct.rs:3:1
|
LL | pub struct XEmpty6();
| --------------------- similarly named tuple struct `XEmpty6` defined here
+ |
+help: use this syntax instead
+ |
+LL | Empty2 => ()
+ | ^^^^^^
+help: a tuple struct with a similar name exists
+ |
+LL | XEmpty6(..) => ()
+ | ^^^^^^^
error[E0532]: expected tuple struct or tuple variant, found unit struct `XEmpty2`
--> $DIR/empty-struct-unit-pat.rs:32:9
|
LL | XEmpty2(..) => ()
- | ^^^^^^^ help: a tuple struct with a similar name exists: `XEmpty6`
+ | ^^^^^^^^^^^
|
- ::: $DIR/auxiliary/empty-struct.rs:3:1
+ ::: $DIR/auxiliary/empty-struct.rs:2:1
|
+LL | pub struct XEmpty2;
+ | ------------------- `XEmpty2` defined here
LL | pub struct XEmpty6();
| --------------------- similarly named tuple struct `XEmpty6` defined here
+ |
+help: use this syntax instead
+ |
+LL | XEmpty2 => ()
+ | ^^^^^^^
+help: a tuple struct with a similar name exists
+ |
+LL | XEmpty6(..) => ()
+ | ^^^^^^^
error[E0532]: expected tuple struct or tuple variant, found unit variant `E::Empty4`
--> $DIR/empty-struct-unit-pat.rs:37:9
|
+LL | Empty4
+ | ------ `E::Empty4` defined here
+...
LL | E::Empty4() => ()
- | ^^^^^^^^^ not a tuple struct or tuple variant
+ | ^^^^^^^^^^^ help: use this syntax instead: `E::Empty4`
error[E0532]: expected tuple struct or tuple variant, found unit variant `XE::XEmpty4`
--> $DIR/empty-struct-unit-pat.rs:41:9
|
LL | XE::XEmpty4() => (),
- | ^^^^-------
- | |
- | help: a tuple variant with a similar name exists: `XEmpty5`
+ | ^^^^^^^^^^^^^
|
- ::: $DIR/auxiliary/empty-struct.rs:8:5
+ ::: $DIR/auxiliary/empty-struct.rs:7:5
|
+LL | XEmpty4,
+ | ------- `XE::XEmpty4` defined here
LL | XEmpty5(),
| --------- similarly named tuple variant `XEmpty5` defined here
+ |
+help: use this syntax instead
+ |
+LL | XE::XEmpty4 => (),
+ | ^^^^^^^^^^^
+help: a tuple variant with a similar name exists
+ |
+LL | XE::XEmpty5() => (),
+ | ^^^^^^^
error[E0532]: expected tuple struct or tuple variant, found unit variant `E::Empty4`
--> $DIR/empty-struct-unit-pat.rs:46:9
|
+LL | Empty4
+ | ------ `E::Empty4` defined here
+...
LL | E::Empty4(..) => ()
- | ^^^^^^^^^ not a tuple struct or tuple variant
+ | ^^^^^^^^^^^^^ help: use this syntax instead: `E::Empty4`
error[E0532]: expected tuple struct or tuple variant, found unit variant `XE::XEmpty4`
--> $DIR/empty-struct-unit-pat.rs:50:9
|
LL | XE::XEmpty4(..) => (),
- | ^^^^-------
- | |
- | help: a tuple variant with a similar name exists: `XEmpty5`
+ | ^^^^^^^^^^^^^^^
|
- ::: $DIR/auxiliary/empty-struct.rs:8:5
+ ::: $DIR/auxiliary/empty-struct.rs:7:5
|
+LL | XEmpty4,
+ | ------- `XE::XEmpty4` defined here
LL | XEmpty5(),
| --------- similarly named tuple variant `XEmpty5` defined here
+ |
+help: use this syntax instead
+ |
+LL | XE::XEmpty4 => (),
+ | ^^^^^^^^^^^
+help: a tuple variant with a similar name exists
+ |
+LL | XE::XEmpty5(..) => (),
+ | ^^^^^^^
error: aborting due to 8 previous errors
| ^ unused parameter
|
= help: consider removing `T`, referring to it in a field, or using a marker such as `PhantomData`
+ = help: if you intended `T` to be a const parameter, use `const T: usize` instead
error: aborting due to 2 previous errors
| ^ unused parameter
|
= help: consider removing `S`, referring to it in a field, or using a marker such as `PhantomData`
+ = help: if you intended `S` to be a const parameter, use `const S: usize` instead
error: aborting due to 2 previous errors
| ^ unused parameter
|
= help: consider removing `S`, referring to it in a field, or using a marker such as `PhantomData`
+ = help: if you intended `S` to be a const parameter, use `const S: usize` instead
error: aborting due to 2 previous errors
| ^ unused parameter
|
= help: consider removing `T`, referring to it in a field, or using a marker such as `PhantomData`
+ = help: if you intended `T` to be a const parameter, use `const T: usize` instead
error: aborting due to previous error
LL | let x = move || {
| ^^^^^^^ move out of `fancy_num` occurs here
LL | println!("child function: {}", fancy_num.num);
- | --------- move occurs due to use in closure
+ | ------------- move occurs due to use in closure
...
LL | println!("main function: {}", fancy_ref.num);
| ------------- borrow later used here
LL | *(1 as *mut u32) = 42;
| ^^^^^^^^^^^^^^^^^^^^^ 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
+ = 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: aborting due to previous error
LL | let mut b = || {
| -- generator construction occurs here
LL | let a = &mut *x;
- | - first borrow occurs due to use of `x` in generator
+ | -- first borrow occurs due to use of `x` in generator
...
LL | println!("{}", x);
| ^ second borrow occurs here
//~^ ERROR: lifetime in trait object type must be followed by `+`
//~| ERROR: parenthesized generic arguments cannot be used
//~| WARNING: trait objects without an explicit `dyn` are deprecated
+ //~| WARNING: this was previously accepted by the compiler
fn main() {}
| ^^ help: use `dyn`: `dyn 'a`
|
= note: `#[warn(bare_trait_objects)]` on by default
+ = 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>
error[E0107]: this associated type takes 1 lifetime argument but 0 lifetime arguments were supplied
--> $DIR/gat-trait-path-parenthesised-args.rs:5:8
| ^ unused parameter
|
= help: consider removing `T`, referring to it in a field, or using a marker such as `PhantomData`
+ = help: if you intended `T` to be a const parameter, use `const T: usize` instead
error: aborting due to 2 previous errors
| ----------- mutable borrow occurs here
LL | println!("access {}", foo.x);
LL | ptr = box Foo { x: ptr.x + 1 };
- | --- first borrow occurs due to use of `ptr` in closure
+ | --- first borrow occurs due to use of `ptr` in closure
...
LL | test(&*ptr);
| ---- ^^^^^ immutable borrow occurs here
| ^ unused parameter
|
= help: consider removing `T`, referring to it in a field, or using a marker such as `PhantomData`
+ = help: if you intended `T` to be a const parameter, use `const T: usize` instead
error: aborting due to previous error
| ^ unused parameter
|
= help: consider removing `T`, referring to it in a field, or using a marker such as `PhantomData`
+ = help: if you intended `T` to be a const parameter, use `const T: usize` instead
error[E0275]: overflow evaluating the requirement `NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<T>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>: Foo`
--> $DIR/issue-20413.rs:8:36
| - value is immutable in match guard
...
LL | (|| { *x = None; drop(force_fn_once); })();
- | ^^ - borrow occurs due to use of `x` in closure
+ | ^^ -- borrow occurs due to use of `x` in closure
| |
| cannot mutably borrow
| --- value is immutable in match guard
...
LL | (|| { *x = &None; drop(force_fn_once); })();
- | ^^ - borrow occurs due to use of `x` in closure
+ | ^^ -- borrow occurs due to use of `x` in closure
| |
| cannot mutably borrow
error[E0532]: expected tuple struct or tuple variant, found unit struct `S`
--> $DIR/issue-32004.rs:16:9
|
+LL | struct S;
+ | --------- `S` defined here
+...
LL | S(()) => {}
- | ^ not a tuple struct or tuple variant
+ | ^^^^^ help: use this syntax instead: `S`
error: aborting due to 2 previous errors
| ^ unused parameter
|
= help: consider removing `A`, referring to it in a field, or using a marker such as `PhantomData`
+ = help: if you intended `A` to be a const parameter, use `const A: usize` instead
error: aborting due to 2 previous errors
| ^^^^ unused parameter
|
= help: consider removing `Self`, referring to it in a field, or using a marker such as `PhantomData`
+ = help: if you intended `Self` to be a const parameter, use `const Self: usize` instead
error: aborting due to 3 previous errors
| ^ unused parameter
|
= help: consider removing `T`, referring to it in a field, or using a marker such as `PhantomData`
+ = help: if you intended `T` to be a const parameter, use `const T: usize` instead
error: aborting due to 2 previous errors; 1 warning emitted
LL | match *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
+ = 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: aborting due to 2 previous errors
--> $DIR/issue-61623.rs:6:19
|
LL | f2(|| x.0, f1(x.1))
- | -- -- - ^^^ mutable borrow occurs here
+ | -- -- --- ^^^ mutable borrow occurs here
| | | |
| | | first borrow occurs due to use of `x` in closure
| | immutable borrow occurs here
--> $DIR/issue-6801.rs:19:13
|
LL | let sq = || { *x * *x };
- | -- - borrow occurs due to use in closure
+ | -- -- borrow occurs due to use in closure
| |
| borrow of `x` occurs here
LL |
error[E0532]: expected tuple struct or tuple variant, found unit variant `E::A`
--> $DIR/issue-pr29383.rs:9:14
|
+LL | A,
+ | - `E::A` defined here
+...
LL | Some(E::A(..)) => {}
- | ^^^^ not a tuple struct or tuple variant
+ | ^^^^^^^^ help: use this syntax instead: `E::A`
error[E0532]: expected tuple struct or tuple variant, found unit variant `E::B`
--> $DIR/issue-pr29383.rs:11:14
|
+LL | B,
+ | - `E::B` defined here
+...
LL | Some(E::B(..)) => {}
- | ^^^^ not a tuple struct or tuple variant
+ | ^^^^^^^^ help: use this syntax instead: `E::B`
error: aborting due to 2 previous errors
impl Assoc for dyn Dyn {}
fn main() {
- Dyn::func(); //~ WARN trait objects without an explicit `dyn` are deprecated
- ::Dyn::func(); //~ WARN trait objects without an explicit `dyn` are deprecated
- Dyn::CONST; //~ WARN trait objects without an explicit `dyn` are deprecated
+ Dyn::func();
+ //~^ WARN trait objects without an explicit `dyn` are deprecated
+ //~| WARN this was previously accepted by the compiler
+ ::Dyn::func();
+ //~^ WARN trait objects without an explicit `dyn` are deprecated
+ //~| WARN this was previously accepted by the compiler
+ Dyn::CONST;
+ //~^ WARN trait objects without an explicit `dyn` are deprecated
+ //~| WARN this was previously accepted by the compiler
let _: Dyn::Ty; //~ ERROR ambiguous associated type
}
error[E0223]: ambiguous associated type
- --> $DIR/bare-trait-objects-path.rs:17:12
+ --> $DIR/bare-trait-objects-path.rs:23:12
|
LL | let _: Dyn::Ty;
| ^^^^^^^ help: use fully-qualified syntax: `<dyn Dyn as Trait>::Ty`
| ^^^ help: use `dyn`: `<dyn Dyn>`
|
= note: `#[warn(bare_trait_objects)]` on by default
+ = 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: trait objects without an explicit `dyn` are deprecated
- --> $DIR/bare-trait-objects-path.rs:15:5
+ --> $DIR/bare-trait-objects-path.rs:17:5
|
LL | ::Dyn::func();
| ^^^^^ help: use `dyn`: `<dyn (::Dyn)>`
+ |
+ = 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: trait objects without an explicit `dyn` are deprecated
- --> $DIR/bare-trait-objects-path.rs:16:5
+ --> $DIR/bare-trait-objects-path.rs:20:5
|
LL | Dyn::CONST;
| ^^^ help: use `dyn`: `<dyn Dyn>`
+ |
+ = 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>
error: aborting due to previous error; 3 warnings emitted
// Test that attributes on parens get concatenated
// in the expected order in the hir folder.
- #[deny(non_snake_case)] (
- #![allow(non_snake_case)]
+ #[deny(non_snake_case)] #[allow(non_snake_case)] (
{
let X = 0;
let _ = X;
}
);
- #[allow(non_snake_case)] (
- #![deny(non_snake_case)]
+ #[allow(non_snake_case)] #[deny(non_snake_case)] (
{
let X = 0; //~ ERROR snake case name
let _ = X;
error: variable `X` should have a snake case name
- --> $DIR/expr_attr_paren_order.rs:19:17
+ --> $DIR/expr_attr_paren_order.rs:17:17
|
LL | let X = 0;
| ^ help: convert the identifier to snake case (notice the capitalization): `x`
|
note: the lint level is defined here
- --> $DIR/expr_attr_paren_order.rs:17:17
+ --> $DIR/expr_attr_paren_order.rs:15:37
|
-LL | #![deny(non_snake_case)]
- | ^^^^^^^^^^^^^^
+LL | #[allow(non_snake_case)] #[deny(non_snake_case)] (
+ | ^^^^^^^^^^^^^^
error: aborting due to previous error
match despondency {
1..=2 => {}
//~^ WARN `...` range patterns are deprecated
+ //~| WARN this was previously accepted by the compiler
_ => {}
}
match &despondency {
&(1..=2) => {}
//~^ WARN `...` range patterns are deprecated
+ //~| WARN this was previously accepted by the compiler
_ => {}
}
}
match despondency {
1...2 => {}
//~^ WARN `...` range patterns are deprecated
+ //~| WARN this was previously accepted by the compiler
_ => {}
}
match &despondency {
&1...2 => {}
//~^ WARN `...` range patterns are deprecated
+ //~| WARN this was previously accepted by the compiler
_ => {}
}
}
|
LL | #![warn(ellipsis_inclusive_range_patterns)]
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+ = 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: `...` range patterns are deprecated
- --> $DIR/inclusive-range-pattern-syntax.rs:15:9
+ --> $DIR/inclusive-range-pattern-syntax.rs:16:9
|
LL | &1...2 => {}
| ^^^^^^ help: use `..=` for an inclusive range: `&(1..=2)`
+ |
+ = 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: 2 warnings emitted
error[E0532]: expected tuple struct or tuple variant, found unit variant `Color::NoColor`
--> $DIR/match-pattern-field-mismatch-2.rs:12:11
|
+LL | NoColor,
+ | ------- `Color::NoColor` defined here
+...
LL | Color::NoColor(_) => { }
- | ^^^^^^^^^^^^^^ not a tuple struct or tuple variant
+ | ^^^^^^^^^^^^^^^^^ help: use this syntax instead: `Color::NoColor`
error: aborting due to previous error
-error[E0761]: file for module `mod_file_disambig_aux` found at both mod_file_disambig_aux.rs and mod_file_disambig_aux/mod.rs
+error[E0761]: file for module `mod_file_disambig_aux` found at both "$DIR/mod_file_disambig_aux.rs" and "$DIR/mod_file_disambig_aux/mod.rs"
--> $DIR/mod_file_disambig.rs:1:1
|
LL | mod mod_file_disambig_aux;
LL | let r = &mut x;
| ------ borrow occurs here
LL | || *x = 2;
- | ^^ - second borrow occurs due to use of `x` in closure
+ | ^^ -- second borrow occurs due to use of `x` in closure
| |
| closure construction occurs here
LL | r.use_mut();
LL | let r = x;
| - value moved here
LL | || *x = String::new();
- | ^^ - borrow occurs due to use in closure
+ | ^^ -- borrow occurs due to use in closure
| |
| value borrowed here after move
--> $DIR/closure-borrow-spans.rs:65:13
|
LL | let f = || *x = 0;
- | -- - borrow occurs due to use in closure
+ | -- -- borrow occurs due to use in closure
| |
| borrow of `x` occurs here
LL | let y = x;
--> $DIR/closure-borrow-spans.rs:71:13
|
LL | let f = || *x = 0;
- | -- - first borrow occurs due to use of `x` in closure
+ | -- -- first borrow occurs due to use of `x` in closure
| |
| closure construction occurs here
LL | let y = &x;
--> $DIR/closure-borrow-spans.rs:77:13
|
LL | let f = || *x = 0;
- | -- - first borrow occurs due to use of `x` in closure
+ | -- -- first borrow occurs due to use of `x` in closure
| |
| closure construction occurs here
LL | let y = &mut x;
| - first borrow later used here
error[E0597]: `x` does not live long enough
- --> $DIR/closure-borrow-spans.rs:86:17
+ --> $DIR/closure-borrow-spans.rs:86:16
|
LL | f = || *x = 0;
- | -- ^ borrowed value does not live long enough
+ | -- ^^ borrowed value does not live long enough
| |
| value captured here
LL | }
--> $DIR/closure-borrow-spans.rs:93:5
|
LL | let f = || *x = 0;
- | -- - borrow occurs due to use in closure
+ | -- -- borrow occurs due to use in closure
| |
| borrow of `*x` occurs here
LL | *x = 1;
LL | | ||
| | ^^ cannot borrow as mutable
LL | | *x = 1;});
- | |__________-_____- in this closure
- | |
- | mutable borrow occurs due to use of `x` in closure
+ | |_________--_____- in this closure
+ | |
+ | mutable borrow occurs due to use of `x` in closure
error[E0596]: cannot borrow `x` as mutable, as it is a captured variable in a `Fn` closure
--> $DIR/closure-captures.rs:51:9
LL | | ||
| | ^^ cannot borrow as mutable
LL | | *x = 1;});
- | |__________-_____- in this closure
- | |
- | mutable borrow occurs due to use of `x` in closure
+ | |_________--_____- in this closure
+ | |
+ | mutable borrow occurs due to use of `x` in closure
error: aborting due to 12 previous errors
LL | x = 0;
| ^^^^^ assignment to borrowed `x` occurs here
LL | || *y;
- | - borrow later captured here by closure
+ | -- borrow later captured here by closure
error[E0506]: cannot assign to `x` because it is borrowed
--> $DIR/closure-use-spans.rs:11:5
LL | x = 0;
| ^^^^^ assignment to borrowed `x` occurs here
LL | || *y = 1;
- | - borrow later captured here by closure
+ | -- borrow later captured here by closure
error[E0506]: cannot assign to `x` because it is borrowed
--> $DIR/closure-use-spans.rs:17:5
--> $DIR/closures-in-loops.rs:20:16
|
LL | v.push(|| *x = String::new());
- | ^^ - borrows occur due to use of `x` in closure
+ | ^^ -- borrows occur due to use of `x` in closure
| |
| closures are constructed here in different iterations of loop
| |
LL | |
LL | | &self.number;
- | | ---- first borrow occurs due to use of `self` in closure
+ | | ----------- first borrow occurs due to use of `self` in closure
LL | | });
| |__________^ mutable borrow occurs here
// run-pass
// edition:2021
-// ignore-test
-// FIXME(mark-i-m): enable this test again when 2021 machinery is available
use Foo::*;
+#[allow(dead_code)]
#[derive(Eq, PartialEq, Debug)]
enum Foo {
A(u64),
// Tests that :pat in macros in edition 2021 allows top-level or-patterns.
// run-pass
-// ignore-test
// edition:2021
-// FIXME(mark-i-m): unignore when 2021 machinery is in place.
macro_rules! accept_pat {
($p:pat) => {};
//~^ ERROR `?` may only modify trait bounds, not lifetime bounds
//~| ERROR at least one trait is required for an object type
//~| WARN trait objects without an explicit `dyn` are deprecated
+//~| WARN this was previously accepted by the compiler
| ^^^^^^^ help: use `dyn`: `dyn (?'a) +`
|
= note: `#[warn(bare_trait_objects)]` on by default
+ = 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>
error[E0224]: at least one trait is required for an object type
--> $DIR/issue-68890-2.rs:3:14
fn y<'a>(y: &mut 'a + Send) {
//~^ ERROR expected a path on the left-hand side of `+`, not `&mut 'a`
//~| WARNING trait objects without an explicit `dyn` are deprecated
+ //~| WARN this was previously accepted by the compiler
//~| ERROR at least one trait is required for an object type
let z = y as &mut 'a + Send;
//~^ ERROR expected value, found trait `Send`
//~| WARNING trait objects without an explicit `dyn` are deprecated
+ //~| WARN this was previously accepted by the compiler
}
= note: this error originates in a macro (in Nightly builds, run with -Z macro-backtrace for more info)
error[E0423]: expected value, found trait `Send`
- --> $DIR/issue-73568-lifetime-after-mut.rs:18:28
+ --> $DIR/issue-73568-lifetime-after-mut.rs:19:28
|
LL | let z = y as &mut 'a + Send;
| ^^^^ not a value
| ^^ help: use `dyn`: `dyn 'a`
|
= note: `#[warn(bare_trait_objects)]` on by default
+ = 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: trait objects without an explicit `dyn` are deprecated
- --> $DIR/issue-73568-lifetime-after-mut.rs:18:23
+ --> $DIR/issue-73568-lifetime-after-mut.rs:19:23
|
LL | let z = y as &mut 'a + Send;
| ^^ help: use `dyn`: `dyn 'a`
+ |
+ = 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>
error[E0224]: at least one trait is required for an object type
--> $DIR/issue-73568-lifetime-after-mut.rs:14:18
//~^ ERROR lifetime in trait object type must be followed by `+`
//~| ERROR at least one trait is required for an object type
//~| WARN trait objects without an explicit `dyn` are deprecated
+ //~| WARN this was previously accepted by the compiler
}
| ^^^^^^^ help: use `dyn`: `dyn 'static`
|
= note: `#[warn(bare_trait_objects)]` on by default
+ = 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>
error[E0224]: at least one trait is required for an object type
--> $DIR/trait-object-macro-matcher.rs:11:8
}
fn inclusive2_from_to() {
- if let 0...3 = 0 {} //~ ERROR `...` range patterns are deprecated
- if let 0...Y = 0 {} //~ ERROR `...` range patterns are deprecated
- if let X...3 = 0 {} //~ ERROR `...` range patterns are deprecated
- if let X...Y = 0 {} //~ ERROR `...` range patterns are deprecated
+ if let 0...3 = 0 {}
+ //~^ ERROR `...` range patterns are deprecated
+ //~| WARN this was previously accepted by the compiler
+ if let 0...Y = 0 {}
+ //~^ ERROR `...` range patterns are deprecated
+ //~| WARN this was previously accepted by the compiler
+ if let X...3 = 0 {}
+ //~^ ERROR `...` range patterns are deprecated
+ //~| WARN this was previously accepted by the compiler
+ if let X...Y = 0 {}
+ //~^ ERROR `...` range patterns are deprecated
+ //~| WARN this was previously accepted by the compiler
if let true...Y = 0 {} //~ ERROR only `char` and numeric types
//~^ ERROR `...` range patterns are deprecated
+ //~| WARN this was previously accepted by the compiler
if let X...true = 0 {} //~ ERROR only `char` and numeric types
//~^ ERROR `...` range patterns are deprecated
+ //~| WARN this was previously accepted by the compiler
if let .0...Y = 0 {} //~ ERROR mismatched types
//~^ ERROR float literals must have an integer part
+ //~| WARN this was previously accepted by the compiler
//~| ERROR `...` range patterns are deprecated
if let X... .0 = 0 {} //~ ERROR mismatched types
//~^ ERROR float literals must have an integer part
//~| ERROR `...` range patterns are deprecated
+ //~| WARN this was previously accepted by the compiler
}
fn exclusive_from() {
let $e1..$e2;
let $e1...$e2;
//~^ ERROR `...` range patterns are deprecated
+ //~| WARN this was previously accepted by the compiler
let $e1..=$e2;
}
}
| ^^ help: must have an integer part: `0.0`
error: float literals must have an integer part
- --> $DIR/recover-range-pats.rs:50:12
+ --> $DIR/recover-range-pats.rs:60:12
|
LL | if let .0...Y = 0 {}
| ^^ help: must have an integer part: `0.0`
error: float literals must have an integer part
- --> $DIR/recover-range-pats.rs:53:17
+ --> $DIR/recover-range-pats.rs:64:17
|
LL | if let X... .0 = 0 {}
| ^^ help: must have an integer part: `0.0`
error: float literals must have an integer part
- --> $DIR/recover-range-pats.rs:63:12
+ --> $DIR/recover-range-pats.rs:75:12
|
LL | if let .0.. = 0 {}
| ^^ help: must have an integer part: `0.0`
error[E0586]: inclusive range with no end
- --> $DIR/recover-range-pats.rs:69:13
+ --> $DIR/recover-range-pats.rs:81:13
|
LL | if let 0..= = 0 {}
| ^^^ help: use `..` instead
= note: inclusive ranges must be bounded at the end (`..=b` or `a..=b`)
error[E0586]: inclusive range with no end
- --> $DIR/recover-range-pats.rs:70:13
+ --> $DIR/recover-range-pats.rs:82:13
|
LL | if let X..= = 0 {}
| ^^^ help: use `..` instead
= note: inclusive ranges must be bounded at the end (`..=b` or `a..=b`)
error[E0586]: inclusive range with no end
- --> $DIR/recover-range-pats.rs:71:16
+ --> $DIR/recover-range-pats.rs:83:16
|
LL | if let true..= = 0 {}
| ^^^ help: use `..` instead
= note: inclusive ranges must be bounded at the end (`..=b` or `a..=b`)
error: float literals must have an integer part
- --> $DIR/recover-range-pats.rs:73:12
+ --> $DIR/recover-range-pats.rs:85:12
|
LL | if let .0..= = 0 {}
| ^^ help: must have an integer part: `0.0`
error[E0586]: inclusive range with no end
- --> $DIR/recover-range-pats.rs:73:14
+ --> $DIR/recover-range-pats.rs:85:14
|
LL | if let .0..= = 0 {}
| ^^^ help: use `..` instead
= note: inclusive ranges must be bounded at the end (`..=b` or `a..=b`)
error[E0586]: inclusive range with no end
- --> $DIR/recover-range-pats.rs:79:13
+ --> $DIR/recover-range-pats.rs:91:13
|
LL | if let 0... = 0 {}
| ^^^ help: use `..` instead
= note: inclusive ranges must be bounded at the end (`..=b` or `a..=b`)
error[E0586]: inclusive range with no end
- --> $DIR/recover-range-pats.rs:80:13
+ --> $DIR/recover-range-pats.rs:92:13
|
LL | if let X... = 0 {}
| ^^^ help: use `..` instead
= note: inclusive ranges must be bounded at the end (`..=b` or `a..=b`)
error[E0586]: inclusive range with no end
- --> $DIR/recover-range-pats.rs:81:16
+ --> $DIR/recover-range-pats.rs:93:16
|
LL | if let true... = 0 {}
| ^^^ help: use `..` instead
= note: inclusive ranges must be bounded at the end (`..=b` or `a..=b`)
error: float literals must have an integer part
- --> $DIR/recover-range-pats.rs:83:12
+ --> $DIR/recover-range-pats.rs:95:12
|
LL | if let .0... = 0 {}
| ^^ help: must have an integer part: `0.0`
error[E0586]: inclusive range with no end
- --> $DIR/recover-range-pats.rs:83:14
+ --> $DIR/recover-range-pats.rs:95:14
|
LL | if let .0... = 0 {}
| ^^^ help: use `..` instead
= note: inclusive ranges must be bounded at the end (`..=b` or `a..=b`)
error: float literals must have an integer part
- --> $DIR/recover-range-pats.rs:93:15
+ --> $DIR/recover-range-pats.rs:105:15
|
LL | if let .. .0 = 0 {}
| ^^ help: must have an integer part: `0.0`
error: float literals must have an integer part
- --> $DIR/recover-range-pats.rs:103:15
+ --> $DIR/recover-range-pats.rs:115:15
|
LL | if let ..=.0 = 0 {}
| ^^ help: must have an integer part: `0.0`
error: range-to patterns with `...` are not allowed
- --> $DIR/recover-range-pats.rs:109:12
+ --> $DIR/recover-range-pats.rs:121:12
|
LL | if let ...3 = 0 {}
| ^^^ help: use `..=` instead
error: range-to patterns with `...` are not allowed
- --> $DIR/recover-range-pats.rs:111:12
+ --> $DIR/recover-range-pats.rs:123:12
|
LL | if let ...Y = 0 {}
| ^^^ help: use `..=` instead
error: range-to patterns with `...` are not allowed
- --> $DIR/recover-range-pats.rs:113:12
+ --> $DIR/recover-range-pats.rs:125:12
|
LL | if let ...true = 0 {}
| ^^^ help: use `..=` instead
error: float literals must have an integer part
- --> $DIR/recover-range-pats.rs:116:15
+ --> $DIR/recover-range-pats.rs:128:15
|
LL | if let ....3 = 0 {}
| ^^ help: must have an integer part: `0.3`
error: range-to patterns with `...` are not allowed
- --> $DIR/recover-range-pats.rs:116:12
+ --> $DIR/recover-range-pats.rs:128:12
|
LL | if let ....3 = 0 {}
| ^^^ help: use `..=` instead
error: range-to patterns with `...` are not allowed
- --> $DIR/recover-range-pats.rs:137:17
+ --> $DIR/recover-range-pats.rs:150:17
|
LL | let ...$e;
| ^^^ help: use `..=` instead
= note: this error originates in a macro (in Nightly builds, run with -Z macro-backtrace for more info)
error[E0586]: inclusive range with no end
- --> $DIR/recover-range-pats.rs:141:19
+ --> $DIR/recover-range-pats.rs:154:19
|
LL | let $e...;
| ^^^ help: use `..` instead
= note: this error originates in a macro (in Nightly builds, run with -Z macro-backtrace for more info)
error[E0586]: inclusive range with no end
- --> $DIR/recover-range-pats.rs:142:19
+ --> $DIR/recover-range-pats.rs:155:19
|
LL | let $e..=;
| ^^^ help: use `..` instead
|
LL | #![deny(ellipsis_inclusive_range_patterns)]
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+ = 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>
error: `...` range patterns are deprecated
- --> $DIR/recover-range-pats.rs:43:13
+ --> $DIR/recover-range-pats.rs:45:13
|
LL | if let 0...Y = 0 {}
| ^^^ help: use `..=` for an inclusive range
+ |
+ = 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>
error: `...` range patterns are deprecated
- --> $DIR/recover-range-pats.rs:44:13
+ --> $DIR/recover-range-pats.rs:48:13
|
LL | if let X...3 = 0 {}
| ^^^ help: use `..=` for an inclusive range
+ |
+ = 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>
error: `...` range patterns are deprecated
- --> $DIR/recover-range-pats.rs:45:13
+ --> $DIR/recover-range-pats.rs:51:13
|
LL | if let X...Y = 0 {}
| ^^^ help: use `..=` for an inclusive range
+ |
+ = 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>
error: `...` range patterns are deprecated
- --> $DIR/recover-range-pats.rs:46:16
+ --> $DIR/recover-range-pats.rs:54:16
|
LL | if let true...Y = 0 {}
| ^^^ help: use `..=` for an inclusive range
+ |
+ = 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>
error: `...` range patterns are deprecated
- --> $DIR/recover-range-pats.rs:48:13
+ --> $DIR/recover-range-pats.rs:57:13
|
LL | if let X...true = 0 {}
| ^^^ help: use `..=` for an inclusive range
+ |
+ = 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>
error: `...` range patterns are deprecated
- --> $DIR/recover-range-pats.rs:50:14
+ --> $DIR/recover-range-pats.rs:60:14
|
LL | if let .0...Y = 0 {}
| ^^^ help: use `..=` for an inclusive range
+ |
+ = 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>
error: `...` range patterns are deprecated
- --> $DIR/recover-range-pats.rs:53:13
+ --> $DIR/recover-range-pats.rs:64:13
|
LL | if let X... .0 = 0 {}
| ^^^ help: use `..=` for an inclusive range
+ |
+ = 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>
error: `...` range patterns are deprecated
- --> $DIR/recover-range-pats.rs:126:20
+ --> $DIR/recover-range-pats.rs:138:20
|
LL | let $e1...$e2;
| ^^^ help: use `..=` for an inclusive range
LL | mac2!(0, 1);
| ------------ in this macro invocation
|
+ = 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>
= note: this error originates in a macro (in Nightly builds, run with -Z macro-backtrace for more info)
error[E0029]: only `char` and numeric types are allowed in range patterns
| this is of type `u8`
error[E0029]: only `char` and numeric types are allowed in range patterns
- --> $DIR/recover-range-pats.rs:46:12
+ --> $DIR/recover-range-pats.rs:54:12
|
LL | if let true...Y = 0 {}
| ^^^^ - this is of type `u8`
| this is of type `bool` but it should be `char` or numeric
error[E0029]: only `char` and numeric types are allowed in range patterns
- --> $DIR/recover-range-pats.rs:48:16
+ --> $DIR/recover-range-pats.rs:57:16
|
LL | if let X...true = 0 {}
| - ^^^^ this is of type `bool` but it should be `char` or numeric
| this is of type `u8`
error[E0308]: mismatched types
- --> $DIR/recover-range-pats.rs:50:12
+ --> $DIR/recover-range-pats.rs:60:12
|
LL | if let .0...Y = 0 {}
| ^^ - this is of type `u8`
| expected integer, found floating-point number
error[E0308]: mismatched types
- --> $DIR/recover-range-pats.rs:53:17
+ --> $DIR/recover-range-pats.rs:64:17
|
LL | if let X... .0 = 0 {}
| - ^^ - this expression has type `u8`
| this is of type `u8`
error[E0029]: only `char` and numeric types are allowed in range patterns
- --> $DIR/recover-range-pats.rs:61:12
+ --> $DIR/recover-range-pats.rs:73:12
|
LL | if let true.. = 0 {}
| ^^^^ this is of type `bool` but it should be `char` or numeric
error[E0308]: mismatched types
- --> $DIR/recover-range-pats.rs:63:12
+ --> $DIR/recover-range-pats.rs:75:12
|
LL | if let .0.. = 0 {}
| ^^ expected integer, found floating-point number
error[E0029]: only `char` and numeric types are allowed in range patterns
- --> $DIR/recover-range-pats.rs:71:12
+ --> $DIR/recover-range-pats.rs:83:12
|
LL | if let true..= = 0 {}
| ^^^^ this is of type `bool` but it should be `char` or numeric
error[E0308]: mismatched types
- --> $DIR/recover-range-pats.rs:73:12
+ --> $DIR/recover-range-pats.rs:85:12
|
LL | if let .0..= = 0 {}
| ^^ expected integer, found floating-point number
error[E0029]: only `char` and numeric types are allowed in range patterns
- --> $DIR/recover-range-pats.rs:81:12
+ --> $DIR/recover-range-pats.rs:93:12
|
LL | if let true... = 0 {}
| ^^^^ this is of type `bool` but it should be `char` or numeric
error[E0308]: mismatched types
- --> $DIR/recover-range-pats.rs:83:12
+ --> $DIR/recover-range-pats.rs:95:12
|
LL | if let .0... = 0 {}
| ^^ expected integer, found floating-point number
error[E0029]: only `char` and numeric types are allowed in range patterns
- --> $DIR/recover-range-pats.rs:91:14
+ --> $DIR/recover-range-pats.rs:103:14
|
LL | if let ..true = 0 {}
| ^^^^ this is of type `bool` but it should be `char` or numeric
error[E0308]: mismatched types
- --> $DIR/recover-range-pats.rs:93:15
+ --> $DIR/recover-range-pats.rs:105:15
|
LL | if let .. .0 = 0 {}
| ^^ expected integer, found floating-point number
error[E0029]: only `char` and numeric types are allowed in range patterns
- --> $DIR/recover-range-pats.rs:101:15
+ --> $DIR/recover-range-pats.rs:113:15
|
LL | if let ..=true = 0 {}
| ^^^^ this is of type `bool` but it should be `char` or numeric
error[E0308]: mismatched types
- --> $DIR/recover-range-pats.rs:103:15
+ --> $DIR/recover-range-pats.rs:115:15
|
LL | if let ..=.0 = 0 {}
| ^^ expected integer, found floating-point number
error[E0029]: only `char` and numeric types are allowed in range patterns
- --> $DIR/recover-range-pats.rs:113:15
+ --> $DIR/recover-range-pats.rs:125:15
|
LL | if let ...true = 0 {}
| ^^^^ this is of type `bool` but it should be `char` or numeric
error[E0308]: mismatched types
- --> $DIR/recover-range-pats.rs:116:15
+ --> $DIR/recover-range-pats.rs:128:15
|
LL | if let ....3 = 0 {}
| ^^ expected integer, found floating-point number
//~^ ERROR an inner attribute is not permitted in this context
let b = (#![allow(warnings)] 1, 2);
+ //~^ ERROR an inner attribute is not permitted in this context
let c = {
#![allow(warnings)]
(#![allow(warnings)] 1, 2)
+ //~^ ERROR an inner attribute is not permitted in this context
};
let d = {
#![allow(warnings)]
let e = (#![allow(warnings)] 1, 2);
+ //~^ ERROR an inner attribute is not permitted in this context
e
};
+
+ let e = [#![allow(warnings)] 1, 2];
+ //~^ ERROR an inner attribute is not permitted in this context
+
+ let f = [#![allow(warnings)] 1; 0];
+ //~^ ERROR an inner attribute is not permitted in this context
+
+ let g = match true { #![allow(warnings)] _ => {} };
+ //~^ ERROR an inner attribute is not permitted in this context
+
+ struct MyStruct { field: u8 }
+ let h = MyStruct { #![allow(warnings)] field: 0 };
+ //~^ ERROR an inner attribute is not permitted in this context
}
|
= note: inner attributes, like `#![no_std]`, annotate the item enclosing them, and are usually found at the beginning of source files. Outer attributes, like `#[test]`, annotate the item following them.
-error: aborting due to previous error
+error: an inner attribute is not permitted in this context
+ --> $DIR/stmt_expr_attrs_placement.rs:10:14
+ |
+LL | let b = (#![allow(warnings)] 1, 2);
+ | ^^^^^^^^^^^^^^^^^^^
+ |
+ = note: inner attributes, like `#![no_std]`, annotate the item enclosing them, and are usually found at the beginning of source files. Outer attributes, like `#[test]`, annotate the item following them.
+
+error: an inner attribute is not permitted in this context
+ --> $DIR/stmt_expr_attrs_placement.rs:15:10
+ |
+LL | (#![allow(warnings)] 1, 2)
+ | ^^^^^^^^^^^^^^^^^^^
+ |
+ = note: inner attributes, like `#![no_std]`, annotate the item enclosing them, and are usually found at the beginning of source files. Outer attributes, like `#[test]`, annotate the item following them.
+
+error: an inner attribute is not permitted in this context
+ --> $DIR/stmt_expr_attrs_placement.rs:21:18
+ |
+LL | let e = (#![allow(warnings)] 1, 2);
+ | ^^^^^^^^^^^^^^^^^^^
+ |
+ = note: inner attributes, like `#![no_std]`, annotate the item enclosing them, and are usually found at the beginning of source files. Outer attributes, like `#[test]`, annotate the item following them.
+
+error: an inner attribute is not permitted in this context
+ --> $DIR/stmt_expr_attrs_placement.rs:26:14
+ |
+LL | let e = [#![allow(warnings)] 1, 2];
+ | ^^^^^^^^^^^^^^^^^^^
+ |
+ = note: inner attributes, like `#![no_std]`, annotate the item enclosing them, and are usually found at the beginning of source files. Outer attributes, like `#[test]`, annotate the item following them.
+
+error: an inner attribute is not permitted in this context
+ --> $DIR/stmt_expr_attrs_placement.rs:29:14
+ |
+LL | let f = [#![allow(warnings)] 1; 0];
+ | ^^^^^^^^^^^^^^^^^^^
+ |
+ = note: inner attributes, like `#![no_std]`, annotate the item enclosing them, and are usually found at the beginning of source files. Outer attributes, like `#[test]`, annotate the item following them.
+
+error: an inner attribute is not permitted in this context
+ --> $DIR/stmt_expr_attrs_placement.rs:32:26
+ |
+LL | let g = match true { #![allow(warnings)] _ => {} };
+ | ^^^^^^^^^^^^^^^^^^^
+ |
+ = note: inner attributes, like `#![no_std]`, annotate the item enclosing them, and are usually found at the beginning of source files. Outer attributes, like `#[test]`, annotate the item following them.
+
+error: an inner attribute is not permitted in this context
+ --> $DIR/stmt_expr_attrs_placement.rs:36:24
+ |
+LL | let h = MyStruct { #![allow(warnings)] field: 0 };
+ | ^^^^^^^^^^^^^^^^^^^
+ |
+ = note: inner attributes, like `#![no_std]`, annotate the item enclosing them, and are usually found at the beginning of source files. Outer attributes, like `#[test]`, annotate the item following them.
+
+error: aborting due to 8 previous errors
//~^ ERROR `?Trait` is not permitted in trait object types
//~| ERROR only auto traits can be used as additional traits
//~| WARN trait objects without an explicit `dyn` are deprecated
- let _: Box<(?Sized) + (for<'a> Trait<'a>) + (Obj)>;
+ //~| WARN this was previously accepted by the compiler
+ let _: Box<?Sized + (for<'a> Trait<'a>) + (Obj)>;
//~^ ERROR `?Trait` is not permitted in trait object types
//~| ERROR only auto traits can be used as additional traits
//~| WARN trait objects without an explicit `dyn` are deprecated
- let _: Box<(for<'a> Trait<'a>) + (Obj) + (?Sized)>;
+ //~| WARN this was previously accepted by the compiler
+ let _: Box<for<'a> Trait<'a> + (Obj) + (?Sized)>;
//~^ ERROR `?Trait` is not permitted in trait object types
//~| ERROR only auto traits can be used as additional traits
//~| WARN trait objects without an explicit `dyn` are deprecated
+ //~| WARN this was previously accepted by the compiler
}
| ^^^^^^^^
error: `?Trait` is not permitted in trait object types
- --> $DIR/trait-object-trait-parens.rs:12:17
+ --> $DIR/trait-object-trait-parens.rs:13:16
|
-LL | let _: Box<(?Sized) + (for<'a> Trait<'a>) + (Obj)>;
- | ^^^^^^
+LL | let _: Box<?Sized + (for<'a> Trait<'a>) + (Obj)>;
+ | ^^^^^^
error: `?Trait` is not permitted in trait object types
- --> $DIR/trait-object-trait-parens.rs:16:46
+ --> $DIR/trait-object-trait-parens.rs:18:44
|
-LL | let _: Box<(for<'a> Trait<'a>) + (Obj) + (?Sized)>;
- | ^^^^^^^^
+LL | let _: Box<for<'a> Trait<'a> + (Obj) + (?Sized)>;
+ | ^^^^^^^^
warning: trait objects without an explicit `dyn` are deprecated
--> $DIR/trait-object-trait-parens.rs:8:16
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use `dyn`: `dyn (Obj) + (?Sized) + (for<'a> Trait<'a>)`
|
= note: `#[warn(bare_trait_objects)]` on by default
+ = 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: trait objects without an explicit `dyn` are deprecated
- --> $DIR/trait-object-trait-parens.rs:12:16
+ --> $DIR/trait-object-trait-parens.rs:13:16
|
-LL | let _: Box<(?Sized) + (for<'a> Trait<'a>) + (Obj)>;
- | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use `dyn`: `dyn (?Sized) + (for<'a> Trait<'a>) + (Obj)`
+LL | let _: Box<?Sized + (for<'a> Trait<'a>) + (Obj)>;
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use `dyn`: `dyn ?Sized + (for<'a> Trait<'a>) + (Obj)`
+ |
+ = 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: trait objects without an explicit `dyn` are deprecated
- --> $DIR/trait-object-trait-parens.rs:16:16
+ --> $DIR/trait-object-trait-parens.rs:18:16
+ |
+LL | let _: Box<for<'a> Trait<'a> + (Obj) + (?Sized)>;
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use `dyn`: `dyn for<'a> Trait<'a> + (Obj) + (?Sized)`
|
-LL | let _: Box<(for<'a> Trait<'a>) + (Obj) + (?Sized)>;
- | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use `dyn`: `dyn (for<'a> Trait<'a>) + (Obj) + (?Sized)`
+ = 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>
error[E0225]: only auto traits can be used as additional traits in a trait object
--> $DIR/trait-object-trait-parens.rs:8:35
= note: auto-traits like `Send` and `Sync` are traits that have special properties; for more information on them, visit <https://doc.rust-lang.org/reference/special-types-and-traits.html#auto-traits>
error[E0225]: only auto traits can be used as additional traits in a trait object
- --> $DIR/trait-object-trait-parens.rs:12:49
+ --> $DIR/trait-object-trait-parens.rs:13:47
|
-LL | let _: Box<(?Sized) + (for<'a> Trait<'a>) + (Obj)>;
- | ------------------- ^^^^^ additional non-auto trait
- | |
- | first non-auto trait
+LL | let _: Box<?Sized + (for<'a> Trait<'a>) + (Obj)>;
+ | ------------------- ^^^^^ additional non-auto trait
+ | |
+ | first non-auto trait
|
= help: consider creating a new trait with all of these as super-traits and using that trait here instead: `trait NewTrait: for<'a> Trait<'a> + Obj {}`
= note: auto-traits like `Send` and `Sync` are traits that have special properties; for more information on them, visit <https://doc.rust-lang.org/reference/special-types-and-traits.html#auto-traits>
error[E0225]: only auto traits can be used as additional traits in a trait object
- --> $DIR/trait-object-trait-parens.rs:16:38
+ --> $DIR/trait-object-trait-parens.rs:18:36
|
-LL | let _: Box<(for<'a> Trait<'a>) + (Obj) + (?Sized)>;
- | ----------------- ^^^^^ additional non-auto trait
- | |
- | first non-auto trait
+LL | let _: Box<for<'a> Trait<'a> + (Obj) + (?Sized)>;
+ | ----------------- ^^^^^ additional non-auto trait
+ | |
+ | first non-auto trait
|
= help: consider creating a new trait with all of these as super-traits and using that trait here instead: `trait NewTrait: for<'a> Trait<'a> + Obj {}`
= note: auto-traits like `Send` and `Sync` are traits that have special properties; for more information on them, visit <https://doc.rust-lang.org/reference/special-types-and-traits.html#auto-traits>
|
LL | B(isize, isize),
| --------------- similarly named tuple variant `B` defined here
+LL | C(isize, isize, isize),
+LL | D
+ | - `A::D` defined here
...
LL | A::D(_) => (),
- | ^^^-
- | |
- | help: a tuple variant with a similar name exists: `B`
+ | ^^^^^^^
+ |
+help: use this syntax instead
+ |
+LL | A::D => (),
+ | ^^^^
+help: a tuple variant with a similar name exists
+ |
+LL | A::B(_) => (),
+ | ^
error[E0023]: this pattern has 3 fields, but the corresponding tuple variant has 2 fields
--> $DIR/pattern-error-continue.rs:17:9
// compile-flags: -Z span-debug --error-format human
// aux-build:test-macros.rs
// edition:2018
+
#![feature(custom_inner_attributes)]
#![feature(proc_macro_hygiene)]
#![feature(stmt_expr_attributes)]
struct MyDerivePrint {
field: [u8; {
match true {
- #![cfg_attr(not(FALSE), rustc_dummy(first))]
- #![cfg_attr(not(FALSE), rustc_dummy(second))]
_ => {
#![cfg_attr(not(FALSE), rustc_dummy(third))]
true
}
fn bar() {
- (#![print_target_and_args(fifth)] 1, 2);
- //~^ ERROR expected non-macro inner attribute, found attribute macro
-
#[print_target_and_args(tuple_attrs)] (
- #![cfg_attr(FALSE, rustc_dummy)]
3, 4, {
#![cfg_attr(not(FALSE), rustc_dummy(innermost))]
5
}
);
- #[print_target_and_args(array_attrs)] [
- #![rustc_dummy(inner)]
- true; 0
- ];
-
#[print_target_and_args(tuple_attrs)] (
- #![cfg_attr(FALSE, rustc_dummy)]
3, 4, {
#![cfg_attr(not(FALSE), rustc_dummy(innermost))]
5
}
);
- #[print_target_and_args(array_attrs)] [
- #![rustc_dummy(inner)]
- true; 0
- ];
-
- [#![print_target_and_args(sixth)] 1 , 2];
- //~^ ERROR expected non-macro inner attribute, found attribute macro
- [#![print_target_and_args(seventh)] true ; 5];
- //~^ ERROR expected non-macro inner attribute, found attribute macro
-
- match 0 {
- #![print_target_and_args(eighth)]
- //~^ ERROR expected non-macro inner attribute, found attribute macro
- _ => {}
- }
-
- MyStruct { #![print_target_and_args(ninth)] field: true };
- //~^ ERROR expected non-macro inner attribute, found attribute macro
-
for _ in &[true] {
#![print_attr] //~ ERROR expected non-macro inner attribute
}
-error: expected non-macro inner attribute, found attribute macro `print_target_and_args`
- --> $DIR/inner-attrs.rs:49:9
- |
-LL | (#![print_target_and_args(fifth)] 1, 2);
- | ^^^^^^^^^^^^^^^^^^^^^ not a non-macro inner attribute
-
-error: expected non-macro inner attribute, found attribute macro `print_target_and_args`
- --> $DIR/inner-attrs.rs:78:9
- |
-LL | [#![print_target_and_args(sixth)] 1 , 2];
- | ^^^^^^^^^^^^^^^^^^^^^ not a non-macro inner attribute
-
-error: expected non-macro inner attribute, found attribute macro `print_target_and_args`
- --> $DIR/inner-attrs.rs:80:9
- |
-LL | [#![print_target_and_args(seventh)] true ; 5];
- | ^^^^^^^^^^^^^^^^^^^^^ not a non-macro inner attribute
-
-error: expected non-macro inner attribute, found attribute macro `print_target_and_args`
- --> $DIR/inner-attrs.rs:84:12
- |
-LL | #![print_target_and_args(eighth)]
- | ^^^^^^^^^^^^^^^^^^^^^ not a non-macro inner attribute
-
-error: expected non-macro inner attribute, found attribute macro `print_target_and_args`
- --> $DIR/inner-attrs.rs:89:19
- |
-LL | MyStruct { #![print_target_and_args(ninth)] field: true };
- | ^^^^^^^^^^^^^^^^^^^^^ not a non-macro inner attribute
-
error: expected non-macro inner attribute, found attribute macro `print_attr`
- --> $DIR/inner-attrs.rs:93:12
+ --> $DIR/inner-attrs.rs:63:12
|
LL | #![print_attr]
| ^^^^^^^^^^ not a non-macro inner attribute
error: expected non-macro inner attribute, found attribute macro `print_attr`
- --> $DIR/inner-attrs.rs:97:12
+ --> $DIR/inner-attrs.rs:67:12
|
LL | #![print_attr]
| ^^^^^^^^^^ not a non-macro inner attribute
error: expected non-macro inner attribute, found attribute macro `print_attr`
- --> $DIR/inner-attrs.rs:101:12
+ --> $DIR/inner-attrs.rs:71:12
|
LL | #![print_attr]
| ^^^^^^^^^^ not a non-macro inner attribute
error: expected non-macro inner attribute, found attribute macro `print_attr`
- --> $DIR/inner-attrs.rs:105:12
+ --> $DIR/inner-attrs.rs:75:12
|
LL | #![print_attr]
| ^^^^^^^^^^ not a non-macro inner attribute
-error: aborting due to 9 previous errors
+error: aborting due to 4 previous errors
PRINT-ATTR_ARGS INPUT (DEBUG): TokenStream [
Ident {
ident: "first",
- span: $DIR/inner-attrs.rs:15:25: 15:30 (#0),
+ span: $DIR/inner-attrs.rs:16:25: 16:30 (#0),
},
]
PRINT-ATTR INPUT (DISPLAY): #[print_target_and_args(second)] fn foo()
Punct {
ch: '#',
spacing: Alone,
- span: $DIR/inner-attrs.rs:16:1: 16:2 (#0),
+ span: $DIR/inner-attrs.rs:17:1: 17:2 (#0),
},
Group {
delimiter: Bracket,
stream: TokenStream [
Ident {
ident: "print_target_and_args",
- span: $DIR/inner-attrs.rs:16:3: 16:24 (#0),
+ span: $DIR/inner-attrs.rs:17:3: 17:24 (#0),
},
Group {
delimiter: Parenthesis,
stream: TokenStream [
Ident {
ident: "second",
- span: $DIR/inner-attrs.rs:16:25: 16:31 (#0),
+ span: $DIR/inner-attrs.rs:17:25: 17:31 (#0),
},
],
- span: $DIR/inner-attrs.rs:16:24: 16:32 (#0),
+ span: $DIR/inner-attrs.rs:17:24: 17:32 (#0),
},
],
- span: $DIR/inner-attrs.rs:16:2: 16:33 (#0),
+ span: $DIR/inner-attrs.rs:17:2: 17:33 (#0),
},
Ident {
ident: "fn",
- span: $DIR/inner-attrs.rs:17:1: 17:3 (#0),
+ span: $DIR/inner-attrs.rs:18:1: 18:3 (#0),
},
Ident {
ident: "foo",
- span: $DIR/inner-attrs.rs:17:4: 17:7 (#0),
+ span: $DIR/inner-attrs.rs:18:4: 18:7 (#0),
},
Group {
delimiter: Parenthesis,
stream: TokenStream [],
- span: $DIR/inner-attrs.rs:17:7: 17:9 (#0),
+ span: $DIR/inner-attrs.rs:18:7: 18:9 (#0),
},
Group {
delimiter: Brace,
Punct {
ch: '#',
spacing: Joint,
- span: $DIR/inner-attrs.rs:18:5: 18:6 (#0),
+ span: $DIR/inner-attrs.rs:19:5: 19:6 (#0),
},
Punct {
ch: '!',
spacing: Alone,
- span: $DIR/inner-attrs.rs:18:6: 18:7 (#0),
+ span: $DIR/inner-attrs.rs:19:6: 19:7 (#0),
},
Group {
delimiter: Bracket,
stream: TokenStream [
Ident {
ident: "print_target_and_args",
- span: $DIR/inner-attrs.rs:18:8: 18:29 (#0),
+ span: $DIR/inner-attrs.rs:19:8: 19:29 (#0),
},
Group {
delimiter: Parenthesis,
stream: TokenStream [
Ident {
ident: "third",
- span: $DIR/inner-attrs.rs:18:30: 18:35 (#0),
+ span: $DIR/inner-attrs.rs:19:30: 19:35 (#0),
},
],
- span: $DIR/inner-attrs.rs:18:29: 18:36 (#0),
+ span: $DIR/inner-attrs.rs:19:29: 19:36 (#0),
},
],
- span: $DIR/inner-attrs.rs:18:7: 18:37 (#0),
+ span: $DIR/inner-attrs.rs:19:7: 19:37 (#0),
},
Punct {
ch: '#',
spacing: Joint,
- span: $DIR/inner-attrs.rs:19:5: 19:6 (#0),
+ span: $DIR/inner-attrs.rs:20:5: 20:6 (#0),
},
Punct {
ch: '!',
spacing: Alone,
- span: $DIR/inner-attrs.rs:19:6: 19:7 (#0),
+ span: $DIR/inner-attrs.rs:20:6: 20:7 (#0),
},
Group {
delimiter: Bracket,
stream: TokenStream [
Ident {
ident: "print_target_and_args",
- span: $DIR/inner-attrs.rs:19:8: 19:29 (#0),
+ span: $DIR/inner-attrs.rs:20:8: 20:29 (#0),
},
Group {
delimiter: Parenthesis,
stream: TokenStream [
Ident {
ident: "fourth",
- span: $DIR/inner-attrs.rs:19:30: 19:36 (#0),
+ span: $DIR/inner-attrs.rs:20:30: 20:36 (#0),
},
],
- span: $DIR/inner-attrs.rs:19:29: 19:37 (#0),
+ span: $DIR/inner-attrs.rs:20:29: 20:37 (#0),
},
],
- span: $DIR/inner-attrs.rs:19:7: 19:38 (#0),
+ span: $DIR/inner-attrs.rs:20:7: 20:38 (#0),
},
],
- span: $DIR/inner-attrs.rs:17:10: 20:2 (#0),
+ span: $DIR/inner-attrs.rs:18:10: 21:2 (#0),
},
]
PRINT-ATTR_ARGS INPUT (DISPLAY): second
PRINT-ATTR_ARGS INPUT (DEBUG): TokenStream [
Ident {
ident: "second",
- span: $DIR/inner-attrs.rs:16:25: 16:31 (#0),
+ span: $DIR/inner-attrs.rs:17:25: 17:31 (#0),
},
]
PRINT-ATTR INPUT (DISPLAY): fn foo()
PRINT-ATTR INPUT (DEBUG): TokenStream [
Ident {
ident: "fn",
- span: $DIR/inner-attrs.rs:17:1: 17:3 (#0),
+ span: $DIR/inner-attrs.rs:18:1: 18:3 (#0),
},
Ident {
ident: "foo",
- span: $DIR/inner-attrs.rs:17:4: 17:7 (#0),
+ span: $DIR/inner-attrs.rs:18:4: 18:7 (#0),
},
Group {
delimiter: Parenthesis,
stream: TokenStream [],
- span: $DIR/inner-attrs.rs:17:7: 17:9 (#0),
+ span: $DIR/inner-attrs.rs:18:7: 18:9 (#0),
},
Group {
delimiter: Brace,
Punct {
ch: '#',
spacing: Joint,
- span: $DIR/inner-attrs.rs:18:5: 18:6 (#0),
+ span: $DIR/inner-attrs.rs:19:5: 19:6 (#0),
},
Punct {
ch: '!',
spacing: Alone,
- span: $DIR/inner-attrs.rs:18:6: 18:7 (#0),
+ span: $DIR/inner-attrs.rs:19:6: 19:7 (#0),
},
Group {
delimiter: Bracket,
stream: TokenStream [
Ident {
ident: "print_target_and_args",
- span: $DIR/inner-attrs.rs:18:8: 18:29 (#0),
+ span: $DIR/inner-attrs.rs:19:8: 19:29 (#0),
},
Group {
delimiter: Parenthesis,
stream: TokenStream [
Ident {
ident: "third",
- span: $DIR/inner-attrs.rs:18:30: 18:35 (#0),
+ span: $DIR/inner-attrs.rs:19:30: 19:35 (#0),
},
],
- span: $DIR/inner-attrs.rs:18:29: 18:36 (#0),
+ span: $DIR/inner-attrs.rs:19:29: 19:36 (#0),
},
],
- span: $DIR/inner-attrs.rs:18:7: 18:37 (#0),
+ span: $DIR/inner-attrs.rs:19:7: 19:37 (#0),
},
Punct {
ch: '#',
spacing: Joint,
- span: $DIR/inner-attrs.rs:19:5: 19:6 (#0),
+ span: $DIR/inner-attrs.rs:20:5: 20:6 (#0),
},
Punct {
ch: '!',
spacing: Alone,
- span: $DIR/inner-attrs.rs:19:6: 19:7 (#0),
+ span: $DIR/inner-attrs.rs:20:6: 20:7 (#0),
},
Group {
delimiter: Bracket,
stream: TokenStream [
Ident {
ident: "print_target_and_args",
- span: $DIR/inner-attrs.rs:19:8: 19:29 (#0),
+ span: $DIR/inner-attrs.rs:20:8: 20:29 (#0),
},
Group {
delimiter: Parenthesis,
stream: TokenStream [
Ident {
ident: "fourth",
- span: $DIR/inner-attrs.rs:19:30: 19:36 (#0),
+ span: $DIR/inner-attrs.rs:20:30: 20:36 (#0),
},
],
- span: $DIR/inner-attrs.rs:19:29: 19:37 (#0),
+ span: $DIR/inner-attrs.rs:20:29: 20:37 (#0),
},
],
- span: $DIR/inner-attrs.rs:19:7: 19:38 (#0),
+ span: $DIR/inner-attrs.rs:20:7: 20:38 (#0),
},
],
- span: $DIR/inner-attrs.rs:17:10: 20:2 (#0),
+ span: $DIR/inner-attrs.rs:18:10: 21:2 (#0),
},
]
PRINT-ATTR_ARGS INPUT (DISPLAY): third
PRINT-ATTR_ARGS INPUT (DEBUG): TokenStream [
Ident {
ident: "third",
- span: $DIR/inner-attrs.rs:18:30: 18:35 (#0),
+ span: $DIR/inner-attrs.rs:19:30: 19:35 (#0),
},
]
PRINT-ATTR INPUT (DISPLAY): fn foo() { # ! [print_target_and_args(fourth)] }
PRINT-ATTR INPUT (DEBUG): TokenStream [
Ident {
ident: "fn",
- span: $DIR/inner-attrs.rs:17:1: 17:3 (#0),
+ span: $DIR/inner-attrs.rs:18:1: 18:3 (#0),
},
Ident {
ident: "foo",
- span: $DIR/inner-attrs.rs:17:4: 17:7 (#0),
+ span: $DIR/inner-attrs.rs:18:4: 18:7 (#0),
},
Group {
delimiter: Parenthesis,
stream: TokenStream [],
- span: $DIR/inner-attrs.rs:17:7: 17:9 (#0),
+ span: $DIR/inner-attrs.rs:18:7: 18:9 (#0),
},
Group {
delimiter: Brace,
Punct {
ch: '#',
spacing: Joint,
- span: $DIR/inner-attrs.rs:19:5: 19:6 (#0),
+ span: $DIR/inner-attrs.rs:20:5: 20:6 (#0),
},
Punct {
ch: '!',
spacing: Alone,
- span: $DIR/inner-attrs.rs:19:6: 19:7 (#0),
+ span: $DIR/inner-attrs.rs:20:6: 20:7 (#0),
},
Group {
delimiter: Bracket,
stream: TokenStream [
Ident {
ident: "print_target_and_args",
- span: $DIR/inner-attrs.rs:19:8: 19:29 (#0),
+ span: $DIR/inner-attrs.rs:20:8: 20:29 (#0),
},
Group {
delimiter: Parenthesis,
stream: TokenStream [
Ident {
ident: "fourth",
- span: $DIR/inner-attrs.rs:19:30: 19:36 (#0),
+ span: $DIR/inner-attrs.rs:20:30: 20:36 (#0),
},
],
- span: $DIR/inner-attrs.rs:19:29: 19:37 (#0),
+ span: $DIR/inner-attrs.rs:20:29: 20:37 (#0),
},
],
- span: $DIR/inner-attrs.rs:19:7: 19:38 (#0),
+ span: $DIR/inner-attrs.rs:20:7: 20:38 (#0),
},
],
- span: $DIR/inner-attrs.rs:17:10: 20:2 (#0),
+ span: $DIR/inner-attrs.rs:18:10: 21:2 (#0),
},
]
PRINT-ATTR_ARGS INPUT (DISPLAY): fourth
PRINT-ATTR_ARGS INPUT (DEBUG): TokenStream [
Ident {
ident: "fourth",
- span: $DIR/inner-attrs.rs:19:30: 19:36 (#0),
+ span: $DIR/inner-attrs.rs:20:30: 20:36 (#0),
},
]
PRINT-ATTR INPUT (DISPLAY): fn foo() { }
PRINT-ATTR INPUT (DEBUG): TokenStream [
Ident {
ident: "fn",
- span: $DIR/inner-attrs.rs:17:1: 17:3 (#0),
+ span: $DIR/inner-attrs.rs:18:1: 18:3 (#0),
},
Ident {
ident: "foo",
- span: $DIR/inner-attrs.rs:17:4: 17:7 (#0),
+ span: $DIR/inner-attrs.rs:18:4: 18:7 (#0),
},
Group {
delimiter: Parenthesis,
stream: TokenStream [],
- span: $DIR/inner-attrs.rs:17:7: 17:9 (#0),
+ span: $DIR/inner-attrs.rs:18:7: 18:9 (#0),
},
Group {
delimiter: Brace,
stream: TokenStream [],
- span: $DIR/inner-attrs.rs:17:10: 20:2 (#0),
+ span: $DIR/inner-attrs.rs:18:10: 21:2 (#0),
},
]
PRINT-ATTR_ARGS INPUT (DISPLAY): mod_first
PRINT-ATTR_ARGS INPUT (DEBUG): TokenStream [
Ident {
ident: "mod_first",
- span: $DIR/inner-attrs.rs:22:25: 22:34 (#0),
+ span: $DIR/inner-attrs.rs:23:25: 23:34 (#0),
},
]
PRINT-ATTR INPUT (DISPLAY): #[print_target_and_args(mod_second)] mod inline_mod
Punct {
ch: '#',
spacing: Alone,
- span: $DIR/inner-attrs.rs:23:1: 23:2 (#0),
+ span: $DIR/inner-attrs.rs:24:1: 24:2 (#0),
},
Group {
delimiter: Bracket,
stream: TokenStream [
Ident {
ident: "print_target_and_args",
- span: $DIR/inner-attrs.rs:23:3: 23:24 (#0),
+ span: $DIR/inner-attrs.rs:24:3: 24:24 (#0),
},
Group {
delimiter: Parenthesis,
stream: TokenStream [
Ident {
ident: "mod_second",
- span: $DIR/inner-attrs.rs:23:25: 23:35 (#0),
+ span: $DIR/inner-attrs.rs:24:25: 24:35 (#0),
},
],
- span: $DIR/inner-attrs.rs:23:24: 23:36 (#0),
+ span: $DIR/inner-attrs.rs:24:24: 24:36 (#0),
},
],
- span: $DIR/inner-attrs.rs:23:2: 23:37 (#0),
+ span: $DIR/inner-attrs.rs:24:2: 24:37 (#0),
},
Ident {
ident: "mod",
- span: $DIR/inner-attrs.rs:24:1: 24:4 (#0),
+ span: $DIR/inner-attrs.rs:25:1: 25:4 (#0),
},
Ident {
ident: "inline_mod",
- span: $DIR/inner-attrs.rs:24:5: 24:15 (#0),
+ span: $DIR/inner-attrs.rs:25:5: 25:15 (#0),
},
Group {
delimiter: Brace,
Punct {
ch: '#',
spacing: Joint,
- span: $DIR/inner-attrs.rs:25:5: 25:6 (#0),
+ span: $DIR/inner-attrs.rs:26:5: 26:6 (#0),
},
Punct {
ch: '!',
spacing: Alone,
- span: $DIR/inner-attrs.rs:25:6: 25:7 (#0),
+ span: $DIR/inner-attrs.rs:26:6: 26:7 (#0),
},
Group {
delimiter: Bracket,
stream: TokenStream [
Ident {
ident: "print_target_and_args",
- span: $DIR/inner-attrs.rs:25:8: 25:29 (#0),
+ span: $DIR/inner-attrs.rs:26:8: 26:29 (#0),
},
Group {
delimiter: Parenthesis,
stream: TokenStream [
Ident {
ident: "mod_third",
- span: $DIR/inner-attrs.rs:25:30: 25:39 (#0),
+ span: $DIR/inner-attrs.rs:26:30: 26:39 (#0),
},
],
- span: $DIR/inner-attrs.rs:25:29: 25:40 (#0),
+ span: $DIR/inner-attrs.rs:26:29: 26:40 (#0),
},
],
- span: $DIR/inner-attrs.rs:25:7: 25:41 (#0),
+ span: $DIR/inner-attrs.rs:26:7: 26:41 (#0),
},
Punct {
ch: '#',
spacing: Joint,
- span: $DIR/inner-attrs.rs:26:5: 26:6 (#0),
+ span: $DIR/inner-attrs.rs:27:5: 27:6 (#0),
},
Punct {
ch: '!',
spacing: Alone,
- span: $DIR/inner-attrs.rs:26:6: 26:7 (#0),
+ span: $DIR/inner-attrs.rs:27:6: 27:7 (#0),
},
Group {
delimiter: Bracket,
stream: TokenStream [
Ident {
ident: "print_target_and_args",
- span: $DIR/inner-attrs.rs:26:8: 26:29 (#0),
+ span: $DIR/inner-attrs.rs:27:8: 27:29 (#0),
},
Group {
delimiter: Parenthesis,
stream: TokenStream [
Ident {
ident: "mod_fourth",
- span: $DIR/inner-attrs.rs:26:30: 26:40 (#0),
+ span: $DIR/inner-attrs.rs:27:30: 27:40 (#0),
},
],
- span: $DIR/inner-attrs.rs:26:29: 26:41 (#0),
+ span: $DIR/inner-attrs.rs:27:29: 27:41 (#0),
},
],
- span: $DIR/inner-attrs.rs:26:7: 26:42 (#0),
+ span: $DIR/inner-attrs.rs:27:7: 27:42 (#0),
},
],
- span: $DIR/inner-attrs.rs:24:16: 27:2 (#0),
+ span: $DIR/inner-attrs.rs:25:16: 28:2 (#0),
},
]
PRINT-ATTR_ARGS INPUT (DISPLAY): mod_second
PRINT-ATTR_ARGS INPUT (DEBUG): TokenStream [
Ident {
ident: "mod_second",
- span: $DIR/inner-attrs.rs:23:25: 23:35 (#0),
+ span: $DIR/inner-attrs.rs:24:25: 24:35 (#0),
},
]
PRINT-ATTR INPUT (DISPLAY): mod inline_mod
PRINT-ATTR INPUT (DEBUG): TokenStream [
Ident {
ident: "mod",
- span: $DIR/inner-attrs.rs:24:1: 24:4 (#0),
+ span: $DIR/inner-attrs.rs:25:1: 25:4 (#0),
},
Ident {
ident: "inline_mod",
- span: $DIR/inner-attrs.rs:24:5: 24:15 (#0),
+ span: $DIR/inner-attrs.rs:25:5: 25:15 (#0),
},
Group {
delimiter: Brace,
Punct {
ch: '#',
spacing: Joint,
- span: $DIR/inner-attrs.rs:25:5: 25:6 (#0),
+ span: $DIR/inner-attrs.rs:26:5: 26:6 (#0),
},
Punct {
ch: '!',
spacing: Alone,
- span: $DIR/inner-attrs.rs:25:6: 25:7 (#0),
+ span: $DIR/inner-attrs.rs:26:6: 26:7 (#0),
},
Group {
delimiter: Bracket,
stream: TokenStream [
Ident {
ident: "print_target_and_args",
- span: $DIR/inner-attrs.rs:25:8: 25:29 (#0),
+ span: $DIR/inner-attrs.rs:26:8: 26:29 (#0),
},
Group {
delimiter: Parenthesis,
stream: TokenStream [
Ident {
ident: "mod_third",
- span: $DIR/inner-attrs.rs:25:30: 25:39 (#0),
+ span: $DIR/inner-attrs.rs:26:30: 26:39 (#0),
},
],
- span: $DIR/inner-attrs.rs:25:29: 25:40 (#0),
+ span: $DIR/inner-attrs.rs:26:29: 26:40 (#0),
},
],
- span: $DIR/inner-attrs.rs:25:7: 25:41 (#0),
+ span: $DIR/inner-attrs.rs:26:7: 26:41 (#0),
},
Punct {
ch: '#',
spacing: Joint,
- span: $DIR/inner-attrs.rs:26:5: 26:6 (#0),
+ span: $DIR/inner-attrs.rs:27:5: 27:6 (#0),
},
Punct {
ch: '!',
spacing: Alone,
- span: $DIR/inner-attrs.rs:26:6: 26:7 (#0),
+ span: $DIR/inner-attrs.rs:27:6: 27:7 (#0),
},
Group {
delimiter: Bracket,
stream: TokenStream [
Ident {
ident: "print_target_and_args",
- span: $DIR/inner-attrs.rs:26:8: 26:29 (#0),
+ span: $DIR/inner-attrs.rs:27:8: 27:29 (#0),
},
Group {
delimiter: Parenthesis,
stream: TokenStream [
Ident {
ident: "mod_fourth",
- span: $DIR/inner-attrs.rs:26:30: 26:40 (#0),
+ span: $DIR/inner-attrs.rs:27:30: 27:40 (#0),
},
],
- span: $DIR/inner-attrs.rs:26:29: 26:41 (#0),
+ span: $DIR/inner-attrs.rs:27:29: 27:41 (#0),
},
],
- span: $DIR/inner-attrs.rs:26:7: 26:42 (#0),
+ span: $DIR/inner-attrs.rs:27:7: 27:42 (#0),
},
],
- span: $DIR/inner-attrs.rs:24:16: 27:2 (#0),
+ span: $DIR/inner-attrs.rs:25:16: 28:2 (#0),
},
]
PRINT-ATTR_ARGS INPUT (DISPLAY): mod_third
PRINT-ATTR_ARGS INPUT (DEBUG): TokenStream [
Ident {
ident: "mod_third",
- span: $DIR/inner-attrs.rs:25:30: 25:39 (#0),
+ span: $DIR/inner-attrs.rs:26:30: 26:39 (#0),
},
]
PRINT-ATTR INPUT (DISPLAY): mod inline_mod { # ! [print_target_and_args(mod_fourth)] }
PRINT-ATTR INPUT (DEBUG): TokenStream [
Ident {
ident: "mod",
- span: $DIR/inner-attrs.rs:24:1: 24:4 (#0),
+ span: $DIR/inner-attrs.rs:25:1: 25:4 (#0),
},
Ident {
ident: "inline_mod",
- span: $DIR/inner-attrs.rs:24:5: 24:15 (#0),
+ span: $DIR/inner-attrs.rs:25:5: 25:15 (#0),
},
Group {
delimiter: Brace,
Punct {
ch: '#',
spacing: Joint,
- span: $DIR/inner-attrs.rs:26:5: 26:6 (#0),
+ span: $DIR/inner-attrs.rs:27:5: 27:6 (#0),
},
Punct {
ch: '!',
spacing: Alone,
- span: $DIR/inner-attrs.rs:26:6: 26:7 (#0),
+ span: $DIR/inner-attrs.rs:27:6: 27:7 (#0),
},
Group {
delimiter: Bracket,
stream: TokenStream [
Ident {
ident: "print_target_and_args",
- span: $DIR/inner-attrs.rs:26:8: 26:29 (#0),
+ span: $DIR/inner-attrs.rs:27:8: 27:29 (#0),
},
Group {
delimiter: Parenthesis,
stream: TokenStream [
Ident {
ident: "mod_fourth",
- span: $DIR/inner-attrs.rs:26:30: 26:40 (#0),
+ span: $DIR/inner-attrs.rs:27:30: 27:40 (#0),
},
],
- span: $DIR/inner-attrs.rs:26:29: 26:41 (#0),
+ span: $DIR/inner-attrs.rs:27:29: 27:41 (#0),
},
],
- span: $DIR/inner-attrs.rs:26:7: 26:42 (#0),
+ span: $DIR/inner-attrs.rs:27:7: 27:42 (#0),
},
],
- span: $DIR/inner-attrs.rs:24:16: 27:2 (#0),
+ span: $DIR/inner-attrs.rs:25:16: 28:2 (#0),
},
]
PRINT-ATTR_ARGS INPUT (DISPLAY): mod_fourth
PRINT-ATTR_ARGS INPUT (DEBUG): TokenStream [
Ident {
ident: "mod_fourth",
- span: $DIR/inner-attrs.rs:26:30: 26:40 (#0),
+ span: $DIR/inner-attrs.rs:27:30: 27:40 (#0),
},
]
PRINT-ATTR INPUT (DISPLAY): mod inline_mod { }
PRINT-ATTR INPUT (DEBUG): TokenStream [
Ident {
ident: "mod",
- span: $DIR/inner-attrs.rs:24:1: 24:4 (#0),
+ span: $DIR/inner-attrs.rs:25:1: 25:4 (#0),
},
Ident {
ident: "inline_mod",
- span: $DIR/inner-attrs.rs:24:5: 24:15 (#0),
+ span: $DIR/inner-attrs.rs:25:5: 25:15 (#0),
},
Group {
delimiter: Brace,
stream: TokenStream [],
- span: $DIR/inner-attrs.rs:24:16: 27:2 (#0),
+ span: $DIR/inner-attrs.rs:25:16: 28:2 (#0),
},
]
PRINT-DERIVE INPUT (DISPLAY): struct MyDerivePrint
{
field :
- [u8 ;
- {
- match true
- {
- # ! [rustc_dummy(first)] # ! [rustc_dummy(second)] _ =>
- { # ! [rustc_dummy(third)] true }
- } ; 0
- }]
+ [u8 ; { match true { _ => { # ! [rustc_dummy(third)] true } } ; 0 }]
}
PRINT-DERIVE INPUT (DEBUG): TokenStream [
Ident {
ident: "struct",
- span: $DIR/inner-attrs.rs:34:1: 34:7 (#0),
+ span: $DIR/inner-attrs.rs:35:1: 35:7 (#0),
},
Ident {
ident: "MyDerivePrint",
- span: $DIR/inner-attrs.rs:34:8: 34:21 (#0),
+ span: $DIR/inner-attrs.rs:35:8: 35:21 (#0),
},
Group {
delimiter: Brace,
stream: TokenStream [
Ident {
ident: "field",
- span: $DIR/inner-attrs.rs:35:5: 35:10 (#0),
+ span: $DIR/inner-attrs.rs:36:5: 36:10 (#0),
},
Punct {
ch: ':',
spacing: Alone,
- span: $DIR/inner-attrs.rs:35:10: 35:11 (#0),
+ span: $DIR/inner-attrs.rs:36:10: 36:11 (#0),
},
Group {
delimiter: Bracket,
stream: TokenStream [
Ident {
ident: "u8",
- span: $DIR/inner-attrs.rs:35:13: 35:15 (#0),
+ span: $DIR/inner-attrs.rs:36:13: 36:15 (#0),
},
Punct {
ch: ';',
spacing: Alone,
- span: $DIR/inner-attrs.rs:35:15: 35:16 (#0),
+ span: $DIR/inner-attrs.rs:36:15: 36:16 (#0),
},
Group {
delimiter: Brace,
stream: TokenStream [
Ident {
ident: "match",
- span: $DIR/inner-attrs.rs:36:9: 36:14 (#0),
+ span: $DIR/inner-attrs.rs:37:9: 37:14 (#0),
},
Ident {
ident: "true",
- span: $DIR/inner-attrs.rs:36:15: 36:19 (#0),
+ span: $DIR/inner-attrs.rs:37:15: 37:19 (#0),
},
Group {
delimiter: Brace,
stream: TokenStream [
- Punct {
- ch: '#',
- spacing: Alone,
- span: $DIR/inner-attrs.rs:37:13: 37:14 (#0),
- },
- Punct {
- ch: '!',
- spacing: Alone,
- span: $DIR/inner-attrs.rs:37:14: 37:15 (#0),
- },
- Group {
- delimiter: Bracket,
- stream: TokenStream [
- Ident {
- ident: "rustc_dummy",
- span: $DIR/inner-attrs.rs:37:37: 37:48 (#0),
- },
- Group {
- delimiter: Parenthesis,
- stream: TokenStream [
- Ident {
- ident: "first",
- span: $DIR/inner-attrs.rs:37:49: 37:54 (#0),
- },
- ],
- span: $DIR/inner-attrs.rs:37:48: 37:55 (#0),
- },
- ],
- span: $DIR/inner-attrs.rs:37:13: 37:14 (#0),
- },
- Punct {
- ch: '#',
- spacing: Alone,
- span: $DIR/inner-attrs.rs:38:13: 38:14 (#0),
- },
- Punct {
- ch: '!',
- spacing: Alone,
- span: $DIR/inner-attrs.rs:38:14: 38:15 (#0),
- },
- Group {
- delimiter: Bracket,
- stream: TokenStream [
- Ident {
- ident: "rustc_dummy",
- span: $DIR/inner-attrs.rs:38:37: 38:48 (#0),
- },
- Group {
- delimiter: Parenthesis,
- stream: TokenStream [
- Ident {
- ident: "second",
- span: $DIR/inner-attrs.rs:38:49: 38:55 (#0),
- },
- ],
- span: $DIR/inner-attrs.rs:38:48: 38:56 (#0),
- },
- ],
- span: $DIR/inner-attrs.rs:38:13: 38:14 (#0),
- },
Ident {
ident: "_",
- span: $DIR/inner-attrs.rs:39:13: 39:14 (#0),
+ span: $DIR/inner-attrs.rs:38:13: 38:14 (#0),
},
Punct {
ch: '=',
spacing: Joint,
- span: $DIR/inner-attrs.rs:39:15: 39:17 (#0),
+ span: $DIR/inner-attrs.rs:38:15: 38:17 (#0),
},
Punct {
ch: '>',
spacing: Alone,
- span: $DIR/inner-attrs.rs:39:15: 39:17 (#0),
+ span: $DIR/inner-attrs.rs:38:15: 38:17 (#0),
},
Group {
delimiter: Brace,
Punct {
ch: '#',
spacing: Alone,
- span: $DIR/inner-attrs.rs:40:17: 40:18 (#0),
+ span: $DIR/inner-attrs.rs:39:17: 39:18 (#0),
},
Punct {
ch: '!',
spacing: Alone,
- span: $DIR/inner-attrs.rs:40:18: 40:19 (#0),
+ span: $DIR/inner-attrs.rs:39:18: 39:19 (#0),
},
Group {
delimiter: Bracket,
stream: TokenStream [
Ident {
ident: "rustc_dummy",
- span: $DIR/inner-attrs.rs:40:41: 40:52 (#0),
+ span: $DIR/inner-attrs.rs:39:41: 39:52 (#0),
},
Group {
delimiter: Parenthesis,
stream: TokenStream [
Ident {
ident: "third",
- span: $DIR/inner-attrs.rs:40:53: 40:58 (#0),
+ span: $DIR/inner-attrs.rs:39:53: 39:58 (#0),
},
],
- span: $DIR/inner-attrs.rs:40:52: 40:59 (#0),
+ span: $DIR/inner-attrs.rs:39:52: 39:59 (#0),
},
],
- span: $DIR/inner-attrs.rs:40:17: 40:18 (#0),
+ span: $DIR/inner-attrs.rs:39:17: 39:18 (#0),
},
Ident {
ident: "true",
- span: $DIR/inner-attrs.rs:41:17: 41:21 (#0),
+ span: $DIR/inner-attrs.rs:40:17: 40:21 (#0),
},
],
- span: $DIR/inner-attrs.rs:39:18: 42:14 (#0),
+ span: $DIR/inner-attrs.rs:38:18: 41:14 (#0),
},
],
- span: $DIR/inner-attrs.rs:36:20: 43:10 (#0),
+ span: $DIR/inner-attrs.rs:37:20: 42:10 (#0),
},
Punct {
ch: ';',
spacing: Alone,
- span: $DIR/inner-attrs.rs:43:10: 43:11 (#0),
+ span: $DIR/inner-attrs.rs:42:10: 42:11 (#0),
},
Literal {
kind: Integer,
symbol: "0",
suffix: None,
- span: $DIR/inner-attrs.rs:44:9: 44:10 (#0),
+ span: $DIR/inner-attrs.rs:43:9: 43:10 (#0),
},
],
- span: $DIR/inner-attrs.rs:35:17: 45:6 (#0),
+ span: $DIR/inner-attrs.rs:36:17: 44:6 (#0),
},
],
- span: $DIR/inner-attrs.rs:35:12: 45:7 (#0),
+ span: $DIR/inner-attrs.rs:36:12: 44:7 (#0),
},
],
- span: $DIR/inner-attrs.rs:34:22: 46:2 (#0),
+ span: $DIR/inner-attrs.rs:35:22: 45:2 (#0),
},
]
PRINT-ATTR_ARGS INPUT (DISPLAY): tuple_attrs
PRINT-ATTR_ARGS INPUT (DEBUG): TokenStream [
Ident {
ident: "tuple_attrs",
- span: $DIR/inner-attrs.rs:52:29: 52:40 (#0),
+ span: $DIR/inner-attrs.rs:48:29: 48:40 (#0),
},
]
PRINT-ATTR INPUT (DISPLAY): (3, 4, { # ! [cfg_attr(not(FALSE), rustc_dummy(innermost))] 5 }) ;
kind: Integer,
symbol: "3",
suffix: None,
- span: $DIR/inner-attrs.rs:54:9: 54:10 (#0),
+ span: $DIR/inner-attrs.rs:49:9: 49:10 (#0),
},
Punct {
ch: ',',
spacing: Alone,
- span: $DIR/inner-attrs.rs:54:10: 54:11 (#0),
+ span: $DIR/inner-attrs.rs:49:10: 49:11 (#0),
},
Literal {
kind: Integer,
symbol: "4",
suffix: None,
- span: $DIR/inner-attrs.rs:54:12: 54:13 (#0),
+ span: $DIR/inner-attrs.rs:49:12: 49:13 (#0),
},
Punct {
ch: ',',
spacing: Alone,
- span: $DIR/inner-attrs.rs:54:13: 54:14 (#0),
+ span: $DIR/inner-attrs.rs:49:13: 49:14 (#0),
},
Group {
delimiter: Brace,
Punct {
ch: '#',
spacing: Joint,
- span: $DIR/inner-attrs.rs:55:13: 55:14 (#0),
+ span: $DIR/inner-attrs.rs:50:13: 50:14 (#0),
},
Punct {
ch: '!',
spacing: Alone,
- span: $DIR/inner-attrs.rs:55:14: 55:15 (#0),
+ span: $DIR/inner-attrs.rs:50:14: 50:15 (#0),
},
Group {
delimiter: Bracket,
stream: TokenStream [
Ident {
ident: "cfg_attr",
- span: $DIR/inner-attrs.rs:55:16: 55:24 (#0),
+ span: $DIR/inner-attrs.rs:50:16: 50:24 (#0),
},
Group {
delimiter: Parenthesis,
stream: TokenStream [
Ident {
ident: "not",
- span: $DIR/inner-attrs.rs:55:25: 55:28 (#0),
+ span: $DIR/inner-attrs.rs:50:25: 50:28 (#0),
},
Group {
delimiter: Parenthesis,
stream: TokenStream [
Ident {
ident: "FALSE",
- span: $DIR/inner-attrs.rs:55:29: 55:34 (#0),
+ span: $DIR/inner-attrs.rs:50:29: 50:34 (#0),
},
],
- span: $DIR/inner-attrs.rs:55:28: 55:35 (#0),
+ span: $DIR/inner-attrs.rs:50:28: 50:35 (#0),
},
Punct {
ch: ',',
spacing: Alone,
- span: $DIR/inner-attrs.rs:55:35: 55:36 (#0),
+ span: $DIR/inner-attrs.rs:50:35: 50:36 (#0),
},
Ident {
ident: "rustc_dummy",
- span: $DIR/inner-attrs.rs:55:37: 55:48 (#0),
+ span: $DIR/inner-attrs.rs:50:37: 50:48 (#0),
},
Group {
delimiter: Parenthesis,
stream: TokenStream [
Ident {
ident: "innermost",
- span: $DIR/inner-attrs.rs:55:49: 55:58 (#0),
+ span: $DIR/inner-attrs.rs:50:49: 50:58 (#0),
},
],
- span: $DIR/inner-attrs.rs:55:48: 55:59 (#0),
+ span: $DIR/inner-attrs.rs:50:48: 50:59 (#0),
},
],
- span: $DIR/inner-attrs.rs:55:24: 55:60 (#0),
+ span: $DIR/inner-attrs.rs:50:24: 50:60 (#0),
},
],
- span: $DIR/inner-attrs.rs:55:15: 55:61 (#0),
+ span: $DIR/inner-attrs.rs:50:15: 50:61 (#0),
},
Literal {
kind: Integer,
symbol: "5",
suffix: None,
- span: $DIR/inner-attrs.rs:56:13: 56:14 (#0),
+ span: $DIR/inner-attrs.rs:51:13: 51:14 (#0),
},
],
- span: $DIR/inner-attrs.rs:54:15: 57:10 (#0),
+ span: $DIR/inner-attrs.rs:49:15: 52:10 (#0),
},
],
- span: $DIR/inner-attrs.rs:52:43: 58:6 (#0),
+ span: $DIR/inner-attrs.rs:48:43: 53:6 (#0),
},
Punct {
ch: ';',
spacing: Alone,
- span: $DIR/inner-attrs.rs:58:6: 58:7 (#0),
- },
-]
-PRINT-ATTR_ARGS INPUT (DISPLAY): array_attrs
-PRINT-ATTR_ARGS INPUT (DEBUG): TokenStream [
- Ident {
- ident: "array_attrs",
- span: $DIR/inner-attrs.rs:60:29: 60:40 (#0),
- },
-]
-PRINT-ATTR INPUT (DISPLAY): [# ! [rustc_dummy(inner)] true ; 0] ;
-PRINT-ATTR INPUT (DEBUG): TokenStream [
- Group {
- delimiter: Bracket,
- stream: TokenStream [
- Punct {
- ch: '#',
- spacing: Joint,
- span: $DIR/inner-attrs.rs:61:9: 61:10 (#0),
- },
- Punct {
- ch: '!',
- spacing: Alone,
- span: $DIR/inner-attrs.rs:61:10: 61:11 (#0),
- },
- Group {
- delimiter: Bracket,
- stream: TokenStream [
- Ident {
- ident: "rustc_dummy",
- span: $DIR/inner-attrs.rs:61:12: 61:23 (#0),
- },
- Group {
- delimiter: Parenthesis,
- stream: TokenStream [
- Ident {
- ident: "inner",
- span: $DIR/inner-attrs.rs:61:24: 61:29 (#0),
- },
- ],
- span: $DIR/inner-attrs.rs:61:23: 61:30 (#0),
- },
- ],
- span: $DIR/inner-attrs.rs:61:11: 61:31 (#0),
- },
- Ident {
- ident: "true",
- span: $DIR/inner-attrs.rs:62:9: 62:13 (#0),
- },
- Punct {
- ch: ';',
- spacing: Alone,
- span: $DIR/inner-attrs.rs:62:13: 62:14 (#0),
- },
- Literal {
- kind: Integer,
- symbol: "0",
- suffix: None,
- span: $DIR/inner-attrs.rs:62:15: 62:16 (#0),
- },
- ],
- span: $DIR/inner-attrs.rs:60:43: 63:6 (#0),
- },
- Punct {
- ch: ';',
- spacing: Alone,
- span: $DIR/inner-attrs.rs:63:6: 63:7 (#0),
+ span: $DIR/inner-attrs.rs:53:6: 53:7 (#0),
},
]
PRINT-ATTR_ARGS INPUT (DISPLAY): tuple_attrs
PRINT-ATTR_ARGS INPUT (DEBUG): TokenStream [
Ident {
ident: "tuple_attrs",
- span: $DIR/inner-attrs.rs:65:29: 65:40 (#0),
+ span: $DIR/inner-attrs.rs:55:29: 55:40 (#0),
},
]
PRINT-ATTR INPUT (DISPLAY): (3, 4, { # ! [cfg_attr(not(FALSE), rustc_dummy(innermost))] 5 }) ;
kind: Integer,
symbol: "3",
suffix: None,
- span: $DIR/inner-attrs.rs:67:9: 67:10 (#0),
+ span: $DIR/inner-attrs.rs:56:9: 56:10 (#0),
},
Punct {
ch: ',',
spacing: Alone,
- span: $DIR/inner-attrs.rs:67:10: 67:11 (#0),
+ span: $DIR/inner-attrs.rs:56:10: 56:11 (#0),
},
Literal {
kind: Integer,
symbol: "4",
suffix: None,
- span: $DIR/inner-attrs.rs:67:12: 67:13 (#0),
+ span: $DIR/inner-attrs.rs:56:12: 56:13 (#0),
},
Punct {
ch: ',',
spacing: Alone,
- span: $DIR/inner-attrs.rs:67:13: 67:14 (#0),
+ span: $DIR/inner-attrs.rs:56:13: 56:14 (#0),
},
Group {
delimiter: Brace,
Punct {
ch: '#',
spacing: Joint,
- span: $DIR/inner-attrs.rs:68:13: 68:14 (#0),
+ span: $DIR/inner-attrs.rs:57:13: 57:14 (#0),
},
Punct {
ch: '!',
spacing: Alone,
- span: $DIR/inner-attrs.rs:68:14: 68:15 (#0),
+ span: $DIR/inner-attrs.rs:57:14: 57:15 (#0),
},
Group {
delimiter: Bracket,
stream: TokenStream [
Ident {
ident: "cfg_attr",
- span: $DIR/inner-attrs.rs:68:16: 68:24 (#0),
+ span: $DIR/inner-attrs.rs:57:16: 57:24 (#0),
},
Group {
delimiter: Parenthesis,
stream: TokenStream [
Ident {
ident: "not",
- span: $DIR/inner-attrs.rs:68:25: 68:28 (#0),
+ span: $DIR/inner-attrs.rs:57:25: 57:28 (#0),
},
Group {
delimiter: Parenthesis,
stream: TokenStream [
Ident {
ident: "FALSE",
- span: $DIR/inner-attrs.rs:68:29: 68:34 (#0),
+ span: $DIR/inner-attrs.rs:57:29: 57:34 (#0),
},
],
- span: $DIR/inner-attrs.rs:68:28: 68:35 (#0),
+ span: $DIR/inner-attrs.rs:57:28: 57:35 (#0),
},
Punct {
ch: ',',
spacing: Alone,
- span: $DIR/inner-attrs.rs:68:35: 68:36 (#0),
+ span: $DIR/inner-attrs.rs:57:35: 57:36 (#0),
},
Ident {
ident: "rustc_dummy",
- span: $DIR/inner-attrs.rs:68:37: 68:48 (#0),
+ span: $DIR/inner-attrs.rs:57:37: 57:48 (#0),
},
Group {
delimiter: Parenthesis,
stream: TokenStream [
Ident {
ident: "innermost",
- span: $DIR/inner-attrs.rs:68:49: 68:58 (#0),
+ span: $DIR/inner-attrs.rs:57:49: 57:58 (#0),
},
],
- span: $DIR/inner-attrs.rs:68:48: 68:59 (#0),
+ span: $DIR/inner-attrs.rs:57:48: 57:59 (#0),
},
],
- span: $DIR/inner-attrs.rs:68:24: 68:60 (#0),
+ span: $DIR/inner-attrs.rs:57:24: 57:60 (#0),
},
],
- span: $DIR/inner-attrs.rs:68:15: 68:61 (#0),
+ span: $DIR/inner-attrs.rs:57:15: 57:61 (#0),
},
Literal {
kind: Integer,
symbol: "5",
suffix: None,
- span: $DIR/inner-attrs.rs:69:13: 69:14 (#0),
- },
- ],
- span: $DIR/inner-attrs.rs:67:15: 70:10 (#0),
- },
- ],
- span: $DIR/inner-attrs.rs:65:43: 71:6 (#0),
- },
- Punct {
- ch: ';',
- spacing: Alone,
- span: $DIR/inner-attrs.rs:71:6: 71:7 (#0),
- },
-]
-PRINT-ATTR_ARGS INPUT (DISPLAY): array_attrs
-PRINT-ATTR_ARGS INPUT (DEBUG): TokenStream [
- Ident {
- ident: "array_attrs",
- span: $DIR/inner-attrs.rs:73:29: 73:40 (#0),
- },
-]
-PRINT-ATTR INPUT (DISPLAY): [# ! [rustc_dummy(inner)] true ; 0] ;
-PRINT-ATTR INPUT (DEBUG): TokenStream [
- Group {
- delimiter: Bracket,
- stream: TokenStream [
- Punct {
- ch: '#',
- spacing: Joint,
- span: $DIR/inner-attrs.rs:74:9: 74:10 (#0),
- },
- Punct {
- ch: '!',
- spacing: Alone,
- span: $DIR/inner-attrs.rs:74:10: 74:11 (#0),
- },
- Group {
- delimiter: Bracket,
- stream: TokenStream [
- Ident {
- ident: "rustc_dummy",
- span: $DIR/inner-attrs.rs:74:12: 74:23 (#0),
- },
- Group {
- delimiter: Parenthesis,
- stream: TokenStream [
- Ident {
- ident: "inner",
- span: $DIR/inner-attrs.rs:74:24: 74:29 (#0),
- },
- ],
- span: $DIR/inner-attrs.rs:74:23: 74:30 (#0),
+ span: $DIR/inner-attrs.rs:58:13: 58:14 (#0),
},
],
- span: $DIR/inner-attrs.rs:74:11: 74:31 (#0),
- },
- Ident {
- ident: "true",
- span: $DIR/inner-attrs.rs:75:9: 75:13 (#0),
- },
- Punct {
- ch: ';',
- spacing: Alone,
- span: $DIR/inner-attrs.rs:75:13: 75:14 (#0),
- },
- Literal {
- kind: Integer,
- symbol: "0",
- suffix: None,
- span: $DIR/inner-attrs.rs:75:15: 75:16 (#0),
+ span: $DIR/inner-attrs.rs:56:15: 59:10 (#0),
},
],
- span: $DIR/inner-attrs.rs:73:43: 76:6 (#0),
+ span: $DIR/inner-attrs.rs:55:43: 60:6 (#0),
},
Punct {
ch: ';',
spacing: Alone,
- span: $DIR/inner-attrs.rs:76:6: 76:7 (#0),
+ span: $DIR/inner-attrs.rs:60:6: 60:7 (#0),
},
]
PRINT-ATTR_ARGS INPUT (DISPLAY): tenth
PRINT-ATTR_ARGS INPUT (DEBUG): TokenStream [
Ident {
ident: "tenth",
- span: $DIR/inner-attrs.rs:112:42: 112:47 (#0),
+ span: $DIR/inner-attrs.rs:82:42: 82:47 (#0),
},
]
PRINT-ATTR INPUT (DISPLAY): fn weird_extern() { }
PRINT-ATTR INPUT (DEBUG): TokenStream [
Ident {
ident: "fn",
- span: $DIR/inner-attrs.rs:111:5: 111:7 (#0),
+ span: $DIR/inner-attrs.rs:81:5: 81:7 (#0),
},
Ident {
ident: "weird_extern",
- span: $DIR/inner-attrs.rs:111:8: 111:20 (#0),
+ span: $DIR/inner-attrs.rs:81:8: 81:20 (#0),
},
Group {
delimiter: Parenthesis,
stream: TokenStream [],
- span: $DIR/inner-attrs.rs:111:20: 111:22 (#0),
+ span: $DIR/inner-attrs.rs:81:20: 81:22 (#0),
},
Group {
delimiter: Brace,
stream: TokenStream [],
- span: $DIR/inner-attrs.rs:111:23: 113:6 (#0),
+ span: $DIR/inner-attrs.rs:81:23: 83:6 (#0),
},
]
+++ /dev/null
-// check-pass
-// compile-flags: -Z span-debug --error-format human
-// aux-build:test-macros.rs
-// edition:2018
-
-#![feature(proc_macro_hygiene)]
-
-#![no_std] // Don't load unnecessary hygiene information from std
-extern crate std;
-
-#[macro_use]
-extern crate test_macros;
-
-fn main() {
- #[print_target_and_args(my_arg)] (
- #![cfg_attr(not(FALSE), allow(unused))]
- 1, 2, 3
- );
-}
+++ /dev/null
-PRINT-ATTR_ARGS INPUT (DISPLAY): my_arg
-PRINT-ATTR_ARGS INPUT (DEBUG): TokenStream [
- Ident {
- ident: "my_arg",
- span: $DIR/simple-tuple.rs:15:29: 15:35 (#0),
- },
-]
-PRINT-ATTR INPUT (DISPLAY): (# ! [allow(unused)] 1, 2, 3) ;
-PRINT-ATTR INPUT (DEBUG): TokenStream [
- Group {
- delimiter: Parenthesis,
- stream: TokenStream [
- Punct {
- ch: '#',
- spacing: Alone,
- span: $DIR/simple-tuple.rs:16:9: 16:10 (#0),
- },
- Punct {
- ch: '!',
- spacing: Alone,
- span: $DIR/simple-tuple.rs:16:10: 16:11 (#0),
- },
- Group {
- delimiter: Bracket,
- stream: TokenStream [
- Ident {
- ident: "allow",
- span: $DIR/simple-tuple.rs:16:33: 16:38 (#0),
- },
- Group {
- delimiter: Parenthesis,
- stream: TokenStream [
- Ident {
- ident: "unused",
- span: $DIR/simple-tuple.rs:16:39: 16:45 (#0),
- },
- ],
- span: $DIR/simple-tuple.rs:16:38: 16:46 (#0),
- },
- ],
- span: $DIR/simple-tuple.rs:16:9: 16:10 (#0),
- },
- Literal {
- kind: Integer,
- symbol: "1",
- suffix: None,
- span: $DIR/simple-tuple.rs:17:9: 17:10 (#0),
- },
- Punct {
- ch: ',',
- spacing: Alone,
- span: $DIR/simple-tuple.rs:17:10: 17:11 (#0),
- },
- Literal {
- kind: Integer,
- symbol: "2",
- suffix: None,
- span: $DIR/simple-tuple.rs:17:12: 17:13 (#0),
- },
- Punct {
- ch: ',',
- spacing: Alone,
- span: $DIR/simple-tuple.rs:17:13: 17:14 (#0),
- },
- Literal {
- kind: Integer,
- symbol: "3",
- suffix: None,
- span: $DIR/simple-tuple.rs:17:15: 17:16 (#0),
- },
- ],
- span: $DIR/simple-tuple.rs:15:38: 18:6 (#0),
- },
- Punct {
- ch: ';',
- spacing: Alone,
- span: $DIR/simple-tuple.rs:18:6: 18:7 (#0),
- },
-]
--- /dev/null
+// edition:2021
+
+fn main() {
+ let n = 2;
+ match n {
+ 0...3 => {}
+ //~^ ERROR `...` range patterns are deprecated
+ 4...10 => {}
+ //~^ ERROR `...` range patterns are deprecated
+ (11...100) => {}
+ //~^ ERROR `...` range patterns are deprecated
+ _ => {}
+ }
+}
--- /dev/null
+error[E0783]: `...` range patterns are deprecated
+ --> $DIR/exclusive-range-patterns-2021.rs:6:9
+ |
+LL | 0...3 => {}
+ | ^---^
+ | |
+ | help: use `..=` for an inclusive range
+
+error[E0783]: `...` range patterns are deprecated
+ --> $DIR/exclusive-range-patterns-2021.rs:8:9
+ |
+LL | 4...10 => {}
+ | ^---^^
+ | |
+ | help: use `..=` for an inclusive range
+
+error[E0783]: `...` range patterns are deprecated
+ --> $DIR/exclusive-range-patterns-2021.rs:10:10
+ |
+LL | (11...100) => {}
+ | ^^---^^^
+ | |
+ | help: use `..=` for an inclusive range
+
+error: aborting due to 3 previous errors
+
+For more information about this error, try `rustc --explain E0783`.
match &12 {
&(0..=9) => {}
//~^ WARN `...` range patterns are deprecated
+ //~| WARN this was previously accepted by the compiler
//~| HELP use `..=` for an inclusive range
&(10 ..=15) => {}
//~^ ERROR the range pattern here has ambiguous interpretation
- //~^^ HELP add parentheses to clarify the precedence
+ //~| HELP add parentheses to clarify the precedence
&(16..=20) => {}
_ => {}
}
match &12 {
&0...9 => {}
//~^ WARN `...` range patterns are deprecated
+ //~| WARN this was previously accepted by the compiler
//~| HELP use `..=` for an inclusive range
&10..=15 => {}
//~^ ERROR the range pattern here has ambiguous interpretation
- //~^^ HELP add parentheses to clarify the precedence
+ //~| HELP add parentheses to clarify the precedence
&(16..=20) => {}
_ => {}
}
error: the range pattern here has ambiguous interpretation
- --> $DIR/range-inclusive-pattern-precedence.rs:14:10
+ --> $DIR/range-inclusive-pattern-precedence.rs:15:10
|
LL | &10..=15 => {}
| ^^^^^^^ help: add parentheses to clarify the precedence: `(10 ..=15)`
|
LL | #![warn(ellipsis_inclusive_range_patterns)]
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+ = 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>
error: aborting due to previous error; 1 warning emitted
// FIXME: can we add suggestions like `&(0..=9)`?
box 0...9 => {}
//~^ WARN `...` range patterns are deprecated
+ //~| WARN this was previously accepted by the compiler
//~| HELP use `..=` for an inclusive range
box 10..=15 => {}
//~^ ERROR the range pattern here has ambiguous interpretation
error: the range pattern here has ambiguous interpretation
- --> $DIR/range-inclusive-pattern-precedence2.rs:13:13
+ --> $DIR/range-inclusive-pattern-precedence2.rs:14:13
|
LL | box 10..=15 => {}
| ^^^^^^^ help: add parentheses to clarify the precedence: `(10 ..=15)`
|
LL | #![warn(ellipsis_inclusive_range_patterns)]
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+ = 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>
error: aborting due to previous error; 1 warning emitted
LL | let _f = || {
| -- value captured here
LL | let p: &'static mut usize = &mut self.food;
- | ------------------ ^^^^ borrowed value does not live long enough
+ | ------------------ ^^^^^^^^^ borrowed value does not live long enough
| |
| type annotation requires that `self` is borrowed for `'static`
...
mod test {
use crate::foo::foo;
- #[foo] //~ WARN: absolute paths must start with
- //~| WARN: previously accepted
- //~| WARN: absolute paths
- //~| WARN: previously accepted
- fn main() {
- }
+ #[foo]
+ fn main() {}
}
fn main() {
mod test {
use crate::foo::foo;
- #[foo] //~ WARN: absolute paths must start with
- //~| WARN: previously accepted
- //~| WARN: absolute paths
- //~| WARN: previously accepted
- fn main() {
- }
+ #[foo]
+ fn main() {}
}
fn main() {
+++ /dev/null
-warning: absolute paths must start with `self`, `super`, `crate`, or an external crate name in the 2018 edition
- --> $DIR/suggestions-not-always-applicable.rs:17:5
- |
-LL | #[foo]
- | ^^^^^^
- |
-note: the lint level is defined here
- --> $DIR/suggestions-not-always-applicable.rs:8:9
- |
-LL | #![warn(rust_2018_compatibility)]
- | ^^^^^^^^^^^^^^^^^^^^^^^
- = note: `#[warn(absolute_paths_not_starting_with_crate)]` implied by `#[warn(rust_2018_compatibility)]`
- = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in the 2018 edition!
- = note: for more information, see issue #53130 <https://github.com/rust-lang/rust/issues/53130>
- = note: this warning originates in an attribute macro (in Nightly builds, run with -Z macro-backtrace for more info)
-
-warning: absolute paths must start with `self`, `super`, `crate`, or an external crate name in the 2018 edition
- --> $DIR/suggestions-not-always-applicable.rs:17:5
- |
-LL | #[foo]
- | ^^^^^^
- |
- = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in the 2018 edition!
- = note: for more information, see issue #53130 <https://github.com/rust-lang/rust/issues/53130>
- = note: this warning originates in an attribute macro (in Nightly builds, run with -Z macro-backtrace for more info)
-
-warning: 2 warnings emitted
-
// generate code which would trigger the lint.
pub struct Baz;
-pub trait Bar { }
+pub trait Bar {}
pub struct Qux<T>(T);
#[dom_struct]
pub struct Foo {
//~^ ERROR trait objects without an explicit `dyn` are deprecated [bare_trait_objects]
+ //~| WARN this was previously accepted by the compiler
qux: Qux<Qux<Baz>>,
bar: Box<Bar>,
//~^ ERROR trait objects without an explicit `dyn` are deprecated [bare_trait_objects]
+ //~| WARN this was previously accepted by the compiler
}
fn main() {}
error: trait objects without an explicit `dyn` are deprecated
- --> $DIR/issue-61963.rs:21:14
+ --> $DIR/issue-61963.rs:22:14
|
LL | bar: Box<Bar>,
| ^^^ help: use `dyn`: `dyn Bar`
|
LL | #![deny(bare_trait_objects)]
| ^^^^^^^^^^^^^^^^^^
+ = 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>
error: trait objects without an explicit `dyn` are deprecated
--> $DIR/issue-61963.rs:18:1
|
LL | pub struct Foo {
| ^^^ help: use `dyn`: `dyn pub`
+ |
+ = 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>
error: aborting due to 2 previous errors
--- /dev/null
+// test for suggestion on fieldless enum variant
+
+#[derive(PartialEq, Debug)]
+enum FarmAnimal {
+ Worm,
+ Cow,
+ Bull,
+ Chicken { num_eggs: usize },
+ Dog (String),
+}
+
+fn what_does_the_animal_say(animal: &FarmAnimal) {
+
+ let noise = match animal {
+ FarmAnimal::Cow(_) => "moo".to_string(),
+ //~^ ERROR expected tuple struct or tuple variant, found unit variant `FarmAnimal::Cow`
+ FarmAnimal::Chicken(_) => "cluck, cluck!".to_string(),
+ //~^ ERROR expected tuple struct or tuple variant, found struct variant `FarmAnimal::Chicken`
+ FarmAnimal::Dog{..} => "woof!".to_string(),
+ _ => todo!()
+ };
+
+ println!("{:?} says: {:?}", animal, noise);
+}
+
+fn main() {}
--- /dev/null
+error[E0532]: expected tuple struct or tuple variant, found unit variant `FarmAnimal::Cow`
+ --> $DIR/issue-84700.rs:15:9
+ |
+LL | Cow,
+ | --- `FarmAnimal::Cow` defined here
+...
+LL | FarmAnimal::Cow(_) => "moo".to_string(),
+ | ^^^^^^^^^^^^^^^^^^ help: use this syntax instead: `FarmAnimal::Cow`
+
+error[E0532]: expected tuple struct or tuple variant, found struct variant `FarmAnimal::Chicken`
+ --> $DIR/issue-84700.rs:17:9
+ |
+LL | Chicken { num_eggs: usize },
+ | --------------------------- `FarmAnimal::Chicken` defined here
+...
+LL | FarmAnimal::Chicken(_) => "cluck, cluck!".to_string(),
+ | ^^^^^^^^^^^^^^^^^^^^^^ help: use struct pattern syntax instead: `FarmAnimal::Chicken { num_eggs }`
+
+error: aborting due to 2 previous errors
+
+For more information about this error, try `rustc --explain E0532`.
trait Foo {
- fn dummy(&self) { }
+ fn dummy(&self) {}
}
// This should emit the less confusing error, not the more confusing one.
fn foo(_x: Foo + Send) {
//~^ ERROR the size for values of type
//~| WARN trait objects without an explicit `dyn` are deprecated
+ //~| WARN this was previously accepted by the compiler
}
-fn main() { }
+fn main() {}
| ^^^^^^^^^^ help: use `dyn`: `dyn Foo + Send`
|
= note: `#[warn(bare_trait_objects)]` on by default
+ = 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>
error[E0277]: the size for values of type `(dyn Foo + Send + 'static)` cannot be known at compilation time
--> $DIR/not-on-bare-trait.rs:7:8
--- /dev/null
+// compile-flags: --crate-type lib
+// check-pass
+//
+// Regression test for issue #84399
+// Tests that we keep the full `ParamEnv` when
+// caching predicates with freshened types in the global cache
+
+use std::marker::PhantomData;
+pub trait Allocator<R> {
+ type Buffer;
+}
+pub struct DefaultAllocator;
+impl <R> Allocator<R> for DefaultAllocator {
+ type Buffer = ();
+}
+pub type Owned<R> = <DefaultAllocator as Allocator<R>>::Buffer;
+pub type MatrixMN<R> = Matrix<R, Owned<R>>;
+pub type Matrix4<N> = Matrix<N, ()>;
+pub struct Matrix<R, S> {
+ pub data: S,
+ _phantoms: PhantomData<R>,
+}
+pub fn set_object_transform(matrix: &Matrix4<()>) {
+ matrix.js_buffer_view();
+}
+pub trait Storable {
+ type Cell;
+ fn slice_to_items(_buffer: &()) -> &[Self::Cell] {
+ unimplemented!()
+ }
+}
+pub type Cell<T> = <T as Storable>::Cell;
+impl<R> Storable for MatrixMN<R>
+where
+ DefaultAllocator: Allocator<R>,
+{
+ type Cell = ();
+}
+pub trait JsBufferView {
+ fn js_buffer_view(&self) -> usize {
+ unimplemented!()
+ }
+}
+impl<R> JsBufferView for [MatrixMN<R>]
+where
+ DefaultAllocator: Allocator<R>,
+ MatrixMN<R>: Storable,
+ [Cell<MatrixMN<R>>]: JsBufferView,
+{
+ fn js_buffer_view(&self) -> usize {
+ <MatrixMN<R> as Storable>::slice_to_items(&()).js_buffer_view()
+ }
+}
+impl JsBufferView for [()] {}
+impl<R> JsBufferView for MatrixMN<R> where DefaultAllocator: Allocator<R> {}
LL | *self += 1;
| ^^^^^^^^^^ 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
+ = 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: aborting due to previous error
LL | *(1 as *mut u32) = 42;
| ^^^^^^^^^^^^^^^^^^^^^ 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
+ = 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: aborting due to previous error
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
+ = 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 | *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
+ = 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 | *p = 0;
| ^^^^^^ 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
+ = 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: aborting due to previous error
LL | return *p;
| ^^ 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
+ = 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: aborting due to previous error
LL | *a == b
| ^^ 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
+ = 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: aborting due to previous error
| ^ unused parameter
|
= help: consider removing `A`, referring to it in a field, or using a marker such as `PhantomData`
+ = help: if you intended `A` to be a const parameter, use `const A: usize` instead
error[E0392]: parameter `A` is never used
--> $DIR/variance-unused-type-param.rs:9:15
| ^ unused parameter
|
= help: consider removing `A`, referring to it in a field, or using a marker such as `PhantomData`
+ = help: if you intended `A` to be a const parameter, use `const A: usize` instead
error[E0392]: parameter `T` is never used
--> $DIR/variance-unused-type-param.rs:13:15
| ^ unused parameter
|
= help: consider removing `T`, referring to it in a field, or using a marker such as `PhantomData`
+ = help: if you intended `T` to be a const parameter, use `const T: usize` instead
error: aborting due to 3 previous errors
-Subproject commit 4369396ce7d270972955d876eaa4954bea56bcd9
+Subproject commit f3e13226d6d17a2bc5f325303494b43a45f53b7f
| ^^^^^^ help: use `dyn`: `dyn A + 'a`
|
= note: `-D bare-trait-objects` implied by `-D warnings`
+ = 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>
error: trait objects without an explicit `dyn` are deprecated
--> $DIR/ice-3969.rs:27:16
|
LL | let x: Dst<A> = *(Box::new(Dst { x: 1 }) as Box<Dst<A>>);
| ^ help: use `dyn`: `dyn A`
+ |
+ = 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>
error: trait objects without an explicit `dyn` are deprecated
--> $DIR/ice-3969.rs:27:57
|
LL | let x: Dst<A> = *(Box::new(Dst { x: 1 }) as Box<Dst<A>>);
| ^ help: use `dyn`: `dyn A`
+ |
+ = 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>
error: aborting due to 3 previous errors
let error_kind = ErrorKind::NotFound;
match error_kind {
ErrorKind::NotFound => {},
- ErrorKind::PermissionDenied | ErrorKind::ConnectionRefused | ErrorKind::ConnectionReset | ErrorKind::ConnectionAborted | ErrorKind::NotConnected | ErrorKind::AddrInUse | ErrorKind::AddrNotAvailable | ErrorKind::BrokenPipe | ErrorKind::AlreadyExists | ErrorKind::WouldBlock | ErrorKind::InvalidInput | ErrorKind::InvalidData | ErrorKind::TimedOut | ErrorKind::WriteZero | ErrorKind::Interrupted | ErrorKind::Other | ErrorKind::UnexpectedEof | ErrorKind::Unsupported | _ => {},
+ ErrorKind::PermissionDenied | ErrorKind::ConnectionRefused | ErrorKind::ConnectionReset | ErrorKind::ConnectionAborted | ErrorKind::NotConnected | ErrorKind::AddrInUse | ErrorKind::AddrNotAvailable | ErrorKind::BrokenPipe | ErrorKind::AlreadyExists | ErrorKind::WouldBlock | ErrorKind::InvalidInput | ErrorKind::InvalidData | ErrorKind::TimedOut | ErrorKind::WriteZero | ErrorKind::Interrupted | ErrorKind::Other | ErrorKind::UnexpectedEof | ErrorKind::Unsupported | ErrorKind::OutOfMemory | _ => {},
}
match error_kind {
ErrorKind::NotFound => {},
ErrorKind::Other => {},
ErrorKind::UnexpectedEof => {},
ErrorKind::Unsupported => {},
+ ErrorKind::OutOfMemory => {},
_ => {},
}
}
ErrorKind::Other => {},
ErrorKind::UnexpectedEof => {},
ErrorKind::Unsupported => {},
+ ErrorKind::OutOfMemory => {},
_ => {},
}
}
--> $DIR/wildcard_enum_match_arm.rs:80:9
|
LL | _ => {},
- | ^ help: try this: `ErrorKind::PermissionDenied | ErrorKind::ConnectionRefused | ErrorKind::ConnectionReset | ErrorKind::ConnectionAborted | ErrorKind::NotConnected | ErrorKind::AddrInUse | ErrorKind::AddrNotAvailable | ErrorKind::BrokenPipe | ErrorKind::AlreadyExists | ErrorKind::WouldBlock | ErrorKind::InvalidInput | ErrorKind::InvalidData | ErrorKind::TimedOut | ErrorKind::WriteZero | ErrorKind::Interrupted | ErrorKind::Other | ErrorKind::UnexpectedEof | ErrorKind::Unsupported | _`
+ | ^ help: try this: `ErrorKind::PermissionDenied | ErrorKind::ConnectionRefused | ErrorKind::ConnectionReset | ErrorKind::ConnectionAborted | ErrorKind::NotConnected | ErrorKind::AddrInUse | ErrorKind::AddrNotAvailable | ErrorKind::BrokenPipe | ErrorKind::AlreadyExists | ErrorKind::WouldBlock | ErrorKind::InvalidInput | ErrorKind::InvalidData | ErrorKind::TimedOut | ErrorKind::WriteZero | ErrorKind::Interrupted | ErrorKind::Other | ErrorKind::UnexpectedEof | ErrorKind::Unsupported | ErrorKind::OutOfMemory | _`
error: aborting due to 5 previous errors
("nonstandard-style", "Violation of standard naming conventions"),
("future-incompatible", "Lints that detect code that has future-compatibility problems"),
("rust-2018-compatibility", "Lints used to transition code from the 2015 edition to 2018"),
+ ("rust-2021-compatibility", "Lints used to transition code from the 2018 edition to 2021"),
];
type LintGroups = BTreeMap<String, BTreeSet<String>>;
-Subproject commit 41f3fe64317a6ef144d2ac33e4e5870d894d6038
+Subproject commit 67c04afc251ad7d80ea22e2056c93349e7e9df58
-Subproject commit 74d1800c25498689c5b5120a1e8495fce0cd0d0d
+Subproject commit 359513ce678efba186972e4f280dbc7046cac15f
-Subproject commit 0bd2b1927c2b02a6fe7447d58e897cf1f1a1d41f
+Subproject commit 2a3635d5d1218c726ff58af4bc35418836143f69
"winapi-i686-pc-windows-gnu",
"winapi-util",
"winapi-x86_64-pc-windows-gnu",
+ // this is a false-positive: it's only used by rustfmt, but because it's enabled through a feature, tidy thinks it's used by rustc as well.
+ "yansi-term",
];
/// Dependency checks.