diff --git a/.github/pull_request_template.md b/.github/pull_request_template.md index ca704082a3f18..fd54a153a1609 100644 --- a/.github/pull_request_template.md +++ b/.github/pull_request_template.md @@ -1,3 +1,4 @@ + \ No newline at end of file +--> + diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 521f8ef0f5ae5..4cf0e5fba5378 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -95,8 +95,6 @@ jobs: path-type: inherit install: > make - dos2unix - diffutils - name: disable git crlf conversion run: git config --global core.autocrlf false diff --git a/.mailmap b/.mailmap index 0bd16a797ca73..33673244be6d0 100644 --- a/.mailmap +++ b/.mailmap @@ -379,6 +379,7 @@ Markus Westerlind Markus Martin Carton Martin Habovštiak Martin Hafskjold Thoresen +Martin Nordholts Matej Lach Matej Ľach Mateusz Mikuła Mateusz Mikuła diff --git a/Cargo.lock b/Cargo.lock index e5ea9fee8a6d8..2e10b4c49abc7 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -87,7 +87,7 @@ version = "4.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "1ab99eae5ee58501ab236beb6f20f6ca39be615267b014899c89b2f0bc18a459" dependencies = [ - "html5ever 0.27.0", + "html5ever", "maplit", "once_cell", "tendril", @@ -131,9 +131,9 @@ dependencies = [ [[package]] name = "annotate-snippets" -version = "0.11.3" +version = "0.11.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "086b0afab3b349e5691143adbfb26983821e3eec4ba4c51957104d372c2e1b7d" +checksum = "24e35ed54e5ea7997c14ed4c70ba043478db1112e98263b3b035907aa197d991" dependencies = [ "anstyle", "unicode-width", @@ -542,7 +542,7 @@ checksum = "93698b29de5e97ad0ae26447b344c482a7284c737d9ddc5f9e52b74a336671bb" dependencies = [ "chrono", "chrono-tz-build", - "phf 0.11.2", + "phf", ] [[package]] @@ -552,8 +552,8 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "0c088aee841df9c3041febbb73934cfc39708749bf96dc827e3359cd39ef11b1" dependencies = [ "parse-zoneinfo", - "phf 0.11.2", - "phf_codegen 0.11.2", + "phf", + "phf_codegen", ] [[package]] @@ -568,9 +568,9 @@ dependencies = [ [[package]] name = "clap" -version = "4.5.6" +version = "4.5.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a9689a29b593160de5bc4aacab7b5d54fb52231de70122626c178e6a368994c7" +checksum = "5db83dced34638ad474f39f250d7fea9598bdd239eaced1bdf45d597da0f433f" dependencies = [ "clap_builder", "clap_derive", @@ -588,9 +588,9 @@ dependencies = [ [[package]] name = "clap_builder" -version = "4.5.6" +version = "4.5.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2e5387378c84f6faa26890ebf9f0a92989f8873d4d380467bcd0d8d8620424df" +checksum = "f7e204572485eb3fbf28f871612191521df159bc3e15a9f5064c66dba3a8c05f" dependencies = [ "anstream", "anstyle", @@ -628,7 +628,7 @@ checksum = "4b82cf0babdbd58558212896d1a4272303a57bdb245c2bf1147185fb45640e70" [[package]] name = "clippy" -version = "0.1.80" +version = "0.1.81" dependencies = [ "anstream", "clippy_config", @@ -655,7 +655,7 @@ dependencies = [ [[package]] name = "clippy_config" -version = "0.1.80" +version = "0.1.81" dependencies = [ "rustc-semver", "serde", @@ -678,7 +678,7 @@ dependencies = [ [[package]] name = "clippy_lints" -version = "0.1.80" +version = "0.1.81" dependencies = [ "arrayvec", "cargo_metadata 0.18.1", @@ -688,7 +688,7 @@ dependencies = [ "itertools 0.12.1", "quine-mc_cluskey", "regex", - "regex-syntax 0.8.3", + "regex-syntax 0.8.4", "rustc-semver", "semver", "serde", @@ -703,7 +703,7 @@ dependencies = [ [[package]] name = "clippy_utils" -version = "0.1.80" +version = "0.1.81" dependencies = [ "arrayvec", "clippy_config", @@ -1023,7 +1023,7 @@ dependencies = [ [[package]] name = "declare_clippy_lint" -version = "0.1.80" +version = "0.1.81" dependencies = [ "itertools 0.12.1", "quote", @@ -1083,13 +1083,13 @@ dependencies = [ [[package]] name = "derive_more" -version = "0.99.17" +version = "0.99.18" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4fb810d30a7c1953f91334de7244731fc3f3c10d7fe163338a35b9f640960321" +checksum = "5f33878137e4dafd7fa914ad4e259e18a4e8e532b9617a2d0150262bf53abfce" dependencies = [ "proc-macro2", "quote", - "syn 1.0.109", + "syn 2.0.66", ] [[package]] @@ -1694,6 +1694,12 @@ name = "hermit-abi" version = "0.3.9" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d231dfb89cfffdbc30e7fc41579ed6066ad03abda9e567ccafae602b97ec5024" + +[[package]] +name = "hermit-abi" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fbf6a919d6cf397374f7dfeeea91d974c7c0a7221d0d0f4f20d859d329e53fcc" dependencies = [ "compiler_builtins", "rustc-std-workspace-alloc", @@ -1732,20 +1738,6 @@ dependencies = [ "utf8-width", ] -[[package]] -name = "html5ever" -version = "0.26.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bea68cab48b8459f17cf1c944c67ddc572d272d9f2b274140f223ecb1da4a3b7" -dependencies = [ - "log", - "mac", - "markup5ever 0.11.0", - "proc-macro2", - "quote", - "syn 1.0.109", -] - [[package]] name = "html5ever" version = "0.27.0" @@ -1754,7 +1746,7 @@ checksum = "c13771afe0e6e846f1e67d038d4cb29998a6779f93c809212e4e9c32efd244d4" dependencies = [ "log", "mac", - "markup5ever 0.12.1", + "markup5ever", "proc-macro2", "quote", "syn 2.0.66", @@ -1798,6 +1790,18 @@ dependencies = [ "cc", ] +[[package]] +name = "icu_collections" +version = "1.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "db2fa452206ebee18c4b5c2274dbf1de17008e874b4dc4f0aea9d01ca79e4526" +dependencies = [ + "displaydoc", + "yoke", + "zerofrom", + "zerovec", +] + [[package]] name = "icu_list" version = "1.5.0" @@ -1851,6 +1855,51 @@ version = "1.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "fdc8ff3388f852bede6b579ad4e978ab004f139284d7b28715f773507b946f6e" +[[package]] +name = "icu_normalizer" +version = "1.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "19ce3e0da2ec68599d193c93d088142efd7f9c5d6fc9b803774855747dc6a84f" +dependencies = [ + "displaydoc", + "icu_collections", + "icu_normalizer_data", + "icu_properties", + "icu_provider", + "smallvec", + "utf16_iter", + "utf8_iter", + "write16", + "zerovec", +] + +[[package]] +name = "icu_normalizer_data" +version = "1.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f8cafbf7aa791e9b22bec55a167906f9e1215fd475cd22adfcf660e03e989516" + +[[package]] +name = "icu_properties" +version = "1.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1f8ac670d7422d7f76b32e17a5db556510825b29ec9154f235977c9caba61036" +dependencies = [ + "displaydoc", + "icu_collections", + "icu_locid_transform", + "icu_properties_data", + "icu_provider", + "tinystr", + "zerovec", +] + +[[package]] +name = "icu_properties_data" +version = "1.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "67a8effbc3dd3e4ba1afa8ad918d5684b8868b3b26500753effea8d2eed19569" + [[package]] name = "icu_provider" version = "1.5.0" @@ -1900,12 +1949,14 @@ checksum = "b9e0384b61958566e926dc50660321d12159025e767c18e043daf26b70104c39" [[package]] name = "idna" -version = "0.5.0" +version = "1.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "634d9b1461af396cad843f47fdba5597a4f9e6ddd4bfb6ff5d85028c25cb12f6" +checksum = "4716a3a0933a1d01c2f72450e89596eb51dd34ef3c211ccd875acdf1f8fe47ed" dependencies = [ - "unicode-bidi", - "unicode-normalization", + "icu_normalizer", + "icu_properties", + "smallvec", + "utf8_iter", ] [[package]] @@ -2175,7 +2226,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "0c2a198fb6b0eada2a8df47933734e6d35d350665a33a3593d7164fa52c75c19" dependencies = [ "cfg-if", - "windows-targets 0.52.5", + "windows-targets 0.48.5", ] [[package]] @@ -2225,7 +2276,7 @@ dependencies = [ name = "linkchecker" version = "0.1.0" dependencies = [ - "html5ever 0.26.0", + "html5ever", "regex", ] @@ -2310,20 +2361,6 @@ version = "1.0.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "3e2e65a1a2e43cfcb47a895c4c8b10d1f4a61097f9f254f183aee60cad9c651d" -[[package]] -name = "markup5ever" -version = "0.11.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7a2629bb1404f3d34c2e921f21fd34ba00b206124c81f65c50b43b6aaefeb016" -dependencies = [ - "log", - "phf 0.10.1", - "phf_codegen 0.10.0", - "string_cache", - "string_cache_codegen", - "tendril", -] - [[package]] name = "markup5ever" version = "0.12.1" @@ -2331,8 +2368,8 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "16ce3abbeba692c8b8441d036ef91aea6df8da2c6b6e21c7e14d3c18e526be45" dependencies = [ "log", - "phf 0.11.2", - "phf_codegen 0.11.2", + "phf", + "phf_codegen", "string_cache", "string_cache_codegen", "tendril", @@ -2387,9 +2424,9 @@ dependencies = [ [[package]] name = "mdbook-i18n-helpers" -version = "0.3.3" +version = "0.3.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f1f71f5961d6f3376e1ff3e5989c2e3ecccc3e8a00f3a3acde446847f84852e4" +checksum = "8c8f972ab672d366c3dad77ea5aa7bae68db2d25fbeb889849f97469d7b658e4" dependencies = [ "anyhow", "chrono", @@ -2636,7 +2673,7 @@ version = "1.16.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "4161fcb6d602d4d2081af7c3a45852d875a03dd337a6bfdd6e06407b61342a43" dependencies = [ - "hermit-abi", + "hermit-abi 0.3.9", "libc", ] @@ -2865,7 +2902,7 @@ checksum = "1e401f977ab385c9e4e3ab30627d6f26d00e2c73eef317493c4ec6d468726cf8" dependencies = [ "cfg-if", "libc", - "redox_syscall 0.5.1", + "redox_syscall 0.5.2", "smallvec", "windows-targets 0.52.5", ] @@ -2945,15 +2982,6 @@ dependencies = [ "sha2", ] -[[package]] -name = "phf" -version = "0.10.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fabbf1ead8a5bcbc20f5f8b939ee3f5b0f6f281b6ad3468b84656b658b455259" -dependencies = [ - "phf_shared 0.10.0", -] - [[package]] name = "phf" version = "0.11.2" @@ -2963,16 +2991,6 @@ dependencies = [ "phf_shared 0.11.2", ] -[[package]] -name = "phf_codegen" -version = "0.10.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4fb1c3a8bc4dd4e5cfce29b44ffc14bedd2ee294559a294e2a4d4c9e9a6a13cd" -dependencies = [ - "phf_generator 0.10.0", - "phf_shared 0.10.0", -] - [[package]] name = "phf_codegen" version = "0.11.2" @@ -3344,9 +3362,9 @@ dependencies = [ [[package]] name = "redox_syscall" -version = "0.5.1" +version = "0.5.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "469052894dcb553421e483e4209ee581a45100d31b4018de03e5a7ad86374a7e" +checksum = "c82cf8cff14456045f55ec4241383baeff27af886adb72ffb2162f99911de0fd" dependencies = [ "bitflags 2.5.0", ] @@ -3405,9 +3423,9 @@ dependencies = [ [[package]] name = "regex-lite" -version = "0.1.5" +version = "0.1.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "30b661b2f27137bdbc16f00eda72866a92bb28af1753ffbd56744fb6e2e9cd8e" +checksum = "53a49587ad06b26609c52e423de037e7f57f20d53535d66e08c695f347df952a" [[package]] name = "regex-syntax" @@ -3423,9 +3441,9 @@ checksum = "dbb5fb1acd8a1a18b3dd5be62d25485eb770e05afb408a9627d14d451bae12da" [[package]] name = "regex-syntax" -version = "0.8.3" +version = "0.8.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "adad44e29e4c806119491a7f06f03de4d1af22c3a680dd47f1e6e179439d1f56" +checksum = "7a66a03ae7c801facd77a29370b4faec201768915ac14a721ba36f20bc9c209b" [[package]] name = "remote-test-client" @@ -3452,7 +3470,7 @@ dependencies = [ [[package]] name = "run_make_support" -version = "0.1.0" +version = "0.2.0" dependencies = [ "gimli 0.28.1", "object 0.34.0", @@ -4205,7 +4223,6 @@ dependencies = [ "rustc_middle", "rustc_span", "rustc_target", - "rustc_type_ir", "smallvec", "tracing", ] @@ -5346,7 +5363,7 @@ dependencies = [ "dlmalloc", "fortanix-sgx-abi", "hashbrown", - "hermit-abi", + "hermit-abi 0.4.0", "libc", "miniz_oxide", "object 0.36.0", @@ -5479,7 +5496,7 @@ dependencies = [ "once_cell", "onig", "plist", - "regex-syntax 0.8.3", + "regex-syntax 0.8.4", "serde", "serde_derive", "serde_json", @@ -5992,7 +6009,7 @@ version = "0.23.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "29e5f4ffcbab82453958fbf59990e981b8e8a177dcd60c2bd8f9b52c3036a6e1" dependencies = [ - "annotate-snippets 0.11.3", + "annotate-snippets 0.11.4", "anyhow", "bstr", "cargo-platform", @@ -6073,12 +6090,6 @@ dependencies = [ "ucd-parse", ] -[[package]] -name = "unicode-bidi" -version = "0.3.15" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "08f95100a766bf4f8f28f90d77e0a5461bbdb219042e7679bebe79004fed8d75" - [[package]] name = "unicode-ident" version = "1.0.12" @@ -6180,9 +6191,9 @@ dependencies = [ [[package]] name = "url" -version = "2.5.0" +version = "2.5.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "31e6302e3bb753d46e83516cae55ae196fc0c309407cf11ab35cc51a4c2a4633" +checksum = "f7c25da092f0a868cdf09e8674cd3b7ef3a7d92a24253e663a2fb85e2496de56" dependencies = [ "form_urlencoded", "idna", @@ -6195,12 +6206,24 @@ version = "0.7.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "09cc8ee72d2a9becf2f2febe0205bbed8fc6615b7cb429ad062dc7b7ddd036a9" +[[package]] +name = "utf16_iter" +version = "1.0.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c8232dd3cdaed5356e0f716d285e4b40b932ac434100fe9b7e0e8e935b9e6246" + [[package]] name = "utf8-width" version = "0.1.7" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "86bd8d4e895da8537e5315b8254664e6b769c4ff3db18321b297a1e7004392e3" +[[package]] +name = "utf8_iter" +version = "1.0.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b6c140620e7ffbb22c2dee59cafe6084a59b5ffc27a8859a5f0d494b5d52b6be" + [[package]] name = "utf8parse" version = "0.2.2" @@ -6380,9 +6403,9 @@ dependencies = [ [[package]] name = "windows-bindgen" -version = "0.56.0" +version = "0.57.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a28e3ea6330cf17fdcdce8bf08d0549ce93769dca9bedc6c39c36c8c0e17db46" +checksum = "1ccb96113d6277ba543c0f77e1c5494af8094bf9daf9b85acdc3f1b620e7c7b4" dependencies = [ "proc-macro2", "rayon", @@ -6403,9 +6426,9 @@ dependencies = [ [[package]] name = "windows-metadata" -version = "0.56.0" +version = "0.57.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3993f7827fff10c454e3a24847075598c7c08108304b8b07943c2c73d78f3b34" +checksum = "8308d076825b9d9e5abc64f8113e96d02b2aeeba869b20fdd65c7e70cda13dfc" [[package]] name = "windows-sys" @@ -6564,6 +6587,12 @@ dependencies = [ "memchr", ] +[[package]] +name = "write16" +version = "1.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d1890f4022759daae28ed4fe62859b1236caebfc61ede2f63ed4e695f3f6d936" + [[package]] name = "writeable" version = "0.5.5" diff --git a/compiler/rustc_borrowck/src/diagnostics/conflict_errors.rs b/compiler/rustc_borrowck/src/diagnostics/conflict_errors.rs index f32ff57fe88b9..6bc340e44f5b3 100644 --- a/compiler/rustc_borrowck/src/diagnostics/conflict_errors.rs +++ b/compiler/rustc_borrowck/src/diagnostics/conflict_errors.rs @@ -100,12 +100,12 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> { move_site_vec.iter().map(|move_site| move_site.moi).collect(); if move_out_indices.is_empty() { - let root_place = PlaceRef { projection: &[], ..used_place }; + let root_local = used_place.local; - if !self.uninitialized_error_reported.insert(root_place) { + if !self.uninitialized_error_reported.insert(root_local) { debug!( "report_use_of_moved_or_uninitialized place: error about {:?} suppressed", - root_place + root_local ); return; } @@ -284,7 +284,7 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> { && let CallKind::FnCall { fn_trait_id, self_ty } = kind && let ty::Param(_) = self_ty.kind() && ty == self_ty - && Some(fn_trait_id) == self.infcx.tcx.lang_items().fn_once_trait() + && self.infcx.tcx.is_lang_item(fn_trait_id, LangItem::FnOnce) { // this is a type parameter `T: FnOnce()`, don't suggest `T: FnOnce() + Clone`. true @@ -708,9 +708,9 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> { if let ty::ClauseKind::Trait(pred) = pred.kind().skip_binder() && pred.self_ty() == ty { - if Some(pred.def_id()) == tcx.lang_items().fn_trait() { + if tcx.is_lang_item(pred.def_id(), LangItem::Fn) { return Some(hir::Mutability::Not); - } else if Some(pred.def_id()) == tcx.lang_items().fn_mut_trait() { + } else if tcx.is_lang_item(pred.def_id(), LangItem::FnMut) { return Some(hir::Mutability::Mut); } } @@ -1832,7 +1832,7 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> { if let hir::ExprKind::MethodCall(..) = ex.kind && let Some(method_def_id) = self.typeck_results.type_dependent_def_id(ex.hir_id) - && self.tcx.lang_items().clone_trait() == Some(self.tcx.parent(method_def_id)) + && self.tcx.is_lang_item(self.tcx.parent(method_def_id), LangItem::Clone) { self.clones.push(ex); } @@ -2888,7 +2888,7 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> { .. } = explanation { - if let Some(diag) = self.try_report_cannot_return_reference_to_local( + if let Err(diag) = self.try_report_cannot_return_reference_to_local( borrow, borrow_span, span, @@ -3075,7 +3075,7 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> { if let BorrowExplanation::MustBeValidFor { category, span, from_closure: false, .. } = explanation { - if let Some(diag) = self.try_report_cannot_return_reference_to_local( + if let Err(diag) = self.try_report_cannot_return_reference_to_local( borrow, proper_span, span, @@ -3159,8 +3159,7 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> { let is_format_arguments_item = if let Some(expr_ty) = expr_ty && let ty::Adt(adt, _) = expr_ty.kind() { - self.infcx.tcx.lang_items().get(LangItem::FormatArguments) - == Some(adt.did()) + self.infcx.tcx.is_lang_item(adt.did(), LangItem::FormatArguments) } else { false }; @@ -3237,11 +3236,11 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> { return_span: Span, category: ConstraintCategory<'tcx>, opt_place_desc: Option<&String>, - ) -> Option> { + ) -> Result<(), Diag<'tcx>> { let return_kind = match category { ConstraintCategory::Return(_) => "return", ConstraintCategory::Yield => "yield", - _ => return None, + _ => return Ok(()), }; // FIXME use a better heuristic than Spans @@ -3317,7 +3316,7 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> { } } - Some(err) + Err(err) } #[instrument(level = "debug", skip(self))] diff --git a/compiler/rustc_borrowck/src/diagnostics/mod.rs b/compiler/rustc_borrowck/src/diagnostics/mod.rs index 1eb67ea367c2d..abb0b5afbd8b1 100644 --- a/compiler/rustc_borrowck/src/diagnostics/mod.rs +++ b/compiler/rustc_borrowck/src/diagnostics/mod.rs @@ -6,9 +6,9 @@ use crate::session_diagnostics::{ }; use rustc_errors::{Applicability, Diag}; use rustc_errors::{DiagCtxt, MultiSpan}; -use rustc_hir as hir; use rustc_hir::def::{CtorKind, Namespace}; use rustc_hir::CoroutineKind; +use rustc_hir::{self as hir, LangItem}; use rustc_index::IndexSlice; use rustc_infer::infer::BoundRegionConversionTime; use rustc_infer::traits::SelectionError; @@ -116,7 +116,7 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> { { if let ty::FnDef(id, _) = *const_.ty().kind() { debug!("add_moved_or_invoked_closure_note: id={:?}", id); - if Some(self.infcx.tcx.parent(id)) == self.infcx.tcx.lang_items().fn_once_trait() { + if self.infcx.tcx.is_lang_item(self.infcx.tcx.parent(id), LangItem::FnOnce) { let closure = match args.first() { Some(Spanned { node: Operand::Copy(place) | Operand::Move(place), .. @@ -767,13 +767,12 @@ impl<'tcx> BorrowedContentSource<'tcx> { ty::FnDef(def_id, args) => { let trait_id = tcx.trait_of_item(def_id)?; - let lang_items = tcx.lang_items(); - if Some(trait_id) == lang_items.deref_trait() - || Some(trait_id) == lang_items.deref_mut_trait() + if tcx.is_lang_item(trait_id, LangItem::Deref) + || tcx.is_lang_item(trait_id, LangItem::DerefMut) { Some(BorrowedContentSource::OverloadedDeref(args.type_at(0))) - } else if Some(trait_id) == lang_items.index_trait() - || Some(trait_id) == lang_items.index_mut_trait() + } else if tcx.is_lang_item(trait_id, LangItem::Index) + || tcx.is_lang_item(trait_id, LangItem::IndexMut) { Some(BorrowedContentSource::OverloadedIndex(args.type_at(0))) } else { @@ -1041,7 +1040,7 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> { .unwrap_or_else(|| "value".to_owned()); match kind { CallKind::FnCall { fn_trait_id, self_ty } - if Some(fn_trait_id) == self.infcx.tcx.lang_items().fn_once_trait() => + if self.infcx.tcx.is_lang_item(fn_trait_id, LangItem::FnOnce) => { err.subdiagnostic( self.dcx(), @@ -1268,7 +1267,7 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> { let ty = moved_place.ty(self.body, tcx).ty; if let ty::Adt(def, args) = ty.peel_refs().kind() - && Some(def.did()) == tcx.lang_items().pin_type() + && tcx.is_lang_item(def.did(), LangItem::Pin) && let ty::Ref(_, _, hir::Mutability::Mut) = args.type_at(0).kind() && let self_ty = self.infcx.instantiate_binder_with_fresh_vars( fn_call_span, diff --git a/compiler/rustc_borrowck/src/lib.rs b/compiler/rustc_borrowck/src/lib.rs index 5c9826ecca733..b3b53e9cb79ed 100644 --- a/compiler/rustc_borrowck/src/lib.rs +++ b/compiler/rustc_borrowck/src/lib.rs @@ -566,7 +566,7 @@ struct MirBorrowckCtxt<'cx, 'tcx> { fn_self_span_reported: FxIndexSet, /// This field keeps track of errors reported in the checking of uninitialized variables, /// so that we don't report seemingly duplicate errors. - uninitialized_error_reported: FxIndexSet>, + uninitialized_error_reported: FxIndexSet, /// This field keeps track of all the local variables that are declared mut and are mutated. /// Used for the warning issued by an unused mutable local variable. used_mut: FxIndexSet, diff --git a/compiler/rustc_borrowck/src/renumber.rs b/compiler/rustc_borrowck/src/renumber.rs index d382f264c37bd..2858a407e098b 100644 --- a/compiler/rustc_borrowck/src/renumber.rs +++ b/compiler/rustc_borrowck/src/renumber.rs @@ -113,7 +113,7 @@ impl<'a, 'tcx> MutVisitor<'tcx> for RegionRenumberer<'a, 'tcx> { } #[instrument(skip(self), level = "debug")] - fn visit_constant(&mut self, constant: &mut ConstOperand<'tcx>, location: Location) { + fn visit_const_operand(&mut self, constant: &mut ConstOperand<'tcx>, location: Location) { let const_ = constant.const_; constant.const_ = self.renumber_regions(const_, || RegionCtxt::Location(location)); debug!("constant: {:#?}", constant); diff --git a/compiler/rustc_borrowck/src/type_check/mod.rs b/compiler/rustc_borrowck/src/type_check/mod.rs index fcfb297d50aa8..c7c1b2af6a7bc 100644 --- a/compiler/rustc_borrowck/src/type_check/mod.rs +++ b/compiler/rustc_borrowck/src/type_check/mod.rs @@ -301,10 +301,10 @@ impl<'a, 'b, 'tcx> Visitor<'tcx> for TypeVerifier<'a, 'b, 'tcx> { self.sanitize_place(place, location, context); } - fn visit_constant(&mut self, constant: &ConstOperand<'tcx>, location: Location) { - debug!(?constant, ?location, "visit_constant"); + fn visit_const_operand(&mut self, constant: &ConstOperand<'tcx>, location: Location) { + debug!(?constant, ?location, "visit_const_operand"); - self.super_constant(constant, location); + self.super_const_operand(constant, location); let ty = self.sanitize_type(constant, constant.const_.ty()); self.cx.infcx.tcx.for_each_free_region(&ty, |live_region| { @@ -328,7 +328,7 @@ impl<'a, 'b, 'tcx> Visitor<'tcx> for TypeVerifier<'a, 'b, 'tcx> { if let Some(annotation_index) = constant.user_ty { if let Err(terr) = self.cx.relate_type_and_user_type( constant.const_.ty(), - ty::Variance::Invariant, + ty::Invariant, &UserTypeProjection { base: annotation_index, projs: vec![] }, locations, ConstraintCategory::Boring, @@ -451,7 +451,7 @@ impl<'a, 'b, 'tcx> Visitor<'tcx> for TypeVerifier<'a, 'b, 'tcx> { if let Err(terr) = self.cx.relate_type_and_user_type( ty, - ty::Variance::Invariant, + ty::Invariant, user_ty, Locations::All(*span), ConstraintCategory::TypeAnnotation, @@ -1095,7 +1095,7 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> { ) -> Result<(), NoSolution> { // Use this order of parameters because the sup type is usually the // "expected" type in diagnostics. - self.relate_types(sup, ty::Variance::Contravariant, sub, locations, category) + self.relate_types(sup, ty::Contravariant, sub, locations, category) } #[instrument(skip(self, category), level = "debug")] @@ -1106,7 +1106,7 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> { locations: Locations, category: ConstraintCategory<'tcx>, ) -> Result<(), NoSolution> { - self.relate_types(expected, ty::Variance::Invariant, found, locations, category) + self.relate_types(expected, ty::Invariant, found, locations, category) } #[instrument(skip(self), level = "debug")] @@ -1146,7 +1146,7 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> { trace!(?curr_projected_ty); let ty = curr_projected_ty.ty; - self.relate_types(ty, v.xform(ty::Variance::Contravariant), a, locations, category)?; + self.relate_types(ty, v.xform(ty::Contravariant), a, locations, category)?; Ok(()) } @@ -1248,7 +1248,7 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> { if let Some(annotation_index) = self.rvalue_user_ty(rv) { if let Err(terr) = self.relate_type_and_user_type( rv_ty, - ty::Variance::Invariant, + ty::Invariant, &UserTypeProjection { base: annotation_index, projs: vec![] }, location.to_locations(), ConstraintCategory::Boring, diff --git a/compiler/rustc_borrowck/src/type_check/relate_tys.rs b/compiler/rustc_borrowck/src/type_check/relate_tys.rs index c531c9b209be5..b9a82046e59ad 100644 --- a/compiler/rustc_borrowck/src/type_check/relate_tys.rs +++ b/compiler/rustc_borrowck/src/type_check/relate_tys.rs @@ -50,14 +50,8 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> { locations: Locations, category: ConstraintCategory<'tcx>, ) -> Result<(), NoSolution> { - NllTypeRelating::new( - self, - locations, - category, - UniverseInfo::other(), - ty::Variance::Invariant, - ) - .relate(a, b)?; + NllTypeRelating::new(self, locations, category, UniverseInfo::other(), ty::Invariant) + .relate(a, b)?; Ok(()) } } @@ -106,15 +100,15 @@ impl<'me, 'bccx, 'tcx> NllTypeRelating<'me, 'bccx, 'tcx> { fn ambient_covariance(&self) -> bool { match self.ambient_variance { - ty::Variance::Covariant | ty::Variance::Invariant => true, - ty::Variance::Contravariant | ty::Variance::Bivariant => false, + ty::Covariant | ty::Invariant => true, + ty::Contravariant | ty::Bivariant => false, } } fn ambient_contravariance(&self) -> bool { match self.ambient_variance { - ty::Variance::Contravariant | ty::Variance::Invariant => true, - ty::Variance::Covariant | ty::Variance::Bivariant => false, + ty::Contravariant | ty::Invariant => true, + ty::Covariant | ty::Bivariant => false, } } @@ -336,11 +330,7 @@ impl<'bccx, 'tcx> TypeRelation> for NllTypeRelating<'_, 'bccx, 'tcx debug!(?self.ambient_variance); // In a bivariant context this always succeeds. - let r = if self.ambient_variance == ty::Variance::Bivariant { - Ok(a) - } else { - self.relate(a, b) - }; + let r = if self.ambient_variance == ty::Bivariant { Ok(a) } else { self.relate(a, b) }; self.ambient_variance = old_ambient_variance; @@ -474,7 +464,7 @@ impl<'bccx, 'tcx> TypeRelation> for NllTypeRelating<'_, 'bccx, 'tcx } match self.ambient_variance { - ty::Variance::Covariant => { + ty::Covariant => { // Covariance, so we want `for<..> A <: for<..> B` -- // therefore we compare any instantiation of A (i.e., A // instantiated with existentials) against every @@ -489,7 +479,7 @@ impl<'bccx, 'tcx> TypeRelation> for NllTypeRelating<'_, 'bccx, 'tcx })?; } - ty::Variance::Contravariant => { + ty::Contravariant => { // Contravariance, so we want `for<..> A :> for<..> B` -- // therefore we compare every instantiation of A (i.e., A // instantiated with universals) against any @@ -504,7 +494,7 @@ impl<'bccx, 'tcx> TypeRelation> for NllTypeRelating<'_, 'bccx, 'tcx })?; } - ty::Variance::Invariant => { + ty::Invariant => { // Invariant, so we want `for<..> A == for<..> B` -- // therefore we want `exists<..> A == for<..> B` and // `exists<..> B == for<..> A`. @@ -525,7 +515,7 @@ impl<'bccx, 'tcx> TypeRelation> for NllTypeRelating<'_, 'bccx, 'tcx })?; } - ty::Variance::Bivariant => {} + ty::Bivariant => {} } Ok(a) @@ -584,23 +574,23 @@ impl<'bccx, 'tcx> PredicateEmittingRelation<'tcx> for NllTypeRelating<'_, 'bccx, fn register_alias_relate_predicate(&mut self, a: Ty<'tcx>, b: Ty<'tcx>) { self.register_predicates([ty::Binder::dummy(match self.ambient_variance { - ty::Variance::Covariant => ty::PredicateKind::AliasRelate( + ty::Covariant => ty::PredicateKind::AliasRelate( a.into(), b.into(), ty::AliasRelationDirection::Subtype, ), // a :> b is b <: a - ty::Variance::Contravariant => ty::PredicateKind::AliasRelate( + ty::Contravariant => ty::PredicateKind::AliasRelate( b.into(), a.into(), ty::AliasRelationDirection::Subtype, ), - ty::Variance::Invariant => ty::PredicateKind::AliasRelate( + ty::Invariant => ty::PredicateKind::AliasRelate( a.into(), b.into(), ty::AliasRelationDirection::Equate, ), - ty::Variance::Bivariant => { + ty::Bivariant => { unreachable!("cannot defer an alias-relate goal with Bivariant variance (yet?)") } })]); diff --git a/compiler/rustc_codegen_cranelift/src/inline_asm.rs b/compiler/rustc_codegen_cranelift/src/inline_asm.rs index 2de804f5e0423..c6b26dd873bdc 100644 --- a/compiler/rustc_codegen_cranelift/src/inline_asm.rs +++ b/compiler/rustc_codegen_cranelift/src/inline_asm.rs @@ -4,6 +4,7 @@ use std::fmt::Write; use cranelift_codegen::isa::CallConv; use rustc_ast::ast::{InlineAsmOptions, InlineAsmTemplatePiece}; +use rustc_hir::LangItem; use rustc_span::sym; use rustc_target::asm::*; use target_lexicon::BinaryFormat; @@ -927,7 +928,7 @@ fn call_inline_asm<'tcx>( fn asm_clif_type<'tcx>(fx: &FunctionCx<'_, '_, 'tcx>, ty: Ty<'tcx>) -> Option { match ty.kind() { // Adapted from https://github.com/rust-lang/rust/blob/f3c66088610c1b80110297c2d9a8b5f9265b013f/compiler/rustc_hir_analysis/src/check/intrinsicck.rs#L136-L151 - ty::Adt(adt, args) if Some(adt.did()) == fx.tcx.lang_items().maybe_uninit() => { + ty::Adt(adt, args) if fx.tcx.is_lang_item(adt.did(), LangItem::MaybeUninit) => { let fields = &adt.non_enum_variant().fields; let ty = fields[FieldIdx::from_u32(1)].ty(fx.tcx, args); let ty::Adt(ty, args) = ty.kind() else { diff --git a/compiler/rustc_codegen_cranelift/src/unsize.rs b/compiler/rustc_codegen_cranelift/src/unsize.rs index 4acbc8a27edb9..967aa53abbda5 100644 --- a/compiler/rustc_codegen_cranelift/src/unsize.rs +++ b/compiler/rustc_codegen_cranelift/src/unsize.rs @@ -39,8 +39,7 @@ pub(crate) fn unsized_info<'tcx>( } // trait upcasting coercion - let vptr_entry_idx = - fx.tcx.vtable_trait_upcasting_coercion_new_vptr_slot((source, target)); + let vptr_entry_idx = fx.tcx.supertrait_vtable_slot((source, target)); if let Some(entry_idx) = vptr_entry_idx { let entry_idx = u32::try_from(entry_idx).unwrap(); diff --git a/compiler/rustc_codegen_llvm/src/asm.rs b/compiler/rustc_codegen_llvm/src/asm.rs index db28c6857b743..60e63b956db6e 100644 --- a/compiler/rustc_codegen_llvm/src/asm.rs +++ b/compiler/rustc_codegen_llvm/src/asm.rs @@ -959,6 +959,43 @@ fn llvm_fixup_input<'ll, 'tcx>( InlineAsmRegClass::X86(X86InlineAsmRegClass::xmm_reg | X86InlineAsmRegClass::zmm_reg), Abi::Vector { .. }, ) if layout.size.bytes() == 64 => bx.bitcast(value, bx.cx.type_vector(bx.cx.type_f64(), 8)), + ( + InlineAsmRegClass::X86( + X86InlineAsmRegClass::xmm_reg + | X86InlineAsmRegClass::ymm_reg + | X86InlineAsmRegClass::zmm_reg, + ), + Abi::Scalar(s), + ) if bx.sess().asm_arch == Some(InlineAsmArch::X86) + && s.primitive() == Primitive::Float(Float::F128) => + { + bx.bitcast(value, bx.type_vector(bx.type_i32(), 4)) + } + ( + InlineAsmRegClass::X86( + X86InlineAsmRegClass::xmm_reg + | X86InlineAsmRegClass::ymm_reg + | X86InlineAsmRegClass::zmm_reg, + ), + Abi::Scalar(s), + ) if s.primitive() == Primitive::Float(Float::F16) => { + let value = bx.insert_element( + bx.const_undef(bx.type_vector(bx.type_f16(), 8)), + value, + bx.const_usize(0), + ); + bx.bitcast(value, bx.type_vector(bx.type_i16(), 8)) + } + ( + InlineAsmRegClass::X86( + X86InlineAsmRegClass::xmm_reg + | X86InlineAsmRegClass::ymm_reg + | X86InlineAsmRegClass::zmm_reg, + ), + Abi::Vector { element, count: count @ (8 | 16) }, + ) if element.primitive() == Primitive::Float(Float::F16) => { + bx.bitcast(value, bx.type_vector(bx.type_i16(), count)) + } ( InlineAsmRegClass::Arm(ArmInlineAsmRegClass::sreg | ArmInlineAsmRegClass::sreg_low16), Abi::Scalar(s), @@ -1036,6 +1073,39 @@ fn llvm_fixup_output<'ll, 'tcx>( InlineAsmRegClass::X86(X86InlineAsmRegClass::xmm_reg | X86InlineAsmRegClass::zmm_reg), Abi::Vector { .. }, ) if layout.size.bytes() == 64 => bx.bitcast(value, layout.llvm_type(bx.cx)), + ( + InlineAsmRegClass::X86( + X86InlineAsmRegClass::xmm_reg + | X86InlineAsmRegClass::ymm_reg + | X86InlineAsmRegClass::zmm_reg, + ), + Abi::Scalar(s), + ) if bx.sess().asm_arch == Some(InlineAsmArch::X86) + && s.primitive() == Primitive::Float(Float::F128) => + { + bx.bitcast(value, bx.type_f128()) + } + ( + InlineAsmRegClass::X86( + X86InlineAsmRegClass::xmm_reg + | X86InlineAsmRegClass::ymm_reg + | X86InlineAsmRegClass::zmm_reg, + ), + Abi::Scalar(s), + ) if s.primitive() == Primitive::Float(Float::F16) => { + let value = bx.bitcast(value, bx.type_vector(bx.type_f16(), 8)); + bx.extract_element(value, bx.const_usize(0)) + } + ( + InlineAsmRegClass::X86( + X86InlineAsmRegClass::xmm_reg + | X86InlineAsmRegClass::ymm_reg + | X86InlineAsmRegClass::zmm_reg, + ), + Abi::Vector { element, count: count @ (8 | 16) }, + ) if element.primitive() == Primitive::Float(Float::F16) => { + bx.bitcast(value, bx.type_vector(bx.type_f16(), count)) + } ( InlineAsmRegClass::Arm(ArmInlineAsmRegClass::sreg | ArmInlineAsmRegClass::sreg_low16), Abi::Scalar(s), @@ -1109,6 +1179,36 @@ fn llvm_fixup_output_type<'ll, 'tcx>( InlineAsmRegClass::X86(X86InlineAsmRegClass::xmm_reg | X86InlineAsmRegClass::zmm_reg), Abi::Vector { .. }, ) if layout.size.bytes() == 64 => cx.type_vector(cx.type_f64(), 8), + ( + InlineAsmRegClass::X86( + X86InlineAsmRegClass::xmm_reg + | X86InlineAsmRegClass::ymm_reg + | X86InlineAsmRegClass::zmm_reg, + ), + Abi::Scalar(s), + ) if cx.sess().asm_arch == Some(InlineAsmArch::X86) + && s.primitive() == Primitive::Float(Float::F128) => + { + cx.type_vector(cx.type_i32(), 4) + } + ( + InlineAsmRegClass::X86( + X86InlineAsmRegClass::xmm_reg + | X86InlineAsmRegClass::ymm_reg + | X86InlineAsmRegClass::zmm_reg, + ), + Abi::Scalar(s), + ) if s.primitive() == Primitive::Float(Float::F16) => cx.type_vector(cx.type_i16(), 8), + ( + InlineAsmRegClass::X86( + X86InlineAsmRegClass::xmm_reg + | X86InlineAsmRegClass::ymm_reg + | X86InlineAsmRegClass::zmm_reg, + ), + Abi::Vector { element, count: count @ (8 | 16) }, + ) if element.primitive() == Primitive::Float(Float::F16) => { + cx.type_vector(cx.type_i16(), count) + } ( InlineAsmRegClass::Arm(ArmInlineAsmRegClass::sreg | ArmInlineAsmRegClass::sreg_low16), Abi::Scalar(s), diff --git a/compiler/rustc_codegen_llvm/src/debuginfo/metadata.rs b/compiler/rustc_codegen_llvm/src/debuginfo/metadata.rs index a543ccbde0edf..8de4e0effad28 100644 --- a/compiler/rustc_codegen_llvm/src/debuginfo/metadata.rs +++ b/compiler/rustc_codegen_llvm/src/debuginfo/metadata.rs @@ -36,7 +36,7 @@ use rustc_middle::ty::{ }; use rustc_session::config::{self, DebugInfo, Lto}; use rustc_span::symbol::Symbol; -use rustc_span::FileName; +use rustc_span::{hygiene, FileName, DUMMY_SP}; use rustc_span::{FileNameDisplayPreference, SourceFile}; use rustc_symbol_mangling::typeid_for_trait_ref; use rustc_target::abi::{Align, Size}; @@ -1306,7 +1306,7 @@ pub fn build_global_var_di_node<'ll>(cx: &CodegenCx<'ll, '_>, def_id: DefId, glo // We may want to remove the namespace scope if we're in an extern block (see // https://github.com/rust-lang/rust/pull/46457#issuecomment-351750952). let var_scope = get_namespace_for_item(cx, def_id); - let span = tcx.def_span(def_id); + let span = hygiene::walk_chain_collapsed(tcx.def_span(def_id), DUMMY_SP); let (file_metadata, line_number) = if !span.is_dummy() { let loc = cx.lookup_debug_loc(span.lo()); diff --git a/compiler/rustc_codegen_llvm/src/llvm_util.rs b/compiler/rustc_codegen_llvm/src/llvm_util.rs index 53b9b530e9bd6..7e0f264a4aedf 100644 --- a/compiler/rustc_codegen_llvm/src/llvm_util.rs +++ b/compiler/rustc_codegen_llvm/src/llvm_util.rs @@ -394,10 +394,15 @@ fn print_target_features(out: &mut dyn PrintBackendInfo, sess: &Session, tm: &ll (*feature, desc) }) .collect::>(); + + // Since we add this at the end ... rustc_target_features.extend_from_slice(&[( "crt-static", "Enables C Run-time Libraries to be statically linked", )]); + // ... we need to sort the list again. + rustc_target_features.sort(); + llvm_target_features.retain(|(f, _d)| !known_llvm_target_features.contains(f)); let max_feature_len = llvm_target_features diff --git a/compiler/rustc_codegen_ssa/src/base.rs b/compiler/rustc_codegen_ssa/src/base.rs index 0b450c43924e8..c18816533a2fb 100644 --- a/compiler/rustc_codegen_ssa/src/base.rs +++ b/compiler/rustc_codegen_ssa/src/base.rs @@ -163,8 +163,7 @@ pub fn unsized_info<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>>( // trait upcasting coercion - let vptr_entry_idx = - cx.tcx().vtable_trait_upcasting_coercion_new_vptr_slot((source, target)); + let vptr_entry_idx = cx.tcx().supertrait_vtable_slot((source, target)); if let Some(entry_idx) = vptr_entry_idx { let ptr_size = bx.data_layout().pointer_size; diff --git a/compiler/rustc_const_eval/src/check_consts/check.rs b/compiler/rustc_const_eval/src/check_consts/check.rs index 9e01c59a96f9f..0818d9425e20c 100644 --- a/compiler/rustc_const_eval/src/check_consts/check.rs +++ b/compiler/rustc_const_eval/src/check_consts/check.rs @@ -1,8 +1,8 @@ //! The `Visitor` responsible for actually checking a `mir::Body` for invalid operations. use rustc_errors::{Diag, ErrorGuaranteed}; -use rustc_hir as hir; use rustc_hir::def_id::DefId; +use rustc_hir::{self as hir, LangItem}; use rustc_index::bit_set::BitSet; use rustc_infer::infer::TyCtxtInferExt; use rustc_infer::traits::ObligationCause; @@ -801,7 +801,7 @@ impl<'tcx> Visitor<'tcx> for Checker<'_, 'tcx> { // const-eval. // const-eval of the `begin_panic` fn assumes the argument is `&str` - if Some(callee) == tcx.lang_items().begin_panic_fn() { + if tcx.is_lang_item(callee, LangItem::BeginPanic) { match args[0].node.ty(&self.ccx.body.local_decls, tcx).kind() { ty::Ref(_, ty, _) if ty.is_str() => return, _ => self.check_op(ops::PanicNonStr), @@ -819,7 +819,7 @@ impl<'tcx> Visitor<'tcx> for Checker<'_, 'tcx> { } } - if Some(callee) == tcx.lang_items().exchange_malloc_fn() { + if tcx.is_lang_item(callee, LangItem::ExchangeMalloc) { self.check_op(ops::HeapAllocation); return; } diff --git a/compiler/rustc_const_eval/src/check_consts/ops.rs b/compiler/rustc_const_eval/src/check_consts/ops.rs index feab5b929acbb..eb9a83fb9cfa4 100644 --- a/compiler/rustc_const_eval/src/check_consts/ops.rs +++ b/compiler/rustc_const_eval/src/check_consts/ops.rs @@ -218,7 +218,7 @@ impl<'tcx> NonConstOp<'tcx> for FnCallNonConst<'tcx> { } else { let mut sugg = None; - if Some(trait_id) == ccx.tcx.lang_items().eq_trait() { + if ccx.tcx.is_lang_item(trait_id, LangItem::PartialEq) { match (args[0].unpack(), args[1].unpack()) { (GenericArgKind::Type(self_ty), GenericArgKind::Type(rhs_ty)) if self_ty == rhs_ty diff --git a/compiler/rustc_const_eval/src/const_eval/error.rs b/compiler/rustc_const_eval/src/const_eval/error.rs index 923b9ddf9afbb..b17dc7f3ddde6 100644 --- a/compiler/rustc_const_eval/src/const_eval/error.rs +++ b/compiler/rustc_const_eval/src/const_eval/error.rs @@ -1,7 +1,6 @@ use std::mem; use rustc_errors::{DiagArgName, DiagArgValue, DiagMessage, Diagnostic, IntoDiagArg}; -use rustc_hir::CRATE_HIR_ID; use rustc_middle::mir::interpret::{Provenance, ReportedErrorInfo}; use rustc_middle::mir::AssertKind; use rustc_middle::query::TyCtxtAt; @@ -9,7 +8,7 @@ use rustc_middle::ty::TyCtxt; use rustc_middle::ty::{layout::LayoutError, ConstInt}; use rustc_span::{Span, Symbol}; -use super::CompileTimeInterpreter; +use super::CompileTimeMachine; use crate::errors::{self, FrameNote, ReportErrorExt}; use crate::interpret::{err_inval, err_machine_stop}; use crate::interpret::{ErrorHandled, Frame, InterpError, InterpErrorInfo, MachineStopType}; @@ -156,11 +155,11 @@ where } } -/// Emit a lint from a const-eval situation. +/// Emit a lint from a const-eval situation, with a backtrace. // Even if this is unused, please don't remove it -- chances are we will need to emit a lint during const-eval again in the future! pub(super) fn lint<'tcx, L>( tcx: TyCtxtAt<'tcx>, - machine: &CompileTimeInterpreter<'tcx>, + machine: &CompileTimeMachine<'tcx>, lint: &'static rustc_session::lint::Lint, decorator: impl FnOnce(Vec) -> L, ) where @@ -168,12 +167,5 @@ pub(super) fn lint<'tcx, L>( { let (span, frames) = get_span_and_frames(tcx, &machine.stack); - tcx.emit_node_span_lint( - lint, - // We use the root frame for this so the crate that defines the const defines whether the - // lint is emitted. - machine.stack.first().and_then(|frame| frame.lint_root()).unwrap_or(CRATE_HIR_ID), - span, - decorator(frames), - ); + tcx.emit_node_span_lint(lint, machine.best_lint_scope(*tcx), span, decorator(frames)); } diff --git a/compiler/rustc_const_eval/src/const_eval/eval_queries.rs b/compiler/rustc_const_eval/src/const_eval/eval_queries.rs index 36f468d3308a8..4b8145eb4855b 100644 --- a/compiler/rustc_const_eval/src/const_eval/eval_queries.rs +++ b/compiler/rustc_const_eval/src/const_eval/eval_queries.rs @@ -17,7 +17,7 @@ use rustc_span::def_id::LocalDefId; use rustc_span::{Span, DUMMY_SP}; use rustc_target::abi::{self, Abi}; -use super::{CanAccessMutGlobal, CompileTimeEvalContext, CompileTimeInterpreter}; +use super::{CanAccessMutGlobal, CompileTimeInterpCx, CompileTimeMachine}; use crate::const_eval::CheckAlignment; use crate::errors::ConstEvalError; use crate::errors::{self, DanglingPtrInFinal}; @@ -32,7 +32,7 @@ use crate::CTRL_C_RECEIVED; // Returns a pointer to where the result lives #[instrument(level = "trace", skip(ecx, body))] fn eval_body_using_ecx<'tcx, R: InterpretationResult<'tcx>>( - ecx: &mut CompileTimeEvalContext<'tcx>, + ecx: &mut CompileTimeInterpCx<'tcx>, cid: GlobalId<'tcx>, body: &'tcx mir::Body<'tcx>, ) -> InterpResult<'tcx, R> { @@ -114,7 +114,7 @@ fn eval_body_using_ecx<'tcx, R: InterpretationResult<'tcx>>( let err_diag = errors::MutablePtrInFinal { span: ecx.tcx.span, kind: intern_kind }; ecx.tcx.emit_node_span_lint( lint::builtin::CONST_EVAL_MUTABLE_PTR_IN_FINAL_VALUE, - ecx.best_lint_scope(), + ecx.machine.best_lint_scope(*ecx.tcx), err_diag.span, err_diag, ) @@ -139,13 +139,13 @@ pub(crate) fn mk_eval_cx_to_read_const_val<'tcx>( root_span: Span, param_env: ty::ParamEnv<'tcx>, can_access_mut_global: CanAccessMutGlobal, -) -> CompileTimeEvalContext<'tcx> { +) -> CompileTimeInterpCx<'tcx> { debug!("mk_eval_cx: {:?}", param_env); InterpCx::new( tcx, root_span, param_env, - CompileTimeInterpreter::new(can_access_mut_global, CheckAlignment::No), + CompileTimeMachine::new(can_access_mut_global, CheckAlignment::No), ) } @@ -156,7 +156,7 @@ pub fn mk_eval_cx_for_const_val<'tcx>( param_env: ty::ParamEnv<'tcx>, val: mir::ConstValue<'tcx>, ty: Ty<'tcx>, -) -> Option<(CompileTimeEvalContext<'tcx>, OpTy<'tcx>)> { +) -> Option<(CompileTimeInterpCx<'tcx>, OpTy<'tcx>)> { let ecx = mk_eval_cx_to_read_const_val(tcx.tcx, tcx.span, param_env, CanAccessMutGlobal::No); let op = ecx.const_val_to_op(val, ty, None).ok()?; Some((ecx, op)) @@ -170,7 +170,7 @@ pub fn mk_eval_cx_for_const_val<'tcx>( /// encounter an `Indirect` they cannot handle. #[instrument(skip(ecx), level = "debug")] pub(super) fn op_to_const<'tcx>( - ecx: &CompileTimeEvalContext<'tcx>, + ecx: &CompileTimeInterpCx<'tcx>, op: &OpTy<'tcx>, for_diagnostics: bool, ) -> ConstValue<'tcx> { @@ -328,14 +328,14 @@ pub trait InterpretationResult<'tcx> { /// evaluation query. fn make_result( mplace: MPlaceTy<'tcx>, - ecx: &mut InterpCx<'tcx, CompileTimeInterpreter<'tcx>>, + ecx: &mut InterpCx<'tcx, CompileTimeMachine<'tcx>>, ) -> Self; } impl<'tcx> InterpretationResult<'tcx> for ConstAlloc<'tcx> { fn make_result( mplace: MPlaceTy<'tcx>, - _ecx: &mut InterpCx<'tcx, CompileTimeInterpreter<'tcx>>, + _ecx: &mut InterpCx<'tcx, CompileTimeMachine<'tcx>>, ) -> Self { ConstAlloc { alloc_id: mplace.ptr().provenance.unwrap().alloc_id(), ty: mplace.layout.ty } } @@ -383,7 +383,7 @@ fn eval_in_interpreter<'tcx, R: InterpretationResult<'tcx>>( // they do not have to behave "as if" they were evaluated at runtime. // For consts however we want to ensure they behave "as if" they were evaluated at runtime, // so we have to reject reading mutable global memory. - CompileTimeInterpreter::new(CanAccessMutGlobal::from(is_static), CheckAlignment::Error), + CompileTimeMachine::new(CanAccessMutGlobal::from(is_static), CheckAlignment::Error), ); let res = ecx.load_mir(cid.instance.def, cid.promoted); res.and_then(|body| eval_body_using_ecx(&mut ecx, cid, body)).map_err(|error| { @@ -417,7 +417,7 @@ fn eval_in_interpreter<'tcx, R: InterpretationResult<'tcx>>( #[inline(always)] fn const_validate_mplace<'tcx>( - ecx: &InterpCx<'tcx, CompileTimeInterpreter<'tcx>>, + ecx: &InterpCx<'tcx, CompileTimeMachine<'tcx>>, mplace: &MPlaceTy<'tcx>, cid: GlobalId<'tcx>, ) -> Result<(), ErrorHandled> { @@ -447,7 +447,7 @@ fn const_validate_mplace<'tcx>( #[inline(always)] fn report_validation_error<'tcx>( - ecx: &InterpCx<'tcx, CompileTimeInterpreter<'tcx>>, + ecx: &InterpCx<'tcx, CompileTimeMachine<'tcx>>, error: InterpErrorInfo<'tcx>, alloc_id: AllocId, ) -> ErrorHandled { diff --git a/compiler/rustc_const_eval/src/const_eval/machine.rs b/compiler/rustc_const_eval/src/const_eval/machine.rs index 79a161d3f03d7..d3631e0d72321 100644 --- a/compiler/rustc_const_eval/src/const_eval/machine.rs +++ b/compiler/rustc_const_eval/src/const_eval/machine.rs @@ -9,12 +9,13 @@ use rustc_data_structures::fx::IndexEntry; use rustc_hir::def_id::DefId; use rustc_hir::def_id::LocalDefId; use rustc_hir::LangItem; +use rustc_hir::{self as hir, CRATE_HIR_ID}; use rustc_middle::bug; use rustc_middle::mir; use rustc_middle::mir::AssertMessage; use rustc_middle::query::TyCtxtAt; -use rustc_middle::ty; use rustc_middle::ty::layout::{FnAbiOf, TyAndLayout}; +use rustc_middle::ty::{self, TyCtxt}; use rustc_session::lint::builtin::WRITES_THROUGH_IMMUTABLE_POINTER; use rustc_span::symbol::{sym, Symbol}; use rustc_span::Span; @@ -44,7 +45,7 @@ const TINY_LINT_TERMINATOR_LIMIT: usize = 20; const PROGRESS_INDICATOR_START: usize = 4_000_000; /// Extra machine state for CTFE, and the Machine instance -pub struct CompileTimeInterpreter<'tcx> { +pub struct CompileTimeMachine<'tcx> { /// The number of terminators that have been evaluated. /// /// This is used to produce lints informing the user that the compiler is not stuck. @@ -89,12 +90,12 @@ impl From for CanAccessMutGlobal { } } -impl<'tcx> CompileTimeInterpreter<'tcx> { +impl<'tcx> CompileTimeMachine<'tcx> { pub(crate) fn new( can_access_mut_global: CanAccessMutGlobal, check_alignment: CheckAlignment, ) -> Self { - CompileTimeInterpreter { + CompileTimeMachine { num_evaluated_steps: 0, stack: Vec::new(), can_access_mut_global, @@ -163,7 +164,7 @@ impl interpret::AllocMap for FxIndexMap { } } -pub(crate) type CompileTimeEvalContext<'tcx> = InterpCx<'tcx, CompileTimeInterpreter<'tcx>>; +pub(crate) type CompileTimeInterpCx<'tcx> = InterpCx<'tcx, CompileTimeMachine<'tcx>>; #[derive(Debug, PartialEq, Eq, Copy, Clone)] pub enum MemoryKind { @@ -195,7 +196,7 @@ impl interpret::MayLeak for ! { } } -impl<'tcx> CompileTimeEvalContext<'tcx> { +impl<'tcx> CompileTimeInterpCx<'tcx> { fn location_triple_for_span(&self, span: Span) -> (Symbol, u32, u32) { let topmost = span.ctxt().outer_expn().expansion_cause().unwrap_or(span); let caller = self.tcx.sess.source_map().lookup_char_pos(topmost.lo()); @@ -229,7 +230,7 @@ impl<'tcx> CompileTimeEvalContext<'tcx> { let def_id = instance.def_id(); if self.tcx.has_attr(def_id, sym::rustc_const_panic_str) - || Some(def_id) == self.tcx.lang_items().begin_panic_fn() + || self.tcx.is_lang_item(def_id, LangItem::BeginPanic) { let args = self.copy_fn_args(args); // &str or &&str @@ -244,7 +245,7 @@ impl<'tcx> CompileTimeEvalContext<'tcx> { let span = self.find_closest_untracked_caller_location(); let (file, line, col) = self.location_triple_for_span(span); return Err(ConstEvalErrKind::Panic { msg, file, line, col }.into()); - } else if Some(def_id) == self.tcx.lang_items().panic_fmt() { + } else if self.tcx.is_lang_item(def_id, LangItem::PanicFmt) { // For panic_fmt, call const_panic_fmt instead. let const_def_id = self.tcx.require_lang_item(LangItem::ConstPanicFmt, None); let new_instance = ty::Instance::expect_resolve( @@ -255,7 +256,7 @@ impl<'tcx> CompileTimeEvalContext<'tcx> { ); return Ok(Some(new_instance)); - } else if Some(def_id) == self.tcx.lang_items().align_offset_fn() { + } else if self.tcx.is_lang_item(def_id, LangItem::AlignOffset) { let args = self.copy_fn_args(args); // For align_offset, we replace the function call if the pointer has no address. match self.align_offset(instance, &args, dest, ret)? { @@ -369,7 +370,16 @@ impl<'tcx> CompileTimeEvalContext<'tcx> { } } -impl<'tcx> interpret::Machine<'tcx> for CompileTimeInterpreter<'tcx> { +impl<'tcx> CompileTimeMachine<'tcx> { + #[inline(always)] + /// Find the first stack frame that is within the current crate, if any. + /// Otherwise, return the crate's HirId + pub fn best_lint_scope(&self, tcx: TyCtxt<'tcx>) -> hir::HirId { + self.stack.iter().find_map(|frame| frame.lint_root(tcx)).unwrap_or(CRATE_HIR_ID) + } +} + +impl<'tcx> interpret::Machine<'tcx> for CompileTimeMachine<'tcx> { compile_time_machine!(<'tcx>); type MemoryKind = MemoryKind; @@ -600,7 +610,7 @@ impl<'tcx> interpret::Machine<'tcx> for CompileTimeInterpreter<'tcx> { // By default, we stop after a million steps, but the user can disable this lint // to be able to run until the heat death of the universe or power loss, whichever // comes first. - let hir_id = ecx.best_lint_scope(); + let hir_id = ecx.machine.best_lint_scope(*ecx.tcx); let is_error = ecx .tcx .lint_level_at_node( diff --git a/compiler/rustc_const_eval/src/const_eval/valtrees.rs b/compiler/rustc_const_eval/src/const_eval/valtrees.rs index 66993476bef43..2e8ad445cf5e8 100644 --- a/compiler/rustc_const_eval/src/const_eval/valtrees.rs +++ b/compiler/rustc_const_eval/src/const_eval/valtrees.rs @@ -9,7 +9,7 @@ use rustc_target::abi::{Abi, VariantIdx}; use tracing::{debug, instrument, trace}; use super::eval_queries::{mk_eval_cx_to_read_const_val, op_to_const}; -use super::machine::CompileTimeEvalContext; +use super::machine::CompileTimeInterpCx; use super::{ValTreeCreationError, ValTreeCreationResult, VALTREE_MAX_NODES}; use crate::const_eval::CanAccessMutGlobal; use crate::errors::MaxNumNodesInConstErr; @@ -21,7 +21,7 @@ use crate::interpret::{ #[instrument(skip(ecx), level = "debug")] fn branches<'tcx>( - ecx: &CompileTimeEvalContext<'tcx>, + ecx: &CompileTimeInterpCx<'tcx>, place: &MPlaceTy<'tcx>, n: usize, variant: Option, @@ -59,7 +59,7 @@ fn branches<'tcx>( #[instrument(skip(ecx), level = "debug")] fn slice_branches<'tcx>( - ecx: &CompileTimeEvalContext<'tcx>, + ecx: &CompileTimeInterpCx<'tcx>, place: &MPlaceTy<'tcx>, num_nodes: &mut usize, ) -> ValTreeCreationResult<'tcx> { @@ -77,7 +77,7 @@ fn slice_branches<'tcx>( #[instrument(skip(ecx), level = "debug")] fn const_to_valtree_inner<'tcx>( - ecx: &CompileTimeEvalContext<'tcx>, + ecx: &CompileTimeInterpCx<'tcx>, place: &MPlaceTy<'tcx>, num_nodes: &mut usize, ) -> ValTreeCreationResult<'tcx> { @@ -219,7 +219,7 @@ fn reconstruct_place_meta<'tcx>( #[instrument(skip(ecx), level = "debug", ret)] fn create_valtree_place<'tcx>( - ecx: &mut CompileTimeEvalContext<'tcx>, + ecx: &mut CompileTimeInterpCx<'tcx>, layout: TyAndLayout<'tcx>, valtree: ty::ValTree<'tcx>, ) -> MPlaceTy<'tcx> { @@ -364,7 +364,7 @@ pub fn valtree_to_const_value<'tcx>( /// Put a valtree into memory and return a reference to that. fn valtree_to_ref<'tcx>( - ecx: &mut CompileTimeEvalContext<'tcx>, + ecx: &mut CompileTimeInterpCx<'tcx>, valtree: ty::ValTree<'tcx>, pointee_ty: Ty<'tcx>, ) -> Immediate { @@ -380,7 +380,7 @@ fn valtree_to_ref<'tcx>( #[instrument(skip(ecx), level = "debug")] fn valtree_into_mplace<'tcx>( - ecx: &mut CompileTimeEvalContext<'tcx>, + ecx: &mut CompileTimeInterpCx<'tcx>, place: &MPlaceTy<'tcx>, valtree: ty::ValTree<'tcx>, ) { @@ -457,6 +457,6 @@ fn valtree_into_mplace<'tcx>( } } -fn dump_place<'tcx>(ecx: &CompileTimeEvalContext<'tcx>, place: &MPlaceTy<'tcx>) { +fn dump_place<'tcx>(ecx: &CompileTimeInterpCx<'tcx>, place: &MPlaceTy<'tcx>) { trace!("{:?}", ecx.dump_place(&PlaceTy::from(place.clone()))); } diff --git a/compiler/rustc_const_eval/src/interpret/discriminant.rs b/compiler/rustc_const_eval/src/interpret/discriminant.rs index 0dbee8c1d948e..a50b50d231d78 100644 --- a/compiler/rustc_const_eval/src/interpret/discriminant.rs +++ b/compiler/rustc_const_eval/src/interpret/discriminant.rs @@ -241,10 +241,7 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> { variant_index: VariantIdx, ) -> InterpResult<'tcx, Option<(ScalarInt, usize)>> { match self.layout_of(ty)?.variants { - abi::Variants::Single { index } => { - assert_eq!(index, variant_index); - Ok(None) - } + abi::Variants::Single { .. } => Ok(None), abi::Variants::Multiple { tag_encoding: TagEncoding::Direct, diff --git a/compiler/rustc_const_eval/src/interpret/eval_context.rs b/compiler/rustc_const_eval/src/interpret/eval_context.rs index e28cc05cc2a80..4d93038a81e44 100644 --- a/compiler/rustc_const_eval/src/interpret/eval_context.rs +++ b/compiler/rustc_const_eval/src/interpret/eval_context.rs @@ -4,7 +4,6 @@ use std::{fmt, mem}; use either::{Either, Left, Right}; use tracing::{debug, info, info_span, instrument, trace}; -use hir::CRATE_HIR_ID; use rustc_errors::DiagCtxt; use rustc_hir::{self as hir, def_id::DefId, definitions::DefPathData}; use rustc_index::IndexVec; @@ -250,7 +249,7 @@ impl<'tcx, Prov: Provenance> Frame<'tcx, Prov> { impl<'tcx, Prov: Provenance, Extra> Frame<'tcx, Prov, Extra> { /// Get the current location within the Frame. /// - /// If this is `Left`, we are not currently executing any particular statement in + /// If this is `Right`, we are not currently executing any particular statement in /// this frame (can happen e.g. during frame initialization, and during unwinding on /// frames without cleanup code). /// @@ -271,13 +270,18 @@ impl<'tcx, Prov: Provenance, Extra> Frame<'tcx, Prov, Extra> { } } - pub fn lint_root(&self) -> Option { - self.current_source_info().and_then(|source_info| { - match &self.body.source_scopes[source_info.scope].local_data { + pub fn lint_root(&self, tcx: TyCtxt<'tcx>) -> Option { + // We first try to get a HirId via the current source scope, + // and fall back to `body.source`. + self.current_source_info() + .and_then(|source_info| match &self.body.source_scopes[source_info.scope].local_data { mir::ClearCrossCrate::Set(data) => Some(data.lint_root), mir::ClearCrossCrate::Clear => None, - } - }) + }) + .or_else(|| { + let def_id = self.body.source.def_id().as_local(); + def_id.map(|def_id| tcx.local_def_id_to_hir_id(def_id)) + }) } /// Returns the address of the buffer where the locals are stored. This is used by `Place` as a @@ -500,6 +504,8 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> { } } + /// Returns the span of the currently executed statement/terminator. + /// This is the span typically used for error reporting. #[inline(always)] pub fn cur_span(&self) -> Span { // This deliberately does *not* honor `requires_caller_location` since it is used for much @@ -507,16 +513,6 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> { self.stack().last().map_or(self.tcx.span, |f| f.current_span()) } - #[inline(always)] - /// Find the first stack frame that is within the current crate, if any, otherwise return the crate's HirId - pub fn best_lint_scope(&self) -> hir::HirId { - self.stack() - .iter() - .find_map(|frame| frame.body.source.def_id().as_local()) - .map_or(CRATE_HIR_ID, |def_id| self.tcx.local_def_id_to_hir_id(def_id)) - } - - #[inline(always)] pub(crate) fn stack(&self) -> &[Frame<'tcx, M::Provenance, M::FrameExtra>] { M::stack(self) } @@ -632,7 +628,8 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> { } /// Walks up the callstack from the intrinsic's callsite, searching for the first callsite in a - /// frame which is not `#[track_caller]`. This is the fancy version of `cur_span`. + /// frame which is not `#[track_caller]`. This matches the `caller_location` intrinsic, + /// and is primarily intended for the panic machinery. pub(crate) fn find_closest_untracked_caller_location(&self) -> Span { for frame in self.stack().iter().rev() { debug!("find_closest_untracked_caller_location: checking frame {:?}", frame.instance); @@ -1057,7 +1054,7 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> { ty::Str | ty::Slice(_) | ty::Dynamic(_, _, ty::Dyn) | ty::Foreign(..) => false, - ty::Tuple(tys) => tys.last().iter().all(|ty| is_very_trivially_sized(**ty)), + ty::Tuple(tys) => tys.last().is_none_or(|ty| is_very_trivially_sized(*ty)), ty::Pat(ty, ..) => is_very_trivially_sized(*ty), diff --git a/compiler/rustc_const_eval/src/interpret/intern.rs b/compiler/rustc_const_eval/src/interpret/intern.rs index 3066e0933d94d..8b0a2afa4d669 100644 --- a/compiler/rustc_const_eval/src/interpret/intern.rs +++ b/compiler/rustc_const_eval/src/interpret/intern.rs @@ -45,7 +45,7 @@ pub trait HasStaticRootDefId { fn static_def_id(&self) -> Option; } -impl HasStaticRootDefId for const_eval::CompileTimeInterpreter<'_> { +impl HasStaticRootDefId for const_eval::CompileTimeMachine<'_> { fn static_def_id(&self) -> Option { Some(self.static_root_ids?.1) } diff --git a/compiler/rustc_const_eval/src/interpret/memory.rs b/compiler/rustc_const_eval/src/interpret/memory.rs index 5461e9c6ad3f6..9a26ac04b85a3 100644 --- a/compiler/rustc_const_eval/src/interpret/memory.rs +++ b/compiler/rustc_const_eval/src/interpret/memory.rs @@ -446,7 +446,7 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> { let (alloc_size, _alloc_align, ret_val) = alloc_size(alloc_id, offset, prov)?; // Test bounds. // It is sufficient to check this for the end pointer. Also check for overflow! - if offset.checked_add(size, &self.tcx).map_or(true, |end| end > alloc_size) { + if offset.checked_add(size, &self.tcx).is_none_or(|end| end > alloc_size) { throw_ub!(PointerOutOfBounds { alloc_id, alloc_size, diff --git a/compiler/rustc_const_eval/src/interpret/operator.rs b/compiler/rustc_const_eval/src/interpret/operator.rs index a6eef9f5662ca..73bdf96627ae4 100644 --- a/compiler/rustc_const_eval/src/interpret/operator.rs +++ b/compiler/rustc_const_eval/src/interpret/operator.rs @@ -112,25 +112,20 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> { // Shift ops can have an RHS with a different numeric type. if matches!(bin_op, Shl | ShlUnchecked | Shr | ShrUnchecked) { - let size = left.layout.size.bits(); + let l_bits = left.layout.size.bits(); // Compute the equivalent shift modulo `size` that is in the range `0..size`. (This is // the one MIR operator that does *not* directly map to a single LLVM operation.) let (shift_amount, overflow) = if right.layout.abi.is_signed() { let shift_amount = r_signed(); - let overflow = shift_amount < 0 || shift_amount >= i128::from(size); - // Deliberately wrapping `as` casts: shift_amount *can* be negative, but the result - // of the `as` will be equal modulo `size` (since it is a power of two). - let masked_amount = (shift_amount as u128) % u128::from(size); - assert_eq!(overflow, shift_amount != i128::try_from(masked_amount).unwrap()); - (masked_amount, overflow) + let rem = shift_amount.rem_euclid(l_bits.into()); + // `rem` is guaranteed positive, so the `unwrap` cannot fail + (u128::try_from(rem).unwrap(), rem != shift_amount) } else { let shift_amount = r_unsigned(); - let overflow = shift_amount >= u128::from(size); - let masked_amount = shift_amount % u128::from(size); - assert_eq!(overflow, shift_amount != masked_amount); - (masked_amount, overflow) + let rem = shift_amount.rem_euclid(l_bits.into()); + (rem, rem != shift_amount) }; - let shift_amount = u32::try_from(shift_amount).unwrap(); // we masked so this will always fit + let shift_amount = u32::try_from(shift_amount).unwrap(); // we brought this in the range `0..size` so this will always fit // Compute the shifted result. let result = if left.layout.abi.is_signed() { let l = l_signed(); @@ -362,14 +357,18 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> { let left = left.to_scalar(); let right = right.to_scalar(); Ok(match fty { - FloatTy::F16 => unimplemented!("f16_f128"), + FloatTy::F16 => { + self.binary_float_op(bin_op, layout, left.to_f16()?, right.to_f16()?) + } FloatTy::F32 => { self.binary_float_op(bin_op, layout, left.to_f32()?, right.to_f32()?) } FloatTy::F64 => { self.binary_float_op(bin_op, layout, left.to_f64()?, right.to_f64()?) } - FloatTy::F128 => unimplemented!("f16_f128"), + FloatTy::F128 => { + self.binary_float_op(bin_op, layout, left.to_f128()?, right.to_f128()?) + } }) } _ if left.layout.ty.is_integral() => { @@ -429,11 +428,16 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> { } ty::Float(fty) => { let val = val.to_scalar(); + if un_op != Neg { + span_bug!(self.cur_span(), "Invalid float op {:?}", un_op); + } + // No NaN adjustment here, `-` is a bitwise operation! - let res = match (un_op, fty) { - (Neg, FloatTy::F32) => Scalar::from_f32(-val.to_f32()?), - (Neg, FloatTy::F64) => Scalar::from_f64(-val.to_f64()?), - _ => span_bug!(self.cur_span(), "Invalid float op {:?}", un_op), + let res = match fty { + FloatTy::F16 => Scalar::from_f16(-val.to_f16()?), + FloatTy::F32 => Scalar::from_f32(-val.to_f32()?), + FloatTy::F64 => Scalar::from_f64(-val.to_f64()?), + FloatTy::F128 => Scalar::from_f128(-val.to_f128()?), }; Ok(ImmTy::from_scalar(res, layout)) } diff --git a/compiler/rustc_const_eval/src/interpret/projection.rs b/compiler/rustc_const_eval/src/interpret/projection.rs index 09e1a59dfa1a7..efa01b5434260 100644 --- a/compiler/rustc_const_eval/src/interpret/projection.rs +++ b/compiler/rustc_const_eval/src/interpret/projection.rs @@ -300,7 +300,7 @@ where ) -> InterpResult<'tcx, P> { let len = base.len(self)?; // also asserts that we have a type where this makes sense let actual_to = if from_end { - if from.checked_add(to).map_or(true, |to| to > len) { + if from.checked_add(to).is_none_or(|to| to > len) { // This can only be reached in ConstProp and non-rustc-MIR. throw_ub!(BoundsCheckFailed { len: len, index: from.saturating_add(to) }); } diff --git a/compiler/rustc_const_eval/src/interpret/util.rs b/compiler/rustc_const_eval/src/interpret/util.rs index 10fd6399b9a37..f6537ed6ea9ed 100644 --- a/compiler/rustc_const_eval/src/interpret/util.rs +++ b/compiler/rustc_const_eval/src/interpret/util.rs @@ -1,4 +1,4 @@ -use crate::const_eval::{CompileTimeEvalContext, CompileTimeInterpreter, InterpretationResult}; +use crate::const_eval::{CompileTimeInterpCx, CompileTimeMachine, InterpretationResult}; use rustc_hir::def_id::LocalDefId; use rustc_middle::mir; use rustc_middle::mir::interpret::{Allocation, InterpResult, Pointer}; @@ -84,7 +84,7 @@ where impl<'tcx> InterpretationResult<'tcx> for mir::interpret::ConstAllocation<'tcx> { fn make_result( mplace: MPlaceTy<'tcx>, - ecx: &mut InterpCx<'tcx, CompileTimeInterpreter<'tcx>>, + ecx: &mut InterpCx<'tcx, CompileTimeMachine<'tcx>>, ) -> Self { let alloc_id = mplace.ptr().provenance.unwrap().alloc_id(); let alloc = ecx.memory.alloc_map.swap_remove(&alloc_id).unwrap().1; @@ -93,7 +93,7 @@ impl<'tcx> InterpretationResult<'tcx> for mir::interpret::ConstAllocation<'tcx> } pub(crate) fn create_static_alloc<'tcx>( - ecx: &mut CompileTimeEvalContext<'tcx>, + ecx: &mut CompileTimeInterpCx<'tcx>, static_def_id: LocalDefId, layout: TyAndLayout<'tcx>, ) -> InterpResult<'tcx, MPlaceTy<'tcx>> { diff --git a/compiler/rustc_const_eval/src/interpret/validity.rs b/compiler/rustc_const_eval/src/interpret/validity.rs index 6f75bc2af4ec8..ca8b98849338b 100644 --- a/compiler/rustc_const_eval/src/interpret/validity.rs +++ b/compiler/rustc_const_eval/src/interpret/validity.rs @@ -29,7 +29,7 @@ use rustc_target::abi::{ use std::hash::Hash; use super::{ - err_ub, format_interp_error, machine::AllocMap, throw_ub, AllocId, CheckInAllocMsg, + err_ub, format_interp_error, machine::AllocMap, throw_ub, AllocId, AllocKind, CheckInAllocMsg, GlobalAlloc, ImmTy, Immediate, InterpCx, InterpResult, MPlaceTy, Machine, MemPlaceMeta, OpTy, Pointer, Projectable, Scalar, ValueVisitor, }; @@ -413,8 +413,6 @@ impl<'rt, 'tcx, M: Machine<'tcx>> ValidityVisitor<'rt, 'tcx, M> { Ub(PointerOutOfBounds { .. }) => DanglingPtrOutOfBounds { ptr_kind }, - // This cannot happen during const-eval (because interning already detects - // dangling pointers), but it can happen in Miri. Ub(PointerUseAfterFree(..)) => DanglingPtrUseAfterFree { ptr_kind, }, @@ -493,9 +491,17 @@ impl<'rt, 'tcx, M: Machine<'tcx>> ValidityVisitor<'rt, 'tcx, M> { } } - // Mutability check. + // Dangling and Mutability check. + let (size, _align, alloc_kind) = self.ecx.get_alloc_info(alloc_id); + if alloc_kind == AllocKind::Dead { + // This can happen for zero-sized references. We can't have *any* references to non-existing + // allocations though, interning rejects them all as the rest of rustc isn't happy with them... + // so we throw an error, even though this isn't really UB. + // A potential future alternative would be to resurrect this as a zero-sized allocation + // (which codegen will then compile to an aligned dummy pointer anyway). + throw_validation_failure!(self.path, DanglingPtrUseAfterFree { ptr_kind }); + } // If this allocation has size zero, there is no actual mutability here. - let (size, _align, _alloc_kind) = self.ecx.get_alloc_info(alloc_id); if size != Size::ZERO { let alloc_actual_mutbl = mutability(self.ecx, alloc_id); // Mutable pointer to immutable memory is no good. diff --git a/compiler/rustc_const_eval/src/lib.rs b/compiler/rustc_const_eval/src/lib.rs index 45ea3ec08f8f4..50a4d0612ccd3 100644 --- a/compiler/rustc_const_eval/src/lib.rs +++ b/compiler/rustc_const_eval/src/lib.rs @@ -6,6 +6,7 @@ #![feature(box_patterns)] #![feature(decl_macro)] #![feature(if_let_guard)] +#![feature(is_none_or)] #![feature(let_chains)] #![feature(never_type)] #![feature(rustdoc_internals)] diff --git a/compiler/rustc_const_eval/src/util/caller_location.rs b/compiler/rustc_const_eval/src/util/caller_location.rs index 62c5f8734a249..3b07bee2d9c27 100644 --- a/compiler/rustc_const_eval/src/util/caller_location.rs +++ b/compiler/rustc_const_eval/src/util/caller_location.rs @@ -7,12 +7,12 @@ use rustc_middle::ty::{self, Mutability}; use rustc_span::symbol::Symbol; use tracing::trace; -use crate::const_eval::{mk_eval_cx_to_read_const_val, CanAccessMutGlobal, CompileTimeEvalContext}; +use crate::const_eval::{mk_eval_cx_to_read_const_val, CanAccessMutGlobal, CompileTimeInterpCx}; use crate::interpret::*; /// Allocate a `const core::panic::Location` with the provided filename and line/column numbers. fn alloc_caller_location<'tcx>( - ecx: &mut CompileTimeEvalContext<'tcx>, + ecx: &mut CompileTimeInterpCx<'tcx>, filename: Symbol, line: u32, col: u32, diff --git a/compiler/rustc_const_eval/src/util/check_validity_requirement.rs b/compiler/rustc_const_eval/src/util/check_validity_requirement.rs index 68fb122a765da..daf57285ebe6d 100644 --- a/compiler/rustc_const_eval/src/util/check_validity_requirement.rs +++ b/compiler/rustc_const_eval/src/util/check_validity_requirement.rs @@ -3,7 +3,7 @@ use rustc_middle::ty::layout::{LayoutCx, LayoutError, LayoutOf, TyAndLayout, Val use rustc_middle::ty::{ParamEnv, ParamEnvAnd, Ty, TyCtxt}; use rustc_target::abi::{Abi, FieldsShape, Scalar, Variants}; -use crate::const_eval::{CanAccessMutGlobal, CheckAlignment, CompileTimeInterpreter}; +use crate::const_eval::{CanAccessMutGlobal, CheckAlignment, CompileTimeMachine}; use crate::interpret::{InterpCx, MemoryKind, OpTy}; /// Determines if this type permits "raw" initialization by just transmuting some memory into an @@ -45,7 +45,7 @@ fn might_permit_raw_init_strict<'tcx>( tcx: TyCtxt<'tcx>, kind: ValidityRequirement, ) -> Result> { - let machine = CompileTimeInterpreter::new(CanAccessMutGlobal::No, CheckAlignment::Error); + let machine = CompileTimeMachine::new(CanAccessMutGlobal::No, CheckAlignment::Error); let mut cx = InterpCx::new(tcx, rustc_span::DUMMY_SP, ParamEnv::reveal_all(), machine); diff --git a/compiler/rustc_data_structures/Cargo.toml b/compiler/rustc_data_structures/Cargo.toml index 6876046a58380..ff0a94f8e9b27 100644 --- a/compiler/rustc_data_structures/Cargo.toml +++ b/compiler/rustc_data_structures/Cargo.toml @@ -12,7 +12,6 @@ elsa = "=1.7.1" ena = "0.14.3" indexmap = { version = "2.0.0" } jobserver_crate = { version = "0.1.28", package = "jobserver" } -libc = "0.2" measureme = "11" rustc-hash = "1.1.0" rustc-rayon = { version = "0.5.0", optional = true } @@ -41,6 +40,11 @@ features = [ "Win32_System_Threading", ] +[target.'cfg(unix)'.dependencies] +# tidy-alphabetical-start +libc = "0.2" +# tidy-alphabetical-end + [target.'cfg(not(target_arch = "wasm32"))'.dependencies] # tidy-alphabetical-start memmap2 = "0.2.1" diff --git a/compiler/rustc_data_structures/src/flock.rs b/compiler/rustc_data_structures/src/flock.rs index 008565e4c7b97..e03962a54ecab 100644 --- a/compiler/rustc_data_structures/src/flock.rs +++ b/compiler/rustc_data_structures/src/flock.rs @@ -9,6 +9,10 @@ cfg_match! { mod linux; use linux as imp; } + cfg(target_os = "redox") => { + mod linux; + use linux as imp; + } cfg(unix) => { mod unix; use unix as imp; diff --git a/compiler/rustc_expand/src/mbe/metavar_expr.rs b/compiler/rustc_expand/src/mbe/metavar_expr.rs index 128e9f48ff573..3295a91029eac 100644 --- a/compiler/rustc_expand/src/mbe/metavar_expr.rs +++ b/compiler/rustc_expand/src/mbe/metavar_expr.rs @@ -8,9 +8,14 @@ use rustc_session::parse::ParseSess; use rustc_span::symbol::Ident; use rustc_span::Span; +pub(crate) const RAW_IDENT_ERR: &str = "`${concat(..)}` currently does not support raw identifiers"; + /// A meta-variable expression, for expansions based on properties of meta-variables. -#[derive(Debug, Clone, PartialEq, Encodable, Decodable)] +#[derive(Debug, PartialEq, Encodable, Decodable)] pub(crate) enum MetaVarExpr { + /// Unification of two or more identifiers. + Concat(Box<[MetaVarExprConcatElem]>), + /// The number of repetitions of an identifier. Count(Ident, usize), @@ -42,6 +47,31 @@ impl MetaVarExpr { check_trailing_token(&mut tts, psess)?; let mut iter = args.trees(); let rslt = match ident.as_str() { + "concat" => { + let mut result = Vec::new(); + loop { + let is_var = try_eat_dollar(&mut iter); + let element_ident = parse_ident(&mut iter, psess, outer_span)?; + let element = if is_var { + MetaVarExprConcatElem::Var(element_ident) + } else { + MetaVarExprConcatElem::Ident(element_ident) + }; + result.push(element); + if iter.look_ahead(0).is_none() { + break; + } + if !try_eat_comma(&mut iter) { + return Err(psess.dcx.struct_span_err(outer_span, "expected comma")); + } + } + if result.len() < 2 { + return Err(psess + .dcx + .struct_span_err(ident.span, "`concat` must have at least two elements")); + } + MetaVarExpr::Concat(result.into()) + } "count" => parse_count(&mut iter, psess, ident.span)?, "ignore" => { eat_dollar(&mut iter, psess, ident.span)?; @@ -68,11 +98,21 @@ impl MetaVarExpr { pub(crate) fn ident(&self) -> Option { match *self { MetaVarExpr::Count(ident, _) | MetaVarExpr::Ignore(ident) => Some(ident), - MetaVarExpr::Index(..) | MetaVarExpr::Len(..) => None, + MetaVarExpr::Concat { .. } | MetaVarExpr::Index(..) | MetaVarExpr::Len(..) => None, } } } +#[derive(Debug, Decodable, Encodable, PartialEq)] +pub(crate) enum MetaVarExprConcatElem { + /// There is NO preceding dollar sign, which means that this identifier should be interpreted + /// as a literal. + Ident(Ident), + /// There is a preceding dollar sign, which means that this identifier should be expanded + /// and interpreted as a variable. + Var(Ident), +} + // Checks if there are any remaining tokens. For example, `${ignore(ident ... a b c ...)}` fn check_trailing_token<'psess>( iter: &mut RefTokenTreeCursor<'_>, @@ -138,26 +178,30 @@ fn parse_depth<'psess>( fn parse_ident<'psess>( iter: &mut RefTokenTreeCursor<'_>, psess: &'psess ParseSess, - span: Span, + fallback_span: Span, ) -> PResult<'psess, Ident> { - if let Some(tt) = iter.next() - && let TokenTree::Token(token, _) = tt - { - if let Some((elem, IdentIsRaw::No)) = token.ident() { - return Ok(elem); + let Some(tt) = iter.next() else { + return Err(psess.dcx.struct_span_err(fallback_span, "expected identifier")); + }; + let TokenTree::Token(token, _) = tt else { + return Err(psess.dcx.struct_span_err(tt.span(), "expected identifier")); + }; + if let Some((elem, is_raw)) = token.ident() { + if let IdentIsRaw::Yes = is_raw { + return Err(psess.dcx.struct_span_err(elem.span, RAW_IDENT_ERR)); } - let token_str = pprust::token_to_string(token); - let mut err = - psess.dcx.struct_span_err(span, format!("expected identifier, found `{}`", &token_str)); - err.span_suggestion( - token.span, - format!("try removing `{}`", &token_str), - "", - Applicability::MaybeIncorrect, - ); - return Err(err); + return Ok(elem); } - Err(psess.dcx.struct_span_err(span, "expected identifier")) + let token_str = pprust::token_to_string(token); + let mut err = + psess.dcx.struct_span_err(token.span, format!("expected identifier, found `{token_str}`")); + err.span_suggestion( + token.span, + format!("try removing `{token_str}`"), + "", + Applicability::MaybeIncorrect, + ); + Err(err) } /// Tries to move the iterator forward returning `true` if there is a comma. If not, then the @@ -170,6 +214,17 @@ fn try_eat_comma(iter: &mut RefTokenTreeCursor<'_>) -> bool { false } +/// Tries to move the iterator forward returning `true` if there is a dollar sign. If not, then the +/// iterator is not modified and the result is `false`. +fn try_eat_dollar(iter: &mut RefTokenTreeCursor<'_>) -> bool { + if let Some(TokenTree::Token(token::Token { kind: token::Dollar, .. }, _)) = iter.look_ahead(0) + { + let _ = iter.next(); + return true; + } + false +} + /// Expects that the next item is a dollar sign. fn eat_dollar<'psess>( iter: &mut RefTokenTreeCursor<'_>, diff --git a/compiler/rustc_expand/src/mbe/quoted.rs b/compiler/rustc_expand/src/mbe/quoted.rs index 8ad7cb15c92a9..74f78c0ef7857 100644 --- a/compiler/rustc_expand/src/mbe/quoted.rs +++ b/compiler/rustc_expand/src/mbe/quoted.rs @@ -155,6 +155,13 @@ fn maybe_emit_macro_metavar_expr_feature(features: &Features, sess: &Session, sp } } +fn maybe_emit_macro_metavar_expr_concat_feature(features: &Features, sess: &Session, span: Span) { + if !features.macro_metavar_expr_concat { + let msg = "the `concat` meta-variable expression is unstable"; + feature_err(sess, sym::macro_metavar_expr_concat, span, msg).emit(); + } +} + /// Takes a `tokenstream::TokenTree` and returns a `self::TokenTree`. Specifically, this takes a /// generic `TokenTree`, such as is used in the rest of the compiler, and returns a `TokenTree` /// for use in parsing a macro. @@ -217,11 +224,19 @@ fn parse_tree<'a>( return TokenTree::token(token::Dollar, dollar_span); } Ok(elem) => { - maybe_emit_macro_metavar_expr_feature( - features, - sess, - delim_span.entire(), - ); + if let MetaVarExpr::Concat(_) = elem { + maybe_emit_macro_metavar_expr_concat_feature( + features, + sess, + delim_span.entire(), + ); + } else { + maybe_emit_macro_metavar_expr_feature( + features, + sess, + delim_span.entire(), + ); + } return TokenTree::MetaVarExpr(delim_span, elem); } } diff --git a/compiler/rustc_expand/src/mbe/transcribe.rs b/compiler/rustc_expand/src/mbe/transcribe.rs index 25e961d600901..914bd03675a7d 100644 --- a/compiler/rustc_expand/src/mbe/transcribe.rs +++ b/compiler/rustc_expand/src/mbe/transcribe.rs @@ -3,18 +3,19 @@ use crate::errors::{ NoSyntaxVarsExprRepeat, VarStillRepeating, }; use crate::mbe::macro_parser::{NamedMatch, NamedMatch::*}; +use crate::mbe::metavar_expr::{MetaVarExprConcatElem, RAW_IDENT_ERR}; use crate::mbe::{self, KleeneOp, MetaVarExpr}; use rustc_ast::mut_visit::{self, MutVisitor}; +use rustc_ast::token::IdentIsRaw; use rustc_ast::token::{self, Delimiter, Token, TokenKind}; use rustc_ast::tokenstream::{DelimSpacing, DelimSpan, Spacing, TokenStream, TokenTree}; use rustc_data_structures::fx::FxHashMap; use rustc_errors::{pluralize, Diag, DiagCtxt, PResult}; use rustc_parse::parser::ParseNtResult; +use rustc_session::parse::ParseSess; use rustc_span::hygiene::{LocalExpnId, Transparency}; use rustc_span::symbol::{sym, Ident, MacroRulesNormalizedIdent}; -use rustc_span::{with_metavar_spans, Span, SyntaxContext}; - -use rustc_session::parse::ParseSess; +use rustc_span::{with_metavar_spans, Span, Symbol, SyntaxContext}; use smallvec::{smallvec, SmallVec}; use std::mem; @@ -30,7 +31,7 @@ impl MutVisitor for Marker { // it's some advanced case with macro-generated macros. So if we cache the marked version // of that context once, we'll typically have a 100% cache hit rate after that. let Marker(expn_id, transparency, ref mut cache) = *self; - span.update_ctxt(|ctxt| { + *span = span.map_ctxt(|ctxt| { *cache .entry(ctxt) .or_insert_with(|| ctxt.apply_mark(expn_id.to_expn_id(), transparency)) @@ -675,6 +676,23 @@ fn transcribe_metavar_expr<'a>( span }; match *expr { + MetaVarExpr::Concat(ref elements) => { + let mut concatenated = String::new(); + for element in elements.into_iter() { + let string = match element { + MetaVarExprConcatElem::Ident(ident) => ident.to_string(), + MetaVarExprConcatElem::Var(ident) => extract_ident(dcx, *ident, interp)?, + }; + concatenated.push_str(&string); + } + // The current implementation marks the span as coming from the macro regardless of + // contexts of the concatenated identifiers but this behavior may change in the + // future. + result.push(TokenTree::Token( + Token::from_ast_ident(Ident::new(Symbol::intern(&concatenated), visited_span())), + Spacing::Alone, + )); + } MetaVarExpr::Count(original_ident, depth) => { let matched = matched_from_ident(dcx, original_ident, interp)?; let count = count_repetitions(dcx, depth, matched, repeats, sp)?; @@ -709,3 +727,33 @@ fn transcribe_metavar_expr<'a>( } Ok(()) } + +/// Extracts an identifier that can be originated from a `$var:ident` variable or from a token tree. +fn extract_ident<'a>( + dcx: &'a DiagCtxt, + ident: Ident, + interp: &FxHashMap, +) -> PResult<'a, String> { + if let NamedMatch::MatchedSingle(pnr) = matched_from_ident(dcx, ident, interp)? { + if let ParseNtResult::Ident(nt_ident, is_raw) = pnr { + if let IdentIsRaw::Yes = is_raw { + return Err(dcx.struct_span_err(ident.span, RAW_IDENT_ERR)); + } + return Ok(nt_ident.to_string()); + } + if let ParseNtResult::Tt(TokenTree::Token( + Token { kind: TokenKind::Ident(token_ident, is_raw), .. }, + _, + )) = pnr + { + if let IdentIsRaw::Yes = is_raw { + return Err(dcx.struct_span_err(ident.span, RAW_IDENT_ERR)); + } + return Ok(token_ident.to_string()); + } + } + Err(dcx.struct_span_err( + ident.span, + "`${concat(..)}` currently only accepts identifiers or meta-variables as parameters", + )) +} diff --git a/compiler/rustc_feature/src/unstable.rs b/compiler/rustc_feature/src/unstable.rs index 2d13f430cfce1..58832cb108750 100644 --- a/compiler/rustc_feature/src/unstable.rs +++ b/compiler/rustc_feature/src/unstable.rs @@ -516,6 +516,8 @@ declare_features! ( (unstable, lint_reasons, "1.31.0", Some(54503)), /// Give access to additional metadata about declarative macro meta-variables. (unstable, macro_metavar_expr, "1.61.0", Some(83527)), + /// Provides a way to concatenate identifiers using metavariable expressions. + (unstable, macro_metavar_expr_concat, "CURRENT_RUSTC_VERSION", Some(124225)), /// Allows `#[marker]` on certain traits allowing overlapping implementations. (unstable, marker_trait_attr, "1.30.0", Some(29864)), /// Allows exhaustive pattern matching on types that contain uninhabited types in cases that are diff --git a/compiler/rustc_hir/src/hir.rs b/compiler/rustc_hir/src/hir.rs index 042894beec221..d4a22c4c31f6a 100644 --- a/compiler/rustc_hir/src/hir.rs +++ b/compiler/rustc_hir/src/hir.rs @@ -1633,6 +1633,13 @@ pub struct ConstBlock { } /// An expression. +/// +/// For more details, see the [rust lang reference]. +/// Note that the reference does not document nightly-only features. +/// There may be also slight differences in the names and representation of AST nodes between +/// the compiler and the reference. +/// +/// [rust lang reference]: https://doc.rust-lang.org/reference/expressions.html #[derive(Debug, Clone, Copy, HashStable_Generic)] pub struct Expr<'hir> { pub hir_id: HirId, @@ -2464,6 +2471,15 @@ pub enum AssocItemConstraintKind<'hir> { Bound { bounds: &'hir [GenericBound<'hir>] }, } +impl<'hir> AssocItemConstraintKind<'hir> { + pub fn descr(&self) -> &'static str { + match self { + AssocItemConstraintKind::Equality { .. } => "binding", + AssocItemConstraintKind::Bound { .. } => "constraint", + } + } +} + #[derive(Debug, Clone, Copy, HashStable_Generic)] pub struct Ty<'hir> { pub hir_id: HirId, @@ -3147,6 +3163,13 @@ impl ItemId { /// An item /// /// The name might be a dummy name in case of anonymous items +/// +/// For more details, see the [rust lang reference]. +/// Note that the reference does not document nightly-only features. +/// There may be also slight differences in the names and representation of AST nodes between +/// the compiler and the reference. +/// +/// [rust lang reference]: https://doc.rust-lang.org/reference/items.html #[derive(Debug, Clone, Copy, HashStable_Generic)] pub struct Item<'hir> { pub ident: Ident, @@ -3749,6 +3772,21 @@ impl<'hir> Node<'hir> { } } + /// Get a `hir::Impl` if the node is an impl block for the given `trait_def_id`. + pub fn impl_block_of_trait(self, trait_def_id: DefId) -> Option<&'hir Impl<'hir>> { + match self { + Node::Item(Item { kind: ItemKind::Impl(impl_block), .. }) + if impl_block + .of_trait + .and_then(|trait_ref| trait_ref.trait_def_id()) + .is_some_and(|trait_id| trait_id == trait_def_id) => + { + Some(impl_block) + } + _ => None, + } + } + pub fn fn_sig(self) -> Option<&'hir FnSig<'hir>> { match self { Node::TraitItem(TraitItem { kind: TraitItemKind::Fn(fn_sig, _), .. }) diff --git a/compiler/rustc_hir/src/lang_items.rs b/compiler/rustc_hir/src/lang_items.rs index c3ccba487ede7..69461957f804d 100644 --- a/compiler/rustc_hir/src/lang_items.rs +++ b/compiler/rustc_hir/src/lang_items.rs @@ -244,7 +244,9 @@ language_item_table! { AsyncIterator, sym::async_iterator, async_iterator_trait, Target::Trait, GenericRequirement::Exact(0); CoroutineState, sym::coroutine_state, coroutine_state, Target::Enum, GenericRequirement::None; - Coroutine, sym::coroutine, coroutine_trait, Target::Trait, GenericRequirement::Minimum(1); + Coroutine, sym::coroutine, coroutine_trait, Target::Trait, GenericRequirement::Exact(1); + CoroutineReturn, sym::coroutine_return, coroutine_return, Target::AssocTy, GenericRequirement::Exact(1); + CoroutineYield, sym::coroutine_yield, coroutine_yield, Target::AssocTy, GenericRequirement::Exact(1); CoroutineResume, sym::coroutine_resume, coroutine_resume, Target::Method(MethodKind::Trait { body: false }), GenericRequirement::None; Unpin, sym::unpin, unpin_trait, Target::Trait, GenericRequirement::None; diff --git a/compiler/rustc_hir_analysis/src/bounds.rs b/compiler/rustc_hir_analysis/src/bounds.rs index 38ecd7dd08210..7f0d72b3a8d4d 100644 --- a/compiler/rustc_hir_analysis/src/bounds.rs +++ b/compiler/rustc_hir_analysis/src/bounds.rs @@ -53,7 +53,7 @@ impl<'tcx> Bounds<'tcx> { span, ); // FIXME(-Znext-solver): We can likely remove this hack once the new trait solver lands. - if tcx.lang_items().sized_trait() == Some(trait_ref.def_id()) { + if tcx.is_lang_item(trait_ref.def_id(), LangItem::Sized) { self.clauses.insert(0, clause); } else { self.clauses.push(clause); diff --git a/compiler/rustc_hir_analysis/src/check/intrinsicck.rs b/compiler/rustc_hir_analysis/src/check/intrinsicck.rs index 2672614a89548..2e965c59ebb53 100644 --- a/compiler/rustc_hir_analysis/src/check/intrinsicck.rs +++ b/compiler/rustc_hir_analysis/src/check/intrinsicck.rs @@ -1,6 +1,6 @@ use rustc_ast::InlineAsmTemplatePiece; use rustc_data_structures::fx::FxIndexSet; -use rustc_hir as hir; +use rustc_hir::{self as hir, LangItem}; use rustc_middle::bug; use rustc_middle::ty::{self, Article, FloatTy, IntTy, Ty, TyCtxt, TypeVisitableExt, UintTy}; use rustc_session::lint; @@ -62,8 +62,10 @@ impl<'a, 'tcx> InlineAsmCtxt<'a, 'tcx> { ty::Int(IntTy::I64) | ty::Uint(UintTy::U64) => Some(InlineAsmType::I64), ty::Int(IntTy::I128) | ty::Uint(UintTy::U128) => Some(InlineAsmType::I128), ty::Int(IntTy::Isize) | ty::Uint(UintTy::Usize) => Some(asm_ty_isize), + ty::Float(FloatTy::F16) => Some(InlineAsmType::F16), ty::Float(FloatTy::F32) => Some(InlineAsmType::F32), ty::Float(FloatTy::F64) => Some(InlineAsmType::F64), + ty::Float(FloatTy::F128) => Some(InlineAsmType::F128), ty::FnPtr(_) => Some(asm_ty_isize), ty::RawPtr(ty, _) if self.is_thin_ptr_ty(ty) => Some(asm_ty_isize), ty::Adt(adt, args) if adt.repr().simd() => { @@ -105,8 +107,10 @@ impl<'a, 'tcx> InlineAsmCtxt<'a, 'tcx> { width => bug!("unsupported pointer width: {width}"), }) } + ty::Float(FloatTy::F16) => Some(InlineAsmType::VecF16(size)), ty::Float(FloatTy::F32) => Some(InlineAsmType::VecF32(size)), ty::Float(FloatTy::F64) => Some(InlineAsmType::VecF64(size)), + ty::Float(FloatTy::F128) => Some(InlineAsmType::VecF128(size)), _ => None, } } @@ -134,7 +138,7 @@ impl<'a, 'tcx> InlineAsmCtxt<'a, 'tcx> { // `!` is allowed for input but not for output (issue #87802) ty::Never if is_input => return None, _ if ty.references_error() => return None, - ty::Adt(adt, args) if Some(adt.did()) == self.tcx.lang_items().maybe_uninit() => { + ty::Adt(adt, args) if self.tcx.is_lang_item(adt.did(), LangItem::MaybeUninit) => { let fields = &adt.non_enum_variant().fields; let ty = fields[FieldIdx::from_u32(1)].ty(self.tcx, args); // FIXME: Are we just trying to map to the `T` in `MaybeUninit`? diff --git a/compiler/rustc_hir_analysis/src/coherence/mod.rs b/compiler/rustc_hir_analysis/src/coherence/mod.rs index eae41d28e897c..e9961d3ad0862 100644 --- a/compiler/rustc_hir_analysis/src/coherence/mod.rs +++ b/compiler/rustc_hir_analysis/src/coherence/mod.rs @@ -8,6 +8,7 @@ use crate::errors; use rustc_errors::{codes::*, struct_span_code_err}; use rustc_hir::def_id::{DefId, LocalDefId}; +use rustc_hir::LangItem; use rustc_middle::query::Providers; use rustc_middle::ty::{self, TyCtxt, TypeVisitableExt}; use rustc_session::parse::feature_err; @@ -49,7 +50,7 @@ fn enforce_trait_manually_implementable( ) -> Result<(), ErrorGuaranteed> { let impl_header_span = tcx.def_span(impl_def_id); - if tcx.lang_items().freeze_trait() == Some(trait_def_id) { + if tcx.is_lang_item(trait_def_id, LangItem::Freeze) { if !tcx.features().freeze_impls { feature_err( &tcx.sess, @@ -75,7 +76,7 @@ fn enforce_trait_manually_implementable( // Maintain explicit error code for `Unsize`, since it has a useful // explanation about using `CoerceUnsized` instead. - if Some(trait_def_id) == tcx.lang_items().unsize_trait() { + if tcx.is_lang_item(trait_def_id, LangItem::Unsize) { err.code(E0328); } diff --git a/compiler/rustc_hir_analysis/src/hir_ty_lowering/errors.rs b/compiler/rustc_hir_analysis/src/hir_ty_lowering/errors.rs index 3a9ef244fd3f5..2d240699105d6 100644 --- a/compiler/rustc_hir_analysis/src/hir_ty_lowering/errors.rs +++ b/compiler/rustc_hir_analysis/src/hir_ty_lowering/errors.rs @@ -1217,7 +1217,6 @@ pub fn prohibit_assoc_item_constraint( // otherwise suggest the removal of the binding. if let Some((def_id, segment, _)) = segment && segment.args().parenthesized == hir::GenericArgsParentheses::No - && let hir::AssocItemConstraintKind::Equality { term } = constraint.kind { // Suggests removal of the offending binding let suggest_removal = |e: &mut Diag<'_>| { @@ -1263,7 +1262,7 @@ pub fn prohibit_assoc_item_constraint( if let Ok(suggestion) = tcx.sess.source_map().span_to_snippet(removal_span) { e.span_suggestion_verbose( removal_span, - "consider removing this associated item binding", + format!("consider removing this associated item {}", constraint.kind.descr()), suggestion, Applicability::MaybeIncorrect, ); @@ -1286,19 +1285,73 @@ pub fn prohibit_assoc_item_constraint( // Check if the type has a generic param with the same name // as the assoc type name in the associated item binding. let generics = tcx.generics_of(def_id); - let matching_param = - generics.own_params.iter().find(|p| p.name.as_str() == constraint.ident.as_str()); + let matching_param = generics.own_params.iter().find(|p| p.name == constraint.ident.name); // Now emit the appropriate suggestion if let Some(matching_param) = matching_param { - match (&matching_param.kind, term) { - (GenericParamDefKind::Type { .. }, hir::Term::Ty(ty)) => { - suggest_direct_use(&mut err, ty.span); - } - (GenericParamDefKind::Const { .. }, hir::Term::Const(c)) => { + match (constraint.kind, &matching_param.kind) { + ( + hir::AssocItemConstraintKind::Equality { term: hir::Term::Ty(ty) }, + GenericParamDefKind::Type { .. }, + ) => suggest_direct_use(&mut err, ty.span), + ( + hir::AssocItemConstraintKind::Equality { term: hir::Term::Const(c) }, + GenericParamDefKind::Const { .. }, + ) => { let span = tcx.hir().span(c.hir_id); suggest_direct_use(&mut err, span); } + (hir::AssocItemConstraintKind::Bound { bounds }, _) => { + // Suggest `impl Trait for Foo` when finding + // `impl Trait for Foo` + + // Get the parent impl block based on the binding we have + // and the trait DefId + let impl_block = tcx + .hir() + .parent_iter(constraint.hir_id) + .find_map(|(_, node)| node.impl_block_of_trait(def_id)); + + let type_with_constraints = + tcx.sess.source_map().span_to_snippet(constraint.span); + + if let Some(impl_block) = impl_block + && let Ok(type_with_constraints) = type_with_constraints + { + // Filter out the lifetime parameters because + // they should be declared before the type parameter + let lifetimes: String = bounds + .iter() + .filter_map(|bound| { + if let hir::GenericBound::Outlives(lifetime) = bound { + Some(format!("{lifetime}, ")) + } else { + None + } + }) + .collect(); + // Figure out a span and suggestion string based on + // whether there are any existing parameters + let param_decl = if let Some(param_span) = + impl_block.generics.span_for_param_suggestion() + { + (param_span, format!(", {lifetimes}{type_with_constraints}")) + } else { + ( + impl_block.generics.span.shrink_to_lo(), + format!("<{lifetimes}{type_with_constraints}>"), + ) + }; + let suggestions = + vec![param_decl, (constraint.span, format!("{}", matching_param.name))]; + + err.multipart_suggestion_verbose( + format!("declare the type parameter right after the `impl` keyword"), + suggestions, + Applicability::MaybeIncorrect, + ); + } + } _ => suggest_removal(&mut err), } } else { diff --git a/compiler/rustc_hir_analysis/src/hir_ty_lowering/generics.rs b/compiler/rustc_hir_analysis/src/hir_ty_lowering/generics.rs index 26cabb69d25c7..3f888c4e2722b 100644 --- a/compiler/rustc_hir_analysis/src/hir_ty_lowering/generics.rs +++ b/compiler/rustc_hir_analysis/src/hir_ty_lowering/generics.rs @@ -531,6 +531,7 @@ pub(crate) fn check_generic_arg_count( let num_default_params = expected_max - expected_min; + let mut all_params_are_binded = false; let gen_args_info = if provided > expected_max { invalid_args.extend((expected_max..provided).map(|i| i + args_offset)); let num_redundant_args = provided - expected_max; @@ -547,6 +548,20 @@ pub(crate) fn check_generic_arg_count( } else { let num_missing_args = expected_max - provided; + let constraint_names: Vec<_> = + gen_args.constraints.iter().map(|b| b.ident.name).collect(); + let param_names: Vec<_> = gen_params + .own_params + .iter() + .filter(|param| !has_self || param.index != 0) // Assumes `Self` will always be the first parameter + .map(|param| param.name) + .collect(); + if constraint_names == param_names { + // We set this to true and delay emitting `WrongNumberOfGenericArgs` + // to provide a succinct error for cases like issue #113073 + all_params_are_binded = true; + }; + GenericArgsInfo::MissingTypesOrConsts { num_missing_args, num_default_params, @@ -567,7 +582,7 @@ pub(crate) fn check_generic_arg_count( def_id, ) .diagnostic() - .emit() + .emit_unless(all_params_are_binded) }); Err(reported) diff --git a/compiler/rustc_hir_typeck/messages.ftl b/compiler/rustc_hir_typeck/messages.ftl index 6f499947d5cd4..d6f3f4d640bd5 100644 --- a/compiler/rustc_hir_typeck/messages.ftl +++ b/compiler/rustc_hir_typeck/messages.ftl @@ -44,6 +44,10 @@ hir_typeck_convert_using_method = try using `{$sugg}` to convert `{$found}` to ` hir_typeck_ctor_is_private = tuple struct constructor `{$def}` is private +hir_typeck_dependency_on_unit_never_type_fallback = this function depends on never type fallback being `()` + .note = in edition 2024, the requirement `{$obligation}` will fail + .help = specify the types explicitly + hir_typeck_deref_is_empty = this expression `Deref`s to `{$deref_ty}` which implements `is_empty` hir_typeck_expected_default_return_type = expected `()` because of default return type diff --git a/compiler/rustc_hir_typeck/src/_match.rs b/compiler/rustc_hir_typeck/src/_match.rs index a599e8d05fd3c..281af80bff577 100644 --- a/compiler/rustc_hir_typeck/src/_match.rs +++ b/compiler/rustc_hir_typeck/src/_match.rs @@ -234,7 +234,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { let ret_ty = ret_coercion.borrow().expected_ty(); let ret_ty = self.infcx.shallow_resolve(ret_ty); self.can_coerce(arm_ty, ret_ty) - && prior_arm.map_or(true, |(_, ty, _)| self.can_coerce(ty, ret_ty)) + && prior_arm.is_none_or(|(_, ty, _)| self.can_coerce(ty, ret_ty)) // The match arms need to unify for the case of `impl Trait`. && !matches!(ret_ty.kind(), ty::Alias(ty::Opaque, ..)) } diff --git a/compiler/rustc_hir_typeck/src/callee.rs b/compiler/rustc_hir_typeck/src/callee.rs index 9736c8b89204e..46c855155753d 100644 --- a/compiler/rustc_hir_typeck/src/callee.rs +++ b/compiler/rustc_hir_typeck/src/callee.rs @@ -5,9 +5,9 @@ use super::{Expectation, FnCtxt, TupleArgumentsFlag}; use crate::errors; use rustc_ast::util::parser::PREC_POSTFIX; use rustc_errors::{Applicability, Diag, ErrorGuaranteed, StashKey}; -use rustc_hir as hir; use rustc_hir::def::{self, CtorKind, Namespace, Res}; use rustc_hir::def_id::DefId; +use rustc_hir::{self as hir, LangItem}; use rustc_hir_analysis::autoderef::Autoderef; use rustc_infer::traits::ObligationCauseCode; use rustc_infer::{ @@ -41,7 +41,7 @@ pub fn check_legal_trait_for_method_call( trait_id: DefId, body_id: DefId, ) -> Result<(), ErrorGuaranteed> { - if tcx.lang_items().drop_trait() == Some(trait_id) + if tcx.is_lang_item(trait_id, LangItem::Drop) && tcx.lang_items().fallback_surface_drop_fn() != Some(body_id) { let sugg = if let Some(receiver) = receiver.filter(|s| !s.is_empty()) { @@ -628,7 +628,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { return; }; - let pick = self.confirm_method( + let pick = self.confirm_method_for_diagnostic( call_expr.span, callee_expr, call_expr, diff --git a/compiler/rustc_hir_typeck/src/coercion.rs b/compiler/rustc_hir_typeck/src/coercion.rs index e54a07786cd1d..fcd22b746769c 100644 --- a/compiler/rustc_hir_typeck/src/coercion.rs +++ b/compiler/rustc_hir_typeck/src/coercion.rs @@ -913,7 +913,7 @@ impl<'f, 'tcx> Coerce<'f, 'tcx> { if self .tcx .upvars_mentioned(closure_def_id_a.expect_local()) - .map_or(true, |u| u.is_empty()) => + .is_none_or(|u| u.is_empty()) => { // We coerce the closure, which has fn type // `extern "rust-call" fn((arg0,arg1,...)) -> _` diff --git a/compiler/rustc_hir_typeck/src/demand.rs b/compiler/rustc_hir_typeck/src/demand.rs index d2a5924c8bbb9..f9720c9c30795 100644 --- a/compiler/rustc_hir_typeck/src/demand.rs +++ b/compiler/rustc_hir_typeck/src/demand.rs @@ -4,7 +4,7 @@ use rustc_errors::{Applicability, Diag}; use rustc_hir as hir; use rustc_hir::def::Res; use rustc_hir::intravisit::Visitor; -use rustc_infer::infer::{DefineOpaqueTypes, InferOk}; +use rustc_infer::infer::DefineOpaqueTypes; use rustc_middle::bug; use rustc_middle::ty::adjustment::AllowTwoPhase; use rustc_middle::ty::error::{ExpectedFound, TypeError}; @@ -166,7 +166,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { /// Requires that the two types unify, and prints an error message if /// they don't. pub fn demand_suptype(&self, sp: Span, expected: Ty<'tcx>, actual: Ty<'tcx>) { - if let Some(e) = self.demand_suptype_diag(sp, expected, actual) { + if let Err(e) = self.demand_suptype_diag(sp, expected, actual) { e.emit(); } } @@ -176,7 +176,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { sp: Span, expected: Ty<'tcx>, actual: Ty<'tcx>, - ) -> Option> { + ) -> Result<(), Diag<'tcx>> { self.demand_suptype_with_origin(&self.misc(sp), expected, actual) } @@ -186,18 +186,15 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { cause: &ObligationCause<'tcx>, expected: Ty<'tcx>, actual: Ty<'tcx>, - ) -> Option> { - match self.at(cause, self.param_env).sup(DefineOpaqueTypes::Yes, expected, actual) { - Ok(InferOk { obligations, value: () }) => { - self.register_predicates(obligations); - None - } - Err(e) => Some(self.err_ctxt().report_mismatched_types(cause, expected, actual, e)), - } + ) -> Result<(), Diag<'tcx>> { + self.at(cause, self.param_env) + .sup(DefineOpaqueTypes::Yes, expected, actual) + .map(|infer_ok| self.register_infer_ok_obligations(infer_ok)) + .map_err(|e| self.err_ctxt().report_mismatched_types(cause, expected, actual, e)) } pub fn demand_eqtype(&self, sp: Span, expected: Ty<'tcx>, actual: Ty<'tcx>) { - if let Some(err) = self.demand_eqtype_diag(sp, expected, actual) { + if let Err(err) = self.demand_eqtype_diag(sp, expected, actual) { err.emit(); } } @@ -207,7 +204,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { sp: Span, expected: Ty<'tcx>, actual: Ty<'tcx>, - ) -> Option> { + ) -> Result<(), Diag<'tcx>> { self.demand_eqtype_with_origin(&self.misc(sp), expected, actual) } @@ -216,14 +213,11 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { cause: &ObligationCause<'tcx>, expected: Ty<'tcx>, actual: Ty<'tcx>, - ) -> Option> { - match self.at(cause, self.param_env).eq(DefineOpaqueTypes::Yes, expected, actual) { - Ok(InferOk { obligations, value: () }) => { - self.register_predicates(obligations); - None - } - Err(e) => Some(self.err_ctxt().report_mismatched_types(cause, expected, actual, e)), - } + ) -> Result<(), Diag<'tcx>> { + self.at(cause, self.param_env) + .eq(DefineOpaqueTypes::Yes, expected, actual) + .map(|infer_ok| self.register_infer_ok_obligations(infer_ok)) + .map_err(|e| self.err_ctxt().report_mismatched_types(cause, expected, actual, e)) } pub fn demand_coerce( @@ -234,12 +228,17 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { expected_ty_expr: Option<&'tcx hir::Expr<'tcx>>, allow_two_phase: AllowTwoPhase, ) -> Ty<'tcx> { - let (ty, err) = - self.demand_coerce_diag(expr, checked_ty, expected, expected_ty_expr, allow_two_phase); - if let Some(err) = err { - err.emit(); + match self.demand_coerce_diag(expr, checked_ty, expected, expected_ty_expr, allow_two_phase) + { + Ok(ty) => ty, + Err(err) => { + err.emit(); + // Return the original type instead of an error type here, otherwise the type of `x` in + // `let x: u32 = ();` will be a type error, causing all subsequent usages of `x` to not + // report errors, even though `x` is definitely `u32`. + expected + } } - ty } /// Checks that the type of `expr` can be coerced to `expected`. @@ -254,11 +253,11 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { expected: Ty<'tcx>, mut expected_ty_expr: Option<&'tcx hir::Expr<'tcx>>, allow_two_phase: AllowTwoPhase, - ) -> (Ty<'tcx>, Option>) { + ) -> Result, Diag<'tcx>> { let expected = self.resolve_vars_with_obligations(expected); let e = match self.coerce(expr, checked_ty, expected, allow_two_phase, None) { - Ok(ty) => return (ty, None), + Ok(ty) => return Ok(ty), Err(e) => e, }; @@ -275,7 +274,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { self.emit_coerce_suggestions(&mut err, expr, expr_ty, expected, expected_ty_expr, Some(e)); - (expected, Some(err)) + Err(err) } /// Notes the point at which a variable is constrained to some type incompatible diff --git a/compiler/rustc_hir_typeck/src/errors.rs b/compiler/rustc_hir_typeck/src/errors.rs index 3f12f25265454..24f039b8e90bc 100644 --- a/compiler/rustc_hir_typeck/src/errors.rs +++ b/compiler/rustc_hir_typeck/src/errors.rs @@ -7,7 +7,7 @@ use rustc_errors::{ SubdiagMessageOp, Subdiagnostic, }; use rustc_macros::{Diagnostic, LintDiagnostic, Subdiagnostic}; -use rustc_middle::ty::Ty; +use rustc_middle::ty::{self, Ty}; use rustc_span::{ edition::{Edition, LATEST_STABLE_EDITION}, symbol::Ident, @@ -183,6 +183,15 @@ pub enum NeverTypeFallbackFlowingIntoUnsafe { Deref, } +#[derive(LintDiagnostic)] +#[help] +#[diag(hir_typeck_dependency_on_unit_never_type_fallback)] +pub struct DependencyOnUnitNeverTypeFallback<'tcx> { + #[note] + pub obligation_span: Span, + pub obligation: ty::Predicate<'tcx>, +} + #[derive(Subdiagnostic)] #[multipart_suggestion( hir_typeck_add_missing_parentheses_in_range, diff --git a/compiler/rustc_hir_typeck/src/expr.rs b/compiler/rustc_hir_typeck/src/expr.rs index 3321f029c8d8c..fe497498c4bc2 100644 --- a/compiler/rustc_hir_typeck/src/expr.rs +++ b/compiler/rustc_hir_typeck/src/expr.rs @@ -87,7 +87,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { ty = adj_ty; } - if let Some(mut err) = self.demand_suptype_diag(expr.span, expected_ty, ty) { + if let Err(mut err) = self.demand_suptype_diag(expr.span, expected_ty, ty) { let _ = self.emit_type_mismatch_suggestions( &mut err, expr.peel_drop_temps(), @@ -1132,7 +1132,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { // say that the user intended to write `lhs == rhs` instead of `lhs = rhs`. // The likely cause of this is `if foo = bar { .. }`. let actual_ty = self.tcx.types.unit; - let mut err = self.demand_suptype_diag(expr.span, expected_ty, actual_ty).unwrap(); + let mut err = self.demand_suptype_diag(expr.span, expected_ty, actual_ty).unwrap_err(); let lhs_ty = self.check_expr(lhs); let rhs_ty = self.check_expr(rhs); let refs_can_coerce = |lhs: Ty<'tcx>, rhs: Ty<'tcx>| { @@ -1236,7 +1236,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { // This is (basically) inlined `check_expr_coercible_to_type`, but we want // to suggest an additional fixup here in `suggest_deref_binop`. let rhs_ty = self.check_expr_with_hint(rhs, lhs_ty); - if let (_, Some(mut diag)) = + if let Err(mut diag) = self.demand_coerce_diag(rhs, rhs_ty, lhs_ty, Some(lhs), AllowTwoPhase::No) { suggest_deref_binop(&mut diag, rhs_ty); @@ -1557,7 +1557,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { // If the length is 0, we don't create any elements, so we don't copy any. If the length is 1, we // don't copy that one element, we move it. Only check for Copy if the length is larger. - if count.try_eval_target_usize(tcx, self.param_env).map_or(true, |len| len > 1) { + if count.try_eval_target_usize(tcx, self.param_env).is_none_or(|len| len > 1) { let lang_item = self.tcx.require_lang_item(LangItem::Copy, None); let code = traits::ObligationCauseCode::RepeatElementCopy { is_constable, @@ -1738,10 +1738,9 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { // Make sure to give a type to the field even if there's // an error, so we can continue type-checking. let ty = self.check_expr_with_hint(field.expr, field_type); - let (_, diag) = - self.demand_coerce_diag(field.expr, ty, field_type, None, AllowTwoPhase::No); + let diag = self.demand_coerce_diag(field.expr, ty, field_type, None, AllowTwoPhase::No); - if let Some(diag) = diag { + if let Err(diag) = diag { if idx == hir_fields.len() - 1 { if remaining_fields.is_empty() { self.suggest_fru_from_range_and_emit(field, variant, args, diag); @@ -3151,7 +3150,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { error.obligation.predicate.kind().skip_binder(), ) { (ty::PredicateKind::Clause(ty::ClauseKind::Trait(predicate)), _) - if self.tcx.lang_items().index_trait() == Some(predicate.trait_ref.def_id) => + if self.tcx.is_lang_item(predicate.trait_ref.def_id, LangItem::Index) => { seen_preds.insert(error.obligation.predicate.kind().skip_binder()); } diff --git a/compiler/rustc_hir_typeck/src/fallback.rs b/compiler/rustc_hir_typeck/src/fallback.rs index 5ba67c52ef297..3cecbfd42757e 100644 --- a/compiler/rustc_hir_typeck/src/fallback.rs +++ b/compiler/rustc_hir_typeck/src/fallback.rs @@ -14,6 +14,7 @@ use rustc_middle::ty::{self, Ty, TyCtxt, TypeSuperVisitable, TypeVisitable}; use rustc_session::lint; use rustc_span::DUMMY_SP; use rustc_span::{def_id::LocalDefId, Span}; +use rustc_trait_selection::traits::{ObligationCause, ObligationCtxt}; #[derive(Copy, Clone)] pub enum DivergingFallbackBehavior { @@ -344,6 +345,9 @@ impl<'tcx> FnCtxt<'_, 'tcx> { // `!`. let mut diverging_fallback = UnordMap::with_capacity(diverging_vids.len()); let unsafe_infer_vars = OnceCell::new(); + + self.lint_obligations_broken_by_never_type_fallback_change(behavior, &diverging_vids); + for &diverging_vid in &diverging_vids { let diverging_ty = Ty::new_var(self.tcx, diverging_vid); let root_vid = self.root_var(diverging_vid); @@ -468,6 +472,56 @@ impl<'tcx> FnCtxt<'_, 'tcx> { } } + fn lint_obligations_broken_by_never_type_fallback_change( + &self, + behavior: DivergingFallbackBehavior, + diverging_vids: &[ty::TyVid], + ) { + let DivergingFallbackBehavior::ToUnit = behavior else { return }; + + // Fallback happens if and only if there are diverging variables + if diverging_vids.is_empty() { + return; + } + + // Returns errors which happen if fallback is set to `fallback` + let remaining_errors_if_fallback_to = |fallback| { + self.probe(|_| { + let obligations = self.fulfillment_cx.borrow().pending_obligations(); + let ocx = ObligationCtxt::new_with_diagnostics(&self.infcx); + ocx.register_obligations(obligations.iter().cloned()); + + for &diverging_vid in diverging_vids { + let diverging_ty = Ty::new_var(self.tcx, diverging_vid); + + ocx.eq(&ObligationCause::dummy(), self.param_env, diverging_ty, fallback) + .expect("expected diverging var to be unconstrained"); + } + + ocx.select_where_possible() + }) + }; + + // If we have no errors with `fallback = ()`, but *do* have errors with `fallback = !`, + // then this code will be broken by the never type fallback change.qba + let unit_errors = remaining_errors_if_fallback_to(self.tcx.types.unit); + if unit_errors.is_empty() + && let mut never_errors = remaining_errors_if_fallback_to(self.tcx.types.never) + && let [ref mut never_error, ..] = never_errors.as_mut_slice() + { + self.adjust_fulfillment_error_for_expr_obligation(never_error); + self.tcx.emit_node_span_lint( + lint::builtin::DEPENDENCY_ON_UNIT_NEVER_TYPE_FALLBACK, + self.tcx.local_def_id_to_hir_id(self.body_id), + self.tcx.def_span(self.body_id), + errors::DependencyOnUnitNeverTypeFallback { + obligation_span: never_error.obligation.cause.span, + obligation: never_error.obligation.predicate, + }, + ) + } + } + /// Returns a graph whose nodes are (unresolved) inference variables and where /// an edge `?A -> ?B` indicates that the variable `?A` is coerced to `?B`. fn create_coercion_graph(&self) -> VecGraph { diff --git a/compiler/rustc_hir_typeck/src/fn_ctxt/_impl.rs b/compiler/rustc_hir_typeck/src/fn_ctxt/_impl.rs index 94e879ae9c3ed..9531c002829ea 100644 --- a/compiler/rustc_hir_typeck/src/fn_ctxt/_impl.rs +++ b/compiler/rustc_hir_typeck/src/fn_ctxt/_impl.rs @@ -1418,7 +1418,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { let impl_ty = self.normalize(span, tcx.type_of(impl_def_id).instantiate(tcx, args)); let self_ty = self.normalize(span, self_ty); match self.at(&self.misc(span), self.param_env).eq( - DefineOpaqueTypes::No, + DefineOpaqueTypes::Yes, impl_ty, self_ty, ) { diff --git a/compiler/rustc_hir_typeck/src/fn_ctxt/checks.rs b/compiler/rustc_hir_typeck/src/fn_ctxt/checks.rs index e20a6ef7c1339..10d9e07db6f1f 100644 --- a/compiler/rustc_hir_typeck/src/fn_ctxt/checks.rs +++ b/compiler/rustc_hir_typeck/src/fn_ctxt/checks.rs @@ -1578,7 +1578,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { // type of the place it is referencing, and not some // supertype thereof. let init_ty = self.check_expr_with_needs(init, Needs::maybe_mut_place(m)); - if let Some(mut diag) = self.demand_eqtype_diag(init.span, local_ty, init_ty) { + if let Err(mut diag) = self.demand_eqtype_diag(init.span, local_ty, init_ty) { self.emit_type_mismatch_suggestions( &mut diag, init.peel_drop_temps(), @@ -1624,7 +1624,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { let previous_diverges = self.diverges.get(); let else_ty = self.check_block_with_expected(blk, NoExpectation); let cause = self.cause(blk.span, ObligationCauseCode::LetElse); - if let Some(err) = self.demand_eqtype_with_origin(&cause, self.tcx.types.never, else_ty) + if let Err(err) = self.demand_eqtype_with_origin(&cause, self.tcx.types.never, else_ty) { err.emit(); } @@ -2240,7 +2240,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { for (idx, (generic_param, param)) in params_with_generics.iter().enumerate().filter(|(idx, _)| { check_for_matched_generics - || expected_idx.map_or(true, |expected_idx| expected_idx == *idx) + || expected_idx.is_none_or(|expected_idx| expected_idx == *idx) }) { let Some(generic_param) = generic_param else { diff --git a/compiler/rustc_hir_typeck/src/fn_ctxt/suggestions.rs b/compiler/rustc_hir_typeck/src/fn_ctxt/suggestions.rs index 9ab89f3444c9c..9743dc7c69fbc 100644 --- a/compiler/rustc_hir_typeck/src/fn_ctxt/suggestions.rs +++ b/compiler/rustc_hir_typeck/src/fn_ctxt/suggestions.rs @@ -440,7 +440,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { }; // Given `Result<_, E>`, check our expected ty is `Result<_, &E>` for // `as_ref` and `as_deref` compatibility. - let error_tys_equate_as_ref = error_tys.map_or(true, |(found, expected)| { + let error_tys_equate_as_ref = error_tys.is_none_or(|(found, expected)| { self.can_eq( self.param_env, Ty::new_imm_ref(self.tcx, self.tcx.lifetimes.re_erased, found), @@ -489,10 +489,10 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { ); return true; } else if let ty::Adt(adt, _) = found_ty_inner.peel_refs().kind() - && Some(adt.did()) == self.tcx.lang_items().string() + && self.tcx.is_lang_item(adt.did(), LangItem::String) && peeled.is_str() // `Result::map`, conversely, does not take ref of the error type. - && error_tys.map_or(true, |(found, expected)| { + && error_tys.is_none_or(|(found, expected)| { self.can_eq(self.param_env, found, expected) }) { @@ -3147,7 +3147,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { return; } if let ty::Adt(adt, _) = expected_ty.kind() - && self.tcx.lang_items().range_struct() == Some(adt.did()) + && self.tcx.is_lang_item(adt.did(), LangItem::Range) { return; } diff --git a/compiler/rustc_hir_typeck/src/lib.rs b/compiler/rustc_hir_typeck/src/lib.rs index b0fd6de349680..a87ee7b455488 100644 --- a/compiler/rustc_hir_typeck/src/lib.rs +++ b/compiler/rustc_hir_typeck/src/lib.rs @@ -4,6 +4,7 @@ #![feature(box_patterns)] #![feature(control_flow_enum)] #![feature(if_let_guard)] +#![feature(is_none_or)] #![feature(let_chains)] #![feature(never_type)] #![feature(try_blocks)] diff --git a/compiler/rustc_hir_typeck/src/method/confirm.rs b/compiler/rustc_hir_typeck/src/method/confirm.rs index 3c9a49e91a3f9..120e3239d1f1b 100644 --- a/compiler/rustc_hir_typeck/src/method/confirm.rs +++ b/compiler/rustc_hir_typeck/src/method/confirm.rs @@ -497,7 +497,7 @@ impl<'a, 'tcx> ConfirmContext<'a, 'tcx> { args, })), ); - match self.at(&cause, self.param_env).sup(DefineOpaqueTypes::No, method_self_ty, self_ty) { + match self.at(&cause, self.param_env).sup(DefineOpaqueTypes::Yes, method_self_ty, self_ty) { Ok(InferOk { obligations, value: () }) => { self.register_predicates(obligations); } diff --git a/compiler/rustc_hir_typeck/src/method/probe.rs b/compiler/rustc_hir_typeck/src/method/probe.rs index e842bba34bf82..3986374a343f0 100644 --- a/compiler/rustc_hir_typeck/src/method/probe.rs +++ b/compiler/rustc_hir_typeck/src/method/probe.rs @@ -634,8 +634,8 @@ impl<'a, 'tcx> ProbeContext<'a, 'tcx> { } } + #[instrument(level = "debug", skip(self))] fn assemble_probe(&mut self, self_ty: &Canonical<'tcx, QueryResponse<'tcx, Ty<'tcx>>>) { - debug!("assemble_probe: self_ty={:?}", self_ty); let raw_self_ty = self_ty.value.value; match *raw_self_ty.kind() { ty::Dynamic(data, ..) if let Some(p) = data.principal() => { @@ -713,13 +713,12 @@ impl<'a, 'tcx> ProbeContext<'a, 'tcx> { } } + #[instrument(level = "debug", skip(self))] fn assemble_inherent_impl_probe(&mut self, impl_def_id: DefId) { if !self.impl_dups.insert(impl_def_id) { return; // already visited } - debug!("assemble_inherent_impl_probe {:?}", impl_def_id); - for item in self.impl_or_trait_item(impl_def_id) { if !self.has_applicable_self(&item) { // No receiver declared. Not a candidate. @@ -737,9 +736,8 @@ impl<'a, 'tcx> ProbeContext<'a, 'tcx> { } } + #[instrument(level = "debug", skip(self))] fn assemble_inherent_candidates_from_object(&mut self, self_ty: Ty<'tcx>) { - debug!("assemble_inherent_candidates_from_object(self_ty={:?})", self_ty); - let principal = match self_ty.kind() { ty::Dynamic(ref data, ..) => Some(data), _ => None, @@ -768,9 +766,9 @@ impl<'a, 'tcx> ProbeContext<'a, 'tcx> { }); } + #[instrument(level = "debug", skip(self))] fn assemble_inherent_candidates_from_param(&mut self, param_ty: ty::ParamTy) { // FIXME: do we want to commit to this behavior for param bounds? - debug!("assemble_inherent_candidates_from_param(param_ty={:?})", param_ty); let bounds = self.param_env.caller_bounds().iter().filter_map(|predicate| { let bound_predicate = predicate.kind(); @@ -826,6 +824,7 @@ impl<'a, 'tcx> ProbeContext<'a, 'tcx> { } } + #[instrument(level = "debug", skip(self))] fn assemble_extension_candidates_for_traits_in_scope(&mut self) { let mut duplicates = FxHashSet::default(); let opt_applicable_traits = self.tcx.in_scope_traits(self.scope_expr_id); @@ -842,6 +841,7 @@ impl<'a, 'tcx> ProbeContext<'a, 'tcx> { } } + #[instrument(level = "debug", skip(self))] fn assemble_extension_candidates_for_all_traits(&mut self) { let mut duplicates = FxHashSet::default(); for trait_info in suggest::all_traits(self.tcx) { @@ -863,12 +863,12 @@ impl<'a, 'tcx> ProbeContext<'a, 'tcx> { } } + #[instrument(level = "debug", skip(self))] fn assemble_extension_candidates_for_trait( &mut self, import_ids: &SmallVec<[LocalDefId; 1]>, trait_def_id: DefId, ) { - debug!("assemble_extension_candidates_for_trait(trait_def_id={:?})", trait_def_id); let trait_args = self.fresh_args_for_item(self.span, trait_def_id); let trait_ref = ty::TraitRef::new(self.tcx, trait_def_id, trait_args); @@ -958,6 +958,7 @@ impl<'a, 'tcx> ProbeContext<'a, 'tcx> { /////////////////////////////////////////////////////////////////////////// // THE ACTUAL SEARCH + #[instrument(level = "debug", skip(self))] fn pick(mut self) -> PickResult<'tcx> { assert!(self.method_name.is_some()); @@ -1386,6 +1387,7 @@ impl<'a, 'tcx> ProbeContext<'a, 'tcx> { } } + #[instrument(level = "trace", skip(self, possibly_unsatisfied_predicates), ret)] fn consider_probe( &self, self_ty: Ty<'tcx>, @@ -1415,15 +1417,8 @@ impl<'a, 'tcx> ProbeContext<'a, 'tcx> { (xform_self_ty, xform_ret_ty) = self.xform_self_ty(probe.item, impl_ty, impl_args); xform_self_ty = ocx.normalize(cause, self.param_env, xform_self_ty); - // FIXME: Make this `ocx.sup` once we define opaques more eagerly. - match self.at(cause, self.param_env).sup( - DefineOpaqueTypes::No, - xform_self_ty, - self_ty, - ) { - Ok(infer_ok) => { - ocx.register_infer_ok_obligations(infer_ok); - } + match ocx.sup(cause, self.param_env, xform_self_ty, self_ty) { + Ok(()) => {} Err(err) => { debug!("--> cannot relate self-types {:?}", err); return ProbeResult::NoMatch; @@ -1484,19 +1479,23 @@ impl<'a, 'tcx> ProbeContext<'a, 'tcx> { (xform_self_ty, xform_ret_ty) = self.xform_self_ty(probe.item, trait_ref.self_ty(), trait_ref.args); xform_self_ty = ocx.normalize(cause, self.param_env, xform_self_ty); - // FIXME: Make this `ocx.sup` once we define opaques more eagerly. - match self.at(cause, self.param_env).sup( - DefineOpaqueTypes::No, - xform_self_ty, - self_ty, - ) { - Ok(infer_ok) => { - ocx.register_infer_ok_obligations(infer_ok); - } - Err(err) => { - debug!("--> cannot relate self-types {:?}", err); + match self_ty.kind() { + // HACK: opaque types will match anything for which their bounds hold. + // Thus we need to prevent them from trying to match the `&_` autoref + // candidates that get created for `&self` trait methods. + ty::Alias(ty::Opaque, alias_ty) + if self.infcx.can_define_opaque_ty(alias_ty.def_id) + && !xform_self_ty.is_ty_var() => + { return ProbeResult::NoMatch; } + _ => match ocx.sup(cause, self.param_env, xform_self_ty, self_ty) { + Ok(()) => {} + Err(err) => { + debug!("--> cannot relate self-types {:?}", err); + return ProbeResult::NoMatch; + } + }, } let obligation = traits::Obligation::new( self.tcx, @@ -1536,15 +1535,8 @@ impl<'a, 'tcx> ProbeContext<'a, 'tcx> { (xform_self_ty, xform_ret_ty) = self.xform_self_ty(probe.item, trait_ref.self_ty(), trait_ref.args); xform_self_ty = ocx.normalize(cause, self.param_env, xform_self_ty); - // FIXME: Make this `ocx.sup` once we define opaques more eagerly. - match self.at(cause, self.param_env).sup( - DefineOpaqueTypes::No, - xform_self_ty, - self_ty, - ) { - Ok(infer_ok) => { - ocx.register_infer_ok_obligations(infer_ok); - } + match ocx.sup(cause, self.param_env, xform_self_ty, self_ty) { + Ok(()) => {} Err(err) => { debug!("--> cannot relate self-types {:?}", err); return ProbeResult::NoMatch; @@ -1665,6 +1657,7 @@ impl<'a, 'tcx> ProbeContext<'a, 'tcx> { /// Similarly to `probe_for_return_type`, this method attempts to find the best matching /// candidate method where the method name may have been misspelled. Similarly to other /// edit distance based suggestions, we provide at most one such suggestion. + #[instrument(level = "debug", skip(self))] pub(crate) fn probe_for_similar_candidate( &mut self, ) -> Result, MethodError<'tcx>> { diff --git a/compiler/rustc_hir_typeck/src/method/suggest.rs b/compiler/rustc_hir_typeck/src/method/suggest.rs index 28d738c11c8fa..abbfe452f5f3d 100644 --- a/compiler/rustc_hir_typeck/src/method/suggest.rs +++ b/compiler/rustc_hir_typeck/src/method/suggest.rs @@ -1102,7 +1102,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { unsatisfied_predicates.iter().any(|(pred, _, _)| { match pred.kind().skip_binder() { ty::PredicateKind::Clause(ty::ClauseKind::Trait(pred)) => { - Some(pred.def_id()) == self.tcx.lang_items().sized_trait() + self.tcx.is_lang_item(pred.def_id(), LangItem::Sized) && pred.polarity == ty::PredicatePolarity::Positive } _ => false, @@ -1375,10 +1375,10 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { ty.is_str() || matches!( ty.kind(), - ty::Adt(adt, _) if Some(adt.did()) == self.tcx.lang_items().string() + ty::Adt(adt, _) if self.tcx.is_lang_item(adt.did(), LangItem::String) ) } - ty::Adt(adt, _) => Some(adt.did()) == self.tcx.lang_items().string(), + ty::Adt(adt, _) => self.tcx.is_lang_item(adt.did(), LangItem::String), _ => false, }; if is_string_or_ref_str && item_name.name == sym::iter { @@ -2723,7 +2723,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { if tcx.is_diagnostic_item(sym::LocalKey, inner_id) { err.help("use `with` or `try_with` to access thread local storage"); - } else if Some(kind.did()) == tcx.lang_items().maybe_uninit() { + } else if tcx.is_lang_item(kind.did(), LangItem::MaybeUninit) { err.help(format!( "if this `{name}` has been initialized, \ use one of the `assume_init` methods to access the inner value" diff --git a/compiler/rustc_hir_typeck/src/pat.rs b/compiler/rustc_hir_typeck/src/pat.rs index 9476dc704831d..aaf3d3ec34d01 100644 --- a/compiler/rustc_hir_typeck/src/pat.rs +++ b/compiler/rustc_hir_typeck/src/pat.rs @@ -7,7 +7,7 @@ use rustc_errors::{ }; use rustc_hir::def::{CtorKind, DefKind, Res}; use rustc_hir::pat_util::EnumerateAndAdjustIterator; -use rustc_hir::{self as hir, BindingMode, ByRef, HirId, Mutability, Pat, PatKind}; +use rustc_hir::{self as hir, BindingMode, ByRef, HirId, LangItem, Mutability, Pat, PatKind}; use rustc_infer::infer; use rustc_middle::mir::interpret::ErrorHandled; use rustc_middle::ty::{self, Ty, TypeVisitableExt}; @@ -105,15 +105,16 @@ impl<'tcx> FnCtxt<'_, 'tcx> { expected: Ty<'tcx>, actual: Ty<'tcx>, ti: &TopInfo<'tcx>, - ) -> Option> { - let mut diag = - self.demand_eqtype_with_origin(&self.pattern_cause(ti, cause_span), expected, actual)?; - if let Some(expr) = ti.origin_expr { - self.suggest_fn_call(&mut diag, expr, expected, |output| { - self.can_eq(self.param_env, output, actual) - }); - } - Some(diag) + ) -> Result<(), Diag<'tcx>> { + self.demand_eqtype_with_origin(&self.pattern_cause(ti, cause_span), expected, actual) + .map_err(|mut diag| { + if let Some(expr) = ti.origin_expr { + self.suggest_fn_call(&mut diag, expr, expected, |output| { + self.can_eq(self.param_env, output, actual) + }); + } + diag + }) } fn demand_eqtype_pat( @@ -122,10 +123,8 @@ impl<'tcx> FnCtxt<'_, 'tcx> { expected: Ty<'tcx>, actual: Ty<'tcx>, ti: &TopInfo<'tcx>, - ) { - if let Some(err) = self.demand_eqtype_pat_diag(cause_span, expected, actual, ti) { - err.emit(); - } + ) -> Result<(), ErrorGuaranteed> { + self.demand_eqtype_pat_diag(cause_span, expected, actual, ti).map_err(|err| err.emit()) } } @@ -492,7 +491,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { let tcx = self.tcx; let expected = self.resolve_vars_if_possible(expected); pat_ty = match expected.kind() { - ty::Adt(def, _) if Some(def.did()) == tcx.lang_items().string() => expected, + ty::Adt(def, _) if tcx.is_lang_item(def.did(), LangItem::String) => expected, ty::Str => Ty::new_static_str(tcx), _ => pat_ty, }; @@ -509,7 +508,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { // // then that's equivalent to there existing a LUB. let cause = self.pattern_cause(ti, span); - if let Some(err) = self.demand_suptype_with_origin(&cause, expected, pat_ty) { + if let Err(err) = self.demand_suptype_with_origin(&cause, expected, pat_ty) { err.emit_unless( ti.span .filter(|&s| { @@ -562,7 +561,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { // Subtyping doesn't matter here, as the value is some kind of scalar. let demand_eqtype = |x: &mut _, y| { if let Some((ref mut fail, x_ty, x_span)) = *x - && let Some(mut err) = self.demand_eqtype_pat_diag(x_span, expected, x_ty, ti) + && let Err(mut err) = self.demand_eqtype_pat_diag(x_span, expected, x_ty, ti) { if let Some((_, y_ty, y_span)) = y { self.endpoint_has_type(&mut err, y_span, y_ty); @@ -736,7 +735,9 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { // Otherwise, the type of x is the expected type `T`. ByRef::No => expected, // As above, `T <: typeof(x)` is required, but we use equality, see (note_1). }; - self.demand_eqtype_pat(pat.span, eq_ty, local_ty, ti); + + // We have a concrete type for the local, so we do not need to taint it and hide follow up errors *using* the local. + let _ = self.demand_eqtype_pat(pat.span, eq_ty, local_ty, ti); // If there are multiple arms, make sure they all agree on // what the type of the binding `x` ought to be. @@ -763,7 +764,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { ti: &TopInfo<'tcx>, ) { let var_ty = self.local_ty(span, var_id); - if let Some(mut err) = self.demand_eqtype_pat_diag(span, var_ty, ty, ti) { + if let Err(mut err) = self.demand_eqtype_pat_diag(span, var_ty, ty, ti) { let hir = self.tcx.hir(); let var_ty = self.resolve_vars_if_possible(var_ty); let msg = format!("first introduced with type `{var_ty}` here"); @@ -986,13 +987,12 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { }; // Type-check the path. - self.demand_eqtype_pat(pat.span, expected, pat_ty, pat_info.top_info); + let _ = self.demand_eqtype_pat(pat.span, expected, pat_ty, pat_info.top_info); // Type-check subpatterns. - if self.check_struct_pat_fields(pat_ty, pat, variant, fields, has_rest_pat, pat_info) { - pat_ty - } else { - Ty::new_misc_error(self.tcx) + match self.check_struct_pat_fields(pat_ty, pat, variant, fields, has_rest_pat, pat_info) { + Ok(()) => pat_ty, + Err(guar) => Ty::new_error(self.tcx, guar), } } @@ -1050,7 +1050,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { // Type-check the path. let (pat_ty, pat_res) = self.instantiate_value_path(segments, opt_ty, res, pat.span, pat.span, pat.hir_id); - if let Some(err) = + if let Err(err) = self.demand_suptype_with_origin(&self.pattern_cause(ti, pat.span), expected, pat_ty) { self.emit_bad_pat_path(err, pat, res, pat_res, pat_ty, segments); @@ -1223,12 +1223,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { // Type-check the tuple struct pattern against the expected type. let diag = self.demand_eqtype_pat_diag(pat.span, expected, pat_ty, pat_info.top_info); - let had_err = if let Some(err) = diag { - err.emit(); - true - } else { - false - }; + let had_err = diag.map_err(|diag| diag.emit()); // Type-check subpatterns. if subpats.len() == variant.fields.len() @@ -1249,6 +1244,10 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { None, ); } + if let Err(e) = had_err { + on_error(e); + return Ty::new_error(tcx, e); + } } else { let e = self.emit_err_pat_wrong_number_of_fields( pat.span, @@ -1273,7 +1272,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { subpats: &'tcx [Pat<'tcx>], fields: &'tcx [ty::FieldDef], expected: Ty<'tcx>, - had_err: bool, + had_err: Result<(), ErrorGuaranteed>, ) -> ErrorGuaranteed { let subpats_ending = pluralize!(subpats.len()); let fields_ending = pluralize!(fields.len()); @@ -1330,7 +1329,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { // #67037: only do this if we could successfully type-check the expected type against // the tuple struct pattern. Otherwise the args could get out of range on e.g., // `let P() = U;` where `P != U` with `struct P(T);`. - (ty::Adt(_, args), [field], false) => { + (ty::Adt(_, args), [field], Ok(())) => { let field_ty = self.field_ty(pat_span, field, args); match field_ty.kind() { ty::Tuple(fields) => fields.len() == subpats.len(), @@ -1445,8 +1444,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { let element_tys_iter = (0..max_len).map(|_| self.next_ty_var(span)); let element_tys = tcx.mk_type_list_from_iter(element_tys_iter); let pat_ty = Ty::new_tup(tcx, element_tys); - if let Some(err) = self.demand_eqtype_pat_diag(span, expected, pat_ty, pat_info.top_info) { - let reported = err.emit(); + if let Err(reported) = self.demand_eqtype_pat(span, expected, pat_ty, pat_info.top_info) { // Walk subpatterns with an expected type of `err` in this case to silence // further errors being emitted when using the bindings. #50333 let element_tys_iter = (0..max_len).map(|_| Ty::new_error(tcx, reported)); @@ -1470,7 +1468,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { fields: &'tcx [hir::PatField<'tcx>], has_rest_pat: bool, pat_info: PatInfo<'tcx, '_>, - ) -> bool { + ) -> Result<(), ErrorGuaranteed> { let tcx = self.tcx; let ty::Adt(adt, args) = adt_ty.kind() else { @@ -1486,7 +1484,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { // Keep track of which fields have already appeared in the pattern. let mut used_fields = FxHashMap::default(); - let mut no_field_errors = true; + let mut result = Ok(()); let mut inexistent_fields = vec![]; // Typecheck each field. @@ -1495,8 +1493,8 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { let ident = tcx.adjust_ident(field.ident, variant.def_id); let field_ty = match used_fields.entry(ident) { Occupied(occupied) => { - no_field_errors = false; let guar = self.error_field_already_bound(span, field.ident, *occupied.get()); + result = Err(guar); Ty::new_error(tcx, guar) } Vacant(vacant) => { @@ -1511,7 +1509,6 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { }) .unwrap_or_else(|| { inexistent_fields.push(field); - no_field_errors = false; Ty::new_misc_error(tcx) }) } @@ -1585,37 +1582,31 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { } match (inexistent_fields_err, unmentioned_err) { (Some(i), Some(u)) => { - if let Some(e) = self.error_tuple_variant_as_struct_pat(pat, fields, variant) { + if let Err(e) = self.error_tuple_variant_as_struct_pat(pat, fields, variant) { // We don't want to show the nonexistent fields error when this was // `Foo { a, b }` when it should have been `Foo(a, b)`. i.delay_as_bug(); u.delay_as_bug(); - e.emit(); + Err(e) } else { i.emit(); - u.emit(); + Err(u.emit()) } } (None, Some(u)) => { - if let Some(e) = self.error_tuple_variant_as_struct_pat(pat, fields, variant) { + if let Err(e) = self.error_tuple_variant_as_struct_pat(pat, fields, variant) { u.delay_as_bug(); - e.emit(); + Err(e) } else { - u.emit(); + Err(u.emit()) } } - (Some(err), None) => { - err.emit(); - } - (None, None) - if let Some(err) = - self.error_tuple_variant_index_shorthand(variant, pat, fields) => - { - err.emit(); + (Some(err), None) => Err(err.emit()), + (None, None) => { + self.error_tuple_variant_index_shorthand(variant, pat, fields)?; + result } - (None, None) => {} } - no_field_errors } fn error_tuple_variant_index_shorthand( @@ -1623,7 +1614,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { variant: &VariantDef, pat: &'_ Pat<'_>, fields: &[hir::PatField<'_>], - ) -> Option> { + ) -> Result<(), ErrorGuaranteed> { // if this is a tuple struct, then all field names will be numbers // so if any fields in a struct pattern use shorthand syntax, they will // be invalid identifiers (for example, Foo { 0, 1 }). @@ -1645,10 +1636,10 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { format!("({})", self.get_suggested_tuple_struct_pattern(fields, variant)), Applicability::MaybeIncorrect, ); - return Some(err); + return Err(err.emit()); } } - None + Ok(()) } fn error_foreign_non_exhaustive_spat(&self, pat: &Pat<'_>, descr: &str, no_fields: bool) { @@ -1804,14 +1795,14 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { pat: &Pat<'_>, fields: &'tcx [hir::PatField<'tcx>], variant: &ty::VariantDef, - ) -> Option> { + ) -> Result<(), ErrorGuaranteed> { if let (Some(CtorKind::Fn), PatKind::Struct(qpath, pattern_fields, ..)) = (variant.ctor_kind(), &pat.kind) { let is_tuple_struct_match = !pattern_fields.is_empty() && pattern_fields.iter().map(|field| field.ident.name.as_str()).all(is_number); if is_tuple_struct_match { - return None; + return Ok(()); } let path = rustc_hir_pretty::qpath_to_string(&self.tcx, qpath); @@ -1839,9 +1830,9 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { format!("({sugg})"), appl, ); - return Some(err); + return Err(err.emit()); } - None + Ok(()) } fn get_suggested_tuple_struct_pattern( @@ -2065,20 +2056,20 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { pat_info: PatInfo<'tcx, '_>, ) -> Ty<'tcx> { let tcx = self.tcx; - let (box_ty, inner_ty) = match self.check_dereferenceable(span, expected, inner) { - Ok(()) => { + let (box_ty, inner_ty) = self + .check_dereferenceable(span, expected, inner) + .and_then(|()| { // Here, `demand::subtype` is good enough, but I don't // think any errors can be introduced by using `demand::eqtype`. let inner_ty = self.next_ty_var(inner.span); let box_ty = Ty::new_box(tcx, inner_ty); - self.demand_eqtype_pat(span, expected, box_ty, pat_info.top_info); - (box_ty, inner_ty) - } - Err(guar) => { + self.demand_eqtype_pat(span, expected, box_ty, pat_info.top_info)?; + Ok((box_ty, inner_ty)) + }) + .unwrap_or_else(|guar| { let err = Ty::new_error(tcx, guar); (err, err) - } - }; + }); self.check_pat(inner, inner_ty, pat_info); box_ty } @@ -2222,7 +2213,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { // Look for a case like `fn foo(&foo: u32)` and suggest // `fn foo(foo: &u32)` - if let Some(mut err) = err { + if let Err(mut err) = err { self.borrow_pat_suggestion(&mut err, pat); err.emit(); } @@ -2327,7 +2318,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { self.try_resolve_slice_ty_to_array_ty(before, slice, span) { debug!(?resolved_arr_ty); - self.demand_eqtype(span, expected, resolved_arr_ty); + let _ = self.demand_eqtype(span, expected, resolved_arr_ty); } } diff --git a/compiler/rustc_index_macros/src/newtype.rs b/compiler/rustc_index_macros/src/newtype.rs index fe9a048734fc7..41863f7b15f98 100644 --- a/compiler/rustc_index_macros/src/newtype.rs +++ b/compiler/rustc_index_macros/src/newtype.rs @@ -205,6 +205,21 @@ impl Parse for Newtype { } } + /// Creates a new index from a given `u16`. + /// + /// # Panics + /// + /// Will panic if `value` exceeds `MAX`. + #[inline] + #vis const fn from_u16(value: u16) -> Self { + let value = value as u32; + assert!(value <= #max); + // SAFETY: We just checked that `value <= max`. + unsafe { + Self::from_u32_unchecked(value) + } + } + /// Creates a new index from a given `u32`. /// /// # Safety diff --git a/compiler/rustc_infer/Cargo.toml b/compiler/rustc_infer/Cargo.toml index 5136ab79a0f84..c1565a7d40fd5 100644 --- a/compiler/rustc_infer/Cargo.toml +++ b/compiler/rustc_infer/Cargo.toml @@ -18,7 +18,6 @@ rustc_macros = { path = "../rustc_macros" } rustc_middle = { path = "../rustc_middle" } rustc_span = { path = "../rustc_span" } rustc_target = { path = "../rustc_target" } -rustc_type_ir = { path = "../rustc_type_ir" } smallvec = { version = "1.8.1", features = ["union", "may_dangle"] } tracing = "0.1" # tidy-alphabetical-end diff --git a/compiler/rustc_infer/src/infer/at.rs b/compiler/rustc_infer/src/infer/at.rs index 01bd732a4cd84..fc7a22833ff05 100644 --- a/compiler/rustc_infer/src/infer/at.rs +++ b/compiler/rustc_infer/src/infer/at.rs @@ -212,19 +212,63 @@ impl<'a, 'tcx> At<'a, 'tcx> { T: ToTrace<'tcx>, { match variance { - ty::Variance::Covariant => self.sub(define_opaque_types, expected, actual), - ty::Variance::Invariant => self.eq(define_opaque_types, expected, actual), - ty::Variance::Contravariant => self.sup(define_opaque_types, expected, actual), + ty::Covariant => self.sub(define_opaque_types, expected, actual), + ty::Invariant => self.eq(define_opaque_types, expected, actual), + ty::Contravariant => self.sup(define_opaque_types, expected, actual), // We could make this make sense but it's not readily // exposed and I don't feel like dealing with it. Note // that bivariance in general does a bit more than just // *nothing*, it checks that the types are the same // "modulo variance" basically. - ty::Variance::Bivariant => panic!("Bivariant given to `relate()`"), + ty::Bivariant => panic!("Bivariant given to `relate()`"), } } + /// Used in the new solver since we don't care about tracking an `ObligationCause`. + pub fn relate_no_trace( + self, + expected: T, + variance: ty::Variance, + actual: T, + ) -> Result>>, NoSolution> + where + T: Relate>, + { + let mut fields = CombineFields::new( + self.infcx, + TypeTrace::dummy(self.cause), + self.param_env, + DefineOpaqueTypes::Yes, + ); + fields.sub().relate_with_variance( + variance, + ty::VarianceDiagInfo::default(), + expected, + actual, + )?; + Ok(fields.goals) + } + + /// Used in the new solver since we don't care about tracking an `ObligationCause`. + pub fn eq_structurally_relating_aliases_no_trace( + self, + expected: T, + actual: T, + ) -> Result>>, NoSolution> + where + T: Relate>, + { + let mut fields = CombineFields::new( + self.infcx, + TypeTrace::dummy(self.cause), + self.param_env, + DefineOpaqueTypes::Yes, + ); + fields.equate(StructurallyRelateAliases::Yes).relate(expected, actual)?; + Ok(fields.goals) + } + /// Computes the least-upper-bound, or mutual supertype, of two /// values. The order of the arguments doesn't matter, but since /// this can result in an error (e.g., if asked to compute LUB of @@ -303,7 +347,7 @@ impl<'tcx> ToTrace<'tcx> for Ty<'tcx> { ) -> TypeTrace<'tcx> { TypeTrace { cause: cause.clone(), - values: Terms(ExpectedFound::new(a_is_expected, a.into(), b.into())), + values: ValuePairs::Terms(ExpectedFound::new(a_is_expected, a.into(), b.into())), } } } @@ -315,7 +359,10 @@ impl<'tcx> ToTrace<'tcx> for ty::Region<'tcx> { a: Self, b: Self, ) -> TypeTrace<'tcx> { - TypeTrace { cause: cause.clone(), values: Regions(ExpectedFound::new(a_is_expected, a, b)) } + TypeTrace { + cause: cause.clone(), + values: ValuePairs::Regions(ExpectedFound::new(a_is_expected, a, b)), + } } } @@ -328,7 +375,7 @@ impl<'tcx> ToTrace<'tcx> for Const<'tcx> { ) -> TypeTrace<'tcx> { TypeTrace { cause: cause.clone(), - values: Terms(ExpectedFound::new(a_is_expected, a.into(), b.into())), + values: ValuePairs::Terms(ExpectedFound::new(a_is_expected, a.into(), b.into())), } } } @@ -344,13 +391,13 @@ impl<'tcx> ToTrace<'tcx> for ty::GenericArg<'tcx> { cause: cause.clone(), values: match (a.unpack(), b.unpack()) { (GenericArgKind::Lifetime(a), GenericArgKind::Lifetime(b)) => { - Regions(ExpectedFound::new(a_is_expected, a, b)) + ValuePairs::Regions(ExpectedFound::new(a_is_expected, a, b)) } (GenericArgKind::Type(a), GenericArgKind::Type(b)) => { - Terms(ExpectedFound::new(a_is_expected, a.into(), b.into())) + ValuePairs::Terms(ExpectedFound::new(a_is_expected, a.into(), b.into())) } (GenericArgKind::Const(a), GenericArgKind::Const(b)) => { - Terms(ExpectedFound::new(a_is_expected, a.into(), b.into())) + ValuePairs::Terms(ExpectedFound::new(a_is_expected, a.into(), b.into())) } ( @@ -379,7 +426,10 @@ impl<'tcx> ToTrace<'tcx> for ty::Term<'tcx> { a: Self, b: Self, ) -> TypeTrace<'tcx> { - TypeTrace { cause: cause.clone(), values: Terms(ExpectedFound::new(a_is_expected, a, b)) } + TypeTrace { + cause: cause.clone(), + values: ValuePairs::Terms(ExpectedFound::new(a_is_expected, a, b)), + } } } @@ -392,7 +442,7 @@ impl<'tcx> ToTrace<'tcx> for ty::TraitRef<'tcx> { ) -> TypeTrace<'tcx> { TypeTrace { cause: cause.clone(), - values: TraitRefs(ExpectedFound::new(a_is_expected, a, b)), + values: ValuePairs::TraitRefs(ExpectedFound::new(a_is_expected, a, b)), } } } @@ -406,7 +456,7 @@ impl<'tcx> ToTrace<'tcx> for ty::AliasTy<'tcx> { ) -> TypeTrace<'tcx> { TypeTrace { cause: cause.clone(), - values: Aliases(ExpectedFound::new(a_is_expected, a.into(), b.into())), + values: ValuePairs::Aliases(ExpectedFound::new(a_is_expected, a.into(), b.into())), } } } @@ -418,7 +468,10 @@ impl<'tcx> ToTrace<'tcx> for ty::AliasTerm<'tcx> { a: Self, b: Self, ) -> TypeTrace<'tcx> { - TypeTrace { cause: cause.clone(), values: Aliases(ExpectedFound::new(a_is_expected, a, b)) } + TypeTrace { + cause: cause.clone(), + values: ValuePairs::Aliases(ExpectedFound::new(a_is_expected, a, b)), + } } } @@ -431,7 +484,7 @@ impl<'tcx> ToTrace<'tcx> for ty::FnSig<'tcx> { ) -> TypeTrace<'tcx> { TypeTrace { cause: cause.clone(), - values: PolySigs(ExpectedFound::new( + values: ValuePairs::PolySigs(ExpectedFound::new( a_is_expected, ty::Binder::dummy(a), ty::Binder::dummy(b), @@ -449,7 +502,7 @@ impl<'tcx> ToTrace<'tcx> for ty::PolyFnSig<'tcx> { ) -> TypeTrace<'tcx> { TypeTrace { cause: cause.clone(), - values: PolySigs(ExpectedFound::new(a_is_expected, a, b)), + values: ValuePairs::PolySigs(ExpectedFound::new(a_is_expected, a, b)), } } } @@ -463,7 +516,7 @@ impl<'tcx> ToTrace<'tcx> for ty::PolyExistentialTraitRef<'tcx> { ) -> TypeTrace<'tcx> { TypeTrace { cause: cause.clone(), - values: ExistentialTraitRef(ExpectedFound::new(a_is_expected, a, b)), + values: ValuePairs::ExistentialTraitRef(ExpectedFound::new(a_is_expected, a, b)), } } } @@ -477,7 +530,7 @@ impl<'tcx> ToTrace<'tcx> for ty::PolyExistentialProjection<'tcx> { ) -> TypeTrace<'tcx> { TypeTrace { cause: cause.clone(), - values: ExistentialProjection(ExpectedFound::new(a_is_expected, a, b)), + values: ValuePairs::ExistentialProjection(ExpectedFound::new(a_is_expected, a, b)), } } } diff --git a/compiler/rustc_infer/src/infer/error_reporting/mod.rs b/compiler/rustc_infer/src/infer/error_reporting/mod.rs index ed483c6cbeb41..e15866f3f0f62 100644 --- a/compiler/rustc_infer/src/infer/error_reporting/mod.rs +++ b/compiler/rustc_infer/src/infer/error_reporting/mod.rs @@ -64,11 +64,11 @@ use rustc_errors::{ codes::*, pluralize, struct_span_code_err, Applicability, Diag, DiagCtxt, DiagStyledString, ErrorGuaranteed, IntoDiagArg, StringPart, }; -use rustc_hir as hir; use rustc_hir::def::DefKind; use rustc_hir::def_id::{DefId, LocalDefId}; use rustc_hir::intravisit::Visitor; use rustc_hir::lang_items::LangItem; +use rustc_hir::{self as hir, ParamName}; use rustc_macros::extension; use rustc_middle::bug; use rustc_middle::dep_graph::DepContext; @@ -1707,6 +1707,9 @@ impl<'tcx> TypeErrCtxt<'_, 'tcx> { ValuePairs::ExistentialProjection(_) => { (false, Mismatch::Fixed("existential projection")) } + ValuePairs::Dummy => { + bug!("do not expect to report a type error from a ValuePairs::Dummy") + } }; let Some(vals) = self.values_str(values) else { // Derived error. Cancel the emitter. @@ -2250,12 +2253,12 @@ impl<'tcx> TypeErrCtxt<'_, 'tcx> { values: ValuePairs<'tcx>, ) -> Option<(DiagStyledString, DiagStyledString, Option)> { match values { - infer::Regions(exp_found) => self.expected_found_str(exp_found), - infer::Terms(exp_found) => self.expected_found_str_term(exp_found), - infer::Aliases(exp_found) => self.expected_found_str(exp_found), - infer::ExistentialTraitRef(exp_found) => self.expected_found_str(exp_found), - infer::ExistentialProjection(exp_found) => self.expected_found_str(exp_found), - infer::TraitRefs(exp_found) => { + ValuePairs::Regions(exp_found) => self.expected_found_str(exp_found), + ValuePairs::Terms(exp_found) => self.expected_found_str_term(exp_found), + ValuePairs::Aliases(exp_found) => self.expected_found_str(exp_found), + ValuePairs::ExistentialTraitRef(exp_found) => self.expected_found_str(exp_found), + ValuePairs::ExistentialProjection(exp_found) => self.expected_found_str(exp_found), + ValuePairs::TraitRefs(exp_found) => { let pretty_exp_found = ty::error::ExpectedFound { expected: exp_found.expected.print_trait_sugared(), found: exp_found.found.print_trait_sugared(), @@ -2267,7 +2270,7 @@ impl<'tcx> TypeErrCtxt<'_, 'tcx> { ret => ret, } } - infer::PolySigs(exp_found) => { + ValuePairs::PolySigs(exp_found) => { let exp_found = self.resolve_vars_if_possible(exp_found); if exp_found.references_error() { return None; @@ -2275,6 +2278,9 @@ impl<'tcx> TypeErrCtxt<'_, 'tcx> { let (exp, fnd) = self.cmp_fn_sig(&exp_found.expected, &exp_found.found); Some((exp, fnd, None)) } + ValuePairs::Dummy => { + bug!("do not expect to report a type error from a ValuePairs::Dummy") + } } } @@ -2423,7 +2429,8 @@ impl<'tcx> TypeErrCtxt<'_, 'tcx> { let (type_scope, type_param_sugg_span) = match bound_kind { GenericKind::Param(param) => { let generics = self.tcx.generics_of(generic_param_scope); - let def_id = generics.type_param(param, self.tcx).def_id.expect_local(); + let type_param = generics.type_param(param, self.tcx); + let def_id = type_param.def_id.expect_local(); let scope = self.tcx.local_def_id_to_hir_id(def_id).owner.def_id; // Get the `hir::Param` to verify whether it already has any bounds. // We do this to avoid suggesting code that ends up as `T: 'a'b`, @@ -2433,7 +2440,18 @@ impl<'tcx> TypeErrCtxt<'_, 'tcx> { Some((span, open_paren_sp)) => Some((span, true, open_paren_sp)), // If `param` corresponds to `Self`, no usable suggestion span. None if generics.has_self && param.index == 0 => None, - None => Some((self.tcx.def_span(def_id).shrink_to_hi(), false, None)), + None => { + let span = if let Some(param) = + hir_generics.params.iter().find(|param| param.def_id == def_id) + && let ParamName::Plain(ident) = param.name + { + ident.span.shrink_to_hi() + } else { + let span = self.tcx.def_span(def_id); + span.shrink_to_hi() + }; + Some((span, false, None)) + } }; (scope, sugg_span) } diff --git a/compiler/rustc_infer/src/infer/error_reporting/note_and_explain.rs b/compiler/rustc_infer/src/infer/error_reporting/note_and_explain.rs index effb4090692cc..bc59b5e033baa 100644 --- a/compiler/rustc_infer/src/infer/error_reporting/note_and_explain.rs +++ b/compiler/rustc_infer/src/infer/error_reporting/note_and_explain.rs @@ -546,7 +546,7 @@ impl Trait for X { for pred in hir_generics.bounds_for_param(def_id) { if self.constrain_generic_bound_associated_type_structured_suggestion( diag, - &trait_ref, + trait_ref, pred.bounds, assoc, assoc_args, @@ -715,7 +715,7 @@ fn foo(&self) -> Self::T { String::new() } self.constrain_generic_bound_associated_type_structured_suggestion( diag, - &trait_ref, + trait_ref, opaque_hir_ty.bounds, assoc, assoc_args, @@ -869,7 +869,7 @@ fn foo(&self) -> Self::T { String::new() } fn constrain_generic_bound_associated_type_structured_suggestion( &self, diag: &mut Diag<'_>, - trait_ref: &ty::TraitRef<'tcx>, + trait_ref: ty::TraitRef<'tcx>, bounds: hir::GenericBounds<'_>, assoc: ty::AssocItem, assoc_args: &[ty::GenericArg<'tcx>], diff --git a/compiler/rustc_infer/src/infer/mod.rs b/compiler/rustc_infer/src/infer/mod.rs index 32b50053b5076..8412912b9f370 100644 --- a/compiler/rustc_infer/src/infer/mod.rs +++ b/compiler/rustc_infer/src/infer/mod.rs @@ -9,9 +9,8 @@ pub use rustc_middle::ty::IntVarValue; pub use BoundRegionConversionTime::*; pub use RegionVariableOrigin::*; pub use SubregionOrigin::*; -pub use ValuePairs::*; -use crate::infer::relate::RelateResult; +use crate::infer::relate::{Relate, RelateResult}; use crate::traits::{self, ObligationCause, ObligationInspector, PredicateObligation, TraitEngine}; use error_reporting::TypeErrCtxt; use free_regions::RegionRelations; @@ -35,6 +34,7 @@ use rustc_middle::infer::unify_key::{ConstVidKey, EffectVidKey}; use rustc_middle::mir::interpret::{ErrorHandled, EvalToValTreeResult}; use rustc_middle::mir::ConstraintCategory; use rustc_middle::traits::select; +use rustc_middle::traits::solve::{Goal, NoSolution}; use rustc_middle::ty::error::{ExpectedFound, TypeError}; use rustc_middle::ty::fold::BoundVarReplacerDelegate; use rustc_middle::ty::fold::{TypeFoldable, TypeFolder, TypeSuperFoldable}; @@ -44,7 +44,7 @@ use rustc_middle::ty::{ConstVid, EffectVid, FloatVid, IntVid, TyVid}; use rustc_middle::ty::{GenericArg, GenericArgKind, GenericArgs, GenericArgsRef}; use rustc_middle::{bug, span_bug}; use rustc_span::symbol::Symbol; -use rustc_span::Span; +use rustc_span::{Span, DUMMY_SP}; use snapshot::undo_log::InferCtxtUndoLogs; use std::cell::{Cell, RefCell}; use std::fmt; @@ -352,27 +352,27 @@ impl<'tcx> ty::InferCtxtLike for InferCtxt<'tcx> { } } - fn universe_of_ct(&self, ct: ConstVid) -> Option { - // Same issue as with `universe_of_ty` - match self.probe_const_var(ct) { + fn universe_of_lt(&self, lt: ty::RegionVid) -> Option { + match self.inner.borrow_mut().unwrap_region_constraints().probe_value(lt) { Err(universe) => Some(universe), Ok(_) => None, } } - fn universe_of_lt(&self, lt: ty::RegionVid) -> Option { - match self.inner.borrow_mut().unwrap_region_constraints().probe_value(lt) { + fn universe_of_ct(&self, ct: ConstVid) -> Option { + // Same issue as with `universe_of_ty` + match self.probe_const_var(ct) { Err(universe) => Some(universe), Ok(_) => None, } } - fn opportunistic_resolve_lt_var(&self, vid: ty::RegionVid) -> ty::Region<'tcx> { - self.inner.borrow_mut().unwrap_region_constraints().opportunistic_resolve_var(self.tcx, vid) + fn root_ty_var(&self, var: TyVid) -> TyVid { + self.root_var(var) } - fn defining_opaque_types(&self) -> &'tcx ty::List { - self.defining_opaque_types + fn root_const_var(&self, var: ConstVid) -> ConstVid { + self.root_const_var(var) } fn opportunistic_resolve_ty_var(&self, vid: TyVid) -> Ty<'tcx> { @@ -405,6 +405,76 @@ impl<'tcx> ty::InferCtxtLike for InferCtxt<'tcx> { } } } + + fn opportunistic_resolve_lt_var(&self, vid: ty::RegionVid) -> ty::Region<'tcx> { + self.inner.borrow_mut().unwrap_region_constraints().opportunistic_resolve_var(self.tcx, vid) + } + + fn defining_opaque_types(&self) -> &'tcx ty::List { + self.defining_opaque_types + } + + fn next_ty_infer(&self) -> Ty<'tcx> { + self.next_ty_var(DUMMY_SP) + } + + fn next_const_infer(&self) -> ty::Const<'tcx> { + self.next_const_var(DUMMY_SP) + } + + fn fresh_args_for_item(&self, def_id: DefId) -> ty::GenericArgsRef<'tcx> { + self.fresh_args_for_item(DUMMY_SP, def_id) + } + + fn instantiate_binder_with_infer + Copy>( + &self, + value: ty::Binder<'tcx, T>, + ) -> T { + self.instantiate_binder_with_fresh_vars( + DUMMY_SP, + BoundRegionConversionTime::HigherRankedType, + value, + ) + } + + fn enter_forall> + Copy, U>( + &self, + value: ty::Binder<'tcx, T>, + f: impl FnOnce(T) -> U, + ) -> U { + self.enter_forall(value, f) + } + + fn relate>>( + &self, + param_env: ty::ParamEnv<'tcx>, + lhs: T, + variance: ty::Variance, + rhs: T, + ) -> Result>>, NoSolution> { + self.at(&ObligationCause::dummy(), param_env).relate_no_trace(lhs, variance, rhs) + } + + fn eq_structurally_relating_aliases>>( + &self, + param_env: ty::ParamEnv<'tcx>, + lhs: T, + rhs: T, + ) -> Result>>, NoSolution> { + self.at(&ObligationCause::dummy(), param_env) + .eq_structurally_relating_aliases_no_trace(lhs, rhs) + } + + fn resolve_vars_if_possible(&self, value: T) -> T + where + T: TypeFoldable>, + { + self.resolve_vars_if_possible(value) + } + + fn probe(&self, probe: impl FnOnce() -> T) -> T { + self.probe(|_| probe()) + } } /// See the `error_reporting` module for more details. @@ -417,6 +487,7 @@ pub enum ValuePairs<'tcx> { PolySigs(ExpectedFound>), ExistentialTraitRef(ExpectedFound>), ExistentialProjection(ExpectedFound>), + Dummy, } impl<'tcx> ValuePairs<'tcx> { @@ -810,13 +881,13 @@ impl<'tcx> InferCtxt<'tcx> { .collect(); vars.extend( (0..inner.int_unification_table().len()) - .map(|i| ty::IntVid::from_u32(i as u32)) + .map(|i| ty::IntVid::from_usize(i)) .filter(|&vid| inner.int_unification_table().probe_value(vid).is_unknown()) .map(|v| Ty::new_int_var(self.tcx, v)), ); vars.extend( (0..inner.float_unification_table().len()) - .map(|i| ty::FloatVid::from_u32(i as u32)) + .map(|i| ty::FloatVid::from_usize(i)) .filter(|&vid| inner.float_unification_table().probe_value(vid).is_unknown()) .map(|v| Ty::new_float_var(self.tcx, v)), ); @@ -1812,7 +1883,7 @@ impl<'tcx> TypeTrace<'tcx> { ) -> TypeTrace<'tcx> { TypeTrace { cause: cause.clone(), - values: Terms(ExpectedFound::new(a_is_expected, a.into(), b.into())), + values: ValuePairs::Terms(ExpectedFound::new(a_is_expected, a.into(), b.into())), } } @@ -1824,7 +1895,7 @@ impl<'tcx> TypeTrace<'tcx> { ) -> TypeTrace<'tcx> { TypeTrace { cause: cause.clone(), - values: TraitRefs(ExpectedFound::new(a_is_expected, a, b)), + values: ValuePairs::TraitRefs(ExpectedFound::new(a_is_expected, a, b)), } } @@ -1836,9 +1907,13 @@ impl<'tcx> TypeTrace<'tcx> { ) -> TypeTrace<'tcx> { TypeTrace { cause: cause.clone(), - values: Terms(ExpectedFound::new(a_is_expected, a.into(), b.into())), + values: ValuePairs::Terms(ExpectedFound::new(a_is_expected, a.into(), b.into())), } } + + fn dummy(cause: &ObligationCause<'tcx>) -> TypeTrace<'tcx> { + TypeTrace { cause: cause.clone(), values: ValuePairs::Dummy } + } } impl<'tcx> SubregionOrigin<'tcx> { diff --git a/compiler/rustc_infer/src/infer/opaque_types/mod.rs b/compiler/rustc_infer/src/infer/opaque_types/mod.rs index 7114b888718b3..b8dd501a721b5 100644 --- a/compiler/rustc_infer/src/infer/opaque_types/mod.rs +++ b/compiler/rustc_infer/src/infer/opaque_types/mod.rs @@ -345,7 +345,7 @@ impl<'tcx> InferCtxt<'tcx> { .args .iter() .enumerate() - .filter(|(i, _)| variances[*i] == ty::Variance::Invariant) + .filter(|(i, _)| variances[*i] == ty::Invariant) .filter_map(|(_, arg)| match arg.unpack() { GenericArgKind::Lifetime(r) => Some(r), GenericArgKind::Type(_) | GenericArgKind::Const(_) => None, @@ -441,7 +441,7 @@ where let variances = self.tcx.variances_of(*def_id); for (v, s) in std::iter::zip(variances, args.iter()) { - if *v != ty::Variance::Bivariant { + if *v != ty::Bivariant { s.visit_with(self); } } diff --git a/compiler/rustc_infer/src/infer/outlives/for_liveness.rs b/compiler/rustc_infer/src/infer/outlives/for_liveness.rs index 488f435994d4d..c02ab98b2baeb 100644 --- a/compiler/rustc_infer/src/infer/outlives/for_liveness.rs +++ b/compiler/rustc_infer/src/infer/outlives/for_liveness.rs @@ -102,9 +102,7 @@ where }; for (idx, s) in args.iter().enumerate() { - if variances.map(|variances| variances[idx]) - != Some(ty::Variance::Bivariant) - { + if variances.map(|variances| variances[idx]) != Some(ty::Bivariant) { s.visit_with(self); } } diff --git a/compiler/rustc_infer/src/infer/relate/generalize.rs b/compiler/rustc_infer/src/infer/relate/generalize.rs index 87a2f0b45803d..d6e57d8538772 100644 --- a/compiler/rustc_infer/src/infer/relate/generalize.rs +++ b/compiler/rustc_infer/src/infer/relate/generalize.rs @@ -83,16 +83,16 @@ impl<'tcx> InferCtxt<'tcx> { // mention `?0`. if self.next_trait_solver() { let (lhs, rhs, direction) = match instantiation_variance { - ty::Variance::Invariant => { + ty::Invariant => { (generalized_ty.into(), source_ty.into(), AliasRelationDirection::Equate) } - ty::Variance::Covariant => { + ty::Covariant => { (generalized_ty.into(), source_ty.into(), AliasRelationDirection::Subtype) } - ty::Variance::Contravariant => { + ty::Contravariant => { (source_ty.into(), generalized_ty.into(), AliasRelationDirection::Subtype) } - ty::Variance::Bivariant => unreachable!("bivariant generalization"), + ty::Bivariant => unreachable!("bivariant generalization"), }; relation.register_predicates([ty::PredicateKind::AliasRelate(lhs, rhs, direction)]); @@ -192,7 +192,7 @@ impl<'tcx> InferCtxt<'tcx> { relation.span(), relation.structurally_relate_aliases(), target_vid, - ty::Variance::Invariant, + ty::Invariant, source_ct, )?; @@ -210,14 +210,14 @@ impl<'tcx> InferCtxt<'tcx> { // generalized const and the source. if target_is_expected { relation.relate_with_variance( - ty::Variance::Invariant, + ty::Invariant, ty::VarianceDiagInfo::default(), generalized_ct, source_ct, )?; } else { relation.relate_with_variance( - ty::Variance::Invariant, + ty::Invariant, ty::VarianceDiagInfo::default(), source_ct, generalized_ct, @@ -411,7 +411,7 @@ impl<'tcx> TypeRelation> for Generalizer<'_, 'tcx> { a_arg: ty::GenericArgsRef<'tcx>, b_arg: ty::GenericArgsRef<'tcx>, ) -> RelateResult<'tcx, ty::GenericArgsRef<'tcx>> { - if self.ambient_variance == ty::Variance::Invariant { + if self.ambient_variance == ty::Invariant { // Avoid fetching the variance if we are in an invariant // context; no need, and it can induce dependency cycles // (e.g., #41849). @@ -667,7 +667,7 @@ impl<'tcx> TypeRelation> for Generalizer<'_, 'tcx> { // structural. ty::ConstKind::Unevaluated(ty::UnevaluatedConst { def, args }) => { let args = self.relate_with_variance( - ty::Variance::Invariant, + ty::Invariant, ty::VarianceDiagInfo::default(), args, args, diff --git a/compiler/rustc_infer/src/infer/relate/glb.rs b/compiler/rustc_infer/src/infer/relate/glb.rs index cc17e60a79b00..067004ecaebbf 100644 --- a/compiler/rustc_infer/src/infer/relate/glb.rs +++ b/compiler/rustc_infer/src/infer/relate/glb.rs @@ -94,12 +94,7 @@ impl<'tcx> TypeRelation> for Glb<'_, '_, 'tcx> { // When higher-ranked types are involved, computing the GLB is // very challenging, switch to invariance. This is obviously // overly conservative but works ok in practice. - self.relate_with_variance( - ty::Variance::Invariant, - ty::VarianceDiagInfo::default(), - a, - b, - )?; + self.relate_with_variance(ty::Invariant, ty::VarianceDiagInfo::default(), a, b)?; Ok(a) } else { Ok(ty::Binder::dummy(self.relate(a.skip_binder(), b.skip_binder())?)) diff --git a/compiler/rustc_infer/src/infer/relate/lub.rs b/compiler/rustc_infer/src/infer/relate/lub.rs index e9d300d349c62..2184416b4ccef 100644 --- a/compiler/rustc_infer/src/infer/relate/lub.rs +++ b/compiler/rustc_infer/src/infer/relate/lub.rs @@ -94,12 +94,7 @@ impl<'tcx> TypeRelation> for Lub<'_, '_, 'tcx> { // When higher-ranked types are involved, computing the LUB is // very challenging, switch to invariance. This is obviously // overly conservative but works ok in practice. - self.relate_with_variance( - ty::Variance::Invariant, - ty::VarianceDiagInfo::default(), - a, - b, - )?; + self.relate_with_variance(ty::Invariant, ty::VarianceDiagInfo::default(), a, b)?; Ok(a) } else { Ok(ty::Binder::dummy(self.relate(a.skip_binder(), b.skip_binder())?)) diff --git a/compiler/rustc_infer/src/infer/relate/mod.rs b/compiler/rustc_infer/src/infer/relate/mod.rs index e7b50479b850c..41cc945492daf 100644 --- a/compiler/rustc_infer/src/infer/relate/mod.rs +++ b/compiler/rustc_infer/src/infer/relate/mod.rs @@ -4,11 +4,9 @@ pub use rustc_middle::ty::relate::*; -pub use self::_match::MatchAgainstFreshVars; pub use self::combine::CombineFields; pub use self::combine::PredicateEmittingRelation; -pub mod _match; pub(super) mod combine; mod generalize; mod glb; diff --git a/compiler/rustc_infer/src/infer/relate/type_relating.rs b/compiler/rustc_infer/src/infer/relate/type_relating.rs index f7b2f11e3d707..f2bec9392d542 100644 --- a/compiler/rustc_infer/src/infer/relate/type_relating.rs +++ b/compiler/rustc_infer/src/infer/relate/type_relating.rs @@ -42,7 +42,7 @@ impl<'tcx> TypeRelation> for TypeRelating<'_, '_, 'tcx> { a_arg: ty::GenericArgsRef<'tcx>, b_arg: ty::GenericArgsRef<'tcx>, ) -> RelateResult<'tcx, ty::GenericArgsRef<'tcx>> { - if self.ambient_variance == ty::Variance::Invariant { + if self.ambient_variance == ty::Invariant { // Avoid fetching the variance if we are in an invariant // context; no need, and it can induce dependency cycles // (e.g., #41849). @@ -325,23 +325,23 @@ impl<'tcx> PredicateEmittingRelation<'tcx> for TypeRelating<'_, '_, 'tcx> { fn register_alias_relate_predicate(&mut self, a: Ty<'tcx>, b: Ty<'tcx>) { self.register_predicates([ty::Binder::dummy(match self.ambient_variance { - ty::Variance::Covariant => ty::PredicateKind::AliasRelate( + ty::Covariant => ty::PredicateKind::AliasRelate( a.into(), b.into(), ty::AliasRelationDirection::Subtype, ), // a :> b is b <: a - ty::Variance::Contravariant => ty::PredicateKind::AliasRelate( + ty::Contravariant => ty::PredicateKind::AliasRelate( b.into(), a.into(), ty::AliasRelationDirection::Subtype, ), - ty::Variance::Invariant => ty::PredicateKind::AliasRelate( + ty::Invariant => ty::PredicateKind::AliasRelate( a.into(), b.into(), ty::AliasRelationDirection::Equate, ), - ty::Variance::Bivariant => { + ty::Bivariant => { unreachable!("Expected bivariance to be handled in relate_with_variance") } })]); diff --git a/compiler/rustc_infer/src/traits/util.rs b/compiler/rustc_infer/src/traits/util.rs index cc12a4bf09146..ab4148faaab63 100644 --- a/compiler/rustc_infer/src/traits/util.rs +++ b/compiler/rustc_infer/src/traits/util.rs @@ -285,8 +285,7 @@ impl<'tcx, O: Elaboratable<'tcx>> Elaborator<'tcx, O> { let obligations = predicates.predicates.iter().enumerate().map(|(index, &(clause, span))| { elaboratable.child_with_derived_cause( - clause - .instantiate_supertrait(tcx, &bound_clause.rebind(data.trait_ref)), + clause.instantiate_supertrait(tcx, bound_clause.rebind(data.trait_ref)), span, bound_clause.rebind(data), index, diff --git a/compiler/rustc_lint/messages.ftl b/compiler/rustc_lint/messages.ftl index 733c73bc3d078..043042a492b54 100644 --- a/compiler/rustc_lint/messages.ftl +++ b/compiler/rustc_lint/messages.ftl @@ -550,6 +550,7 @@ lint_non_local_definitions_impl = non-local `impl` definition, `impl` blocks sho .bounds = `impl` may be usable in bounds, etc. from outside the expression, which might e.g. make something constructible that previously wasn't, because it's still on a publicly-visible type .exception = items in an anonymous const item (`const _: () = {"{"} ... {"}"}`) are treated as in the same scope as the anonymous const's declaration .const_anon = use a const-anon item to suppress this lint + .macro_to_change = the {$macro_kind} `{$macro_to_change}` defines the non-local `impl`, and may need to be changed lint_non_local_definitions_impl_move_help = move the `impl` block outside of this {$body_kind_descr} {$depth -> diff --git a/compiler/rustc_lint/src/deref_into_dyn_supertrait.rs b/compiler/rustc_lint/src/deref_into_dyn_supertrait.rs index b671dfaa0d1b0..911975f617912 100644 --- a/compiler/rustc_lint/src/deref_into_dyn_supertrait.rs +++ b/compiler/rustc_lint/src/deref_into_dyn_supertrait.rs @@ -3,7 +3,7 @@ use crate::{ LateContext, LateLintPass, LintContext, }; -use rustc_hir as hir; +use rustc_hir::{self as hir, LangItem}; use rustc_middle::ty; use rustc_session::lint::FutureIncompatibilityReason; use rustc_session::{declare_lint, declare_lint_pass}; @@ -66,7 +66,7 @@ impl<'tcx> LateLintPass<'tcx> for DerefIntoDynSupertrait { // the trait is a `Deref` implementation && let Some(trait_) = &impl_.of_trait && let Some(did) = trait_.trait_def_id() - && Some(did) == tcx.lang_items().deref_trait() + && tcx.is_lang_item(did, LangItem::Deref) // the self type is `dyn t_principal` && let self_ty = tcx.type_of(item.owner_id).instantiate_identity() && let ty::Dynamic(data, _, ty::Dyn) = self_ty.kind() diff --git a/compiler/rustc_lint/src/lints.rs b/compiler/rustc_lint/src/lints.rs index b377da31a581b..8059f5c1a2ea7 100644 --- a/compiler/rustc_lint/src/lints.rs +++ b/compiler/rustc_lint/src/lints.rs @@ -1362,6 +1362,7 @@ pub enum NonLocalDefinitionsDiag { has_trait: bool, self_ty_str: String, of_trait_str: Option, + macro_to_change: Option<(String, &'static str)>, }, MacroRules { depth: u32, @@ -1387,6 +1388,7 @@ impl<'a> LintDiagnostic<'a, ()> for NonLocalDefinitionsDiag { has_trait, self_ty_str, of_trait_str, + macro_to_change, } => { diag.primary_message(fluent::lint_non_local_definitions_impl); diag.arg("depth", depth); @@ -1397,6 +1399,15 @@ impl<'a> LintDiagnostic<'a, ()> for NonLocalDefinitionsDiag { diag.arg("of_trait_str", of_trait_str); } + if let Some((macro_to_change, macro_kind)) = macro_to_change { + diag.arg("macro_to_change", macro_to_change); + diag.arg("macro_kind", macro_kind); + diag.note(fluent::lint_macro_to_change); + } + if let Some(cargo_update) = cargo_update { + diag.subdiagnostic(&diag.dcx, cargo_update); + } + if has_trait { diag.note(fluent::lint_bounds); diag.note(fluent::lint_with_trait); @@ -1422,9 +1433,6 @@ impl<'a> LintDiagnostic<'a, ()> for NonLocalDefinitionsDiag { ); } - if let Some(cargo_update) = cargo_update { - diag.subdiagnostic(&diag.dcx, cargo_update); - } if let Some(const_anon) = const_anon { diag.note(fluent::lint_exception); if let Some(const_anon) = const_anon { diff --git a/compiler/rustc_lint/src/non_fmt_panic.rs b/compiler/rustc_lint/src/non_fmt_panic.rs index c9d6785411237..2dc2a0efdf040 100644 --- a/compiler/rustc_lint/src/non_fmt_panic.rs +++ b/compiler/rustc_lint/src/non_fmt_panic.rs @@ -2,7 +2,7 @@ use crate::lints::{NonFmtPanicBraces, NonFmtPanicUnused}; use crate::{fluent_generated as fluent, LateContext, LateLintPass, LintContext}; use rustc_ast as ast; use rustc_errors::Applicability; -use rustc_hir as hir; +use rustc_hir::{self as hir, LangItem}; use rustc_infer::infer::TyCtxtInferExt; use rustc_middle::bug; use rustc_middle::lint::in_external_macro; @@ -53,8 +53,8 @@ impl<'tcx> LateLintPass<'tcx> for NonPanicFmt { if let &ty::FnDef(def_id, _) = cx.typeck_results().expr_ty(f).kind() { let f_diagnostic_name = cx.tcx.get_diagnostic_name(def_id); - if Some(def_id) == cx.tcx.lang_items().begin_panic_fn() - || Some(def_id) == cx.tcx.lang_items().panic_fn() + if cx.tcx.is_lang_item(def_id, LangItem::BeginPanic) + || cx.tcx.is_lang_item(def_id, LangItem::Panic) || f_diagnostic_name == Some(sym::panic_str_2015) { if let Some(id) = f.span.ctxt().outer_expn_data().macro_def_id { @@ -153,7 +153,7 @@ fn check_panic<'tcx>(cx: &LateContext<'tcx>, f: &'tcx hir::Expr<'tcx>, arg: &'tc ty::Ref(_, r, _) if r.is_str(), ) || matches!( ty.ty_adt_def(), - Some(ty_def) if Some(ty_def.did()) == cx.tcx.lang_items().string(), + Some(ty_def) if cx.tcx.is_lang_item(ty_def.did(), LangItem::String), ); let infcx = cx.tcx.infer_ctxt().build(); diff --git a/compiler/rustc_lint/src/non_local_def.rs b/compiler/rustc_lint/src/non_local_def.rs index d7ffc34d824fd..b0ec6e06658f3 100644 --- a/compiler/rustc_lint/src/non_local_def.rs +++ b/compiler/rustc_lint/src/non_local_def.rs @@ -258,6 +258,13 @@ impl<'tcx> LateLintPass<'tcx> for NonLocalDefinitions { Some((cx.tcx.def_span(parent), may_move)) }; + let macro_to_change = + if let ExpnKind::Macro(kind, name) = item.span.ctxt().outer_expn_data().kind { + Some((name.to_string(), kind.descr())) + } else { + None + }; + cx.emit_span_lint( NON_LOCAL_DEFINITIONS, ms, @@ -274,6 +281,7 @@ impl<'tcx> LateLintPass<'tcx> for NonLocalDefinitions { move_to, may_remove, has_trait: impl_.of_trait.is_some(), + macro_to_change, }, ) } diff --git a/compiler/rustc_lint/src/shadowed_into_iter.rs b/compiler/rustc_lint/src/shadowed_into_iter.rs index 85006421fdd24..da2b5878b19cd 100644 --- a/compiler/rustc_lint/src/shadowed_into_iter.rs +++ b/compiler/rustc_lint/src/shadowed_into_iter.rs @@ -52,7 +52,7 @@ declare_lint! { /// Since Rust 1.80.0, boxed slices implement `IntoIterator`. However, to avoid /// breakage, `boxed_slice.into_iter()` in Rust 2015, 2018, and 2021 code will still /// behave as `(&boxed_slice).into_iter()`, returning an iterator over - /// references, just like in Rust 1.80.0 and earlier. + /// references, just like in Rust 1.79.0 and earlier. /// This only applies to the method call syntax `boxed_slice.into_iter()`, not to /// any other syntax such as `for _ in boxed_slice` or `IntoIterator::into_iter(boxed_slice)`. pub BOXED_SLICE_INTO_ITER, diff --git a/compiler/rustc_lint/src/traits.rs b/compiler/rustc_lint/src/traits.rs index 4d1b1dc4fb783..6983e7abbd64e 100644 --- a/compiler/rustc_lint/src/traits.rs +++ b/compiler/rustc_lint/src/traits.rs @@ -2,7 +2,7 @@ use crate::lints::{DropGlue, DropTraitConstraintsDiag}; use crate::LateContext; use crate::LateLintPass; use crate::LintContext; -use rustc_hir as hir; +use rustc_hir::{self as hir, LangItem}; use rustc_session::{declare_lint, declare_lint_pass}; use rustc_span::symbol::sym; @@ -96,7 +96,7 @@ impl<'tcx> LateLintPass<'tcx> for DropTraitConstraints { continue; }; let def_id = trait_predicate.trait_ref.def_id; - if cx.tcx.lang_items().drop_trait() == Some(def_id) { + if cx.tcx.is_lang_item(def_id, LangItem::Drop) { // Explicitly allow `impl Drop`, a drop-guards-as-unnameable-type pattern. if trait_predicate.trait_ref.self_ty().is_impl_trait() { continue; diff --git a/compiler/rustc_lint/src/unused.rs b/compiler/rustc_lint/src/unused.rs index c8da9f179e711..7a1aa4043be02 100644 --- a/compiler/rustc_lint/src/unused.rs +++ b/compiler/rustc_lint/src/unused.rs @@ -10,9 +10,9 @@ use rustc_ast as ast; use rustc_ast::util::{classify, parser}; use rustc_ast::{ExprKind, StmtKind}; use rustc_errors::{pluralize, MultiSpan}; -use rustc_hir as hir; use rustc_hir::def::{DefKind, Res}; use rustc_hir::def_id::DefId; +use rustc_hir::{self as hir, LangItem}; use rustc_infer::traits::util::elaborate; use rustc_middle::ty::adjustment; use rustc_middle::ty::{self, Ty}; @@ -289,7 +289,7 @@ impl<'tcx> LateLintPass<'tcx> for UnusedResults { is_ty_must_use(cx, boxed_ty, expr, span) .map(|inner| MustUsePath::Boxed(Box::new(inner))) } - ty::Adt(def, args) if cx.tcx.lang_items().pin_type() == Some(def.did()) => { + ty::Adt(def, args) if cx.tcx.is_lang_item(def.did(), LangItem::Pin) => { let pinned_ty = args.type_at(0); is_ty_must_use(cx, pinned_ty, expr, span) .map(|inner| MustUsePath::Pinned(Box::new(inner))) diff --git a/compiler/rustc_lint_defs/src/builtin.rs b/compiler/rustc_lint_defs/src/builtin.rs index 726bd0de1299f..a12c76037e77e 100644 --- a/compiler/rustc_lint_defs/src/builtin.rs +++ b/compiler/rustc_lint_defs/src/builtin.rs @@ -34,6 +34,7 @@ declare_lint_pass! { CONST_EVALUATABLE_UNCHECKED, CONST_ITEM_MUTATION, DEAD_CODE, + DEPENDENCY_ON_UNIT_NEVER_TYPE_FALLBACK, DEPRECATED, DEPRECATED_CFG_ATTR_CRATE_TYPE_NAME, DEPRECATED_IN_FUTURE, @@ -3257,7 +3258,11 @@ declare_lint! { /// See the [Checking Conditional Configurations][check-cfg] section for more /// details. /// + /// See the [Cargo Specifics][unexpected_cfgs_lint_config] section for configuring this lint in + /// `Cargo.toml`. + /// /// [check-cfg]: https://doc.rust-lang.org/nightly/rustc/check-cfg.html + /// [unexpected_cfgs_lint_config]: https://doc.rust-lang.org/nightly/rustc/check-cfg/cargo-specifics.html#check-cfg-in-lintsrust-table pub UNEXPECTED_CFGS, Warn, "detects unexpected names and values in `#[cfg]` conditions", @@ -4195,6 +4200,59 @@ declare_lint! { report_in_external_macro } +declare_lint! { + /// The `dependency_on_unit_never_type_fallback` lint detects cases where code compiles with + /// [never type fallback] being [`()`], but will stop compiling with fallback being [`!`]. + /// + /// [never type fallback]: https://doc.rust-lang.org/nightly/core/primitive.never.html#never-type-fallback + /// [`!`]: https://doc.rust-lang.org/core/primitive.never.html + /// [`()`]: https://doc.rust-lang.org/core/primitive.unit.html + /// + /// ### Example + /// + /// ```rust,compile_fail + /// #![deny(dependency_on_unit_never_type_fallback)] + /// fn main() { + /// if true { + /// // return has type `!` which, is some cases, causes never type fallback + /// return + /// } else { + /// // the type produced by this call is not specified explicitly, + /// // so it will be inferred from the previous branch + /// Default::default() + /// }; + /// // depending on the fallback, this may compile (because `()` implements `Default`), + /// // or it may not (because `!` does not implement `Default`) + /// } + /// ``` + /// + /// {{produces}} + /// + /// ### Explanation + /// + /// Due to historic reasons never type fallback was `()`, meaning that `!` got spontaneously + /// coerced to `()`. There are plans to change that, but they may make the code such as above + /// not compile. Instead of depending on the fallback, you should specify the type explicitly: + /// ``` + /// if true { + /// return + /// } else { + /// // type is explicitly specified, fallback can't hurt us no more + /// <() as Default>::default() + /// }; + /// ``` + /// + /// See [Tracking Issue for making `!` fall back to `!`](https://github.com/rust-lang/rust/issues/123748). + pub DEPENDENCY_ON_UNIT_NEVER_TYPE_FALLBACK, + Warn, + "never type fallback affecting unsafe function calls", + @future_incompatible = FutureIncompatibleInfo { + reason: FutureIncompatibilityReason::FutureReleaseErrorDontReportInDeps, + reference: "issue #123748 ", + }; + report_in_external_macro +} + declare_lint! { /// The `byte_slice_in_packed_struct_with_derive` lint detects cases where a byte slice field /// (`[u8]`) or string slice field (`str`) is used in a `packed` struct that derives one or diff --git a/compiler/rustc_metadata/src/rmeta/decoder.rs b/compiler/rustc_metadata/src/rmeta/decoder.rs index 19bb943e6bccd..ea7037740f17e 100644 --- a/compiler/rustc_metadata/src/rmeta/decoder.rs +++ b/compiler/rustc_metadata/src/rmeta/decoder.rs @@ -539,7 +539,7 @@ impl<'a, 'tcx> SpanDecoder for DecodeContext<'a, 'tcx> { } else { SpanData::decode(self) }; - Span::new(data.lo, data.hi, data.ctxt, data.parent) + data.span() } fn decode_symbol(&mut self) -> Symbol { @@ -669,7 +669,7 @@ impl<'a, 'tcx> Decodable> for SpanData { let lo = lo + source_file.translated_source_file.start_pos; let hi = hi + source_file.translated_source_file.start_pos; - // Do not try to decode parent for foreign spans. + // Do not try to decode parent for foreign spans (it wasn't encoded in the first place). SpanData { lo, hi, ctxt, parent: None } } } diff --git a/compiler/rustc_metadata/src/rmeta/encoder.rs b/compiler/rustc_metadata/src/rmeta/encoder.rs index 89da0df8575e3..d7840a2d516f5 100644 --- a/compiler/rustc_metadata/src/rmeta/encoder.rs +++ b/compiler/rustc_metadata/src/rmeta/encoder.rs @@ -2020,7 +2020,7 @@ impl<'a, 'tcx> EncodeContext<'a, 'tcx> { // if this is an impl of `CoerceUnsized`, create its // "unsized info", else just store None - if Some(trait_ref.def_id) == tcx.lang_items().coerce_unsized_trait() { + if tcx.is_lang_item(trait_ref.def_id, LangItem::CoerceUnsized) { let coerce_unsized_info = tcx.coerce_unsized_info(def_id).unwrap(); record!(self.tables.coerce_unsized_info[def_id] <- coerce_unsized_info); } diff --git a/compiler/rustc_middle/src/middle/lang_items.rs b/compiler/rustc_middle/src/middle/lang_items.rs index 4fd1c1f4a1b7d..e76d7af6e4aba 100644 --- a/compiler/rustc_middle/src/middle/lang_items.rs +++ b/compiler/rustc_middle/src/middle/lang_items.rs @@ -23,6 +23,10 @@ impl<'tcx> TyCtxt<'tcx> { }) } + pub fn is_lang_item(self, def_id: DefId, lang_item: LangItem) -> bool { + self.lang_items().get(lang_item) == Some(def_id) + } + /// Given a [`DefId`] of one of the [`Fn`], [`FnMut`] or [`FnOnce`] traits, /// returns a corresponding [`ty::ClosureKind`]. /// For any other [`DefId`] return `None`. diff --git a/compiler/rustc_middle/src/mir/interpret/value.rs b/compiler/rustc_middle/src/mir/interpret/value.rs index 70e5ad0635ba1..a84a4c583edd2 100644 --- a/compiler/rustc_middle/src/mir/interpret/value.rs +++ b/compiler/rustc_middle/src/mir/interpret/value.rs @@ -69,6 +69,13 @@ impl fmt::LowerHex for Scalar { } } +impl From for Scalar { + #[inline(always)] + fn from(f: Half) -> Self { + Scalar::from_f16(f) + } +} + impl From for Scalar { #[inline(always)] fn from(f: Single) -> Self { @@ -83,6 +90,13 @@ impl From for Scalar { } } +impl From for Scalar { + #[inline(always)] + fn from(f: Quad) -> Self { + Scalar::from_f128(f) + } +} + impl From for Scalar { #[inline(always)] fn from(ptr: ScalarInt) -> Self { diff --git a/compiler/rustc_middle/src/mir/pretty.rs b/compiler/rustc_middle/src/mir/pretty.rs index b64b7e2b1dc6f..f1c3cb698969d 100644 --- a/compiler/rustc_middle/src/mir/pretty.rs +++ b/compiler/rustc_middle/src/mir/pretty.rs @@ -1287,7 +1287,7 @@ fn use_verbose(ty: Ty<'_>, fn_def: bool) -> bool { } impl<'tcx> Visitor<'tcx> for ExtraComments<'tcx> { - fn visit_constant(&mut self, constant: &ConstOperand<'tcx>, _location: Location) { + fn visit_const_operand(&mut self, constant: &ConstOperand<'tcx>, _location: Location) { let ConstOperand { span, user_ty, const_ } = constant; if use_verbose(const_.ty(), true) { self.push("mir::ConstOperand"); @@ -1415,7 +1415,7 @@ pub fn write_allocations<'tcx>( struct CollectAllocIds(BTreeSet); impl<'tcx> Visitor<'tcx> for CollectAllocIds { - fn visit_constant(&mut self, c: &ConstOperand<'tcx>, _: Location) { + fn visit_const_operand(&mut self, c: &ConstOperand<'tcx>, _: Location) { match c.const_ { Const::Ty(_, _) | Const::Unevaluated(..) => {} Const::Val(val, _) => { diff --git a/compiler/rustc_middle/src/mir/syntax.rs b/compiler/rustc_middle/src/mir/syntax.rs index ebe77a1abfd8b..3edc5fe36cd2f 100644 --- a/compiler/rustc_middle/src/mir/syntax.rs +++ b/compiler/rustc_middle/src/mir/syntax.rs @@ -1490,7 +1490,8 @@ pub enum BinOp { BitOr, /// The `<<` operator (shift left) /// - /// The offset is (uniquely) determined as follows: + /// The offset is given by `RHS.rem_euclid(LHS::BITS)`. + /// In other words, it is (uniquely) determined as follows: /// - it is "equal modulo LHS::BITS" to the RHS /// - it is in the range `0..LHS::BITS` Shl, @@ -1498,7 +1499,8 @@ pub enum BinOp { ShlUnchecked, /// The `>>` operator (shift right) /// - /// The offset is (uniquely) determined as follows: + /// The offset is given by `RHS.rem_euclid(LHS::BITS)`. + /// In other words, it is (uniquely) determined as follows: /// - it is "equal modulo LHS::BITS" to the RHS /// - it is in the range `0..LHS::BITS` /// diff --git a/compiler/rustc_middle/src/mir/visit.rs b/compiler/rustc_middle/src/mir/visit.rs index f553b417294a4..10609e56f2c47 100644 --- a/compiler/rustc_middle/src/mir/visit.rs +++ b/compiler/rustc_middle/src/mir/visit.rs @@ -184,12 +184,12 @@ macro_rules! make_mir_visitor { /// This is called for every constant in the MIR body and every `required_consts` /// (i.e., including consts that have been dead-code-eliminated). - fn visit_constant( + fn visit_const_operand( &mut self, constant: & $($mutability)? ConstOperand<'tcx>, location: Location, ) { - self.super_constant(constant, location); + self.super_const_operand(constant, location); } fn visit_ty_const( @@ -597,7 +597,7 @@ macro_rules! make_mir_visitor { } InlineAsmOperand::Const { value } | InlineAsmOperand::SymFn { value } => { - self.visit_constant(value, location); + self.visit_const_operand(value, location); } InlineAsmOperand::Out { place: None, .. } | InlineAsmOperand::SymStatic { def_id: _ } @@ -788,7 +788,7 @@ macro_rules! make_mir_visitor { ); } Operand::Constant(constant) => { - self.visit_constant(constant, location); + self.visit_const_operand(constant, location); } } } @@ -867,7 +867,7 @@ macro_rules! make_mir_visitor { } } match value { - VarDebugInfoContents::Const(c) => self.visit_constant(c, location), + VarDebugInfoContents::Const(c) => self.visit_const_operand(c, location), VarDebugInfoContents::Place(place) => self.visit_place( place, @@ -882,7 +882,7 @@ macro_rules! make_mir_visitor { _scope: $(& $mutability)? SourceScope ) {} - fn super_constant( + fn super_const_operand( &mut self, constant: & $($mutability)? ConstOperand<'tcx>, location: Location @@ -1057,7 +1057,7 @@ macro_rules! super_body { for const_ in &$($mutability)? $body.required_consts { let location = Location::START; - $self.visit_constant(const_, location); + $self.visit_const_operand(const_, location); } } } diff --git a/compiler/rustc_middle/src/query/keys.rs b/compiler/rustc_middle/src/query/keys.rs index faa137019cb92..5452e1dff3ef3 100644 --- a/compiler/rustc_middle/src/query/keys.rs +++ b/compiler/rustc_middle/src/query/keys.rs @@ -360,6 +360,14 @@ impl<'tcx> Key for (ty::ParamEnv<'tcx>, ty::TraitRef<'tcx>) { } } +impl<'tcx> Key for ty::TraitRef<'tcx> { + type Cache = DefaultCache; + + fn default_span(&self, tcx: TyCtxt<'_>) -> Span { + tcx.def_span(self.def_id) + } +} + impl<'tcx> Key for ty::PolyTraitRef<'tcx> { type Cache = DefaultCache; diff --git a/compiler/rustc_middle/src/query/mod.rs b/compiler/rustc_middle/src/query/mod.rs index a8bf735fa5a93..8ba930f493e2c 100644 --- a/compiler/rustc_middle/src/query/mod.rs +++ b/compiler/rustc_middle/src/query/mod.rs @@ -46,6 +46,7 @@ use crate::traits::{ }; use crate::ty::fast_reject::SimplifiedType; use crate::ty::layout::ValidityRequirement; +use crate::ty::print::PrintTraitRefExt; use crate::ty::util::AlwaysRequiresDrop; use crate::ty::TyCtxtFeed; use crate::ty::{ @@ -1271,7 +1272,11 @@ rustc_queries! { desc { |tcx| "finding all vtable entries for trait `{}`", tcx.def_path_str(key.def_id()) } } - query vtable_trait_upcasting_coercion_new_vptr_slot(key: (Ty<'tcx>, Ty<'tcx>)) -> Option { + query first_method_vtable_slot(key: ty::TraitRef<'tcx>) -> usize { + desc { |tcx| "finding the slot within the vtable of `{}` for the implementation of `{}`", key.self_ty(), key.print_only_trait_name() } + } + + query supertrait_vtable_slot(key: (Ty<'tcx>, Ty<'tcx>)) -> Option { desc { |tcx| "finding the slot within vtable for trait object `{}` vtable ptr during trait upcasting coercion from `{}` vtable", key.1, key.0 } } diff --git a/compiler/rustc_middle/src/traits/query.rs b/compiler/rustc_middle/src/traits/query.rs index 50b6c77e1b29d..4fad721ce9847 100644 --- a/compiler/rustc_middle/src/traits/query.rs +++ b/compiler/rustc_middle/src/traits/query.rs @@ -156,7 +156,7 @@ pub struct CandidateStep<'tcx> { #[derive(Copy, Clone, Debug, HashStable)] pub struct MethodAutoderefStepsResult<'tcx> { - /// The valid autoderef steps that could be find. + /// The valid autoderef steps that could be found. pub steps: &'tcx [CandidateStep<'tcx>], /// If Some(T), a type autoderef reported an error on. pub opt_bad_ty: Option<&'tcx MethodAutoderefBadTy<'tcx>>, diff --git a/compiler/rustc_middle/src/traits/util.rs b/compiler/rustc_middle/src/traits/util.rs index 707e076921bce..adbb6cf2ddc94 100644 --- a/compiler/rustc_middle/src/traits/util.rs +++ b/compiler/rustc_middle/src/traits/util.rs @@ -37,7 +37,7 @@ impl<'tcx> Elaborator<'tcx> { let super_predicates = self.tcx.super_predicates_of(trait_ref.def_id()).predicates.iter().filter_map( |&(pred, _)| { - let clause = pred.instantiate_supertrait(self.tcx, &trait_ref); + let clause = pred.instantiate_supertrait(self.tcx, trait_ref); self.visited.insert(clause).then_some(clause) }, ); diff --git a/compiler/rustc_middle/src/ty/adt.rs b/compiler/rustc_middle/src/ty/adt.rs index 886dbd317afa3..684b3233cfd61 100644 --- a/compiler/rustc_middle/src/ty/adt.rs +++ b/compiler/rustc_middle/src/ty/adt.rs @@ -8,9 +8,9 @@ use rustc_data_structures::intern::Interned; use rustc_data_structures::stable_hasher::HashingControls; use rustc_data_structures::stable_hasher::{HashStable, StableHasher}; use rustc_errors::ErrorGuaranteed; -use rustc_hir as hir; use rustc_hir::def::{CtorKind, DefKind, Res}; use rustc_hir::def_id::DefId; +use rustc_hir::{self as hir, LangItem}; use rustc_index::{IndexSlice, IndexVec}; use rustc_macros::{HashStable, TyDecodable, TyEncodable}; use rustc_query_system::ich::StableHashingContext; @@ -204,6 +204,23 @@ impl<'tcx> rustc_type_ir::inherent::AdtDef> for AdtDef<'tcx> { fn def_id(self) -> DefId { self.did() } + + fn is_phantom_data(self) -> bool { + self.is_phantom_data() + } + + fn all_field_tys( + self, + tcx: TyCtxt<'tcx>, + ) -> ty::EarlyBinder<'tcx, impl Iterator>> { + ty::EarlyBinder::bind( + self.all_fields().map(move |field| tcx.type_of(field.did).skip_binder()), + ) + } + + fn sized_constraint(self, tcx: TyCtxt<'tcx>) -> Option>> { + self.sized_constraint(tcx) + } } #[derive(Copy, Clone, Debug, Eq, PartialEq, HashStable, TyEncodable, TyDecodable)] @@ -257,16 +274,16 @@ impl AdtDefData { if tcx.has_attr(did, sym::fundamental) { flags |= AdtFlags::IS_FUNDAMENTAL; } - if Some(did) == tcx.lang_items().phantom_data() { + if tcx.is_lang_item(did, LangItem::PhantomData) { flags |= AdtFlags::IS_PHANTOM_DATA; } - if Some(did) == tcx.lang_items().owned_box() { + if tcx.is_lang_item(did, LangItem::OwnedBox) { flags |= AdtFlags::IS_BOX; } - if Some(did) == tcx.lang_items().manually_drop() { + if tcx.is_lang_item(did, LangItem::ManuallyDrop) { flags |= AdtFlags::IS_MANUALLY_DROP; } - if Some(did) == tcx.lang_items().unsafe_cell_type() { + if tcx.is_lang_item(did, LangItem::UnsafeCell) { flags |= AdtFlags::IS_UNSAFE_CELL; } if is_anonymous { diff --git a/compiler/rustc_middle/src/ty/context.rs b/compiler/rustc_middle/src/ty/context.rs index 65d744239a6ab..3651c990c9792 100644 --- a/compiler/rustc_middle/src/ty/context.rs +++ b/compiler/rustc_middle/src/ty/context.rs @@ -70,9 +70,9 @@ use rustc_span::{Span, DUMMY_SP}; use rustc_target::abi::{FieldIdx, Layout, LayoutS, TargetDataLayout, VariantIdx}; use rustc_target::spec::abi; use rustc_type_ir::fold::TypeFoldable; +use rustc_type_ir::lang_items::TraitSolverLangItem; use rustc_type_ir::TyKind::*; -use rustc_type_ir::WithCachedTypeInfo; -use rustc_type_ir::{CollectAndApply, Interner, TypeFlags}; +use rustc_type_ir::{CollectAndApply, Interner, TypeFlags, WithCachedTypeInfo}; use tracing::{debug, instrument}; use std::assert_matches::assert_matches; @@ -154,7 +154,7 @@ impl<'tcx> Interner for TyCtxt<'tcx> { type VariancesOf = &'tcx [ty::Variance]; - fn variances_of(self, def_id: Self::DefId) -> Self::VariancesOf { + fn variances_of(self, def_id: DefId) -> Self::VariancesOf { self.variances_of(def_id) } @@ -198,7 +198,7 @@ impl<'tcx> Interner for TyCtxt<'tcx> { fn trait_ref_and_own_args_for_alias( self, - def_id: Self::DefId, + def_id: DefId, args: Self::GenericArgs, ) -> (rustc_type_ir::TraitRef, Self::GenericArgsSlice) { assert_matches!(self.def_kind(def_id), DefKind::AssocTy | DefKind::AssocConst); @@ -246,7 +246,7 @@ impl<'tcx> Interner for TyCtxt<'tcx> { self.mk_type_list_from_iter(args) } - fn parent(self, def_id: Self::DefId) -> Self::DefId { + fn parent(self, def_id: DefId) -> DefId { self.parent(def_id) } @@ -259,15 +259,85 @@ impl<'tcx> Interner for TyCtxt<'tcx> { fn features(self) -> Self::Features { self.features() } + + fn bound_coroutine_hidden_types( + self, + def_id: DefId, + ) -> impl IntoIterator>>> { + self.bound_coroutine_hidden_types(def_id) + } + + fn fn_sig(self, def_id: DefId) -> ty::EarlyBinder<'tcx, ty::PolyFnSig<'tcx>> { + self.fn_sig(def_id) + } + + fn coroutine_movability(self, def_id: DefId) -> rustc_ast::Movability { + self.coroutine_movability(def_id) + } + + fn coroutine_for_closure(self, def_id: DefId) -> DefId { + self.coroutine_for_closure(def_id) + } + + fn generics_require_sized_self(self, def_id: DefId) -> bool { + self.generics_require_sized_self(def_id) + } + + fn item_bounds( + self, + def_id: DefId, + ) -> ty::EarlyBinder<'tcx, impl IntoIterator>> { + self.item_bounds(def_id).map_bound(IntoIterator::into_iter) + } + + fn super_predicates_of( + self, + def_id: DefId, + ) -> ty::EarlyBinder<'tcx, impl IntoIterator>> { + ty::EarlyBinder::bind( + self.super_predicates_of(def_id).instantiate_identity(self).predicates.into_iter(), + ) + } + + fn has_target_features(self, def_id: DefId) -> bool { + !self.codegen_fn_attrs(def_id).target_features.is_empty() + } + + fn require_lang_item(self, lang_item: TraitSolverLangItem) -> DefId { + self.require_lang_item( + match lang_item { + TraitSolverLangItem::Future => hir::LangItem::Future, + TraitSolverLangItem::FutureOutput => hir::LangItem::FutureOutput, + TraitSolverLangItem::AsyncFnKindHelper => hir::LangItem::AsyncFnKindHelper, + TraitSolverLangItem::AsyncFnKindUpvars => hir::LangItem::AsyncFnKindUpvars, + }, + None, + ) + } + + fn associated_type_def_ids(self, def_id: DefId) -> impl IntoIterator { + self.associated_items(def_id) + .in_definition_order() + .filter(|assoc_item| matches!(assoc_item.kind, ty::AssocKind::Type)) + .map(|assoc_item| assoc_item.def_id) + } } impl<'tcx> rustc_type_ir::inherent::Abi> for abi::Abi { + fn rust() -> Self { + abi::Abi::Rust + } + fn is_rust(self) -> bool { matches!(self, abi::Abi::Rust) } } impl<'tcx> rustc_type_ir::inherent::Safety> for hir::Safety { + fn safe() -> Self { + hir::Safety::Safe + } + fn is_safe(self) -> bool { matches!(self, hir::Safety::Safe) } @@ -281,6 +351,10 @@ impl<'tcx> rustc_type_ir::inherent::Features> for &'tcx rustc_featu fn generic_const_exprs(self) -> bool { self.generic_const_exprs } + + fn coroutine_clone(self) -> bool { + self.coroutine_clone + } } type InternedSet<'tcx, T> = ShardedHashMap, ()>; diff --git a/compiler/rustc_middle/src/ty/generic_args.rs b/compiler/rustc_middle/src/ty/generic_args.rs index 7fff3d0132493..54c88e48614b0 100644 --- a/compiler/rustc_middle/src/ty/generic_args.rs +++ b/compiler/rustc_middle/src/ty/generic_args.rs @@ -41,6 +41,8 @@ pub struct GenericArg<'tcx> { marker: PhantomData<(Ty<'tcx>, ty::Region<'tcx>, ty::Const<'tcx>)>, } +impl<'tcx> rustc_type_ir::inherent::GenericArg> for GenericArg<'tcx> {} + impl<'tcx> rustc_type_ir::inherent::GenericArgs> for ty::GenericArgsRef<'tcx> { fn type_at(self, i: usize) -> Ty<'tcx> { self.type_at(i) diff --git a/compiler/rustc_middle/src/ty/instance.rs b/compiler/rustc_middle/src/ty/instance.rs index a887047f62f21..bdf90cbb25bb3 100644 --- a/compiler/rustc_middle/src/ty/instance.rs +++ b/compiler/rustc_middle/src/ty/instance.rs @@ -699,26 +699,25 @@ impl<'tcx> Instance<'tcx> { }; let coroutine_kind = tcx.coroutine_kind(coroutine_def_id).unwrap(); - let lang_items = tcx.lang_items(); - let coroutine_callable_item = if Some(trait_id) == lang_items.future_trait() { + let coroutine_callable_item = if tcx.is_lang_item(trait_id, LangItem::Future) { assert_matches!( coroutine_kind, hir::CoroutineKind::Desugared(hir::CoroutineDesugaring::Async, _) ); hir::LangItem::FuturePoll - } else if Some(trait_id) == lang_items.iterator_trait() { + } else if tcx.is_lang_item(trait_id, LangItem::Iterator) { assert_matches!( coroutine_kind, hir::CoroutineKind::Desugared(hir::CoroutineDesugaring::Gen, _) ); hir::LangItem::IteratorNext - } else if Some(trait_id) == lang_items.async_iterator_trait() { + } else if tcx.is_lang_item(trait_id, LangItem::AsyncIterator) { assert_matches!( coroutine_kind, hir::CoroutineKind::Desugared(hir::CoroutineDesugaring::AsyncGen, _) ); hir::LangItem::AsyncIteratorPollNext - } else if Some(trait_id) == lang_items.coroutine_trait() { + } else if tcx.is_lang_item(trait_id, LangItem::Coroutine) { assert_matches!(coroutine_kind, hir::CoroutineKind::Coroutine(_)); hir::LangItem::CoroutineResume } else { diff --git a/compiler/rustc_middle/src/ty/layout.rs b/compiler/rustc_middle/src/ty/layout.rs index 56945bf6be4f8..02c0d41f61908 100644 --- a/compiler/rustc_middle/src/ty/layout.rs +++ b/compiler/rustc_middle/src/ty/layout.rs @@ -9,6 +9,7 @@ use rustc_errors::{ }; use rustc_hir as hir; use rustc_hir::def_id::DefId; +use rustc_hir::LangItem; use rustc_index::IndexVec; use rustc_macros::{extension, HashStable, TyDecodable, TyEncodable}; use rustc_session::config::OptLevel; @@ -850,7 +851,7 @@ where // and we rely on this layout information to trigger a panic in // `std::mem::uninitialized::<&dyn Trait>()`, for example. if let ty::Adt(def, args) = metadata.kind() - && Some(def.did()) == tcx.lang_items().dyn_metadata() + && tcx.is_lang_item(def.did(), LangItem::DynMetadata) && let ty::Dynamic(data, _, ty::Dyn) = args.type_at(0).kind() { mk_dyn_vtable(data.principal()) @@ -1169,7 +1170,7 @@ pub fn fn_can_unwind(tcx: TyCtxt<'_>, fn_def_id: Option, abi: SpecAbi) -> // This is not part of `codegen_fn_attrs` as it can differ between crates // and therefore cannot be computed in core. if tcx.sess.opts.unstable_opts.panic_in_drop == PanicStrategy::Abort { - if Some(did) == tcx.lang_items().drop_in_place_fn() { + if tcx.is_lang_item(did, LangItem::DropInPlace) { return false; } } diff --git a/compiler/rustc_middle/src/ty/mod.rs b/compiler/rustc_middle/src/ty/mod.rs index 83f8de6b6f93f..5a94a53e175ea 100644 --- a/compiler/rustc_middle/src/ty/mod.rs +++ b/compiler/rustc_middle/src/ty/mod.rs @@ -16,7 +16,6 @@ pub use self::visit::{TypeSuperVisitable, TypeVisitable, TypeVisitableExt, TypeV pub use self::AssocItemContainer::*; pub use self::BorrowKind::*; pub use self::IntVarValue::*; -pub use self::Variance::*; use crate::error::{OpaqueHiddenTypeMismatch, TypeMismatchReason}; use crate::metadata::ModChild; use crate::middle::privacy::EffectiveVisibilities; @@ -488,6 +487,8 @@ pub struct Term<'tcx> { marker: PhantomData<(Ty<'tcx>, Const<'tcx>)>, } +impl<'tcx> rustc_type_ir::inherent::Term> for Term<'tcx> {} + impl<'tcx> rustc_type_ir::inherent::IntoKind for Term<'tcx> { type Kind = TermKind<'tcx>; diff --git a/compiler/rustc_middle/src/ty/predicate.rs b/compiler/rustc_middle/src/ty/predicate.rs index c730f5117c561..ae36f2624ca5f 100644 --- a/compiler/rustc_middle/src/ty/predicate.rs +++ b/compiler/rustc_middle/src/ty/predicate.rs @@ -49,6 +49,18 @@ impl<'tcx> rustc_type_ir::inherent::Predicate> for Predicate<'tcx> fn is_coinductive(self, interner: TyCtxt<'tcx>) -> bool { self.is_coinductive(interner) } + + fn allow_normalization(self) -> bool { + self.allow_normalization() + } +} + +impl<'tcx> rustc_type_ir::inherent::IntoKind for Predicate<'tcx> { + type Kind = ty::Binder<'tcx, ty::PredicateKind<'tcx>>; + + fn kind(self) -> Self::Kind { + self.kind() + } } impl<'tcx> rustc_type_ir::visit::Flags for Predicate<'tcx> { @@ -120,6 +132,7 @@ impl<'tcx> Predicate<'tcx> { /// unsoundly accept some programs. See #91068. #[inline] pub fn allow_normalization(self) -> bool { + // Keep this in sync with the one in `rustc_type_ir::inherent`! match self.kind().skip_binder() { PredicateKind::Clause(ClauseKind::WellFormed(_)) | PredicateKind::AliasRelate(..) @@ -313,7 +326,7 @@ impl<'tcx> Clause<'tcx> { pub fn instantiate_supertrait( self, tcx: TyCtxt<'tcx>, - trait_ref: &ty::PolyTraitRef<'tcx>, + trait_ref: ty::PolyTraitRef<'tcx>, ) -> Clause<'tcx> { // The interaction between HRTB and supertraits is not entirely // obvious. Let me walk you (and myself) through an example. diff --git a/compiler/rustc_middle/src/ty/print/pretty.rs b/compiler/rustc_middle/src/ty/print/pretty.rs index 662eafd0ccb65..de1796d480021 100644 --- a/compiler/rustc_middle/src/ty/print/pretty.rs +++ b/compiler/rustc_middle/src/ty/print/pretty.rs @@ -999,7 +999,7 @@ pub trait PrettyPrinter<'tcx>: Printer<'tcx> + fmt::Write { let trait_ref = bound_predicate.rebind(pred.trait_ref); // Don't print `+ Sized`, but rather `+ ?Sized` if absent. - if Some(trait_ref.def_id()) == tcx.lang_items().sized_trait() { + if tcx.is_lang_item(trait_ref.def_id(), LangItem::Sized) { match pred.polarity { ty::PredicatePolarity::Positive => { has_sized_bound = true; @@ -1254,14 +1254,14 @@ pub trait PrettyPrinter<'tcx>: Printer<'tcx> + fmt::Write { } entry.has_fn_once = true; return; - } else if Some(trait_def_id) == self.tcx().lang_items().fn_mut_trait() { + } else if self.tcx().is_lang_item(trait_def_id, LangItem::FnMut) { let super_trait_ref = supertraits_for_pretty_printing(self.tcx(), trait_ref) .find(|super_trait_ref| super_trait_ref.def_id() == fn_once_trait) .unwrap(); fn_traits.entry(super_trait_ref).or_default().fn_mut_trait_ref = Some(trait_ref); return; - } else if Some(trait_def_id) == self.tcx().lang_items().fn_trait() { + } else if self.tcx().is_lang_item(trait_def_id, LangItem::Fn) { let super_trait_ref = supertraits_for_pretty_printing(self.tcx(), trait_ref) .find(|super_trait_ref| super_trait_ref.def_id() == fn_once_trait) .unwrap(); diff --git a/compiler/rustc_middle/src/ty/sty.rs b/compiler/rustc_middle/src/ty/sty.rs index ba9ed0d5b70a6..8308e537e5edf 100644 --- a/compiler/rustc_middle/src/ty/sty.rs +++ b/compiler/rustc_middle/src/ty/sty.rs @@ -786,6 +786,10 @@ impl<'tcx> rustc_type_ir::inherent::Ty> for Ty<'tcx> { tcx.types.bool } + fn new_u8(tcx: TyCtxt<'tcx>) -> Self { + tcx.types.u8 + } + fn new_infer(tcx: TyCtxt<'tcx>, infer: ty::InferTy) -> Self { Ty::new_infer(tcx, infer) } diff --git a/compiler/rustc_middle/src/util/call_kind.rs b/compiler/rustc_middle/src/util/call_kind.rs index a4cbfe867112d..dc1d73684f4f2 100644 --- a/compiler/rustc_middle/src/util/call_kind.rs +++ b/compiler/rustc_middle/src/util/call_kind.rs @@ -117,19 +117,19 @@ pub fn call_kind<'tcx>( kind.unwrap_or_else(|| { // This isn't a 'special' use of `self` debug!(?method_did, ?fn_call_span); - let desugaring = if Some(method_did) == tcx.lang_items().into_iter_fn() + let desugaring = if tcx.is_lang_item(method_did, LangItem::IntoIterIntoIter) && fn_call_span.desugaring_kind() == Some(DesugaringKind::ForLoop) { Some((CallDesugaringKind::ForLoopIntoIter, method_args.type_at(0))) } else if fn_call_span.desugaring_kind() == Some(DesugaringKind::QuestionMark) { - if Some(method_did) == tcx.lang_items().branch_fn() { + if tcx.is_lang_item(method_did, LangItem::TryTraitBranch) { Some((CallDesugaringKind::QuestionBranch, method_args.type_at(0))) - } else if Some(method_did) == tcx.lang_items().from_residual_fn() { + } else if tcx.is_lang_item(method_did, LangItem::TryTraitFromResidual) { Some((CallDesugaringKind::QuestionFromResidual, method_args.type_at(0))) } else { None } - } else if Some(method_did) == tcx.lang_items().from_output_fn() + } else if tcx.is_lang_item(method_did, LangItem::TryTraitFromOutput) && fn_call_span.desugaring_kind() == Some(DesugaringKind::TryBlock) { Some((CallDesugaringKind::TryBlockFromOutput, method_args.type_at(0))) diff --git a/compiler/rustc_middle/src/values.rs b/compiler/rustc_middle/src/values.rs index 4ae475d35d14d..8c323188826b2 100644 --- a/compiler/rustc_middle/src/values.rs +++ b/compiler/rustc_middle/src/values.rs @@ -142,7 +142,7 @@ impl<'tcx> Value> for &[ty::Variance] { && let Some(def_id) = frame.query.def_id { let n = tcx.generics_of(def_id).own_params.len(); - vec![ty::Variance::Bivariant; n].leak() + vec![ty::Bivariant; n].leak() } else { span_bug!( cycle_error.usage.as_ref().unwrap().0, diff --git a/compiler/rustc_mir_build/src/build/expr/as_constant.rs b/compiler/rustc_mir_build/src/build/expr/as_constant.rs index b783eba8c4e18..3b69058d3cb4a 100644 --- a/compiler/rustc_mir_build/src/build/expr/as_constant.rs +++ b/compiler/rustc_mir_build/src/build/expr/as_constant.rs @@ -2,6 +2,7 @@ use crate::build::{parse_float_into_constval, Builder}; use rustc_ast as ast; +use rustc_hir::LangItem; use rustc_middle::mir; use rustc_middle::mir::interpret::{Allocation, LitToConstError, LitToConstInput, Scalar}; use rustc_middle::mir::*; @@ -142,7 +143,7 @@ fn lit_to_mir_constant<'tcx>( let id = tcx.allocate_bytes(data); ConstValue::Scalar(Scalar::from_pointer(id.into(), &tcx)) } - (ast::LitKind::CStr(data, _), ty::Ref(_, inner_ty, _)) if matches!(inner_ty.kind(), ty::Adt(def, _) if Some(def.did()) == tcx.lang_items().c_str()) => + (ast::LitKind::CStr(data, _), ty::Ref(_, inner_ty, _)) if matches!(inner_ty.kind(), ty::Adt(def, _) if tcx.is_lang_item(def.did(), LangItem::CStr)) => { let allocation = Allocation::from_bytes_byte_aligned_immutable(data as &[u8]); let allocation = tcx.mk_const_alloc(allocation); diff --git a/compiler/rustc_mir_build/src/build/matches/mod.rs b/compiler/rustc_mir_build/src/build/matches/mod.rs index 5413878936983..544f27b84e90d 100644 --- a/compiler/rustc_mir_build/src/build/matches/mod.rs +++ b/compiler/rustc_mir_build/src/build/matches/mod.rs @@ -699,7 +699,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { // exactly `T` (i.e., with invariance). The variance field, in // contrast, is intended to be used to relate `T` to the type of // ``. - ty::Variance::Invariant, + ty::Invariant, ), }, ); diff --git a/compiler/rustc_mir_build/src/build/matches/test.rs b/compiler/rustc_mir_build/src/build/matches/test.rs index 2040071e76eb2..11d3e2a8180f5 100644 --- a/compiler/rustc_mir_build/src/build/matches/test.rs +++ b/compiler/rustc_mir_build/src/build/matches/test.rs @@ -141,7 +141,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { let success_block = target_block(TestBranch::Success); let fail_block = target_block(TestBranch::Failure); if let ty::Adt(def, _) = ty.kind() - && Some(def.did()) == tcx.lang_items().string() + && tcx.is_lang_item(def.did(), LangItem::String) { if !tcx.features().string_deref_patterns { bug!( diff --git a/compiler/rustc_mir_build/src/thir/constant.rs b/compiler/rustc_mir_build/src/thir/constant.rs index a98e046d4dc02..7b94867114d5a 100644 --- a/compiler/rustc_mir_build/src/thir/constant.rs +++ b/compiler/rustc_mir_build/src/thir/constant.rs @@ -1,4 +1,5 @@ use rustc_ast as ast; +use rustc_hir::LangItem; use rustc_middle::bug; use rustc_middle::mir::interpret::{LitToConstError, LitToConstInput}; use rustc_middle::ty::{self, ParamEnv, ScalarInt, TyCtxt}; @@ -46,7 +47,7 @@ pub(crate) fn lit_to_const<'tcx>( (ast::LitKind::Byte(n), ty::Uint(ty::UintTy::U8)) => { ty::ValTree::from_scalar_int((*n).into()) } - (ast::LitKind::CStr(data, _), ty::Ref(_, inner_ty, _)) if matches!(inner_ty.kind(), ty::Adt(def, _) if Some(def.did()) == tcx.lang_items().c_str()) => + (ast::LitKind::CStr(data, _), ty::Ref(_, inner_ty, _)) if matches!(inner_ty.kind(), ty::Adt(def, _) if tcx.is_lang_item(def.did(), LangItem::CStr)) => { let bytes = data as &[u8]; ty::ValTree::from_raw_bytes(tcx, bytes) diff --git a/compiler/rustc_mir_build/src/thir/cx/block.rs b/compiler/rustc_mir_build/src/thir/cx/block.rs index 54eafdd828ae6..95cd703dbb3c0 100644 --- a/compiler/rustc_mir_build/src/thir/cx/block.rs +++ b/compiler/rustc_mir_build/src/thir/cx/block.rs @@ -92,7 +92,7 @@ impl<'tcx> Cx<'tcx> { kind: PatKind::AscribeUserType { ascription: Ascription { annotation, - variance: ty::Variance::Covariant, + variance: ty::Covariant, }, subpattern: pattern, }, diff --git a/compiler/rustc_mir_build/src/thir/pattern/mod.rs b/compiler/rustc_mir_build/src/thir/pattern/mod.rs index 158ca91fcf138..93db1f618533b 100644 --- a/compiler/rustc_mir_build/src/thir/pattern/mod.rs +++ b/compiler/rustc_mir_build/src/thir/pattern/mod.rs @@ -525,7 +525,7 @@ impl<'a, 'tcx> PatCtxt<'a, 'tcx> { }; kind = PatKind::AscribeUserType { subpattern: Box::new(Pat { span, ty, kind }), - ascription: Ascription { annotation, variance: ty::Variance::Covariant }, + ascription: Ascription { annotation, variance: ty::Covariant }, }; } @@ -612,7 +612,7 @@ impl<'a, 'tcx> PatCtxt<'a, 'tcx> { annotation, // Note that use `Contravariant` here. See the // `variance` field documentation for details. - variance: ty::Variance::Contravariant, + variance: ty::Contravariant, }, }, ty: const_.ty(), diff --git a/compiler/rustc_mir_dataflow/src/elaborate_drops.rs b/compiler/rustc_mir_dataflow/src/elaborate_drops.rs index bdc59e843563b..654020164db8b 100644 --- a/compiler/rustc_mir_dataflow/src/elaborate_drops.rs +++ b/compiler/rustc_mir_dataflow/src/elaborate_drops.rs @@ -454,8 +454,7 @@ where }); } - let skip_contents = - adt.is_union() || Some(adt.did()) == self.tcx().lang_items().manually_drop(); + let skip_contents = adt.is_union() || adt.is_manually_drop(); let contents_drop = if skip_contents { (self.succ, self.unwind) } else { diff --git a/compiler/rustc_mir_transform/src/add_retag.rs b/compiler/rustc_mir_transform/src/add_retag.rs index f880476cec2f2..16977a63c598e 100644 --- a/compiler/rustc_mir_transform/src/add_retag.rs +++ b/compiler/rustc_mir_transform/src/add_retag.rs @@ -4,6 +4,7 @@ //! of MIR building, and only after this pass we think of the program has having the //! normal MIR semantics. +use rustc_hir::LangItem; use rustc_middle::mir::*; use rustc_middle::ty::{self, Ty, TyCtxt}; @@ -27,7 +28,7 @@ fn may_contain_reference<'tcx>(ty: Ty<'tcx>, depth: u32, tcx: TyCtxt<'tcx>) -> b // References and Boxes (`noalias` sources) ty::Ref(..) => true, ty::Adt(..) if ty.is_box() => true, - ty::Adt(adt, _) if Some(adt.did()) == tcx.lang_items().ptr_unique() => true, + ty::Adt(adt, _) if tcx.is_lang_item(adt.did(), LangItem::PtrUnique) => true, // Compound types: recurse ty::Array(ty, _) | ty::Slice(ty) => { // This does not branch so we keep the depth the same. diff --git a/compiler/rustc_mir_transform/src/gvn.rs b/compiler/rustc_mir_transform/src/gvn.rs index 121a3b99a39ee..0f8f28e3462ab 100644 --- a/compiler/rustc_mir_transform/src/gvn.rs +++ b/compiler/rustc_mir_transform/src/gvn.rs @@ -330,8 +330,7 @@ impl<'body, 'tcx> VnState<'body, 'tcx> { let is_sized = !self.feature_unsized_locals || self.local_decls[local].ty.is_sized(self.tcx, self.param_env); if is_sized { - self.rev_locals.ensure_contains_elem(value, SmallVec::new); - self.rev_locals[value].push(local); + self.rev_locals.ensure_contains_elem(value, SmallVec::new).push(local); } } diff --git a/compiler/rustc_mir_transform/src/inline.rs b/compiler/rustc_mir_transform/src/inline.rs index fe2237dd2e97a..2cbe0a01e9ece 100644 --- a/compiler/rustc_mir_transform/src/inline.rs +++ b/compiler/rustc_mir_transform/src/inline.rs @@ -225,13 +225,8 @@ impl<'tcx> Inliner<'tcx> { // Normally, this shouldn't be required, but trait normalization failure can create a // validation ICE. let output_type = callee_body.return_ty(); - if !util::relate_types( - self.tcx, - self.param_env, - ty::Variance::Covariant, - output_type, - destination_ty, - ) { + if !util::relate_types(self.tcx, self.param_env, ty::Covariant, output_type, destination_ty) + { trace!(?output_type, ?destination_ty); return Err("failed to normalize return type"); } @@ -261,13 +256,8 @@ impl<'tcx> Inliner<'tcx> { self_arg_ty.into_iter().chain(arg_tuple_tys).zip(callee_body.args_iter()) { let input_type = callee_body.local_decls[input].ty; - if !util::relate_types( - self.tcx, - self.param_env, - ty::Variance::Covariant, - input_type, - arg_ty, - ) { + if !util::relate_types(self.tcx, self.param_env, ty::Covariant, input_type, arg_ty) + { trace!(?arg_ty, ?input_type); return Err("failed to normalize tuple argument type"); } @@ -276,13 +266,8 @@ impl<'tcx> Inliner<'tcx> { for (arg, input) in args.iter().zip(callee_body.args_iter()) { let input_type = callee_body.local_decls[input].ty; let arg_ty = arg.node.ty(&caller_body.local_decls, self.tcx); - if !util::relate_types( - self.tcx, - self.param_env, - ty::Variance::Covariant, - input_type, - arg_ty, - ) { + if !util::relate_types(self.tcx, self.param_env, ty::Covariant, input_type, arg_ty) + { trace!(?arg_ty, ?input_type); return Err("failed to normalize argument type"); } diff --git a/compiler/rustc_mir_transform/src/known_panics_lint.rs b/compiler/rustc_mir_transform/src/known_panics_lint.rs index 6a20b46e7f9c4..8d6c00bbedbae 100644 --- a/compiler/rustc_mir_transform/src/known_panics_lint.rs +++ b/compiler/rustc_mir_transform/src/known_panics_lint.rs @@ -706,9 +706,9 @@ impl<'tcx> Visitor<'tcx> for ConstPropagator<'_, 'tcx> { self.super_operand(operand, location); } - fn visit_constant(&mut self, constant: &ConstOperand<'tcx>, location: Location) { - trace!("visit_constant: {:?}", constant); - self.super_constant(constant, location); + fn visit_const_operand(&mut self, constant: &ConstOperand<'tcx>, location: Location) { + trace!("visit_const_operand: {:?}", constant); + self.super_const_operand(constant, location); self.eval_constant(constant); } diff --git a/compiler/rustc_mir_transform/src/promote_consts.rs b/compiler/rustc_mir_transform/src/promote_consts.rs index ecd1179ca9959..ecdca8292b438 100644 --- a/compiler/rustc_mir_transform/src/promote_consts.rs +++ b/compiler/rustc_mir_transform/src/promote_consts.rs @@ -956,7 +956,7 @@ impl<'a, 'tcx> MutVisitor<'tcx> for Promoter<'a, 'tcx> { } } - fn visit_constant(&mut self, constant: &mut ConstOperand<'tcx>, _location: Location) { + fn visit_const_operand(&mut self, constant: &mut ConstOperand<'tcx>, _location: Location) { if constant.const_.is_required_const() { self.promoted.required_consts.push(*constant); } diff --git a/compiler/rustc_mir_transform/src/required_consts.rs b/compiler/rustc_mir_transform/src/required_consts.rs index 71ac929d35ebd..00bfb5e66008b 100644 --- a/compiler/rustc_mir_transform/src/required_consts.rs +++ b/compiler/rustc_mir_transform/src/required_consts.rs @@ -12,7 +12,7 @@ impl<'a, 'tcx> RequiredConstsVisitor<'a, 'tcx> { } impl<'tcx> Visitor<'tcx> for RequiredConstsVisitor<'_, 'tcx> { - fn visit_constant(&mut self, constant: &ConstOperand<'tcx>, _: Location) { + fn visit_const_operand(&mut self, constant: &ConstOperand<'tcx>, _: Location) { if constant.const_.is_required_const() { self.required_consts.push(*constant); } diff --git a/compiler/rustc_mir_transform/src/reveal_all.rs b/compiler/rustc_mir_transform/src/reveal_all.rs index 4d2eca578404c..5eaa024f84689 100644 --- a/compiler/rustc_mir_transform/src/reveal_all.rs +++ b/compiler/rustc_mir_transform/src/reveal_all.rs @@ -49,14 +49,14 @@ impl<'tcx> MutVisitor<'tcx> for RevealAllVisitor<'tcx> { } #[inline] - fn visit_constant(&mut self, constant: &mut ConstOperand<'tcx>, location: Location) { + fn visit_const_operand(&mut self, constant: &mut ConstOperand<'tcx>, location: Location) { // We have to use `try_normalize_erasing_regions` here, since it's // possible that we visit impossible-to-satisfy where clauses here, // see #91745 if let Ok(c) = self.tcx.try_normalize_erasing_regions(self.param_env, constant.const_) { constant.const_ = c; } - self.super_constant(constant, location); + self.super_const_operand(constant, location); } #[inline] diff --git a/compiler/rustc_mir_transform/src/shim/async_destructor_ctor.rs b/compiler/rustc_mir_transform/src/shim/async_destructor_ctor.rs index aa9c87d8f80d9..41643f2028516 100644 --- a/compiler/rustc_mir_transform/src/shim/async_destructor_ctor.rs +++ b/compiler/rustc_mir_transform/src/shim/async_destructor_ctor.rs @@ -561,7 +561,7 @@ impl<'tcx> AsyncDestructorCtorShimBuilder<'tcx> { // If projection of Discriminant then compare with `Ty::discriminant_ty` if let ty::Alias(ty::Projection, ty::AliasTy { args, def_id, .. }) = expected_ty.kind() - && Some(*def_id) == self.tcx.lang_items().discriminant_type() + && self.tcx.is_lang_item(*def_id, LangItem::Discriminant) && args.first().unwrap().as_type().unwrap().discriminant_ty(self.tcx) == operand_ty { return; diff --git a/compiler/rustc_mir_transform/src/sroa.rs b/compiler/rustc_mir_transform/src/sroa.rs index f19c34cae7a70..c2108795372f6 100644 --- a/compiler/rustc_mir_transform/src/sroa.rs +++ b/compiler/rustc_mir_transform/src/sroa.rs @@ -1,4 +1,5 @@ use rustc_data_structures::flat_map_in_place::FlatMapInPlace; +use rustc_hir::LangItem; use rustc_index::bit_set::{BitSet, GrowableBitSet}; use rustc_index::IndexVec; use rustc_middle::bug; @@ -70,7 +71,7 @@ fn escaping_locals<'tcx>( // Exclude #[repr(simd)] types so that they are not de-optimized into an array return true; } - if Some(def.did()) == tcx.lang_items().dyn_metadata() { + if tcx.is_lang_item(def.did(), LangItem::DynMetadata) { // codegen wants to see the `DynMetadata`, // not the inner reference-to-opaque-type. return true; diff --git a/compiler/rustc_mir_transform/src/validate.rs b/compiler/rustc_mir_transform/src/validate.rs index 586c125499538..ea23bbc2a38ea 100644 --- a/compiler/rustc_mir_transform/src/validate.rs +++ b/compiler/rustc_mir_transform/src/validate.rs @@ -1,6 +1,7 @@ //! Validates the MIR to ensure that invariants are upheld. use rustc_data_structures::fx::{FxHashMap, FxHashSet}; +use rustc_hir::LangItem; use rustc_index::bit_set::BitSet; use rustc_index::IndexVec; use rustc_infer::traits::Reveal; @@ -689,7 +690,7 @@ impl<'a, 'tcx> Visitor<'tcx> for TypeChecker<'a, 'tcx> { } ty::Adt(adt_def, args) => { // see - if Some(adt_def.did()) == self.tcx.lang_items().dyn_metadata() { + if self.tcx.is_lang_item(adt_def.did(), LangItem::DynMetadata) { self.fail( location, format!( diff --git a/compiler/rustc_monomorphize/src/collector.rs b/compiler/rustc_monomorphize/src/collector.rs index 61680dbfaf52d..04de1654c1a44 100644 --- a/compiler/rustc_monomorphize/src/collector.rs +++ b/compiler/rustc_monomorphize/src/collector.rs @@ -593,7 +593,7 @@ fn check_recursion_limit<'tcx>( let recursion_depth = recursion_depths.get(&def_id).cloned().unwrap_or(0); debug!(" => recursion depth={}", recursion_depth); - let adjusted_recursion_depth = if Some(def_id) == tcx.lang_items().drop_in_place_fn() { + let adjusted_recursion_depth = if tcx.is_lang_item(def_id, LangItem::DropInPlace) { // HACK: drop_in_place creates tight monomorphization loops. Give // it more margin. recursion_depth / 4 @@ -799,7 +799,7 @@ impl<'a, 'tcx> MirVisitor<'tcx> for MirUsedCollector<'a, 'tcx> { /// This does not walk the MIR of the constant as that is not needed for codegen, all we need is /// to ensure that the constant evaluates successfully and walk the result. #[instrument(skip(self), level = "debug")] - fn visit_constant(&mut self, constant: &mir::ConstOperand<'tcx>, location: Location) { + fn visit_const_operand(&mut self, constant: &mir::ConstOperand<'tcx>, location: Location) { // No `super_constant` as we don't care about `visit_ty`/`visit_ty_const`. let Some(val) = self.eval_constant(constant) else { return }; collect_const_value(self.tcx, val, self.used_items); @@ -945,7 +945,7 @@ fn visit_instance_use<'tcx>( // be lowered in codegen to nothing or a call to panic_nounwind. So if we encounter any // of those intrinsics, we need to include a mono item for panic_nounwind, else we may try to // codegen a call to that function without generating code for the function itself. - let def_id = tcx.lang_items().get(LangItem::PanicNounwind).unwrap(); + let def_id = tcx.require_lang_item(LangItem::PanicNounwind, None); let panic_instance = Instance::mono(tcx, def_id); if should_codegen_locally(tcx, panic_instance) { output.push(create_fn_mono_item(tcx, panic_instance, source)); diff --git a/compiler/rustc_monomorphize/src/partitioning.rs b/compiler/rustc_monomorphize/src/partitioning.rs index 336341f4e746d..14b5b22dc648e 100644 --- a/compiler/rustc_monomorphize/src/partitioning.rs +++ b/compiler/rustc_monomorphize/src/partitioning.rs @@ -104,6 +104,7 @@ use rustc_data_structures::unord::{UnordMap, UnordSet}; use rustc_hir::def::DefKind; use rustc_hir::def_id::{DefId, DefIdSet, LOCAL_CRATE}; use rustc_hir::definitions::DefPathDataName; +use rustc_hir::LangItem; use rustc_middle::bug; use rustc_middle::middle::codegen_fn_attrs::CodegenFnAttrFlags; use rustc_middle::middle::exported_symbols::{SymbolExportInfo, SymbolExportLevel}; @@ -813,7 +814,7 @@ fn mono_item_visibility<'tcx>( // from the `main` symbol we'll generate later. // // This may be fixable with a new `InstanceDef` perhaps? Unsure! - if tcx.lang_items().start_fn() == Some(def_id) { + if tcx.is_lang_item(def_id, LangItem::Start) { *can_be_internalized = false; return Visibility::Hidden; } diff --git a/compiler/rustc_monomorphize/src/polymorphize.rs b/compiler/rustc_monomorphize/src/polymorphize.rs index a3ca9e9f9cfe9..c187cb63ee189 100644 --- a/compiler/rustc_monomorphize/src/polymorphize.rs +++ b/compiler/rustc_monomorphize/src/polymorphize.rs @@ -261,7 +261,7 @@ impl<'a, 'tcx> Visitor<'tcx> for MarkUsedGenericParams<'a, 'tcx> { self.super_local_decl(local, local_decl); } - fn visit_constant(&mut self, ct: &mir::ConstOperand<'tcx>, location: Location) { + fn visit_const_operand(&mut self, ct: &mir::ConstOperand<'tcx>, location: Location) { match ct.const_ { mir::Const::Ty(_, c) => { c.visit_with(self); diff --git a/compiler/rustc_passes/src/dead.rs b/compiler/rustc_passes/src/dead.rs index a72fbdb902159..6a74ddc5508a7 100644 --- a/compiler/rustc_passes/src/dead.rs +++ b/compiler/rustc_passes/src/dead.rs @@ -898,7 +898,7 @@ fn create_and_seed_worklist( match tcx.def_kind(id) { DefKind::Impl { .. } => false, DefKind::AssocConst | DefKind::AssocFn => !matches!(tcx.associated_item(id).container, AssocItemContainer::ImplContainer), - DefKind::Struct => struct_all_fields_are_public(tcx, id.to_def_id()), + DefKind::Struct => struct_all_fields_are_public(tcx, id.to_def_id()) || has_allow_dead_code_or_lang_attr(tcx, id).is_some(), _ => true }) .map(|id| (id, ComesFromAllowExpect::No)) diff --git a/compiler/rustc_resolve/src/diagnostics.rs b/compiler/rustc_resolve/src/diagnostics.rs index d1541527cf595..8d470c6c61ef4 100644 --- a/compiler/rustc_resolve/src/diagnostics.rs +++ b/compiler/rustc_resolve/src/diagnostics.rs @@ -2783,33 +2783,65 @@ fn show_candidates( // by iterating through a hash map, so make sure they are ordered: for path_strings in [&mut accessible_path_strings, &mut inaccessible_path_strings] { path_strings.sort_by(|a, b| a.0.cmp(&b.0)); + path_strings.dedup_by(|a, b| a.0 == b.0); let core_path_strings = path_strings.extract_if(|p| p.0.starts_with("core::")).collect::>(); - path_strings.extend(core_path_strings); - path_strings.dedup_by(|a, b| a.0 == b.0); + let std_path_strings = + path_strings.extract_if(|p| p.0.starts_with("std::")).collect::>(); + let foreign_crate_path_strings = + path_strings.extract_if(|p| !p.0.starts_with("crate::")).collect::>(); + + // We list the `crate` local paths first. + // Then we list the `std`/`core` paths. + if std_path_strings.len() == core_path_strings.len() { + // Do not list `core::` paths if we are already listing the `std::` ones. + path_strings.extend(std_path_strings); + } else { + path_strings.extend(std_path_strings); + path_strings.extend(core_path_strings); + } + // List all paths from foreign crates last. + path_strings.extend(foreign_crate_path_strings); } - accessible_path_strings.sort(); if !accessible_path_strings.is_empty() { - let (determiner, kind, name, through) = + let (determiner, kind, s, name, through) = if let [(name, descr, _, _, via_import)] = &accessible_path_strings[..] { ( "this", *descr, + "", format!(" `{name}`"), if *via_import { " through its public re-export" } else { "" }, ) } else { - ("one of these", "items", String::new(), "") + // Get the unique item kinds and if there's only one, we use the right kind name + // instead of the more generic "items". + let mut kinds = accessible_path_strings + .iter() + .map(|(_, descr, _, _, _)| *descr) + .collect::>() + .into_iter(); + let kind = if let Some(kind) = kinds.next() + && let None = kinds.next() + { + kind + } else { + "item" + }; + let s = if kind.ends_with('s') { "es" } else { "s" }; + + ("one of these", kind, s, String::new(), "") }; let instead = if let Instead::Yes = instead { " instead" } else { "" }; let mut msg = if let DiagMode::Pattern = mode { format!( - "if you meant to match on {kind}{instead}{name}, use the full path in the pattern", + "if you meant to match on {kind}{s}{instead}{name}, use the full path in the \ + pattern", ) } else { - format!("consider importing {determiner} {kind}{through}{instead}") + format!("consider importing {determiner} {kind}{s}{through}{instead}") }; for note in accessible_path_strings.iter().flat_map(|cand| cand.3.as_ref()) { diff --git a/compiler/rustc_resolve/src/late.rs b/compiler/rustc_resolve/src/late.rs index b0adc3775f667..fa711d932b63b 100644 --- a/compiler/rustc_resolve/src/late.rs +++ b/compiler/rustc_resolve/src/late.rs @@ -3281,17 +3281,19 @@ impl<'a: 'ast, 'b, 'ast, 'tcx> LateResolutionVisitor<'a, 'b, 'ast, 'tcx> { } self.visit_path(&delegation.path, delegation.id); if let Some(body) = &delegation.body { - // `PatBoundCtx` is not necessary in this context - let mut bindings = smallvec![(PatBoundCtx::Product, Default::default())]; - - let span = delegation.path.segments.last().unwrap().ident.span; - self.fresh_binding( - Ident::new(kw::SelfLower, span), - delegation.id, - PatternSource::FnParam, - &mut bindings, - ); - self.visit_block(body); + self.with_rib(ValueNS, RibKind::FnOrCoroutine, |this| { + // `PatBoundCtx` is not necessary in this context + let mut bindings = smallvec![(PatBoundCtx::Product, Default::default())]; + + let span = delegation.path.segments.last().unwrap().ident.span; + this.fresh_binding( + Ident::new(kw::SelfLower, span), + delegation.id, + PatternSource::FnParam, + &mut bindings, + ); + this.visit_block(body); + }); } } diff --git a/compiler/rustc_resolve/src/late/diagnostics.rs b/compiler/rustc_resolve/src/late/diagnostics.rs index 9eeb0da7ed2fd..be24755d4c5a0 100644 --- a/compiler/rustc_resolve/src/late/diagnostics.rs +++ b/compiler/rustc_resolve/src/late/diagnostics.rs @@ -1021,12 +1021,14 @@ impl<'a: 'ast, 'ast, 'tcx> LateResolutionVisitor<'a, '_, 'ast, 'tcx> { }, ); let is_assoc_fn = self.self_type_is_available(); + let self_from_macro = "a `self` parameter, but a macro invocation can only \ + access identifiers it receives from parameters"; if let Some((fn_kind, span)) = &self.diag_metadata.current_function { // The current function has a `self` parameter, but we were unable to resolve // a reference to `self`. This can only happen if the `self` identifier we // are resolving came from a different hygiene context. if fn_kind.decl().inputs.get(0).is_some_and(|p| p.is_self()) { - err.span_label(*span, "this function has a `self` parameter, but a macro invocation can only access identifiers it receives from parameters"); + err.span_label(*span, format!("this function has {self_from_macro}")); } else { let doesnt = if is_assoc_fn { let (span, sugg) = fn_kind @@ -1068,14 +1070,18 @@ impl<'a: 'ast, 'ast, 'tcx> LateResolutionVisitor<'a, '_, 'ast, 'tcx> { } } } else if let Some(item_kind) = self.diag_metadata.current_item { - err.span_label( - item_kind.ident.span, - format!( - "`self` not allowed in {} {}", - item_kind.kind.article(), - item_kind.kind.descr() - ), - ); + if matches!(item_kind.kind, ItemKind::Delegation(..)) { + err.span_label(item_kind.span, format!("delegation supports {self_from_macro}")); + } else { + err.span_label( + item_kind.ident.span, + format!( + "`self` not allowed in {} {}", + item_kind.kind.article(), + item_kind.kind.descr() + ), + ); + } } true } diff --git a/compiler/rustc_sanitizers/src/cfi/typeid/itanium_cxx_abi/transform.rs b/compiler/rustc_sanitizers/src/cfi/typeid/itanium_cxx_abi/transform.rs index 2fbfb93150e7a..2cb0c06e3361b 100644 --- a/compiler/rustc_sanitizers/src/cfi/typeid/itanium_cxx_abi/transform.rs +++ b/compiler/rustc_sanitizers/src/cfi/typeid/itanium_cxx_abi/transform.rs @@ -289,7 +289,7 @@ pub fn transform_instance<'tcx>( options: TransformTyOptions, ) -> Instance<'tcx> { if (matches!(instance.def, ty::InstanceDef::Virtual(..)) - && Some(instance.def_id()) == tcx.lang_items().drop_in_place_fn()) + && tcx.is_lang_item(instance.def_id(), LangItem::DropInPlace)) || matches!(instance.def, ty::InstanceDef::DropGlue(..)) { // Adjust the type ids of DropGlues diff --git a/compiler/rustc_smir/src/rustc_smir/builder.rs b/compiler/rustc_smir/src/rustc_smir/builder.rs index 221224eed0170..577373cbc958f 100644 --- a/compiler/rustc_smir/src/rustc_smir/builder.rs +++ b/compiler/rustc_smir/src/rustc_smir/builder.rs @@ -52,7 +52,11 @@ impl<'tcx> BodyBuilder<'tcx> { } impl<'tcx> MutVisitor<'tcx> for BodyBuilder<'tcx> { - fn visit_constant(&mut self, constant: &mut mir::ConstOperand<'tcx>, location: mir::Location) { + fn visit_const_operand( + &mut self, + constant: &mut mir::ConstOperand<'tcx>, + location: mir::Location, + ) { let const_ = constant.const_; let val = match const_.eval(self.tcx, ty::ParamEnv::reveal_all(), constant.span) { Ok(v) => v, @@ -63,7 +67,7 @@ impl<'tcx> MutVisitor<'tcx> for BodyBuilder<'tcx> { }; let ty = constant.ty(); constant.const_ = mir::Const::Val(val, ty); - self.super_constant(constant, location); + self.super_const_operand(constant, location); } fn tcx(&self) -> TyCtxt<'tcx> { diff --git a/compiler/rustc_smir/src/rustc_smir/context.rs b/compiler/rustc_smir/src/rustc_smir/context.rs index a8688c88601c5..4348bc31bf9e0 100644 --- a/compiler/rustc_smir/src/rustc_smir/context.rs +++ b/compiler/rustc_smir/src/rustc_smir/context.rs @@ -6,6 +6,7 @@ #![allow(rustc::usage_of_qualified_ty)] use rustc_abi::HasDataLayout; +use rustc_hir::LangItem; use rustc_middle::ty::layout::{ FnAbiOf, FnAbiOfHelpers, HasParamEnv, HasTyCtxt, LayoutOf, LayoutOfHelpers, }; @@ -63,9 +64,10 @@ impl<'tcx> Context for TablesWrapper<'tcx> { } fn has_body(&self, def: DefId) -> bool { - let tables = self.0.borrow(); - let def_id = tables[def]; - tables.tcx.is_mir_available(def_id) + let mut tables = self.0.borrow_mut(); + let tcx = tables.tcx; + let def_id = def.internal(&mut *tables, tcx); + tables.item_has_body(def_id) } fn foreign_modules(&self, crate_num: CrateNum) -> Vec { @@ -295,7 +297,7 @@ impl<'tcx> Context for TablesWrapper<'tcx> { let mut tables = self.0.borrow_mut(); let tcx = tables.tcx; let def_id = def.0.internal(&mut *tables, tcx); - tables.tcx.lang_items().c_str() == Some(def_id) + tables.tcx.is_lang_item(def_id, LangItem::CStr) } fn fn_sig(&self, def: FnDef, args: &GenericArgs) -> PolyFnSig { @@ -322,13 +324,6 @@ impl<'tcx> Context for TablesWrapper<'tcx> { tcx.intrinsic(def_id).unwrap().name.to_string() } - fn intrinsic_must_be_overridden(&self, def: IntrinsicDef) -> bool { - let mut tables = self.0.borrow_mut(); - let tcx = tables.tcx; - let def_id = def.0.internal(&mut *tables, tcx); - tcx.intrinsic_raw(def_id).unwrap().must_be_overridden - } - fn closure_sig(&self, args: &GenericArgs) -> PolyFnSig { let mut tables = self.0.borrow_mut(); let tcx = tables.tcx; @@ -515,7 +510,7 @@ impl<'tcx> Context for TablesWrapper<'tcx> { let mut tables = self.0.borrow_mut(); let instance = tables.instances[def]; tables - .has_body(instance) + .instance_has_body(instance) .then(|| BodyBuilder::new(tables.tcx, instance).build(&mut *tables)) } diff --git a/compiler/rustc_smir/src/rustc_smir/convert/mir.rs b/compiler/rustc_smir/src/rustc_smir/convert/mir.rs index bcacf54baf361..f15b82d0c031f 100644 --- a/compiler/rustc_smir/src/rustc_smir/convert/mir.rs +++ b/compiler/rustc_smir/src/rustc_smir/convert/mir.rs @@ -328,13 +328,13 @@ impl<'tcx> Stable<'tcx> for mir::Operand<'tcx> { } impl<'tcx> Stable<'tcx> for mir::ConstOperand<'tcx> { - type T = stable_mir::mir::Constant; + type T = stable_mir::mir::ConstOperand; fn stable(&self, tables: &mut Tables<'_>) -> Self::T { - stable_mir::mir::Constant { + stable_mir::mir::ConstOperand { span: self.span.stable(tables), user_ty: self.user_ty.map(|u| u.as_usize()).or(None), - literal: self.const_.stable(tables), + const_: self.const_.stable(tables), } } } diff --git a/compiler/rustc_smir/src/rustc_smir/convert/ty.rs b/compiler/rustc_smir/src/rustc_smir/convert/ty.rs index 73bc87dc9abf9..e3cd7187e7731 100644 --- a/compiler/rustc_smir/src/rustc_smir/convert/ty.rs +++ b/compiler/rustc_smir/src/rustc_smir/convert/ty.rs @@ -866,10 +866,10 @@ impl<'tcx> Stable<'tcx> for ty::Variance { type T = stable_mir::mir::Variance; fn stable(&self, _: &mut Tables<'_>) -> Self::T { match self { - ty::Variance::Bivariant => stable_mir::mir::Variance::Bivariant, - ty::Variance::Contravariant => stable_mir::mir::Variance::Contravariant, - ty::Variance::Covariant => stable_mir::mir::Variance::Covariant, - ty::Variance::Invariant => stable_mir::mir::Variance::Invariant, + ty::Bivariant => stable_mir::mir::Variance::Bivariant, + ty::Contravariant => stable_mir::mir::Variance::Contravariant, + ty::Covariant => stable_mir::mir::Variance::Covariant, + ty::Invariant => stable_mir::mir::Variance::Invariant, } } } diff --git a/compiler/rustc_smir/src/rustc_smir/mod.rs b/compiler/rustc_smir/src/rustc_smir/mod.rs index d13e780332632..89f9adfcfd663 100644 --- a/compiler/rustc_smir/src/rustc_smir/mod.rs +++ b/compiler/rustc_smir/src/rustc_smir/mod.rs @@ -51,9 +51,13 @@ impl<'tcx> Tables<'tcx> { self.mir_consts.create_or_fetch(constant) } - pub(crate) fn has_body(&self, instance: Instance<'tcx>) -> bool { + /// Return whether the instance as a body available. + /// + /// Items and intrinsics may have a body available from its definition. + /// Shims body may be generated depending on their type. + pub(crate) fn instance_has_body(&self, instance: Instance<'tcx>) -> bool { let def_id = instance.def_id(); - self.tcx.is_mir_available(def_id) + self.item_has_body(def_id) || !matches!( instance.def, ty::InstanceDef::Virtual(..) @@ -61,6 +65,19 @@ impl<'tcx> Tables<'tcx> { | ty::InstanceDef::Item(..) ) } + + /// Return whether the item has a body defined by the user. + /// + /// Note that intrinsics may have a placeholder body that shouldn't be used in practice. + /// In StableMIR, we handle this case as if the body is not available. + pub(crate) fn item_has_body(&self, def_id: DefId) -> bool { + let must_override = if let Some(intrinsic) = self.tcx.intrinsic(def_id) { + intrinsic.must_be_overridden + } else { + false + }; + !must_override && self.tcx.is_mir_available(def_id) + } } /// Build a stable mir crate from a given crate number. diff --git a/compiler/rustc_span/src/hygiene.rs b/compiler/rustc_span/src/hygiene.rs index 00ef17d630c5d..ba0ad9230c860 100644 --- a/compiler/rustc_span/src/hygiene.rs +++ b/compiler/rustc_span/src/hygiene.rs @@ -691,6 +691,11 @@ impl SyntaxContext { SyntaxContext(raw) } + #[inline] + pub(crate) const fn from_u16(raw: u16) -> SyntaxContext { + SyntaxContext(raw as u32) + } + /// Extend a syntax context with a given expansion and transparency. pub fn apply_mark(self, expn_id: ExpnId, transparency: Transparency) -> SyntaxContext { HygieneData::with(|data| data.apply_mark(self, expn_id, transparency)) diff --git a/compiler/rustc_span/src/lib.rs b/compiler/rustc_span/src/lib.rs index 99fcaf917fe9c..99ac973497e1c 100644 --- a/compiler/rustc_span/src/lib.rs +++ b/compiler/rustc_span/src/lib.rs @@ -520,6 +520,7 @@ impl SpanData { pub fn with_hi(&self, hi: BytePos) -> Span { Span::new(self.lo, hi, self.ctxt, self.parent) } + /// Avoid if possible, `Span::map_ctxt` should be preferred. #[inline] fn with_ctxt(&self, ctxt: SyntaxContext) -> Span { Span::new(self.lo, self.hi, ctxt, self.parent) @@ -576,9 +577,8 @@ impl Span { self.data().with_hi(hi) } #[inline] - pub fn with_ctxt(mut self, ctxt: SyntaxContext) -> Span { - self.update_ctxt(|_| ctxt); - self + pub fn with_ctxt(self, ctxt: SyntaxContext) -> Span { + self.map_ctxt(|_| ctxt) } #[inline] pub fn parent(self) -> Option { @@ -967,7 +967,7 @@ impl Span { /// This span, but in a larger context, may switch to the metavariable span if suitable. pub fn with_neighbor(self, neighbor: Span) -> Span { match Span::prepare_to_combine(self, neighbor) { - Ok((this, ..)) => Span::new(this.lo, this.hi, this.ctxt, this.parent), + Ok((this, ..)) => this.span(), Err(_) => self, } } @@ -1059,40 +1059,47 @@ impl Span { } #[inline] - pub fn apply_mark(mut self, expn_id: ExpnId, transparency: Transparency) -> Span { - self.update_ctxt(|ctxt| ctxt.apply_mark(expn_id, transparency)); - self + pub fn apply_mark(self, expn_id: ExpnId, transparency: Transparency) -> Span { + self.map_ctxt(|ctxt| ctxt.apply_mark(expn_id, transparency)) } #[inline] pub fn remove_mark(&mut self) -> ExpnId { - let mut span = self.data(); - let mark = span.ctxt.remove_mark(); - *self = Span::new(span.lo, span.hi, span.ctxt, span.parent); + let mut mark = ExpnId::root(); + *self = self.map_ctxt(|mut ctxt| { + mark = ctxt.remove_mark(); + ctxt + }); mark } #[inline] pub fn adjust(&mut self, expn_id: ExpnId) -> Option { - let mut span = self.data(); - let mark = span.ctxt.adjust(expn_id); - *self = Span::new(span.lo, span.hi, span.ctxt, span.parent); + let mut mark = None; + *self = self.map_ctxt(|mut ctxt| { + mark = ctxt.adjust(expn_id); + ctxt + }); mark } #[inline] pub fn normalize_to_macros_2_0_and_adjust(&mut self, expn_id: ExpnId) -> Option { - let mut span = self.data(); - let mark = span.ctxt.normalize_to_macros_2_0_and_adjust(expn_id); - *self = Span::new(span.lo, span.hi, span.ctxt, span.parent); + let mut mark = None; + *self = self.map_ctxt(|mut ctxt| { + mark = ctxt.normalize_to_macros_2_0_and_adjust(expn_id); + ctxt + }); mark } #[inline] pub fn glob_adjust(&mut self, expn_id: ExpnId, glob_span: Span) -> Option> { - let mut span = self.data(); - let mark = span.ctxt.glob_adjust(expn_id, glob_span); - *self = Span::new(span.lo, span.hi, span.ctxt, span.parent); + let mut mark = None; + *self = self.map_ctxt(|mut ctxt| { + mark = ctxt.glob_adjust(expn_id, glob_span); + ctxt + }); mark } @@ -1102,22 +1109,22 @@ impl Span { expn_id: ExpnId, glob_span: Span, ) -> Option> { - let mut span = self.data(); - let mark = span.ctxt.reverse_glob_adjust(expn_id, glob_span); - *self = Span::new(span.lo, span.hi, span.ctxt, span.parent); + let mut mark = None; + *self = self.map_ctxt(|mut ctxt| { + mark = ctxt.reverse_glob_adjust(expn_id, glob_span); + ctxt + }); mark } #[inline] - pub fn normalize_to_macros_2_0(mut self) -> Span { - self.update_ctxt(|ctxt| ctxt.normalize_to_macros_2_0()); - self + pub fn normalize_to_macros_2_0(self) -> Span { + self.map_ctxt(|ctxt| ctxt.normalize_to_macros_2_0()) } #[inline] - pub fn normalize_to_macro_rules(mut self) -> Span { - self.update_ctxt(|ctxt| ctxt.normalize_to_macro_rules()); - self + pub fn normalize_to_macro_rules(self) -> Span { + self.map_ctxt(|ctxt| ctxt.normalize_to_macro_rules()) } } @@ -1355,7 +1362,7 @@ impl fmt::Debug for Span { impl fmt::Debug for SpanData { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - fmt::Debug::fmt(&Span::new(self.lo, self.hi, self.ctxt, self.parent), f) + fmt::Debug::fmt(&self.span(), f) } } diff --git a/compiler/rustc_span/src/span_encoding.rs b/compiler/rustc_span/src/span_encoding.rs index 52a1267f8918c..31d2a9db01df9 100644 --- a/compiler/rustc_span/src/span_encoding.rs +++ b/compiler/rustc_span/src/span_encoding.rs @@ -87,43 +87,150 @@ pub struct Span { ctxt_or_parent_or_marker: u16, } -impl Span { +// Convenience structures for all span formats. +#[derive(Clone, Copy)] +struct InlineCtxt { + lo: u32, + len: u16, + ctxt: u16, +} + +#[derive(Clone, Copy)] +struct InlineParent { + lo: u32, + len_with_tag: u16, + parent: u16, +} + +#[derive(Clone, Copy)] +struct PartiallyInterned { + index: u32, + ctxt: u16, +} + +#[derive(Clone, Copy)] +struct Interned { + index: u32, +} + +impl InlineCtxt { #[inline] - fn data_inline_ctxt(self) -> SpanData { - let len = self.len_with_tag_or_marker as u32; + fn data(self) -> SpanData { + let len = self.len as u32; debug_assert!(len <= MAX_LEN); SpanData { - lo: BytePos(self.lo_or_index), - hi: BytePos(self.lo_or_index.debug_strict_add(len)), - ctxt: SyntaxContext::from_u32(self.ctxt_or_parent_or_marker as u32), + lo: BytePos(self.lo), + hi: BytePos(self.lo.debug_strict_add(len)), + ctxt: SyntaxContext::from_u16(self.ctxt), parent: None, } } #[inline] - fn data_inline_parent(self) -> SpanData { - let len = (self.len_with_tag_or_marker & !PARENT_TAG) as u32; + fn span(lo: u32, len: u16, ctxt: u16) -> Span { + Span { lo_or_index: lo, len_with_tag_or_marker: len, ctxt_or_parent_or_marker: ctxt } + } + #[inline] + fn from_span(span: Span) -> InlineCtxt { + let (lo, len, ctxt) = + (span.lo_or_index, span.len_with_tag_or_marker, span.ctxt_or_parent_or_marker); + InlineCtxt { lo, len, ctxt } + } +} + +impl InlineParent { + #[inline] + fn data(self) -> SpanData { + let len = (self.len_with_tag & !PARENT_TAG) as u32; debug_assert!(len <= MAX_LEN); - let parent = LocalDefId { - local_def_index: DefIndex::from_u32(self.ctxt_or_parent_or_marker as u32), - }; SpanData { - lo: BytePos(self.lo_or_index), - hi: BytePos(self.lo_or_index.debug_strict_add(len)), + lo: BytePos(self.lo), + hi: BytePos(self.lo.debug_strict_add(len)), ctxt: SyntaxContext::root(), - parent: Some(parent), + parent: Some(LocalDefId { local_def_index: DefIndex::from_u16(self.parent) }), } } #[inline] - fn data_partially_interned(self) -> SpanData { + fn span(lo: u32, len: u16, parent: u16) -> Span { + let (lo_or_index, len_with_tag_or_marker, ctxt_or_parent_or_marker) = + (lo, PARENT_TAG | len, parent); + Span { lo_or_index, len_with_tag_or_marker, ctxt_or_parent_or_marker } + } + #[inline] + fn from_span(span: Span) -> InlineParent { + let (lo, len_with_tag, parent) = + (span.lo_or_index, span.len_with_tag_or_marker, span.ctxt_or_parent_or_marker); + InlineParent { lo, len_with_tag, parent } + } +} + +impl PartiallyInterned { + #[inline] + fn data(self) -> SpanData { SpanData { - ctxt: SyntaxContext::from_u32(self.ctxt_or_parent_or_marker as u32), - ..with_span_interner(|interner| interner.spans[self.lo_or_index as usize]) + ctxt: SyntaxContext::from_u16(self.ctxt), + ..with_span_interner(|interner| interner.spans[self.index as usize]) } } #[inline] - fn data_interned(self) -> SpanData { - with_span_interner(|interner| interner.spans[self.lo_or_index as usize]) + fn span(index: u32, ctxt: u16) -> Span { + let (lo_or_index, len_with_tag_or_marker, ctxt_or_parent_or_marker) = + (index, BASE_LEN_INTERNED_MARKER, ctxt); + Span { lo_or_index, len_with_tag_or_marker, ctxt_or_parent_or_marker } + } + #[inline] + fn from_span(span: Span) -> PartiallyInterned { + PartiallyInterned { index: span.lo_or_index, ctxt: span.ctxt_or_parent_or_marker } + } +} + +impl Interned { + #[inline] + fn data(self) -> SpanData { + with_span_interner(|interner| interner.spans[self.index as usize]) + } + #[inline] + fn span(index: u32) -> Span { + let (lo_or_index, len_with_tag_or_marker, ctxt_or_parent_or_marker) = + (index, BASE_LEN_INTERNED_MARKER, CTXT_INTERNED_MARKER); + Span { lo_or_index, len_with_tag_or_marker, ctxt_or_parent_or_marker } } + #[inline] + fn from_span(span: Span) -> Interned { + Interned { index: span.lo_or_index } + } +} + +// This code is very hot, and converting span to an enum and matching on it doesn't optimize away +// properly. So we are using a macro emulating such a match, but expand it directly to an if-else +// chain. +macro_rules! match_span_kind { + ( + $span:expr, + InlineCtxt($span1:ident) => $arm1:expr, + InlineParent($span2:ident) => $arm2:expr, + PartiallyInterned($span3:ident) => $arm3:expr, + Interned($span4:ident) => $arm4:expr, + ) => { + if $span.len_with_tag_or_marker != BASE_LEN_INTERNED_MARKER { + if $span.len_with_tag_or_marker & PARENT_TAG == 0 { + // Inline-context format. + let $span1 = InlineCtxt::from_span($span); + $arm1 + } else { + // Inline-parent format. + let $span2 = InlineParent::from_span($span); + $arm2 + } + } else if $span.ctxt_or_parent_or_marker != CTXT_INTERNED_MARKER { + // Partially-interned format. + let $span3 = PartiallyInterned::from_span($span); + $arm3 + } else { + // Interned format. + let $span4 = Interned::from_span($span); + $arm4 + } + }; } // `MAX_LEN` is chosen so that `PARENT_TAG | MAX_LEN` is distinct from @@ -154,23 +261,13 @@ impl Span { let (len, ctxt32) = (hi.0 - lo.0, ctxt.as_u32()); if len <= MAX_LEN { if ctxt32 <= MAX_CTXT && parent.is_none() { - // Inline-context format. - return Span { - lo_or_index: lo.0, - len_with_tag_or_marker: len as u16, - ctxt_or_parent_or_marker: ctxt32 as u16, - }; + return InlineCtxt::span(lo.0, len as u16, ctxt32 as u16); } else if ctxt32 == 0 && let Some(parent) = parent && let parent32 = parent.local_def_index.as_u32() && parent32 <= MAX_CTXT { - // Inline-parent format. - return Span { - lo_or_index: lo.0, - len_with_tag_or_marker: PARENT_TAG | len as u16, - ctxt_or_parent_or_marker: parent32 as u16, - }; + return InlineParent::span(lo.0, len as u16, parent32 as u16); } } @@ -179,20 +276,10 @@ impl Span { with_span_interner(|interner| interner.intern(&SpanData { lo, hi, ctxt, parent })) }; if ctxt32 <= MAX_CTXT { - // Partially-interned format. - Span { - // Interned ctxt should never be read, so it can use any value. - lo_or_index: index(SyntaxContext::from_u32(u32::MAX)), - len_with_tag_or_marker: BASE_LEN_INTERNED_MARKER, - ctxt_or_parent_or_marker: ctxt32 as u16, - } + // Interned ctxt should never be read, so it can use any value. + PartiallyInterned::span(index(SyntaxContext::from_u32(u32::MAX)), ctxt32 as u16) } else { - // Interned format. - Span { - lo_or_index: index(ctxt), - len_with_tag_or_marker: BASE_LEN_INTERNED_MARKER, - ctxt_or_parent_or_marker: CTXT_INTERNED_MARKER, - } + Interned::span(index(ctxt)) } } @@ -209,20 +296,12 @@ impl Span { /// This function must not be used outside the incremental engine. #[inline] pub fn data_untracked(self) -> SpanData { - if self.len_with_tag_or_marker != BASE_LEN_INTERNED_MARKER { - if self.len_with_tag_or_marker & PARENT_TAG == 0 { - // Inline-context format. - self.data_inline_ctxt() - } else { - // Inline-parent format. - self.data_inline_parent() - } - } else if self.ctxt_or_parent_or_marker != CTXT_INTERNED_MARKER { - // Partially-interned format. - self.data_partially_interned() - } else { - // Interned format. - self.data_interned() + match_span_kind! { + self, + InlineCtxt(span) => span.data(), + InlineParent(span) => span.data(), + PartiallyInterned(span) => span.data(), + Interned(span) => span.data(), } } @@ -247,68 +326,56 @@ impl Span { // update doesn't change format. All non-inline or format changing scenarios require accessing // interner and can fall back to `Span::new`. #[inline] - pub fn update_ctxt(&mut self, update: impl FnOnce(SyntaxContext) -> SyntaxContext) { + pub fn map_ctxt(self, update: impl FnOnce(SyntaxContext) -> SyntaxContext) -> Span { let (updated_ctxt32, data); - if self.len_with_tag_or_marker != BASE_LEN_INTERNED_MARKER { - if self.len_with_tag_or_marker & PARENT_TAG == 0 { - // Inline-context format. - updated_ctxt32 = - update(SyntaxContext::from_u32(self.ctxt_or_parent_or_marker as u32)).as_u32(); + match_span_kind! { + self, + InlineCtxt(span) => { + updated_ctxt32 = update(SyntaxContext::from_u16(span.ctxt)).as_u32(); // Any small new context including zero will preserve the format. if updated_ctxt32 <= MAX_CTXT { - self.ctxt_or_parent_or_marker = updated_ctxt32 as u16; - return; + return InlineCtxt::span(span.lo, span.len, updated_ctxt32 as u16); } - data = self.data_inline_ctxt(); - } else { - // Inline-parent format. + data = span.data(); + }, + InlineParent(span) => { updated_ctxt32 = update(SyntaxContext::root()).as_u32(); // Only if the new context is zero the format will be preserved. if updated_ctxt32 == 0 { // Do nothing. - return; + return self; } - data = self.data_inline_parent(); - } - } else if self.ctxt_or_parent_or_marker != CTXT_INTERNED_MARKER { - // Partially-interned format. - updated_ctxt32 = - update(SyntaxContext::from_u32(self.ctxt_or_parent_or_marker as u32)).as_u32(); - // Any small new context excluding zero will preserve the format. - // Zero may change the format to `InlineParent` if parent and len are small enough. - if updated_ctxt32 <= MAX_CTXT && updated_ctxt32 != 0 { - self.ctxt_or_parent_or_marker = updated_ctxt32 as u16; - return; - } - data = self.data_partially_interned(); - } else { - // Interned format. - data = self.data_interned(); - updated_ctxt32 = update(data.ctxt).as_u32(); + data = span.data(); + }, + PartiallyInterned(span) => { + updated_ctxt32 = update(SyntaxContext::from_u16(span.ctxt)).as_u32(); + // Any small new context excluding zero will preserve the format. + // Zero may change the format to `InlineParent` if parent and len are small enough. + if updated_ctxt32 <= MAX_CTXT && updated_ctxt32 != 0 { + return PartiallyInterned::span(span.index, updated_ctxt32 as u16); + } + data = span.data(); + }, + Interned(span) => { + data = span.data(); + updated_ctxt32 = update(data.ctxt).as_u32(); + }, } // We could not keep the span in the same inline format, fall back to the complete logic. - *self = data.with_ctxt(SyntaxContext::from_u32(updated_ctxt32)); + data.with_ctxt(SyntaxContext::from_u32(updated_ctxt32)) } // Returns either syntactic context, if it can be retrieved without taking the interner lock, // or an index into the interner if it cannot. #[inline] fn inline_ctxt(self) -> Result { - if self.len_with_tag_or_marker != BASE_LEN_INTERNED_MARKER { - if self.len_with_tag_or_marker & PARENT_TAG == 0 { - // Inline-context format. - Ok(SyntaxContext::from_u32(self.ctxt_or_parent_or_marker as u32)) - } else { - // Inline-parent format. - Ok(SyntaxContext::root()) - } - } else if self.ctxt_or_parent_or_marker != CTXT_INTERNED_MARKER { - // Partially-interned format. - Ok(SyntaxContext::from_u32(self.ctxt_or_parent_or_marker as u32)) - } else { - // Interned format. - Err(self.lo_or_index as usize) + match_span_kind! { + self, + InlineCtxt(span) => Ok(SyntaxContext::from_u16(span.ctxt)), + InlineParent(_span) => Ok(SyntaxContext::root()), + PartiallyInterned(span) => Ok(SyntaxContext::from_u16(span.ctxt)), + Interned(span) => Err(span.index as usize), } } diff --git a/compiler/rustc_span/src/symbol.rs b/compiler/rustc_span/src/symbol.rs index e245dfb9f5d77..f44fa1bcb4fd1 100644 --- a/compiler/rustc_span/src/symbol.rs +++ b/compiler/rustc_span/src/symbol.rs @@ -635,7 +635,9 @@ symbols! { coroutine, coroutine_clone, coroutine_resume, + coroutine_return, coroutine_state, + coroutine_yield, coroutines, cosf128, cosf16, @@ -1116,6 +1118,7 @@ symbols! { macro_lifetime_matcher, macro_literal_matcher, macro_metavar_expr, + macro_metavar_expr_concat, macro_reexport, macro_use, macro_vis_matcher, diff --git a/compiler/rustc_target/src/asm/mod.rs b/compiler/rustc_target/src/asm/mod.rs index 5f4ce5ed59974..b057bf94a087a 100644 --- a/compiler/rustc_target/src/asm/mod.rs +++ b/compiler/rustc_target/src/asm/mod.rs @@ -707,15 +707,19 @@ pub enum InlineAsmType { I32, I64, I128, + F16, F32, F64, + F128, VecI8(u64), VecI16(u64), VecI32(u64), VecI64(u64), VecI128(u64), + VecF16(u64), VecF32(u64), VecF64(u64), + VecF128(u64), } impl InlineAsmType { @@ -730,15 +734,19 @@ impl InlineAsmType { Self::I32 => 4, Self::I64 => 8, Self::I128 => 16, + Self::F16 => 2, Self::F32 => 4, Self::F64 => 8, + Self::F128 => 16, Self::VecI8(n) => n * 1, Self::VecI16(n) => n * 2, Self::VecI32(n) => n * 4, Self::VecI64(n) => n * 8, Self::VecI128(n) => n * 16, + Self::VecF16(n) => n * 2, Self::VecF32(n) => n * 4, Self::VecF64(n) => n * 8, + Self::VecF128(n) => n * 16, }) } } @@ -751,15 +759,19 @@ impl fmt::Display for InlineAsmType { Self::I32 => f.write_str("i32"), Self::I64 => f.write_str("i64"), Self::I128 => f.write_str("i128"), + Self::F16 => f.write_str("f16"), Self::F32 => f.write_str("f32"), Self::F64 => f.write_str("f64"), + Self::F128 => f.write_str("f128"), Self::VecI8(n) => write!(f, "i8x{n}"), Self::VecI16(n) => write!(f, "i16x{n}"), Self::VecI32(n) => write!(f, "i32x{n}"), Self::VecI64(n) => write!(f, "i64x{n}"), Self::VecI128(n) => write!(f, "i128x{n}"), + Self::VecF16(n) => write!(f, "f16x{n}"), Self::VecF32(n) => write!(f, "f32x{n}"), Self::VecF64(n) => write!(f, "f64x{n}"), + Self::VecF128(n) => write!(f, "f128x{n}"), } } } diff --git a/compiler/rustc_target/src/asm/x86.rs b/compiler/rustc_target/src/asm/x86.rs index 28413a5bcbd17..8452961c17c0f 100644 --- a/compiler/rustc_target/src/asm/x86.rs +++ b/compiler/rustc_target/src/asm/x86.rs @@ -107,26 +107,26 @@ impl X86InlineAsmRegClass { match self { Self::reg | Self::reg_abcd => { if arch == InlineAsmArch::X86_64 { - types! { _: I16, I32, I64, F32, F64; } + types! { _: I16, I32, I64, F16, F32, F64; } } else { - types! { _: I16, I32, F32; } + types! { _: I16, I32, F16, F32; } } } Self::reg_byte => types! { _: I8; }, Self::xmm_reg => types! { - sse: I32, I64, F32, F64, - VecI8(16), VecI16(8), VecI32(4), VecI64(2), VecF32(4), VecF64(2); + sse: I32, I64, F16, F32, F64, F128, + VecI8(16), VecI16(8), VecI32(4), VecI64(2), VecF16(8), VecF32(4), VecF64(2); }, Self::ymm_reg => types! { - avx: I32, I64, F32, F64, - VecI8(16), VecI16(8), VecI32(4), VecI64(2), VecF32(4), VecF64(2), - VecI8(32), VecI16(16), VecI32(8), VecI64(4), VecF32(8), VecF64(4); + avx: I32, I64, F16, F32, F64, F128, + VecI8(16), VecI16(8), VecI32(4), VecI64(2), VecF16(8), VecF32(4), VecF64(2), + VecI8(32), VecI16(16), VecI32(8), VecI64(4), VecF16(16), VecF32(8), VecF64(4); }, Self::zmm_reg => types! { - avx512f: I32, I64, F32, F64, - VecI8(16), VecI16(8), VecI32(4), VecI64(2), VecF32(4), VecF64(2), - VecI8(32), VecI16(16), VecI32(8), VecI64(4), VecF32(8), VecF64(4), - VecI8(64), VecI16(32), VecI32(16), VecI64(8), VecF32(16), VecF64(8); + avx512f: I32, I64, F16, F32, F64, F128, + VecI8(16), VecI16(8), VecI32(4), VecI64(2), VecF16(8), VecF32(4), VecF64(2), + VecI8(32), VecI16(16), VecI32(8), VecI64(4), VecF16(16), VecF32(8), VecF64(4), + VecI8(64), VecI16(32), VecI32(16), VecI64(8), VecF16(32), VecF32(16), VecF64(8); }, Self::kreg => types! { avx512f: I8, I16; diff --git a/compiler/rustc_target/src/spec/base/redox.rs b/compiler/rustc_target/src/spec/base/redox.rs index 468fe478549b2..9070791e9dfc4 100644 --- a/compiler/rustc_target/src/spec/base/redox.rs +++ b/compiler/rustc_target/src/spec/base/redox.rs @@ -1,4 +1,4 @@ -use crate::spec::{cvs, RelroLevel, TargetOptions}; +use crate::spec::{cvs, Cc, LinkerFlavor, Lld, RelroLevel, TargetOptions}; pub fn opts() -> TargetOptions { TargetOptions { @@ -12,6 +12,8 @@ pub fn opts() -> TargetOptions { has_thread_local: true, crt_static_default: true, crt_static_respected: true, + crt_static_allows_dylibs: true, + late_link_args: TargetOptions::link_args(LinkerFlavor::Gnu(Cc::Yes, Lld::No), &["-lgcc"]), ..Default::default() } } diff --git a/compiler/rustc_target/src/spec/mod.rs b/compiler/rustc_target/src/spec/mod.rs index adea2caabbe75..42860b1059ed7 100644 --- a/compiler/rustc_target/src/spec/mod.rs +++ b/compiler/rustc_target/src/spec/mod.rs @@ -1647,6 +1647,7 @@ supported_targets! { ("x86_64-unknown-l4re-uclibc", x86_64_unknown_l4re_uclibc), ("aarch64-unknown-redox", aarch64_unknown_redox), + ("i686-unknown-redox", i686_unknown_redox), ("x86_64-unknown-redox", x86_64_unknown_redox), ("i386-apple-ios", i386_apple_ios), diff --git a/compiler/rustc_target/src/spec/targets/i686_unknown_redox.rs b/compiler/rustc_target/src/spec/targets/i686_unknown_redox.rs new file mode 100644 index 0000000000000..83252fadb78ea --- /dev/null +++ b/compiler/rustc_target/src/spec/targets/i686_unknown_redox.rs @@ -0,0 +1,27 @@ +use crate::spec::{base, Cc, LinkerFlavor, Lld, StackProbeType, Target}; + +pub fn target() -> Target { + let mut base = base::redox::opts(); + base.cpu = "pentiumpro".into(); + base.plt_by_default = false; + base.max_atomic_width = Some(64); + base.add_pre_link_args(LinkerFlavor::Gnu(Cc::Yes, Lld::No), &["-m32"]); + // don't use probe-stack=inline-asm until rust#83139 and rust#84667 are resolved + base.stack_probes = StackProbeType::Call; + + Target { + llvm_target: "i686-unknown-redox".into(), + metadata: crate::spec::TargetMetadata { + description: None, + tier: None, + host_tools: None, + std: None, + }, + pointer_width: 32, + data_layout: + "e-m:e-p:32:32-p270:32:32-p271:32:32-p272:64:64-i128:128-f64:32:64-f80:32-n8:16:32-S128" + .into(), + arch: "x86".into(), + options: base, + } +} diff --git a/compiler/rustc_trait_selection/src/solve/alias_relate.rs b/compiler/rustc_trait_selection/src/solve/alias_relate.rs index 4d7e2fc2cefab..4e52caa5a5b8e 100644 --- a/compiler/rustc_trait_selection/src/solve/alias_relate.rs +++ b/compiler/rustc_trait_selection/src/solve/alias_relate.rs @@ -48,6 +48,12 @@ impl<'tcx> EvalCtxt<'_, InferCtxt<'tcx>> { rhs }; + // Add a `make_canonical_response` probe step so that we treat this as + // a candidate, even if `try_evaluate_added_goals` bails due to an error. + // It's `Certainty::AMBIGUOUS` because this candidate is not "finished", + // since equating the normalized terms will lead to additional constraints. + self.inspect.make_canonical_response(Certainty::AMBIGUOUS); + // Apply the constraints. self.try_evaluate_added_goals()?; let lhs = self.resolve_vars_if_possible(lhs); @@ -55,8 +61,8 @@ impl<'tcx> EvalCtxt<'_, InferCtxt<'tcx>> { trace!(?lhs, ?rhs); let variance = match direction { - ty::AliasRelationDirection::Equate => ty::Variance::Invariant, - ty::AliasRelationDirection::Subtype => ty::Variance::Covariant, + ty::AliasRelationDirection::Equate => ty::Invariant, + ty::AliasRelationDirection::Subtype => ty::Covariant, }; match (lhs.to_alias_term(), rhs.to_alias_term()) { (None, None) => { @@ -72,7 +78,7 @@ impl<'tcx> EvalCtxt<'_, InferCtxt<'tcx>> { self.relate_rigid_alias_non_alias( param_env, alias, - variance.xform(ty::Variance::Contravariant), + variance.xform(ty::Contravariant), lhs, )?; self.evaluate_added_goals_and_make_canonical_response(Certainty::Yes) diff --git a/compiler/rustc_trait_selection/src/solve/assembly/mod.rs b/compiler/rustc_trait_selection/src/solve/assembly/mod.rs index b51efd339c4d8..1cdbf0820780d 100644 --- a/compiler/rustc_trait_selection/src/solve/assembly/mod.rs +++ b/compiler/rustc_trait_selection/src/solve/assembly/mod.rs @@ -1,20 +1,22 @@ //! Code shared by trait and projection goals for candidate assembly. +use derivative::Derivative; use rustc_hir::def_id::DefId; +use rustc_hir::LangItem; use rustc_infer::infer::InferCtxt; use rustc_infer::traits::query::NoSolution; +use rustc_infer::traits::util::supertraits; use rustc_middle::bug; use rustc_middle::traits::solve::inspect::ProbeKind; -use rustc_middle::traits::solve::{ - CandidateSource, CanonicalResponse, Certainty, Goal, MaybeCause, QueryResult, -}; +use rustc_middle::traits::solve::{Certainty, Goal, MaybeCause, QueryResult}; use rustc_middle::traits::BuiltinImplSource; use rustc_middle::ty::fast_reject::{SimplifiedType, TreatParams}; use rustc_middle::ty::{self, Ty, TyCtxt}; use rustc_middle::ty::{fast_reject, TypeFoldable}; use rustc_middle::ty::{TypeVisitableExt, Upcast}; use rustc_span::{ErrorGuaranteed, DUMMY_SP}; -use std::fmt::Debug; +use rustc_type_ir::solve::{CandidateSource, CanonicalResponse}; +use rustc_type_ir::Interner; use crate::solve::GoalSource; use crate::solve::{EvalCtxt, SolverMode}; @@ -25,10 +27,11 @@ pub(super) mod structural_traits; /// /// It consists of both the `source`, which describes how that goal would be proven, /// and the `result` when using the given `source`. -#[derive(Debug, Clone)] -pub(super) struct Candidate<'tcx> { - pub(super) source: CandidateSource<'tcx>, - pub(super) result: CanonicalResponse<'tcx>, +#[derive(Derivative)] +#[derivative(Debug(bound = ""), Clone(bound = ""))] +pub(super) struct Candidate { + pub(super) source: CandidateSource, + pub(super) result: CanonicalResponse, } /// Methods used to assemble candidates for either trait or projection goals. @@ -49,22 +52,22 @@ pub(super) trait GoalKind<'tcx>: /// [`EvalCtxt::evaluate_added_goals_and_make_canonical_response`]). fn probe_and_match_goal_against_assumption( ecx: &mut EvalCtxt<'_, InferCtxt<'tcx>>, - source: CandidateSource<'tcx>, + source: CandidateSource>, goal: Goal<'tcx, Self>, assumption: ty::Clause<'tcx>, then: impl FnOnce(&mut EvalCtxt<'_, InferCtxt<'tcx>>) -> QueryResult<'tcx>, - ) -> Result, NoSolution>; + ) -> Result>, NoSolution>; /// Consider a clause, which consists of a "assumption" and some "requirements", /// to satisfy a goal. If the requirements hold, then attempt to satisfy our /// goal by equating it with the assumption. fn probe_and_consider_implied_clause( ecx: &mut EvalCtxt<'_, InferCtxt<'tcx>>, - parent_source: CandidateSource<'tcx>, + parent_source: CandidateSource>, goal: Goal<'tcx, Self>, assumption: ty::Clause<'tcx>, requirements: impl IntoIterator>)>, - ) -> Result, NoSolution> { + ) -> Result>, NoSolution> { Self::probe_and_match_goal_against_assumption(ecx, parent_source, goal, assumption, |ecx| { for (nested_source, goal) in requirements { ecx.add_goal(nested_source, goal); @@ -78,10 +81,10 @@ pub(super) trait GoalKind<'tcx>: /// since they're not implied by the well-formedness of the object type. fn probe_and_consider_object_bound_candidate( ecx: &mut EvalCtxt<'_, InferCtxt<'tcx>>, - source: CandidateSource<'tcx>, + source: CandidateSource>, goal: Goal<'tcx, Self>, assumption: ty::Clause<'tcx>, - ) -> Result, NoSolution> { + ) -> Result>, NoSolution> { Self::probe_and_match_goal_against_assumption(ecx, source, goal, assumption, |ecx| { let tcx = ecx.interner(); let ty::Dynamic(bounds, _, _) = *goal.predicate.self_ty().kind() else { @@ -104,7 +107,7 @@ pub(super) trait GoalKind<'tcx>: ecx: &mut EvalCtxt<'_, InferCtxt<'tcx>>, goal: Goal<'tcx, Self>, impl_def_id: DefId, - ) -> Result, NoSolution>; + ) -> Result>, NoSolution>; /// If the predicate contained an error, we want to avoid emitting unnecessary trait /// errors but still want to emit errors for other trait goals. We have some special @@ -115,7 +118,7 @@ pub(super) trait GoalKind<'tcx>: fn consider_error_guaranteed_candidate( ecx: &mut EvalCtxt<'_, InferCtxt<'tcx>>, guar: ErrorGuaranteed, - ) -> Result, NoSolution>; + ) -> Result>, NoSolution>; /// A type implements an `auto trait` if its components do as well. /// @@ -124,13 +127,13 @@ pub(super) trait GoalKind<'tcx>: fn consider_auto_trait_candidate( ecx: &mut EvalCtxt<'_, InferCtxt<'tcx>>, goal: Goal<'tcx, Self>, - ) -> Result, NoSolution>; + ) -> Result>, NoSolution>; /// A trait alias holds if the RHS traits and `where` clauses hold. fn consider_trait_alias_candidate( ecx: &mut EvalCtxt<'_, InferCtxt<'tcx>>, goal: Goal<'tcx, Self>, - ) -> Result, NoSolution>; + ) -> Result>, NoSolution>; /// A type is `Sized` if its tail component is `Sized`. /// @@ -139,7 +142,7 @@ pub(super) trait GoalKind<'tcx>: fn consider_builtin_sized_candidate( ecx: &mut EvalCtxt<'_, InferCtxt<'tcx>>, goal: Goal<'tcx, Self>, - ) -> Result, NoSolution>; + ) -> Result>, NoSolution>; /// A type is `Copy` or `Clone` if its components are `Copy` or `Clone`. /// @@ -148,20 +151,20 @@ pub(super) trait GoalKind<'tcx>: fn consider_builtin_copy_clone_candidate( ecx: &mut EvalCtxt<'_, InferCtxt<'tcx>>, goal: Goal<'tcx, Self>, - ) -> Result, NoSolution>; + ) -> Result>, NoSolution>; /// A type is `PointerLike` if we can compute its layout, and that layout /// matches the layout of `usize`. fn consider_builtin_pointer_like_candidate( ecx: &mut EvalCtxt<'_, InferCtxt<'tcx>>, goal: Goal<'tcx, Self>, - ) -> Result, NoSolution>; + ) -> Result>, NoSolution>; /// A type is a `FnPtr` if it is of `FnPtr` type. fn consider_builtin_fn_ptr_trait_candidate( ecx: &mut EvalCtxt<'_, InferCtxt<'tcx>>, goal: Goal<'tcx, Self>, - ) -> Result, NoSolution>; + ) -> Result>, NoSolution>; /// A callable type (a closure, fn def, or fn ptr) is known to implement the `Fn` /// family of traits where `A` is given by the signature of the type. @@ -169,7 +172,7 @@ pub(super) trait GoalKind<'tcx>: ecx: &mut EvalCtxt<'_, InferCtxt<'tcx>>, goal: Goal<'tcx, Self>, kind: ty::ClosureKind, - ) -> Result, NoSolution>; + ) -> Result>, NoSolution>; /// An async closure is known to implement the `AsyncFn` family of traits /// where `A` is given by the signature of the type. @@ -177,7 +180,7 @@ pub(super) trait GoalKind<'tcx>: ecx: &mut EvalCtxt<'_, InferCtxt<'tcx>>, goal: Goal<'tcx, Self>, kind: ty::ClosureKind, - ) -> Result, NoSolution>; + ) -> Result>, NoSolution>; /// Compute the built-in logic of the `AsyncFnKindHelper` helper trait, which /// is used internally to delay computation for async closures until after @@ -185,13 +188,13 @@ pub(super) trait GoalKind<'tcx>: fn consider_builtin_async_fn_kind_helper_candidate( ecx: &mut EvalCtxt<'_, InferCtxt<'tcx>>, goal: Goal<'tcx, Self>, - ) -> Result, NoSolution>; + ) -> Result>, NoSolution>; /// `Tuple` is implemented if the `Self` type is a tuple. fn consider_builtin_tuple_candidate( ecx: &mut EvalCtxt<'_, InferCtxt<'tcx>>, goal: Goal<'tcx, Self>, - ) -> Result, NoSolution>; + ) -> Result>, NoSolution>; /// `Pointee` is always implemented. /// @@ -201,7 +204,7 @@ pub(super) trait GoalKind<'tcx>: fn consider_builtin_pointee_candidate( ecx: &mut EvalCtxt<'_, InferCtxt<'tcx>>, goal: Goal<'tcx, Self>, - ) -> Result, NoSolution>; + ) -> Result>, NoSolution>; /// A coroutine (that comes from an `async` desugaring) is known to implement /// `Future`, where `O` is given by the coroutine's return type @@ -209,7 +212,7 @@ pub(super) trait GoalKind<'tcx>: fn consider_builtin_future_candidate( ecx: &mut EvalCtxt<'_, InferCtxt<'tcx>>, goal: Goal<'tcx, Self>, - ) -> Result, NoSolution>; + ) -> Result>, NoSolution>; /// A coroutine (that comes from a `gen` desugaring) is known to implement /// `Iterator`, where `O` is given by the generator's yield type @@ -217,19 +220,19 @@ pub(super) trait GoalKind<'tcx>: fn consider_builtin_iterator_candidate( ecx: &mut EvalCtxt<'_, InferCtxt<'tcx>>, goal: Goal<'tcx, Self>, - ) -> Result, NoSolution>; + ) -> Result>, NoSolution>; /// A coroutine (that comes from a `gen` desugaring) is known to implement /// `FusedIterator` fn consider_builtin_fused_iterator_candidate( ecx: &mut EvalCtxt<'_, InferCtxt<'tcx>>, goal: Goal<'tcx, Self>, - ) -> Result, NoSolution>; + ) -> Result>, NoSolution>; fn consider_builtin_async_iterator_candidate( ecx: &mut EvalCtxt<'_, InferCtxt<'tcx>>, goal: Goal<'tcx, Self>, - ) -> Result, NoSolution>; + ) -> Result>, NoSolution>; /// A coroutine (that doesn't come from an `async` or `gen` desugaring) is known to /// implement `Coroutine`, given the resume, yield, @@ -237,27 +240,27 @@ pub(super) trait GoalKind<'tcx>: fn consider_builtin_coroutine_candidate( ecx: &mut EvalCtxt<'_, InferCtxt<'tcx>>, goal: Goal<'tcx, Self>, - ) -> Result, NoSolution>; + ) -> Result>, NoSolution>; fn consider_builtin_discriminant_kind_candidate( ecx: &mut EvalCtxt<'_, InferCtxt<'tcx>>, goal: Goal<'tcx, Self>, - ) -> Result, NoSolution>; + ) -> Result>, NoSolution>; fn consider_builtin_async_destruct_candidate( ecx: &mut EvalCtxt<'_, InferCtxt<'tcx>>, goal: Goal<'tcx, Self>, - ) -> Result, NoSolution>; + ) -> Result>, NoSolution>; fn consider_builtin_destruct_candidate( ecx: &mut EvalCtxt<'_, InferCtxt<'tcx>>, goal: Goal<'tcx, Self>, - ) -> Result, NoSolution>; + ) -> Result>, NoSolution>; fn consider_builtin_transmute_candidate( ecx: &mut EvalCtxt<'_, InferCtxt<'tcx>>, goal: Goal<'tcx, Self>, - ) -> Result, NoSolution>; + ) -> Result>, NoSolution>; /// Consider (possibly several) candidates to upcast or unsize a type to another /// type, excluding the coercion of a sized type into a `dyn Trait`. @@ -269,14 +272,14 @@ pub(super) trait GoalKind<'tcx>: fn consider_structural_builtin_unsize_candidates( ecx: &mut EvalCtxt<'_, InferCtxt<'tcx>>, goal: Goal<'tcx, Self>, - ) -> Vec>; + ) -> Vec>>; } impl<'tcx> EvalCtxt<'_, InferCtxt<'tcx>> { pub(super) fn assemble_and_evaluate_candidates>( &mut self, goal: Goal<'tcx, G>, - ) -> Vec> { + ) -> Vec>> { let Ok(normalized_self_ty) = self.structurally_normalize_ty(goal.param_env, goal.predicate.self_ty()) else { @@ -323,7 +326,7 @@ impl<'tcx> EvalCtxt<'_, InferCtxt<'tcx>> { pub(super) fn forced_ambiguity( &mut self, cause: MaybeCause, - ) -> Result, NoSolution> { + ) -> Result>, NoSolution> { // This may fail if `try_evaluate_added_goals` overflows because it // fails to reach a fixpoint but ends up getting an error after // running for some additional step. @@ -339,7 +342,7 @@ impl<'tcx> EvalCtxt<'_, InferCtxt<'tcx>> { fn assemble_non_blanket_impl_candidates>( &mut self, goal: Goal<'tcx, G>, - candidates: &mut Vec>, + candidates: &mut Vec>>, ) { let tcx = self.interner(); let self_ty = goal.predicate.self_ty(); @@ -455,7 +458,7 @@ impl<'tcx> EvalCtxt<'_, InferCtxt<'tcx>> { fn assemble_blanket_impl_candidates>( &mut self, goal: Goal<'tcx, G>, - candidates: &mut Vec>, + candidates: &mut Vec>>, ) { let tcx = self.interner(); let trait_impls = tcx.trait_impls_of(goal.predicate.trait_def_id(tcx)); @@ -478,10 +481,9 @@ impl<'tcx> EvalCtxt<'_, InferCtxt<'tcx>> { fn assemble_builtin_impl_candidates>( &mut self, goal: Goal<'tcx, G>, - candidates: &mut Vec>, + candidates: &mut Vec>>, ) { let tcx = self.interner(); - let lang_items = tcx.lang_items(); let trait_def_id = goal.predicate.trait_def_id(tcx); // N.B. When assembling built-in candidates for lang items that are also @@ -497,43 +499,43 @@ impl<'tcx> EvalCtxt<'_, InferCtxt<'tcx>> { G::consider_auto_trait_candidate(self, goal) } else if tcx.trait_is_alias(trait_def_id) { G::consider_trait_alias_candidate(self, goal) - } else if lang_items.sized_trait() == Some(trait_def_id) { + } else if tcx.is_lang_item(trait_def_id, LangItem::Sized) { G::consider_builtin_sized_candidate(self, goal) - } else if lang_items.copy_trait() == Some(trait_def_id) - || lang_items.clone_trait() == Some(trait_def_id) + } else if tcx.is_lang_item(trait_def_id, LangItem::Copy) + || tcx.is_lang_item(trait_def_id, LangItem::Clone) { G::consider_builtin_copy_clone_candidate(self, goal) - } else if lang_items.pointer_like() == Some(trait_def_id) { + } else if tcx.is_lang_item(trait_def_id, LangItem::PointerLike) { G::consider_builtin_pointer_like_candidate(self, goal) - } else if lang_items.fn_ptr_trait() == Some(trait_def_id) { + } else if tcx.is_lang_item(trait_def_id, LangItem::FnPtrTrait) { G::consider_builtin_fn_ptr_trait_candidate(self, goal) } else if let Some(kind) = self.interner().fn_trait_kind_from_def_id(trait_def_id) { G::consider_builtin_fn_trait_candidates(self, goal, kind) } else if let Some(kind) = self.interner().async_fn_trait_kind_from_def_id(trait_def_id) { G::consider_builtin_async_fn_trait_candidates(self, goal, kind) - } else if lang_items.async_fn_kind_helper() == Some(trait_def_id) { + } else if tcx.is_lang_item(trait_def_id, LangItem::AsyncFnKindHelper) { G::consider_builtin_async_fn_kind_helper_candidate(self, goal) - } else if lang_items.tuple_trait() == Some(trait_def_id) { + } else if tcx.is_lang_item(trait_def_id, LangItem::Tuple) { G::consider_builtin_tuple_candidate(self, goal) - } else if lang_items.pointee_trait() == Some(trait_def_id) { + } else if tcx.is_lang_item(trait_def_id, LangItem::PointeeTrait) { G::consider_builtin_pointee_candidate(self, goal) - } else if lang_items.future_trait() == Some(trait_def_id) { + } else if tcx.is_lang_item(trait_def_id, LangItem::Future) { G::consider_builtin_future_candidate(self, goal) - } else if lang_items.iterator_trait() == Some(trait_def_id) { + } else if tcx.is_lang_item(trait_def_id, LangItem::Iterator) { G::consider_builtin_iterator_candidate(self, goal) - } else if lang_items.fused_iterator_trait() == Some(trait_def_id) { + } else if tcx.is_lang_item(trait_def_id, LangItem::FusedIterator) { G::consider_builtin_fused_iterator_candidate(self, goal) - } else if lang_items.async_iterator_trait() == Some(trait_def_id) { + } else if tcx.is_lang_item(trait_def_id, LangItem::AsyncIterator) { G::consider_builtin_async_iterator_candidate(self, goal) - } else if lang_items.coroutine_trait() == Some(trait_def_id) { + } else if tcx.is_lang_item(trait_def_id, LangItem::Coroutine) { G::consider_builtin_coroutine_candidate(self, goal) - } else if lang_items.discriminant_kind_trait() == Some(trait_def_id) { + } else if tcx.is_lang_item(trait_def_id, LangItem::DiscriminantKind) { G::consider_builtin_discriminant_kind_candidate(self, goal) - } else if lang_items.async_destruct_trait() == Some(trait_def_id) { + } else if tcx.is_lang_item(trait_def_id, LangItem::AsyncDestruct) { G::consider_builtin_async_destruct_candidate(self, goal) - } else if lang_items.destruct_trait() == Some(trait_def_id) { + } else if tcx.is_lang_item(trait_def_id, LangItem::Destruct) { G::consider_builtin_destruct_candidate(self, goal) - } else if lang_items.transmute_trait() == Some(trait_def_id) { + } else if tcx.is_lang_item(trait_def_id, LangItem::TransmuteTrait) { G::consider_builtin_transmute_candidate(self, goal) } else { Err(NoSolution) @@ -543,7 +545,7 @@ impl<'tcx> EvalCtxt<'_, InferCtxt<'tcx>> { // There may be multiple unsize candidates for a trait with several supertraits: // `trait Foo: Bar + Bar` and `dyn Foo: Unsize>` - if lang_items.unsize_trait() == Some(trait_def_id) { + if tcx.is_lang_item(trait_def_id, LangItem::Unsize) { candidates.extend(G::consider_structural_builtin_unsize_candidates(self, goal)); } } @@ -552,7 +554,7 @@ impl<'tcx> EvalCtxt<'_, InferCtxt<'tcx>> { fn assemble_param_env_candidates>( &mut self, goal: Goal<'tcx, G>, - candidates: &mut Vec>, + candidates: &mut Vec>>, ) { for (i, assumption) in goal.param_env.caller_bounds().iter().enumerate() { candidates.extend(G::probe_and_consider_implied_clause( @@ -569,7 +571,7 @@ impl<'tcx> EvalCtxt<'_, InferCtxt<'tcx>> { fn assemble_alias_bound_candidates>( &mut self, goal: Goal<'tcx, G>, - candidates: &mut Vec>, + candidates: &mut Vec>>, ) { let () = self.probe(|_| ProbeKind::NormalizedSelfTyAssembly).enter(|ecx| { ecx.assemble_alias_bound_candidates_recur(goal.predicate.self_ty(), goal, candidates); @@ -589,7 +591,7 @@ impl<'tcx> EvalCtxt<'_, InferCtxt<'tcx>> { &mut self, self_ty: Ty<'tcx>, goal: Goal<'tcx, G>, - candidates: &mut Vec>, + candidates: &mut Vec>>, ) { let (kind, alias_ty) = match *self_ty.kind() { ty::Bool @@ -673,7 +675,7 @@ impl<'tcx> EvalCtxt<'_, InferCtxt<'tcx>> { fn assemble_object_bound_candidates>( &mut self, goal: Goal<'tcx, G>, - candidates: &mut Vec>, + candidates: &mut Vec>>, ) { let tcx = self.interner(); if !tcx.trait_def(goal.predicate.trait_def_id(tcx)).implement_via_object { @@ -743,14 +745,14 @@ impl<'tcx> EvalCtxt<'_, InferCtxt<'tcx>> { // a projection goal. if let Some(principal) = bounds.principal() { let principal_trait_ref = principal.with_self_ty(tcx, self_ty); - self.walk_vtable(principal_trait_ref, |ecx, assumption, vtable_base, _| { + for (idx, assumption) in supertraits(self.interner(), principal_trait_ref).enumerate() { candidates.extend(G::probe_and_consider_object_bound_candidate( - ecx, - CandidateSource::BuiltinImpl(BuiltinImplSource::Object { vtable_base }), + self, + CandidateSource::BuiltinImpl(BuiltinImplSource::Object(idx)), goal, assumption.upcast(tcx), )); - }); + } } } @@ -764,7 +766,7 @@ impl<'tcx> EvalCtxt<'_, InferCtxt<'tcx>> { fn assemble_coherence_unknowable_candidates>( &mut self, goal: Goal<'tcx, G>, - candidates: &mut Vec>, + candidates: &mut Vec>>, ) { let tcx = self.interner(); @@ -793,7 +795,7 @@ impl<'tcx> EvalCtxt<'_, InferCtxt<'tcx>> { fn discard_impls_shadowed_by_env>( &mut self, goal: Goal<'tcx, G>, - candidates: &mut Vec>, + candidates: &mut Vec>>, ) { let tcx = self.interner(); let trait_goal: Goal<'tcx, ty::TraitPredicate<'tcx>> = @@ -841,7 +843,7 @@ impl<'tcx> EvalCtxt<'_, InferCtxt<'tcx>> { #[instrument(level = "debug", skip(self), ret)] pub(super) fn merge_candidates( &mut self, - candidates: Vec>, + candidates: Vec>>, ) -> QueryResult<'tcx> { // First try merging all candidates. This is complete and fully sound. let responses = candidates.iter().map(|c| c.result).collect::>(); diff --git a/compiler/rustc_trait_selection/src/solve/assembly/structural_traits.rs b/compiler/rustc_trait_selection/src/solve/assembly/structural_traits.rs index 98f98d9992d30..d6074617cafe7 100644 --- a/compiler/rustc_trait_selection/src/solve/assembly/structural_traits.rs +++ b/compiler/rustc_trait_selection/src/solve/assembly/structural_traits.rs @@ -1,14 +1,14 @@ //! Code which is used by built-in goals that match "structurally", such a auto //! traits, `Copy`/`Clone`. + +use rustc_ast_ir::{Movability, Mutability}; use rustc_data_structures::fx::FxHashMap; -use rustc_hir::LangItem; -use rustc_hir::{def_id::DefId, Movability, Mutability}; -use rustc_infer::infer::InferCtxt; -use rustc_infer::traits::query::NoSolution; -use rustc_macros::{TypeFoldable, TypeVisitable}; -use rustc_middle::bug; -use rustc_middle::traits::solve::Goal; -use rustc_middle::ty::{self, Ty, TyCtxt, TypeFoldable, TypeFolder, TypeSuperFoldable, Upcast}; +use rustc_next_trait_solver::solve::{Goal, NoSolution}; +use rustc_type_ir::fold::{TypeFoldable, TypeFolder, TypeSuperFoldable}; +use rustc_type_ir::inherent::*; +use rustc_type_ir::lang_items::TraitSolverLangItem; +use rustc_type_ir::{self as ty, InferCtxtLike, Interner, Upcast}; +use rustc_type_ir_macros::{TypeFoldable_Generic, TypeVisitable_Generic}; use crate::solve::EvalCtxt; @@ -17,12 +17,16 @@ use crate::solve::EvalCtxt; // For types with an "existential" binder, i.e. coroutine witnesses, we also // instantiate the binder with placeholders eagerly. #[instrument(level = "trace", skip(ecx), ret)] -pub(in crate::solve) fn instantiate_constituent_tys_for_auto_trait<'tcx>( - ecx: &EvalCtxt<'_, InferCtxt<'tcx>>, - ty: Ty<'tcx>, -) -> Result>>, NoSolution> { +pub(in crate::solve) fn instantiate_constituent_tys_for_auto_trait( + ecx: &EvalCtxt<'_, Infcx>, + ty: I::Ty, +) -> Result>, NoSolution> +where + Infcx: InferCtxtLike, + I: Interner, +{ let tcx = ecx.interner(); - match *ty.kind() { + match ty.kind() { ty::Uint(_) | ty::Int(_) | ty::Bool @@ -34,7 +38,7 @@ pub(in crate::solve) fn instantiate_constituent_tys_for_auto_trait<'tcx>( | ty::Char => Ok(vec![]), // Treat `str` like it's defined as `struct str([u8]);` - ty::Str => Ok(vec![ty::Binder::dummy(Ty::new_slice(tcx, tcx.types.u8))]), + ty::Str => Ok(vec![ty::Binder::dummy(Ty::new_slice(tcx, Ty::new_u8(tcx)))]), ty::Dynamic(..) | ty::Param(..) @@ -43,7 +47,7 @@ pub(in crate::solve) fn instantiate_constituent_tys_for_auto_trait<'tcx>( | ty::Placeholder(..) | ty::Bound(..) | ty::Infer(_) => { - bug!("unexpected type `{ty}`") + panic!("unexpected type `{ty:?}`") } ty::RawPtr(element_ty, _) | ty::Ref(_, element_ty, _) => { @@ -56,7 +60,7 @@ pub(in crate::solve) fn instantiate_constituent_tys_for_auto_trait<'tcx>( ty::Tuple(tys) => { // (T1, ..., Tn) -- meets any bound that all of T1...Tn meet - Ok(tys.iter().map(ty::Binder::dummy).collect()) + Ok(tys.into_iter().map(ty::Binder::dummy).collect()) } ty::Closure(_, args) => Ok(vec![ty::Binder::dummy(args.as_closure().tupled_upvars_ty())]), @@ -76,31 +80,38 @@ pub(in crate::solve) fn instantiate_constituent_tys_for_auto_trait<'tcx>( ty::CoroutineWitness(def_id, args) => Ok(ecx .interner() .bound_coroutine_hidden_types(def_id) - .map(|bty| bty.instantiate(tcx, args)) + .into_iter() + .map(|bty| bty.instantiate(tcx, &args)) .collect()), // For `PhantomData`, we pass `T`. ty::Adt(def, args) if def.is_phantom_data() => Ok(vec![ty::Binder::dummy(args.type_at(0))]), - ty::Adt(def, args) => { - Ok(def.all_fields().map(|f| ty::Binder::dummy(f.ty(tcx, args))).collect()) - } + ty::Adt(def, args) => Ok(def + .all_field_tys(tcx) + .iter_instantiated(tcx, &args) + .map(ty::Binder::dummy) + .collect()), ty::Alias(ty::Opaque, ty::AliasTy { def_id, args, .. }) => { // We can resolve the `impl Trait` to its concrete type, // which enforces a DAG between the functions requiring // the auto trait bounds in question. - Ok(vec![ty::Binder::dummy(tcx.type_of(def_id).instantiate(tcx, args))]) + Ok(vec![ty::Binder::dummy(tcx.type_of(def_id).instantiate(tcx, &args))]) } } } #[instrument(level = "trace", skip(ecx), ret)] -pub(in crate::solve) fn instantiate_constituent_tys_for_sized_trait<'tcx>( - ecx: &EvalCtxt<'_, InferCtxt<'tcx>>, - ty: Ty<'tcx>, -) -> Result>>, NoSolution> { - match *ty.kind() { +pub(in crate::solve) fn instantiate_constituent_tys_for_sized_trait( + ecx: &EvalCtxt<'_, Infcx>, + ty: I::Ty, +) -> Result>, NoSolution> +where + Infcx: InferCtxtLike, + I: Interner, +{ + match ty.kind() { // impl Sized for u*, i*, bool, f*, FnDef, FnPtr, *(const/mut) T, char, &mut? T, [T; N], dyn* Trait, ! // impl Sized for Coroutine, CoroutineWitness, Closure, CoroutineClosure ty::Infer(ty::IntVar(_) | ty::FloatVar(_)) @@ -133,7 +144,7 @@ pub(in crate::solve) fn instantiate_constituent_tys_for_sized_trait<'tcx>( ty::Bound(..) | ty::Infer(ty::TyVar(_) | ty::FreshTy(_) | ty::FreshIntTy(_) | ty::FreshFloatTy(_)) => { - bug!("unexpected type `{ty}`") + panic!("unexpected type `{ty:?}`") } // impl Sized for () @@ -151,7 +162,7 @@ pub(in crate::solve) fn instantiate_constituent_tys_for_sized_trait<'tcx>( // if the ADT is sized for all possible args. ty::Adt(def, args) => { if let Some(sized_crit) = def.sized_constraint(ecx.interner()) { - Ok(vec![ty::Binder::dummy(sized_crit.instantiate(ecx.interner(), args))]) + Ok(vec![ty::Binder::dummy(sized_crit.instantiate(ecx.interner(), &args))]) } else { Ok(vec![]) } @@ -160,11 +171,15 @@ pub(in crate::solve) fn instantiate_constituent_tys_for_sized_trait<'tcx>( } #[instrument(level = "trace", skip(ecx), ret)] -pub(in crate::solve) fn instantiate_constituent_tys_for_copy_clone_trait<'tcx>( - ecx: &EvalCtxt<'_, InferCtxt<'tcx>>, - ty: Ty<'tcx>, -) -> Result>>, NoSolution> { - match *ty.kind() { +pub(in crate::solve) fn instantiate_constituent_tys_for_copy_clone_trait( + ecx: &EvalCtxt<'_, Infcx>, + ty: I::Ty, +) -> Result>, NoSolution> +where + Infcx: InferCtxtLike, + I: Interner, +{ + match ty.kind() { // impl Copy/Clone for FnDef, FnPtr ty::FnDef(..) | ty::FnPtr(_) | ty::Error(_) => Ok(vec![]), @@ -196,11 +211,11 @@ pub(in crate::solve) fn instantiate_constituent_tys_for_copy_clone_trait<'tcx>( ty::Bound(..) | ty::Infer(ty::TyVar(_) | ty::FreshTy(_) | ty::FreshIntTy(_) | ty::FreshFloatTy(_)) => { - bug!("unexpected type `{ty}`") + panic!("unexpected type `{ty:?}`") } // impl Copy/Clone for (T1, T2, .., Tn) where T1: Copy/Clone, T2: Copy/Clone, .. Tn: Copy/Clone - ty::Tuple(tys) => Ok(tys.iter().map(ty::Binder::dummy).collect()), + ty::Tuple(tys) => Ok(tys.into_iter().map(ty::Binder::dummy).collect()), // impl Copy/Clone for Closure where Self::TupledUpvars: Copy/Clone ty::Closure(_, args) => Ok(vec![ty::Binder::dummy(args.as_closure().tupled_upvars_ty())]), @@ -212,7 +227,7 @@ pub(in crate::solve) fn instantiate_constituent_tys_for_copy_clone_trait<'tcx>( ty::Coroutine(def_id, args) => match ecx.interner().coroutine_movability(def_id) { Movability::Static => Err(NoSolution), Movability::Movable => { - if ecx.interner().features().coroutine_clone { + if ecx.interner().features().coroutine_clone() { let coroutine = args.as_coroutine(); Ok(vec![ ty::Binder::dummy(coroutine.tupled_upvars_ty()), @@ -228,27 +243,26 @@ pub(in crate::solve) fn instantiate_constituent_tys_for_copy_clone_trait<'tcx>( ty::CoroutineWitness(def_id, args) => Ok(ecx .interner() .bound_coroutine_hidden_types(def_id) - .map(|bty| bty.instantiate(ecx.interner(), args)) + .into_iter() + .map(|bty| bty.instantiate(ecx.interner(), &args)) .collect()), } } // Returns a binder of the tupled inputs types and output type from a builtin callable type. -pub(in crate::solve) fn extract_tupled_inputs_and_output_from_callable<'tcx>( - tcx: TyCtxt<'tcx>, - self_ty: Ty<'tcx>, +pub(in crate::solve) fn extract_tupled_inputs_and_output_from_callable( + tcx: I, + self_ty: I::Ty, goal_kind: ty::ClosureKind, -) -> Result, Ty<'tcx>)>>, NoSolution> { - match *self_ty.kind() { +) -> Result>, NoSolution> { + match self_ty.kind() { // keep this in sync with assemble_fn_pointer_candidates until the old solver is removed. ty::FnDef(def_id, args) => { let sig = tcx.fn_sig(def_id); - if sig.skip_binder().is_fn_trait_compatible() - && tcx.codegen_fn_attrs(def_id).target_features.is_empty() - { + if sig.skip_binder().is_fn_trait_compatible() && !tcx.has_target_features(def_id) { Ok(Some( - sig.instantiate(tcx, args) - .map_bound(|sig| (Ty::new_tup(tcx, sig.inputs()), sig.output())), + sig.instantiate(tcx, &args) + .map_bound(|sig| (Ty::new_tup(tcx, &sig.inputs()), sig.output())), )) } else { Err(NoSolution) @@ -257,7 +271,7 @@ pub(in crate::solve) fn extract_tupled_inputs_and_output_from_callable<'tcx>( // keep this in sync with assemble_fn_pointer_candidates until the old solver is removed. ty::FnPtr(sig) => { if sig.is_fn_trait_compatible() { - Ok(Some(sig.map_bound(|sig| (Ty::new_tup(tcx, sig.inputs()), sig.output())))) + Ok(Some(sig.map_bound(|sig| (Ty::new_tup(tcx, &sig.inputs()), sig.output())))) } else { Err(NoSolution) } @@ -311,7 +325,7 @@ pub(in crate::solve) fn extract_tupled_inputs_and_output_from_callable<'tcx>( tcx, goal_kind, // No captures by ref, so this doesn't matter. - tcx.lifetimes.re_static, + Region::new_static(tcx), def_id, args, sig, @@ -326,7 +340,7 @@ pub(in crate::solve) fn extract_tupled_inputs_and_output_from_callable<'tcx>( coroutine_closure_to_ambiguous_coroutine( tcx, goal_kind, // No captures by ref, so this doesn't matter. - tcx.lifetimes.re_static, + Region::new_static(tcx), def_id, args, sig, @@ -362,22 +376,24 @@ pub(in crate::solve) fn extract_tupled_inputs_and_output_from_callable<'tcx>( ty::Bound(..) | ty::Infer(ty::TyVar(_) | ty::FreshTy(_) | ty::FreshIntTy(_) | ty::FreshFloatTy(_)) => { - bug!("unexpected type `{self_ty}`") + panic!("unexpected type `{self_ty:?}`") } } } /// Relevant types for an async callable, including its inputs, output, /// and the return type you get from awaiting the output. -#[derive(Copy, Clone, Debug, TypeVisitable, TypeFoldable)] -pub(in crate::solve) struct AsyncCallableRelevantTypes<'tcx> { - pub tupled_inputs_ty: Ty<'tcx>, +#[derive(derivative::Derivative)] +#[derivative(Clone(bound = ""), Copy(bound = ""), Debug(bound = ""))] +#[derive(TypeVisitable_Generic, TypeFoldable_Generic)] +pub(in crate::solve) struct AsyncCallableRelevantTypes { + pub tupled_inputs_ty: I::Ty, /// Type returned by calling the closure /// i.e. `f()`. - pub output_coroutine_ty: Ty<'tcx>, + pub output_coroutine_ty: I::Ty, /// Type returned by `await`ing the output /// i.e. `f().await`. - pub coroutine_return_ty: Ty<'tcx>, + pub coroutine_return_ty: I::Ty, } // Returns a binder of the tupled inputs types, output type, and coroutine type @@ -385,16 +401,13 @@ pub(in crate::solve) struct AsyncCallableRelevantTypes<'tcx> { // the coroutine-closure, emit an additional trait predicate for `AsyncFnKindHelper` // which enforces the closure is actually callable with the given trait. When we // know the kind already, we can short-circuit this check. -pub(in crate::solve) fn extract_tupled_inputs_and_output_from_async_callable<'tcx>( - tcx: TyCtxt<'tcx>, - self_ty: Ty<'tcx>, +pub(in crate::solve) fn extract_tupled_inputs_and_output_from_async_callable( + tcx: I, + self_ty: I::Ty, goal_kind: ty::ClosureKind, - env_region: ty::Region<'tcx>, -) -> Result< - (ty::Binder<'tcx, AsyncCallableRelevantTypes<'tcx>>, Vec>), - NoSolution, -> { - match *self_ty.kind() { + env_region: I::Region, +) -> Result<(ty::Binder>, Vec), NoSolution> { + match self_ty.kind() { ty::CoroutineClosure(def_id, args) => { let args = args.as_coroutine_closure(); let kind_ty = args.kind_ty(); @@ -421,7 +434,7 @@ pub(in crate::solve) fn extract_tupled_inputs_and_output_from_async_callable<'tc nested.push( ty::TraitRef::new( tcx, - tcx.require_lang_item(LangItem::AsyncFnKindHelper, None), + tcx.require_lang_item(TraitSolverLangItem::AsyncFnKindHelper), [kind_ty, Ty::from_closure_kind(tcx, goal_kind)], ) .upcast(tcx), @@ -445,7 +458,7 @@ pub(in crate::solve) fn extract_tupled_inputs_and_output_from_async_callable<'tc ty::FnDef(..) | ty::FnPtr(..) => { let bound_sig = self_ty.fn_sig(tcx); let sig = bound_sig.skip_binder(); - let future_trait_def_id = tcx.require_lang_item(LangItem::Future, None); + let future_trait_def_id = tcx.require_lang_item(TraitSolverLangItem::Future); // `FnDef` and `FnPtr` only implement `AsyncFn*` when their // return type implements `Future`. let nested = vec![ @@ -453,11 +466,11 @@ pub(in crate::solve) fn extract_tupled_inputs_and_output_from_async_callable<'tc .rebind(ty::TraitRef::new(tcx, future_trait_def_id, [sig.output()])) .upcast(tcx), ]; - let future_output_def_id = tcx.require_lang_item(LangItem::FutureOutput, None); + let future_output_def_id = tcx.require_lang_item(TraitSolverLangItem::FutureOutput); let future_output_ty = Ty::new_projection(tcx, future_output_def_id, [sig.output()]); Ok(( bound_sig.rebind(AsyncCallableRelevantTypes { - tupled_inputs_ty: Ty::new_tup(tcx, sig.inputs()), + tupled_inputs_ty: Ty::new_tup(tcx, &sig.inputs()), output_coroutine_ty: sig.output(), coroutine_return_ty: future_output_ty, }), @@ -468,7 +481,7 @@ pub(in crate::solve) fn extract_tupled_inputs_and_output_from_async_callable<'tc let args = args.as_closure(); let bound_sig = args.sig(); let sig = bound_sig.skip_binder(); - let future_trait_def_id = tcx.require_lang_item(LangItem::Future, None); + let future_trait_def_id = tcx.require_lang_item(TraitSolverLangItem::Future); // `Closure`s only implement `AsyncFn*` when their return type // implements `Future`. let mut nested = vec![ @@ -486,7 +499,7 @@ pub(in crate::solve) fn extract_tupled_inputs_and_output_from_async_callable<'tc } } else { let async_fn_kind_trait_def_id = - tcx.require_lang_item(LangItem::AsyncFnKindHelper, None); + tcx.require_lang_item(TraitSolverLangItem::AsyncFnKindHelper); // When we don't know the closure kind (and therefore also the closure's upvars, // which are computed at the same time), we must delay the computation of the // generator's upvars. We do this using the `AsyncFnKindHelper`, which as a trait @@ -504,7 +517,7 @@ pub(in crate::solve) fn extract_tupled_inputs_and_output_from_async_callable<'tc ); } - let future_output_def_id = tcx.require_lang_item(LangItem::FutureOutput, None); + let future_output_def_id = tcx.require_lang_item(TraitSolverLangItem::FutureOutput); let future_output_ty = Ty::new_projection(tcx, future_output_def_id, [sig.output()]); Ok(( bound_sig.rebind(AsyncCallableRelevantTypes { @@ -542,21 +555,21 @@ pub(in crate::solve) fn extract_tupled_inputs_and_output_from_async_callable<'tc ty::Bound(..) | ty::Infer(ty::TyVar(_) | ty::FreshTy(_) | ty::FreshIntTy(_) | ty::FreshFloatTy(_)) => { - bug!("unexpected type `{self_ty}`") + panic!("unexpected type `{self_ty:?}`") } } } /// Given a coroutine-closure, project to its returned coroutine when we are *certain* /// that the closure's kind is compatible with the goal. -fn coroutine_closure_to_certain_coroutine<'tcx>( - tcx: TyCtxt<'tcx>, +fn coroutine_closure_to_certain_coroutine( + tcx: I, goal_kind: ty::ClosureKind, - goal_region: ty::Region<'tcx>, - def_id: DefId, - args: ty::CoroutineClosureArgs>, - sig: ty::CoroutineClosureSignature>, -) -> Ty<'tcx> { + goal_region: I::Region, + def_id: I::DefId, + args: ty::CoroutineClosureArgs, + sig: ty::CoroutineClosureSignature, +) -> I::Ty { sig.to_coroutine_given_kind_and_upvars( tcx, args.parent_args(), @@ -573,20 +586,20 @@ fn coroutine_closure_to_certain_coroutine<'tcx>( /// yet what the closure's upvars are. /// /// Note that we do not also push a `AsyncFnKindHelper` goal here. -fn coroutine_closure_to_ambiguous_coroutine<'tcx>( - tcx: TyCtxt<'tcx>, +fn coroutine_closure_to_ambiguous_coroutine( + tcx: I, goal_kind: ty::ClosureKind, - goal_region: ty::Region<'tcx>, - def_id: DefId, - args: ty::CoroutineClosureArgs>, - sig: ty::CoroutineClosureSignature>, -) -> Ty<'tcx> { - let upvars_projection_def_id = tcx.require_lang_item(LangItem::AsyncFnKindUpvars, None); + goal_region: I::Region, + def_id: I::DefId, + args: ty::CoroutineClosureArgs, + sig: ty::CoroutineClosureSignature, +) -> I::Ty { + let upvars_projection_def_id = tcx.require_lang_item(TraitSolverLangItem::AsyncFnKindUpvars); let tupled_upvars_ty = Ty::new_projection( tcx, upvars_projection_def_id, [ - ty::GenericArg::from(args.kind_ty()), + I::GenericArg::from(args.kind_ty()), Ty::from_closure_kind(tcx, goal_kind).into(), goal_region.into(), sig.tupled_inputs_ty.into(), @@ -643,41 +656,44 @@ fn coroutine_closure_to_ambiguous_coroutine<'tcx>( // This is unsound in general and once that is fixed, we don't need to // normalize eagerly here. See https://github.com/lcnr/solver-woes/issues/9 // for more details. -pub(in crate::solve) fn predicates_for_object_candidate<'tcx>( - ecx: &EvalCtxt<'_, InferCtxt<'tcx>>, - param_env: ty::ParamEnv<'tcx>, - trait_ref: ty::TraitRef<'tcx>, - object_bound: &'tcx ty::List>, -) -> Vec>> { +pub(in crate::solve) fn predicates_for_object_candidate( + ecx: &EvalCtxt<'_, Infcx>, + param_env: I::ParamEnv, + trait_ref: ty::TraitRef, + object_bounds: I::BoundExistentialPredicates, +) -> Vec> +where + Infcx: InferCtxtLike, + I: Interner, +{ let tcx = ecx.interner(); let mut requirements = vec![]; - requirements.extend( - tcx.super_predicates_of(trait_ref.def_id).instantiate(tcx, trait_ref.args).predicates, - ); - for item in tcx.associated_items(trait_ref.def_id).in_definition_order() { - // FIXME(associated_const_equality): Also add associated consts to - // the requirements here. - if item.kind == ty::AssocKind::Type { - // associated types that require `Self: Sized` do not show up in the built-in - // implementation of `Trait for dyn Trait`, and can be dropped here. - if tcx.generics_require_sized_self(item.def_id) { - continue; - } - - requirements - .extend(tcx.item_bounds(item.def_id).iter_instantiated(tcx, trait_ref.args)); + requirements + .extend(tcx.super_predicates_of(trait_ref.def_id).iter_instantiated(tcx, &trait_ref.args)); + + // FIXME(associated_const_equality): Also add associated consts to + // the requirements here. + for associated_type_def_id in tcx.associated_type_def_ids(trait_ref.def_id) { + // associated types that require `Self: Sized` do not show up in the built-in + // implementation of `Trait for dyn Trait`, and can be dropped here. + if tcx.generics_require_sized_self(associated_type_def_id) { + continue; } + + requirements.extend( + tcx.item_bounds(associated_type_def_id).iter_instantiated(tcx, &trait_ref.args), + ); } let mut replace_projection_with = FxHashMap::default(); - for bound in object_bound { + for bound in object_bounds { if let ty::ExistentialPredicate::Projection(proj) = bound.skip_binder() { let proj = proj.with_self_ty(tcx, trait_ref.self_ty()); let old_ty = replace_projection_with.insert(proj.def_id(), bound.rebind(proj)); assert_eq!( old_ty, None, - "{} has two generic parameters: {} and {}", + "{:?} has two generic parameters: {:?} and {:?}", proj.projection_term, proj.term, old_ty.unwrap() @@ -696,20 +712,22 @@ pub(in crate::solve) fn predicates_for_object_candidate<'tcx>( .collect() } -struct ReplaceProjectionWith<'a, 'tcx> { - ecx: &'a EvalCtxt<'a, InferCtxt<'tcx>>, - param_env: ty::ParamEnv<'tcx>, - mapping: FxHashMap>, - nested: Vec>>, +struct ReplaceProjectionWith<'a, Infcx: InferCtxtLike, I: Interner> { + ecx: &'a EvalCtxt<'a, Infcx>, + param_env: I::ParamEnv, + mapping: FxHashMap>>, + nested: Vec>, } -impl<'tcx> TypeFolder> for ReplaceProjectionWith<'_, 'tcx> { - fn interner(&self) -> TyCtxt<'tcx> { +impl, I: Interner> TypeFolder + for ReplaceProjectionWith<'_, Infcx, I> +{ + fn interner(&self) -> I { self.ecx.interner() } - fn fold_ty(&mut self, ty: Ty<'tcx>) -> Ty<'tcx> { - if let ty::Alias(ty::Projection, alias_ty) = *ty.kind() + fn fold_ty(&mut self, ty: I::Ty) -> I::Ty { + if let ty::Alias(ty::Projection, alias_ty) = ty.kind() && let Some(replacement) = self.mapping.get(&alias_ty.def_id) { // We may have a case where our object type's projection bound is higher-ranked, diff --git a/compiler/rustc_trait_selection/src/solve/eval_ctxt/mod.rs b/compiler/rustc_trait_selection/src/solve/eval_ctxt/mod.rs index 43013a01069e5..6b8375b53e8ff 100644 --- a/compiler/rustc_trait_selection/src/solve/eval_ctxt/mod.rs +++ b/compiler/rustc_trait_selection/src/solve/eval_ctxt/mod.rs @@ -1,9 +1,6 @@ use rustc_data_structures::stack::ensure_sufficient_stack; use rustc_hir::def_id::DefId; -use rustc_infer::infer::at::ToTrace; -use rustc_infer::infer::{ - BoundRegionConversionTime, DefineOpaqueTypes, InferCtxt, InferOk, TyCtxtInferExt, -}; +use rustc_infer::infer::{InferCtxt, TyCtxtInferExt}; use rustc_infer::traits::query::NoSolution; use rustc_infer::traits::solve::{MaybeCause, NestedNormalizationGoals}; use rustc_infer::traits::ObligationCause; @@ -15,17 +12,18 @@ use rustc_middle::traits::solve::{ use rustc_middle::ty::AliasRelationDirection; use rustc_middle::ty::TypeFolder; use rustc_middle::ty::{ - self, InferCtxtLike, OpaqueTypeKey, Ty, TyCtxt, TypeFoldable, TypeSuperVisitable, - TypeVisitable, TypeVisitableExt, TypeVisitor, + self, InferCtxtLike, OpaqueTypeKey, Ty, TyCtxt, TypeFoldable, TypeVisitableExt, }; use rustc_span::DUMMY_SP; use rustc_type_ir::fold::TypeSuperFoldable; +use rustc_type_ir::inherent::*; +use rustc_type_ir::relate::Relate; +use rustc_type_ir::visit::{TypeSuperVisitable, TypeVisitable, TypeVisitor}; use rustc_type_ir::{self as ir, CanonicalVarValues, Interner}; use rustc_type_ir_macros::{Lift_Generic, TypeFoldable_Generic, TypeVisitable_Generic}; use std::ops::ControlFlow; use crate::traits::coherence; -use crate::traits::vtable::{count_own_vtable_entries, prepare_vtable_segments, VtblSegment}; use super::inspect::ProofTreeBuilder; use super::{search_graph, GoalEvaluationKind, FIXPOINT_STEP_LIMIT}; @@ -456,28 +454,6 @@ impl<'a, 'tcx> EvalCtxt<'a, InferCtxt<'tcx>> { } } - #[instrument(level = "trace", skip(self))] - pub(super) fn add_normalizes_to_goal(&mut self, mut goal: Goal<'tcx, ty::NormalizesTo<'tcx>>) { - goal.predicate = goal - .predicate - .fold_with(&mut ReplaceAliasWithInfer { ecx: self, param_env: goal.param_env }); - self.inspect.add_normalizes_to_goal(self.infcx, self.max_input_universe, goal); - self.nested_goals.normalizes_to_goals.push(goal); - } - - #[instrument(level = "debug", skip(self))] - pub(super) fn add_goal( - &mut self, - source: GoalSource, - mut goal: Goal<'tcx, ty::Predicate<'tcx>>, - ) { - goal.predicate = goal - .predicate - .fold_with(&mut ReplaceAliasWithInfer { ecx: self, param_env: goal.param_env }); - self.inspect.add_goal(self.infcx, self.max_input_universe, source, goal); - self.nested_goals.goals.push((source, goal)); - } - // Recursively evaluates all the goals added to this `EvalCtxt` to completion, returning // the certainty of all the goals. #[instrument(level = "trace", skip(self))] @@ -600,27 +576,61 @@ impl, I: Interner> EvalCtxt<'_, Infcx> { pub(super) fn interner(&self) -> I { self.infcx.interner() } -} -impl<'tcx> EvalCtxt<'_, InferCtxt<'tcx>> { - pub(super) fn next_ty_infer(&mut self) -> Ty<'tcx> { - let ty = self.infcx.next_ty_var(DUMMY_SP); + #[instrument(level = "trace", skip(self))] + pub(super) fn add_normalizes_to_goal( + &mut self, + mut goal: ir::solve::Goal>, + ) { + goal.predicate = goal + .predicate + .fold_with(&mut ReplaceAliasWithInfer { ecx: self, param_env: goal.param_env }); + self.inspect.add_normalizes_to_goal(self.infcx, self.max_input_universe, goal); + self.nested_goals.normalizes_to_goals.push(goal); + } + + #[instrument(level = "debug", skip(self))] + pub(super) fn add_goal( + &mut self, + source: GoalSource, + mut goal: ir::solve::Goal, + ) { + goal.predicate = goal + .predicate + .fold_with(&mut ReplaceAliasWithInfer { ecx: self, param_env: goal.param_env }); + self.inspect.add_goal(self.infcx, self.max_input_universe, source, goal); + self.nested_goals.goals.push((source, goal)); + } + + #[instrument(level = "trace", skip(self, goals))] + pub(super) fn add_goals( + &mut self, + source: GoalSource, + goals: impl IntoIterator>, + ) { + for goal in goals { + self.add_goal(source, goal); + } + } + + pub(super) fn next_ty_infer(&mut self) -> I::Ty { + let ty = self.infcx.next_ty_infer(); self.inspect.add_var_value(ty); ty } - pub(super) fn next_const_infer(&mut self) -> ty::Const<'tcx> { - let ct = self.infcx.next_const_var(DUMMY_SP); + pub(super) fn next_const_infer(&mut self) -> I::Const { + let ct = self.infcx.next_const_infer(); self.inspect.add_var_value(ct); ct } /// Returns a ty infer or a const infer depending on whether `kind` is a `Ty` or `Const`. /// If `kind` is an integer inference variable this will still return a ty infer var. - pub(super) fn next_term_infer_of_kind(&mut self, kind: ty::Term<'tcx>) -> ty::Term<'tcx> { - match kind.unpack() { - ty::TermKind::Ty(_) => self.next_ty_infer().into(), - ty::TermKind::Const(_) => self.next_const_infer().into(), + pub(super) fn next_term_infer_of_kind(&mut self, kind: I::Term) -> I::Term { + match kind.kind() { + ir::TermKind::Ty(_) => self.next_ty_infer().into(), + ir::TermKind::Const(_) => self.next_const_infer().into(), } } @@ -631,18 +641,18 @@ impl<'tcx> EvalCtxt<'_, InferCtxt<'tcx>> { #[instrument(level = "trace", skip(self), ret)] pub(super) fn term_is_fully_unconstrained( &self, - goal: Goal<'tcx, ty::NormalizesTo<'tcx>>, + goal: ir::solve::Goal>, ) -> bool { - let universe_of_term = match goal.predicate.term.unpack() { - ty::TermKind::Ty(ty) => { - if let &ty::Infer(ty::TyVar(vid)) = ty.kind() { + let universe_of_term = match goal.predicate.term.kind() { + ir::TermKind::Ty(ty) => { + if let ir::Infer(ir::TyVar(vid)) = ty.kind() { self.infcx.universe_of_ty(vid).unwrap() } else { return false; } } - ty::TermKind::Const(ct) => { - if let ty::ConstKind::Infer(ty::InferConst::Var(vid)) = ct.kind() { + ir::TermKind::Const(ct) => { + if let ir::ConstKind::Infer(ir::InferConst::Var(vid)) = ct.kind() { self.infcx.universe_of_ct(vid).unwrap() } else { return false; @@ -650,14 +660,14 @@ impl<'tcx> EvalCtxt<'_, InferCtxt<'tcx>> { } }; - struct ContainsTermOrNotNameable<'a, 'tcx> { - term: ty::Term<'tcx>, - universe_of_term: ty::UniverseIndex, - infcx: &'a InferCtxt<'tcx>, + struct ContainsTermOrNotNameable<'a, Infcx: InferCtxtLike, I: Interner> { + term: I::Term, + universe_of_term: ir::UniverseIndex, + infcx: &'a Infcx, } - impl<'a, 'tcx> ContainsTermOrNotNameable<'a, 'tcx> { - fn check_nameable(&self, universe: ty::UniverseIndex) -> ControlFlow<()> { + impl, I: Interner> ContainsTermOrNotNameable<'_, Infcx, I> { + fn check_nameable(&self, universe: ir::UniverseIndex) -> ControlFlow<()> { if self.universe_of_term.can_name(universe) { ControlFlow::Continue(()) } else { @@ -666,21 +676,23 @@ impl<'tcx> EvalCtxt<'_, InferCtxt<'tcx>> { } } - impl<'tcx> TypeVisitor> for ContainsTermOrNotNameable<'_, 'tcx> { + impl, I: Interner> TypeVisitor + for ContainsTermOrNotNameable<'_, Infcx, I> + { type Result = ControlFlow<()>; - fn visit_ty(&mut self, t: Ty<'tcx>) -> Self::Result { - match *t.kind() { - ty::Infer(ty::TyVar(vid)) => { - if let ty::TermKind::Ty(term) = self.term.unpack() - && let Some(term_vid) = term.ty_vid() - && self.infcx.root_var(vid) == self.infcx.root_var(term_vid) + fn visit_ty(&mut self, t: I::Ty) -> Self::Result { + match t.kind() { + ir::Infer(ir::TyVar(vid)) => { + if let ir::TermKind::Ty(term) = self.term.kind() + && let ir::Infer(ir::TyVar(term_vid)) = term.kind() + && self.infcx.root_ty_var(vid) == self.infcx.root_ty_var(term_vid) { ControlFlow::Break(()) } else { self.check_nameable(self.infcx.universe_of_ty(vid).unwrap()) } } - ty::Placeholder(p) => self.check_nameable(p.universe), + ir::Placeholder(p) => self.check_nameable(p.universe()), _ => { if t.has_non_region_infer() || t.has_placeholders() { t.super_visit_with(self) @@ -691,11 +703,11 @@ impl<'tcx> EvalCtxt<'_, InferCtxt<'tcx>> { } } - fn visit_const(&mut self, c: ty::Const<'tcx>) -> Self::Result { + fn visit_const(&mut self, c: I::Const) -> Self::Result { match c.kind() { - ty::ConstKind::Infer(ty::InferConst::Var(vid)) => { - if let ty::TermKind::Const(term) = self.term.unpack() - && let ty::ConstKind::Infer(ty::InferConst::Var(term_vid)) = term.kind() + ir::ConstKind::Infer(ir::InferConst::Var(vid)) => { + if let ir::TermKind::Const(term) = self.term.kind() + && let ir::ConstKind::Infer(ir::InferConst::Var(term_vid)) = term.kind() && self.infcx.root_const_var(vid) == self.infcx.root_const_var(term_vid) { ControlFlow::Break(()) @@ -703,7 +715,7 @@ impl<'tcx> EvalCtxt<'_, InferCtxt<'tcx>> { self.check_nameable(self.infcx.universe_of_ct(vid).unwrap()) } } - ty::ConstKind::Placeholder(p) => self.check_nameable(p.universe), + ir::ConstKind::Placeholder(p) => self.check_nameable(p.universe()), _ => { if c.has_non_region_infer() || c.has_placeholders() { c.super_visit_with(self) @@ -725,23 +737,13 @@ impl<'tcx> EvalCtxt<'_, InferCtxt<'tcx>> { } #[instrument(level = "trace", skip(self, param_env), ret)] - pub(super) fn eq>( + pub(super) fn eq>( &mut self, - param_env: ty::ParamEnv<'tcx>, + param_env: I::ParamEnv, lhs: T, rhs: T, ) -> Result<(), NoSolution> { - self.infcx - .at(&ObligationCause::dummy(), param_env) - // New solver ignores DefineOpaqueTypes, so choose Yes for consistency - .eq(DefineOpaqueTypes::Yes, lhs, rhs) - .map(|InferOk { value: (), obligations }| { - self.add_goals(GoalSource::Misc, obligations.into_iter().map(|o| o.into())); - }) - .map_err(|e| { - trace!(?e, "failed to equate"); - NoSolution - }) + self.relate(param_env, lhs, ir::Variance::Invariant, rhs) } /// This should be used when relating a rigid alias with another type. @@ -752,10 +754,10 @@ impl<'tcx> EvalCtxt<'_, InferCtxt<'tcx>> { #[instrument(level = "trace", skip(self, param_env), ret)] pub(super) fn relate_rigid_alias_non_alias( &mut self, - param_env: ty::ParamEnv<'tcx>, - alias: ty::AliasTerm<'tcx>, - variance: ty::Variance, - term: ty::Term<'tcx>, + param_env: I::ParamEnv, + alias: ir::AliasTerm, + variance: ir::Variance, + term: I::Term, ) -> Result<(), NoSolution> { // NOTE: this check is purely an optimization, the structural eq would // always fail if the term is not an inference variable. @@ -770,12 +772,10 @@ impl<'tcx> EvalCtxt<'_, InferCtxt<'tcx>> { // Alternatively we could modify `Equate` for this case by adding another // variant to `StructurallyRelateAliases`. let identity_args = self.fresh_args_for_item(alias.def_id); - let rigid_ctor = ty::AliasTerm::new(tcx, alias.def_id, identity_args); + let rigid_ctor = ir::AliasTerm::new(tcx, alias.def_id, identity_args); let ctor_term = rigid_ctor.to_term(tcx); - let InferOk { value: (), obligations } = self - .infcx - .at(&ObligationCause::dummy(), param_env) - .eq_structurally_relating_aliases(term, ctor_term)?; + let obligations = + self.infcx.eq_structurally_relating_aliases(param_env, term, ctor_term)?; debug_assert!(obligations.is_empty()); self.relate(param_env, alias, variance, rigid_ctor) } else { @@ -787,58 +787,38 @@ impl<'tcx> EvalCtxt<'_, InferCtxt<'tcx>> { /// unconstrained "return value" or when we're sure that all aliases in /// the types are rigid. #[instrument(level = "trace", skip(self, param_env), ret)] - pub(super) fn eq_structurally_relating_aliases>( + pub(super) fn eq_structurally_relating_aliases>( &mut self, - param_env: ty::ParamEnv<'tcx>, + param_env: I::ParamEnv, lhs: T, rhs: T, ) -> Result<(), NoSolution> { - let cause = ObligationCause::dummy(); - let InferOk { value: (), obligations } = - self.infcx.at(&cause, param_env).eq_structurally_relating_aliases(lhs, rhs)?; - assert!(obligations.is_empty()); + let result = self.infcx.eq_structurally_relating_aliases(param_env, lhs, rhs)?; + assert_eq!(result, vec![]); Ok(()) } #[instrument(level = "trace", skip(self, param_env), ret)] - pub(super) fn sub>( + pub(super) fn sub>( &mut self, - param_env: ty::ParamEnv<'tcx>, + param_env: I::ParamEnv, sub: T, sup: T, ) -> Result<(), NoSolution> { - self.infcx - .at(&ObligationCause::dummy(), param_env) - // New solver ignores DefineOpaqueTypes, so choose Yes for consistency - .sub(DefineOpaqueTypes::Yes, sub, sup) - .map(|InferOk { value: (), obligations }| { - self.add_goals(GoalSource::Misc, obligations.into_iter().map(|o| o.into())); - }) - .map_err(|e| { - trace!(?e, "failed to subtype"); - NoSolution - }) + self.relate(param_env, sub, ir::Variance::Covariant, sup) } #[instrument(level = "trace", skip(self, param_env), ret)] - pub(super) fn relate>( + pub(super) fn relate>( &mut self, - param_env: ty::ParamEnv<'tcx>, + param_env: I::ParamEnv, lhs: T, - variance: ty::Variance, + variance: ir::Variance, rhs: T, ) -> Result<(), NoSolution> { - self.infcx - .at(&ObligationCause::dummy(), param_env) - // New solver ignores DefineOpaqueTypes, so choose Yes for consistency - .relate(DefineOpaqueTypes::Yes, lhs, variance, rhs) - .map(|InferOk { value: (), obligations }| { - self.add_goals(GoalSource::Misc, obligations.into_iter().map(|o| o.into())); - }) - .map_err(|e| { - trace!(?e, "failed to relate"); - NoSolution - }) + let goals = self.infcx.relate(param_env, lhs, variance, rhs)?; + self.add_goals(GoalSource::Misc, goals); + Ok(()) } /// Equates two values returning the nested goals without adding them @@ -847,58 +827,47 @@ impl<'tcx> EvalCtxt<'_, InferCtxt<'tcx>> { /// If possible, try using `eq` instead which automatically handles nested /// goals correctly. #[instrument(level = "trace", skip(self, param_env), ret)] - pub(super) fn eq_and_get_goals>( + pub(super) fn eq_and_get_goals>( &self, - param_env: ty::ParamEnv<'tcx>, + param_env: I::ParamEnv, lhs: T, rhs: T, - ) -> Result>>, NoSolution> { - self.infcx - .at(&ObligationCause::dummy(), param_env) - // New solver ignores DefineOpaqueTypes, so choose Yes for consistency - .eq(DefineOpaqueTypes::Yes, lhs, rhs) - .map(|InferOk { value: (), obligations }| { - obligations.into_iter().map(|o| o.into()).collect() - }) - .map_err(|e| { - trace!(?e, "failed to equate"); - NoSolution - }) + ) -> Result>, NoSolution> { + self.infcx.relate(param_env, lhs, ir::Variance::Invariant, rhs) } - pub(super) fn instantiate_binder_with_infer> + Copy>( + pub(super) fn instantiate_binder_with_infer + Copy>( &self, - value: ty::Binder<'tcx, T>, + value: ir::Binder, ) -> T { - self.infcx.instantiate_binder_with_fresh_vars( - DUMMY_SP, - BoundRegionConversionTime::HigherRankedType, - value, - ) + self.infcx.instantiate_binder_with_infer(value) } - pub(super) fn enter_forall> + Copy, U>( + pub(super) fn enter_forall + Copy, U>( &self, - value: ty::Binder<'tcx, T>, + value: ir::Binder, f: impl FnOnce(T) -> U, ) -> U { self.infcx.enter_forall(value, f) } + pub(super) fn resolve_vars_if_possible(&self, value: T) -> T where - T: TypeFoldable>, + T: TypeFoldable, { self.infcx.resolve_vars_if_possible(value) } - pub(super) fn fresh_args_for_item(&mut self, def_id: DefId) -> ty::GenericArgsRef<'tcx> { - let args = self.infcx.fresh_args_for_item(DUMMY_SP, def_id); + pub(super) fn fresh_args_for_item(&mut self, def_id: I::DefId) -> I::GenericArgs { + let args = self.infcx.fresh_args_for_item(def_id); for arg in args { self.inspect.add_var_value(arg); } args } +} +impl<'tcx> EvalCtxt<'_, InferCtxt<'tcx>> { pub(super) fn register_ty_outlives(&self, ty: Ty<'tcx>, lt: ty::Region<'tcx>) { self.infcx.register_region_obligation_with_cause(ty, lt, &ObligationCause::dummy()); } @@ -1052,41 +1021,6 @@ impl<'tcx> EvalCtxt<'_, InferCtxt<'tcx>> { } } } - - /// Walk through the vtable of a principal trait ref, executing a `supertrait_visitor` - /// for every trait ref encountered (including the principal). Passes both the vtable - /// base and the (optional) vptr slot. - pub(super) fn walk_vtable( - &mut self, - principal: ty::PolyTraitRef<'tcx>, - mut supertrait_visitor: impl FnMut(&mut Self, ty::PolyTraitRef<'tcx>, usize, Option), - ) { - let tcx = self.interner(); - let mut offset = 0; - prepare_vtable_segments::<()>(tcx, principal, |segment| { - match segment { - VtblSegment::MetadataDSA => { - offset += TyCtxt::COMMON_VTABLE_ENTRIES.len(); - } - VtblSegment::TraitOwnEntries { trait_ref, emit_vptr } => { - let own_vtable_entries = count_own_vtable_entries(tcx, trait_ref); - - supertrait_visitor( - self, - trait_ref, - offset, - emit_vptr.then(|| offset + own_vtable_entries), - ); - - offset += own_vtable_entries; - if emit_vptr { - offset += 1; - } - } - } - ControlFlow::Continue(()) - }); - } } /// Eagerly replace aliases with inference variables, emitting `AliasRelate` @@ -1096,28 +1030,36 @@ impl<'tcx> EvalCtxt<'_, InferCtxt<'tcx>> { /// /// This is a performance optimization to more eagerly detect cycles during trait /// solving. See tests/ui/traits/next-solver/cycles/cycle-modulo-ambig-aliases.rs. -struct ReplaceAliasWithInfer<'me, 'a, 'tcx> { - ecx: &'me mut EvalCtxt<'a, InferCtxt<'tcx>>, - param_env: ty::ParamEnv<'tcx>, +struct ReplaceAliasWithInfer<'me, 'a, Infcx, I> +where + Infcx: InferCtxtLike, + I: Interner, +{ + ecx: &'me mut EvalCtxt<'a, Infcx>, + param_env: I::ParamEnv, } -impl<'tcx> TypeFolder> for ReplaceAliasWithInfer<'_, '_, 'tcx> { - fn interner(&self) -> TyCtxt<'tcx> { +impl TypeFolder for ReplaceAliasWithInfer<'_, '_, Infcx, I> +where + Infcx: InferCtxtLike, + I: Interner, +{ + fn interner(&self) -> I { self.ecx.interner() } - fn fold_ty(&mut self, ty: Ty<'tcx>) -> Ty<'tcx> { - match *ty.kind() { - ty::Alias(..) if !ty.has_escaping_bound_vars() => { + fn fold_ty(&mut self, ty: I::Ty) -> I::Ty { + match ty.kind() { + ir::Alias(..) if !ty.has_escaping_bound_vars() => { let infer_ty = self.ecx.next_ty_infer(); - let normalizes_to = ty::PredicateKind::AliasRelate( + let normalizes_to = ir::PredicateKind::AliasRelate( ty.into(), infer_ty.into(), AliasRelationDirection::Equate, ); self.ecx.add_goal( GoalSource::Misc, - Goal::new(self.interner(), self.param_env, normalizes_to), + ir::solve::Goal::new(self.interner(), self.param_env, normalizes_to), ); infer_ty } @@ -1125,18 +1067,18 @@ impl<'tcx> TypeFolder> for ReplaceAliasWithInfer<'_, '_, 'tcx> { } } - fn fold_const(&mut self, ct: ty::Const<'tcx>) -> ty::Const<'tcx> { + fn fold_const(&mut self, ct: I::Const) -> I::Const { match ct.kind() { - ty::ConstKind::Unevaluated(..) if !ct.has_escaping_bound_vars() => { + ir::ConstKind::Unevaluated(..) if !ct.has_escaping_bound_vars() => { let infer_ct = self.ecx.next_const_infer(); - let normalizes_to = ty::PredicateKind::AliasRelate( + let normalizes_to = ir::PredicateKind::AliasRelate( ct.into(), infer_ct.into(), AliasRelationDirection::Equate, ); self.ecx.add_goal( GoalSource::Misc, - Goal::new(self.interner(), self.param_env, normalizes_to), + ir::solve::Goal::new(self.interner(), self.param_env, normalizes_to), ); infer_ct } @@ -1144,7 +1086,7 @@ impl<'tcx> TypeFolder> for ReplaceAliasWithInfer<'_, '_, 'tcx> { } } - fn fold_predicate(&mut self, predicate: ty::Predicate<'tcx>) -> ty::Predicate<'tcx> { + fn fold_predicate(&mut self, predicate: I::Predicate) -> I::Predicate { if predicate.allow_normalization() { predicate.super_fold_with(self) } else { predicate } } } diff --git a/compiler/rustc_trait_selection/src/solve/eval_ctxt/probe.rs b/compiler/rustc_trait_selection/src/solve/eval_ctxt/probe.rs index 1748c9be9275e..ad6fdd2707de2 100644 --- a/compiler/rustc_trait_selection/src/solve/eval_ctxt/probe.rs +++ b/compiler/rustc_trait_selection/src/solve/eval_ctxt/probe.rs @@ -1,27 +1,29 @@ use crate::solve::assembly::Candidate; use super::EvalCtxt; -use rustc_infer::infer::InferCtxt; -use rustc_infer::traits::BuiltinImplSource; -use rustc_middle::traits::query::NoSolution; -use rustc_middle::traits::solve::{inspect, CandidateSource, QueryResult}; -use rustc_middle::ty::TyCtxt; +use rustc_next_trait_solver::solve::{ + inspect, BuiltinImplSource, CandidateSource, NoSolution, QueryResult, +}; +use rustc_type_ir::{InferCtxtLike, Interner}; use std::marker::PhantomData; -pub(in crate::solve) struct ProbeCtxt<'me, 'a, 'tcx, F, T> { - ecx: &'me mut EvalCtxt<'a, InferCtxt<'tcx>>, +pub(in crate::solve) struct ProbeCtxt<'me, 'a, Infcx, I, F, T> +where + Infcx: InferCtxtLike, + I: Interner, +{ + ecx: &'me mut EvalCtxt<'a, Infcx, I>, probe_kind: F, _result: PhantomData, } -impl<'tcx, F, T> ProbeCtxt<'_, '_, 'tcx, F, T> +impl ProbeCtxt<'_, '_, Infcx, I, F, T> where - F: FnOnce(&T) -> inspect::ProbeKind>, + F: FnOnce(&T) -> inspect::ProbeKind, + Infcx: InferCtxtLike, + I: Interner, { - pub(in crate::solve) fn enter( - self, - f: impl FnOnce(&mut EvalCtxt<'_, InferCtxt<'tcx>>) -> T, - ) -> T { + pub(in crate::solve) fn enter(self, f: impl FnOnce(&mut EvalCtxt<'_, Infcx>) -> T) -> T { let ProbeCtxt { ecx: outer_ecx, probe_kind, _result } = self; let infcx = outer_ecx.infcx; @@ -38,7 +40,7 @@ where tainted: outer_ecx.tainted, inspect: outer_ecx.inspect.take_and_enter_probe(), }; - let r = nested_ecx.infcx.probe(|_| { + let r = nested_ecx.infcx.probe(|| { let r = f(&mut nested_ecx); nested_ecx.inspect.probe_final_state(infcx, max_input_universe); r @@ -52,30 +54,43 @@ where } } -pub(in crate::solve) struct TraitProbeCtxt<'me, 'a, 'tcx, F> { - cx: ProbeCtxt<'me, 'a, 'tcx, F, QueryResult<'tcx>>, - source: CandidateSource<'tcx>, +pub(in crate::solve) struct TraitProbeCtxt<'me, 'a, Infcx, I, F> +where + Infcx: InferCtxtLike, + I: Interner, +{ + cx: ProbeCtxt<'me, 'a, Infcx, I, F, QueryResult>, + source: CandidateSource, } -impl<'tcx, F> TraitProbeCtxt<'_, '_, 'tcx, F> +impl TraitProbeCtxt<'_, '_, Infcx, I, F> where - F: FnOnce(&QueryResult<'tcx>) -> inspect::ProbeKind>, + Infcx: InferCtxtLike, + I: Interner, + F: FnOnce(&QueryResult) -> inspect::ProbeKind, { #[instrument(level = "debug", skip_all, fields(source = ?self.source))] pub(in crate::solve) fn enter( self, - f: impl FnOnce(&mut EvalCtxt<'_, InferCtxt<'tcx>>) -> QueryResult<'tcx>, - ) -> Result, NoSolution> { + f: impl FnOnce(&mut EvalCtxt<'_, Infcx>) -> QueryResult, + ) -> Result, NoSolution> { self.cx.enter(|ecx| f(ecx)).map(|result| Candidate { source: self.source, result }) } } -impl<'a, 'tcx> EvalCtxt<'a, InferCtxt<'tcx>> { +impl<'a, Infcx, I> EvalCtxt<'a, Infcx, I> +where + Infcx: InferCtxtLike, + I: Interner, +{ /// `probe_kind` is only called when proof tree building is enabled so it can be /// as expensive as necessary to output the desired information. - pub(in crate::solve) fn probe(&mut self, probe_kind: F) -> ProbeCtxt<'_, 'a, 'tcx, F, T> + pub(in crate::solve) fn probe( + &mut self, + probe_kind: F, + ) -> ProbeCtxt<'_, 'a, Infcx, I, F, T> where - F: FnOnce(&T) -> inspect::ProbeKind>, + F: FnOnce(&T) -> inspect::ProbeKind, { ProbeCtxt { ecx: self, probe_kind, _result: PhantomData } } @@ -83,28 +98,20 @@ impl<'a, 'tcx> EvalCtxt<'a, InferCtxt<'tcx>> { pub(in crate::solve) fn probe_builtin_trait_candidate( &mut self, source: BuiltinImplSource, - ) -> TraitProbeCtxt< - '_, - 'a, - 'tcx, - impl FnOnce(&QueryResult<'tcx>) -> inspect::ProbeKind>, - > { + ) -> TraitProbeCtxt<'_, 'a, Infcx, I, impl FnOnce(&QueryResult) -> inspect::ProbeKind> + { self.probe_trait_candidate(CandidateSource::BuiltinImpl(source)) } pub(in crate::solve) fn probe_trait_candidate( &mut self, - source: CandidateSource<'tcx>, - ) -> TraitProbeCtxt< - '_, - 'a, - 'tcx, - impl FnOnce(&QueryResult<'tcx>) -> inspect::ProbeKind>, - > { + source: CandidateSource, + ) -> TraitProbeCtxt<'_, 'a, Infcx, I, impl FnOnce(&QueryResult) -> inspect::ProbeKind> + { TraitProbeCtxt { cx: ProbeCtxt { ecx: self, - probe_kind: move |result: &QueryResult<'tcx>| inspect::ProbeKind::TraitCandidate { + probe_kind: move |result: &QueryResult| inspect::ProbeKind::TraitCandidate { source, result: *result, }, diff --git a/compiler/rustc_trait_selection/src/solve/eval_ctxt/select.rs b/compiler/rustc_trait_selection/src/solve/eval_ctxt/select.rs index 68c0c8bf09eac..257fd263b9447 100644 --- a/compiler/rustc_trait_selection/src/solve/eval_ctxt/select.rs +++ b/compiler/rustc_trait_selection/src/solve/eval_ctxt/select.rs @@ -114,8 +114,8 @@ fn candidate_should_be_dropped_in_favor_of<'tcx>( // In the old trait solver, we arbitrarily choose lower vtable candidates // over higher ones. ( - CandidateSource::BuiltinImpl(BuiltinImplSource::Object { vtable_base: a }), - CandidateSource::BuiltinImpl(BuiltinImplSource::Object { vtable_base: b }), + CandidateSource::BuiltinImpl(BuiltinImplSource::Object(a)), + CandidateSource::BuiltinImpl(BuiltinImplSource::Object(b)), ) => a >= b, // Prefer dyn candidates over non-dyn candidates. This is necessary to // handle the unsoundness between `impl Any for T` and `dyn Any: Any`. diff --git a/compiler/rustc_trait_selection/src/solve/fulfill.rs b/compiler/rustc_trait_selection/src/solve/fulfill.rs index dc13941e5d7b5..3c01d1a65f506 100644 --- a/compiler/rustc_trait_selection/src/solve/fulfill.rs +++ b/compiler/rustc_trait_selection/src/solve/fulfill.rs @@ -460,9 +460,10 @@ impl<'tcx> ProofTreeVisitor<'tcx> for BestObligation<'tcx> { polarity: ty::PredicatePolarity::Positive, })) } - ty::PredicateKind::Clause(ty::ClauseKind::WellFormed(_)) => { - ChildMode::WellFormedObligation - } + ty::PredicateKind::Clause( + ty::ClauseKind::WellFormed(_) | ty::ClauseKind::Projection(..), + ) + | ty::PredicateKind::AliasRelate(..) => ChildMode::PassThrough, _ => { return ControlFlow::Break(self.obligation.clone()); } @@ -496,7 +497,7 @@ impl<'tcx> ProofTreeVisitor<'tcx> for BestObligation<'tcx> { (_, GoalSource::InstantiateHigherRanked) => { obligation = self.obligation.clone(); } - (ChildMode::WellFormedObligation, _) => { + (ChildMode::PassThrough, _) => { obligation = make_obligation(self.obligation.cause.clone()); } } @@ -514,6 +515,32 @@ impl<'tcx> ProofTreeVisitor<'tcx> for BestObligation<'tcx> { self.with_derived_obligation(obligation, |this| nested_goal.visit_with(this))?; } + // alias-relate may fail because the lhs or rhs can't be normalized, + // and therefore is treated as rigid. + if let Some(ty::PredicateKind::AliasRelate(lhs, rhs, _)) = pred_kind.no_bound_vars() { + if let Some(obligation) = goal + .infcx() + .visit_proof_tree_at_depth( + goal.goal().with(goal.infcx().tcx, ty::ClauseKind::WellFormed(lhs.into())), + goal.depth() + 1, + self, + ) + .break_value() + { + return ControlFlow::Break(obligation); + } else if let Some(obligation) = goal + .infcx() + .visit_proof_tree_at_depth( + goal.goal().with(goal.infcx().tcx, ty::ClauseKind::WellFormed(rhs.into())), + goal.depth() + 1, + self, + ) + .break_value() + { + return ControlFlow::Break(obligation); + } + } + ControlFlow::Break(self.obligation.clone()) } } @@ -527,7 +554,7 @@ enum ChildMode<'tcx> { // Skip trying to derive an `ObligationCause` from this obligation, and // report *all* sub-obligations as if they came directly from the parent // obligation. - WellFormedObligation, + PassThrough, } fn derive_cause<'tcx>( diff --git a/compiler/rustc_trait_selection/src/solve/inspect/analyse.rs b/compiler/rustc_trait_selection/src/solve/inspect/analyse.rs index 19c95dad48cb5..464c188b6e325 100644 --- a/compiler/rustc_trait_selection/src/solve/inspect/analyse.rs +++ b/compiler/rustc_trait_selection/src/solve/inspect/analyse.rs @@ -15,7 +15,7 @@ use rustc_infer::infer::{DefineOpaqueTypes, InferCtxt, InferOk}; use rustc_macros::extension; use rustc_middle::traits::query::NoSolution; use rustc_middle::traits::solve::{inspect, QueryResult}; -use rustc_middle::traits::solve::{Certainty, Goal}; +use rustc_middle::traits::solve::{Certainty, Goal, MaybeCause}; use rustc_middle::traits::ObligationCause; use rustc_middle::ty::{TyCtxt, TypeFoldable}; use rustc_middle::{bug, ty}; @@ -278,6 +278,10 @@ impl<'a, 'tcx> InspectGoal<'a, 'tcx> { self.source } + pub fn depth(&self) -> usize { + self.depth + } + fn candidates_recur( &'a self, candidates: &mut Vec>, @@ -291,7 +295,10 @@ impl<'a, 'tcx> InspectGoal<'a, 'tcx> { steps.push(step) } inspect::ProbeStep::MakeCanonicalResponse { shallow_certainty: c } => { - assert_eq!(shallow_certainty.replace(c), None); + assert!(matches!( + shallow_certainty.replace(c), + None | Some(Certainty::Maybe(MaybeCause::Ambiguity)) + )); } inspect::ProbeStep::NestedProbe(ref probe) => { match probe.kind { @@ -432,9 +439,18 @@ impl<'tcx> InferCtxt<'tcx> { &self, goal: Goal<'tcx, ty::Predicate<'tcx>>, visitor: &mut V, + ) -> V::Result { + self.visit_proof_tree_at_depth(goal, 0, visitor) + } + + fn visit_proof_tree_at_depth>( + &self, + goal: Goal<'tcx, ty::Predicate<'tcx>>, + depth: usize, + visitor: &mut V, ) -> V::Result { let (_, proof_tree) = self.evaluate_root_goal(goal, GenerateProofTree::Yes); let proof_tree = proof_tree.unwrap(); - visitor.visit_goal(&InspectGoal::new(self, 0, proof_tree, None, GoalSource::Misc)) + visitor.visit_goal(&InspectGoal::new(self, depth, proof_tree, None, GoalSource::Misc)) } } diff --git a/compiler/rustc_trait_selection/src/solve/inspect/build.rs b/compiler/rustc_trait_selection/src/solve/inspect/build.rs index 84c04900ae484..35750598bc740 100644 --- a/compiler/rustc_trait_selection/src/solve/inspect/build.rs +++ b/compiler/rustc_trait_selection/src/solve/inspect/build.rs @@ -34,10 +34,11 @@ use rustc_type_ir::{self as ty, InferCtxtLike, Interner}; /// trees. At the end of trait solving `ProofTreeBuilder::finalize` /// is called to recursively convert the whole structure to a /// finished proof tree. -pub(in crate::solve) struct ProofTreeBuilder< +pub(in crate::solve) struct ProofTreeBuilder::Interner> +where Infcx: InferCtxtLike, - I: Interner = ::Interner, -> { + I: Interner, +{ _infcx: PhantomData, state: Option>>, } diff --git a/compiler/rustc_trait_selection/src/solve/mod.rs b/compiler/rustc_trait_selection/src/solve/mod.rs index c47b01949641b..fdcf4ff11e468 100644 --- a/compiler/rustc_trait_selection/src/solve/mod.rs +++ b/compiler/rustc_trait_selection/src/solve/mod.rs @@ -235,17 +235,6 @@ impl<'a, 'tcx> EvalCtxt<'a, InferCtxt<'tcx>> { } impl<'tcx> EvalCtxt<'_, InferCtxt<'tcx>> { - #[instrument(level = "trace", skip(self, goals))] - fn add_goals( - &mut self, - source: GoalSource, - goals: impl IntoIterator>>, - ) { - for goal in goals { - self.add_goal(source, goal); - } - } - /// Try to merge multiple possible ways to prove a goal, if that is not possible returns `None`. /// /// In this case we tend to flounder and return ambiguity by calling `[EvalCtxt::flounder]`. diff --git a/compiler/rustc_trait_selection/src/solve/normalizes_to/mod.rs b/compiler/rustc_trait_selection/src/solve/normalizes_to/mod.rs index 787f08a084ee6..60a15392e0bee 100644 --- a/compiler/rustc_trait_selection/src/solve/normalizes_to/mod.rs +++ b/compiler/rustc_trait_selection/src/solve/normalizes_to/mod.rs @@ -17,7 +17,7 @@ use rustc_middle::ty::NormalizesTo; use rustc_middle::ty::{self, Ty, TyCtxt}; use rustc_middle::ty::{TypeVisitableExt, Upcast}; use rustc_middle::{bug, span_bug}; -use rustc_span::{sym, ErrorGuaranteed, DUMMY_SP}; +use rustc_span::{ErrorGuaranteed, DUMMY_SP}; mod anon_const; mod inherent; @@ -40,7 +40,7 @@ impl<'tcx> EvalCtxt<'_, InferCtxt<'tcx>> { Ok(res) => Ok(res), Err(NoSolution) => { let Goal { param_env, predicate: NormalizesTo { alias, term } } = goal; - self.relate_rigid_alias_non_alias(param_env, alias, ty::Variance::Invariant, term)?; + self.relate_rigid_alias_non_alias(param_env, alias, ty::Invariant, term)?; self.evaluate_added_goals_and_make_canonical_response(Certainty::Yes) } } @@ -103,7 +103,7 @@ impl<'tcx> assembly::GoalKind<'tcx> for NormalizesTo<'tcx> { goal: Goal<'tcx, Self>, assumption: ty::Clause<'tcx>, then: impl FnOnce(&mut EvalCtxt<'_, InferCtxt<'tcx>>) -> QueryResult<'tcx>, - ) -> Result, NoSolution> { + ) -> Result>, NoSolution> { if let Some(projection_pred) = assumption.as_projection_clause() { if projection_pred.projection_def_id() == goal.predicate.def_id() { let tcx = ecx.interner(); @@ -140,7 +140,7 @@ impl<'tcx> assembly::GoalKind<'tcx> for NormalizesTo<'tcx> { ecx: &mut EvalCtxt<'_, InferCtxt<'tcx>>, goal: Goal<'tcx, NormalizesTo<'tcx>>, impl_def_id: DefId, - ) -> Result, NoSolution> { + ) -> Result>, NoSolution> { let tcx = ecx.interner(); let goal_trait_ref = goal.predicate.alias.trait_ref(tcx); @@ -267,14 +267,14 @@ impl<'tcx> assembly::GoalKind<'tcx> for NormalizesTo<'tcx> { fn consider_error_guaranteed_candidate( _ecx: &mut EvalCtxt<'_, InferCtxt<'tcx>>, _guar: ErrorGuaranteed, - ) -> Result, NoSolution> { + ) -> Result>, NoSolution> { Err(NoSolution) } fn consider_auto_trait_candidate( ecx: &mut EvalCtxt<'_, InferCtxt<'tcx>>, goal: Goal<'tcx, Self>, - ) -> Result, NoSolution> { + ) -> Result>, NoSolution> { ecx.interner().dcx().span_delayed_bug( ecx.interner().def_span(goal.predicate.def_id()), "associated types not allowed on auto traits", @@ -285,35 +285,35 @@ impl<'tcx> assembly::GoalKind<'tcx> for NormalizesTo<'tcx> { fn consider_trait_alias_candidate( _ecx: &mut EvalCtxt<'_, InferCtxt<'tcx>>, goal: Goal<'tcx, Self>, - ) -> Result, NoSolution> { + ) -> Result>, NoSolution> { bug!("trait aliases do not have associated types: {:?}", goal); } fn consider_builtin_sized_candidate( _ecx: &mut EvalCtxt<'_, InferCtxt<'tcx>>, goal: Goal<'tcx, Self>, - ) -> Result, NoSolution> { + ) -> Result>, NoSolution> { bug!("`Sized` does not have an associated type: {:?}", goal); } fn consider_builtin_copy_clone_candidate( _ecx: &mut EvalCtxt<'_, InferCtxt<'tcx>>, goal: Goal<'tcx, Self>, - ) -> Result, NoSolution> { + ) -> Result>, NoSolution> { bug!("`Copy`/`Clone` does not have an associated type: {:?}", goal); } fn consider_builtin_pointer_like_candidate( _ecx: &mut EvalCtxt<'_, InferCtxt<'tcx>>, goal: Goal<'tcx, Self>, - ) -> Result, NoSolution> { + ) -> Result>, NoSolution> { bug!("`PointerLike` does not have an associated type: {:?}", goal); } fn consider_builtin_fn_ptr_trait_candidate( _ecx: &mut EvalCtxt<'_, InferCtxt<'tcx>>, goal: Goal<'tcx, Self>, - ) -> Result, NoSolution> { + ) -> Result>, NoSolution> { bug!("`FnPtr` does not have an associated type: {:?}", goal); } @@ -321,7 +321,7 @@ impl<'tcx> assembly::GoalKind<'tcx> for NormalizesTo<'tcx> { ecx: &mut EvalCtxt<'_, InferCtxt<'tcx>>, goal: Goal<'tcx, Self>, goal_kind: ty::ClosureKind, - ) -> Result, NoSolution> { + ) -> Result>, NoSolution> { let tcx = ecx.interner(); let tupled_inputs_and_output = match structural_traits::extract_tupled_inputs_and_output_from_callable( @@ -364,7 +364,7 @@ impl<'tcx> assembly::GoalKind<'tcx> for NormalizesTo<'tcx> { ecx: &mut EvalCtxt<'_, InferCtxt<'tcx>>, goal: Goal<'tcx, Self>, goal_kind: ty::ClosureKind, - ) -> Result, NoSolution> { + ) -> Result>, NoSolution> { let tcx = ecx.interner(); let env_region = match goal_kind { @@ -392,9 +392,8 @@ impl<'tcx> assembly::GoalKind<'tcx> for NormalizesTo<'tcx> { output_coroutine_ty, coroutine_return_ty, }| { - let lang_items = tcx.lang_items(); - let (projection_term, term) = if Some(goal.predicate.def_id()) - == lang_items.call_once_future() + let (projection_term, term) = if tcx + .is_lang_item(goal.predicate.def_id(), LangItem::CallOnceFuture) { ( ty::AliasTerm::new( @@ -404,7 +403,7 @@ impl<'tcx> assembly::GoalKind<'tcx> for NormalizesTo<'tcx> { ), output_coroutine_ty.into(), ) - } else if Some(goal.predicate.def_id()) == lang_items.call_ref_future() { + } else if tcx.is_lang_item(goal.predicate.def_id(), LangItem::CallRefFuture) { ( ty::AliasTerm::new( tcx, @@ -417,7 +416,8 @@ impl<'tcx> assembly::GoalKind<'tcx> for NormalizesTo<'tcx> { ), output_coroutine_ty.into(), ) - } else if Some(goal.predicate.def_id()) == lang_items.async_fn_once_output() { + } else if tcx.is_lang_item(goal.predicate.def_id(), LangItem::AsyncFnOnceOutput) + { ( ty::AliasTerm::new( tcx, @@ -454,7 +454,7 @@ impl<'tcx> assembly::GoalKind<'tcx> for NormalizesTo<'tcx> { fn consider_builtin_async_fn_kind_helper_candidate( ecx: &mut EvalCtxt<'_, InferCtxt<'tcx>>, goal: Goal<'tcx, Self>, - ) -> Result, NoSolution> { + ) -> Result>, NoSolution> { let [ closure_fn_kind_ty, goal_kind_ty, @@ -501,14 +501,14 @@ impl<'tcx> assembly::GoalKind<'tcx> for NormalizesTo<'tcx> { fn consider_builtin_tuple_candidate( _ecx: &mut EvalCtxt<'_, InferCtxt<'tcx>>, goal: Goal<'tcx, Self>, - ) -> Result, NoSolution> { + ) -> Result>, NoSolution> { bug!("`Tuple` does not have an associated type: {:?}", goal); } fn consider_builtin_pointee_candidate( ecx: &mut EvalCtxt<'_, InferCtxt<'tcx>>, goal: Goal<'tcx, Self>, - ) -> Result, NoSolution> { + ) -> Result>, NoSolution> { let tcx = ecx.interner(); let metadata_def_id = tcx.require_lang_item(LangItem::Metadata, None); assert_eq!(metadata_def_id, goal.predicate.def_id()); @@ -590,7 +590,7 @@ impl<'tcx> assembly::GoalKind<'tcx> for NormalizesTo<'tcx> { fn consider_builtin_future_candidate( ecx: &mut EvalCtxt<'_, InferCtxt<'tcx>>, goal: Goal<'tcx, Self>, - ) -> Result, NoSolution> { + ) -> Result>, NoSolution> { let self_ty = goal.predicate.self_ty(); let ty::Coroutine(def_id, args) = *self_ty.kind() else { return Err(NoSolution); @@ -626,7 +626,7 @@ impl<'tcx> assembly::GoalKind<'tcx> for NormalizesTo<'tcx> { fn consider_builtin_iterator_candidate( ecx: &mut EvalCtxt<'_, InferCtxt<'tcx>>, goal: Goal<'tcx, Self>, - ) -> Result, NoSolution> { + ) -> Result>, NoSolution> { let self_ty = goal.predicate.self_ty(); let ty::Coroutine(def_id, args) = *self_ty.kind() else { return Err(NoSolution); @@ -662,14 +662,14 @@ impl<'tcx> assembly::GoalKind<'tcx> for NormalizesTo<'tcx> { fn consider_builtin_fused_iterator_candidate( _ecx: &mut EvalCtxt<'_, InferCtxt<'tcx>>, goal: Goal<'tcx, Self>, - ) -> Result, NoSolution> { + ) -> Result>, NoSolution> { bug!("`FusedIterator` does not have an associated type: {:?}", goal); } fn consider_builtin_async_iterator_candidate( ecx: &mut EvalCtxt<'_, InferCtxt<'tcx>>, goal: Goal<'tcx, Self>, - ) -> Result, NoSolution> { + ) -> Result>, NoSolution> { let self_ty = goal.predicate.self_ty(); let ty::Coroutine(def_id, args) = *self_ty.kind() else { return Err(NoSolution); @@ -705,7 +705,7 @@ impl<'tcx> assembly::GoalKind<'tcx> for NormalizesTo<'tcx> { fn consider_builtin_coroutine_candidate( ecx: &mut EvalCtxt<'_, InferCtxt<'tcx>>, goal: Goal<'tcx, Self>, - ) -> Result, NoSolution> { + ) -> Result>, NoSolution> { let self_ty = goal.predicate.self_ty(); let ty::Coroutine(def_id, args) = *self_ty.kind() else { return Err(NoSolution); @@ -719,13 +719,15 @@ impl<'tcx> assembly::GoalKind<'tcx> for NormalizesTo<'tcx> { let coroutine = args.as_coroutine(); - let name = tcx.associated_item(goal.predicate.def_id()).name; - let term = if name == sym::Return { + let term = if tcx.is_lang_item(goal.predicate.def_id(), LangItem::CoroutineReturn) { coroutine.return_ty().into() - } else if name == sym::Yield { + } else if tcx.is_lang_item(goal.predicate.def_id(), LangItem::CoroutineYield) { coroutine.yield_ty().into() } else { - bug!("unexpected associated item `<{self_ty} as Coroutine>::{name}`") + bug!( + "unexpected associated item `<{self_ty} as Coroutine>::{}`", + tcx.item_name(goal.predicate.def_id()) + ) }; Self::probe_and_consider_implied_clause( @@ -750,14 +752,14 @@ impl<'tcx> assembly::GoalKind<'tcx> for NormalizesTo<'tcx> { fn consider_structural_builtin_unsize_candidates( _ecx: &mut EvalCtxt<'_, InferCtxt<'tcx>>, goal: Goal<'tcx, Self>, - ) -> Vec> { + ) -> Vec>> { bug!("`Unsize` does not have an associated type: {:?}", goal); } fn consider_builtin_discriminant_kind_candidate( ecx: &mut EvalCtxt<'_, InferCtxt<'tcx>>, goal: Goal<'tcx, Self>, - ) -> Result, NoSolution> { + ) -> Result>, NoSolution> { let self_ty = goal.predicate.self_ty(); let discriminant_ty = match *self_ty.kind() { ty::Bool @@ -809,7 +811,7 @@ impl<'tcx> assembly::GoalKind<'tcx> for NormalizesTo<'tcx> { fn consider_builtin_async_destruct_candidate( ecx: &mut EvalCtxt<'_, InferCtxt<'tcx>>, goal: Goal<'tcx, Self>, - ) -> Result, NoSolution> { + ) -> Result>, NoSolution> { let self_ty = goal.predicate.self_ty(); let async_destructor_ty = match *self_ty.kind() { ty::Bool @@ -862,14 +864,14 @@ impl<'tcx> assembly::GoalKind<'tcx> for NormalizesTo<'tcx> { fn consider_builtin_destruct_candidate( _ecx: &mut EvalCtxt<'_, InferCtxt<'tcx>>, goal: Goal<'tcx, Self>, - ) -> Result, NoSolution> { + ) -> Result>, NoSolution> { bug!("`Destruct` does not have an associated type: {:?}", goal); } fn consider_builtin_transmute_candidate( _ecx: &mut EvalCtxt<'_, InferCtxt<'tcx>>, goal: Goal<'tcx, Self>, - ) -> Result, NoSolution> { + ) -> Result>, NoSolution> { bug!("`BikeshedIntrinsicFrom` does not have an associated type: {:?}", goal) } } diff --git a/compiler/rustc_trait_selection/src/solve/trait_goals.rs b/compiler/rustc_trait_selection/src/solve/trait_goals.rs index a741f488901eb..bcb2ea18f78ec 100644 --- a/compiler/rustc_trait_selection/src/solve/trait_goals.rs +++ b/compiler/rustc_trait_selection/src/solve/trait_goals.rs @@ -9,6 +9,7 @@ use rustc_hir::{LangItem, Movability}; use rustc_infer::infer::InferCtxt; use rustc_infer::traits::query::NoSolution; use rustc_infer::traits::solve::MaybeCause; +use rustc_infer::traits::util::supertraits; use rustc_middle::bug; use rustc_middle::traits::solve::inspect::ProbeKind; use rustc_middle::traits::solve::{CandidateSource, Certainty, Goal, QueryResult}; @@ -39,7 +40,7 @@ impl<'tcx> assembly::GoalKind<'tcx> for TraitPredicate<'tcx> { ecx: &mut EvalCtxt<'_, InferCtxt<'tcx>>, goal: Goal<'tcx, TraitPredicate<'tcx>>, impl_def_id: DefId, - ) -> Result, NoSolution> { + ) -> Result>, NoSolution> { let tcx = ecx.interner(); let impl_trait_header = tcx.impl_trait_header(impl_def_id).unwrap(); @@ -94,7 +95,7 @@ impl<'tcx> assembly::GoalKind<'tcx> for TraitPredicate<'tcx> { fn consider_error_guaranteed_candidate( ecx: &mut EvalCtxt<'_, InferCtxt<'tcx>>, _guar: ErrorGuaranteed, - ) -> Result, NoSolution> { + ) -> Result>, NoSolution> { // FIXME: don't need to enter a probe here. ecx.probe_builtin_trait_candidate(BuiltinImplSource::Misc) .enter(|ecx| ecx.evaluate_added_goals_and_make_canonical_response(Certainty::Yes)) @@ -106,7 +107,7 @@ impl<'tcx> assembly::GoalKind<'tcx> for TraitPredicate<'tcx> { goal: Goal<'tcx, Self>, assumption: ty::Clause<'tcx>, then: impl FnOnce(&mut EvalCtxt<'_, InferCtxt<'tcx>>) -> QueryResult<'tcx>, - ) -> Result, NoSolution> { + ) -> Result>, NoSolution> { if let Some(trait_clause) = assumption.as_trait_clause() { if trait_clause.def_id() == goal.predicate.def_id() && trait_clause.polarity() == goal.predicate.polarity @@ -131,7 +132,7 @@ impl<'tcx> assembly::GoalKind<'tcx> for TraitPredicate<'tcx> { fn consider_auto_trait_candidate( ecx: &mut EvalCtxt<'_, InferCtxt<'tcx>>, goal: Goal<'tcx, Self>, - ) -> Result, NoSolution> { + ) -> Result>, NoSolution> { if goal.predicate.polarity != ty::PredicatePolarity::Positive { return Err(NoSolution); } @@ -174,7 +175,7 @@ impl<'tcx> assembly::GoalKind<'tcx> for TraitPredicate<'tcx> { fn consider_trait_alias_candidate( ecx: &mut EvalCtxt<'_, InferCtxt<'tcx>>, goal: Goal<'tcx, Self>, - ) -> Result, NoSolution> { + ) -> Result>, NoSolution> { if goal.predicate.polarity != ty::PredicatePolarity::Positive { return Err(NoSolution); } @@ -197,7 +198,7 @@ impl<'tcx> assembly::GoalKind<'tcx> for TraitPredicate<'tcx> { fn consider_builtin_sized_candidate( ecx: &mut EvalCtxt<'_, InferCtxt<'tcx>>, goal: Goal<'tcx, Self>, - ) -> Result, NoSolution> { + ) -> Result>, NoSolution> { if goal.predicate.polarity != ty::PredicatePolarity::Positive { return Err(NoSolution); } @@ -212,7 +213,7 @@ impl<'tcx> assembly::GoalKind<'tcx> for TraitPredicate<'tcx> { fn consider_builtin_copy_clone_candidate( ecx: &mut EvalCtxt<'_, InferCtxt<'tcx>>, goal: Goal<'tcx, Self>, - ) -> Result, NoSolution> { + ) -> Result>, NoSolution> { if goal.predicate.polarity != ty::PredicatePolarity::Positive { return Err(NoSolution); } @@ -227,7 +228,7 @@ impl<'tcx> assembly::GoalKind<'tcx> for TraitPredicate<'tcx> { fn consider_builtin_pointer_like_candidate( ecx: &mut EvalCtxt<'_, InferCtxt<'tcx>>, goal: Goal<'tcx, Self>, - ) -> Result, NoSolution> { + ) -> Result>, NoSolution> { if goal.predicate.polarity != ty::PredicatePolarity::Positive { return Err(NoSolution); } @@ -257,7 +258,7 @@ impl<'tcx> assembly::GoalKind<'tcx> for TraitPredicate<'tcx> { fn consider_builtin_fn_ptr_trait_candidate( ecx: &mut EvalCtxt<'_, InferCtxt<'tcx>>, goal: Goal<'tcx, Self>, - ) -> Result, NoSolution> { + ) -> Result>, NoSolution> { let self_ty = goal.predicate.self_ty(); match goal.predicate.polarity { // impl FnPtr for FnPtr {} @@ -289,7 +290,7 @@ impl<'tcx> assembly::GoalKind<'tcx> for TraitPredicate<'tcx> { ecx: &mut EvalCtxt<'_, InferCtxt<'tcx>>, goal: Goal<'tcx, Self>, goal_kind: ty::ClosureKind, - ) -> Result, NoSolution> { + ) -> Result>, NoSolution> { if goal.predicate.polarity != ty::PredicatePolarity::Positive { return Err(NoSolution); } @@ -330,7 +331,7 @@ impl<'tcx> assembly::GoalKind<'tcx> for TraitPredicate<'tcx> { ecx: &mut EvalCtxt<'_, InferCtxt<'tcx>>, goal: Goal<'tcx, Self>, goal_kind: ty::ClosureKind, - ) -> Result, NoSolution> { + ) -> Result>, NoSolution> { if goal.predicate.polarity != ty::PredicatePolarity::Positive { return Err(NoSolution); } @@ -380,7 +381,7 @@ impl<'tcx> assembly::GoalKind<'tcx> for TraitPredicate<'tcx> { fn consider_builtin_async_fn_kind_helper_candidate( ecx: &mut EvalCtxt<'_, InferCtxt<'tcx>>, goal: Goal<'tcx, Self>, - ) -> Result, NoSolution> { + ) -> Result>, NoSolution> { let [closure_fn_kind_ty, goal_kind_ty] = **goal.predicate.trait_ref.args else { bug!(); }; @@ -407,7 +408,7 @@ impl<'tcx> assembly::GoalKind<'tcx> for TraitPredicate<'tcx> { fn consider_builtin_tuple_candidate( ecx: &mut EvalCtxt<'_, InferCtxt<'tcx>>, goal: Goal<'tcx, Self>, - ) -> Result, NoSolution> { + ) -> Result>, NoSolution> { if goal.predicate.polarity != ty::PredicatePolarity::Positive { return Err(NoSolution); } @@ -423,7 +424,7 @@ impl<'tcx> assembly::GoalKind<'tcx> for TraitPredicate<'tcx> { fn consider_builtin_pointee_candidate( ecx: &mut EvalCtxt<'_, InferCtxt<'tcx>>, goal: Goal<'tcx, Self>, - ) -> Result, NoSolution> { + ) -> Result>, NoSolution> { if goal.predicate.polarity != ty::PredicatePolarity::Positive { return Err(NoSolution); } @@ -435,7 +436,7 @@ impl<'tcx> assembly::GoalKind<'tcx> for TraitPredicate<'tcx> { fn consider_builtin_future_candidate( ecx: &mut EvalCtxt<'_, InferCtxt<'tcx>>, goal: Goal<'tcx, Self>, - ) -> Result, NoSolution> { + ) -> Result>, NoSolution> { if goal.predicate.polarity != ty::PredicatePolarity::Positive { return Err(NoSolution); } @@ -461,7 +462,7 @@ impl<'tcx> assembly::GoalKind<'tcx> for TraitPredicate<'tcx> { fn consider_builtin_iterator_candidate( ecx: &mut EvalCtxt<'_, InferCtxt<'tcx>>, goal: Goal<'tcx, Self>, - ) -> Result, NoSolution> { + ) -> Result>, NoSolution> { if goal.predicate.polarity != ty::PredicatePolarity::Positive { return Err(NoSolution); } @@ -487,7 +488,7 @@ impl<'tcx> assembly::GoalKind<'tcx> for TraitPredicate<'tcx> { fn consider_builtin_fused_iterator_candidate( ecx: &mut EvalCtxt<'_, InferCtxt<'tcx>>, goal: Goal<'tcx, Self>, - ) -> Result, NoSolution> { + ) -> Result>, NoSolution> { if goal.predicate.polarity != ty::PredicatePolarity::Positive { return Err(NoSolution); } @@ -511,7 +512,7 @@ impl<'tcx> assembly::GoalKind<'tcx> for TraitPredicate<'tcx> { fn consider_builtin_async_iterator_candidate( ecx: &mut EvalCtxt<'_, InferCtxt<'tcx>>, goal: Goal<'tcx, Self>, - ) -> Result, NoSolution> { + ) -> Result>, NoSolution> { if goal.predicate.polarity != ty::PredicatePolarity::Positive { return Err(NoSolution); } @@ -537,7 +538,7 @@ impl<'tcx> assembly::GoalKind<'tcx> for TraitPredicate<'tcx> { fn consider_builtin_coroutine_candidate( ecx: &mut EvalCtxt<'_, InferCtxt<'tcx>>, goal: Goal<'tcx, Self>, - ) -> Result, NoSolution> { + ) -> Result>, NoSolution> { if goal.predicate.polarity != ty::PredicatePolarity::Positive { return Err(NoSolution); } @@ -569,7 +570,7 @@ impl<'tcx> assembly::GoalKind<'tcx> for TraitPredicate<'tcx> { fn consider_builtin_discriminant_kind_candidate( ecx: &mut EvalCtxt<'_, InferCtxt<'tcx>>, goal: Goal<'tcx, Self>, - ) -> Result, NoSolution> { + ) -> Result>, NoSolution> { if goal.predicate.polarity != ty::PredicatePolarity::Positive { return Err(NoSolution); } @@ -582,7 +583,7 @@ impl<'tcx> assembly::GoalKind<'tcx> for TraitPredicate<'tcx> { fn consider_builtin_async_destruct_candidate( ecx: &mut EvalCtxt<'_, InferCtxt<'tcx>>, goal: Goal<'tcx, Self>, - ) -> Result, NoSolution> { + ) -> Result>, NoSolution> { if goal.predicate.polarity != ty::PredicatePolarity::Positive { return Err(NoSolution); } @@ -595,7 +596,7 @@ impl<'tcx> assembly::GoalKind<'tcx> for TraitPredicate<'tcx> { fn consider_builtin_destruct_candidate( ecx: &mut EvalCtxt<'_, InferCtxt<'tcx>>, goal: Goal<'tcx, Self>, - ) -> Result, NoSolution> { + ) -> Result>, NoSolution> { if goal.predicate.polarity != ty::PredicatePolarity::Positive { return Err(NoSolution); } @@ -611,7 +612,7 @@ impl<'tcx> assembly::GoalKind<'tcx> for TraitPredicate<'tcx> { fn consider_builtin_transmute_candidate( ecx: &mut EvalCtxt<'_, InferCtxt<'tcx>>, goal: Goal<'tcx, Self>, - ) -> Result, NoSolution> { + ) -> Result>, NoSolution> { if goal.predicate.polarity != ty::PredicatePolarity::Positive { return Err(NoSolution); } @@ -652,7 +653,7 @@ impl<'tcx> assembly::GoalKind<'tcx> for TraitPredicate<'tcx> { fn consider_structural_builtin_unsize_candidates( ecx: &mut EvalCtxt<'_, InferCtxt<'tcx>>, goal: Goal<'tcx, Self>, - ) -> Vec> { + ) -> Vec>> { if goal.predicate.polarity != ty::PredicatePolarity::Positive { return vec![]; } @@ -738,7 +739,7 @@ impl<'tcx> EvalCtxt<'_, InferCtxt<'tcx>> { a_region: ty::Region<'tcx>, b_data: &'tcx ty::List>, b_region: ty::Region<'tcx>, - ) -> Vec> { + ) -> Vec>> { let tcx = self.interner(); let Goal { predicate: (a_ty, _b_ty), .. } = goal; @@ -756,24 +757,19 @@ impl<'tcx> EvalCtxt<'_, InferCtxt<'tcx>> { a_data.principal(), )); } else if let Some(a_principal) = a_data.principal() { - self.walk_vtable( - a_principal.with_self_ty(tcx, a_ty), - |ecx, new_a_principal, _, vtable_vptr_slot| { - responses.extend(ecx.consider_builtin_upcast_to_principal( - goal, - CandidateSource::BuiltinImpl(BuiltinImplSource::TraitUpcasting { - vtable_vptr_slot, - }), - a_data, - a_region, - b_data, - b_region, - Some(new_a_principal.map_bound(|trait_ref| { - ty::ExistentialTraitRef::erase_self_ty(tcx, trait_ref) - })), - )); - }, - ); + for new_a_principal in supertraits(tcx, a_principal.with_self_ty(tcx, a_ty)).skip(1) { + responses.extend(self.consider_builtin_upcast_to_principal( + goal, + CandidateSource::BuiltinImpl(BuiltinImplSource::TraitUpcasting), + a_data, + a_region, + b_data, + b_region, + Some(new_a_principal.map_bound(|trait_ref| { + ty::ExistentialTraitRef::erase_self_ty(tcx, trait_ref) + })), + )); + } } responses @@ -784,7 +780,7 @@ impl<'tcx> EvalCtxt<'_, InferCtxt<'tcx>> { goal: Goal<'tcx, (Ty<'tcx>, Ty<'tcx>)>, b_data: &'tcx ty::List>, b_region: ty::Region<'tcx>, - ) -> Result, NoSolution> { + ) -> Result>, NoSolution> { let tcx = self.interner(); let Goal { predicate: (a_ty, _), .. } = goal; @@ -802,14 +798,13 @@ impl<'tcx> EvalCtxt<'_, InferCtxt<'tcx>> { ); // The type must be `Sized` to be unsized. - if let Some(sized_def_id) = tcx.lang_items().sized_trait() { - ecx.add_goal( - GoalSource::ImplWhereBound, - goal.with(tcx, ty::TraitRef::new(tcx, sized_def_id, [a_ty])), - ); - } else { - return Err(NoSolution); - } + ecx.add_goal( + GoalSource::ImplWhereBound, + goal.with( + tcx, + ty::TraitRef::new(tcx, tcx.require_lang_item(LangItem::Sized, None), [a_ty]), + ), + ); // The type must outlive the lifetime of the `dyn` we're unsizing into. ecx.add_goal(GoalSource::Misc, goal.with(tcx, ty::OutlivesPredicate(a_ty, b_region))); @@ -826,7 +821,7 @@ impl<'tcx> EvalCtxt<'_, InferCtxt<'tcx>> { b_data: &'tcx ty::List>, b_region: ty::Region<'tcx>, upcast_principal: Option>, - ) -> Result, NoSolution> { + ) -> Result>, NoSolution> { let param_env = goal.param_env; // We may upcast to auto traits that are either explicitly listed in @@ -929,7 +924,7 @@ impl<'tcx> EvalCtxt<'_, InferCtxt<'tcx>> { goal: Goal<'tcx, (Ty<'tcx>, Ty<'tcx>)>, a_elem_ty: Ty<'tcx>, b_elem_ty: Ty<'tcx>, - ) -> Result, NoSolution> { + ) -> Result>, NoSolution> { self.eq(goal.param_env, a_elem_ty, b_elem_ty)?; self.probe_builtin_trait_candidate(BuiltinImplSource::Misc) .enter(|ecx| ecx.evaluate_added_goals_and_make_canonical_response(Certainty::Yes)) @@ -954,7 +949,7 @@ impl<'tcx> EvalCtxt<'_, InferCtxt<'tcx>> { def: ty::AdtDef<'tcx>, a_args: ty::GenericArgsRef<'tcx>, b_args: ty::GenericArgsRef<'tcx>, - ) -> Result, NoSolution> { + ) -> Result>, NoSolution> { let tcx = self.interner(); let Goal { predicate: (_a_ty, b_ty), .. } = goal; @@ -991,7 +986,7 @@ impl<'tcx> EvalCtxt<'_, InferCtxt<'tcx>> { tcx, ty::TraitRef::new( tcx, - tcx.lang_items().unsize_trait().unwrap(), + tcx.require_lang_item(LangItem::Unsize, None), [a_tail_ty, b_tail_ty], ), ), @@ -1015,7 +1010,7 @@ impl<'tcx> EvalCtxt<'_, InferCtxt<'tcx>> { goal: Goal<'tcx, (Ty<'tcx>, Ty<'tcx>)>, a_tys: &'tcx ty::List>, b_tys: &'tcx ty::List>, - ) -> Result, NoSolution> { + ) -> Result>, NoSolution> { let tcx = self.interner(); let Goal { predicate: (_a_ty, b_ty), .. } = goal; @@ -1034,7 +1029,7 @@ impl<'tcx> EvalCtxt<'_, InferCtxt<'tcx>> { tcx, ty::TraitRef::new( tcx, - tcx.lang_items().unsize_trait().unwrap(), + tcx.require_lang_item(LangItem::Unsize, None), [a_last_ty, b_last_ty], ), ), @@ -1050,7 +1045,7 @@ impl<'tcx> EvalCtxt<'_, InferCtxt<'tcx>> { fn disqualify_auto_trait_candidate_due_to_possible_impl( &mut self, goal: Goal<'tcx, TraitPredicate<'tcx>>, - ) -> Option, NoSolution>> { + ) -> Option>, NoSolution>> { let self_ty = goal.predicate.self_ty(); match *self_ty.kind() { // Stall int and float vars until they are resolved to a concrete @@ -1076,7 +1071,7 @@ impl<'tcx> EvalCtxt<'_, InferCtxt<'tcx>> { // takes precedence over the structural auto trait candidate being // assembled. ty::Coroutine(def_id, _) - if Some(goal.predicate.def_id()) == self.interner().lang_items().unpin_trait() => + if self.interner().is_lang_item(goal.predicate.def_id(), LangItem::Unpin) => { match self.interner().coroutine_movability(def_id) { Movability::Static => Some(Err(NoSolution)), @@ -1155,7 +1150,7 @@ impl<'tcx> EvalCtxt<'_, InferCtxt<'tcx>> { &EvalCtxt<'_, InferCtxt<'tcx>>, Ty<'tcx>, ) -> Result>>, NoSolution>, - ) -> Result, NoSolution> { + ) -> Result>, NoSolution> { self.probe_trait_candidate(source).enter(|ecx| { ecx.add_goals( GoalSource::ImplWhereBound, diff --git a/compiler/rustc_trait_selection/src/traits/coherence.rs b/compiler/rustc_trait_selection/src/traits/coherence.rs index fc5c71252e1c4..a4177d8a93f47 100644 --- a/compiler/rustc_trait_selection/src/traits/coherence.rs +++ b/compiler/rustc_trait_selection/src/traits/coherence.rs @@ -769,8 +769,8 @@ pub struct UncoveredTyParams<'tcx, T> { /// add "non-blanket" impls without breaking negative reasoning in dependent /// crates. This is the "rebalancing coherence" (RFC 1023) restriction. /// -/// For that, we only a allow crate to perform negative reasoning on -/// non-local-non-`#[fundamental]` only if there's a local key parameter as per (2). +/// For that, we only allow a crate to perform negative reasoning on +/// non-local-non-`#[fundamental]` if there's a local key parameter as per (2). /// /// Because we never perform negative reasoning generically (coherence does /// not involve type parameters), this can be interpreted as doing the full diff --git a/compiler/rustc_trait_selection/src/traits/error_reporting/suggestions.rs b/compiler/rustc_trait_selection/src/traits/error_reporting/suggestions.rs index 087f7fbea00b3..f632f1ad4f260 100644 --- a/compiler/rustc_trait_selection/src/traits/error_reporting/suggestions.rs +++ b/compiler/rustc_trait_selection/src/traits/error_reporting/suggestions.rs @@ -794,7 +794,7 @@ impl<'tcx> TypeErrCtxt<'_, 'tcx> { if let ty::PredicateKind::Clause(ty::ClauseKind::Trait(trait_pred)) = obligation.predicate.kind().skip_binder() - && Some(trait_pred.def_id()) == self.tcx.lang_items().sized_trait() + && self.tcx.is_lang_item(trait_pred.def_id(), LangItem::Sized) { // Don't suggest calling to turn an unsized type into a sized type return false; @@ -1106,7 +1106,7 @@ impl<'tcx> TypeErrCtxt<'_, 'tcx> { .iter() .find_map(|pred| { if let ty::ClauseKind::Projection(proj) = pred.kind().skip_binder() - && Some(proj.projection_term.def_id) == self.tcx.lang_items().fn_once_output() + && self.tcx.is_lang_item(proj.projection_term.def_id,LangItem::FnOnceOutput) // args tuple will always be args[1] && let ty::Tuple(args) = proj.projection_term.args.type_at(1).kind() { @@ -1123,7 +1123,7 @@ impl<'tcx> TypeErrCtxt<'_, 'tcx> { ty::Dynamic(data, _, ty::Dyn) => { data.iter().find_map(|pred| { if let ty::ExistentialPredicate::Projection(proj) = pred.skip_binder() - && Some(proj.def_id) == self.tcx.lang_items().fn_once_output() + && self.tcx.is_lang_item(proj.def_id, LangItem::FnOnceOutput) // for existential projection, args are shifted over by 1 && let ty::Tuple(args) = proj.args.type_at(0).kind() { @@ -1150,7 +1150,7 @@ impl<'tcx> TypeErrCtxt<'_, 'tcx> { }; param_env.caller_bounds().iter().find_map(|pred| { if let ty::ClauseKind::Projection(proj) = pred.kind().skip_binder() - && Some(proj.projection_term.def_id) == self.tcx.lang_items().fn_once_output() + && self.tcx.is_lang_item(proj.projection_term.def_id, LangItem::FnOnceOutput) && proj.projection_term.self_ty() == found // args tuple will always be args[1] && let ty::Tuple(args) = proj.projection_term.args.type_at(1).kind() @@ -1822,7 +1822,7 @@ impl<'tcx> TypeErrCtxt<'_, 'tcx> { && box_path .res .opt_def_id() - .is_some_and(|def_id| Some(def_id) == self.tcx.lang_items().owned_box()) + .is_some_and(|def_id| self.tcx.is_lang_item(def_id, LangItem::OwnedBox)) { // Don't box `Box::new` vec![] @@ -2737,7 +2737,7 @@ impl<'tcx> TypeErrCtxt<'_, 'tcx> { | ObligationCauseCode::ObjectTypeBound(..) => {} ObligationCauseCode::RustCall => { if let Some(pred) = predicate.as_trait_clause() - && Some(pred.def_id()) == tcx.lang_items().sized_trait() + && tcx.is_lang_item(pred.def_id(), LangItem::Sized) { err.note("argument required to be sized due to `extern \"rust-call\"` ABI"); } @@ -2790,7 +2790,7 @@ impl<'tcx> TypeErrCtxt<'_, 'tcx> { // Check for foreign traits being reachable. tcx.visible_parent_map(()).get(&def_id).is_some() }; - if Some(def_id) == tcx.lang_items().sized_trait() { + if tcx.is_lang_item(def_id, LangItem::Sized) { // Check if this is an implicit bound, even in foreign crates. if tcx .generics_of(item_def_id) @@ -3597,7 +3597,7 @@ impl<'tcx> TypeErrCtxt<'_, 'tcx> { &self, obligation: &PredicateObligation<'tcx>, err: &mut Diag<'_>, - trait_ref: &ty::PolyTraitRef<'tcx>, + trait_ref: ty::PolyTraitRef<'tcx>, ) { let rhs_span = match obligation.cause.code() { ObligationCauseCode::BinOp { rhs_span: Some(span), rhs_is_lit, .. } if *rhs_is_lit => { @@ -4592,7 +4592,7 @@ impl<'tcx> TypeErrCtxt<'_, 'tcx> { &self, obligation: &PredicateObligation<'tcx>, err: &mut Diag<'_>, - trait_ref: ty::PolyTraitRef<'tcx>, + trait_pred: ty::PolyTraitPredicate<'tcx>, ) { if ObligationCauseCode::QuestionMark != *obligation.cause.code().peel_derives() { return; @@ -4602,10 +4602,9 @@ impl<'tcx> TypeErrCtxt<'_, 'tcx> { if let hir::Node::Item(item) = node && let hir::ItemKind::Fn(sig, _, body_id) = item.kind && let hir::FnRetTy::DefaultReturn(ret_span) = sig.decl.output - && self.tcx.is_diagnostic_item(sym::FromResidual, trait_ref.def_id()) - && let ty::Tuple(l) = trait_ref.skip_binder().args.type_at(0).kind() - && l.len() == 0 - && let ty::Adt(def, _) = trait_ref.skip_binder().args.type_at(1).kind() + && self.tcx.is_diagnostic_item(sym::FromResidual, trait_pred.def_id()) + && trait_pred.skip_binder().trait_ref.args.type_at(0).is_unit() + && let ty::Adt(def, _) = trait_pred.skip_binder().trait_ref.args.type_at(1).kind() && self.tcx.is_diagnostic_item(sym::Result, def.did()) { let body = self.tcx.hir().body(body_id); @@ -4863,14 +4862,13 @@ impl<'a, 'hir> hir::intravisit::Visitor<'hir> for ReplaceImplTraitVisitor<'a> { pub(super) fn get_explanation_based_on_obligation<'tcx>( tcx: TyCtxt<'tcx>, obligation: &PredicateObligation<'tcx>, - trait_ref: ty::PolyTraitRef<'tcx>, - trait_predicate: &ty::PolyTraitPredicate<'tcx>, + trait_predicate: ty::PolyTraitPredicate<'tcx>, pre_message: String, ) -> String { if let ObligationCauseCode::MainFunctionType = obligation.cause.code() { "consider using `()`, or a `Result`".to_owned() } else { - let ty_desc = match trait_ref.skip_binder().self_ty().kind() { + let ty_desc = match trait_predicate.self_ty().skip_binder().kind() { ty::FnDef(_, _) => Some("fn item"), ty::Closure(_, _) => Some("closure"), _ => None, @@ -4895,7 +4893,7 @@ pub(super) fn get_explanation_based_on_obligation<'tcx>( format!( "{pre_message}the trait `{}` is not implemented for{desc} `{}`{post}", trait_predicate.print_modifiers_and_trait_path(), - tcx.short_ty_string(trait_ref.skip_binder().self_ty(), &mut None), + tcx.short_ty_string(trait_predicate.self_ty().skip_binder(), &mut None), ) } else { // "the trait bound `T: !Send` is not satisfied" reads better than "`!Send` is diff --git a/compiler/rustc_trait_selection/src/traits/error_reporting/type_err_ctxt_ext.rs b/compiler/rustc_trait_selection/src/traits/error_reporting/type_err_ctxt_ext.rs index 6b6438a7887e5..e38f795119772 100644 --- a/compiler/rustc_trait_selection/src/traits/error_reporting/type_err_ctxt_ext.rs +++ b/compiler/rustc_trait_selection/src/traits/error_reporting/type_err_ctxt_ext.rs @@ -24,10 +24,10 @@ use rustc_data_structures::unord::UnordSet; use rustc_errors::codes::*; use rustc_errors::{pluralize, struct_span_code_err, Applicability, MultiSpan, StringPart}; use rustc_errors::{Diag, EmissionGuarantee, ErrorGuaranteed, FatalError, StashKey}; -use rustc_hir as hir; use rustc_hir::def::{DefKind, Namespace, Res}; use rustc_hir::def_id::{DefId, LocalDefId}; use rustc_hir::intravisit::Visitor; +use rustc_hir::{self as hir, LangItem}; use rustc_hir::{GenericParam, Item, Node}; use rustc_infer::infer::error_reporting::TypeErrCtxt; use rustc_infer::infer::{InferOk, TypeTrace}; @@ -118,7 +118,7 @@ impl<'tcx> TypeErrCtxt<'_, 'tcx> { // with more relevant type information and hide redundant E0282 errors. errors.sort_by_key(|e| match e.obligation.predicate.kind().skip_binder() { ty::PredicateKind::Clause(ty::ClauseKind::Trait(pred)) - if Some(pred.def_id()) == self.tcx.lang_items().sized_trait() => + if self.tcx.is_lang_item(pred.def_id(), LangItem::Sized) => { 1 } @@ -412,8 +412,8 @@ impl<'tcx> TypeErrCtxt<'_, 'tcx> { let bound_predicate = obligation.predicate.kind(); match bound_predicate.skip_binder() { ty::PredicateKind::Clause(ty::ClauseKind::Trait(trait_predicate)) => { - let trait_predicate = bound_predicate.rebind(trait_predicate); - let trait_predicate = self.resolve_vars_if_possible(trait_predicate); + let leaf_trait_predicate = + self.resolve_vars_if_possible(bound_predicate.rebind(trait_predicate)); // Let's use the root obligation as the main message, when we care about the // most general case ("X doesn't implement Pattern<'_>") over the case that @@ -424,7 +424,7 @@ impl<'tcx> TypeErrCtxt<'_, 'tcx> { let (main_trait_predicate, o) = if let ty::PredicateKind::Clause( ty::ClauseKind::Trait(root_pred) ) = root_obligation.predicate.kind().skip_binder() - && !trait_predicate.self_ty().skip_binder().has_escaping_bound_vars() + && !leaf_trait_predicate.self_ty().skip_binder().has_escaping_bound_vars() && !root_pred.self_ty().has_escaping_bound_vars() // The type of the leaf predicate is (roughly) the same as the type // from the root predicate, as a proxy for "we care about the root" @@ -434,20 +434,20 @@ impl<'tcx> TypeErrCtxt<'_, 'tcx> { // `T: Trait` && `&&T: OtherTrait`, we want `OtherTrait` self.can_eq( obligation.param_env, - trait_predicate.self_ty().skip_binder(), + leaf_trait_predicate.self_ty().skip_binder(), root_pred.self_ty().peel_refs(), ) // `&str: Iterator` && `&str: IntoIterator`, we want `IntoIterator` || self.can_eq( obligation.param_env, - trait_predicate.self_ty().skip_binder(), + leaf_trait_predicate.self_ty().skip_binder(), root_pred.self_ty(), ) ) // The leaf trait and the root trait are different, so as to avoid // talking about `&mut T: Trait` and instead remain talking about // `T: Trait` instead - && trait_predicate.def_id() != root_pred.def_id() + && leaf_trait_predicate.def_id() != root_pred.def_id() // The root trait is not `Unsize`, as to avoid talking about it in // `tests/ui/coercion/coerce-issue-49593-box-never.rs`. && Some(root_pred.def_id()) != self.tcx.lang_items().unsize_trait() @@ -459,13 +459,14 @@ impl<'tcx> TypeErrCtxt<'_, 'tcx> { root_obligation, ) } else { - (trait_predicate, &obligation) + (leaf_trait_predicate, &obligation) }; - let trait_ref = main_trait_predicate.to_poly_trait_ref(); + let main_trait_ref = main_trait_predicate.to_poly_trait_ref(); + let leaf_trait_ref = leaf_trait_predicate.to_poly_trait_ref(); if let Some(guar) = self.emit_specialized_closure_kind_error( &obligation, - trait_ref, + leaf_trait_ref, ) { return guar; } @@ -473,7 +474,7 @@ impl<'tcx> TypeErrCtxt<'_, 'tcx> { // FIXME(effects) let predicate_is_const = false; - if let Err(guar) = trait_predicate.error_reported() + if let Err(guar) = leaf_trait_predicate.error_reported() { return guar; } @@ -507,16 +508,17 @@ impl<'tcx> TypeErrCtxt<'_, 'tcx> { notes, parent_label, append_const_msg, - } = self.on_unimplemented_note(trait_ref, o, &mut long_ty_file); + } = self.on_unimplemented_note(main_trait_ref, o, &mut long_ty_file); + let have_alt_message = message.is_some() || label.is_some(); - let is_try_conversion = self.is_try_conversion(span, trait_ref.def_id()); + let is_try_conversion = self.is_try_conversion(span, main_trait_ref.def_id()); let is_unsize = - Some(trait_ref.def_id()) == self.tcx.lang_items().unsize_trait(); + self.tcx.is_lang_item(leaf_trait_ref.def_id(), LangItem::Unsize); let (message, notes, append_const_msg) = if is_try_conversion { ( Some(format!( "`?` couldn't convert the error to `{}`", - trait_ref.skip_binder().self_ty(), + main_trait_ref.skip_binder().self_ty(), )), vec![ "the question mark operation (`?`) implicitly performs a \ @@ -530,20 +532,20 @@ impl<'tcx> TypeErrCtxt<'_, 'tcx> { }; let err_msg = self.get_standard_error_message( - &main_trait_predicate, + main_trait_predicate, message, predicate_is_const, append_const_msg, post_message, ); - let (err_msg, safe_transmute_explanation) = if Some(trait_ref.def_id()) + let (err_msg, safe_transmute_explanation) = if Some(main_trait_ref.def_id()) == self.tcx.lang_items().transmute_trait() { // Recompute the safe transmute reason and use that for the error reporting match self.get_safe_transmute_error_and_reason( obligation.clone(), - trait_ref, + main_trait_ref, span, ) { GetSafeTransmuteErrorAndReason::Silent => { @@ -571,7 +573,7 @@ impl<'tcx> TypeErrCtxt<'_, 'tcx> { } let mut suggested = false; if is_try_conversion { - suggested = self.try_conversion_context(&obligation, trait_ref.skip_binder(), &mut err); + suggested = self.try_conversion_context(&obligation, main_trait_ref.skip_binder(), &mut err); } if is_try_conversion && let Some(ret_span) = self.return_type_span(&obligation) { @@ -579,19 +581,19 @@ impl<'tcx> TypeErrCtxt<'_, 'tcx> { ret_span, format!( "expected `{}` because of this", - trait_ref.skip_binder().self_ty() + main_trait_ref.skip_binder().self_ty() ), ); } - if Some(trait_ref.def_id()) == tcx.lang_items().tuple_trait() { + if tcx.is_lang_item(leaf_trait_ref.def_id(), LangItem::Tuple) { self.add_tuple_trait_message( obligation.cause.code().peel_derives(), &mut err, ); } - if Some(trait_ref.def_id()) == tcx.lang_items().drop_trait() + if tcx.is_lang_item(leaf_trait_ref.def_id(), LangItem::Drop) && predicate_is_const { err.note("`~const Drop` was renamed to `~const Destruct`"); @@ -601,24 +603,25 @@ impl<'tcx> TypeErrCtxt<'_, 'tcx> { let explanation = get_explanation_based_on_obligation( self.tcx, &obligation, - trait_ref, - &trait_predicate, + leaf_trait_predicate, pre_message, ); self.check_for_binding_assigned_block_without_tail_expression( &obligation, &mut err, - trait_predicate, + leaf_trait_predicate, ); - self.suggest_add_result_as_return_type(&obligation, + self.suggest_add_result_as_return_type( + &obligation, &mut err, - trait_ref); + leaf_trait_predicate, + ); if self.suggest_add_reference_to_arg( &obligation, &mut err, - trait_predicate, + leaf_trait_predicate, have_alt_message, ) { self.note_obligation_cause(&mut err, &obligation); @@ -630,7 +633,7 @@ impl<'tcx> TypeErrCtxt<'_, 'tcx> { // If it has a custom `#[rustc_on_unimplemented]` // error message, let's display it as the label! err.span_label(span, s); - if !matches!(trait_ref.skip_binder().self_ty().kind(), ty::Param(_)) { + if !matches!(leaf_trait_ref.skip_binder().self_ty().kind(), ty::Param(_)) { // When the self type is a type param We don't need to "the trait // `std::marker::Sized` is not implemented for `T`" as we will point // at the type param with a label to suggest constraining it. @@ -645,7 +648,7 @@ impl<'tcx> TypeErrCtxt<'_, 'tcx> { if let ObligationCauseCode::Coercion { source, target } = *obligation.cause.code().peel_derives() { - if Some(trait_ref.def_id()) == self.tcx.lang_items().sized_trait() { + if self.tcx.is_lang_item(leaf_trait_ref.def_id(), LangItem::Sized) { self.suggest_borrowing_for_object_cast( &mut err, root_obligation, @@ -657,7 +660,7 @@ impl<'tcx> TypeErrCtxt<'_, 'tcx> { let UnsatisfiedConst(unsatisfied_const) = self .maybe_add_note_for_unsatisfied_const( - &trait_predicate, + leaf_trait_predicate, &mut err, span, ); @@ -674,15 +677,15 @@ impl<'tcx> TypeErrCtxt<'_, 'tcx> { err.span_label(tcx.def_span(body), s); } - self.suggest_floating_point_literal(&obligation, &mut err, &trait_ref); - self.suggest_dereferencing_index(&obligation, &mut err, trait_predicate); - suggested |= self.suggest_dereferences(&obligation, &mut err, trait_predicate); - suggested |= self.suggest_fn_call(&obligation, &mut err, trait_predicate); - let impl_candidates = self.find_similar_impl_candidates(trait_predicate); + self.suggest_floating_point_literal(&obligation, &mut err, leaf_trait_ref); + self.suggest_dereferencing_index(&obligation, &mut err, leaf_trait_predicate); + suggested |= self.suggest_dereferences(&obligation, &mut err, leaf_trait_predicate); + suggested |= self.suggest_fn_call(&obligation, &mut err, leaf_trait_predicate); + let impl_candidates = self.find_similar_impl_candidates(leaf_trait_predicate); suggested = if let &[cand] = &impl_candidates[..] { let cand = cand.trait_ref; if let (ty::FnPtr(_), ty::FnDef(..)) = - (cand.self_ty().kind(), trait_ref.self_ty().skip_binder().kind()) + (cand.self_ty().kind(), main_trait_ref.self_ty().skip_binder().kind()) { err.span_suggestion( span.shrink_to_hi(), @@ -702,31 +705,31 @@ impl<'tcx> TypeErrCtxt<'_, 'tcx> { false } || suggested; suggested |= - self.suggest_remove_reference(&obligation, &mut err, trait_predicate); + self.suggest_remove_reference(&obligation, &mut err, leaf_trait_predicate); suggested |= self.suggest_semicolon_removal( &obligation, &mut err, span, - trait_predicate, + leaf_trait_predicate, ); - self.note_version_mismatch(&mut err, &trait_ref); + self.note_version_mismatch(&mut err, leaf_trait_ref); self.suggest_remove_await(&obligation, &mut err); - self.suggest_derive(&obligation, &mut err, trait_predicate); + self.suggest_derive(&obligation, &mut err, leaf_trait_predicate); - if Some(trait_ref.def_id()) == tcx.lang_items().try_trait() { + if tcx.is_lang_item(leaf_trait_ref.def_id(), LangItem::Try) { self.suggest_await_before_try( &mut err, &obligation, - trait_predicate, + leaf_trait_predicate, span, ); } - if self.suggest_add_clone_to_arg(&obligation, &mut err, trait_predicate) { + if self.suggest_add_clone_to_arg(&obligation, &mut err, leaf_trait_predicate) { return err.emit(); } - if self.suggest_impl_trait(&mut err, &obligation, trait_predicate) { + if self.suggest_impl_trait(&mut err, &obligation, leaf_trait_predicate) { return err.emit(); } @@ -741,9 +744,9 @@ impl<'tcx> TypeErrCtxt<'_, 'tcx> { ); } - let is_fn_trait = tcx.is_fn_trait(trait_ref.def_id()); + let is_fn_trait = tcx.is_fn_trait(leaf_trait_ref.def_id()); let is_target_feature_fn = if let ty::FnDef(def_id, _) = - *trait_ref.skip_binder().self_ty().kind() + *leaf_trait_ref.skip_binder().self_ty().kind() { !self.tcx.codegen_fn_attrs(def_id).target_features.is_empty() } else { @@ -757,8 +760,7 @@ impl<'tcx> TypeErrCtxt<'_, 'tcx> { self.try_to_add_help_message( &obligation, - trait_ref, - &trait_predicate, + leaf_trait_predicate, &mut err, span, is_fn_trait, @@ -769,17 +771,17 @@ impl<'tcx> TypeErrCtxt<'_, 'tcx> { // Changing mutability doesn't make a difference to whether we have // an `Unsize` impl (Fixes ICE in #71036) if !is_unsize { - self.suggest_change_mut(&obligation, &mut err, trait_predicate); + self.suggest_change_mut(&obligation, &mut err, leaf_trait_predicate); } // If this error is due to `!: Trait` not implemented but `(): Trait` is // implemented, and fallback has occurred, then it could be due to a // variable that used to fallback to `()` now falling back to `!`. Issue a // note informing about the change in behaviour. - if trait_predicate.skip_binder().self_ty().is_never() + if leaf_trait_predicate.skip_binder().self_ty().is_never() && self.fallback_has_occurred { - let predicate = trait_predicate.map_bound(|trait_pred| { + let predicate = leaf_trait_predicate.map_bound(|trait_pred| { trait_pred.with_self_ty(self.tcx, tcx.types.unit) }); let unit_obligation = obligation.with(tcx, predicate); @@ -794,8 +796,8 @@ impl<'tcx> TypeErrCtxt<'_, 'tcx> { } } - self.explain_hrtb_projection(&mut err, trait_predicate, obligation.param_env, &obligation.cause); - self.suggest_desugaring_async_fn_in_trait(&mut err, trait_ref); + self.explain_hrtb_projection(&mut err, leaf_trait_predicate, obligation.param_env, &obligation.cause); + self.suggest_desugaring_async_fn_in_trait(&mut err, main_trait_ref); // Return early if the trait is Debug or Display and the invocation // originates within a standard library macro, because the output @@ -813,15 +815,13 @@ impl<'tcx> TypeErrCtxt<'_, 'tcx> { if in_std_macro && matches!( - self.tcx.get_diagnostic_name(trait_ref.def_id()), + self.tcx.get_diagnostic_name(leaf_trait_ref.def_id()), Some(sym::Debug | sym::Display) ) { return err.emit(); } - - err } @@ -1020,7 +1020,7 @@ impl<'tcx> TypeErrCtxt<'_, 'tcx> { // doesn't extend the goal kind. This is worth reporting, but we can only do so // if we actually know which closure this goal comes from, so look at the cause // to see if we can extract that information. - if Some(trait_ref.def_id()) == self.tcx.lang_items().async_fn_kind_helper() + if self.tcx.is_lang_item(trait_ref.def_id(), LangItem::AsyncFnKindHelper) && let Some(found_kind) = trait_ref.skip_binder().args.type_at(0).to_opt_closure_kind() && let Some(expected_kind) = trait_ref.skip_binder().args.type_at(1).to_opt_closure_kind() @@ -1744,7 +1744,7 @@ impl<'tcx> TypeErrCtxt<'_, 'tcx> { let self_ty = pred.projection_term.self_ty(); with_forced_trimmed_paths! { - if Some(pred.projection_term.def_id) == self.tcx.lang_items().fn_once_output() { + if self.tcx.is_lang_item(pred.projection_term.def_id,LangItem::FnOnceOutput) { let fn_kind = self_ty.prefix_string(self.tcx); let item = match self_ty.kind() { ty::FnDef(def, _) => self.tcx.item_name(*def).to_string(), @@ -1754,7 +1754,7 @@ impl<'tcx> TypeErrCtxt<'_, 'tcx> { "expected `{item}` to be a {fn_kind} that returns `{expected_ty}`, but it \ returns `{normalized_ty}`", )) - } else if Some(trait_def_id) == self.tcx.lang_items().future_trait() { + } else if self.tcx.is_lang_item(trait_def_id, LangItem::Future) { Some(format!( "expected `{self_ty}` to be a future that resolves to `{expected_ty}`, but it \ resolves to `{normalized_ty}`" @@ -1783,7 +1783,7 @@ impl<'tcx> TypeErrCtxt<'_, 'tcx> { ty::Bool => Some(0), ty::Char => Some(1), ty::Str => Some(2), - ty::Adt(def, _) if Some(def.did()) == tcx.lang_items().string() => Some(2), + ty::Adt(def, _) if tcx.is_lang_item(def.did(), LangItem::String) => Some(2), ty::Int(..) | ty::Uint(..) | ty::Float(..) @@ -2068,7 +2068,7 @@ impl<'tcx> TypeErrCtxt<'_, 'tcx> { if all_traits_equal { format!("\n {}", c.self_ty()) } else { - format!("\n {c}") + format!("\n `{}` implements `{}`", c.self_ty(), c.print_only_trait_path()) } }) .collect(); @@ -2236,11 +2236,7 @@ impl<'tcx> TypeErrCtxt<'_, 'tcx> { /// If the `Self` type of the unsatisfied trait `trait_ref` implements a trait /// with the same path as `trait_ref`, a help message about /// a probable version mismatch is added to `err` - fn note_version_mismatch( - &self, - err: &mut Diag<'_>, - trait_ref: &ty::PolyTraitRef<'tcx>, - ) -> bool { + fn note_version_mismatch(&self, err: &mut Diag<'_>, trait_ref: ty::PolyTraitRef<'tcx>) -> bool { let get_trait_impls = |trait_def_id| { let mut trait_impls = vec![]; self.tcx.for_each_relevant_impl( @@ -2346,7 +2342,7 @@ impl<'tcx> TypeErrCtxt<'_, 'tcx> { // avoid inundating the user with unnecessary errors, but we now // check upstream for type errors and don't add the obligations to // begin with in those cases. - if self.tcx.lang_items().sized_trait() == Some(trait_ref.def_id()) { + if self.tcx.is_lang_item(trait_ref.def_id(), LangItem::Sized) { match self.tainted_by_errors() { None => { let err = self.emit_inference_failure_err( @@ -2705,6 +2701,22 @@ impl<'tcx> TypeErrCtxt<'_, 'tcx> { ), ); } + + ty::PredicateKind::NormalizesTo(ty::NormalizesTo { alias, term }) + if term.is_infer() => + { + if let Some(e) = self.tainted_by_errors() { + return e; + } + struct_span_code_err!( + self.dcx(), + span, + E0284, + "type annotations needed: cannot normalize `{alias}`", + ) + .with_span_label(span, format!("cannot normalize `{alias}`")) + } + _ => { if let Some(e) = self.tainted_by_errors() { return e; @@ -2913,7 +2925,7 @@ impl<'tcx> TypeErrCtxt<'_, 'tcx> { let (Some(node), true) = ( self.tcx.hir().get_if_local(item_def_id), - Some(pred.def_id()) == self.tcx.lang_items().sized_trait(), + self.tcx.is_lang_item(pred.def_id(), LangItem::Sized), ) else { return; }; @@ -3044,7 +3056,7 @@ impl<'tcx> TypeErrCtxt<'_, 'tcx> { fn get_standard_error_message( &self, - trait_predicate: &ty::PolyTraitPredicate<'tcx>, + trait_predicate: ty::PolyTraitPredicate<'tcx>, message: Option, predicate_is_const: bool, append_const_msg: Option, @@ -3215,8 +3227,7 @@ impl<'tcx> TypeErrCtxt<'_, 'tcx> { fn try_to_add_help_message( &self, obligation: &PredicateObligation<'tcx>, - trait_ref: ty::PolyTraitRef<'tcx>, - trait_predicate: &ty::PolyTraitPredicate<'tcx>, + trait_predicate: ty::PolyTraitPredicate<'tcx>, err: &mut Diag<'_>, span: Span, is_fn_trait: bool, @@ -3233,16 +3244,22 @@ impl<'tcx> TypeErrCtxt<'_, 'tcx> { }; // Try to report a help message + let trait_def_id = trait_predicate.def_id(); if is_fn_trait && let Ok((implemented_kind, params)) = self.type_implements_fn_trait( obligation.param_env, - trait_ref.self_ty(), + trait_predicate.self_ty(), trait_predicate.skip_binder().polarity, ) { - self.add_help_message_for_fn_trait(trait_ref, err, implemented_kind, params); - } else if !trait_ref.has_non_region_infer() - && self.predicate_can_apply(obligation.param_env, *trait_predicate) + self.add_help_message_for_fn_trait( + trait_predicate.to_poly_trait_ref(), + err, + implemented_kind, + params, + ); + } else if !trait_predicate.has_non_region_infer() + && self.predicate_can_apply(obligation.param_env, trait_predicate) { // If a where-clause may be useful, remind the // user that they can add it. @@ -3253,25 +3270,25 @@ impl<'tcx> TypeErrCtxt<'_, 'tcx> { // which is somewhat confusing. self.suggest_restricting_param_bound( err, - *trait_predicate, + trait_predicate, None, obligation.cause.body_id, ); - } else if trait_ref.def_id().is_local() - && self.tcx.trait_impls_of(trait_ref.def_id()).is_empty() - && !self.tcx.trait_is_auto(trait_ref.def_id()) - && !self.tcx.trait_is_alias(trait_ref.def_id()) + } else if trait_def_id.is_local() + && self.tcx.trait_impls_of(trait_def_id).is_empty() + && !self.tcx.trait_is_auto(trait_def_id) + && !self.tcx.trait_is_alias(trait_def_id) { err.span_help( - self.tcx.def_span(trait_ref.def_id()), + self.tcx.def_span(trait_def_id), crate::fluent_generated::trait_selection_trait_has_no_impls, ); } else if !suggested && !unsatisfied_const { // Can't show anything else useful, try to find similar impls. - let impl_candidates = self.find_similar_impl_candidates(*trait_predicate); + let impl_candidates = self.find_similar_impl_candidates(trait_predicate); if !self.report_similar_impl_candidates( &impl_candidates, - trait_ref, + trait_predicate.to_poly_trait_ref(), body_def_id, err, true, @@ -3279,7 +3296,7 @@ impl<'tcx> TypeErrCtxt<'_, 'tcx> { ) { self.report_similar_impl_candidates_for_root_obligation( obligation, - *trait_predicate, + trait_predicate, body_def_id, err, ); @@ -3288,7 +3305,7 @@ impl<'tcx> TypeErrCtxt<'_, 'tcx> { self.suggest_convert_to_slice( err, obligation, - trait_ref, + trait_predicate.to_poly_trait_ref(), impl_candidates.as_slice(), span, ); @@ -3353,7 +3370,7 @@ impl<'tcx> TypeErrCtxt<'_, 'tcx> { fn maybe_add_note_for_unsatisfied_const( &self, - _trait_predicate: &ty::PolyTraitPredicate<'tcx>, + _trait_predicate: ty::PolyTraitPredicate<'tcx>, _err: &mut Diag<'_>, _span: Span, ) -> UnsatisfiedConst { diff --git a/compiler/rustc_trait_selection/src/traits/mod.rs b/compiler/rustc_trait_selection/src/traits/mod.rs index eae2f9d1792f6..af6bfdae44029 100644 --- a/compiler/rustc_trait_selection/src/traits/mod.rs +++ b/compiler/rustc_trait_selection/src/traits/mod.rs @@ -65,7 +65,7 @@ pub use self::structural_match::search_for_structural_match_violation; pub use self::structural_normalize::StructurallyNormalizeExt; pub use self::util::elaborate; pub use self::util::{expand_trait_aliases, TraitAliasExpander, TraitAliasExpansionInfo}; -pub use self::util::{get_vtable_index_of_object_method, impl_item_is_final, upcast_choices}; +pub use self::util::{impl_item_is_final, upcast_choices}; pub use self::util::{supertraits, transitive_bounds, transitive_bounds_that_define_assoc_item}; pub use self::util::{with_replaced_escaping_bound_vars, BoundVarReplacer, PlaceholderReplacer}; diff --git a/compiler/rustc_trait_selection/src/traits/object_safety.rs b/compiler/rustc_trait_selection/src/traits/object_safety.rs index 08355ef55c492..fc5a2875b67ad 100644 --- a/compiler/rustc_trait_selection/src/traits/object_safety.rs +++ b/compiler/rustc_trait_selection/src/traits/object_safety.rs @@ -194,7 +194,7 @@ fn predicates_reference_self( predicates .predicates .iter() - .map(|&(predicate, sp)| (predicate.instantiate_supertrait(tcx, &trait_ref), sp)) + .map(|&(predicate, sp)| (predicate.instantiate_supertrait(tcx, trait_ref), sp)) .filter_map(|predicate| predicate_references_self(tcx, predicate)) .collect() } diff --git a/compiler/rustc_trait_selection/src/traits/project.rs b/compiler/rustc_trait_selection/src/traits/project.rs index 2c9cb79664b34..8ab324e6601bc 100644 --- a/compiler/rustc_trait_selection/src/traits/project.rs +++ b/compiler/rustc_trait_selection/src/traits/project.rs @@ -1015,6 +1015,7 @@ fn assemble_candidates_from_impls<'cx, 'tcx>( // not eligible. let self_ty = selcx.infcx.shallow_resolve(obligation.predicate.self_ty()); + let tcx = selcx.tcx(); let lang_items = selcx.tcx().lang_items(); if [ lang_items.coroutine_trait(), @@ -1031,7 +1032,7 @@ fn assemble_candidates_from_impls<'cx, 'tcx>( .contains(&Some(trait_ref.def_id)) { true - } else if lang_items.async_fn_kind_helper() == Some(trait_ref.def_id) { + } else if tcx.is_lang_item(trait_ref.def_id, LangItem::AsyncFnKindHelper) { // FIXME(async_closures): Validity constraints here could be cleaned up. if obligation.predicate.args.type_at(0).is_ty_var() || obligation.predicate.args.type_at(4).is_ty_var() @@ -1043,7 +1044,7 @@ fn assemble_candidates_from_impls<'cx, 'tcx>( obligation.predicate.args.type_at(0).to_opt_closure_kind().is_some() && obligation.predicate.args.type_at(1).to_opt_closure_kind().is_some() } - } else if lang_items.discriminant_kind_trait() == Some(trait_ref.def_id) { + } else if tcx.is_lang_item(trait_ref.def_id, LangItem::DiscriminantKind) { match self_ty.kind() { ty::Bool | ty::Char @@ -1080,7 +1081,7 @@ fn assemble_candidates_from_impls<'cx, 'tcx>( | ty::Infer(..) | ty::Error(_) => false, } - } else if lang_items.async_destruct_trait() == Some(trait_ref.def_id) { + } else if tcx.is_lang_item(trait_ref.def_id, LangItem::AsyncDestruct) { match self_ty.kind() { ty::Bool | ty::Char @@ -1116,7 +1117,7 @@ fn assemble_candidates_from_impls<'cx, 'tcx>( | ty::Infer(_) | ty::Error(_) => false, } - } else if lang_items.pointee_trait() == Some(trait_ref.def_id) { + } else if tcx.is_lang_item(trait_ref.def_id, LangItem::PointeeTrait) { let tail = selcx.tcx().struct_tail_with_normalize( self_ty, |ty| { @@ -1300,15 +1301,15 @@ fn confirm_select_candidate<'cx, 'tcx>( match impl_source { ImplSource::UserDefined(data) => confirm_impl_candidate(selcx, obligation, data), ImplSource::Builtin(BuiltinImplSource::Misc, data) => { - let trait_def_id = obligation.predicate.trait_def_id(selcx.tcx()); - let lang_items = selcx.tcx().lang_items(); - if lang_items.coroutine_trait() == Some(trait_def_id) { + let tcx = selcx.tcx(); + let trait_def_id = obligation.predicate.trait_def_id(tcx); + if tcx.is_lang_item(trait_def_id, LangItem::Coroutine) { confirm_coroutine_candidate(selcx, obligation, data) - } else if lang_items.future_trait() == Some(trait_def_id) { + } else if tcx.is_lang_item(trait_def_id, LangItem::Future) { confirm_future_candidate(selcx, obligation, data) - } else if lang_items.iterator_trait() == Some(trait_def_id) { + } else if tcx.is_lang_item(trait_def_id, LangItem::Iterator) { confirm_iterator_candidate(selcx, obligation, data) - } else if lang_items.async_iterator_trait() == Some(trait_def_id) { + } else if tcx.is_lang_item(trait_def_id, LangItem::AsyncIterator) { confirm_async_iterator_candidate(selcx, obligation, data) } else if selcx.tcx().fn_trait_kind_from_def_id(trait_def_id).is_some() { if obligation.predicate.self_ty().is_closure() @@ -1320,7 +1321,7 @@ fn confirm_select_candidate<'cx, 'tcx>( } } else if selcx.tcx().async_fn_trait_kind_from_def_id(trait_def_id).is_some() { confirm_async_closure_candidate(selcx, obligation, data) - } else if lang_items.async_fn_kind_helper() == Some(trait_def_id) { + } else if tcx.is_lang_item(trait_def_id, LangItem::AsyncFnKindHelper) { confirm_async_fn_kind_helper_candidate(selcx, obligation, data) } else { confirm_builtin_candidate(selcx, obligation, data) @@ -1373,15 +1374,15 @@ fn confirm_coroutine_candidate<'cx, 'tcx>( coroutine_sig, ); - let name = tcx.associated_item(obligation.predicate.def_id).name; - let ty = if name == sym::Return { + let ty = if tcx.is_lang_item(obligation.predicate.def_id, LangItem::CoroutineReturn) { return_ty - } else if name == sym::Yield { + } else if tcx.is_lang_item(obligation.predicate.def_id, LangItem::CoroutineYield) { yield_ty } else { span_bug!( tcx.def_span(obligation.predicate.def_id), - "unexpected associated type: `Coroutine::{name}`" + "unexpected associated type: `Coroutine::{}`", + tcx.item_name(obligation.predicate.def_id), ); }; @@ -1538,21 +1539,20 @@ fn confirm_builtin_candidate<'cx, 'tcx>( ) -> Progress<'tcx> { let tcx = selcx.tcx(); let self_ty = obligation.predicate.self_ty(); - let lang_items = tcx.lang_items(); let item_def_id = obligation.predicate.def_id; let trait_def_id = tcx.trait_of_item(item_def_id).unwrap(); let args = tcx.mk_args(&[self_ty.into()]); - let (term, obligations) = if lang_items.discriminant_kind_trait() == Some(trait_def_id) { + let (term, obligations) = if tcx.is_lang_item(trait_def_id, LangItem::DiscriminantKind) { let discriminant_def_id = tcx.require_lang_item(LangItem::Discriminant, None); assert_eq!(discriminant_def_id, item_def_id); (self_ty.discriminant_ty(tcx).into(), Vec::new()) - } else if lang_items.async_destruct_trait() == Some(trait_def_id) { + } else if tcx.is_lang_item(trait_def_id, LangItem::AsyncDestruct) { let destructor_def_id = tcx.associated_item_def_ids(trait_def_id)[0]; assert_eq!(destructor_def_id, item_def_id); (self_ty.async_destructor_ty(tcx).into(), Vec::new()) - } else if lang_items.pointee_trait() == Some(trait_def_id) { + } else if tcx.is_lang_item(trait_def_id, LangItem::PointeeTrait) { let metadata_def_id = tcx.require_lang_item(LangItem::Metadata, None); assert_eq!(metadata_def_id, item_def_id); diff --git a/compiler/rustc_trait_selection/src/traits/query/dropck_outlives.rs b/compiler/rustc_trait_selection/src/traits/query/dropck_outlives.rs index 326c68e01dbf7..7dc051e6fe959 100644 --- a/compiler/rustc_trait_selection/src/traits/query/dropck_outlives.rs +++ b/compiler/rustc_trait_selection/src/traits/query/dropck_outlives.rs @@ -55,7 +55,7 @@ pub fn trivial_dropck_outlives<'tcx>(tcx: TyCtxt<'tcx>, ty: Ty<'tcx>) -> bool { } ty::Adt(def, _) => { - if Some(def.did()) == tcx.lang_items().manually_drop() { + if def.is_manually_drop() { // `ManuallyDrop` never has a dtor. true } else { diff --git a/compiler/rustc_infer/src/infer/relate/_match.rs b/compiler/rustc_trait_selection/src/traits/select/_match.rs similarity index 97% rename from compiler/rustc_infer/src/infer/relate/_match.rs rename to compiler/rustc_trait_selection/src/traits/select/_match.rs index 30a066a265acd..50d8e96aaf91f 100644 --- a/compiler/rustc_infer/src/infer/relate/_match.rs +++ b/compiler/rustc_trait_selection/src/traits/select/_match.rs @@ -1,10 +1,10 @@ +use rustc_infer::infer::relate::{ + self, structurally_relate_tys, Relate, RelateResult, TypeRelation, +}; use rustc_middle::ty::error::{ExpectedFound, TypeError}; use rustc_middle::ty::{self, InferConst, Ty, TyCtxt}; use tracing::{debug, instrument}; -use super::{structurally_relate_tys, Relate, RelateResult, TypeRelation}; -use crate::infer::relate; - /// A type "A" *matches* "B" if the fresh types in B could be /// instantiated with values so as to make it equal to A. Matching is /// intended to be used only on freshened types, and it basically diff --git a/compiler/rustc_trait_selection/src/traits/select/candidate_assembly.rs b/compiler/rustc_trait_selection/src/traits/select/candidate_assembly.rs index 6db5fa0e4e552..c53939bfe602f 100644 --- a/compiler/rustc_trait_selection/src/traits/select/candidate_assembly.rs +++ b/compiler/rustc_trait_selection/src/traits/select/candidate_assembly.rs @@ -67,9 +67,9 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { // Other bounds. Consider both in-scope bounds from fn decl // and applicable impls. There is a certain set of precedence rules here. let def_id = obligation.predicate.def_id(); - let lang_items = self.tcx().lang_items(); + let tcx = self.tcx(); - if lang_items.copy_trait() == Some(def_id) { + if tcx.is_lang_item(def_id, LangItem::Copy) { debug!(obligation_self_ty = ?obligation.predicate.skip_binder().self_ty()); // User-defined copy impls are permitted, but only for @@ -79,16 +79,16 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { // For other types, we'll use the builtin rules. let copy_conditions = self.copy_clone_conditions(obligation); self.assemble_builtin_bound_candidates(copy_conditions, &mut candidates); - } else if lang_items.discriminant_kind_trait() == Some(def_id) { + } else if tcx.is_lang_item(def_id, LangItem::DiscriminantKind) { // `DiscriminantKind` is automatically implemented for every type. candidates.vec.push(BuiltinCandidate { has_nested: false }); - } else if lang_items.async_destruct_trait() == Some(def_id) { + } else if tcx.is_lang_item(def_id, LangItem::AsyncDestruct) { // `AsyncDestruct` is automatically implemented for every type. candidates.vec.push(BuiltinCandidate { has_nested: false }); - } else if lang_items.pointee_trait() == Some(def_id) { + } else if tcx.is_lang_item(def_id, LangItem::PointeeTrait) { // `Pointee` is automatically implemented for every type. candidates.vec.push(BuiltinCandidate { has_nested: false }); - } else if lang_items.sized_trait() == Some(def_id) { + } else if tcx.is_lang_item(def_id, LangItem::Sized) { // Sized is never implementable by end-users, it is // always automatically computed. @@ -101,22 +101,22 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { let sized_conditions = self.sized_conditions(obligation); self.assemble_builtin_bound_candidates(sized_conditions, &mut candidates); - } else if lang_items.unsize_trait() == Some(def_id) { + } else if tcx.is_lang_item(def_id, LangItem::Unsize) { self.assemble_candidates_for_unsizing(obligation, &mut candidates); - } else if lang_items.destruct_trait() == Some(def_id) { + } else if tcx.is_lang_item(def_id, LangItem::Destruct) { self.assemble_const_destruct_candidates(obligation, &mut candidates); - } else if lang_items.transmute_trait() == Some(def_id) { + } else if tcx.is_lang_item(def_id, LangItem::TransmuteTrait) { // User-defined transmutability impls are permitted. self.assemble_candidates_from_impls(obligation, &mut candidates); self.assemble_candidates_for_transmutability(obligation, &mut candidates); - } else if lang_items.tuple_trait() == Some(def_id) { + } else if tcx.is_lang_item(def_id, LangItem::Tuple) { self.assemble_candidate_for_tuple(obligation, &mut candidates); - } else if lang_items.pointer_like() == Some(def_id) { + } else if tcx.is_lang_item(def_id, LangItem::PointerLike) { self.assemble_candidate_for_pointer_like(obligation, &mut candidates); - } else if lang_items.fn_ptr_trait() == Some(def_id) { + } else if tcx.is_lang_item(def_id, LangItem::FnPtrTrait) { self.assemble_candidates_for_fn_ptr_trait(obligation, &mut candidates); } else { - if lang_items.clone_trait() == Some(def_id) { + if tcx.is_lang_item(def_id, LangItem::Clone) { // Same builtin conditions as `Copy`, i.e., every type which has builtin support // for `Copy` also has builtin support for `Clone`, and tuples/arrays of `Clone` // types have builtin support for `Clone`. @@ -124,17 +124,17 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { self.assemble_builtin_bound_candidates(clone_conditions, &mut candidates); } - if lang_items.coroutine_trait() == Some(def_id) { + if tcx.is_lang_item(def_id, LangItem::Coroutine) { self.assemble_coroutine_candidates(obligation, &mut candidates); - } else if lang_items.future_trait() == Some(def_id) { + } else if tcx.is_lang_item(def_id, LangItem::Future) { self.assemble_future_candidates(obligation, &mut candidates); - } else if lang_items.iterator_trait() == Some(def_id) { + } else if tcx.is_lang_item(def_id, LangItem::Iterator) { self.assemble_iterator_candidates(obligation, &mut candidates); - } else if lang_items.fused_iterator_trait() == Some(def_id) { + } else if tcx.is_lang_item(def_id, LangItem::FusedIterator) { self.assemble_fused_iterator_candidates(obligation, &mut candidates); - } else if lang_items.async_iterator_trait() == Some(def_id) { + } else if tcx.is_lang_item(def_id, LangItem::AsyncIterator) { self.assemble_async_iterator_candidates(obligation, &mut candidates); - } else if lang_items.async_fn_kind_helper() == Some(def_id) { + } else if tcx.is_lang_item(def_id, LangItem::AsyncFnKindHelper) { self.assemble_async_fn_kind_helper_candidates(obligation, &mut candidates); } @@ -239,24 +239,19 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { return Ok(()); } - let all_bounds = stack + let bounds = stack .obligation .param_env .caller_bounds() .iter() .filter(|p| !p.references_error()) - .filter_map(|p| p.as_trait_clause()); - - // Micro-optimization: filter out predicates relating to different traits. - let matching_bounds = - all_bounds.filter(|p| p.def_id() == stack.obligation.predicate.def_id()); + .filter_map(|p| p.as_trait_clause()) + // Micro-optimization: filter out predicates relating to different traits. + .filter(|p| p.def_id() == stack.obligation.predicate.def_id()) + .filter(|p| p.polarity() == stack.obligation.predicate.polarity()); // Keep only those bounds which may apply, and propagate overflow if it occurs. - for bound in matching_bounds { - if bound.skip_binder().polarity != stack.obligation.predicate.skip_binder().polarity { - continue; - } - + for bound in bounds { // FIXME(oli-obk): it is suspicious that we are dropping the constness and // polarity here. let wc = self.where_clause_may_apply(stack, bound.map_bound(|t| t.trait_ref))?; @@ -755,7 +750,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { candidates.ambiguous = true; } ty::Coroutine(coroutine_def_id, _) - if self.tcx().lang_items().unpin_trait() == Some(def_id) => + if self.tcx().is_lang_item(def_id, LangItem::Unpin) => { match self.tcx().coroutine_movability(coroutine_def_id) { hir::Movability::Static => { diff --git a/compiler/rustc_trait_selection/src/traits/select/confirmation.rs b/compiler/rustc_trait_selection/src/traits/select/confirmation.rs index 749081006f392..af599108c49dc 100644 --- a/compiler/rustc_trait_selection/src/traits/select/confirmation.rs +++ b/compiler/rustc_trait_selection/src/traits/select/confirmation.rs @@ -22,10 +22,6 @@ use rustc_span::def_id::DefId; use crate::traits::normalize::{normalize_with_depth, normalize_with_depth_to}; use crate::traits::util::{self, closure_trait_ref_and_return_type}; -use crate::traits::vtable::{ - count_own_vtable_entries, prepare_vtable_segments, vtable_trait_first_method_offset, - VtblSegment, -}; use crate::traits::{ ImplDerivedCause, ImplSource, ImplSourceUserDefinedData, Normalized, Obligation, ObligationCause, PolyTraitObligation, PredicateObligation, Selection, SelectionError, @@ -258,16 +254,16 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { ) -> Vec> { debug!(?obligation, ?has_nested, "confirm_builtin_candidate"); - let lang_items = self.tcx().lang_items(); + let tcx = self.tcx(); let obligations = if has_nested { let trait_def = obligation.predicate.def_id(); - let conditions = if Some(trait_def) == lang_items.sized_trait() { + let conditions = if tcx.is_lang_item(trait_def, LangItem::Sized) { self.sized_conditions(obligation) - } else if Some(trait_def) == lang_items.copy_trait() { + } else if tcx.is_lang_item(trait_def, LangItem::Copy) { self.copy_clone_conditions(obligation) - } else if Some(trait_def) == lang_items.clone_trait() { + } else if tcx.is_lang_item(trait_def, LangItem::Clone) { self.copy_clone_conditions(obligation) - } else if Some(trait_def) == lang_items.fused_iterator_trait() { + } else if tcx.is_lang_item(trait_def, LangItem::FusedIterator) { self.fused_iterator_conditions(obligation) } else { bug!("unexpected builtin trait {:?}", trait_def) @@ -338,7 +334,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { let make_freeze_obl = |ty| { let trait_ref = ty::TraitRef::new( tcx, - tcx.lang_items().freeze_trait().unwrap(), + tcx.require_lang_item(LangItem::Freeze, None), [ty::GenericArg::from(ty)], ); Obligation::with_depth( @@ -689,13 +685,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { debug!(?nested, "object nested obligations"); - let vtable_base = vtable_trait_first_method_offset( - tcx, - unnormalized_upcast_trait_ref, - ty::Binder::dummy(object_trait_ref), - ); - - Ok(ImplSource::Builtin(BuiltinImplSource::Object { vtable_base: vtable_base }, nested)) + Ok(ImplSource::Builtin(BuiltinImplSource::Object(index), nested)) } fn confirm_fn_pointer_candidate( @@ -1125,36 +1115,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { )? .expect("did not expect ambiguity during confirmation"); - let vtable_segment_callback = { - let mut vptr_offset = 0; - move |segment| { - match segment { - VtblSegment::MetadataDSA => { - vptr_offset += TyCtxt::COMMON_VTABLE_ENTRIES.len(); - } - VtblSegment::TraitOwnEntries { trait_ref, emit_vptr } => { - vptr_offset += count_own_vtable_entries(tcx, trait_ref); - if trait_ref == unnormalized_upcast_principal { - if emit_vptr { - return ControlFlow::Break(Some(vptr_offset)); - } else { - return ControlFlow::Break(None); - } - } - - if emit_vptr { - vptr_offset += 1; - } - } - } - ControlFlow::Continue(()) - } - }; - - let vtable_vptr_slot = - prepare_vtable_segments(tcx, source_principal, vtable_segment_callback).unwrap(); - - Ok(ImplSource::Builtin(BuiltinImplSource::TraitUpcasting { vtable_vptr_slot }, nested)) + Ok(ImplSource::Builtin(BuiltinImplSource::TraitUpcasting, nested)) } fn confirm_builtin_unsize_candidate( @@ -1444,7 +1405,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { | ty::Foreign(_) => {} // `ManuallyDrop` is trivially drop - ty::Adt(def, _) if Some(def.did()) == tcx.lang_items().manually_drop() => {} + ty::Adt(def, _) if def.is_manually_drop() => {} // These types are built-in, so we can fast-track by registering // nested predicates for their constituent type(s) diff --git a/compiler/rustc_trait_selection/src/traits/select/mod.rs b/compiler/rustc_trait_selection/src/traits/select/mod.rs index 4306a8035241a..b401958577121 100644 --- a/compiler/rustc_trait_selection/src/traits/select/mod.rs +++ b/compiler/rustc_trait_selection/src/traits/select/mod.rs @@ -32,7 +32,7 @@ use rustc_data_structures::stack::ensure_sufficient_stack; use rustc_errors::{Diag, EmissionGuarantee}; use rustc_hir as hir; use rustc_hir::def_id::DefId; -use rustc_infer::infer::relate::MatchAgainstFreshVars; +use rustc_hir::LangItem; use rustc_infer::infer::relate::TypeRelation; use rustc_infer::infer::BoundRegionConversionTime; use rustc_infer::infer::BoundRegionConversionTime::HigherRankedType; @@ -60,6 +60,7 @@ use std::ops::ControlFlow; pub use rustc_middle::traits::select::*; use rustc_middle::ty::print::with_no_trimmed_paths; +mod _match; mod candidate_assembly; mod confirmation; @@ -1866,7 +1867,7 @@ impl<'tcx> SelectionContext<'_, 'tcx> { // the param_env so that it can be given the lowest priority. See // #50825 for the motivation for this. let is_global = - |cand: &ty::PolyTraitPredicate<'tcx>| cand.is_global() && !cand.has_bound_vars(); + |cand: ty::PolyTraitPredicate<'tcx>| cand.is_global() && !cand.has_bound_vars(); // (*) Prefer `BuiltinCandidate { has_nested: false }`, `PointeeCandidate`, // `DiscriminantKindCandidate`, `ConstDestructCandidate` @@ -1909,7 +1910,7 @@ impl<'tcx> SelectionContext<'_, 'tcx> { } ( - ParamCandidate(ref other_cand), + ParamCandidate(other_cand), ImplCandidate(..) | AutoImplCandidate | ClosureCandidate { .. } @@ -1934,12 +1935,12 @@ impl<'tcx> SelectionContext<'_, 'tcx> { // // Global bounds from the where clause should be ignored // here (see issue #50825). - DropVictim::drop_if(!is_global(other_cand)) + DropVictim::drop_if(!is_global(*other_cand)) } - (ObjectCandidate(_) | ProjectionCandidate(_), ParamCandidate(ref victim_cand)) => { + (ObjectCandidate(_) | ProjectionCandidate(_), ParamCandidate(victim_cand)) => { // Prefer these to a global where-clause bound // (see issue #50825). - if is_global(victim_cand) { DropVictim::Yes } else { DropVictim::No } + if is_global(*victim_cand) { DropVictim::Yes } else { DropVictim::No } } ( ImplCandidate(_) @@ -1957,12 +1958,12 @@ impl<'tcx> SelectionContext<'_, 'tcx> { | TraitUpcastingUnsizeCandidate(_) | BuiltinCandidate { has_nested: true } | TraitAliasCandidate, - ParamCandidate(ref victim_cand), + ParamCandidate(victim_cand), ) => { // Prefer these to a global where-clause bound // (see issue #50825). DropVictim::drop_if( - is_global(victim_cand) && other.evaluation.must_apply_modulo_regions(), + is_global(*victim_cand) && other.evaluation.must_apply_modulo_regions(), ) } @@ -2719,7 +2720,7 @@ impl<'tcx> SelectionContext<'_, 'tcx> { previous: ty::PolyTraitPredicate<'tcx>, current: ty::PolyTraitPredicate<'tcx>, ) -> bool { - let mut matcher = MatchAgainstFreshVars::new(self.tcx()); + let mut matcher = _match::MatchAgainstFreshVars::new(self.tcx()); matcher.relate(previous, current).is_ok() } @@ -2800,19 +2801,18 @@ impl<'tcx> SelectionContext<'_, 'tcx> { let predicates = predicates.instantiate_own(tcx, args); let mut obligations = Vec::with_capacity(predicates.len()); for (index, (predicate, span)) in predicates.into_iter().enumerate() { - let cause = - if Some(parent_trait_pred.def_id()) == tcx.lang_items().coerce_unsized_trait() { - cause.clone() - } else { - cause.clone().derived_cause(parent_trait_pred, |derived| { - ObligationCauseCode::ImplDerived(Box::new(ImplDerivedCause { - derived, - impl_or_alias_def_id: def_id, - impl_def_predicate_index: Some(index), - span, - })) - }) - }; + let cause = if tcx.is_lang_item(parent_trait_pred.def_id(), LangItem::CoerceUnsized) { + cause.clone() + } else { + cause.clone().derived_cause(parent_trait_pred, |derived| { + ObligationCauseCode::ImplDerived(Box::new(ImplDerivedCause { + derived, + impl_or_alias_def_id: def_id, + impl_def_predicate_index: Some(index), + span, + })) + }) + }; let clause = normalize_with_depth_to( self, param_env, diff --git a/compiler/rustc_trait_selection/src/traits/util.rs b/compiler/rustc_trait_selection/src/traits/util.rs index 960c27b636e12..c3fe816028e33 100644 --- a/compiler/rustc_trait_selection/src/traits/util.rs +++ b/compiler/rustc_trait_selection/src/traits/util.rs @@ -132,7 +132,7 @@ impl<'tcx> TraitAliasExpander<'tcx> { debug!(?predicates); let items = predicates.predicates.iter().rev().filter_map(|(pred, span)| { - pred.instantiate_supertrait(tcx, &trait_ref) + pred.instantiate_supertrait(tcx, trait_ref) .as_trait_clause() .map(|trait_ref| item.clone_and_push(trait_ref.map_bound(|t| t.trait_ref), *span)) }); @@ -208,23 +208,6 @@ pub fn upcast_choices<'tcx>( supertraits(tcx, source_trait_ref).filter(|r| r.def_id() == target_trait_def_id).collect() } -/// Given an upcast trait object described by `object`, returns the -/// index of the method `method_def_id` (which should be part of -/// `object.upcast_trait_ref`) within the vtable for `object`. -pub fn get_vtable_index_of_object_method<'tcx>( - tcx: TyCtxt<'tcx>, - vtable_base: usize, - method_def_id: DefId, -) -> Option { - // Count number of methods preceding the one we are selecting and - // add them to the total offset. - tcx.own_existential_vtable_entries(tcx.parent(method_def_id)) - .iter() - .copied() - .position(|def_id| def_id == method_def_id) - .map(|index| vtable_base + index) -} - pub fn closure_trait_ref_and_return_type<'tcx>( tcx: TyCtxt<'tcx>, fn_trait_def_id: DefId, diff --git a/compiler/rustc_trait_selection/src/traits/vtable.rs b/compiler/rustc_trait_selection/src/traits/vtable.rs index c93ec43944ad2..017b0a45d1f41 100644 --- a/compiler/rustc_trait_selection/src/traits/vtable.rs +++ b/compiler/rustc_trait_selection/src/traits/vtable.rs @@ -1,15 +1,11 @@ use crate::errors::DumpVTableEntries; use crate::traits::{impossible_predicates, is_vtable_safe_method}; use rustc_hir::def_id::DefId; -use rustc_hir::lang_items::LangItem; use rustc_infer::traits::util::PredicateSet; -use rustc_infer::traits::ImplSource; use rustc_middle::bug; use rustc_middle::query::Providers; -use rustc_middle::traits::BuiltinImplSource; -use rustc_middle::ty::visit::TypeVisitableExt; -use rustc_middle::ty::GenericArgs; use rustc_middle::ty::{self, GenericParamDefKind, Ty, TyCtxt, Upcast, VtblEntry}; +use rustc_middle::ty::{GenericArgs, TypeVisitableExt}; use rustc_span::{sym, Span}; use smallvec::{smallvec, SmallVec}; @@ -125,7 +121,7 @@ fn prepare_vtable_segments_inner<'tcx, T>( .predicates .into_iter() .filter_map(move |(pred, _)| { - pred.instantiate_supertrait(tcx, &inner_most_trait_ref).as_trait_clause() + pred.instantiate_supertrait(tcx, inner_most_trait_ref).as_trait_clause() }); // Find an unvisited supertrait @@ -320,30 +316,42 @@ fn vtable_entries<'tcx>( tcx.arena.alloc_from_iter(entries) } -/// Find slot base for trait methods within vtable entries of another trait -pub(super) fn vtable_trait_first_method_offset<'tcx>( - tcx: TyCtxt<'tcx>, - trait_to_be_found: ty::PolyTraitRef<'tcx>, - trait_owning_vtable: ty::PolyTraitRef<'tcx>, -) -> usize { - // #90177 - let trait_to_be_found_erased = tcx.erase_regions(trait_to_be_found); +// Given a `dyn Subtrait: Supertrait` trait ref, find corresponding first slot +// for `Supertrait`'s methods in the vtable of `Subtrait`. +pub(crate) fn first_method_vtable_slot<'tcx>(tcx: TyCtxt<'tcx>, key: ty::TraitRef<'tcx>) -> usize { + debug_assert!(!key.has_non_region_infer() && !key.has_non_region_param()); - let vtable_segment_callback = { - let mut vtable_base = 0; + let ty::Dynamic(source, _, _) = *key.self_ty().kind() else { + bug!(); + }; + let source_principal = tcx + .normalize_erasing_regions(ty::ParamEnv::reveal_all(), source.principal().unwrap()) + .with_self_ty(tcx, tcx.types.trait_object_dummy_self); + + let target_principal = tcx + .normalize_erasing_regions(ty::ParamEnv::reveal_all(), key) + // We don't care about the self type, since it will always be the same thing. + .with_self_ty(tcx, tcx.types.trait_object_dummy_self); + let vtable_segment_callback = { + let mut vptr_offset = 0; move |segment| { match segment { VtblSegment::MetadataDSA => { - vtable_base += TyCtxt::COMMON_VTABLE_ENTRIES.len(); + vptr_offset += TyCtxt::COMMON_VTABLE_ENTRIES.len(); } VtblSegment::TraitOwnEntries { trait_ref, emit_vptr } => { - if tcx.erase_regions(trait_ref) == trait_to_be_found_erased { - return ControlFlow::Break(vtable_base); + if tcx + .normalize_erasing_late_bound_regions(ty::ParamEnv::reveal_all(), trait_ref) + == target_principal + { + return ControlFlow::Break(vptr_offset); } - vtable_base += count_own_vtable_entries(tcx, trait_ref); + + vptr_offset += tcx.own_existential_vtable_entries(trait_ref.def_id()).len(); + if emit_vptr { - vtable_base += 1; + vptr_offset += 1; } } } @@ -351,55 +359,72 @@ pub(super) fn vtable_trait_first_method_offset<'tcx>( } }; - if let Some(vtable_base) = - prepare_vtable_segments(tcx, trait_owning_vtable, vtable_segment_callback) - { - vtable_base - } else { - bug!("Failed to find info for expected trait in vtable"); - } + prepare_vtable_segments(tcx, source_principal, vtable_segment_callback).unwrap() } -/// Find slot offset for trait vptr within vtable entries of another trait -pub(crate) fn vtable_trait_upcasting_coercion_new_vptr_slot<'tcx>( +/// Given a `dyn Subtrait` and `dyn Supertrait` trait object, find the slot of +/// // the trait vptr in the subtrait's vtable. +pub(crate) fn supertrait_vtable_slot<'tcx>( tcx: TyCtxt<'tcx>, key: ( - Ty<'tcx>, // trait object type whose trait owning vtable - Ty<'tcx>, // trait object for supertrait + Ty<'tcx>, // Source -- `dyn Subtrait`. + Ty<'tcx>, // Target -- `dyn Supertrait` being coerced to. ), ) -> Option { + debug_assert!(!key.has_non_region_infer() && !key.has_non_region_param()); + let (source, target) = key; - assert!(matches!(&source.kind(), &ty::Dynamic(..)) && !source.has_infer()); - assert!(matches!(&target.kind(), &ty::Dynamic(..)) && !target.has_infer()); + let ty::Dynamic(source, _, _) = *source.kind() else { + bug!(); + }; + let source_principal = tcx + .normalize_erasing_regions(ty::ParamEnv::reveal_all(), source.principal().unwrap()) + .with_self_ty(tcx, tcx.types.trait_object_dummy_self); - // this has been typecked-before, so diagnostics is not really needed. - let unsize_trait_did = tcx.require_lang_item(LangItem::Unsize, None); + let ty::Dynamic(target, _, _) = *target.kind() else { + bug!(); + }; + let target_principal = tcx + .normalize_erasing_regions(ty::ParamEnv::reveal_all(), target.principal().unwrap()) + .with_self_ty(tcx, tcx.types.trait_object_dummy_self); - let trait_ref = ty::TraitRef::new(tcx, unsize_trait_did, [source, target]); + let vtable_segment_callback = { + let mut vptr_offset = 0; + move |segment| { + match segment { + VtblSegment::MetadataDSA => { + vptr_offset += TyCtxt::COMMON_VTABLE_ENTRIES.len(); + } + VtblSegment::TraitOwnEntries { trait_ref, emit_vptr } => { + vptr_offset += tcx.own_existential_vtable_entries(trait_ref.def_id()).len(); + if tcx.normalize_erasing_regions(ty::ParamEnv::reveal_all(), trait_ref) + == target_principal + { + if emit_vptr { + return ControlFlow::Break(Some(vptr_offset)); + } else { + return ControlFlow::Break(None); + } + } - match tcx.codegen_select_candidate((ty::ParamEnv::reveal_all(), trait_ref)) { - Ok(ImplSource::Builtin(BuiltinImplSource::TraitUpcasting { vtable_vptr_slot }, _)) => { - *vtable_vptr_slot + if emit_vptr { + vptr_offset += 1; + } + } + } + ControlFlow::Continue(()) } - otherwise => bug!("expected TraitUpcasting candidate, got {otherwise:?}"), - } -} + }; -/// Given a trait `trait_ref`, returns the number of vtable entries -/// that come from `trait_ref`, excluding its supertraits. Used in -/// computing the vtable base for an upcast trait of a trait object. -pub(crate) fn count_own_vtable_entries<'tcx>( - tcx: TyCtxt<'tcx>, - trait_ref: ty::PolyTraitRef<'tcx>, -) -> usize { - tcx.own_existential_vtable_entries(trait_ref.def_id()).len() + prepare_vtable_segments(tcx, source_principal, vtable_segment_callback).unwrap() } pub(super) fn provide(providers: &mut Providers) { *providers = Providers { own_existential_vtable_entries, vtable_entries, - vtable_trait_upcasting_coercion_new_vptr_slot, + first_method_vtable_slot, + supertrait_vtable_slot, ..*providers }; } diff --git a/compiler/rustc_transmute/src/layout/tree.rs b/compiler/rustc_transmute/src/layout/tree.rs index eae1a9dfaa2c2..241381f5875ed 100644 --- a/compiler/rustc_transmute/src/layout/tree.rs +++ b/compiler/rustc_transmute/src/layout/tree.rs @@ -331,30 +331,63 @@ pub(crate) mod rustc { assert!(def.is_enum()); let layout = ty_and_layout.layout; - if let Variants::Multiple { tag_field, .. } = layout.variants() { - // For enums (but not coroutines), the tag field is - // currently always the first field of the layout. - assert_eq!(*tag_field, 0); - } + // Computes the variant of a given index. + let layout_of_variant = |index| { + let tag = cx.tcx.tag_for_variant((ty_and_layout.ty, index)); + let variant_def = Def::Variant(def.variant(index)); + let variant_ty_and_layout = ty_and_layout.for_variant(&cx, index); + Self::from_variant(variant_def, tag, variant_ty_and_layout, layout.size, cx) + }; - let variants = def.discriminants(cx.tcx()).try_fold( - Self::uninhabited(), - |variants, (idx, ref discriminant)| { - let tag = cx.tcx.tag_for_variant((ty_and_layout.ty, idx)); - let variant_def = Def::Variant(def.variant(idx)); - let variant_ty_and_layout = ty_and_layout.for_variant(&cx, idx); - let variant = Self::from_variant( - variant_def, - tag, - variant_ty_and_layout, - layout.size, - cx, + // We consider three kinds of enums, each demanding a different + // treatment of their layout computation: + // 1. enums that are uninhabited + // 2. enums for which all but one variant is uninhabited + // 3. enums with multiple inhabited variants + match layout.variants() { + _ if layout.abi.is_uninhabited() => { + // Uninhabited enums are usually (always?) zero-sized. In + // the (unlikely?) event that an uninhabited enum is + // non-zero-sized, this assert will trigger an ICE, and this + // code should be modified such that a `layout.size` amount + // of uninhabited bytes is returned instead. + // + // Uninhabited enums are currently implemented such that + // their layout is described with `Variants::Single`, even + // though they don't necessarily have a 'single' variant to + // defer to. That said, we don't bother specifically + // matching on `Variants::Single` in this arm because the + // behavioral principles here remain true even if, for + // whatever reason, the compiler describes an uninhabited + // enum with `Variants::Multiple`. + assert_eq!(layout.size, Size::ZERO); + Ok(Self::uninhabited()) + } + Variants::Single { index } => { + // `Variants::Single` on non-uninhabited enums denotes that + // the enum delegates its layout to the variant at `index`. + layout_of_variant(*index) + } + Variants::Multiple { tag_field, .. } => { + // `Variants::Multiple` denotes an enum with multiple + // inhabited variants. The layout of such an enum is the + // disjunction of the layouts of its tagged variants. + + // For enums (but not coroutines), the tag field is + // currently always the first field of the layout. + assert_eq!(*tag_field, 0); + + let variants = def.discriminants(cx.tcx()).try_fold( + Self::uninhabited(), + |variants, (idx, ref discriminant)| { + let variant = layout_of_variant(idx)?; + Result::::Ok(variants.or(variant)) + }, )?; - Result::::Ok(variants.or(variant)) - }, - )?; - return Ok(Self::def(Def::Adt(def)).then(variants)); + return Ok(Self::def(Def::Adt(def)).then(variants)); + } + } } /// Constructs a `Tree` from a 'variant-like' layout. diff --git a/compiler/rustc_ty_utils/src/instance.rs b/compiler/rustc_ty_utils/src/instance.rs index e4dcea785d411..fcd808b59464e 100644 --- a/compiler/rustc_ty_utils/src/instance.rs +++ b/compiler/rustc_ty_utils/src/instance.rs @@ -1,5 +1,6 @@ use rustc_errors::ErrorGuaranteed; use rustc_hir::def_id::DefId; +use rustc_hir::LangItem; use rustc_infer::infer::TyCtxtInferExt; use rustc_middle::bug; use rustc_middle::query::Providers; @@ -34,7 +35,7 @@ fn resolve_instance<'tcx>( let def = if tcx.intrinsic(def_id).is_some() { debug!(" => intrinsic"); ty::InstanceDef::Intrinsic(def_id) - } else if Some(def_id) == tcx.lang_items().drop_in_place_fn() { + } else if tcx.is_lang_item(def_id, LangItem::DropInPlace) { let ty = args.type_at(0); if ty.needs_drop(tcx, param_env) { @@ -57,7 +58,7 @@ fn resolve_instance<'tcx>( debug!(" => trivial drop glue"); ty::InstanceDef::DropGlue(def_id, None) } - } else if Some(def_id) == tcx.lang_items().async_drop_in_place_fn() { + } else if tcx.is_lang_item(def_id, LangItem::AsyncDropInPlace) { let ty = args.type_at(0); if ty.async_drop_glue_morphology(tcx) != AsyncDropGlueMorphology::Noop { @@ -212,17 +213,26 @@ fn resolve_associated_item<'tcx>( Some(ty::Instance::new(leaf_def.item.def_id, args)) } - traits::ImplSource::Builtin(BuiltinImplSource::Object { vtable_base }, _) => { - traits::get_vtable_index_of_object_method(tcx, *vtable_base, trait_item_id).map( - |index| Instance { - def: ty::InstanceDef::Virtual(trait_item_id, index), + traits::ImplSource::Builtin(BuiltinImplSource::Object(_), _) => { + let trait_ref = ty::TraitRef::from_method(tcx, trait_id, rcvr_args); + if trait_ref.has_non_region_infer() || trait_ref.has_non_region_param() { + // We only resolve totally substituted vtable entries. + None + } else { + let vtable_base = tcx.first_method_vtable_slot(trait_ref); + let offset = tcx + .own_existential_vtable_entries(trait_id) + .iter() + .copied() + .position(|def_id| def_id == trait_item_id); + offset.map(|offset| Instance { + def: ty::InstanceDef::Virtual(trait_item_id, vtable_base + offset), args: rcvr_args, - }, - ) + }) + } } traits::ImplSource::Builtin(BuiltinImplSource::Misc, _) => { - let lang_items = tcx.lang_items(); - if Some(trait_ref.def_id) == lang_items.clone_trait() { + if tcx.is_lang_item(trait_ref.def_id, LangItem::Clone) { // FIXME(eddyb) use lang items for methods instead of names. let name = tcx.item_name(trait_item_id); if name == sym::clone { @@ -248,8 +258,8 @@ fn resolve_associated_item<'tcx>( let args = tcx.erase_regions(rcvr_args); Some(ty::Instance::new(trait_item_id, args)) } - } else if Some(trait_ref.def_id) == lang_items.fn_ptr_trait() { - if lang_items.fn_ptr_addr() == Some(trait_item_id) { + } else if tcx.is_lang_item(trait_ref.def_id, LangItem::FnPtrTrait) { + if tcx.is_lang_item(trait_item_id, LangItem::FnPtrAddr) { let self_ty = trait_ref.self_ty(); if !matches!(self_ty.kind(), ty::FnPtr(..)) { return Ok(None); diff --git a/compiler/rustc_type_ir/src/infcx.rs b/compiler/rustc_type_ir/src/infcx.rs index 24e10722448cc..4a5f34e354208 100644 --- a/compiler/rustc_type_ir/src/infcx.rs +++ b/compiler/rustc_type_ir/src/infcx.rs @@ -1,23 +1,77 @@ -use crate::{ConstVid, EffectVid, FloatVid, IntVid, Interner, RegionVid, TyVid, UniverseIndex}; +use crate::fold::TypeFoldable; +use crate::relate::Relate; +use crate::solve::{Goal, NoSolution}; +use crate::{self as ty, Interner}; -pub trait InferCtxtLike { +pub trait InferCtxtLike: Sized { type Interner: Interner; fn interner(&self) -> Self::Interner; - fn universe_of_ty(&self, ty: TyVid) -> Option; - fn universe_of_lt(&self, lt: RegionVid) -> Option; - fn universe_of_ct(&self, ct: ConstVid) -> Option; + fn universe_of_ty(&self, ty: ty::TyVid) -> Option; + fn universe_of_lt(&self, lt: ty::RegionVid) -> Option; + fn universe_of_ct(&self, ct: ty::ConstVid) -> Option; - fn opportunistic_resolve_ty_var(&self, vid: TyVid) -> ::Ty; - fn opportunistic_resolve_int_var(&self, vid: IntVid) -> ::Ty; - fn opportunistic_resolve_float_var(&self, vid: FloatVid) -> ::Ty; - fn opportunistic_resolve_ct_var(&self, vid: ConstVid) -> ::Const; + fn root_ty_var(&self, var: ty::TyVid) -> ty::TyVid; + fn root_const_var(&self, var: ty::ConstVid) -> ty::ConstVid; + + fn opportunistic_resolve_ty_var(&self, vid: ty::TyVid) -> ::Ty; + fn opportunistic_resolve_int_var(&self, vid: ty::IntVid) -> ::Ty; + fn opportunistic_resolve_float_var( + &self, + vid: ty::FloatVid, + ) -> ::Ty; + fn opportunistic_resolve_ct_var( + &self, + vid: ty::ConstVid, + ) -> ::Const; fn opportunistic_resolve_effect_var( &self, - vid: EffectVid, + vid: ty::EffectVid, ) -> ::Const; - fn opportunistic_resolve_lt_var(&self, vid: RegionVid) -> ::Region; + fn opportunistic_resolve_lt_var( + &self, + vid: ty::RegionVid, + ) -> ::Region; fn defining_opaque_types(&self) -> ::DefiningOpaqueTypes; + + fn next_ty_infer(&self) -> ::Ty; + fn next_const_infer(&self) -> ::Const; + fn fresh_args_for_item( + &self, + def_id: ::DefId, + ) -> ::GenericArgs; + + fn instantiate_binder_with_infer + Copy>( + &self, + value: ty::Binder, + ) -> T; + + fn enter_forall + Copy, U>( + &self, + value: ty::Binder, + f: impl FnOnce(T) -> U, + ) -> U; + + fn relate>( + &self, + param_env: ::ParamEnv, + lhs: T, + variance: ty::Variance, + rhs: T, + ) -> Result::Predicate>>, NoSolution>; + + fn eq_structurally_relating_aliases>( + &self, + param_env: ::ParamEnv, + lhs: T, + rhs: T, + ) -> Result::Predicate>>, NoSolution>; + + fn resolve_vars_if_possible(&self, value: T) -> T + where + T: TypeFoldable; + + fn probe(&self, probe: impl FnOnce() -> T) -> T; } diff --git a/compiler/rustc_type_ir/src/inherent.rs b/compiler/rustc_type_ir/src/inherent.rs index 2fc765f1c8fae..6b84592978a26 100644 --- a/compiler/rustc_type_ir/src/inherent.rs +++ b/compiler/rustc_type_ir/src/inherent.rs @@ -29,6 +29,8 @@ pub trait Ty>: { fn new_bool(interner: I) -> Self; + fn new_u8(interner: I) -> Self; + fn new_infer(interner: I, var: ty::InferTy) -> Self; fn new_var(interner: I, var: ty::TyVid) -> Self; @@ -39,6 +41,18 @@ pub trait Ty>: fn new_alias(interner: I, kind: ty::AliasTyKind, alias_ty: ty::AliasTy) -> Self; + fn new_projection( + interner: I, + def_id: I::DefId, + args: impl IntoIterator>, + ) -> Self { + Ty::new_alias( + interner, + ty::AliasTyKind::Projection, + ty::AliasTy::new(interner, def_id, args), + ) + } + fn new_error(interner: I, guar: I::ErrorGuaranteed) -> Self; fn new_adt(interner: I, adt_def: I::AdtDef, args: I::GenericArgs) -> Self; @@ -75,6 +89,12 @@ pub trait Ty>: It: Iterator, T: CollectAndApply; + fn new_fn_def(interner: I, def_id: I::DefId, args: I::GenericArgs) -> Self; + + fn new_fn_ptr(interner: I, sig: ty::Binder>) -> Self; + + fn new_pat(interner: I, ty: Self, pat: I::Pat) -> Self; + fn tuple_fields(self) -> I::Tys; fn to_opt_closure_kind(self) -> Option; @@ -83,11 +103,29 @@ pub trait Ty>: fn from_coroutine_closure_kind(interner: I, kind: ty::ClosureKind) -> Self; - fn new_fn_def(interner: I, def_id: I::DefId, args: I::GenericArgs) -> Self; - - fn new_fn_ptr(interner: I, sig: ty::Binder>) -> Self; - - fn new_pat(interner: I, ty: Self, pat: I::Pat) -> Self; + fn is_ty_var(self) -> bool { + matches!(self.kind(), ty::Infer(ty::TyVar(_))) + } + + fn fn_sig(self, interner: I) -> ty::Binder> { + match self.kind() { + ty::FnPtr(sig) => sig, + ty::FnDef(def_id, args) => interner.fn_sig(def_id).instantiate(interner, &args), + ty::Error(_) => { + // ignore errors (#54954) + ty::Binder::dummy(ty::FnSig { + inputs_and_output: Default::default(), + c_variadic: false, + safety: I::Safety::safe(), + abi: I::Abi::rust(), + }) + } + ty::Closure(..) => panic!( + "to get the signature of a closure, use `args.as_closure().sig()` not `fn_sig()`", + ), + _ => panic!("Ty::fn_sig() called on non-fn type: {:?}", self), + } + } } pub trait Tys>: @@ -103,12 +141,16 @@ pub trait Tys>: fn split_inputs_and_output(self) -> (I::FnInputTys, I::Ty); } -pub trait Abi>: Copy + Debug + Hash + Eq + TypeVisitable { +pub trait Abi>: Copy + Debug + Hash + Eq + Relate { + fn rust() -> Self; + /// Whether this ABI is `extern "Rust"`. fn is_rust(self) -> bool; } -pub trait Safety>: Copy + Debug + Hash + Eq + TypeVisitable { +pub trait Safety>: Copy + Debug + Hash + Eq + Relate { + fn safe() -> Self; + fn is_safe(self) -> bool; fn prefix_str(self) -> &'static str; @@ -122,7 +164,6 @@ pub trait Region>: + Into + IntoKind> + Flags - + TypeVisitable + Relate { fn new_bound(interner: I, debruijn: ty::DebruijnIndex, var: I::BoundRegion) -> Self; @@ -158,12 +199,57 @@ pub trait Const>: fn new_unevaluated(interner: I, uv: ty::UnevaluatedConst) -> Self; fn new_expr(interner: I, expr: I::ExprConst) -> Self; + + fn is_ct_var(self) -> bool { + matches!(self.kind(), ty::ConstKind::Infer(ty::InferConst::Var(_))) + } } pub trait GenericsOf> { fn count(&self) -> usize; } +pub trait GenericArg>: + Copy + + Debug + + Hash + + Eq + + IntoKind> + + TypeVisitable + + Relate + + From + + From + + From +{ +} + +pub trait Term>: + Copy + Debug + Hash + Eq + IntoKind> + TypeFoldable + Relate +{ + fn as_type(&self) -> Option { + if let ty::TermKind::Ty(ty) = self.kind() { Some(ty) } else { None } + } + + fn expect_type(&self) -> I::Ty { + self.as_type().expect("expected a type, but found a const") + } + + fn as_const(&self) -> Option { + if let ty::TermKind::Const(c) = self.kind() { Some(c) } else { None } + } + + fn expect_const(&self) -> I::Const { + self.as_const().expect("expected a const, but found a type") + } + + fn is_infer(self) -> bool { + match self.kind() { + ty::TermKind::Ty(ty) => ty.is_ty_var(), + ty::TermKind::Const(ct) => ct.is_ct_var(), + } + } +} + pub trait GenericArgs>: Copy + Debug @@ -172,7 +258,6 @@ pub trait GenericArgs>: + IntoIterator + Deref> + Default - + TypeFoldable + Relate { fn type_at(self, i: usize) -> I::Ty; @@ -188,6 +273,16 @@ pub trait GenericArgs>: fn split_closure_args(self) -> ty::ClosureArgsParts; fn split_coroutine_closure_args(self) -> ty::CoroutineClosureArgsParts; fn split_coroutine_args(self) -> ty::CoroutineArgsParts; + + fn as_closure(self) -> ty::ClosureArgs { + ty::ClosureArgs { args: self } + } + fn as_coroutine_closure(self) -> ty::CoroutineClosureArgs { + ty::CoroutineClosureArgs { args: self } + } + fn as_coroutine(self) -> ty::CoroutineArgs { + ty::CoroutineArgs { args: self } + } } pub trait Predicate>: @@ -198,9 +293,20 @@ pub trait Predicate>: + TypeSuperVisitable + TypeSuperFoldable + Flags + + UpcastFrom> + + UpcastFrom>> + + UpcastFrom> + + UpcastFrom>> + + UpcastFrom + UpcastFrom> + + UpcastFrom> + + UpcastFrom>> + + IntoKind>> { fn is_coinductive(self, interner: I) -> bool; + + // FIXME: Eventually uplift the impl out of rustc and make this defaulted. + fn allow_normalization(self) -> bool; } pub trait Clause>: @@ -208,6 +314,7 @@ pub trait Clause>: + Debug + Hash + Eq + + TypeFoldable // FIXME: Remove these, uplift the `Upcast` impls. + UpcastFrom>> + UpcastFrom>> @@ -242,8 +349,17 @@ pub trait ParamLike { pub trait AdtDef: Copy + Debug + Hash + Eq { fn def_id(self) -> I::DefId; + + fn is_phantom_data(self) -> bool; + + // FIXME: perhaps use `all_fields` and expose `FieldDef`. + fn all_field_tys(self, interner: I) -> ty::EarlyBinder>; + + fn sized_constraint(self, interner: I) -> Option>; } pub trait Features: Copy { fn generic_const_exprs(self) -> bool; + + fn coroutine_clone(self) -> bool; } diff --git a/compiler/rustc_type_ir/src/interner.rs b/compiler/rustc_type_ir/src/interner.rs index b7f412ecb8ea9..a2b71e1fc2575 100644 --- a/compiler/rustc_type_ir/src/interner.rs +++ b/compiler/rustc_type_ir/src/interner.rs @@ -1,3 +1,4 @@ +use rustc_ast_ir::Movability; use smallvec::SmallVec; use std::fmt::Debug; use std::hash::Hash; @@ -6,6 +7,7 @@ use std::ops::Deref; use crate::fold::TypeFoldable; use crate::inherent::*; use crate::ir_print::IrPrint; +use crate::lang_items::TraitSolverLangItem; use crate::relate::Relate; use crate::solve::inspect::CanonicalGoalEvaluationStep; use crate::visit::{Flags, TypeSuperVisitable, TypeVisitable}; @@ -31,20 +33,8 @@ pub trait Interner: type GenericArgs: GenericArgs; type GenericArgsSlice: Copy + Debug + Hash + Eq + Deref; - type GenericArg: Copy - + Debug - + Hash - + Eq - + IntoKind> - + TypeVisitable - + Relate; - type Term: Copy - + Debug - + Hash - + Eq - + IntoKind> - + TypeFoldable - + Relate; + type GenericArg: GenericArg; + type Term: Term; type BoundVarKinds: Copy + Debug @@ -74,11 +64,16 @@ pub trait Interner: // Things stored inside of tys type ErrorGuaranteed: Copy + Debug + Hash + Eq; - type BoundExistentialPredicates: Copy + Debug + Hash + Eq + Relate; + type BoundExistentialPredicates: Copy + + Debug + + Hash + + Eq + + Relate + + IntoIterator>>; type AllocId: Copy + Debug + Hash + Eq; type Pat: Copy + Debug + Hash + Eq + Debug + Relate; - type Safety: Safety + TypeFoldable + Relate; - type Abi: Abi + TypeFoldable + Relate; + type Safety: Safety; + type Abi: Abi; // Kinds of consts type Const: Const; @@ -153,6 +148,38 @@ pub trait Interner: type Features: Features; fn features(self) -> Self::Features; + + fn bound_coroutine_hidden_types( + self, + def_id: Self::DefId, + ) -> impl IntoIterator>>; + + fn fn_sig( + self, + def_id: Self::DefId, + ) -> ty::EarlyBinder>>; + + fn coroutine_movability(self, def_id: Self::DefId) -> Movability; + + fn coroutine_for_closure(self, def_id: Self::DefId) -> Self::DefId; + + fn generics_require_sized_self(self, def_id: Self::DefId) -> bool; + + fn item_bounds( + self, + def_id: Self::DefId, + ) -> ty::EarlyBinder>; + + fn super_predicates_of( + self, + def_id: Self::DefId, + ) -> ty::EarlyBinder>; + + fn has_target_features(self, def_id: Self::DefId) -> bool; + + fn require_lang_item(self, lang_item: TraitSolverLangItem) -> Self::DefId; + + fn associated_type_def_ids(self, def_id: Self::DefId) -> impl IntoIterator; } /// Imagine you have a function `F: FnOnce(&[T]) -> R`, plus an iterator `iter` diff --git a/compiler/rustc_type_ir/src/lang_items.rs b/compiler/rustc_type_ir/src/lang_items.rs new file mode 100644 index 0000000000000..9a3b324fcd765 --- /dev/null +++ b/compiler/rustc_type_ir/src/lang_items.rs @@ -0,0 +1,8 @@ +/// Lang items used by the new trait solver. This can be mapped to whatever internal +/// representation of `LangItem`s used in the underlying compiler implementation. +pub enum TraitSolverLangItem { + Future, + FutureOutput, + AsyncFnKindHelper, + AsyncFnKindUpvars, +} diff --git a/compiler/rustc_type_ir/src/lib.rs b/compiler/rustc_type_ir/src/lib.rs index a76e278cc05d0..4775a0f8cbbe4 100644 --- a/compiler/rustc_type_ir/src/lib.rs +++ b/compiler/rustc_type_ir/src/lib.rs @@ -32,6 +32,7 @@ pub mod error; pub mod fold; pub mod inherent; pub mod ir_print; +pub mod lang_items; pub mod lift; pub mod relate; pub mod solve; @@ -73,6 +74,7 @@ pub use DynKind::*; pub use InferTy::*; pub use RegionKind::*; pub use TyKind::*; +pub use Variance::*; rustc_index::newtype_index! { /// A [De Bruijn index][dbi] is a standard means of representing diff --git a/compiler/rustc_type_ir/src/relate.rs b/compiler/rustc_type_ir/src/relate.rs index cae1d13020d34..8a6ba87b60e06 100644 --- a/compiler/rustc_type_ir/src/relate.rs +++ b/compiler/rustc_type_ir/src/relate.rs @@ -128,7 +128,7 @@ pub fn relate_args_invariantly>( b_arg: I::GenericArgs, ) -> RelateResult { relation.tcx().mk_args_from_iter(iter::zip(a_arg, b_arg).map(|(a, b)| { - relation.relate_with_variance(ty::Variance::Invariant, VarianceDiagInfo::default(), a, b) + relation.relate_with_variance(ty::Invariant, VarianceDiagInfo::default(), a, b) })) } @@ -145,7 +145,7 @@ pub fn relate_args_with_variances>( let mut cached_ty = None; let params = iter::zip(a_arg, b_arg).enumerate().map(|(i, (a, b))| { let variance = variances[i]; - let variance_info = if variance == ty::Variance::Invariant && fetch_ty_for_diag { + let variance_info = if variance == ty::Invariant && fetch_ty_for_diag { let ty = *cached_ty.get_or_insert_with(|| tcx.type_of(ty_def_id).instantiate(tcx, &a_arg)); VarianceDiagInfo::Invariant { ty, param_index: i.try_into().unwrap() } @@ -191,7 +191,7 @@ impl Relate for ty::FnSig { relation.relate(a, b) } else { relation.relate_with_variance( - ty::Variance::Contravariant, + ty::Contravariant, VarianceDiagInfo::default(), a, b, @@ -311,13 +311,13 @@ impl Relate for ty::ExistentialProjection { })) } else { let term = relation.relate_with_variance( - ty::Variance::Invariant, + ty::Invariant, VarianceDiagInfo::default(), a.term, b.term, )?; let args = relation.relate_with_variance( - ty::Variance::Invariant, + ty::Invariant, VarianceDiagInfo::default(), a.args, b.args, @@ -466,9 +466,9 @@ pub fn structurally_relate_tys>( } let (variance, info) = match a_mutbl { - Mutability::Not => (ty::Variance::Covariant, VarianceDiagInfo::None), + Mutability::Not => (ty::Covariant, VarianceDiagInfo::None), Mutability::Mut => { - (ty::Variance::Invariant, VarianceDiagInfo::Invariant { ty: a, param_index: 0 }) + (ty::Invariant, VarianceDiagInfo::Invariant { ty: a, param_index: 0 }) } }; @@ -483,9 +483,9 @@ pub fn structurally_relate_tys>( } let (variance, info) = match a_mutbl { - Mutability::Not => (ty::Variance::Covariant, VarianceDiagInfo::None), + Mutability::Not => (ty::Covariant, VarianceDiagInfo::None), Mutability::Mut => { - (ty::Variance::Invariant, VarianceDiagInfo::Invariant { ty: a, param_index: 0 }) + (ty::Invariant, VarianceDiagInfo::Invariant { ty: a, param_index: 0 }) } }; @@ -612,7 +612,7 @@ pub fn structurally_relate_consts>( } let args = relation.relate_with_variance( - ty::Variance::Invariant, + ty::Invariant, VarianceDiagInfo::default(), au.args, bu.args, diff --git a/compiler/rustc_type_ir/src/solve.rs b/compiler/rustc_type_ir/src/solve.rs index 45125fe619193..6a89a8a4cc306 100644 --- a/compiler/rustc_type_ir/src/solve.rs +++ b/compiler/rustc_type_ir/src/solve.rs @@ -171,25 +171,20 @@ pub enum CandidateSource { #[derive(Clone, Copy, Hash, PartialEq, Eq, Debug)] #[cfg_attr(feature = "nightly", derive(HashStable_NoContext, TyEncodable, TyDecodable))] pub enum BuiltinImplSource { - /// Some builtin impl we don't need to differentiate. This should be used + /// Some built-in impl we don't need to differentiate. This should be used /// unless more specific information is necessary. Misc, - /// A builtin impl for trait objects. + /// A built-in impl for trait objects. The index is only used in winnowing. + Object(usize), + /// A built-in implementation of `Upcast` for trait objects to other trait objects. /// - /// The vtable is formed by concatenating together the method lists of - /// the base object trait and all supertraits, pointers to supertrait vtable will - /// be provided when necessary; this is the start of `upcast_trait_ref`'s methods - /// in that vtable. - Object { vtable_base: usize }, - /// The vtable is formed by concatenating together the method lists of - /// the base object trait and all supertraits, pointers to supertrait vtable will - /// be provided when necessary; this is the position of `upcast_trait_ref`'s vtable - /// within that vtable. - TraitUpcasting { vtable_vptr_slot: Option }, + /// This can be removed when `feature(dyn_upcasting)` is stabilized, since we only + /// use it to detect when upcasting traits in hir typeck. + TraitUpcasting, /// Unsizing a tuple like `(A, B, ..., X)` to `(A, B, ..., Y)` if `X` unsizes to `Y`. /// - /// This needs to be a separate variant as it is still unstable and we need to emit - /// a feature error when using it on stable. + /// This can be removed when `feature(tuple_unsizing)` is stabilized, since we only + /// use it to detect when unsizing tuples in hir typeck. TupleUnsizing, } diff --git a/compiler/stable_mir/src/compiler_interface.rs b/compiler/stable_mir/src/compiler_interface.rs index 085dfd9ea8909..3e138e3c2e04e 100644 --- a/compiler/stable_mir/src/compiler_interface.rs +++ b/compiler/stable_mir/src/compiler_interface.rs @@ -94,10 +94,6 @@ pub trait Context { /// Retrieve the plain function name of an intrinsic. fn intrinsic_name(&self, def: IntrinsicDef) -> Symbol; - /// Returns whether the intrinsic has no meaningful body and all backends - /// need to shim all calls to it. - fn intrinsic_must_be_overridden(&self, def: IntrinsicDef) -> bool; - /// Retrieve the closure signature for the given generic arguments. fn closure_sig(&self, args: &GenericArgs) -> PolyFnSig; diff --git a/compiler/stable_mir/src/crate_def.rs b/compiler/stable_mir/src/crate_def.rs index 70ca9e6825e1f..67752a5e629f3 100644 --- a/compiler/stable_mir/src/crate_def.rs +++ b/compiler/stable_mir/src/crate_def.rs @@ -1,7 +1,7 @@ //! Module that define a common trait for things that represent a crate definition, //! such as, a function, a trait, an enum, and any other definitions. -use crate::ty::Span; +use crate::ty::{GenericArgs, Span, Ty}; use crate::{with, Crate, Symbol}; /// A unique identification number for each item accessible for the current compilation unit. @@ -52,6 +52,23 @@ pub trait CrateDef { } } +/// A trait that can be used to retrieve a definition's type. +/// +/// Note that not every CrateDef has a type `Ty`. They should not implement this trait. +pub trait CrateDefType: CrateDef { + /// Returns the type of this crate item. + fn ty(&self) -> Ty { + with(|cx| cx.def_ty(self.def_id())) + } + + /// Retrieve the type of this definition by instantiating and normalizing it with `args`. + /// + /// This will panic if instantiation fails. + fn ty_with_args(&self, args: &GenericArgs) -> Ty { + with(|cx| cx.def_ty_with_args(self.def_id(), args)) + } +} + macro_rules! crate_def { ( $(#[$attr:meta])* $vis:vis $name:ident $(;)? @@ -67,3 +84,21 @@ macro_rules! crate_def { } }; } + +macro_rules! crate_def_with_ty { + ( $(#[$attr:meta])* + $vis:vis $name:ident $(;)? + ) => { + $(#[$attr])* + #[derive(Clone, Copy, PartialEq, Eq, Debug, Hash)] + $vis struct $name(pub DefId); + + impl CrateDef for $name { + fn def_id(&self) -> DefId { + self.0 + } + } + + impl CrateDefType for $name {} + }; +} diff --git a/compiler/stable_mir/src/lib.rs b/compiler/stable_mir/src/lib.rs index d9f988935ab19..8385856ae532d 100644 --- a/compiler/stable_mir/src/lib.rs +++ b/compiler/stable_mir/src/lib.rs @@ -22,8 +22,7 @@ use std::fmt::Debug; use std::io; use crate::compiler_interface::with; -pub use crate::crate_def::CrateDef; -pub use crate::crate_def::DefId; +pub use crate::crate_def::{CrateDef, CrateDefType, DefId}; pub use crate::error::*; use crate::mir::Body; use crate::mir::Mutability; @@ -115,12 +114,15 @@ pub enum CtorKind { pub type Filename = String; -crate_def! { +crate_def_with_ty! { /// Holds information about an item in a crate. pub CrateItem; } impl CrateItem { + /// This will return the body of an item. + /// + /// This will panic if no body is available. pub fn body(&self) -> mir::Body { with(|cx| cx.mir_body(self.0)) } diff --git a/compiler/stable_mir/src/mir/body.rs b/compiler/stable_mir/src/mir/body.rs index 43e4682dc1008..e0f9e7ae67a0f 100644 --- a/compiler/stable_mir/src/mir/body.rs +++ b/compiler/stable_mir/src/mir/body.rs @@ -637,7 +637,7 @@ pub enum AggregateKind { pub enum Operand { Copy(Place), Move(Place), - Constant(Constant), + Constant(ConstOperand), } #[derive(Clone, Eq, PartialEq)] @@ -653,6 +653,13 @@ impl From for Place { } } +#[derive(Clone, Debug, Eq, PartialEq)] +pub struct ConstOperand { + pub span: Span, + pub user_ty: Option, + pub const_: MirConst, +} + /// Debug information pertaining to a user variable. #[derive(Clone, Debug, Eq, PartialEq)] pub struct VarDebugInfo { @@ -714,13 +721,6 @@ pub enum VarDebugInfoContents { Const(ConstOperand), } -#[derive(Clone, Debug, Eq, PartialEq)] -pub struct ConstOperand { - pub span: Span, - pub user_ty: Option, - pub const_: MirConst, -} - // In MIR ProjectionElem is parameterized on the second Field argument and the Index argument. This // is so it can be used for both Places (for which the projection elements are of type // ProjectionElem) and user-provided type annotations (for which the projection elements @@ -829,13 +829,6 @@ pub type FieldIdx = usize; type UserTypeAnnotationIndex = usize; -#[derive(Clone, Debug, Eq, PartialEq)] -pub struct Constant { - pub span: Span, - pub user_ty: Option, - pub literal: MirConst, -} - /// The possible branch sites of a [TerminatorKind::SwitchInt]. #[derive(Clone, Debug, Eq, PartialEq)] pub struct SwitchTargets { @@ -1001,9 +994,9 @@ impl Operand { } } -impl Constant { +impl ConstOperand { pub fn ty(&self) -> Ty { - self.literal.ty() + self.const_.ty() } } diff --git a/compiler/stable_mir/src/mir/pretty.rs b/compiler/stable_mir/src/mir/pretty.rs index 2fb180b84c7c3..83734a0d13826 100644 --- a/compiler/stable_mir/src/mir/pretty.rs +++ b/compiler/stable_mir/src/mir/pretty.rs @@ -310,7 +310,7 @@ fn pretty_operand(operand: &Operand) -> String { Operand::Move(mv) => { format!("move {:?}", mv) } - Operand::Constant(cnst) => pretty_mir_const(&cnst.literal), + Operand::Constant(cnst) => pretty_mir_const(&cnst.const_), } } diff --git a/compiler/stable_mir/src/mir/visit.rs b/compiler/stable_mir/src/mir/visit.rs index 10f30083dc2d9..50d7bae21db72 100644 --- a/compiler/stable_mir/src/mir/visit.rs +++ b/compiler/stable_mir/src/mir/visit.rs @@ -108,8 +108,8 @@ pub trait MirVisitor { self.super_ty(ty) } - fn visit_constant(&mut self, constant: &Constant, location: Location) { - self.super_constant(constant, location) + fn visit_const_operand(&mut self, constant: &ConstOperand, location: Location) { + self.super_const_operand(constant, location) } fn visit_mir_const(&mut self, constant: &MirConst, location: Location) { @@ -366,7 +366,7 @@ pub trait MirVisitor { self.visit_place(place, PlaceContext::NON_MUTATING, location) } Operand::Constant(constant) => { - self.visit_constant(constant, location); + self.visit_const_operand(constant, location); } } } @@ -380,10 +380,10 @@ pub trait MirVisitor { let _ = ty; } - fn super_constant(&mut self, constant: &Constant, location: Location) { - let Constant { span, user_ty: _, literal } = constant; + fn super_const_operand(&mut self, constant: &ConstOperand, location: Location) { + let ConstOperand { span, user_ty: _, const_ } = constant; self.visit_span(span); - self.visit_mir_const(literal, location); + self.visit_mir_const(const_, location); } fn super_mir_const(&mut self, constant: &MirConst, location: Location) { diff --git a/compiler/stable_mir/src/ty.rs b/compiler/stable_mir/src/ty.rs index bcbe87f7303b3..35927237281a0 100644 --- a/compiler/stable_mir/src/ty.rs +++ b/compiler/stable_mir/src/ty.rs @@ -3,9 +3,10 @@ use super::{ with, DefId, Error, Symbol, }; use crate::abi::Layout; +use crate::crate_def::{CrateDef, CrateDefType}; use crate::mir::alloc::{read_target_int, read_target_uint, AllocId}; +use crate::mir::mono::StaticDef; use crate::target::MachineInfo; -use crate::{crate_def::CrateDef, mir::mono::StaticDef}; use crate::{Filename, Opaque}; use std::fmt::{self, Debug, Display, Formatter}; use std::ops::Range; @@ -122,7 +123,7 @@ impl TyConst { } /// Creates an interned usize constant. - fn try_from_target_usize(val: u64) -> Result { + pub fn try_from_target_usize(val: u64) -> Result { with(|cx| cx.try_new_ty_const_uint(val.into(), UintTy::Usize)) } @@ -504,6 +505,15 @@ impl TyKind { pub fn discriminant_ty(&self) -> Option { self.rigid().map(|ty| with(|cx| cx.rigid_ty_discriminant_ty(ty))) } + + /// Deconstruct a function type if this is one. + pub fn fn_def(&self) -> Option<(FnDef, &GenericArgs)> { + if let TyKind::RigidTy(RigidTy::FnDef(def, args)) = self { + Some((*def, args)) + } else { + None + } + } } pub struct TypeAndMut { @@ -629,7 +639,7 @@ impl ForeignModule { } } -crate_def! { +crate_def_with_ty! { /// Hold information about a ForeignItem in a crate. pub ForeignDef; } @@ -647,7 +657,7 @@ pub enum ForeignItemKind { Type(Ty), } -crate_def! { +crate_def_with_ty! { /// Hold information about a function definition in a crate. pub FnDef; } @@ -658,6 +668,11 @@ impl FnDef { with(|ctx| ctx.has_body(self.0).then(|| ctx.mir_body(self.0))) } + // Check if the function body is available. + pub fn has_body(&self) -> bool { + with(|ctx| ctx.has_body(self.0)) + } + /// Get the information of the intrinsic if this function is a definition of one. pub fn as_intrinsic(&self) -> Option { with(|cx| cx.intrinsic(self.def_id())) @@ -668,9 +683,15 @@ impl FnDef { pub fn is_intrinsic(&self) -> bool { self.as_intrinsic().is_some() } + + /// Get the function signature for this function definition. + pub fn fn_sig(&self) -> PolyFnSig { + let kind = self.ty().kind(); + kind.fn_sig().unwrap() + } } -crate_def! { +crate_def_with_ty! { pub IntrinsicDef; } @@ -684,7 +705,7 @@ impl IntrinsicDef { /// Returns whether the intrinsic has no meaningful body and all backends /// need to shim all calls to it. pub fn must_be_overridden(&self) -> bool { - with(|cx| cx.intrinsic_must_be_overridden(*self)) + with(|cx| !cx.has_body(self.0)) } } @@ -710,7 +731,7 @@ crate_def! { pub BrNamedDef; } -crate_def! { +crate_def_with_ty! { pub AdtDef; } @@ -866,7 +887,7 @@ crate_def! { pub GenericDef; } -crate_def! { +crate_def_with_ty! { pub ConstDef; } diff --git a/config.example.toml b/config.example.toml index fb45493ec4a15..76541ee4e9e7e 100644 --- a/config.example.toml +++ b/config.example.toml @@ -657,7 +657,7 @@ # whether to set it as rustc's default linker on `x86_64-unknown-linux-gnu`. This will also only be # when *not* building an external LLVM (so only when using `download-ci-llvm` or building LLVM from # the in-tree source): setting `llvm-config` in the `[target.x86_64-unknown-linux-gnu]` section will -# make this default to false. +# make this default to false. #lld = false in all cases, except on `x86_64-unknown-linux-gnu` as described above, where it is true # Indicates whether LLD will be used to link Rust crates during bootstrap on @@ -676,7 +676,7 @@ #llvm-tools = true # Indicates whether the `self-contained` llvm-bitcode-linker, will be made available -# in the sysroot +# in the sysroot. It is required for running nvptx tests. #llvm-bitcode-linker = false # Whether to deny warnings in crates diff --git a/library/alloc/src/rc.rs b/library/alloc/src/rc.rs index c3561512c0579..2b7ab2f6e2590 100644 --- a/library/alloc/src/rc.rs +++ b/library/alloc/src/rc.rs @@ -3516,7 +3516,7 @@ fn data_offset_align(align: usize) -> usize { layout.size() + layout.padding_needed_for(align) } -/// A uniquely owned `Rc` +/// A uniquely owned [`Rc`]. /// /// This represents an `Rc` that is known to be uniquely owned -- that is, have exactly one strong /// reference. Multiple weak pointers can be created, but attempts to upgrade those to strong @@ -3554,13 +3554,24 @@ fn data_offset_align(align: usize) -> usize { /// including fallible or async constructors. #[unstable(feature = "unique_rc_arc", issue = "112566")] #[derive(Debug)] -pub struct UniqueRc { +pub struct UniqueRc< + T: ?Sized, + #[unstable(feature = "allocator_api", issue = "32838")] A: Allocator = Global, +> { ptr: NonNull>, phantom: PhantomData>, + alloc: A, } +#[unstable(feature = "unique_rc_arc", issue = "112566")] +impl, U: ?Sized, A: Allocator> CoerceUnsized> + for UniqueRc +{ +} + +// Depends on A = Global impl UniqueRc { - /// Creates a new `UniqueRc` + /// Creates a new `UniqueRc`. /// /// Weak references to this `UniqueRc` can be created with [`UniqueRc::downgrade`]. Upgrading /// these weak references will fail before the `UniqueRc` has been converted into an [`Rc`]. @@ -3569,34 +3580,36 @@ impl UniqueRc { #[cfg(not(no_global_oom_handling))] #[unstable(feature = "unique_rc_arc", issue = "112566")] pub fn new(value: T) -> Self { - Self { - ptr: Box::leak(Box::new(RcBox { + Self::new_in(value, Global) + } +} + +impl UniqueRc { + /// Creates a new `UniqueRc` in the provided allocator. + /// + /// Weak references to this `UniqueRc` can be created with [`UniqueRc::downgrade`]. Upgrading + /// these weak references will fail before the `UniqueRc` has been converted into an [`Rc`]. + /// After converting the `UniqueRc` into an [`Rc`], any weak references created beforehand will + /// point to the new [`Rc`]. + #[cfg(not(no_global_oom_handling))] + #[unstable(feature = "unique_rc_arc", issue = "112566")] + pub fn new_in(value: T, alloc: A) -> Self { + let (ptr, alloc) = Box::into_unique(Box::new_in( + RcBox { strong: Cell::new(0), // keep one weak reference so if all the weak pointers that are created are dropped // the UniqueRc still stays valid. weak: Cell::new(1), value, - })) - .into(), - phantom: PhantomData, - } - } - - /// Creates a new weak reference to the `UniqueRc` - /// - /// Attempting to upgrade this weak reference will fail before the `UniqueRc` has been converted - /// to a [`Rc`] using [`UniqueRc::into_rc`]. - #[unstable(feature = "unique_rc_arc", issue = "112566")] - pub fn downgrade(this: &Self) -> Weak { - // SAFETY: This pointer was allocated at creation time and we guarantee that we only have - // one strong reference before converting to a regular Rc. - unsafe { - this.ptr.as_ref().inc_weak(); - } - Weak { ptr: this.ptr, alloc: Global } + }, + alloc, + )); + Self { ptr: ptr.into(), phantom: PhantomData, alloc } } +} - /// Converts the `UniqueRc` into a regular [`Rc`] +impl UniqueRc { + /// Converts the `UniqueRc` into a regular [`Rc`]. /// /// This consumes the `UniqueRc` and returns a regular [`Rc`] that contains the `value` that /// is passed to `into_rc`. @@ -3604,19 +3617,41 @@ impl UniqueRc { /// Any weak references created before this method is called can now be upgraded to strong /// references. #[unstable(feature = "unique_rc_arc", issue = "112566")] - pub fn into_rc(this: Self) -> Rc { + pub fn into_rc(this: Self) -> Rc { let mut this = ManuallyDrop::new(this); + + // Move the allocator out. + // SAFETY: `this.alloc` will not be accessed again, nor dropped because it is in + // a `ManuallyDrop`. + let alloc: A = unsafe { ptr::read(&this.alloc) }; + // SAFETY: This pointer was allocated at creation time so we know it is valid. unsafe { // Convert our weak reference into a strong reference this.ptr.as_mut().strong.set(1); - Rc::from_inner(this.ptr) + Rc::from_inner_in(this.ptr, alloc) + } + } +} + +impl UniqueRc { + /// Creates a new weak reference to the `UniqueRc`. + /// + /// Attempting to upgrade this weak reference will fail before the `UniqueRc` has been converted + /// to a [`Rc`] using [`UniqueRc::into_rc`]. + #[unstable(feature = "unique_rc_arc", issue = "112566")] + pub fn downgrade(this: &Self) -> Weak { + // SAFETY: This pointer was allocated at creation time and we guarantee that we only have + // one strong reference before converting to a regular Rc. + unsafe { + this.ptr.as_ref().inc_weak(); } + Weak { ptr: this.ptr, alloc: this.alloc.clone() } } } #[unstable(feature = "unique_rc_arc", issue = "112566")] -impl Deref for UniqueRc { +impl Deref for UniqueRc { type Target = T; fn deref(&self) -> &T { @@ -3626,7 +3661,7 @@ impl Deref for UniqueRc { } #[unstable(feature = "unique_rc_arc", issue = "112566")] -impl DerefMut for UniqueRc { +impl DerefMut for UniqueRc { fn deref_mut(&mut self) -> &mut T { // SAFETY: This pointer was allocated at creation time so we know it is valid. We know we // have unique ownership and therefore it's safe to make a mutable reference because @@ -3636,7 +3671,7 @@ impl DerefMut for UniqueRc { } #[unstable(feature = "unique_rc_arc", issue = "112566")] -unsafe impl<#[may_dangle] T> Drop for UniqueRc { +unsafe impl<#[may_dangle] T: ?Sized, A: Allocator> Drop for UniqueRc { fn drop(&mut self) { unsafe { // destroy the contained object @@ -3646,7 +3681,7 @@ unsafe impl<#[may_dangle] T> Drop for UniqueRc { self.ptr.as_ref().dec_weak(); if self.ptr.as_ref().weak() == 0 { - Global.deallocate(self.ptr.cast(), Layout::for_value_raw(self.ptr.as_ptr())); + self.alloc.deallocate(self.ptr.cast(), Layout::for_value_raw(self.ptr.as_ptr())); } } } diff --git a/library/alloc/src/rc/tests.rs b/library/alloc/src/rc/tests.rs index c8a40603d9db2..0f09be7721fa9 100644 --- a/library/alloc/src/rc/tests.rs +++ b/library/alloc/src/rc/tests.rs @@ -606,6 +606,23 @@ fn test_unique_rc_drops_contents() { assert!(dropped); } +/// Exercise the non-default allocator usage. +#[test] +fn test_unique_rc_with_alloc_drops_contents() { + let mut dropped = false; + struct DropMe<'a>(&'a mut bool); + impl Drop for DropMe<'_> { + fn drop(&mut self) { + *self.0 = true; + } + } + { + let rc = UniqueRc::new_in(DropMe(&mut dropped), std::alloc::System); + drop(rc); + } + assert!(dropped); +} + #[test] fn test_unique_rc_weak_clone_holding_ref() { let mut v = UniqueRc::new(0u8); @@ -614,3 +631,12 @@ fn test_unique_rc_weak_clone_holding_ref() { let _ = w.clone(); // touch weak count *r = 123; } + +#[test] +fn test_unique_rc_unsizing_coercion() { + let mut rc: UniqueRc<[u8]> = UniqueRc::new([0u8; 3]); + assert_eq!(rc.len(), 3); + rc[0] = 123; + let rc: Rc<[u8]> = UniqueRc::into_rc(rc); + assert_eq!(*rc, [123, 0, 0]); +} diff --git a/library/alloc/src/sync.rs b/library/alloc/src/sync.rs index 60e3918157efb..f9d884e0ea551 100644 --- a/library/alloc/src/sync.rs +++ b/library/alloc/src/sync.rs @@ -940,15 +940,18 @@ impl Arc { /// This will succeed even if there are outstanding weak references. /// /// It is strongly recommended to use [`Arc::into_inner`] instead if you don't - /// want to keep the `Arc` in the [`Err`] case. - /// Immediately dropping the [`Err`] payload, like in the expression - /// `Arc::try_unwrap(this).ok()`, can still cause the strong count to - /// drop to zero and the inner value of the `Arc` to be dropped: - /// For instance if two threads each execute this expression in parallel, then - /// there is a race condition. The threads could first both check whether they - /// have the last clone of their `Arc` via `Arc::try_unwrap`, and then - /// both drop their `Arc` in the call to [`ok`][`Result::ok`], - /// taking the strong count from two down to zero. + /// keep the `Arc` in the [`Err`] case. + /// Immediately dropping the [`Err`]-value, as the expression + /// `Arc::try_unwrap(this).ok()` does, can cause the strong count to + /// drop to zero and the inner value of the `Arc` to be dropped. + /// For instance, if two threads execute such an expression in parallel, + /// there is a race condition without the possibility of unsafety: + /// The threads could first both check whether they own the last instance + /// in `Arc::try_unwrap`, determine that they both do not, and then both + /// discard and drop their instance in the call to [`ok`][`Result::ok`]. + /// In this scenario, the value inside the `Arc` is safely destroyed + /// by exactly one of the threads, but neither thread will ever be able + /// to use the value. /// /// # Examples /// diff --git a/library/core/src/intrinsics.rs b/library/core/src/intrinsics.rs index cd3534ecb1239..6b5054a9f0612 100644 --- a/library/core/src/intrinsics.rs +++ b/library/core/src/intrinsics.rs @@ -3043,8 +3043,7 @@ pub const unsafe fn copy(src: *const T, dst: *mut T, count: usize) { unsafe { ub_checks::assert_unsafe_precondition!( check_language_ub, - "ptr::copy_nonoverlapping requires that both pointer arguments are aligned and non-null \ - and the specified memory ranges do not overlap", + "ptr::copy requires that both pointer arguments are aligned and non-null", ( src: *const () = src as *const (), dst: *mut () = dst as *mut (), diff --git a/library/core/src/iter/traits/iterator.rs b/library/core/src/iter/traits/iterator.rs index cee99e28b5a97..733d414d44465 100644 --- a/library/core/src/iter/traits/iterator.rs +++ b/library/core/src/iter/traits/iterator.rs @@ -2080,8 +2080,7 @@ pub trait Iterator { fn try_collect(&mut self) -> ChangeOutputType where Self: Sized, - ::Item: Try, - <::Item as Try>::Residual: Residual, + Self::Item: Try>, B: FromIterator<::Output>, { try_process(ByRefSized(self), |i| i.collect()) @@ -2689,12 +2688,13 @@ pub trait Iterator { #[inline] #[unstable(feature = "iterator_try_reduce", reason = "new API", issue = "87053")] #[rustc_do_not_const_check] - fn try_reduce(&mut self, f: F) -> ChangeOutputType> + fn try_reduce( + &mut self, + f: impl FnMut(Self::Item, Self::Item) -> R, + ) -> ChangeOutputType> where Self: Sized, - F: FnMut(Self::Item, Self::Item) -> R, - R: Try, - R::Residual: Residual>, + R: Try>>, { let first = match self.next() { Some(i) => i, @@ -2956,12 +2956,13 @@ pub trait Iterator { #[inline] #[unstable(feature = "try_find", reason = "new API", issue = "63178")] #[rustc_do_not_const_check] - fn try_find(&mut self, f: F) -> ChangeOutputType> + fn try_find( + &mut self, + f: impl FnMut(&Self::Item) -> R, + ) -> ChangeOutputType> where Self: Sized, - F: FnMut(&Self::Item) -> R, - R: Try, - R::Residual: Residual>, + R: Try>>, { #[inline] fn check( diff --git a/library/core/src/num/nonzero.rs b/library/core/src/num/nonzero.rs index 863f0d61df374..5956a08593ad4 100644 --- a/library/core/src/num/nonzero.rs +++ b/library/core/src/num/nonzero.rs @@ -1059,7 +1059,7 @@ macro_rules! nonzero_integer_signedness_dependent_methods { unsafe { Self::new_unchecked(self.get().unchecked_add(other)) } } - /// Returns the smallest power of two greater than or equal to n. + /// Returns the smallest power of two greater than or equal to `self`. /// Checks for overflow and returns [`None`] /// if the next power of two is greater than the type’s maximum value. /// As a consequence, the result cannot wrap to zero. diff --git a/library/core/src/num/uint_macros.rs b/library/core/src/num/uint_macros.rs index 1491c27372bfb..cdbd695008e86 100644 --- a/library/core/src/num/uint_macros.rs +++ b/library/core/src/num/uint_macros.rs @@ -2830,7 +2830,7 @@ macro_rules! uint_impl { /// /// When return value overflows (i.e., `self > (1 << (N-1))` for type /// `uN`), it panics in debug mode and the return value is wrapped to 0 in - /// release mode (the only situation in which method can return 0). + /// release mode (the only situation in which this method can return 0). /// /// # Examples /// @@ -2851,7 +2851,7 @@ macro_rules! uint_impl { self.one_less_than_next_power_of_two() + 1 } - /// Returns the smallest power of two greater than or equal to `n`. If + /// Returns the smallest power of two greater than or equal to `self`. If /// the next power of two is greater than the type's maximum value, /// `None` is returned, otherwise the power of two is wrapped in `Some`. /// diff --git a/library/core/src/ops/coroutine.rs b/library/core/src/ops/coroutine.rs index 6a6c5db1ab115..753f14c6b85ec 100644 --- a/library/core/src/ops/coroutine.rs +++ b/library/core/src/ops/coroutine.rs @@ -76,6 +76,7 @@ pub trait Coroutine { /// values which are allowed to be returned each time a coroutine yields. /// For example an iterator-as-a-coroutine would likely have this type as /// `T`, the type being iterated over. + #[cfg_attr(not(bootstrap), lang = "coroutine_yield")] type Yield; /// The type of value this coroutine returns. @@ -84,6 +85,7 @@ pub trait Coroutine { /// `return` statement or implicitly as the last expression of a coroutine /// literal. For example futures would use this as `Result` as it /// represents a completed future. + #[cfg_attr(not(bootstrap), lang = "coroutine_return")] type Return; /// Resumes the execution of this coroutine. diff --git a/library/core/src/option.rs b/library/core/src/option.rs index 8ac2a8bb17f41..4d6ba2fa3b38c 100644 --- a/library/core/src/option.rs +++ b/library/core/src/option.rs @@ -654,6 +654,32 @@ impl Option { !self.is_some() } + /// Returns `true` if the option is a [`None`] or the value inside of it matches a predicate. + /// + /// # Examples + /// + /// ``` + /// #![feature(is_none_or)] + /// + /// let x: Option = Some(2); + /// assert_eq!(x.is_none_or(|x| x > 1), true); + /// + /// let x: Option = Some(0); + /// assert_eq!(x.is_none_or(|x| x > 1), false); + /// + /// let x: Option = None; + /// assert_eq!(x.is_none_or(|x| x > 1), true); + /// ``` + #[must_use] + #[inline] + #[unstable(feature = "is_none_or", issue = "126383")] + pub fn is_none_or(self, f: impl FnOnce(T) -> bool) -> bool { + match self { + None => true, + Some(x) => f(x), + } + } + ///////////////////////////////////////////////////////////////////////// // Adapter for working with references ///////////////////////////////////////////////////////////////////////// diff --git a/library/core/src/slice/index.rs b/library/core/src/slice/index.rs index 98513340a4741..143dbd8a496d0 100644 --- a/library/core/src/slice/index.rs +++ b/library/core/src/slice/index.rs @@ -2,7 +2,6 @@ use crate::intrinsics::const_eval_select; use crate::ops; -use crate::ptr; use crate::ub_checks::assert_unsafe_precondition; #[stable(feature = "rust1", since = "1.0.0")] @@ -106,6 +105,47 @@ const fn slice_end_index_overflow_fail() -> ! { panic!("attempted to index slice up to maximum usize"); } +// The UbChecks are great for catching bugs in the unsafe methods, but including +// them in safe indexing is unnecessary and hurts inlining and debug runtime perf. +// Both the safe and unsafe public methods share these helpers, +// which use intrinsics directly to get *no* extra checks. + +#[inline(always)] +const unsafe fn get_noubcheck(ptr: *const [T], index: usize) -> *const T { + let ptr = ptr as *const T; + // SAFETY: The caller already checked these preconditions + unsafe { crate::intrinsics::offset(ptr, index) } +} + +#[inline(always)] +const unsafe fn get_mut_noubcheck(ptr: *mut [T], index: usize) -> *mut T { + let ptr = ptr as *mut T; + // SAFETY: The caller already checked these preconditions + unsafe { crate::intrinsics::offset(ptr, index) } +} + +#[inline(always)] +const unsafe fn get_offset_len_noubcheck( + ptr: *const [T], + offset: usize, + len: usize, +) -> *const [T] { + // SAFETY: The caller already checked these preconditions + let ptr = unsafe { get_noubcheck(ptr, offset) }; + crate::intrinsics::aggregate_raw_ptr(ptr, len) +} + +#[inline(always)] +const unsafe fn get_offset_len_mut_noubcheck( + ptr: *mut [T], + offset: usize, + len: usize, +) -> *mut [T] { + // SAFETY: The caller already checked these preconditions + let ptr = unsafe { get_mut_noubcheck(ptr, offset) }; + crate::intrinsics::aggregate_raw_ptr(ptr, len) +} + mod private_slice_index { use super::ops; #[stable(feature = "slice_get_slice", since = "1.28.0")] @@ -203,13 +243,17 @@ unsafe impl SliceIndex<[T]> for usize { #[inline] fn get(self, slice: &[T]) -> Option<&T> { // SAFETY: `self` is checked to be in bounds. - if self < slice.len() { unsafe { Some(&*self.get_unchecked(slice)) } } else { None } + if self < slice.len() { unsafe { Some(&*get_noubcheck(slice, self)) } } else { None } } #[inline] fn get_mut(self, slice: &mut [T]) -> Option<&mut T> { - // SAFETY: `self` is checked to be in bounds. - if self < slice.len() { unsafe { Some(&mut *self.get_unchecked_mut(slice)) } } else { None } + if self < slice.len() { + // SAFETY: `self` is checked to be in bounds. + unsafe { Some(&mut *get_mut_noubcheck(slice, self)) } + } else { + None + } } #[inline] @@ -227,7 +271,7 @@ unsafe impl SliceIndex<[T]> for usize { // Use intrinsics::assume instead of hint::assert_unchecked so that we don't check the // precondition of this function twice. crate::intrinsics::assume(self < slice.len()); - slice.as_ptr().add(self) + get_noubcheck(slice, self) } } @@ -239,7 +283,7 @@ unsafe impl SliceIndex<[T]> for usize { (this: usize = self, len: usize = slice.len()) => this < len ); // SAFETY: see comments for `get_unchecked` above. - unsafe { slice.as_mut_ptr().add(self) } + unsafe { get_mut_noubcheck(slice, self) } } #[inline] @@ -265,7 +309,7 @@ unsafe impl SliceIndex<[T]> for ops::IndexRange { fn get(self, slice: &[T]) -> Option<&[T]> { if self.end() <= slice.len() { // SAFETY: `self` is checked to be valid and in bounds above. - unsafe { Some(&*self.get_unchecked(slice)) } + unsafe { Some(&*get_offset_len_noubcheck(slice, self.start(), self.len())) } } else { None } @@ -275,7 +319,7 @@ unsafe impl SliceIndex<[T]> for ops::IndexRange { fn get_mut(self, slice: &mut [T]) -> Option<&mut [T]> { if self.end() <= slice.len() { // SAFETY: `self` is checked to be valid and in bounds above. - unsafe { Some(&mut *self.get_unchecked_mut(slice)) } + unsafe { Some(&mut *get_offset_len_mut_noubcheck(slice, self.start(), self.len())) } } else { None } @@ -292,7 +336,7 @@ unsafe impl SliceIndex<[T]> for ops::IndexRange { // cannot be longer than `isize::MAX`. They also guarantee that // `self` is in bounds of `slice` so `self` cannot overflow an `isize`, // so the call to `add` is safe. - unsafe { ptr::slice_from_raw_parts(slice.as_ptr().add(self.start()), self.len()) } + unsafe { get_offset_len_noubcheck(slice, self.start(), self.len()) } } #[inline] @@ -304,14 +348,14 @@ unsafe impl SliceIndex<[T]> for ops::IndexRange { ); // SAFETY: see comments for `get_unchecked` above. - unsafe { ptr::slice_from_raw_parts_mut(slice.as_mut_ptr().add(self.start()), self.len()) } + unsafe { get_offset_len_mut_noubcheck(slice, self.start(), self.len()) } } #[inline] fn index(self, slice: &[T]) -> &[T] { if self.end() <= slice.len() { // SAFETY: `self` is checked to be valid and in bounds above. - unsafe { &*self.get_unchecked(slice) } + unsafe { &*get_offset_len_noubcheck(slice, self.start(), self.len()) } } else { slice_end_index_len_fail(self.end(), slice.len()) } @@ -321,7 +365,7 @@ unsafe impl SliceIndex<[T]> for ops::IndexRange { fn index_mut(self, slice: &mut [T]) -> &mut [T] { if self.end() <= slice.len() { // SAFETY: `self` is checked to be valid and in bounds above. - unsafe { &mut *self.get_unchecked_mut(slice) } + unsafe { &mut *get_offset_len_mut_noubcheck(slice, self.start(), self.len()) } } else { slice_end_index_len_fail(self.end(), slice.len()) } @@ -338,21 +382,26 @@ unsafe impl SliceIndex<[T]> for ops::Range { #[inline] fn get(self, slice: &[T]) -> Option<&[T]> { - if self.start > self.end || self.end > slice.len() { - None - } else { + // Using checked_sub is a safe way to get `SubUnchecked` in MIR + if let Some(new_len) = usize::checked_sub(self.end, self.start) + && self.end <= slice.len() + { // SAFETY: `self` is checked to be valid and in bounds above. - unsafe { Some(&*self.get_unchecked(slice)) } + unsafe { Some(&*get_offset_len_noubcheck(slice, self.start, new_len)) } + } else { + None } } #[inline] fn get_mut(self, slice: &mut [T]) -> Option<&mut [T]> { - if self.start > self.end || self.end > slice.len() { - None - } else { + if let Some(new_len) = usize::checked_sub(self.end, self.start) + && self.end <= slice.len() + { // SAFETY: `self` is checked to be valid and in bounds above. - unsafe { Some(&mut *self.get_unchecked_mut(slice)) } + unsafe { Some(&mut *get_offset_len_mut_noubcheck(slice, self.start, new_len)) } + } else { + None } } @@ -373,8 +422,10 @@ unsafe impl SliceIndex<[T]> for ops::Range { // `self` is in bounds of `slice` so `self` cannot overflow an `isize`, // so the call to `add` is safe and the length calculation cannot overflow. unsafe { - let new_len = self.end.unchecked_sub(self.start); - ptr::slice_from_raw_parts(slice.as_ptr().add(self.start), new_len) + // Using the intrinsic avoids a superfluous UB check, + // since the one on this method already checked `end >= start`. + let new_len = crate::intrinsics::unchecked_sub(self.end, self.start); + get_offset_len_noubcheck(slice, self.start, new_len) } } @@ -391,31 +442,34 @@ unsafe impl SliceIndex<[T]> for ops::Range { ); // SAFETY: see comments for `get_unchecked` above. unsafe { - let new_len = self.end.unchecked_sub(self.start); - ptr::slice_from_raw_parts_mut(slice.as_mut_ptr().add(self.start), new_len) + let new_len = crate::intrinsics::unchecked_sub(self.end, self.start); + get_offset_len_mut_noubcheck(slice, self.start, new_len) } } #[inline(always)] fn index(self, slice: &[T]) -> &[T] { - if self.start > self.end { - slice_index_order_fail(self.start, self.end); - } else if self.end > slice.len() { + // Using checked_sub is a safe way to get `SubUnchecked` in MIR + let Some(new_len) = usize::checked_sub(self.end, self.start) else { + slice_index_order_fail(self.start, self.end) + }; + if self.end > slice.len() { slice_end_index_len_fail(self.end, slice.len()); } // SAFETY: `self` is checked to be valid and in bounds above. - unsafe { &*self.get_unchecked(slice) } + unsafe { &*get_offset_len_noubcheck(slice, self.start, new_len) } } #[inline] fn index_mut(self, slice: &mut [T]) -> &mut [T] { - if self.start > self.end { - slice_index_order_fail(self.start, self.end); - } else if self.end > slice.len() { + let Some(new_len) = usize::checked_sub(self.end, self.start) else { + slice_index_order_fail(self.start, self.end) + }; + if self.end > slice.len() { slice_end_index_len_fail(self.end, slice.len()); } // SAFETY: `self` is checked to be valid and in bounds above. - unsafe { &mut *self.get_unchecked_mut(slice) } + unsafe { &mut *get_offset_len_mut_noubcheck(slice, self.start, new_len) } } } diff --git a/library/core/src/slice/rotate.rs b/library/core/src/slice/rotate.rs index fa8c238f8e7a2..1d7b86339799b 100644 --- a/library/core/src/slice/rotate.rs +++ b/library/core/src/slice/rotate.rs @@ -71,7 +71,9 @@ pub unsafe fn ptr_rotate(mut left: usize, mut mid: *mut T, mut right: usize) if (right == 0) || (left == 0) { return; } - if (left + right < 24) || (mem::size_of::() > mem::size_of::<[usize; 4]>()) { + if !cfg!(feature = "optimize_for_size") + && ((left + right < 24) || (mem::size_of::() > mem::size_of::<[usize; 4]>())) + { // Algorithm 1 // Microbenchmarks indicate that the average performance for random shifts is better all // the way until about `left + right == 32`, but the worst case performance breaks even @@ -158,7 +160,9 @@ pub unsafe fn ptr_rotate(mut left: usize, mut mid: *mut T, mut right: usize) } return; // `T` is not a zero-sized type, so it's okay to divide by its size. - } else if cmp::min(left, right) <= mem::size_of::() / mem::size_of::() { + } else if !cfg!(feature = "optimize_for_size") + && cmp::min(left, right) <= mem::size_of::() / mem::size_of::() + { // Algorithm 2 // The `[T; 0]` here is to ensure this is appropriately aligned for T let mut rawarray = MaybeUninit::<(BufType, [T; 0])>::uninit(); diff --git a/library/proc_macro/src/escape.rs b/library/proc_macro/src/escape.rs new file mode 100644 index 0000000000000..87a4d1d50fd48 --- /dev/null +++ b/library/proc_macro/src/escape.rs @@ -0,0 +1,57 @@ +#[derive(Copy, Clone)] +pub(crate) struct EscapeOptions { + /// Produce \'. + pub escape_single_quote: bool, + /// Produce \". + pub escape_double_quote: bool, + /// Produce \x escapes for non-ASCII, and use \x rather than \u for ASCII + /// control characters. + pub escape_nonascii: bool, +} + +pub(crate) fn escape_bytes(bytes: &[u8], opt: EscapeOptions) -> String { + let mut repr = String::new(); + + if opt.escape_nonascii { + for &byte in bytes { + escape_single_byte(byte, opt, &mut repr); + } + } else { + let mut chunks = bytes.utf8_chunks(); + while let Some(chunk) = chunks.next() { + for ch in chunk.valid().chars() { + escape_single_char(ch, opt, &mut repr); + } + for &byte in chunk.invalid() { + escape_single_byte(byte, opt, &mut repr); + } + } + } + + repr +} + +fn escape_single_byte(byte: u8, opt: EscapeOptions, repr: &mut String) { + if byte == b'\0' { + repr.push_str("\\0"); + } else if (byte == b'\'' && !opt.escape_single_quote) + || (byte == b'"' && !opt.escape_double_quote) + { + repr.push(byte as char); + } else { + // Escapes \t, \r, \n, \\, \', \", and uses \x## for non-ASCII and + // for ASCII control characters. + repr.extend(byte.escape_ascii().map(char::from)); + } +} + +fn escape_single_char(ch: char, opt: EscapeOptions, repr: &mut String) { + if (ch == '\'' && !opt.escape_single_quote) || (ch == '"' && !opt.escape_double_quote) { + repr.push(ch); + } else { + // Escapes \0, \t, \r, \n, \\, \', \", and uses \u{...} for + // non-printable characters and for Grapheme_Extend characters, which + // includes things like U+0300 "Combining Grave Accent". + repr.extend(ch.escape_debug()); + } +} diff --git a/library/proc_macro/src/lib.rs b/library/proc_macro/src/lib.rs index 3d7d36b27e53b..581d7e3efe373 100644 --- a/library/proc_macro/src/lib.rs +++ b/library/proc_macro/src/lib.rs @@ -43,10 +43,12 @@ pub mod bridge; mod diagnostic; +mod escape; #[unstable(feature = "proc_macro_diagnostic", issue = "54140")] pub use diagnostic::{Diagnostic, Level, MultiSpan}; +use crate::escape::{escape_bytes, EscapeOptions}; use std::ffi::CStr; use std::ops::{Range, RangeBounds}; use std::path::PathBuf; @@ -1356,40 +1358,61 @@ impl Literal { /// String literal. #[stable(feature = "proc_macro_lib2", since = "1.29.0")] pub fn string(string: &str) -> Literal { - let quoted = format!("{:?}", string); - assert!(quoted.starts_with('"') && quoted.ends_with('"')); - let symbol = "ed[1..quoted.len() - 1]; - Literal::new(bridge::LitKind::Str, symbol, None) + let escape = EscapeOptions { + escape_single_quote: false, + escape_double_quote: true, + escape_nonascii: false, + }; + let repr = escape_bytes(string.as_bytes(), escape); + Literal::new(bridge::LitKind::Str, &repr, None) } /// Character literal. #[stable(feature = "proc_macro_lib2", since = "1.29.0")] pub fn character(ch: char) -> Literal { - let quoted = format!("{:?}", ch); - assert!(quoted.starts_with('\'') && quoted.ends_with('\'')); - let symbol = "ed[1..quoted.len() - 1]; - Literal::new(bridge::LitKind::Char, symbol, None) + let escape = EscapeOptions { + escape_single_quote: true, + escape_double_quote: false, + escape_nonascii: false, + }; + let repr = escape_bytes(ch.encode_utf8(&mut [0u8; 4]).as_bytes(), escape); + Literal::new(bridge::LitKind::Char, &repr, None) } /// Byte character literal. #[stable(feature = "proc_macro_byte_character", since = "1.79.0")] pub fn byte_character(byte: u8) -> Literal { - let string = [byte].escape_ascii().to_string(); - Literal::new(bridge::LitKind::Byte, &string, None) + let escape = EscapeOptions { + escape_single_quote: true, + escape_double_quote: false, + escape_nonascii: true, + }; + let repr = escape_bytes(&[byte], escape); + Literal::new(bridge::LitKind::Byte, &repr, None) } /// Byte string literal. #[stable(feature = "proc_macro_lib2", since = "1.29.0")] pub fn byte_string(bytes: &[u8]) -> Literal { - let string = bytes.escape_ascii().to_string(); - Literal::new(bridge::LitKind::ByteStr, &string, None) + let escape = EscapeOptions { + escape_single_quote: false, + escape_double_quote: true, + escape_nonascii: true, + }; + let repr = escape_bytes(bytes, escape); + Literal::new(bridge::LitKind::ByteStr, &repr, None) } /// C string literal. #[stable(feature = "proc_macro_c_str_literals", since = "1.79.0")] pub fn c_string(string: &CStr) -> Literal { - let string = string.to_bytes().escape_ascii().to_string(); - Literal::new(bridge::LitKind::CStr, &string, None) + let escape = EscapeOptions { + escape_single_quote: false, + escape_double_quote: true, + escape_nonascii: false, + }; + let repr = escape_bytes(string.to_bytes(), escape); + Literal::new(bridge::LitKind::CStr, &repr, None) } /// Returns the span encompassing this literal. diff --git a/library/std/Cargo.toml b/library/std/Cargo.toml index 68bba5c2be112..32479cd2836fa 100644 --- a/library/std/Cargo.toml +++ b/library/std/Cargo.toml @@ -50,7 +50,7 @@ dlmalloc = { version = "0.2.4", features = ['rustc-dep-of-std'] } fortanix-sgx-abi = { version = "0.5.0", features = ['rustc-dep-of-std'], public = true } [target.'cfg(target_os = "hermit")'.dependencies] -hermit-abi = { version = "0.3.9", features = ['rustc-dep-of-std'], public = true } +hermit-abi = { version = "0.4.0", features = ['rustc-dep-of-std'], public = true } [target.'cfg(target_os = "wasi")'.dependencies] wasi = { version = "0.11.0", features = ['rustc-dep-of-std'], default-features = false } diff --git a/library/std/src/alloc.rs b/library/std/src/alloc.rs index b98fbbf762fa2..dc4924cdf581d 100644 --- a/library/std/src/alloc.rs +++ b/library/std/src/alloc.rs @@ -73,7 +73,9 @@ pub use alloc_crate::alloc::*; /// work, such as to serve alignment requests greater than the alignment /// provided directly by the backing system allocator. /// -/// This type implements the `GlobalAlloc` trait and Rust programs by default +/// This type implements the [`GlobalAlloc`] trait. Currently the default +/// global allocator is unspecified. Libraries, however, like `cdylib`s and +/// `staticlib`s are guaranteed to use the [`System`] by default and as such /// work as if they had this definition: /// /// ```rust diff --git a/library/std/src/backtrace.rs b/library/std/src/backtrace.rs index e3e0cde8afead..4d376753cb6d2 100644 --- a/library/std/src/backtrace.rs +++ b/library/std/src/backtrace.rs @@ -95,7 +95,7 @@ use crate::fmt; use crate::panic::UnwindSafe; use crate::sync::atomic::{AtomicU8, Ordering::Relaxed}; use crate::sync::LazyLock; -use crate::sys_common::backtrace::{lock, output_filename, set_image_base}; +use crate::sys::backtrace::{lock, output_filename, set_image_base}; /// A captured OS thread stack backtrace. /// diff --git a/library/std/src/error.rs b/library/std/src/error.rs index b240e4e2c45be..87aad8f764bd0 100644 --- a/library/std/src/error.rs +++ b/library/std/src/error.rs @@ -429,7 +429,7 @@ impl Report { /// 1: rust_out::main::_doctest_main_src_error_rs_1158_0 /// 2: rust_out::main /// 3: core::ops::function::FnOnce::call_once - /// 4: std::sys_common::backtrace::__rust_begin_short_backtrace + /// 4: std::sys::backtrace::__rust_begin_short_backtrace /// 5: std::rt::lang_start::{{closure}} /// 6: std::panicking::try /// 7: std::rt::lang_start_internal diff --git a/library/std/src/fs.rs b/library/std/src/fs.rs index 0dcf554770c5c..cf9a3446522cc 100644 --- a/library/std/src/fs.rs +++ b/library/std/src/fs.rs @@ -2302,7 +2302,7 @@ pub fn read_link>(path: P) -> io::Result { /// /// This function currently corresponds to the `realpath` function on Unix /// and the `CreateFile` and `GetFinalPathNameByHandle` functions on Windows. -/// Note that, this [may change in the future][changes]. +/// Note that this [may change in the future][changes]. /// /// On Windows, this converts the path to use [extended length path][path] /// syntax, which allows your program to use longer path names, but means you @@ -2386,6 +2386,9 @@ pub fn create_dir>(path: P) -> io::Result<()> { /// If this function returns an error, some of the parent components might have /// been created already. /// +/// If the empty path is passed to this function, it always succeeds without +/// creating any directories. +/// /// # Platform-specific behavior /// /// This function currently corresponds to multiple calls to the `mkdir` diff --git a/library/std/src/panicking.rs b/library/std/src/panicking.rs index 8fd8134c11147..2bb5ea28b181c 100644 --- a/library/std/src/panicking.rs +++ b/library/std/src/panicking.rs @@ -19,8 +19,8 @@ use crate::mem::{self, ManuallyDrop}; use crate::process; use crate::sync::atomic::{AtomicBool, Ordering}; use crate::sync::{PoisonError, RwLock}; +use crate::sys::backtrace; use crate::sys::stdio::panic_output; -use crate::sys_common::backtrace; use crate::thread; #[cfg(not(test))] @@ -655,7 +655,7 @@ pub fn begin_panic_handler(info: &core::panic::PanicInfo<'_>) -> ! { let loc = info.location().unwrap(); // The current implementation always returns Some let msg = info.message(); - crate::sys_common::backtrace::__rust_end_short_backtrace(move || { + crate::sys::backtrace::__rust_end_short_backtrace(move || { if let Some(s) = msg.as_str() { rust_panic_with_hook( &mut StaticStrPayload(s), @@ -727,7 +727,7 @@ pub const fn begin_panic(msg: M) -> ! { } let loc = Location::caller(); - crate::sys_common::backtrace::__rust_end_short_backtrace(move || { + crate::sys::backtrace::__rust_end_short_backtrace(move || { rust_panic_with_hook( &mut Payload { inner: Some(msg) }, loc, diff --git a/library/std/src/path.rs b/library/std/src/path.rs index adbcdcd2e67e3..7b8caaa268473 100644 --- a/library/std/src/path.rs +++ b/library/std/src/path.rs @@ -3345,14 +3345,33 @@ impl Error for StripPrefixError { /// Makes the path absolute without accessing the filesystem. /// /// If the path is relative, the current directory is used as the base directory. -/// All intermediate components will be resolved according to platforms-specific -/// rules but unlike [`canonicalize`][crate::fs::canonicalize] this does not +/// All intermediate components will be resolved according to platform-specific +/// rules, but unlike [`canonicalize`][crate::fs::canonicalize], this does not /// resolve symlinks and may succeed even if the path does not exist. /// /// If the `path` is empty or getting the -/// [current directory][crate::env::current_dir] fails then an error will be +/// [current directory][crate::env::current_dir] fails, then an error will be /// returned. /// +/// # Platform-specific behavior +/// +/// On POSIX platforms, the path is resolved using [POSIX semantics][posix-semantics], +/// except that it stops short of resolving symlinks. This means it will keep `..` +/// components and trailing slashes. +/// +/// On Windows, for verbatim paths, this will simply return the path as given. For other +/// paths, this is currently equivalent to calling +/// [`GetFullPathNameW`][windows-path]. +/// +/// Note that these [may change in the future][changes]. +/// +/// # Errors +/// +/// This function may return an error in the following situations: +/// +/// * If `path` is syntactically invalid; in particular, if it is empty. +/// * If getting the [current directory][crate::env::current_dir] fails. +/// /// # Examples /// /// ## POSIX paths @@ -3360,50 +3379,42 @@ impl Error for StripPrefixError { /// ``` /// # #[cfg(unix)] /// fn main() -> std::io::Result<()> { -/// use std::path::{self, Path}; +/// use std::path::{self, Path}; /// -/// // Relative to absolute -/// let absolute = path::absolute("foo/./bar")?; -/// assert!(absolute.ends_with("foo/bar")); +/// // Relative to absolute +/// let absolute = path::absolute("foo/./bar")?; +/// assert!(absolute.ends_with("foo/bar")); /// -/// // Absolute to absolute -/// let absolute = path::absolute("/foo//test/.././bar.rs")?; -/// assert_eq!(absolute, Path::new("/foo/test/../bar.rs")); -/// Ok(()) +/// // Absolute to absolute +/// let absolute = path::absolute("/foo//test/.././bar.rs")?; +/// assert_eq!(absolute, Path::new("/foo/test/../bar.rs")); +/// Ok(()) /// } /// # #[cfg(not(unix))] /// # fn main() {} /// ``` /// -/// The path is resolved using [POSIX semantics][posix-semantics] except that -/// it stops short of resolving symlinks. This means it will keep `..` -/// components and trailing slashes. -/// /// ## Windows paths /// /// ``` /// # #[cfg(windows)] /// fn main() -> std::io::Result<()> { -/// use std::path::{self, Path}; +/// use std::path::{self, Path}; /// -/// // Relative to absolute -/// let absolute = path::absolute("foo/./bar")?; -/// assert!(absolute.ends_with(r"foo\bar")); +/// // Relative to absolute +/// let absolute = path::absolute("foo/./bar")?; +/// assert!(absolute.ends_with(r"foo\bar")); /// -/// // Absolute to absolute -/// let absolute = path::absolute(r"C:\foo//test\..\./bar.rs")?; +/// // Absolute to absolute +/// let absolute = path::absolute(r"C:\foo//test\..\./bar.rs")?; /// -/// assert_eq!(absolute, Path::new(r"C:\foo\bar.rs")); -/// Ok(()) +/// assert_eq!(absolute, Path::new(r"C:\foo\bar.rs")); +/// Ok(()) /// } /// # #[cfg(not(windows))] /// # fn main() {} /// ``` /// -/// For verbatim paths this will simply return the path as given. For other -/// paths this is currently equivalent to calling -/// [`GetFullPathNameW`][windows-path]. -/// /// Note that this [may change in the future][changes]. /// /// [changes]: io#platform-specific-behavior diff --git a/library/std/src/process.rs b/library/std/src/process.rs index c926c89f7a97f..f351dab78dc1a 100644 --- a/library/std/src/process.rs +++ b/library/std/src/process.rs @@ -629,6 +629,25 @@ impl Command { /// .spawn() /// .expect("sh command failed to start"); /// ``` + /// + /// # Caveats + /// + /// [`Command::new`] is only intended to accept the path of the program. If you pass a program + /// path along with arguments like `Command::new("ls -l").spawn()`, it will try to search for + /// `ls -l` literally. The arguments need to be passed separately, such as via [`arg`] or + /// [`args`]. + /// + /// ```no_run + /// use std::process::Command; + /// + /// Command::new("ls") + /// .arg("-l") // arg passed separately + /// .spawn() + /// .expect("ls command failed to start"); + /// ``` + /// + /// [`arg`]: Self::arg + /// [`args`]: Self::args #[stable(feature = "process", since = "1.0.0")] pub fn new>(program: S) -> Command { Command { inner: imp::Command::new(program.as_ref()) } diff --git a/library/std/src/rt.rs b/library/std/src/rt.rs index 46f691d7b7504..b03fa1c01f266 100644 --- a/library/std/src/rt.rs +++ b/library/std/src/rt.rs @@ -156,7 +156,7 @@ fn lang_start( sigpipe: u8, ) -> isize { let Ok(v) = lang_start_internal( - &move || crate::sys_common::backtrace::__rust_begin_short_backtrace(main).report().to_i32(), + &move || crate::sys::backtrace::__rust_begin_short_backtrace(main).report().to_i32(), argc, argv, sigpipe, diff --git a/library/std/src/sync/mod.rs b/library/std/src/sync/mod.rs index 2a13b1a8ae2de..9a38c42f43a02 100644 --- a/library/std/src/sync/mod.rs +++ b/library/std/src/sync/mod.rs @@ -133,7 +133,8 @@ //! - [`Mutex`]: Mutual Exclusion mechanism, which ensures that at //! most one thread at a time is able to access some data. //! -//! - [`Once`]: Used for a thread-safe, one-time global initialization routine +//! - [`Once`]: Used for a thread-safe, one-time global initialization routine. +//! Mostly useful for implementing other types like `OnceLock`. //! //! - [`OnceLock`]: Used for thread-safe, one-time initialization of a //! variable, with potentially different initializers based on the caller. diff --git a/library/std/src/sync/once.rs b/library/std/src/sync/once.rs index 608229fd674d8..9d969af8c6d84 100644 --- a/library/std/src/sync/once.rs +++ b/library/std/src/sync/once.rs @@ -10,9 +10,15 @@ use crate::fmt; use crate::panic::{RefUnwindSafe, UnwindSafe}; use crate::sys::sync as sys; -/// A synchronization primitive which can be used to run a one-time global -/// initialization. Useful for one-time initialization for FFI or related -/// functionality. This type can only be constructed with [`Once::new()`]. +/// A low-level synchronization primitive for one-time global execution. +/// +/// Previously this was the only "execute once" synchronization in `std`. +/// Other libraries implemented novel synchronizing types with `Once`, like +/// [`OnceLock`] or [`LazyLock`], before those were added to `std`. +/// `OnceLock` in particular supersedes `Once` in functionality and should +/// be preferred for the common case where the `Once` is associated with data. +/// +/// This type can only be constructed with [`Once::new()`]. /// /// # Examples /// @@ -25,6 +31,9 @@ use crate::sys::sync as sys; /// // run initialization here /// }); /// ``` +/// +/// [`OnceLock`]: crate::sync::OnceLock +/// [`LazyLock`]: crate::sync::LazyLock #[stable(feature = "rust1", since = "1.0.0")] pub struct Once { inner: sys::Once, diff --git a/library/std/src/sys_common/backtrace.rs b/library/std/src/sys/backtrace.rs similarity index 98% rename from library/std/src/sys_common/backtrace.rs rename to library/std/src/sys/backtrace.rs index 67711dbd5bc75..0b2338fd7de9b 100644 --- a/library/std/src/sys_common/backtrace.rs +++ b/library/std/src/sys/backtrace.rs @@ -1,7 +1,7 @@ +//! Common code for printing backtraces. + use crate::backtrace_rs::{self, BacktraceFmt, BytesOrWideString, PrintFmt}; use crate::borrow::Cow; -/// Common code for printing the backtrace in the same way across the different -/// supported platforms. use crate::env; use crate::fmt; use crate::io; diff --git a/library/std/src/sys/mod.rs b/library/std/src/sys/mod.rs index 8f70cefc60121..8aa35c40fe052 100644 --- a/library/std/src/sys/mod.rs +++ b/library/std/src/sys/mod.rs @@ -5,6 +5,7 @@ mod pal; mod personality; +pub mod backtrace; pub mod cmath; pub mod os_str; pub mod path; diff --git a/library/std/src/sys/pal/hermit/fd.rs b/library/std/src/sys/pal/hermit/fd.rs index d7dab08cfbd57..3c52b85de23a2 100644 --- a/library/std/src/sys/pal/hermit/fd.rs +++ b/library/std/src/sys/pal/hermit/fd.rs @@ -1,7 +1,8 @@ #![unstable(reason = "not public", issue = "none", feature = "fd")] use super::hermit_abi; -use crate::io::{self, Read}; +use crate::cmp; +use crate::io::{self, IoSlice, IoSliceMut, Read}; use crate::os::hermit::io::{FromRawFd, OwnedFd, RawFd}; use crate::sys::cvt; use crate::sys::unsupported; @@ -9,6 +10,10 @@ use crate::sys_common::{AsInner, FromInner, IntoInner}; use crate::os::hermit::io::*; +const fn max_iov() -> usize { + hermit_abi::IOV_MAX +} + #[derive(Debug)] pub struct FileDesc { fd: OwnedFd, @@ -21,6 +26,22 @@ impl FileDesc { Ok(result as usize) } + pub fn read_vectored(&self, bufs: &mut [IoSliceMut<'_>]) -> io::Result { + let ret = cvt(unsafe { + hermit_abi::readv( + self.as_raw_fd(), + bufs.as_mut_ptr() as *mut hermit_abi::iovec as *const hermit_abi::iovec, + cmp::min(bufs.len(), max_iov()), + ) + })?; + Ok(ret as usize) + } + + #[inline] + pub fn is_read_vectored(&self) -> bool { + true + } + pub fn read_to_end(&self, buf: &mut Vec) -> io::Result { let mut me = self; (&mut me).read_to_end(buf) @@ -32,6 +53,22 @@ impl FileDesc { Ok(result as usize) } + pub fn write_vectored(&self, bufs: &[IoSlice<'_>]) -> io::Result { + let ret = cvt(unsafe { + hermit_abi::writev( + self.as_raw_fd(), + bufs.as_ptr() as *const hermit_abi::iovec, + cmp::min(bufs.len(), max_iov()), + ) + })?; + Ok(ret as usize) + } + + #[inline] + pub fn is_write_vectored(&self) -> bool { + true + } + pub fn duplicate(&self) -> io::Result { self.duplicate_path(&[]) } diff --git a/library/std/src/sys/pal/hermit/fs.rs b/library/std/src/sys/pal/hermit/fs.rs index a4a16e6e86b0c..a98a1006ef47c 100644 --- a/library/std/src/sys/pal/hermit/fs.rs +++ b/library/std/src/sys/pal/hermit/fs.rs @@ -1,7 +1,7 @@ use super::fd::FileDesc; use super::hermit_abi::{ self, dirent64, stat as stat_struct, DT_DIR, DT_LNK, DT_REG, DT_UNKNOWN, O_APPEND, O_CREAT, - O_EXCL, O_RDONLY, O_RDWR, O_TRUNC, O_WRONLY, S_IFDIR, S_IFLNK, S_IFMT, S_IFREG, + O_DIRECTORY, O_EXCL, O_RDONLY, O_RDWR, O_TRUNC, O_WRONLY, S_IFDIR, S_IFLNK, S_IFMT, S_IFREG, }; use crate::ffi::{CStr, OsStr, OsString}; use crate::fmt; @@ -62,7 +62,7 @@ pub struct DirEntry { /// 64-bit inode number ino: u64, /// File type - type_: u32, + type_: u8, /// name of the entry name: OsString, } @@ -90,7 +90,7 @@ pub struct FilePermissions { #[derive(Copy, Clone, Eq, Debug)] pub struct FileType { - mode: u32, + mode: u8, } impl PartialEq for FileType { @@ -112,31 +112,23 @@ pub struct DirBuilder { impl FileAttr { pub fn modified(&self) -> io::Result { - Ok(SystemTime::new( - self.stat_val.st_mtime.try_into().unwrap(), - self.stat_val.st_mtime_nsec.try_into().unwrap(), - )) + Ok(SystemTime::new(self.stat_val.st_mtim.tv_sec, self.stat_val.st_mtim.tv_nsec)) } pub fn accessed(&self) -> io::Result { - Ok(SystemTime::new( - self.stat_val.st_atime.try_into().unwrap(), - self.stat_val.st_atime_nsec.try_into().unwrap(), - )) + Ok(SystemTime::new(self.stat_val.st_atim.tv_sec, self.stat_val.st_atim.tv_nsec)) } pub fn created(&self) -> io::Result { - Ok(SystemTime::new( - self.stat_val.st_ctime.try_into().unwrap(), - self.stat_val.st_ctime_nsec.try_into().unwrap(), - )) + Ok(SystemTime::new(self.stat_val.st_ctim.tv_sec, self.stat_val.st_ctim.tv_nsec)) } pub fn size(&self) -> u64 { self.stat_val.st_size as u64 } + pub fn perm(&self) -> FilePermissions { - FilePermissions { mode: (self.stat_val.st_mode) } + FilePermissions { mode: self.stat_val.st_mode } } pub fn file_type(&self) -> FileType { @@ -220,7 +212,7 @@ impl Iterator for ReadDir { let entry = DirEntry { root: self.inner.root.clone(), ino: dir.d_ino, - type_: dir.d_type as u32, + type_: dir.d_type, name: OsString::from_vec(name_bytes.to_vec()), }; @@ -251,7 +243,7 @@ impl DirEntry { } pub fn file_type(&self) -> io::Result { - Ok(FileType { mode: self.type_ as u32 }) + Ok(FileType { mode: self.type_ }) } #[allow(dead_code)] @@ -385,12 +377,12 @@ impl File { } pub fn read_vectored(&self, bufs: &mut [IoSliceMut<'_>]) -> io::Result { - crate::io::default_read_vectored(|buf| self.read(buf), bufs) + self.0.read_vectored(bufs) } #[inline] pub fn is_read_vectored(&self) -> bool { - false + self.0.is_read_vectored() } pub fn read_buf(&self, cursor: BorrowedCursor<'_>) -> io::Result<()> { @@ -402,12 +394,12 @@ impl File { } pub fn write_vectored(&self, bufs: &[IoSlice<'_>]) -> io::Result { - crate::io::default_write_vectored(|buf| self.write(buf), bufs) + self.0.write_vectored(bufs) } #[inline] pub fn is_write_vectored(&self) -> bool { - false + self.0.is_write_vectored() } #[inline] @@ -439,13 +431,13 @@ impl DirBuilder { pub fn mkdir(&self, path: &Path) -> io::Result<()> { run_path_with_cstr(path, &|path| { - cvt(unsafe { hermit_abi::mkdir(path.as_ptr(), self.mode) }).map(|_| ()) + cvt(unsafe { hermit_abi::mkdir(path.as_ptr(), self.mode.into()) }).map(|_| ()) }) } #[allow(dead_code)] pub fn set_mode(&mut self, mode: u32) { - self.mode = mode as u32; + self.mode = mode; } } @@ -501,8 +493,9 @@ impl FromRawFd for File { } pub fn readdir(path: &Path) -> io::Result { - let fd_raw = - run_path_with_cstr(path, &|path| cvt(unsafe { hermit_abi::opendir(path.as_ptr()) }))?; + let fd_raw = run_path_with_cstr(path, &|path| { + cvt(unsafe { hermit_abi::open(path.as_ptr(), O_RDONLY | O_DIRECTORY, 0) }) + })?; let fd = unsafe { FileDesc::from_raw_fd(fd_raw as i32) }; let root = path.to_path_buf(); diff --git a/library/std/src/sys/pal/hermit/futex.rs b/library/std/src/sys/pal/hermit/futex.rs index 571b288565871..b2d74d1311bcb 100644 --- a/library/std/src/sys/pal/hermit/futex.rs +++ b/library/std/src/sys/pal/hermit/futex.rs @@ -10,7 +10,7 @@ pub fn futex_wait(futex: &AtomicU32, expected: u32, timeout: Option) - let timespec = timeout.and_then(|dur| { Some(hermit_abi::timespec { tv_sec: dur.as_secs().try_into().ok()?, - tv_nsec: dur.subsec_nanos().into(), + tv_nsec: dur.subsec_nanos().try_into().ok()?, }) }); diff --git a/library/std/src/sys/pal/hermit/io.rs b/library/std/src/sys/pal/hermit/io.rs new file mode 100644 index 0000000000000..9de7b53e53c03 --- /dev/null +++ b/library/std/src/sys/pal/hermit/io.rs @@ -0,0 +1,82 @@ +use crate::marker::PhantomData; +use crate::os::hermit::io::{AsFd, AsRawFd}; +use crate::slice; + +use hermit_abi::{c_void, iovec}; + +#[derive(Copy, Clone)] +#[repr(transparent)] +pub struct IoSlice<'a> { + vec: iovec, + _p: PhantomData<&'a [u8]>, +} + +impl<'a> IoSlice<'a> { + #[inline] + pub fn new(buf: &'a [u8]) -> IoSlice<'a> { + IoSlice { + vec: iovec { iov_base: buf.as_ptr() as *mut u8 as *mut c_void, iov_len: buf.len() }, + _p: PhantomData, + } + } + + #[inline] + pub fn advance(&mut self, n: usize) { + if self.vec.iov_len < n { + panic!("advancing IoSlice beyond its length"); + } + + unsafe { + self.vec.iov_len -= n; + self.vec.iov_base = self.vec.iov_base.add(n); + } + } + + #[inline] + pub fn as_slice(&self) -> &[u8] { + unsafe { slice::from_raw_parts(self.vec.iov_base as *mut u8, self.vec.iov_len) } + } +} + +#[repr(transparent)] +pub struct IoSliceMut<'a> { + vec: iovec, + _p: PhantomData<&'a mut [u8]>, +} + +impl<'a> IoSliceMut<'a> { + #[inline] + pub fn new(buf: &'a mut [u8]) -> IoSliceMut<'a> { + IoSliceMut { + vec: iovec { iov_base: buf.as_mut_ptr() as *mut c_void, iov_len: buf.len() }, + _p: PhantomData, + } + } + + #[inline] + pub fn advance(&mut self, n: usize) { + if self.vec.iov_len < n { + panic!("advancing IoSliceMut beyond its length"); + } + + unsafe { + self.vec.iov_len -= n; + self.vec.iov_base = self.vec.iov_base.add(n); + } + } + + #[inline] + pub fn as_slice(&self) -> &[u8] { + unsafe { slice::from_raw_parts(self.vec.iov_base as *mut u8, self.vec.iov_len) } + } + + #[inline] + pub fn as_mut_slice(&mut self) -> &mut [u8] { + unsafe { slice::from_raw_parts_mut(self.vec.iov_base as *mut u8, self.vec.iov_len) } + } +} + +pub fn is_terminal(fd: &impl AsFd) -> bool { + let fd = fd.as_fd(); + hermit_abi::isatty(fd.as_raw_fd()) +} diff --git a/library/std/src/sys/pal/hermit/mod.rs b/library/std/src/sys/pal/hermit/mod.rs index a64323a3a296e..eca7351d54c8d 100644 --- a/library/std/src/sys/pal/hermit/mod.rs +++ b/library/std/src/sys/pal/hermit/mod.rs @@ -23,7 +23,6 @@ pub mod env; pub mod fd; pub mod fs; pub mod futex; -#[path = "../unsupported/io.rs"] pub mod io; pub mod net; pub mod os; diff --git a/library/std/src/sys/pal/hermit/net.rs b/library/std/src/sys/pal/hermit/net.rs index 00dbca86a4bae..6016d50eba085 100644 --- a/library/std/src/sys/pal/hermit/net.rs +++ b/library/std/src/sys/pal/hermit/net.rs @@ -175,12 +175,12 @@ impl Socket { } pub fn read_vectored(&self, bufs: &mut [IoSliceMut<'_>]) -> io::Result { - crate::io::default_read_vectored(|b| self.read(b), bufs) + self.0.read_vectored(bufs) } #[inline] pub fn is_read_vectored(&self) -> bool { - false + self.0.is_read_vectored() } fn recv_from_with_flags(&self, buf: &mut [u8], flags: i32) -> io::Result<(usize, SocketAddr)> { @@ -209,16 +209,15 @@ impl Socket { } pub fn write(&self, buf: &[u8]) -> io::Result { - let sz = cvt(unsafe { netc::write(self.0.as_raw_fd(), buf.as_ptr(), buf.len()) })?; - Ok(sz.try_into().unwrap()) + self.0.write(buf) } pub fn write_vectored(&self, bufs: &[IoSlice<'_>]) -> io::Result { - crate::io::default_write_vectored(|b| self.write(b), bufs) + self.0.write_vectored(bufs) } pub fn is_write_vectored(&self) -> bool { - false + self.0.is_write_vectored() } pub fn set_timeout(&self, dur: Option, kind: i32) -> io::Result<()> { @@ -265,7 +264,7 @@ impl Socket { Shutdown::Read => netc::SHUT_RD, Shutdown::Both => netc::SHUT_RDWR, }; - cvt(unsafe { netc::shutdown_socket(self.as_raw_fd(), how) })?; + cvt(unsafe { netc::shutdown(self.as_raw_fd(), how) })?; Ok(()) } diff --git a/library/std/src/sys/pal/hermit/os.rs b/library/std/src/sys/pal/hermit/os.rs index 91247d30462f8..a7a73c756f216 100644 --- a/library/std/src/sys/pal/hermit/os.rs +++ b/library/std/src/sys/pal/hermit/os.rs @@ -198,5 +198,5 @@ pub fn exit(code: i32) -> ! { } pub fn getpid() -> u32 { - unsafe { hermit_abi::getpid() } + unsafe { hermit_abi::getpid() as u32 } } diff --git a/library/std/src/sys/pal/hermit/stdio.rs b/library/std/src/sys/pal/hermit/stdio.rs index 777c57b391c89..3ea00f5cc5ec9 100644 --- a/library/std/src/sys/pal/hermit/stdio.rs +++ b/library/std/src/sys/pal/hermit/stdio.rs @@ -1,6 +1,9 @@ use super::hermit_abi; use crate::io; use crate::io::{IoSlice, IoSliceMut}; +use crate::mem::ManuallyDrop; +use crate::os::hermit::io::FromRawFd; +use crate::sys::fd::FileDesc; pub struct Stdin; pub struct Stdout; @@ -13,12 +16,14 @@ impl Stdin { } impl io::Read for Stdin { - fn read(&mut self, data: &mut [u8]) -> io::Result { - self.read_vectored(&mut [IoSliceMut::new(data)]) + fn read(&mut self, buf: &mut [u8]) -> io::Result { + unsafe { ManuallyDrop::new(FileDesc::from_raw_fd(hermit_abi::STDIN_FILENO)).read(buf) } } - fn read_vectored(&mut self, _data: &mut [IoSliceMut<'_>]) -> io::Result { - Ok(0) + fn read_vectored(&mut self, bufs: &mut [IoSliceMut<'_>]) -> io::Result { + unsafe { + ManuallyDrop::new(FileDesc::from_raw_fd(hermit_abi::STDIN_FILENO)).read_vectored(bufs) + } } #[inline] @@ -34,27 +39,13 @@ impl Stdout { } impl io::Write for Stdout { - fn write(&mut self, data: &[u8]) -> io::Result { - let len; - - unsafe { len = hermit_abi::write(1, data.as_ptr() as *const u8, data.len()) } - - if len < 0 { - Err(io::const_io_error!(io::ErrorKind::Uncategorized, "Stdout is not able to print")) - } else { - Ok(len as usize) - } + fn write(&mut self, buf: &[u8]) -> io::Result { + unsafe { ManuallyDrop::new(FileDesc::from_raw_fd(hermit_abi::STDOUT_FILENO)).write(buf) } } - fn write_vectored(&mut self, data: &[IoSlice<'_>]) -> io::Result { - let len; - - unsafe { len = hermit_abi::write(1, data.as_ptr() as *const u8, data.len()) } - - if len < 0 { - Err(io::const_io_error!(io::ErrorKind::Uncategorized, "Stdout is not able to print")) - } else { - Ok(len as usize) + fn write_vectored(&mut self, bufs: &[IoSlice<'_>]) -> io::Result { + unsafe { + ManuallyDrop::new(FileDesc::from_raw_fd(hermit_abi::STDOUT_FILENO)).write_vectored(bufs) } } @@ -75,27 +66,13 @@ impl Stderr { } impl io::Write for Stderr { - fn write(&mut self, data: &[u8]) -> io::Result { - let len; - - unsafe { len = hermit_abi::write(2, data.as_ptr() as *const u8, data.len()) } - - if len < 0 { - Err(io::const_io_error!(io::ErrorKind::Uncategorized, "Stderr is not able to print")) - } else { - Ok(len as usize) - } + fn write(&mut self, buf: &[u8]) -> io::Result { + unsafe { ManuallyDrop::new(FileDesc::from_raw_fd(hermit_abi::STDERR_FILENO)).write(buf) } } - fn write_vectored(&mut self, data: &[IoSlice<'_>]) -> io::Result { - let len; - - unsafe { len = hermit_abi::write(2, data.as_ptr() as *const u8, data.len()) } - - if len < 0 { - Err(io::const_io_error!(io::ErrorKind::Uncategorized, "Stderr is not able to print")) - } else { - Ok(len as usize) + fn write_vectored(&mut self, bufs: &[IoSlice<'_>]) -> io::Result { + unsafe { + ManuallyDrop::new(FileDesc::from_raw_fd(hermit_abi::STDERR_FILENO)).write_vectored(bufs) } } @@ -109,10 +86,10 @@ impl io::Write for Stderr { } } -pub const STDIN_BUF_SIZE: usize = 0; +pub const STDIN_BUF_SIZE: usize = 128; -pub fn is_ebadf(_err: &io::Error) -> bool { - true +pub fn is_ebadf(err: &io::Error) -> bool { + err.raw_os_error() == Some(hermit_abi::EBADF) } pub fn panic_output() -> Option { diff --git a/library/std/src/sys/pal/hermit/thread.rs b/library/std/src/sys/pal/hermit/thread.rs index b336dcd6860e4..07a843a597ea3 100644 --- a/library/std/src/sys/pal/hermit/thread.rs +++ b/library/std/src/sys/pal/hermit/thread.rs @@ -98,5 +98,5 @@ impl Thread { } pub fn available_parallelism() -> io::Result> { - unsafe { Ok(NonZero::new_unchecked(hermit_abi::get_processor_count())) } + unsafe { Ok(NonZero::new_unchecked(hermit_abi::available_parallelism())) } } diff --git a/library/std/src/sys/pal/hermit/time.rs b/library/std/src/sys/pal/hermit/time.rs index 2bf24462fa825..e0cb7c2aa98a5 100644 --- a/library/std/src/sys/pal/hermit/time.rs +++ b/library/std/src/sys/pal/hermit/time.rs @@ -1,11 +1,13 @@ #![allow(dead_code)] -use super::hermit_abi::{self, timespec, CLOCK_MONOTONIC, CLOCK_REALTIME, NSEC_PER_SEC}; +use super::hermit_abi::{self, timespec, CLOCK_MONOTONIC, CLOCK_REALTIME}; use crate::cmp::Ordering; use crate::ops::{Add, AddAssign, Sub, SubAssign}; use crate::time::Duration; use core::hash::{Hash, Hasher}; +const NSEC_PER_SEC: i32 = 1_000_000_000; + #[derive(Copy, Clone, Debug)] struct Timespec { t: timespec, @@ -16,8 +18,8 @@ impl Timespec { Timespec { t: timespec { tv_sec: 0, tv_nsec: 0 } } } - const fn new(tv_sec: i64, tv_nsec: i64) -> Timespec { - assert!(tv_nsec >= 0 && tv_nsec < NSEC_PER_SEC as i64); + const fn new(tv_sec: i64, tv_nsec: i32) -> Timespec { + assert!(tv_nsec >= 0 && tv_nsec < NSEC_PER_SEC); // SAFETY: The assert above checks tv_nsec is within the valid range Timespec { t: timespec { tv_sec: tv_sec, tv_nsec: tv_nsec } } } @@ -32,7 +34,7 @@ impl Timespec { } else { Duration::new( (self.t.tv_sec - 1 - other.t.tv_sec) as u64, - self.t.tv_nsec as u32 + (NSEC_PER_SEC as u32) - other.t.tv_nsec as u32, + (self.t.tv_nsec + NSEC_PER_SEC - other.t.tv_nsec) as u32, ) }) } else { @@ -48,9 +50,9 @@ impl Timespec { // Nano calculations can't overflow because nanos are <1B which fit // in a u32. - let mut nsec = other.subsec_nanos() + self.t.tv_nsec as u32; - if nsec >= NSEC_PER_SEC as u32 { - nsec -= NSEC_PER_SEC as u32; + let mut nsec = other.subsec_nanos() + u32::try_from(self.t.tv_nsec).unwrap(); + if nsec >= NSEC_PER_SEC.try_into().unwrap() { + nsec -= u32::try_from(NSEC_PER_SEC).unwrap(); secs = secs.checked_add(1)?; } Some(Timespec { t: timespec { tv_sec: secs, tv_nsec: nsec as _ } }) @@ -200,7 +202,7 @@ pub struct SystemTime(Timespec); pub const UNIX_EPOCH: SystemTime = SystemTime(Timespec::zero()); impl SystemTime { - pub fn new(tv_sec: i64, tv_nsec: i64) -> SystemTime { + pub fn new(tv_sec: i64, tv_nsec: i32) -> SystemTime { SystemTime(Timespec::new(tv_sec, tv_nsec)) } diff --git a/library/std/src/sys/pal/unix/fs.rs b/library/std/src/sys/pal/unix/fs.rs index 56a0f8e39c4aa..035c92bc84bfe 100644 --- a/library/std/src/sys/pal/unix/fs.rs +++ b/library/std/src/sys/pal/unix/fs.rs @@ -22,16 +22,12 @@ use crate::sys_common::{AsInner, AsInnerMut, FromInner, IntoInner}; #[cfg(any(all(target_os = "linux", target_env = "gnu"), target_vendor = "apple"))] use crate::sys::weak::syscall; -#[cfg(any(target_os = "android", target_os = "macos", target_os = "solaris"))] +#[cfg(target_os = "android")] use crate::sys::weak::weak; use libc::{c_int, mode_t}; -#[cfg(any( - target_os = "solaris", - all(target_os = "linux", target_env = "gnu"), - target_vendor = "apple", -))] +#[cfg(any(all(target_os = "linux", target_env = "gnu"), target_vendor = "apple"))] use libc::c_char; #[cfg(any( all(target_os = "linux", not(target_env = "musl")), @@ -1753,19 +1749,6 @@ pub fn link(original: &Path, link: &Path) -> io::Result<()> { // Android has `linkat` on newer versions, but we happen to know `link` // always has the correct behavior, so it's here as well. cvt(unsafe { libc::link(original.as_ptr(), link.as_ptr()) })?; - } else if #[cfg(any(target_os = "macos", target_os = "solaris"))] { - // MacOS (<=10.9) and Solaris 10 lack support for linkat while newer - // versions have it. We want to use linkat if it is available, so we use weak! - // to check. `linkat` is preferable to `link` because it gives us a flag to - // specify how symlinks should be handled. We pass 0 as the flags argument, - // meaning it shouldn't follow symlinks. - weak!(fn linkat(c_int, *const c_char, c_int, *const c_char, c_int) -> c_int); - - if let Some(f) = linkat.get() { - cvt(unsafe { f(libc::AT_FDCWD, original.as_ptr(), libc::AT_FDCWD, link.as_ptr(), 0) })?; - } else { - cvt(unsafe { libc::link(original.as_ptr(), link.as_ptr()) })?; - }; } else { // Where we can, use `linkat` instead of `link`; see the comment above // this one for details on why. diff --git a/library/std/src/sys/pal/windows/c/windows_sys.rs b/library/std/src/sys/pal/windows/c/windows_sys.rs index 1da8871ae44eb..19f013d3347e4 100644 --- a/library/std/src/sys/pal/windows/c/windows_sys.rs +++ b/library/std/src/sys/pal/windows/c/windows_sys.rs @@ -1,4 +1,4 @@ -// Bindings generated by `windows-bindgen` 0.56.0 +// Bindings generated by `windows-bindgen` 0.57.0 #![allow(non_snake_case, non_upper_case_globals, non_camel_case_types, dead_code, clippy::all)] #[link(name = "advapi32")] @@ -841,6 +841,7 @@ extern "system" { pub const ABOVE_NORMAL_PRIORITY_CLASS: PROCESS_CREATION_FLAGS = 32768u32; pub type ADDRESS_FAMILY = u16; #[repr(C)] +#[derive(Clone, Copy)] pub struct ADDRINFOA { pub ai_flags: i32, pub ai_family: i32, @@ -851,18 +852,13 @@ pub struct ADDRINFOA { pub ai_addr: *mut SOCKADDR, pub ai_next: *mut ADDRINFOA, } -impl Copy for ADDRINFOA {} -impl Clone for ADDRINFOA { - fn clone(&self) -> Self { - *self - } -} pub const AF_INET: ADDRESS_FAMILY = 2u16; pub const AF_INET6: ADDRESS_FAMILY = 23u16; pub const AF_UNIX: u16 = 1u16; pub const AF_UNSPEC: ADDRESS_FAMILY = 0u16; pub const ALL_PROCESSOR_GROUPS: u16 = 65535u16; #[repr(C)] +#[derive(Clone, Copy)] pub union ARM64_NT_NEON128 { pub Anonymous: ARM64_NT_NEON128_0, pub D: [f64; 2], @@ -870,27 +866,17 @@ pub union ARM64_NT_NEON128 { pub H: [u16; 8], pub B: [u8; 16], } -impl Copy for ARM64_NT_NEON128 {} -impl Clone for ARM64_NT_NEON128 { - fn clone(&self) -> Self { - *self - } -} #[repr(C)] +#[derive(Clone, Copy)] pub struct ARM64_NT_NEON128_0 { pub Low: u64, pub High: i64, } -impl Copy for ARM64_NT_NEON128_0 {} -impl Clone for ARM64_NT_NEON128_0 { - fn clone(&self) -> Self { - *self - } -} pub const BELOW_NORMAL_PRIORITY_CLASS: PROCESS_CREATION_FLAGS = 16384u32; pub type BOOL = i32; pub type BOOLEAN = u8; #[repr(C)] +#[derive(Clone, Copy)] pub struct BY_HANDLE_FILE_INFORMATION { pub dwFileAttributes: u32, pub ftCreationTime: FILETIME, @@ -903,41 +889,26 @@ pub struct BY_HANDLE_FILE_INFORMATION { pub nFileIndexHigh: u32, pub nFileIndexLow: u32, } -impl Copy for BY_HANDLE_FILE_INFORMATION {} -impl Clone for BY_HANDLE_FILE_INFORMATION { - fn clone(&self) -> Self { - *self - } -} pub const CALLBACK_CHUNK_FINISHED: LPPROGRESS_ROUTINE_CALLBACK_REASON = 0u32; pub const CALLBACK_STREAM_SWITCH: LPPROGRESS_ROUTINE_CALLBACK_REASON = 1u32; pub type COMPARESTRING_RESULT = i32; #[repr(C)] +#[derive(Clone, Copy)] pub struct CONDITION_VARIABLE { pub Ptr: *mut core::ffi::c_void, } -impl Copy for CONDITION_VARIABLE {} -impl Clone for CONDITION_VARIABLE { - fn clone(&self) -> Self { - *self - } -} pub type CONSOLE_MODE = u32; #[repr(C)] +#[derive(Clone, Copy)] pub struct CONSOLE_READCONSOLE_CONTROL { pub nLength: u32, pub nInitialChars: u32, pub dwCtrlWakeupMask: u32, pub dwControlKeyState: u32, } -impl Copy for CONSOLE_READCONSOLE_CONTROL {} -impl Clone for CONSOLE_READCONSOLE_CONTROL { - fn clone(&self) -> Self { - *self - } -} #[repr(C)] #[cfg(target_arch = "aarch64")] +#[derive(Clone, Copy)] pub struct CONTEXT { pub ContextFlags: CONTEXT_FLAGS, pub Cpsr: u32, @@ -952,30 +923,16 @@ pub struct CONTEXT { pub Wcr: [u32; 2], pub Wvr: [u64; 2], } -#[cfg(target_arch = "aarch64")] -impl Copy for CONTEXT {} -#[cfg(target_arch = "aarch64")] -impl Clone for CONTEXT { - fn clone(&self) -> Self { - *self - } -} #[repr(C)] #[cfg(target_arch = "aarch64")] +#[derive(Clone, Copy)] pub union CONTEXT_0 { pub Anonymous: CONTEXT_0_0, pub X: [u64; 31], } -#[cfg(target_arch = "aarch64")] -impl Copy for CONTEXT_0 {} -#[cfg(target_arch = "aarch64")] -impl Clone for CONTEXT_0 { - fn clone(&self) -> Self { - *self - } -} #[repr(C)] #[cfg(target_arch = "aarch64")] +#[derive(Clone, Copy)] pub struct CONTEXT_0_0 { pub X0: u64, pub X1: u64, @@ -1009,16 +966,9 @@ pub struct CONTEXT_0_0 { pub Fp: u64, pub Lr: u64, } -#[cfg(target_arch = "aarch64")] -impl Copy for CONTEXT_0_0 {} -#[cfg(target_arch = "aarch64")] -impl Clone for CONTEXT_0_0 { - fn clone(&self) -> Self { - *self - } -} #[repr(C)] #[cfg(any(target_arch = "arm64ec", target_arch = "x86_64"))] +#[derive(Clone, Copy)] pub struct CONTEXT { pub P1Home: u64, pub P2Home: u64, @@ -1067,30 +1017,16 @@ pub struct CONTEXT { pub LastExceptionToRip: u64, pub LastExceptionFromRip: u64, } -#[cfg(any(target_arch = "arm64ec", target_arch = "x86_64"))] -impl Copy for CONTEXT {} -#[cfg(any(target_arch = "arm64ec", target_arch = "x86_64"))] -impl Clone for CONTEXT { - fn clone(&self) -> Self { - *self - } -} #[repr(C)] #[cfg(any(target_arch = "arm64ec", target_arch = "x86_64"))] +#[derive(Clone, Copy)] pub union CONTEXT_0 { pub FltSave: XSAVE_FORMAT, pub Anonymous: CONTEXT_0_0, } -#[cfg(any(target_arch = "arm64ec", target_arch = "x86_64"))] -impl Copy for CONTEXT_0 {} -#[cfg(any(target_arch = "arm64ec", target_arch = "x86_64"))] -impl Clone for CONTEXT_0 { - fn clone(&self) -> Self { - *self - } -} #[repr(C)] #[cfg(any(target_arch = "arm64ec", target_arch = "x86_64"))] +#[derive(Clone, Copy)] pub struct CONTEXT_0_0 { pub Header: [M128A; 2], pub Legacy: [M128A; 8], @@ -1111,16 +1047,9 @@ pub struct CONTEXT_0_0 { pub Xmm14: M128A, pub Xmm15: M128A, } -#[cfg(any(target_arch = "arm64ec", target_arch = "x86_64"))] -impl Copy for CONTEXT_0_0 {} -#[cfg(any(target_arch = "arm64ec", target_arch = "x86_64"))] -impl Clone for CONTEXT_0_0 { - fn clone(&self) -> Self { - *self - } -} #[repr(C)] #[cfg(target_arch = "x86")] +#[derive(Clone, Copy)] pub struct CONTEXT { pub ContextFlags: CONTEXT_FLAGS, pub Dr0: u32, @@ -1148,14 +1077,6 @@ pub struct CONTEXT { pub SegSs: u32, pub ExtendedRegisters: [u8; 512], } -#[cfg(target_arch = "x86")] -impl Copy for CONTEXT {} -#[cfg(target_arch = "x86")] -impl Clone for CONTEXT { - fn clone(&self) -> Self { - *self - } -} pub type CONTEXT_FLAGS = u32; pub const CP_UTF8: u32 = 65001u32; pub const CREATE_ALWAYS: FILE_CREATION_DISPOSITION = 2u32; @@ -3068,6 +2989,7 @@ pub const ERROR_XML_PARSE_ERROR: WIN32_ERROR = 1465u32; pub type EXCEPTION_DISPOSITION = i32; pub const EXCEPTION_MAXIMUM_PARAMETERS: u32 = 15u32; #[repr(C)] +#[derive(Clone, Copy)] pub struct EXCEPTION_RECORD { pub ExceptionCode: NTSTATUS, pub ExceptionFlags: u32, @@ -3076,12 +2998,6 @@ pub struct EXCEPTION_RECORD { pub NumberParameters: u32, pub ExceptionInformation: [usize; 15], } -impl Copy for EXCEPTION_RECORD {} -impl Clone for EXCEPTION_RECORD { - fn clone(&self) -> Self { - *self - } -} pub const EXCEPTION_STACK_OVERFLOW: NTSTATUS = 0xC00000FD_u32 as _; pub const EXTENDED_STARTUPINFO_PRESENT: PROCESS_CREATION_FLAGS = 524288u32; pub const E_NOTIMPL: HRESULT = 0x80004001_u32 as _; @@ -3095,40 +3011,25 @@ pub const FALSE: BOOL = 0i32; pub type FARPROC = Option isize>; pub const FAST_FAIL_FATAL_APP_EXIT: u32 = 7u32; #[repr(C)] +#[derive(Clone, Copy)] pub struct FD_SET { pub fd_count: u32, pub fd_array: [SOCKET; 64], } -impl Copy for FD_SET {} -impl Clone for FD_SET { - fn clone(&self) -> Self { - *self - } -} #[repr(C)] +#[derive(Clone, Copy)] pub struct FILETIME { pub dwLowDateTime: u32, pub dwHighDateTime: u32, } -impl Copy for FILETIME {} -impl Clone for FILETIME { - fn clone(&self) -> Self { - *self - } -} pub type FILE_ACCESS_RIGHTS = u32; pub const FILE_ADD_FILE: FILE_ACCESS_RIGHTS = 2u32; pub const FILE_ADD_SUBDIRECTORY: FILE_ACCESS_RIGHTS = 4u32; #[repr(C)] +#[derive(Clone, Copy)] pub struct FILE_ALLOCATION_INFO { pub AllocationSize: i64, } -impl Copy for FILE_ALLOCATION_INFO {} -impl Clone for FILE_ALLOCATION_INFO { - fn clone(&self) -> Self { - *self - } -} pub const FILE_ALL_ACCESS: FILE_ACCESS_RIGHTS = 2032127u32; pub const FILE_APPEND_DATA: FILE_ACCESS_RIGHTS = 4u32; pub const FILE_ATTRIBUTE_ARCHIVE: FILE_FLAGS_AND_ATTRIBUTES = 32u32; @@ -3151,20 +3052,16 @@ pub const FILE_ATTRIBUTE_REPARSE_POINT: FILE_FLAGS_AND_ATTRIBUTES = 1024u32; pub const FILE_ATTRIBUTE_SPARSE_FILE: FILE_FLAGS_AND_ATTRIBUTES = 512u32; pub const FILE_ATTRIBUTE_SYSTEM: FILE_FLAGS_AND_ATTRIBUTES = 4u32; #[repr(C)] +#[derive(Clone, Copy)] pub struct FILE_ATTRIBUTE_TAG_INFO { pub FileAttributes: u32, pub ReparseTag: u32, } -impl Copy for FILE_ATTRIBUTE_TAG_INFO {} -impl Clone for FILE_ATTRIBUTE_TAG_INFO { - fn clone(&self) -> Self { - *self - } -} pub const FILE_ATTRIBUTE_TEMPORARY: FILE_FLAGS_AND_ATTRIBUTES = 256u32; pub const FILE_ATTRIBUTE_UNPINNED: FILE_FLAGS_AND_ATTRIBUTES = 1048576u32; pub const FILE_ATTRIBUTE_VIRTUAL: FILE_FLAGS_AND_ATTRIBUTES = 65536u32; #[repr(C)] +#[derive(Clone, Copy)] pub struct FILE_BASIC_INFO { pub CreationTime: i64, pub LastAccessTime: i64, @@ -3172,12 +3069,6 @@ pub struct FILE_BASIC_INFO { pub ChangeTime: i64, pub FileAttributes: u32, } -impl Copy for FILE_BASIC_INFO {} -impl Clone for FILE_BASIC_INFO { - fn clone(&self) -> Self { - *self - } -} pub const FILE_BEGIN: SET_FILE_POINTER_MOVE_METHOD = 0u32; pub const FILE_COMPLETE_IF_OPLOCKED: NTCREATEFILE_CREATE_OPTIONS = 256u32; pub const FILE_CONTAINS_EXTENDED_CREATE_INFORMATION: NTCREATEFILE_CREATE_OPTIONS = 268435456u32; @@ -3197,37 +3088,22 @@ pub const FILE_DISPOSITION_FLAG_IGNORE_READONLY_ATTRIBUTE: FILE_DISPOSITION_INFO pub const FILE_DISPOSITION_FLAG_ON_CLOSE: FILE_DISPOSITION_INFO_EX_FLAGS = 8u32; pub const FILE_DISPOSITION_FLAG_POSIX_SEMANTICS: FILE_DISPOSITION_INFO_EX_FLAGS = 2u32; #[repr(C)] +#[derive(Clone, Copy)] pub struct FILE_DISPOSITION_INFO { pub DeleteFile: BOOLEAN, } -impl Copy for FILE_DISPOSITION_INFO {} -impl Clone for FILE_DISPOSITION_INFO { - fn clone(&self) -> Self { - *self - } -} #[repr(C)] +#[derive(Clone, Copy)] pub struct FILE_DISPOSITION_INFO_EX { pub Flags: FILE_DISPOSITION_INFO_EX_FLAGS, } -impl Copy for FILE_DISPOSITION_INFO_EX {} -impl Clone for FILE_DISPOSITION_INFO_EX { - fn clone(&self) -> Self { - *self - } -} pub type FILE_DISPOSITION_INFO_EX_FLAGS = u32; pub const FILE_END: SET_FILE_POINTER_MOVE_METHOD = 2u32; #[repr(C)] +#[derive(Clone, Copy)] pub struct FILE_END_OF_FILE_INFO { pub EndOfFile: i64, } -impl Copy for FILE_END_OF_FILE_INFO {} -impl Clone for FILE_END_OF_FILE_INFO { - fn clone(&self) -> Self { - *self - } -} pub const FILE_EXECUTE: FILE_ACCESS_RIGHTS = 32u32; pub type FILE_FLAGS_AND_ATTRIBUTES = u32; pub const FILE_FLAG_BACKUP_SEMANTICS: FILE_FLAGS_AND_ATTRIBUTES = 33554432u32; @@ -3246,6 +3122,7 @@ pub const FILE_GENERIC_EXECUTE: FILE_ACCESS_RIGHTS = 1179808u32; pub const FILE_GENERIC_READ: FILE_ACCESS_RIGHTS = 1179785u32; pub const FILE_GENERIC_WRITE: FILE_ACCESS_RIGHTS = 1179926u32; #[repr(C)] +#[derive(Clone, Copy)] pub struct FILE_ID_BOTH_DIR_INFO { pub NextEntryOffset: u32, pub FileIndex: u32, @@ -3263,23 +3140,12 @@ pub struct FILE_ID_BOTH_DIR_INFO { pub FileId: i64, pub FileName: [u16; 1], } -impl Copy for FILE_ID_BOTH_DIR_INFO {} -impl Clone for FILE_ID_BOTH_DIR_INFO { - fn clone(&self) -> Self { - *self - } -} pub type FILE_INFO_BY_HANDLE_CLASS = i32; #[repr(C)] +#[derive(Clone, Copy)] pub struct FILE_IO_PRIORITY_HINT_INFO { pub PriorityHint: PRIORITY_HINT, } -impl Copy for FILE_IO_PRIORITY_HINT_INFO {} -impl Clone for FILE_IO_PRIORITY_HINT_INFO { - fn clone(&self) -> Self { - *self - } -} pub const FILE_LIST_DIRECTORY: FILE_ACCESS_RIGHTS = 1u32; pub const FILE_NAME_NORMALIZED: GETFINALPATHNAMEBYHANDLE_FLAGS = 0u32; pub const FILE_NAME_OPENED: GETFINALPATHNAMEBYHANDLE_FLAGS = 8u32; @@ -3310,6 +3176,7 @@ pub const FILE_SHARE_NONE: FILE_SHARE_MODE = 0u32; pub const FILE_SHARE_READ: FILE_SHARE_MODE = 1u32; pub const FILE_SHARE_WRITE: FILE_SHARE_MODE = 2u32; #[repr(C)] +#[derive(Clone, Copy)] pub struct FILE_STANDARD_INFO { pub AllocationSize: i64, pub EndOfFile: i64, @@ -3317,12 +3184,6 @@ pub struct FILE_STANDARD_INFO { pub DeletePending: BOOLEAN, pub Directory: BOOLEAN, } -impl Copy for FILE_STANDARD_INFO {} -impl Clone for FILE_STANDARD_INFO { - fn clone(&self) -> Self { - *self - } -} pub const FILE_SUPERSEDE: NTCREATEFILE_CREATE_DISPOSITION = 0u32; pub const FILE_SYNCHRONOUS_IO_ALERT: NTCREATEFILE_CREATE_OPTIONS = 16u32; pub const FILE_SYNCHRONOUS_IO_NONALERT: NTCREATEFILE_CREATE_OPTIONS = 32u32; @@ -3340,6 +3201,7 @@ pub const FILE_WRITE_THROUGH: NTCREATEFILE_CREATE_OPTIONS = 2u32; pub const FIONBIO: i32 = -2147195266i32; #[repr(C)] #[cfg(any(target_arch = "aarch64", target_arch = "arm64ec", target_arch = "x86_64"))] +#[derive(Clone, Copy)] pub struct FLOATING_SAVE_AREA { pub ControlWord: u32, pub StatusWord: u32, @@ -3351,16 +3213,9 @@ pub struct FLOATING_SAVE_AREA { pub RegisterArea: [u8; 80], pub Cr0NpxState: u32, } -#[cfg(any(target_arch = "aarch64", target_arch = "arm64ec", target_arch = "x86_64"))] -impl Copy for FLOATING_SAVE_AREA {} -#[cfg(any(target_arch = "aarch64", target_arch = "arm64ec", target_arch = "x86_64"))] -impl Clone for FLOATING_SAVE_AREA { - fn clone(&self) -> Self { - *self - } -} #[repr(C)] #[cfg(target_arch = "x86")] +#[derive(Clone, Copy)] pub struct FLOATING_SAVE_AREA { pub ControlWord: u32, pub StatusWord: u32, @@ -3372,14 +3227,6 @@ pub struct FLOATING_SAVE_AREA { pub RegisterArea: [u8; 80], pub Spare0: u32, } -#[cfg(target_arch = "x86")] -impl Copy for FLOATING_SAVE_AREA {} -#[cfg(target_arch = "x86")] -impl Clone for FLOATING_SAVE_AREA { - fn clone(&self) -> Self { - *self - } -} pub const FORMAT_MESSAGE_ALLOCATE_BUFFER: FORMAT_MESSAGE_OPTIONS = 256u32; pub const FORMAT_MESSAGE_ARGUMENT_ARRAY: FORMAT_MESSAGE_OPTIONS = 8192u32; pub const FORMAT_MESSAGE_FROM_HMODULE: FORMAT_MESSAGE_OPTIONS = 2048u32; @@ -3422,18 +3269,13 @@ pub const GENERIC_READ: GENERIC_ACCESS_RIGHTS = 2147483648u32; pub const GENERIC_WRITE: GENERIC_ACCESS_RIGHTS = 1073741824u32; pub type GETFINALPATHNAMEBYHANDLE_FLAGS = u32; #[repr(C)] +#[derive(Clone, Copy)] pub struct GUID { pub data1: u32, pub data2: u16, pub data3: u16, pub data4: [u8; 8], } -impl Copy for GUID {} -impl Clone for GUID { - fn clone(&self) -> Self { - *self - } -} impl GUID { pub const fn from_u128(uuid: u128) -> Self { Self { @@ -3454,112 +3296,67 @@ pub type HMODULE = *mut core::ffi::c_void; pub type HRESULT = i32; pub const IDLE_PRIORITY_CLASS: PROCESS_CREATION_FLAGS = 64u32; #[repr(C)] +#[derive(Clone, Copy)] pub struct IN6_ADDR { pub u: IN6_ADDR_0, } -impl Copy for IN6_ADDR {} -impl Clone for IN6_ADDR { - fn clone(&self) -> Self { - *self - } -} #[repr(C)] +#[derive(Clone, Copy)] pub union IN6_ADDR_0 { pub Byte: [u8; 16], pub Word: [u16; 8], } -impl Copy for IN6_ADDR_0 {} -impl Clone for IN6_ADDR_0 { - fn clone(&self) -> Self { - *self - } -} pub const INFINITE: u32 = 4294967295u32; pub const INHERIT_CALLER_PRIORITY: PROCESS_CREATION_FLAGS = 131072u32; pub const INHERIT_PARENT_AFFINITY: PROCESS_CREATION_FLAGS = 65536u32; #[repr(C)] +#[derive(Clone, Copy)] pub union INIT_ONCE { pub Ptr: *mut core::ffi::c_void, } -impl Copy for INIT_ONCE {} -impl Clone for INIT_ONCE { - fn clone(&self) -> Self { - *self - } -} pub const INIT_ONCE_INIT_FAILED: u32 = 4u32; pub const INVALID_FILE_ATTRIBUTES: u32 = 4294967295u32; pub const INVALID_SOCKET: SOCKET = -1i32 as _; #[repr(C)] +#[derive(Clone, Copy)] pub struct IN_ADDR { pub S_un: IN_ADDR_0, } -impl Copy for IN_ADDR {} -impl Clone for IN_ADDR { - fn clone(&self) -> Self { - *self - } -} #[repr(C)] +#[derive(Clone, Copy)] pub union IN_ADDR_0 { pub S_un_b: IN_ADDR_0_0, pub S_un_w: IN_ADDR_0_1, pub S_addr: u32, } -impl Copy for IN_ADDR_0 {} -impl Clone for IN_ADDR_0 { - fn clone(&self) -> Self { - *self - } -} #[repr(C)] +#[derive(Clone, Copy)] pub struct IN_ADDR_0_0 { pub s_b1: u8, pub s_b2: u8, pub s_b3: u8, pub s_b4: u8, } -impl Copy for IN_ADDR_0_0 {} -impl Clone for IN_ADDR_0_0 { - fn clone(&self) -> Self { - *self - } -} #[repr(C)] +#[derive(Clone, Copy)] pub struct IN_ADDR_0_1 { pub s_w1: u16, pub s_w2: u16, } -impl Copy for IN_ADDR_0_1 {} -impl Clone for IN_ADDR_0_1 { - fn clone(&self) -> Self { - *self - } -} pub const IO_REPARSE_TAG_MOUNT_POINT: u32 = 2684354563u32; pub const IO_REPARSE_TAG_SYMLINK: u32 = 2684354572u32; #[repr(C)] +#[derive(Clone, Copy)] pub struct IO_STATUS_BLOCK { pub Anonymous: IO_STATUS_BLOCK_0, pub Information: usize, } -impl Copy for IO_STATUS_BLOCK {} -impl Clone for IO_STATUS_BLOCK { - fn clone(&self) -> Self { - *self - } -} #[repr(C)] +#[derive(Clone, Copy)] pub union IO_STATUS_BLOCK_0 { pub Status: NTSTATUS, pub Pointer: *mut core::ffi::c_void, } -impl Copy for IO_STATUS_BLOCK_0 {} -impl Clone for IO_STATUS_BLOCK_0 { - fn clone(&self) -> Self { - *self - } -} pub type IPPROTO = i32; pub const IPPROTO_AH: IPPROTO = 51i32; pub const IPPROTO_CBT: IPPROTO = 7i32; @@ -3601,45 +3398,30 @@ pub const IPPROTO_UDP: IPPROTO = 17i32; pub const IPV6_ADD_MEMBERSHIP: i32 = 12i32; pub const IPV6_DROP_MEMBERSHIP: i32 = 13i32; #[repr(C)] +#[derive(Clone, Copy)] pub struct IPV6_MREQ { pub ipv6mr_multiaddr: IN6_ADDR, pub ipv6mr_interface: u32, } -impl Copy for IPV6_MREQ {} -impl Clone for IPV6_MREQ { - fn clone(&self) -> Self { - *self - } -} pub const IPV6_MULTICAST_LOOP: i32 = 11i32; pub const IPV6_V6ONLY: i32 = 27i32; pub const IP_ADD_MEMBERSHIP: i32 = 12i32; pub const IP_DROP_MEMBERSHIP: i32 = 13i32; #[repr(C)] +#[derive(Clone, Copy)] pub struct IP_MREQ { pub imr_multiaddr: IN_ADDR, pub imr_interface: IN_ADDR, } -impl Copy for IP_MREQ {} -impl Clone for IP_MREQ { - fn clone(&self) -> Self { - *self - } -} pub const IP_MULTICAST_LOOP: i32 = 11i32; pub const IP_MULTICAST_TTL: i32 = 10i32; pub const IP_TTL: i32 = 4i32; #[repr(C)] +#[derive(Clone, Copy)] pub struct LINGER { pub l_onoff: u16, pub l_linger: u16, } -impl Copy for LINGER {} -impl Clone for LINGER { - fn clone(&self) -> Self { - *self - } -} pub type LPOVERLAPPED_COMPLETION_ROUTINE = Option< unsafe extern "system" fn( dwerrorcode: u32, @@ -3673,16 +3455,11 @@ pub type LPWSAOVERLAPPED_COMPLETION_ROUTINE = Option< ), >; #[repr(C)] +#[derive(Clone, Copy)] pub struct M128A { pub Low: u64, pub High: i64, } -impl Copy for M128A {} -impl Clone for M128A { - fn clone(&self) -> Self { - *self - } -} pub const MAXIMUM_REPARSE_DATA_BUFFER_SIZE: u32 = 16384u32; pub const MAX_PATH: u32 = 260u32; pub const MB_COMPOSITE: MULTI_BYTE_TO_WIDE_CHAR_FLAGS = 2u32; @@ -3710,6 +3487,7 @@ pub type NTCREATEFILE_CREATE_DISPOSITION = u32; pub type NTCREATEFILE_CREATE_OPTIONS = u32; pub type NTSTATUS = i32; #[repr(C)] +#[derive(Clone, Copy)] pub struct OBJECT_ATTRIBUTES { pub Length: u32, pub RootDirectory: HANDLE, @@ -3718,50 +3496,29 @@ pub struct OBJECT_ATTRIBUTES { pub SecurityDescriptor: *const core::ffi::c_void, pub SecurityQualityOfService: *const core::ffi::c_void, } -impl Copy for OBJECT_ATTRIBUTES {} -impl Clone for OBJECT_ATTRIBUTES { - fn clone(&self) -> Self { - *self - } -} pub const OBJ_DONT_REPARSE: i32 = 4096i32; pub const OPEN_ALWAYS: FILE_CREATION_DISPOSITION = 4u32; pub const OPEN_EXISTING: FILE_CREATION_DISPOSITION = 3u32; #[repr(C)] +#[derive(Clone, Copy)] pub struct OVERLAPPED { pub Internal: usize, pub InternalHigh: usize, pub Anonymous: OVERLAPPED_0, pub hEvent: HANDLE, } -impl Copy for OVERLAPPED {} -impl Clone for OVERLAPPED { - fn clone(&self) -> Self { - *self - } -} #[repr(C)] +#[derive(Clone, Copy)] pub union OVERLAPPED_0 { pub Anonymous: OVERLAPPED_0_0, pub Pointer: *mut core::ffi::c_void, } -impl Copy for OVERLAPPED_0 {} -impl Clone for OVERLAPPED_0 { - fn clone(&self) -> Self { - *self - } -} #[repr(C)] +#[derive(Clone, Copy)] pub struct OVERLAPPED_0_0 { pub Offset: u32, pub OffsetHigh: u32, } -impl Copy for OVERLAPPED_0_0 {} -impl Clone for OVERLAPPED_0_0 { - fn clone(&self) -> Self { - *self - } -} pub type PCSTR = *const u8; pub type PCWSTR = *const u16; pub type PIO_APC_ROUTINE = Option< @@ -3788,18 +3545,13 @@ pub type PRIORITY_HINT = i32; pub type PROCESSOR_ARCHITECTURE = u16; pub type PROCESS_CREATION_FLAGS = u32; #[repr(C)] +#[derive(Clone, Copy)] pub struct PROCESS_INFORMATION { pub hProcess: HANDLE, pub hThread: HANDLE, pub dwProcessId: u32, pub dwThreadId: u32, } -impl Copy for PROCESS_INFORMATION {} -impl Clone for PROCESS_INFORMATION { - fn clone(&self) -> Self { - *self - } -} pub const PROCESS_MODE_BACKGROUND_BEGIN: PROCESS_CREATION_FLAGS = 1048576u32; pub const PROCESS_MODE_BACKGROUND_END: PROCESS_CREATION_FLAGS = 2097152u32; pub const PROFILE_KERNEL: PROCESS_CREATION_FLAGS = 536870912u32; @@ -3822,17 +3574,12 @@ pub const SD_RECEIVE: WINSOCK_SHUTDOWN_HOW = 0i32; pub const SD_SEND: WINSOCK_SHUTDOWN_HOW = 1i32; pub const SECURITY_ANONYMOUS: FILE_FLAGS_AND_ATTRIBUTES = 0u32; #[repr(C)] +#[derive(Clone, Copy)] pub struct SECURITY_ATTRIBUTES { pub nLength: u32, pub lpSecurityDescriptor: *mut core::ffi::c_void, pub bInheritHandle: BOOL, } -impl Copy for SECURITY_ATTRIBUTES {} -impl Clone for SECURITY_ATTRIBUTES { - fn clone(&self) -> Self { - *self - } -} pub const SECURITY_CONTEXT_TRACKING: FILE_FLAGS_AND_ATTRIBUTES = 262144u32; pub const SECURITY_DELEGATION: FILE_FLAGS_AND_ATTRIBUTES = 196608u32; pub const SECURITY_EFFECTIVE_ONLY: FILE_FLAGS_AND_ATTRIBUTES = 524288u32; @@ -3843,27 +3590,17 @@ pub const SECURITY_VALID_SQOS_FLAGS: FILE_FLAGS_AND_ATTRIBUTES = 2031616u32; pub type SEND_RECV_FLAGS = i32; pub type SET_FILE_POINTER_MOVE_METHOD = u32; #[repr(C)] +#[derive(Clone, Copy)] pub struct SOCKADDR { pub sa_family: ADDRESS_FAMILY, pub sa_data: [i8; 14], } -impl Copy for SOCKADDR {} -impl Clone for SOCKADDR { - fn clone(&self) -> Self { - *self - } -} #[repr(C)] +#[derive(Clone, Copy)] pub struct SOCKADDR_UN { pub sun_family: ADDRESS_FAMILY, pub sun_path: [i8; 108], } -impl Copy for SOCKADDR_UN {} -impl Clone for SOCKADDR_UN { - fn clone(&self) -> Self { - *self - } -} pub type SOCKET = usize; pub const SOCKET_ERROR: i32 = -1i32; pub const SOCK_DGRAM: WINSOCK_SOCKET_TYPE = 2i32; @@ -3879,15 +3616,10 @@ pub const SO_RCVTIMEO: i32 = 4102i32; pub const SO_SNDTIMEO: i32 = 4101i32; pub const SPECIFIC_RIGHTS_ALL: FILE_ACCESS_RIGHTS = 65535u32; #[repr(C)] +#[derive(Clone, Copy)] pub struct SRWLOCK { pub Ptr: *mut core::ffi::c_void, } -impl Copy for SRWLOCK {} -impl Clone for SRWLOCK { - fn clone(&self) -> Self { - *self - } -} pub const STACK_SIZE_PARAM_IS_A_RESERVATION: THREAD_CREATION_FLAGS = 65536u32; pub const STANDARD_RIGHTS_ALL: FILE_ACCESS_RIGHTS = 2031616u32; pub const STANDARD_RIGHTS_EXECUTE: FILE_ACCESS_RIGHTS = 131072u32; @@ -3909,17 +3641,13 @@ pub const STARTF_USESHOWWINDOW: STARTUPINFOW_FLAGS = 1u32; pub const STARTF_USESIZE: STARTUPINFOW_FLAGS = 2u32; pub const STARTF_USESTDHANDLES: STARTUPINFOW_FLAGS = 256u32; #[repr(C)] +#[derive(Clone, Copy)] pub struct STARTUPINFOEXW { pub StartupInfo: STARTUPINFOW, pub lpAttributeList: LPPROC_THREAD_ATTRIBUTE_LIST, } -impl Copy for STARTUPINFOEXW {} -impl Clone for STARTUPINFOEXW { - fn clone(&self) -> Self { - *self - } -} #[repr(C)] +#[derive(Clone, Copy)] pub struct STARTUPINFOW { pub cb: u32, pub lpReserved: PWSTR, @@ -3940,12 +3668,6 @@ pub struct STARTUPINFOW { pub hStdOutput: HANDLE, pub hStdError: HANDLE, } -impl Copy for STARTUPINFOW {} -impl Clone for STARTUPINFOW { - fn clone(&self) -> Self { - *self - } -} pub type STARTUPINFOW_FLAGS = u32; pub const STATUS_DELETE_PENDING: NTSTATUS = 0xC0000056_u32 as _; pub const STATUS_END_OF_FILE: NTSTATUS = 0xC0000011_u32 as _; @@ -3964,6 +3686,7 @@ pub const SYMLINK_FLAG_RELATIVE: u32 = 1u32; pub type SYNCHRONIZATION_ACCESS_RIGHTS = u32; pub const SYNCHRONIZE: FILE_ACCESS_RIGHTS = 1048576u32; #[repr(C)] +#[derive(Clone, Copy)] pub struct SYSTEM_INFO { pub Anonymous: SYSTEM_INFO_0, pub dwPageSize: u32, @@ -3976,34 +3699,18 @@ pub struct SYSTEM_INFO { pub wProcessorLevel: u16, pub wProcessorRevision: u16, } -impl Copy for SYSTEM_INFO {} -impl Clone for SYSTEM_INFO { - fn clone(&self) -> Self { - *self - } -} #[repr(C)] +#[derive(Clone, Copy)] pub union SYSTEM_INFO_0 { pub dwOemId: u32, pub Anonymous: SYSTEM_INFO_0_0, } -impl Copy for SYSTEM_INFO_0 {} -impl Clone for SYSTEM_INFO_0 { - fn clone(&self) -> Self { - *self - } -} #[repr(C)] +#[derive(Clone, Copy)] pub struct SYSTEM_INFO_0_0 { pub wProcessorArchitecture: PROCESSOR_ARCHITECTURE, pub wReserved: u16, } -impl Copy for SYSTEM_INFO_0_0 {} -impl Clone for SYSTEM_INFO_0_0 { - fn clone(&self) -> Self { - *self - } -} pub const TCP_NODELAY: i32 = 1i32; pub const THREAD_CREATE_RUN_IMMEDIATELY: THREAD_CREATION_FLAGS = 0u32; pub const THREAD_CREATE_SUSPENDED: THREAD_CREATION_FLAGS = 4u32; @@ -4011,16 +3718,11 @@ pub type THREAD_CREATION_FLAGS = u32; pub const TIMER_ALL_ACCESS: SYNCHRONIZATION_ACCESS_RIGHTS = 2031619u32; pub const TIMER_MODIFY_STATE: SYNCHRONIZATION_ACCESS_RIGHTS = 2u32; #[repr(C)] +#[derive(Clone, Copy)] pub struct TIMEVAL { pub tv_sec: i32, pub tv_usec: i32, } -impl Copy for TIMEVAL {} -impl Clone for TIMEVAL { - fn clone(&self) -> Self { - *self - } -} pub const TLS_OUT_OF_INDEXES: u32 = 4294967295u32; pub type TOKEN_ACCESS_MASK = u32; pub const TOKEN_ACCESS_PSEUDO_HANDLE: TOKEN_ACCESS_MASK = 24u32; @@ -4047,17 +3749,12 @@ pub const TOKEN_WRITE_OWNER: TOKEN_ACCESS_MASK = 524288u32; pub const TRUE: BOOL = 1i32; pub const TRUNCATE_EXISTING: FILE_CREATION_DISPOSITION = 5u32; #[repr(C)] +#[derive(Clone, Copy)] pub struct UNICODE_STRING { pub Length: u16, pub MaximumLength: u16, pub Buffer: PWSTR, } -impl Copy for UNICODE_STRING {} -impl Clone for UNICODE_STRING { - fn clone(&self) -> Self { - *self - } -} pub const VOLUME_NAME_DOS: GETFINALPATHNAMEBYHANDLE_FLAGS = 0u32; pub const VOLUME_NAME_GUID: GETFINALPATHNAMEBYHANDLE_FLAGS = 1u32; pub const VOLUME_NAME_NONE: GETFINALPATHNAMEBYHANDLE_FLAGS = 4u32; @@ -4071,6 +3768,7 @@ pub const WAIT_TIMEOUT: WAIT_EVENT = 258u32; pub const WC_ERR_INVALID_CHARS: u32 = 128u32; pub type WIN32_ERROR = u32; #[repr(C)] +#[derive(Clone, Copy)] pub struct WIN32_FIND_DATAW { pub dwFileAttributes: u32, pub ftCreationTime: FILETIME, @@ -4083,30 +3781,20 @@ pub struct WIN32_FIND_DATAW { pub cFileName: [u16; 260], pub cAlternateFileName: [u16; 14], } -impl Copy for WIN32_FIND_DATAW {} -impl Clone for WIN32_FIND_DATAW { - fn clone(&self) -> Self { - *self - } -} pub type WINSOCK_SHUTDOWN_HOW = i32; pub type WINSOCK_SOCKET_TYPE = i32; pub const WRITE_DAC: FILE_ACCESS_RIGHTS = 262144u32; pub const WRITE_OWNER: FILE_ACCESS_RIGHTS = 524288u32; pub const WSABASEERR: WSA_ERROR = 10000i32; #[repr(C)] +#[derive(Clone, Copy)] pub struct WSABUF { pub len: u32, pub buf: PSTR, } -impl Copy for WSABUF {} -impl Clone for WSABUF { - fn clone(&self) -> Self { - *self - } -} #[repr(C)] #[cfg(any(target_arch = "aarch64", target_arch = "arm64ec", target_arch = "x86_64"))] +#[derive(Clone, Copy)] pub struct WSADATA { pub wVersion: u16, pub wHighVersion: u16, @@ -4116,16 +3804,9 @@ pub struct WSADATA { pub szDescription: [i8; 257], pub szSystemStatus: [i8; 129], } -#[cfg(any(target_arch = "aarch64", target_arch = "arm64ec", target_arch = "x86_64"))] -impl Copy for WSADATA {} -#[cfg(any(target_arch = "aarch64", target_arch = "arm64ec", target_arch = "x86_64"))] -impl Clone for WSADATA { - fn clone(&self) -> Self { - *self - } -} #[repr(C)] #[cfg(target_arch = "x86")] +#[derive(Clone, Copy)] pub struct WSADATA { pub wVersion: u16, pub wHighVersion: u16, @@ -4135,14 +3816,6 @@ pub struct WSADATA { pub iMaxUdpDg: u16, pub lpVendorInfo: PSTR, } -#[cfg(target_arch = "x86")] -impl Copy for WSADATA {} -#[cfg(target_arch = "x86")] -impl Clone for WSADATA { - fn clone(&self) -> Self { - *self - } -} pub const WSAEACCES: WSA_ERROR = 10013i32; pub const WSAEADDRINUSE: WSA_ERROR = 10048i32; pub const WSAEADDRNOTAVAIL: WSA_ERROR = 10049i32; @@ -4198,17 +3871,13 @@ pub const WSANOTINITIALISED: WSA_ERROR = 10093i32; pub const WSANO_DATA: WSA_ERROR = 11004i32; pub const WSANO_RECOVERY: WSA_ERROR = 11003i32; #[repr(C)] +#[derive(Clone, Copy)] pub struct WSAPROTOCOLCHAIN { pub ChainLen: i32, pub ChainEntries: [u32; 7], } -impl Copy for WSAPROTOCOLCHAIN {} -impl Clone for WSAPROTOCOLCHAIN { - fn clone(&self) -> Self { - *self - } -} #[repr(C)] +#[derive(Clone, Copy)] pub struct WSAPROTOCOL_INFOW { pub dwServiceFlags1: u32, pub dwServiceFlags2: u32, @@ -4231,12 +3900,6 @@ pub struct WSAPROTOCOL_INFOW { pub dwProviderReserved: u32, pub szProtocol: [u16; 256], } -impl Copy for WSAPROTOCOL_INFOW {} -impl Clone for WSAPROTOCOL_INFOW { - fn clone(&self) -> Self { - *self - } -} pub const WSASERVICE_NOT_FOUND: WSA_ERROR = 10108i32; pub const WSASYSCALLFAILURE: WSA_ERROR = 10107i32; pub const WSASYSNOTREADY: WSA_ERROR = 10091i32; @@ -4287,6 +3950,7 @@ pub const WSA_WAIT_EVENT_0: WSA_ERROR = 0i32; pub const WSA_WAIT_IO_COMPLETION: WSA_ERROR = 192i32; #[repr(C)] #[cfg(any(target_arch = "aarch64", target_arch = "arm64ec", target_arch = "x86_64"))] +#[derive(Clone, Copy)] pub struct XSAVE_FORMAT { pub ControlWord: u16, pub StatusWord: u16, @@ -4305,16 +3969,9 @@ pub struct XSAVE_FORMAT { pub XmmRegisters: [M128A; 16], pub Reserved4: [u8; 96], } -#[cfg(any(target_arch = "aarch64", target_arch = "arm64ec", target_arch = "x86_64"))] -impl Copy for XSAVE_FORMAT {} -#[cfg(any(target_arch = "aarch64", target_arch = "arm64ec", target_arch = "x86_64"))] -impl Clone for XSAVE_FORMAT { - fn clone(&self) -> Self { - *self - } -} #[repr(C)] #[cfg(target_arch = "x86")] +#[derive(Clone, Copy)] pub struct XSAVE_FORMAT { pub ControlWord: u16, pub StatusWord: u16, @@ -4333,12 +3990,4 @@ pub struct XSAVE_FORMAT { pub XmmRegisters: [M128A; 8], pub Reserved4: [u8; 224], } -#[cfg(target_arch = "x86")] -impl Copy for XSAVE_FORMAT {} -#[cfg(target_arch = "x86")] -impl Clone for XSAVE_FORMAT { - fn clone(&self) -> Self { - *self - } -} // ignore-tidy-filelength diff --git a/library/std/src/sys_common/mod.rs b/library/std/src/sys_common/mod.rs index 3a38ba1100f01..200ea028a08ad 100644 --- a/library/std/src/sys_common/mod.rs +++ b/library/std/src/sys_common/mod.rs @@ -20,7 +20,6 @@ #[cfg(test)] mod tests; -pub mod backtrace; pub mod fs; pub mod io; pub mod lazy_box; diff --git a/library/std/src/thread/mod.rs b/library/std/src/thread/mod.rs index 83e27dfb746c2..c8ee365392f85 100644 --- a/library/std/src/thread/mod.rs +++ b/library/std/src/thread/mod.rs @@ -539,7 +539,7 @@ impl Builder { let f = f.into_inner(); set_current(their_thread); let try_result = panic::catch_unwind(panic::AssertUnwindSafe(|| { - crate::sys_common::backtrace::__rust_begin_short_backtrace(f) + crate::sys::backtrace::__rust_begin_short_backtrace(f) })); // SAFETY: `their_packet` as been built just above and moved by the // closure (it is an Arc<...>) and `my_packet` will be stored in the diff --git a/src/bootstrap/Cargo.lock b/src/bootstrap/Cargo.lock index 127699b86411f..9c24742cff1fc 100644 --- a/src/bootstrap/Cargo.lock +++ b/src/bootstrap/Cargo.lock @@ -17,12 +17,6 @@ version = "1.0.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "7079075b41f533b8c61d2a4d073c4676e1f8b249ff94a393b0595db304e0dd87" -[[package]] -name = "autocfg" -version = "1.1.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d468802bab17cbc0cc575e9b053f41e72aa36bfa6b7f55e3529ffa43161b97fa" - [[package]] name = "bitflags" version = "1.3.2" @@ -181,34 +175,28 @@ dependencies = [ [[package]] name = "crossbeam-deque" -version = "0.8.4" +version = "0.8.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fca89a0e215bab21874660c67903c5f143333cab1da83d041c7ded6053774751" +checksum = "613f8cc01fe9cf1a3eb3d7f488fd2fa8388403e97039e2f73692932e291a770d" dependencies = [ - "cfg-if", "crossbeam-epoch", "crossbeam-utils", ] [[package]] name = "crossbeam-epoch" -version = "0.9.17" +version = "0.9.18" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0e3681d554572a651dda4186cd47240627c3d0114d45a95f6ad27f2f22e7548d" +checksum = "5b82ac4a3c2ca9c3460964f020e1402edd5753411d7737aa39c3714ad1b5420e" dependencies = [ - "autocfg", - "cfg-if", "crossbeam-utils", ] [[package]] name = "crossbeam-utils" -version = "0.8.18" +version = "0.8.20" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c3a430a770ebd84726f584a90ee7f020d28db52c6d02138900f22341f866d39c" -dependencies = [ - "cfg-if", -] +checksum = "22ec99545bb0ed0ea7bb9b8e1e9122ea386ff8a48c0922e43f36d45ab09e0e80" [[package]] name = "crypto-common" @@ -331,12 +319,12 @@ checksum = "b1a46d1a171d865aa5f83f92695765caa047a9b4cbae2cbf37dbd613a793fd4c" [[package]] name = "junction" -version = "1.0.0" +version = "1.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ca39ef0d69b18e6a2fd14c2f0a1d593200f4a4ed949b240b5917ab51fac754cb" +checksum = "1c9c415a9b7b1e86cd5738f39d34c9e78c765da7fb1756dbd7d31b3b0d2e7afa" dependencies = [ "scopeguard", - "winapi", + "windows-sys", ] [[package]] diff --git a/src/bootstrap/defaults/config.compiler.toml b/src/bootstrap/defaults/config.compiler.toml index fd2da24699086..789586b58f706 100644 --- a/src/bootstrap/defaults/config.compiler.toml +++ b/src/bootstrap/defaults/config.compiler.toml @@ -19,8 +19,6 @@ lto = "off" # Forces frame pointers to be used with `-Cforce-frame-pointers`. # This can be helpful for profiling at a small performance cost. frame-pointers = true -# Build the llvm-bitcode-linker as it is required for running nvptx tests -llvm-bitcode-linker = true [llvm] # Having this set to true disrupts compiler development workflows for people who use `llvm.download-ci-llvm = true` diff --git a/src/bootstrap/defaults/config.dist.toml b/src/bootstrap/defaults/config.dist.toml index f3c6ffc9bd510..d06930f2b9d9b 100644 --- a/src/bootstrap/defaults/config.dist.toml +++ b/src/bootstrap/defaults/config.dist.toml @@ -16,7 +16,7 @@ download-ci-llvm = false # Make sure they don't get set when installing from source. channel = "nightly" download-rustc = false -# Build the llvm-bitcode-linker as it is required for running nvptx tests +# Build the llvm-bitcode-linker llvm-bitcode-linker = true [dist] diff --git a/src/bootstrap/defaults/config.library.toml b/src/bootstrap/defaults/config.library.toml index 4a1a49b727522..087544397f5ea 100644 --- a/src/bootstrap/defaults/config.library.toml +++ b/src/bootstrap/defaults/config.library.toml @@ -10,8 +10,6 @@ bench-stage = 0 incremental = true # Make the compiler and standard library faster to build, at the expense of a ~20% runtime slowdown. lto = "off" -# Build the llvm-bitcode-linker as it is required for running nvptx tests -llvm-bitcode-linker = true [llvm] # Will download LLVM from CI if available on your platform. diff --git a/src/bootstrap/defaults/config.tools.toml b/src/bootstrap/defaults/config.tools.toml index 94c8b724cbf8c..6e6c366002792 100644 --- a/src/bootstrap/defaults/config.tools.toml +++ b/src/bootstrap/defaults/config.tools.toml @@ -12,8 +12,6 @@ incremental = true # Using these defaults will download the stage2 compiler (see `download-rustc` # setting) and the stage2 toolchain should therefore be used for these defaults. download-rustc = "if-unchanged" -# Build the llvm-bitcode-linker as it is required for running nvptx tests -llvm-bitcode-linker = true [build] # Document with the in-tree rustdoc by default, since `download-rustc` makes it quick to compile. diff --git a/src/bootstrap/src/core/build_steps/format.rs b/src/bootstrap/src/core/build_steps/format.rs index 2deb9168df2ab..f5e346726868a 100644 --- a/src/bootstrap/src/core/build_steps/format.rs +++ b/src/bootstrap/src/core/build_steps/format.rs @@ -1,7 +1,7 @@ //! Runs rustfmt on the repository. use crate::core::builder::Builder; -use crate::utils::helpers::{output, program_out_of_date, t}; +use crate::utils::helpers::{self, output, program_out_of_date, t}; use build_helper::ci::CiEnv; use build_helper::git::get_git_modified_files; use ignore::WalkBuilder; @@ -93,7 +93,7 @@ fn get_modified_rs_files(build: &Builder<'_>) -> Result>, Str return Ok(None); } - get_git_modified_files(&build.config.git_config(), Some(&build.config.src), &vec!["rs"]) + get_git_modified_files(&build.config.git_config(), Some(&build.config.src), &["rs"]) } #[derive(serde_derive::Deserialize)] @@ -160,7 +160,7 @@ pub fn format(build: &Builder<'_>, check: bool, all: bool, paths: &[PathBuf]) { override_builder.add(&format!("!{ignore}")).expect(&ignore); } } - let git_available = match Command::new("git") + let git_available = match helpers::git(None) .arg("--version") .stdout(Stdio::null()) .stderr(Stdio::null()) @@ -172,9 +172,7 @@ pub fn format(build: &Builder<'_>, check: bool, all: bool, paths: &[PathBuf]) { let mut adjective = None; if git_available { - let in_working_tree = match build - .config - .git() + let in_working_tree = match helpers::git(Some(&build.src)) .arg("rev-parse") .arg("--is-inside-work-tree") .stdout(Stdio::null()) @@ -186,9 +184,7 @@ pub fn format(build: &Builder<'_>, check: bool, all: bool, paths: &[PathBuf]) { }; if in_working_tree { let untracked_paths_output = output( - build - .config - .git() + helpers::git(Some(&build.src)) .arg("status") .arg("--porcelain") .arg("-z") diff --git a/src/bootstrap/src/core/build_steps/llvm.rs b/src/bootstrap/src/core/build_steps/llvm.rs index ebac27cd92c27..f90403d2ec455 100644 --- a/src/bootstrap/src/core/build_steps/llvm.rs +++ b/src/bootstrap/src/core/build_steps/llvm.rs @@ -159,7 +159,7 @@ pub(crate) fn detect_llvm_sha(config: &Config, is_git: bool) -> String { // in that case. let closest_upstream = get_git_merge_base(&config.git_config(), Some(&config.src)) .unwrap_or_else(|_| "HEAD".into()); - let mut rev_list = config.git(); + let mut rev_list = helpers::git(Some(&config.src)); rev_list.args(&[ PathBuf::from("rev-list"), format!("--author={}", config.stage0_metadata.config.git_merge_commit_email).into(), @@ -252,7 +252,7 @@ pub(crate) fn is_ci_llvm_modified(config: &Config) -> bool { // We assume we have access to git, so it's okay to unconditionally pass // `true` here. let llvm_sha = detect_llvm_sha(config, true); - let head_sha = output(config.git().arg("rev-parse").arg("HEAD")); + let head_sha = output(helpers::git(Some(&config.src)).arg("rev-parse").arg("HEAD")); let head_sha = head_sha.trim(); llvm_sha == head_sha } diff --git a/src/bootstrap/src/core/build_steps/run.rs b/src/bootstrap/src/core/build_steps/run.rs index 354eb2b600381..9268b335db7c2 100644 --- a/src/bootstrap/src/core/build_steps/run.rs +++ b/src/bootstrap/src/core/build_steps/run.rs @@ -149,12 +149,14 @@ impl Step for Miri { &[], ); miri.add_rustc_lib_path(builder); - // Forward arguments. miri.arg("--").arg("--target").arg(target.rustc_target_arg()); - miri.args(builder.config.args()); // miri tests need to know about the stage sysroot - miri.env("MIRI_SYSROOT", &miri_sysroot); + miri.arg("--sysroot").arg(miri_sysroot); + + // Forward arguments. This may contain further arguments to the program + // after another --, so this must be at the end. + miri.args(builder.config.args()); let mut miri = Command::from(miri); builder.run(&mut miri); diff --git a/src/bootstrap/src/core/build_steps/setup.rs b/src/bootstrap/src/core/build_steps/setup.rs index df38d6166eb85..947c74f32c99e 100644 --- a/src/bootstrap/src/core/build_steps/setup.rs +++ b/src/bootstrap/src/core/build_steps/setup.rs @@ -8,7 +8,7 @@ use crate::core::builder::{Builder, RunConfig, ShouldRun, Step}; use crate::t; use crate::utils::change_tracker::CONFIG_CHANGE_HISTORY; -use crate::utils::helpers::hex_encode; +use crate::utils::helpers::{self, hex_encode}; use crate::Config; use sha2::Digest; use std::env::consts::EXE_SUFFIX; @@ -482,10 +482,13 @@ impl Step for Hook { // install a git hook to automatically run tidy, if they want fn install_git_hook_maybe(config: &Config) -> io::Result<()> { - let git = config.git().args(["rev-parse", "--git-common-dir"]).output().map(|output| { - assert!(output.status.success(), "failed to run `git`"); - PathBuf::from(t!(String::from_utf8(output.stdout)).trim()) - })?; + let git = helpers::git(Some(&config.src)) + .args(["rev-parse", "--git-common-dir"]) + .output() + .map(|output| { + assert!(output.status.success(), "failed to run `git`"); + PathBuf::from(t!(String::from_utf8(output.stdout)).trim()) + })?; let hooks_dir = git.join("hooks"); let dst = hooks_dir.join("pre-push"); if dst.exists() { diff --git a/src/bootstrap/src/core/build_steps/tool.rs b/src/bootstrap/src/core/build_steps/tool.rs index 6cf31f2e61e1c..e0a9674ae5a90 100644 --- a/src/bootstrap/src/core/build_steps/tool.rs +++ b/src/bootstrap/src/core/build_steps/tool.rs @@ -823,19 +823,29 @@ impl Step for LibcxxVersionTool { fn run(self, builder: &Builder<'_>) -> LibcxxVersion { let out_dir = builder.out.join(self.target.to_string()).join("libcxx-version"); - let _ = fs::remove_dir_all(&out_dir); - t!(fs::create_dir_all(&out_dir)); + let executable = out_dir.join(exe("libcxx-version", self.target)); - let compiler = builder.cxx(self.target).unwrap(); - let mut cmd = Command::new(compiler); + // This is a sanity-check specific step, which means it is frequently called (when using + // CI LLVM), and compiling `src/tools/libcxx-version/main.cpp` at the beginning of the bootstrap + // invocation adds a fair amount of overhead to the process (see https://github.com/rust-lang/rust/issues/126423). + // Therefore, we want to avoid recompiling this file unnecessarily. + if !executable.exists() { + if !out_dir.exists() { + t!(fs::create_dir_all(&out_dir)); + } - let executable = out_dir.join(exe("libcxx-version", self.target)); - cmd.arg("-o").arg(&executable).arg(builder.src.join("src/tools/libcxx-version/main.cpp")); + let compiler = builder.cxx(self.target).unwrap(); + let mut cmd = Command::new(compiler); - builder.run_cmd(&mut cmd); + cmd.arg("-o") + .arg(&executable) + .arg(builder.src.join("src/tools/libcxx-version/main.cpp")); - if !executable.exists() { - panic!("Something went wrong. {} is not present", executable.display()); + builder.run_cmd(&mut cmd); + + if !executable.exists() { + panic!("Something went wrong. {} is not present", executable.display()); + } } let version_output = output(&mut Command::new(executable)); diff --git a/src/bootstrap/src/core/build_steps/toolstate.rs b/src/bootstrap/src/core/build_steps/toolstate.rs index ca3756df4d779..9e6d03349b5fb 100644 --- a/src/bootstrap/src/core/build_steps/toolstate.rs +++ b/src/bootstrap/src/core/build_steps/toolstate.rs @@ -5,7 +5,7 @@ //! [Toolstate]: https://forge.rust-lang.org/infra/toolstate.html use crate::core::builder::{Builder, RunConfig, ShouldRun, Step}; -use crate::utils::helpers::t; +use crate::utils::helpers::{self, t}; use serde_derive::{Deserialize, Serialize}; use std::collections::HashMap; use std::env; @@ -13,7 +13,6 @@ use std::fmt; use std::fs; use std::io::{Seek, SeekFrom}; use std::path::{Path, PathBuf}; -use std::process::Command; use std::time; // Each cycle is 42 days long (6 weeks); the last week is 35..=42 then. @@ -102,12 +101,8 @@ fn print_error(tool: &str, submodule: &str) { fn check_changed_files(toolstates: &HashMap, ToolState>) { // Changed files - let output = std::process::Command::new("git") - .arg("diff") - .arg("--name-status") - .arg("HEAD") - .arg("HEAD^") - .output(); + let output = + helpers::git(None).arg("diff").arg("--name-status").arg("HEAD").arg("HEAD^").output(); let output = match output { Ok(o) => o, Err(e) => { @@ -324,7 +319,7 @@ fn checkout_toolstate_repo() { t!(fs::remove_dir_all(TOOLSTATE_DIR)); } - let status = Command::new("git") + let status = helpers::git(None) .arg("clone") .arg("--depth=1") .arg(toolstate_repo()) @@ -342,7 +337,7 @@ fn checkout_toolstate_repo() { /// Sets up config and authentication for modifying the toolstate repo. fn prepare_toolstate_config(token: &str) { fn git_config(key: &str, value: &str) { - let status = Command::new("git").arg("config").arg("--global").arg(key).arg(value).status(); + let status = helpers::git(None).arg("config").arg("--global").arg(key).arg(value).status(); let success = match status { Ok(s) => s.success(), Err(_) => false, @@ -406,8 +401,7 @@ fn commit_toolstate_change(current_toolstate: &ToolstateData) { publish_test_results(current_toolstate); // `git commit` failing means nothing to commit. - let status = t!(Command::new("git") - .current_dir(TOOLSTATE_DIR) + let status = t!(helpers::git(Some(Path::new(TOOLSTATE_DIR))) .arg("commit") .arg("-a") .arg("-m") @@ -418,8 +412,7 @@ fn commit_toolstate_change(current_toolstate: &ToolstateData) { break; } - let status = t!(Command::new("git") - .current_dir(TOOLSTATE_DIR) + let status = t!(helpers::git(Some(Path::new(TOOLSTATE_DIR))) .arg("push") .arg("origin") .arg("master") @@ -431,15 +424,13 @@ fn commit_toolstate_change(current_toolstate: &ToolstateData) { } eprintln!("Sleeping for 3 seconds before retrying push"); std::thread::sleep(std::time::Duration::from_secs(3)); - let status = t!(Command::new("git") - .current_dir(TOOLSTATE_DIR) + let status = t!(helpers::git(Some(Path::new(TOOLSTATE_DIR))) .arg("fetch") .arg("origin") .arg("master") .status()); assert!(status.success()); - let status = t!(Command::new("git") - .current_dir(TOOLSTATE_DIR) + let status = t!(helpers::git(Some(Path::new(TOOLSTATE_DIR))) .arg("reset") .arg("--hard") .arg("origin/master") @@ -458,7 +449,7 @@ fn commit_toolstate_change(current_toolstate: &ToolstateData) { /// `publish_toolstate.py` script if the PR passes all tests and is merged to /// master. fn publish_test_results(current_toolstate: &ToolstateData) { - let commit = t!(std::process::Command::new("git").arg("rev-parse").arg("HEAD").output()); + let commit = t!(helpers::git(None).arg("rev-parse").arg("HEAD").output()); let commit = t!(String::from_utf8(commit.stdout)); let toolstate_serialized = t!(serde_json::to_string(¤t_toolstate)); diff --git a/src/bootstrap/src/core/config/config.rs b/src/bootstrap/src/core/config/config.rs index 36b44d0169c9c..a1d8ca3cbcaa7 100644 --- a/src/bootstrap/src/core/config/config.rs +++ b/src/bootstrap/src/core/config/config.rs @@ -10,7 +10,7 @@ use std::env; use std::fmt::{self, Display}; use std::fs; use std::io::IsTerminal; -use std::path::{Path, PathBuf}; +use std::path::{absolute, Path, PathBuf}; use std::process::Command; use std::str::FromStr; use std::sync::OnceLock; @@ -20,7 +20,7 @@ use crate::core::build_steps::llvm; use crate::core::config::flags::{Color, Flags, Warnings}; use crate::utils::cache::{Interned, INTERNER}; use crate::utils::channel::{self, GitInfo}; -use crate::utils::helpers::{exe, output, t}; +use crate::utils::helpers::{self, exe, output, t}; use build_helper::exit; use serde::{Deserialize, Deserializer}; use serde_derive::Deserialize; @@ -1248,7 +1248,7 @@ impl Config { // Infer the source directory. This is non-trivial because we want to support a downloaded bootstrap binary, // running on a completely different machine from where it was compiled. - let mut cmd = Command::new("git"); + let mut cmd = helpers::git(None); // NOTE: we cannot support running from outside the repository because the only other path we have available // is set at compile time, which can be wrong if bootstrap was downloaded rather than compiled locally. // We still support running outside the repository if we find we aren't in a git directory. @@ -1437,7 +1437,7 @@ impl Config { // To avoid writing to random places on the file system, `config.out` needs to be an absolute path. if !config.out.is_absolute() { // `canonicalize` requires the path to already exist. Use our vendored copy of `absolute` instead. - config.out = crate::utils::helpers::absolute(&config.out); + config.out = absolute(&config.out).expect("can't make empty path absolute"); } config.initial_rustc = if let Some(rustc) = rustc { @@ -2090,15 +2090,6 @@ impl Config { build_helper::util::try_run(cmd, self.is_verbose()) } - /// A git invocation which runs inside the source directory. - /// - /// Use this rather than `Command::new("git")` in order to support out-of-tree builds. - pub(crate) fn git(&self) -> Command { - let mut git = Command::new("git"); - git.current_dir(&self.src); - git - } - pub(crate) fn test_args(&self) -> Vec<&str> { let mut test_args = match self.cmd { Subcommand::Test { ref test_args, .. } @@ -2130,7 +2121,7 @@ impl Config { "`Config::read_file_by_commit` is not supported in non-git sources." ); - let mut git = self.git(); + let mut git = helpers::git(Some(&self.src)); git.arg("show").arg(format!("{commit}:{}", file.to_str().unwrap())); output(&mut git) } @@ -2436,7 +2427,8 @@ impl Config { }; // Handle running from a directory other than the top level - let top_level = output(self.git().args(["rev-parse", "--show-toplevel"])); + let top_level = + output(helpers::git(Some(&self.src)).args(["rev-parse", "--show-toplevel"])); let top_level = top_level.trim_end(); let compiler = format!("{top_level}/compiler/"); let library = format!("{top_level}/library/"); @@ -2444,7 +2436,7 @@ impl Config { // Look for a version to compare to based on the current commit. // Only commits merged by bors will have CI artifacts. let merge_base = output( - self.git() + helpers::git(Some(&self.src)) .arg("rev-list") .arg(format!("--author={}", self.stage0_metadata.config.git_merge_commit_email)) .args(["-n1", "--first-parent", "HEAD"]), @@ -2459,8 +2451,7 @@ impl Config { } // Warn if there were changes to the compiler or standard library since the ancestor commit. - let has_changes = !t!(self - .git() + let has_changes = !t!(helpers::git(Some(&self.src)) .args(["diff-index", "--quiet", commit, "--", &compiler, &library]) .status()) .success(); @@ -2533,13 +2524,14 @@ impl Config { if_unchanged: bool, ) -> Option { // Handle running from a directory other than the top level - let top_level = output(self.git().args(["rev-parse", "--show-toplevel"])); + let top_level = + output(helpers::git(Some(&self.src)).args(["rev-parse", "--show-toplevel"])); let top_level = top_level.trim_end(); // Look for a version to compare to based on the current commit. // Only commits merged by bors will have CI artifacts. let merge_base = output( - self.git() + helpers::git(Some(&self.src)) .arg("rev-list") .arg(format!("--author={}", self.stage0_metadata.config.git_merge_commit_email)) .args(["-n1", "--first-parent", "HEAD"]), @@ -2554,7 +2546,7 @@ impl Config { } // Warn if there were changes to the compiler or standard library since the ancestor commit. - let mut git = self.git(); + let mut git = helpers::git(Some(&self.src)); git.args(["diff-index", "--quiet", commit, "--"]); for path in modified_paths { diff --git a/src/bootstrap/src/core/sanity.rs b/src/bootstrap/src/core/sanity.rs index b5f17b9f54edc..5a0be2948a19e 100644 --- a/src/bootstrap/src/core/sanity.rs +++ b/src/bootstrap/src/core/sanity.rs @@ -128,6 +128,9 @@ pub fn check(build: &mut Build) { eprintln!( "Consider upgrading libstdc++ or disabling the `llvm.download-ci-llvm` option." ); + eprintln!( + "If you choose to upgrade libstdc++, run `x clean` or delete `build/host/libcxx-version` manually after the upgrade." + ); } } tool::LibcxxVersion::Llvm(_) => { @@ -137,19 +140,20 @@ pub fn check(build: &mut Build) { } // We need cmake, but only if we're actually building LLVM or sanitizers. - let building_llvm = build - .hosts - .iter() - .map(|host| { - build.config.llvm_enabled(*host) - && build - .config - .target_config - .get(host) - .map(|config| config.llvm_config.is_none()) - .unwrap_or(true) - }) - .any(|build_llvm_ourselves| build_llvm_ourselves); + let building_llvm = !build.config.llvm_from_ci + && build + .hosts + .iter() + .map(|host| { + build.config.llvm_enabled(*host) + && build + .config + .target_config + .get(host) + .map(|config| config.llvm_config.is_none()) + .unwrap_or(true) + }) + .any(|build_llvm_ourselves| build_llvm_ourselves); let need_cmake = building_llvm || build.config.any_sanitizers_to_build(); if need_cmake && cmd_finder.maybe_have("cmake").is_none() { diff --git a/src/bootstrap/src/lib.rs b/src/bootstrap/src/lib.rs index 1cab02e8c31b7..abf407ea91e6e 100644 --- a/src/bootstrap/src/lib.rs +++ b/src/bootstrap/src/lib.rs @@ -522,14 +522,10 @@ impl Build { // check_submodule let checked_out_hash = - output(Command::new("git").args(["rev-parse", "HEAD"]).current_dir(&absolute_path)); + output(helpers::git(Some(&absolute_path)).args(["rev-parse", "HEAD"])); // update_submodules - let recorded = output( - Command::new("git") - .args(["ls-tree", "HEAD"]) - .arg(relative_path) - .current_dir(&self.config.src), - ); + let recorded = + output(helpers::git(Some(&self.src)).args(["ls-tree", "HEAD"]).arg(relative_path)); let actual_hash = recorded .split_whitespace() .nth(2) @@ -543,10 +539,7 @@ impl Build { println!("Updating submodule {}", relative_path.display()); self.run( - Command::new("git") - .args(["submodule", "-q", "sync"]) - .arg(relative_path) - .current_dir(&self.config.src), + helpers::git(Some(&self.src)).args(["submodule", "-q", "sync"]).arg(relative_path), ); // Try passing `--progress` to start, then run git again without if that fails. @@ -554,9 +547,7 @@ impl Build { // Git is buggy and will try to fetch submodules from the tracking branch for *this* repository, // even though that has no relation to the upstream for the submodule. let current_branch = { - let output = self - .config - .git() + let output = helpers::git(Some(&self.src)) .args(["symbolic-ref", "--short", "HEAD"]) .stderr(Stdio::inherit()) .output(); @@ -568,7 +559,7 @@ impl Build { } }; - let mut git = self.config.git(); + let mut git = helpers::git(Some(&self.src)); if let Some(branch) = current_branch { // If there is a tag named after the current branch, git will try to disambiguate by prepending `heads/` to the branch name. // This syntax isn't accepted by `branch.{branch}`. Strip it. @@ -590,11 +581,11 @@ impl Build { // Save any local changes, but avoid running `git stash pop` if there are none (since it will exit with an error). // diff-index reports the modifications through the exit status let has_local_modifications = !self.run_cmd( - BootstrapCommand::from( - Command::new("git") - .args(["diff-index", "--quiet", "HEAD"]) - .current_dir(&absolute_path), - ) + BootstrapCommand::from(helpers::git(Some(&absolute_path)).args([ + "diff-index", + "--quiet", + "HEAD", + ])) .allow_failure() .output_mode(match self.is_verbose() { true => OutputMode::PrintAll, @@ -602,14 +593,14 @@ impl Build { }), ); if has_local_modifications { - self.run(Command::new("git").args(["stash", "push"]).current_dir(&absolute_path)); + self.run(helpers::git(Some(&absolute_path)).args(["stash", "push"])); } - self.run(Command::new("git").args(["reset", "-q", "--hard"]).current_dir(&absolute_path)); - self.run(Command::new("git").args(["clean", "-qdfx"]).current_dir(&absolute_path)); + self.run(helpers::git(Some(&absolute_path)).args(["reset", "-q", "--hard"])); + self.run(helpers::git(Some(&absolute_path)).args(["clean", "-qdfx"])); if has_local_modifications { - self.run(Command::new("git").args(["stash", "pop"]).current_dir(absolute_path)); + self.run(helpers::git(Some(&absolute_path)).args(["stash", "pop"])); } } @@ -621,8 +612,7 @@ impl Build { return; } let output = output( - self.config - .git() + helpers::git(Some(&self.src)) .args(["config", "--file"]) .arg(self.config.src.join(".gitmodules")) .args(["--get-regexp", "path"]), @@ -1563,10 +1553,14 @@ impl Build { // Figure out how many merge commits happened since we branched off master. // That's our beta number! // (Note that we use a `..` range, not the `...` symmetric difference.) - output(self.config.git().arg("rev-list").arg("--count").arg("--merges").arg(format!( - "refs/remotes/origin/{}..HEAD", - self.config.stage0_metadata.config.nightly_branch - ))) + output( + helpers::git(Some(&self.src)).arg("rev-list").arg("--count").arg("--merges").arg( + format!( + "refs/remotes/origin/{}..HEAD", + self.config.stage0_metadata.config.nightly_branch + ), + ), + ) }); let n = count.trim().parse().unwrap(); self.prerelease_version.set(Some(n)); @@ -1984,15 +1978,13 @@ fn envify(s: &str) -> String { /// In case of errors during `git` command execution (e.g., in tarball sources), default values /// are used to prevent panics. pub fn generate_smart_stamp_hash(dir: &Path, additional_input: &str) -> String { - let diff = Command::new("git") - .current_dir(dir) + let diff = helpers::git(Some(dir)) .arg("diff") .output() .map(|o| String::from_utf8(o.stdout).unwrap_or_default()) .unwrap_or_default(); - let status = Command::new("git") - .current_dir(dir) + let status = helpers::git(Some(dir)) .arg("status") .arg("--porcelain") .arg("-z") diff --git a/src/bootstrap/src/utils/channel.rs b/src/bootstrap/src/utils/channel.rs index 88988c3391617..ce82c52f049e2 100644 --- a/src/bootstrap/src/utils/channel.rs +++ b/src/bootstrap/src/utils/channel.rs @@ -7,11 +7,12 @@ use std::fs; use std::path::Path; -use std::process::Command; use crate::utils::helpers::{output, t}; use crate::Build; +use super::helpers; + #[derive(Clone, Default)] pub enum GitInfo { /// This is not a git repository. @@ -44,7 +45,7 @@ impl GitInfo { } // Make sure git commands work - match Command::new("git").arg("rev-parse").current_dir(dir).output() { + match helpers::git(Some(dir)).arg("rev-parse").output() { Ok(ref out) if out.status.success() => {} _ => return GitInfo::Absent, } @@ -57,17 +58,15 @@ impl GitInfo { // Ok, let's scrape some info let ver_date = output( - Command::new("git") - .current_dir(dir) + helpers::git(Some(dir)) .arg("log") .arg("-1") .arg("--date=short") .arg("--pretty=format:%cd"), ); - let ver_hash = output(Command::new("git").current_dir(dir).arg("rev-parse").arg("HEAD")); - let short_ver_hash = output( - Command::new("git").current_dir(dir).arg("rev-parse").arg("--short=9").arg("HEAD"), - ); + let ver_hash = output(helpers::git(Some(dir)).arg("rev-parse").arg("HEAD")); + let short_ver_hash = + output(helpers::git(Some(dir)).arg("rev-parse").arg("--short=9").arg("HEAD")); GitInfo::Present(Some(Info { commit_date: ver_date.trim().to_string(), sha: ver_hash.trim().to_string(), diff --git a/src/bootstrap/src/utils/helpers.rs b/src/bootstrap/src/utils/helpers.rs index 278359cb08e39..13d1346b3d9a6 100644 --- a/src/bootstrap/src/utils/helpers.rs +++ b/src/bootstrap/src/utils/helpers.rs @@ -331,115 +331,6 @@ fn dir_up_to_date(src: &Path, threshold: SystemTime) -> bool { }) } -/// Copied from `std::path::absolute` until it stabilizes. -/// -/// FIXME: this shouldn't exist. -pub(crate) fn absolute(path: &Path) -> PathBuf { - if path.as_os_str().is_empty() { - panic!("can't make empty path absolute"); - } - #[cfg(unix)] - { - t!(absolute_unix(path), format!("could not make path absolute: {}", path.display())) - } - #[cfg(windows)] - { - t!(absolute_windows(path), format!("could not make path absolute: {}", path.display())) - } - #[cfg(not(any(unix, windows)))] - { - println!("WARNING: bootstrap is not supported on non-unix platforms"); - t!(std::fs::canonicalize(t!(std::env::current_dir()))).join(path) - } -} - -#[cfg(unix)] -/// Make a POSIX path absolute without changing its semantics. -fn absolute_unix(path: &Path) -> io::Result { - // This is mostly a wrapper around collecting `Path::components`, with - // exceptions made where this conflicts with the POSIX specification. - // See 4.13 Pathname Resolution, IEEE Std 1003.1-2017 - // https://pubs.opengroup.org/onlinepubs/9699919799/basedefs/V1_chap04.html#tag_04_13 - - use std::os::unix::prelude::OsStrExt; - let mut components = path.components(); - let path_os = path.as_os_str().as_bytes(); - - let mut normalized = if path.is_absolute() { - // "If a pathname begins with two successive characters, the - // first component following the leading characters may be - // interpreted in an implementation-defined manner, although more than - // two leading characters shall be treated as a single - // character." - if path_os.starts_with(b"//") && !path_os.starts_with(b"///") { - components.next(); - PathBuf::from("//") - } else { - PathBuf::new() - } - } else { - env::current_dir()? - }; - normalized.extend(components); - - // "Interfaces using pathname resolution may specify additional constraints - // when a pathname that does not name an existing directory contains at - // least one non- character and contains one or more trailing - // characters". - // A trailing is also meaningful if "a symbolic link is - // encountered during pathname resolution". - - if path_os.ends_with(b"/") { - normalized.push(""); - } - - Ok(normalized) -} - -#[cfg(windows)] -fn absolute_windows(path: &std::path::Path) -> std::io::Result { - use std::ffi::OsString; - use std::io::Error; - use std::os::windows::ffi::{OsStrExt, OsStringExt}; - use std::ptr::null_mut; - #[link(name = "kernel32")] - extern "system" { - fn GetFullPathNameW( - lpFileName: *const u16, - nBufferLength: u32, - lpBuffer: *mut u16, - lpFilePart: *mut *const u16, - ) -> u32; - } - - unsafe { - // encode the path as UTF-16 - let path: Vec = path.as_os_str().encode_wide().chain([0]).collect(); - let mut buffer = Vec::new(); - // Loop until either success or failure. - loop { - // Try to get the absolute path - let len = GetFullPathNameW( - path.as_ptr(), - buffer.len().try_into().unwrap(), - buffer.as_mut_ptr(), - null_mut(), - ); - match len as usize { - // Failure - 0 => return Err(Error::last_os_error()), - // Buffer is too small, resize. - len if len > buffer.len() => buffer.resize(len, 0), - // Success! - len => { - buffer.truncate(len); - return Ok(OsString::from_wide(&buffer).into()); - } - } - } - } -} - /// Adapted from /// /// When `clang-cl` is used with instrumentation, we need to add clang's runtime library resource @@ -598,3 +489,19 @@ pub fn check_cfg_arg(name: &str, values: Option<&[&str]>) -> String { }; format!("--check-cfg=cfg({name}{next})") } + +/// Prepares `Command` that runs git inside the source directory if given. +/// +/// Whenever a git invocation is needed, this function should be preferred over +/// manually building a git `Command`. This approach allows us to manage bootstrap-specific +/// needs/hacks from a single source, rather than applying them on next to every `Command::new("git")`, +/// which is painful to ensure that the required change is applied on each one of them correctly. +pub fn git(source_dir: Option<&Path>) -> Command { + let mut git = Command::new("git"); + + if let Some(source_dir) = source_dir { + git.current_dir(source_dir); + } + + git +} diff --git a/src/bootstrap/src/utils/helpers/tests.rs b/src/bootstrap/src/utils/helpers/tests.rs index 9cfaa3eb67b5c..2ab3952ae5a1d 100644 --- a/src/bootstrap/src/utils/helpers/tests.rs +++ b/src/bootstrap/src/utils/helpers/tests.rs @@ -25,27 +25,6 @@ fn test_make() { } } -#[cfg(unix)] -#[test] -fn test_absolute_unix() { - use crate::utils::helpers::absolute_unix; - - // Test an absolute path - let path = PathBuf::from("/home/user/file.txt"); - assert_eq!(absolute_unix(&path).unwrap(), PathBuf::from("/home/user/file.txt")); - - // Test an absolute path with double leading slashes - let path = PathBuf::from("//root//file.txt"); - assert_eq!(absolute_unix(&path).unwrap(), PathBuf::from("//root/file.txt")); - - // Test a relative path - let path = PathBuf::from("relative/path"); - assert_eq!( - absolute_unix(&path).unwrap(), - std::env::current_dir().unwrap().join("relative/path") - ); -} - #[test] fn test_beta_rev_parsing() { // single digit revision diff --git a/src/ci/docker/host-x86_64/dist-i686-linux/Dockerfile b/src/ci/docker/host-x86_64/dist-i686-linux/Dockerfile index 1704bef1e4ed0..414bcc52484c9 100644 --- a/src/ci/docker/host-x86_64/dist-i686-linux/Dockerfile +++ b/src/ci/docker/host-x86_64/dist-i686-linux/Dockerfile @@ -6,8 +6,12 @@ FROM centos:7 WORKDIR /build +# CentOS 7 EOL is June 30, 2024, but the repos remain in the vault. +RUN sed -i /etc/yum.repos.d/*.repo -e 's!^mirrorlist!#mirrorlist!' \ + -e 's!^#baseurl=http://mirror.centos.org/!baseurl=https://vault.centos.org/!' +RUN sed -i 's/enabled=1/enabled=0/' /etc/yum/pluginconf.d/fastestmirror.conf + RUN yum upgrade -y && \ - yum install -y epel-release && \ yum install -y \ automake \ bzip2 \ diff --git a/src/ci/docker/host-x86_64/dist-x86_64-linux/Dockerfile b/src/ci/docker/host-x86_64/dist-x86_64-linux/Dockerfile index 4e1aae9822135..4aa1a3ccc2a5d 100644 --- a/src/ci/docker/host-x86_64/dist-x86_64-linux/Dockerfile +++ b/src/ci/docker/host-x86_64/dist-x86_64-linux/Dockerfile @@ -6,8 +6,12 @@ FROM centos:7 WORKDIR /build +# CentOS 7 EOL is June 30, 2024, but the repos remain in the vault. +RUN sed -i /etc/yum.repos.d/*.repo -e 's!^mirrorlist!#mirrorlist!' \ + -e 's!^#baseurl=http://mirror.centos.org/!baseurl=https://vault.centos.org/!' +RUN sed -i 's/enabled=1/enabled=0/' /etc/yum/pluginconf.d/fastestmirror.conf + RUN yum upgrade -y && \ - yum install -y epel-release && \ yum install -y \ automake \ bzip2 \ diff --git a/src/ci/docker/host-x86_64/x86_64-gnu-integration/Dockerfile b/src/ci/docker/host-x86_64/x86_64-gnu-integration/Dockerfile index d228dfc87ebe2..a944f370c6b30 100644 --- a/src/ci/docker/host-x86_64/x86_64-gnu-integration/Dockerfile +++ b/src/ci/docker/host-x86_64/x86_64-gnu-integration/Dockerfile @@ -26,27 +26,27 @@ RUN apt-get update && apt-get install -y --no-install-recommends \ # Duplicated in dist-various-2 Dockerfile. # FIXME: Move to canonical triple ENV \ - AR_x86_64_fuchsia=x86_64-unknown-fuchsia-ar \ - CC_x86_64_fuchsia=x86_64-unknown-fuchsia-clang \ - CFLAGS_x86_64_fuchsia="--target=x86_64-unknown-fuchsia --sysroot=/usr/local/core-linux-amd64-fuchsia-sdk/arch/x64/sysroot -I/usr/local/core-linux-amd64-fuchsia-sdk/pkg/fdio/include" \ - CXX_x86_64_fuchsia=x86_64-unknown-fuchsia-clang++ \ - CXXFLAGS_x86_64_fuchsia="--target=x86_64-unknown-fuchsia --sysroot=/usr/local/core-linux-amd64-fuchsia-sdk/arch/x64/sysroot -I/usr/local/core-linux-amd64-fuchsia-sdk/pkg/fdio/include" \ - LDFLAGS_x86_64_fuchsia="--target=x86_64-unknown-fuchsia --sysroot=/usr/local/core-linux-amd64-fuchsia-sdk/arch/x64/sysroot -L/usr/local/core-linux-amd64-fuchsia-sdk/arch/x64/lib" + AR_x86_64_unknown_fuchsia=x86_64-unknown-fuchsia-ar \ + CC_x86_64_unknown_fuchsia=x86_64-unknown-fuchsia-clang \ + CFLAGS_x86_64_unknown_fuchsia="--target=x86_64-unknown-fuchsia --sysroot=/usr/local/core-linux-amd64-fuchsia-sdk/arch/x64/sysroot -I/usr/local/core-linux-amd64-fuchsia-sdk/pkg/fdio/include" \ + CXX_x86_64_unknown_fuchsia=x86_64-unknown-fuchsia-clang++ \ + CXXFLAGS_x86_64_unknown_fuchsia="--target=x86_64-unknown-fuchsia --sysroot=/usr/local/core-linux-amd64-fuchsia-sdk/arch/x64/sysroot -I/usr/local/core-linux-amd64-fuchsia-sdk/pkg/fdio/include" \ + LDFLAGS_x86_64_unknown_fuchsia="--target=x86_64-unknown-fuchsia --sysroot=/usr/local/core-linux-amd64-fuchsia-sdk/arch/x64/sysroot -L/usr/local/core-linux-amd64-fuchsia-sdk/arch/x64/lib" WORKDIR /tmp COPY scripts/shared.sh /tmp/ COPY scripts/build-fuchsia-toolchain.sh /tmp/ RUN /tmp/build-fuchsia-toolchain.sh -ENV CARGO_TARGET_X86_64_FUCHSIA_AR /usr/local/bin/llvm-ar -ENV CARGO_TARGET_X86_64_FUCHSIA_RUSTFLAGS \ +ENV CARGO_TARGET_X86_64_UNKNOWN_FUCHSIA_AR /usr/local/bin/llvm-ar +ENV CARGO_TARGET_X86_64_UNKNOWN_FUCHSIA_RUSTFLAGS \ -C panic=abort \ -C force-unwind-tables=yes \ -C link-arg=--sysroot=/usr/local/core-linux-amd64-fuchsia-sdk/arch/x64/sysroot \ -Lnative=/usr/local/core-linux-amd64-fuchsia-sdk/arch/x64/sysroot/lib \ -Lnative=/usr/local/core-linux-amd64-fuchsia-sdk/arch/x64/lib -ENV TARGETS=x86_64-fuchsia +ENV TARGETS=x86_64-unknown-fuchsia ENV TARGETS=$TARGETS,x86_64-unknown-linux-gnu ENV TARGETS=$TARGETS,wasm32-unknown-unknown @@ -69,11 +69,11 @@ ENV RUST_CONFIGURE_ARGS \ --llvm-libunwind=in-tree \ --enable-extended \ --disable-docs \ - --set target.x86_64-fuchsia.cc=/usr/local/bin/clang \ - --set target.x86_64-fuchsia.cxx=/usr/local/bin/clang++ \ - --set target.x86_64-fuchsia.ar=/usr/local/bin/llvm-ar \ - --set target.x86_64-fuchsia.ranlib=/usr/local/bin/llvm-ranlib \ - --set target.x86_64-fuchsia.linker=/usr/local/bin/ld.lld + --set target.x86_64-unknown-fuchsia.cc=/usr/local/bin/clang \ + --set target.x86_64-unknown-fuchsia.cxx=/usr/local/bin/clang++ \ + --set target.x86_64-unknown-fuchsia.ar=/usr/local/bin/llvm-ar \ + --set target.x86_64-unknown-fuchsia.ranlib=/usr/local/bin/llvm-ranlib \ + --set target.x86_64-unknown-fuchsia.linker=/usr/local/bin/ld.lld ENV SCRIPT \ python3 ../x.py install --target $TARGETS compiler/rustc library/std clippy && \ bash ../src/ci/docker/host-x86_64/x86_64-gnu-integration/build-fuchsia.sh diff --git a/src/ci/docker/host-x86_64/x86_64-gnu-integration/build-fuchsia.sh b/src/ci/docker/host-x86_64/x86_64-gnu-integration/build-fuchsia.sh index 913a0b0c09c35..2bb1d0a633871 100755 --- a/src/ci/docker/host-x86_64/x86_64-gnu-integration/build-fuchsia.sh +++ b/src/ci/docker/host-x86_64/x86_64-gnu-integration/build-fuchsia.sh @@ -35,7 +35,7 @@ PICK_REFS=() # commit hash of fuchsia.git and some other repos in the "monorepo" checkout, in # addition to versions of prebuilts. It should be bumped regularly by the # Fuchsia team – we aim for every 1-2 months. -INTEGRATION_SHA=1011e3298775ee7cdf6f6dc73e808d6a86e33bd6 +INTEGRATION_SHA=737ebdd83afa47b742ca8325fad0176952fcefbd checkout=fuchsia jiri=.jiri_root/bin/jiri diff --git a/src/ci/docker/scripts/build-fuchsia-toolchain.sh b/src/ci/docker/scripts/build-fuchsia-toolchain.sh index 7a0d4fcffc156..027d412d25066 100755 --- a/src/ci/docker/scripts/build-fuchsia-toolchain.sh +++ b/src/ci/docker/scripts/build-fuchsia-toolchain.sh @@ -4,13 +4,13 @@ set -ex source shared.sh FUCHSIA_SDK_URL=https://chrome-infra-packages.appspot.com/dl/fuchsia/sdk/core/linux-amd64 -FUCHSIA_SDK_ID=version:20.20240412.3.1 -FUCHSIA_SDK_SHA256=cc52f3497487dd813c89d9316e6967efcea89c7759edccf3e40fcf3662e53f19 +FUCHSIA_SDK_ID=version:21.20240610.2.1 +FUCHSIA_SDK_SHA256=2d2d057fc3f0404197cced2200f88cbcdaaf5fbf6475955045091f8676791ce7 FUCHSIA_SDK_USR_DIR=/usr/local/core-linux-amd64-fuchsia-sdk CLANG_DOWNLOAD_URL=\ https://chrome-infra-packages.appspot.com/dl/fuchsia/third_party/clang/linux-amd64 -CLANG_DOWNLOAD_ID=git_revision:c777c011a709dffd4fa5e79cad7947b7c3405d02 -CLANG_DOWNLOAD_SHA256=779167422ad73c292f049dcea5569f84577af9292189ed2749518b966a4d0844 +CLANG_DOWNLOAD_ID=git_revision:3809e20afc68d7d03821f0ec59b928dcf9befbf4 +CLANG_DOWNLOAD_SHA256=3c2c442b61cd9e8f1b567738f6d53cffe11b3fc820e7dae87a82a0859be8f204 install_clang() { mkdir -p clang_download diff --git a/src/ci/docker/scripts/fuchsia-test-runner.py b/src/ci/docker/scripts/fuchsia-test-runner.py index 4f504341d5266..d791550a8db87 100755 --- a/src/ci/docker/scripts/fuchsia-test-runner.py +++ b/src/ci/docker/scripts/fuchsia-test-runner.py @@ -286,7 +286,7 @@ def start(self): # Look up the product bundle transfer manifest. self.log_info("Looking up the product bundle transfer manifest...") product_name = "minimal." + self.triple_to_arch(self.target) - fuchsia_version = "20.20240412.3.1" + fuchsia_version = "21.20240610.2.1" out = self.check_output( [ diff --git a/src/ci/github-actions/jobs.yml b/src/ci/github-actions/jobs.yml index 010e1b8fd51fd..4366a92fbcdf6 100644 --- a/src/ci/github-actions/jobs.yml +++ b/src/ci/github-actions/jobs.yml @@ -390,9 +390,7 @@ auto: - image: x86_64-mingw env: SCRIPT: make ci-mingw - RUST_CONFIGURE_ARGS: >- - --build=x86_64-pc-windows-gnu - --enable-profiler + RUST_CONFIGURE_ARGS: --build=x86_64-pc-windows-gnu # We are intentionally allowing an old toolchain on this builder (and that's # incompatible with LLVM downloads today). NO_DOWNLOAD_CI_LLVM: 1 @@ -440,7 +438,6 @@ auto: RUST_CONFIGURE_ARGS: >- --build=i686-pc-windows-gnu --enable-full-tools - --enable-profiler # We are intentionally allowing an old toolchain on this builder (and that's # incompatible with LLVM downloads today). NO_DOWNLOAD_CI_LLVM: 1 @@ -454,7 +451,6 @@ auto: RUST_CONFIGURE_ARGS: >- --build=x86_64-pc-windows-gnu --enable-full-tools - --enable-profiler # We are intentionally allowing an old toolchain on this builder (and that's # incompatible with LLVM downloads today). NO_DOWNLOAD_CI_LLVM: 1 diff --git a/src/doc/rustc/src/SUMMARY.md b/src/doc/rustc/src/SUMMARY.md index 201ace5ce3a7b..e76ebb8f8aa8c 100644 --- a/src/doc/rustc/src/SUMMARY.md +++ b/src/doc/rustc/src/SUMMARY.md @@ -71,6 +71,7 @@ - [*-unknown-hermit](platform-support/hermit.md) - [\*-unknown-netbsd\*](platform-support/netbsd.md) - [*-unknown-openbsd](platform-support/openbsd.md) + - [*-unknown-redox](platform-support/redox.md) - [\*-unknown-uefi](platform-support/unknown-uefi.md) - [wasm32-wasip1](platform-support/wasm32-wasip1.md) - [wasm32-wasip1-threads](platform-support/wasm32-wasip1-threads.md) diff --git a/src/doc/rustc/src/check-cfg.md b/src/doc/rustc/src/check-cfg.md index 8e39adaa43858..dfc4871b924d4 100644 --- a/src/doc/rustc/src/check-cfg.md +++ b/src/doc/rustc/src/check-cfg.md @@ -11,8 +11,8 @@ development process. In order to accomplish that goal, `rustc` accepts the `--check-cfg` flag, which specifies whether to check conditions and how to check them. -> **Note:** No implicit expectation is added when using `--cfg`. Users are expected to -pass all expected names and values using the _check cfg specification_. +> **Note:** For interacting with this through Cargo, +see [Cargo Specifics](check-cfg/cargo-specifics.md) page. [^reachable]: `rustc` promises to at least check reachable `#[cfg]`, and while non-reachable `#[cfg]` are not currently checked, they may well be checked in the future without it being a @@ -23,6 +23,9 @@ breaking change. To specify expected names and values, the _check cfg specification_ provides the `cfg(...)` option which enables specifying for an expected config name and it's expected values. +> **Note:** No implicit expectation is added when using `--cfg`. Users are expected to +pass all expected names and values using the _check cfg specification_. + It has this basic form: ```bash diff --git a/src/doc/rustc/src/platform-support.md b/src/doc/rustc/src/platform-support.md index c672cff74526e..834e909c0654a 100644 --- a/src/doc/rustc/src/platform-support.md +++ b/src/doc/rustc/src/platform-support.md @@ -203,7 +203,7 @@ target | std | notes `x86_64-unknown-linux-gnux32` | ✓ | 64-bit Linux (x32 ABI) (kernel 4.15, glibc 2.27) [`x86_64-unknown-linux-ohos`](platform-support/openharmony.md) | ✓ | x86_64 OpenHarmony [`x86_64-unknown-none`](platform-support/x86_64-unknown-none.md) | * | Freestanding/bare-metal x86_64, softfloat -`x86_64-unknown-redox` | ✓ | Redox OS +[`x86_64-unknown-redox`](platform-support/redox.md) | ✓ | Redox OS [`x86_64-unknown-uefi`](platform-support/unknown-uefi.md) | ? | 64-bit UEFI [^x86_32-floats-x87]: Floating-point support on `i586` targets is non-compliant: the `x87` registers and instructions used for these targets do not provide IEEE-754-compliant behavior, in particular when it comes to rounding and NaN payload bits. See [issue #114479][x86-32-float-issue]. @@ -258,8 +258,8 @@ target | std | host | notes `aarch64-unknown-linux-gnu_ilp32` | ✓ | ✓ | ARM64 Linux (ILP32 ABI) [`aarch64-unknown-netbsd`](platform-support/netbsd.md) | ✓ | ✓ | ARM64 NetBSD [`aarch64-unknown-openbsd`](platform-support/openbsd.md) | ✓ | ✓ | ARM64 OpenBSD -`aarch64-unknown-redox` | ? | | ARM64 Redox OS -`aarch64-uwp-windows-msvc` | ? | | +[`aarch64-unknown-redox`](platform-support/redox.md) | ✓ | | ARM64 Redox OS +`aarch64-uwp-windows-msvc` | ✓ | | `aarch64-wrs-vxworks` | ? | | `aarch64_be-unknown-linux-gnu_ilp32` | ✓ | ✓ | ARM64 Linux (big-endian, ILP32 ABI) `aarch64_be-unknown-linux-gnu` | ✓ | ✓ | ARM64 Linux (big-endian) @@ -300,8 +300,9 @@ target | std | host | notes [`i686-unknown-hurd-gnu`](platform-support/hurd.md) | ✓ | ✓ | 32-bit GNU/Hurd [^x86_32-floats-return-ABI] [`i686-unknown-netbsd`](platform-support/netbsd.md) | ✓ | ✓ | NetBSD/i386 with SSE2 [^x86_32-floats-return-ABI] [`i686-unknown-openbsd`](platform-support/openbsd.md) | ✓ | ✓ | 32-bit OpenBSD [^x86_32-floats-return-ABI] -`i686-uwp-windows-gnu` | ? | | [^x86_32-floats-return-ABI] -`i686-uwp-windows-msvc` | ? | | [^x86_32-floats-return-ABI] +[`i686-unknown-redox`](platform-support/redox.md) | ✓ | | i686 Redox OS +`i686-uwp-windows-gnu` | ✓ | | [^x86_32-floats-return-ABI] +`i686-uwp-windows-msvc` | ✓ | | [^x86_32-floats-return-ABI] [`i686-win7-windows-msvc`](platform-support/win7-windows-msvc.md) | ✓ | | 32-bit Windows 7 support [^x86_32-floats-return-ABI] `i686-wrs-vxworks` | ? | | [^x86_32-floats-return-ABI] [`loongarch64-unknown-linux-musl`](platform-support/loongarch-linux.md) | ? | | LoongArch64 Linux (LP64D ABI) with musl 1.2.3 @@ -362,7 +363,7 @@ target | std | host | notes [`sparc64-unknown-openbsd`](platform-support/openbsd.md) | ✓ | ✓ | OpenBSD/sparc64 [`thumbv4t-none-eabi`](platform-support/armv4t-none-eabi.md) | * | | Thumb-mode Bare Armv4T [`thumbv5te-none-eabi`](platform-support/armv5te-none-eabi.md) | * | | Thumb-mode Bare Armv5TE -`thumbv7a-pc-windows-msvc` | ? | | +`thumbv7a-pc-windows-msvc` | ✓ | | `thumbv7a-uwp-windows-msvc` | ✓ | | `thumbv7neon-unknown-linux-musleabihf` | ? | | Thumb2-mode Armv7-A Linux with NEON, musl 1.2.3 [`wasm32-wasip2`](platform-support/wasm32-wasip2.md) | ✓ | | WebAssembly diff --git a/src/doc/rustc/src/platform-support/redox.md b/src/doc/rustc/src/platform-support/redox.md new file mode 100644 index 0000000000000..1b3321956ef7b --- /dev/null +++ b/src/doc/rustc/src/platform-support/redox.md @@ -0,0 +1,53 @@ +# `*-unknown-redox` + +**Tier: 2/3** + +Targets for the [Redox OS](https://redox-os.org/) operating +system. + +Target triplets available so far: + +- `x86_64-unknown-redox` (tier 2) +- `aarch64-unknown-redox` (tier 3) +- `i686-unknown-redox` (tier 3) + +## Target maintainers + +- Jeremy Soller ([@jackpot51](https://github.com/jackpot51)) + +## Requirements + +These targets are natively compiled and can be cross-compiled. Std is fully supported. + +The targets are only expected to work with the latest version of Redox OS as the ABI is not yet stable. + +`extern "C"` uses the official calling convention of the respective architectures. + +Redox OS binaries use ELF as file format. + +## Building the target + +You can build Rust with support for the targets by adding it to the `target` list in `config.toml`. In addition a copy of [relibc] needs to be present in the linker search path. + +```toml +[build] +build-stage = 1 +target = [ + "", + "x86_64-unknown-redox", + "aarch64-unknown-redox", + "i686-unknown-redox", +] +``` + +[relibc]: https://gitlab.redox-os.org/redox-os/relibc + +## Building Rust programs and testing + +Rust does not yet ship pre-compiled artifacts for Redox OS except for x86_64-unknown-redox. + +The easiest way to build and test programs for Redox OS is using [redoxer](https://gitlab.redox-os.org/redox-os/redoxer) which sets up the required compiler toolchain for building as well as runs programs inside a Redox OS VM using QEMU. + +## Cross-compilation toolchains and C code + +The target supports C code. Pre-compiled C toolchains can be found at . diff --git a/src/etc/pre-push.sh b/src/etc/pre-push.sh index c9e1a2733fdc5..6f86c7ab8a448 100755 --- a/src/etc/pre-push.sh +++ b/src/etc/pre-push.sh @@ -7,8 +7,6 @@ set -Euo pipefail -# https://github.com/rust-lang/rust/issues/77620#issuecomment-705144570 -unset GIT_DIR ROOT_DIR="$(git rev-parse --show-toplevel)" echo "Running pre-push script $ROOT_DIR/x test tidy" diff --git a/src/tools/build-manifest/src/main.rs b/src/tools/build-manifest/src/main.rs index 9f33e4312740f..a709aab7ce220 100644 --- a/src/tools/build-manifest/src/main.rs +++ b/src/tools/build-manifest/src/main.rs @@ -103,6 +103,7 @@ static TARGETS: &[&str] = &[ "i686-unknown-freebsd", "i686-unknown-linux-gnu", "i686-unknown-linux-musl", + "i686-unknown-redox", "i686-unknown-uefi", "loongarch64-unknown-linux-gnu", "loongarch64-unknown-none", @@ -495,7 +496,7 @@ impl Builder { Some(p) => p, None => return false, }; - pkg.target.get(&c.target).is_some() + pkg.target.contains_key(&c.target) }; extensions.retain(&has_component); components.retain(&has_component); diff --git a/src/tools/build_helper/src/git.rs b/src/tools/build_helper/src/git.rs index a3c857b0268c9..b4522de6897d4 100644 --- a/src/tools/build_helper/src/git.rs +++ b/src/tools/build_helper/src/git.rs @@ -21,7 +21,7 @@ fn output_result(cmd: &mut Command) -> Result { String::from_utf8(output.stderr).map_err(|err| format!("{err:?}"))? )); } - Ok(String::from_utf8(output.stdout).map_err(|err| format!("{err:?}"))?) + String::from_utf8(output.stdout).map_err(|err| format!("{err:?}")) } /// Finds the remote for rust-lang/rust. @@ -64,18 +64,14 @@ pub fn rev_exists(rev: &str, git_dir: Option<&Path>) -> Result { match output.status.code() { Some(0) => Ok(true), Some(128) => Ok(false), - None => { - return Err(format!( - "git didn't exit properly: {}", - String::from_utf8(output.stderr).map_err(|err| format!("{err:?}"))? - )); - } - Some(code) => { - return Err(format!( - "git command exited with status code: {code}: {}", - String::from_utf8(output.stderr).map_err(|err| format!("{err:?}"))? - )); - } + None => Err(format!( + "git didn't exit properly: {}", + String::from_utf8(output.stderr).map_err(|err| format!("{err:?}"))? + )), + Some(code) => Err(format!( + "git command exited with status code: {code}: {}", + String::from_utf8(output.stderr).map_err(|err| format!("{err:?}"))? + )), } } @@ -96,7 +92,7 @@ pub fn updated_master_branch( } } - Err(format!("Cannot find any suitable upstream master branch")) + Err("Cannot find any suitable upstream master branch".to_owned()) } pub fn get_git_merge_base( @@ -118,7 +114,7 @@ pub fn get_git_merge_base( pub fn get_git_modified_files( config: &GitConfig<'_>, git_dir: Option<&Path>, - extensions: &Vec<&str>, + extensions: &[&str], ) -> Result>, String> { let merge_base = get_git_merge_base(config, git_dir)?; diff --git a/src/tools/cargo b/src/tools/cargo index 4dcbca118ab7f..a1f47ec3f7cd0 160000 --- a/src/tools/cargo +++ b/src/tools/cargo @@ -1 +1 @@ -Subproject commit 4dcbca118ab7f9ffac4728004c983754bc6a04ff +Subproject commit a1f47ec3f7cd076986f1bfcd7061f2e8cb1a726e diff --git a/src/tools/clippy/CHANGELOG.md b/src/tools/clippy/CHANGELOG.md index d5115f70f6620..d7bcd7a19687d 100644 --- a/src/tools/clippy/CHANGELOG.md +++ b/src/tools/clippy/CHANGELOG.md @@ -6,11 +6,69 @@ document. ## Unreleased / Beta / In Rust Nightly -[93f0a9a9...master](https://github.com/rust-lang/rust-clippy/compare/93f0a9a9...master) +[ca3b3937...master](https://github.com/rust-lang/rust-clippy/compare/ca3b3937...master) + +## Rust 1.79 + +Current stable, released 2024-06-13 + +[View all 102 merged pull requests](https://github.com/rust-lang/rust-clippy/pulls?q=merged%3A2024-03-08T11%3A13%3A58Z..2024-04-18T15%3A50%3A50Z+base%3Amaster) + +### New Lints + +* Added [`legacy_numeric_constants`] to `style` + [#12312](https://github.com/rust-lang/rust-clippy/pull/12312) +* Added [`missing_transmute_annotations`] to `suspicious` + [#12239](https://github.com/rust-lang/rust-clippy/pull/12239) +* Added [`integer_division_remainder_used`] to `restriction` + [#12451](https://github.com/rust-lang/rust-clippy/pull/12451) +* Added [`duplicated_attributes`] to `suspicious` + [#12378](https://github.com/rust-lang/rust-clippy/pull/12378) +* Added [`manual_unwrap_or_default`] to `suspicious` + [#12440](https://github.com/rust-lang/rust-clippy/pull/12440) +* Added [`zero_repeat_side_effects`] to `suspicious` + [#12449](https://github.com/rust-lang/rust-clippy/pull/12449) +* Added [`const_is_empty`] to `suspicious` + [#12310](https://github.com/rust-lang/rust-clippy/pull/12310) + +### Moves and Deprecations + +* Moved [`box_default`] to `style` (From `perf`) + [#12601](https://github.com/rust-lang/rust-clippy/pull/12601) +* Moved [`manual_clamp`] to `complexity` (From `nursery` now warn-by-default) + [#12543](https://github.com/rust-lang/rust-clippy/pull/12543) +* Moved [`readonly_write_lock`] to `perf` (From `nursery` now warn-by-default) + [#12479](https://github.com/rust-lang/rust-clippy/pull/12479) + +### Enhancements + +* [`module_name_repetitions`]: Added the [`allowed-prefixes`] configuration to allow common prefixes. + [#12573](https://github.com/rust-lang/rust-clippy/pull/12573) +* [`cast_sign_loss`], [`cast_possible_truncation`], [`cast_lossless`]: Are now allowed in macros + [#12631](https://github.com/rust-lang/rust-clippy/pull/12631) +* [`manual_clamp`]: Now only lints on constant min and max values + [#12543](https://github.com/rust-lang/rust-clippy/pull/12543) +* [`assigning_clones`]: Now considers the [`msrv`] configuration + [#12511](https://github.com/rust-lang/rust-clippy/pull/12511) +* [`needless_return`], [`useless_let_if_seq`], [`mut_mut`], [`read_zero_byte_vec`], [`unused_io_amount`], + [`unused_peekable`]: Now respects `#[allow]` attributes on the affected statement instead + [#12446](https://github.com/rust-lang/rust-clippy/pull/12446) + +### False Positive Fixes + +* [`cast_lossless`]: No longer lints when casting to `u128` + [#12496](https://github.com/rust-lang/rust-clippy/pull/12496) +* [`std_instead_of_core`] No longer lints on modules that are only in `std` + [#12447](https://github.com/rust-lang/rust-clippy/pull/12447) + +### ICE Fixes + +* [`needless_return`]: No longer crashes on non-ascii characters + [#12493](https://github.com/rust-lang/rust-clippy/pull/12493) ## Rust 1.78 -Current stable, released 2024-05-02 +Released 2024-05-02 [View all 112 merged pull requests](https://github.com/rust-lang/rust-clippy/pulls?q=merged%3A2024-01-26T05%3A46%3A23Z..2024-03-07T16%3A25%3A52Z+base%3Amaster) @@ -5474,6 +5532,7 @@ Released 2018-09-13 [`manual_next_back`]: https://rust-lang.github.io/rust-clippy/master/index.html#manual_next_back [`manual_non_exhaustive`]: https://rust-lang.github.io/rust-clippy/master/index.html#manual_non_exhaustive [`manual_ok_or`]: https://rust-lang.github.io/rust-clippy/master/index.html#manual_ok_or +[`manual_pattern_char_comparison`]: https://rust-lang.github.io/rust-clippy/master/index.html#manual_pattern_char_comparison [`manual_range_contains`]: https://rust-lang.github.io/rust-clippy/master/index.html#manual_range_contains [`manual_range_patterns`]: https://rust-lang.github.io/rust-clippy/master/index.html#manual_range_patterns [`manual_rem_euclid`]: https://rust-lang.github.io/rust-clippy/master/index.html#manual_rem_euclid @@ -5567,6 +5626,7 @@ Released 2018-09-13 [`needless_borrow`]: https://rust-lang.github.io/rust-clippy/master/index.html#needless_borrow [`needless_borrowed_reference`]: https://rust-lang.github.io/rust-clippy/master/index.html#needless_borrowed_reference [`needless_borrows_for_generic_args`]: https://rust-lang.github.io/rust-clippy/master/index.html#needless_borrows_for_generic_args +[`needless_character_iteration`]: https://rust-lang.github.io/rust-clippy/master/index.html#needless_character_iteration [`needless_collect`]: https://rust-lang.github.io/rust-clippy/master/index.html#needless_collect [`needless_continue`]: https://rust-lang.github.io/rust-clippy/master/index.html#needless_continue [`needless_doctest_main`]: https://rust-lang.github.io/rust-clippy/master/index.html#needless_doctest_main @@ -5576,6 +5636,7 @@ Released 2018-09-13 [`needless_late_init`]: https://rust-lang.github.io/rust-clippy/master/index.html#needless_late_init [`needless_lifetimes`]: https://rust-lang.github.io/rust-clippy/master/index.html#needless_lifetimes [`needless_match`]: https://rust-lang.github.io/rust-clippy/master/index.html#needless_match +[`needless_maybe_sized`]: https://rust-lang.github.io/rust-clippy/master/index.html#needless_maybe_sized [`needless_option_as_deref`]: https://rust-lang.github.io/rust-clippy/master/index.html#needless_option_as_deref [`needless_option_take`]: https://rust-lang.github.io/rust-clippy/master/index.html#needless_option_take [`needless_parens_on_range_literals`]: https://rust-lang.github.io/rust-clippy/master/index.html#needless_parens_on_range_literals diff --git a/src/tools/clippy/Cargo.toml b/src/tools/clippy/Cargo.toml index b48f3ab3919cc..4378849905514 100644 --- a/src/tools/clippy/Cargo.toml +++ b/src/tools/clippy/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "clippy" -version = "0.1.80" +version = "0.1.81" description = "A bunch of helpful lints to avoid common pitfalls in Rust" repository = "https://github.com/rust-lang/rust-clippy" readme = "README.md" diff --git a/src/tools/clippy/README.md b/src/tools/clippy/README.md index fa18447090c19..ec76a6dfb08e9 100644 --- a/src/tools/clippy/README.md +++ b/src/tools/clippy/README.md @@ -172,7 +172,7 @@ You can add options to your code to `allow`/`warn`/`deny` Clippy lints: Note: `allow` means to suppress the lint for your code. With `warn` the lint will only emit a warning, while with `deny` the lint will emit an error, when -triggering for your code. An error causes clippy to exit with an error code, so +triggering for your code. An error causes Clippy to exit with an error code, so is useful in scripts like CI/CD. If you do not want to include your lint levels in your code, you can globally @@ -238,7 +238,7 @@ define the `CLIPPY_DISABLE_DOCS_LINKS` environment variable. ### Specifying the minimum supported Rust version Projects that intend to support old versions of Rust can disable lints pertaining to newer features by -specifying the minimum supported Rust version (MSRV) in the clippy configuration file. +specifying the minimum supported Rust version (MSRV) in the Clippy configuration file. ```toml msrv = "1.30.0" diff --git a/src/tools/clippy/book/src/configuration.md b/src/tools/clippy/book/src/configuration.md index ea549e4df4a51..b130544318980 100644 --- a/src/tools/clippy/book/src/configuration.md +++ b/src/tools/clippy/book/src/configuration.md @@ -99,7 +99,7 @@ For more details and options, refer to the Cargo documentation. ### Specifying the minimum supported Rust version Projects that intend to support old versions of Rust can disable lints pertaining to newer features by specifying the -minimum supported Rust version (MSRV) in the clippy configuration file. +minimum supported Rust version (MSRV) in the Clippy configuration file. ```toml msrv = "1.30.0" diff --git a/src/tools/clippy/book/src/development/basics.md b/src/tools/clippy/book/src/development/basics.md index f4c109ff11917..166b6aab9fb3b 100644 --- a/src/tools/clippy/book/src/development/basics.md +++ b/src/tools/clippy/book/src/development/basics.md @@ -107,7 +107,7 @@ More about [intellij] command usage and reasons. ## lintcheck -`cargo lintcheck` will build and run clippy on a fixed set of crates and +`cargo lintcheck` will build and run Clippy on a fixed set of crates and generate a log of the results. You can `git diff` the updated log against its previous version and see what impact your lint made on a small set of crates. If you add a new lint, please audit the resulting warnings and make sure there diff --git a/src/tools/clippy/book/src/development/defining_lints.md b/src/tools/clippy/book/src/development/defining_lints.md index 806ed0845f031..ceabb255e2d0b 100644 --- a/src/tools/clippy/book/src/development/defining_lints.md +++ b/src/tools/clippy/book/src/development/defining_lints.md @@ -163,11 +163,11 @@ declare_clippy_lint! { /// /// ### Example /// ```rust - /// // example code where clippy issues a warning + /// // example code where Clippy issues a warning /// ``` /// Use instead: /// ```rust - /// // example code which does not raise clippy warning + /// // example code which does not raise Clippy warning /// ``` #[clippy::version = "1.70.0"] // <- In which version was this implemented, keep it up to date! pub LINT_NAME, // <- The lint name IN_ALL_CAPS diff --git a/src/tools/clippy/book/src/development/proposals/syntax-tree-patterns.md b/src/tools/clippy/book/src/development/proposals/syntax-tree-patterns.md index 285488cec55c2..92fbf733a8faf 100644 --- a/src/tools/clippy/book/src/development/proposals/syntax-tree-patterns.md +++ b/src/tools/clippy/book/src/development/proposals/syntax-tree-patterns.md @@ -428,7 +428,7 @@ selection of possible matches is produced by the pattern syntax. In the second stage, the named subpattern references can be used to do additional tests like asserting that a node hasn't been created as part of a macro expansion. -## Implementing clippy lints using patterns +## Implementing Clippy lints using patterns As a "real-world" example, I re-implemented the `collapsible_if` lint using patterns. The code can be found @@ -572,7 +572,7 @@ The pattern syntax and the *PatternTree* are independent of specific syntax tree implementations (rust ast / hir, syn, ...). When looking at the different pattern examples in the previous sections, it can be seen that the patterns don't contain any information specific to a certain syntax tree implementation. -In contrast, clippy lints currently match against ast / hir syntax tree nodes +In contrast, Clippy lints currently match against ast / hir syntax tree nodes and therefore directly depend on their implementation. The connection between the *PatternTree* and specific syntax tree @@ -690,7 +690,7 @@ change, only the `IsMatch` trait implementations need to be adapted and existing lints can remain unchanged. This also means that if the `IsMatch` trait implementations were integrated into the compiler, updating the `IsMatch` implementations would be required for the compiler to compile successfully. This -could reduce the number of times clippy breaks because of changes in the +could reduce the number of times Clippy breaks because of changes in the compiler. Another advantage of the pattern's independence is that converting an `EarlyLintPass` lint into a `LatePassLint` wouldn't require rewriting the whole pattern matching code. In fact, the pattern might work just fine without any @@ -777,7 +777,7 @@ complexity to solve a relatively minor problem. The issue of users not knowing about the *PatternTree* structure could be solved by a tool that, given a rust program, generates a pattern that matches only this -program (similar to the clippy author lint). +program (similar to the Clippy author lint). For some simple cases (like the first example above), it might be possible to successfully mix Rust and pattern syntax. This space could be further explored @@ -789,7 +789,7 @@ The pattern syntax is heavily inspired by regular expressions (repetitions, alternatives, sequences, ...). From what I've seen until now, other linters also implement lints that directly -work on syntax tree data structures, just like clippy does currently. I would +work on syntax tree data structures, just like Clippy does currently. I would therefore consider the pattern syntax to be *new*, but please correct me if I'm wrong. @@ -982,5 +982,5 @@ pattern!{ } ``` -In the future, clippy could use this system to also provide lints for custom +In the future, Clippy could use this system to also provide lints for custom syntaxes like those found in macros. diff --git a/src/tools/clippy/clippy_config/Cargo.toml b/src/tools/clippy/clippy_config/Cargo.toml index 7f7dc9d6cfb0e..be0b048ac0c76 100644 --- a/src/tools/clippy/clippy_config/Cargo.toml +++ b/src/tools/clippy/clippy_config/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "clippy_config" -version = "0.1.80" +version = "0.1.81" edition = "2021" # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html diff --git a/src/tools/clippy/clippy_dummy/PUBLISH.md b/src/tools/clippy/clippy_dummy/PUBLISH.md index 8e420ec959a26..f0021f1594f0b 100644 --- a/src/tools/clippy/clippy_dummy/PUBLISH.md +++ b/src/tools/clippy/clippy_dummy/PUBLISH.md @@ -1,5 +1,5 @@ This is a dummy crate to publish to crates.io. It primarily exists to ensure -that folks trying to install clippy from crates.io get redirected to the +that folks trying to install Clippy from crates.io get redirected to the `rustup` technique. Before publishing, be sure to rename `clippy_dummy` to `clippy` in `Cargo.toml`, diff --git a/src/tools/clippy/clippy_dummy/crates-readme.md b/src/tools/clippy/clippy_dummy/crates-readme.md index 0decae8b9103d..a8ec0a1c36cdf 100644 --- a/src/tools/clippy/clippy_dummy/crates-readme.md +++ b/src/tools/clippy/clippy_dummy/crates-readme.md @@ -1,9 +1,9 @@ -Installing clippy via crates.io is deprecated. Please use the following: +Installing Clippy via crates.io is deprecated. Please use the following: ```terminal rustup component add clippy ``` -on a Rust version 1.29 or later. You may need to run `rustup self update` if it complains about a missing clippy binary. +on a Rust version 1.29 or later. You may need to run `rustup self update` if it complains about a missing Clippy binary. See [the homepage](https://github.com/rust-lang/rust-clippy/#clippy) for more information diff --git a/src/tools/clippy/clippy_lints/Cargo.toml b/src/tools/clippy/clippy_lints/Cargo.toml index 5e3a119337ccd..5708ffba08fd5 100644 --- a/src/tools/clippy/clippy_lints/Cargo.toml +++ b/src/tools/clippy/clippy_lints/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "clippy_lints" -version = "0.1.80" +version = "0.1.81" description = "A bunch of helpful lints to avoid common pitfalls in Rust" repository = "https://github.com/rust-lang/rust-clippy" readme = "README.md" diff --git a/src/tools/clippy/clippy_lints/src/attrs/maybe_misused_cfg.rs b/src/tools/clippy/clippy_lints/src/attrs/maybe_misused_cfg.rs deleted file mode 100644 index e6b2e835be867..0000000000000 --- a/src/tools/clippy/clippy_lints/src/attrs/maybe_misused_cfg.rs +++ /dev/null @@ -1,51 +0,0 @@ -use super::{Attribute, MAYBE_MISUSED_CFG}; -use clippy_utils::diagnostics::span_lint_and_sugg; -use rustc_ast::{MetaItemKind, NestedMetaItem}; -use rustc_errors::Applicability; -use rustc_lint::EarlyContext; -use rustc_span::sym; - -pub(super) fn check(cx: &EarlyContext<'_>, attr: &Attribute) { - if attr.has_name(sym::cfg) - && let Some(items) = attr.meta_item_list() - { - check_nested_misused_cfg(cx, &items); - } -} - -fn check_nested_misused_cfg(cx: &EarlyContext<'_>, items: &[NestedMetaItem]) { - for item in items { - if let NestedMetaItem::MetaItem(meta) = item { - if let Some(ident) = meta.ident() - && ident.name.as_str() == "features" - && let Some(val) = meta.value_str() - { - span_lint_and_sugg( - cx, - MAYBE_MISUSED_CFG, - meta.span, - "'feature' may be misspelled as 'features'", - "did you mean", - format!("feature = \"{val}\""), - Applicability::MaybeIncorrect, - ); - } - if let MetaItemKind::List(list) = &meta.kind { - check_nested_misused_cfg(cx, list); - // If this is not a list, then we check for `cfg(test)`. - } else if let Some(ident) = meta.ident() - && matches!(ident.name.as_str(), "tests" | "Test") - { - span_lint_and_sugg( - cx, - MAYBE_MISUSED_CFG, - meta.span, - format!("'test' may be misspelled as '{}'", ident.name.as_str()), - "did you mean", - "test".to_string(), - Applicability::MaybeIncorrect, - ); - } - } - } -} diff --git a/src/tools/clippy/clippy_lints/src/attrs/mismatched_target_os.rs b/src/tools/clippy/clippy_lints/src/attrs/mismatched_target_os.rs deleted file mode 100644 index b1cc0a763c5e9..0000000000000 --- a/src/tools/clippy/clippy_lints/src/attrs/mismatched_target_os.rs +++ /dev/null @@ -1,90 +0,0 @@ -use super::{Attribute, MISMATCHED_TARGET_OS}; -use clippy_utils::diagnostics::span_lint_and_then; -use rustc_ast::{MetaItemKind, NestedMetaItem}; -use rustc_errors::Applicability; -use rustc_lint::EarlyContext; -use rustc_span::{sym, Span}; - -static UNIX_SYSTEMS: &[&str] = &[ - "android", - "dragonfly", - "emscripten", - "freebsd", - "fuchsia", - "haiku", - "illumos", - "ios", - "l4re", - "linux", - "macos", - "netbsd", - "openbsd", - "redox", - "solaris", - "vxworks", -]; - -// NOTE: windows is excluded from the list because it's also a valid target family. -static NON_UNIX_SYSTEMS: &[&str] = &["hermit", "none", "wasi"]; - -pub(super) fn check(cx: &EarlyContext<'_>, attr: &Attribute) { - fn find_os(name: &str) -> Option<&'static str> { - UNIX_SYSTEMS - .iter() - .chain(NON_UNIX_SYSTEMS.iter()) - .find(|&&os| os == name) - .copied() - } - - fn is_unix(name: &str) -> bool { - UNIX_SYSTEMS.iter().any(|&os| os == name) - } - - fn find_mismatched_target_os(items: &[NestedMetaItem]) -> Vec<(&str, Span)> { - let mut mismatched = Vec::new(); - - for item in items { - if let NestedMetaItem::MetaItem(meta) = item { - match &meta.kind { - MetaItemKind::List(list) => { - mismatched.extend(find_mismatched_target_os(list)); - }, - MetaItemKind::Word => { - if let Some(ident) = meta.ident() - && let Some(os) = find_os(ident.name.as_str()) - { - mismatched.push((os, ident.span)); - } - }, - MetaItemKind::NameValue(..) => {}, - } - } - } - - mismatched - } - - if attr.has_name(sym::cfg) - && let Some(list) = attr.meta_item_list() - && let mismatched = find_mismatched_target_os(&list) - && !mismatched.is_empty() - { - let mess = "operating system used in target family position"; - - span_lint_and_then(cx, MISMATCHED_TARGET_OS, attr.span, mess, |diag| { - // Avoid showing the unix suggestion multiple times in case - // we have more than one mismatch for unix-like systems - let mut unix_suggested = false; - - for (os, span) in mismatched { - let sugg = format!("target_os = \"{os}\""); - diag.span_suggestion(span, "try", sugg, Applicability::MaybeIncorrect); - - if !unix_suggested && is_unix(os) { - diag.help("did you mean `unix`?"); - unix_suggested = true; - } - } - }); - } -} diff --git a/src/tools/clippy/clippy_lints/src/attrs/mod.rs b/src/tools/clippy/clippy_lints/src/attrs/mod.rs index a24bd5ed44be4..e4c98a32fd673 100644 --- a/src/tools/clippy/clippy_lints/src/attrs/mod.rs +++ b/src/tools/clippy/clippy_lints/src/attrs/mod.rs @@ -7,8 +7,6 @@ mod deprecated_semver; mod duplicated_attributes; mod empty_line_after; mod inline_always; -mod maybe_misused_cfg; -mod mismatched_target_os; mod mixed_attributes_style; mod non_minimal_cfg; mod should_panic_without_expect; @@ -270,39 +268,6 @@ declare_clippy_lint! { "usage of `cfg_attr(rustfmt)` instead of tool attributes" } -declare_clippy_lint! { - /// ### What it does - /// Checks for cfg attributes having operating systems used in target family position. - /// - /// ### Why is this bad? - /// The configuration option will not be recognised and the related item will not be included - /// by the conditional compilation engine. - /// - /// ### Example - /// ```no_run - /// #[cfg(linux)] - /// fn conditional() { } - /// ``` - /// - /// Use instead: - /// ```no_run - /// # mod hidden { - /// #[cfg(target_os = "linux")] - /// fn conditional() { } - /// # } - /// - /// // or - /// - /// #[cfg(unix)] - /// fn conditional() { } - /// ``` - /// Check the [Rust Reference](https://doc.rust-lang.org/reference/conditional-compilation.html#target_os) for more details. - #[clippy::version = "1.45.0"] - pub MISMATCHED_TARGET_OS, - correctness, - "usage of `cfg(operating_system)` instead of `cfg(target_os = \"operating_system\")`" -} - declare_clippy_lint! { /// ### What it does /// Checks for attributes that allow lints without a reason. @@ -391,38 +356,6 @@ declare_clippy_lint! { "ensure that all `cfg(any())` and `cfg(all())` have more than one condition" } -declare_clippy_lint! { - /// ### What it does - /// Checks for `#[cfg(features = "...")]` and suggests to replace it with - /// `#[cfg(feature = "...")]`. - /// - /// It also checks if `cfg(test)` was misspelled. - /// - /// ### Why is this bad? - /// Misspelling `feature` as `features` or `test` as `tests` can be sometimes hard to spot. It - /// may cause conditional compilation not work quietly. - /// - /// ### Example - /// ```no_run - /// #[cfg(features = "some-feature")] - /// fn conditional() { } - /// #[cfg(tests)] - /// mod tests { } - /// ``` - /// - /// Use instead: - /// ```no_run - /// #[cfg(feature = "some-feature")] - /// fn conditional() { } - /// #[cfg(test)] - /// mod tests { } - /// ``` - #[clippy::version = "1.69.0"] - pub MAYBE_MISUSED_CFG, - suspicious, - "prevent from misusing the wrong attr name" -} - declare_clippy_lint! { /// ### What it does /// Checks for `#[cfg_attr(feature = "cargo-clippy", ...)]` and for @@ -530,7 +463,7 @@ declare_clippy_lint! { /// #[allow(dead_code)] /// fn foo() {} /// ``` - #[clippy::version = "1.78.0"] + #[clippy::version = "1.79.0"] pub DUPLICATED_ATTRIBUTES, suspicious, "duplicated attribute" @@ -612,11 +545,9 @@ pub struct EarlyAttributes { impl_lint_pass!(EarlyAttributes => [ DEPRECATED_CFG_ATTR, - MISMATCHED_TARGET_OS, EMPTY_LINE_AFTER_OUTER_ATTR, EMPTY_LINE_AFTER_DOC_COMMENTS, NON_MINIMAL_CFG, - MAYBE_MISUSED_CFG, DEPRECATED_CLIPPY_CFG_ATTR, UNNECESSARY_CLIPPY_CFG, ]); @@ -629,9 +560,7 @@ impl EarlyLintPass for EarlyAttributes { fn check_attribute(&mut self, cx: &EarlyContext<'_>, attr: &Attribute) { deprecated_cfg_attr::check(cx, attr, &self.msrv); deprecated_cfg_attr::check_clippy(cx, attr); - mismatched_target_os::check(cx, attr); non_minimal_cfg::check(cx, attr); - maybe_misused_cfg::check(cx, attr); } extract_msrv_attr!(EarlyContext); diff --git a/src/tools/clippy/clippy_lints/src/blocks_in_conditions.rs b/src/tools/clippy/clippy_lints/src/blocks_in_conditions.rs index 171f303186012..eb05dc96cdebf 100644 --- a/src/tools/clippy/clippy_lints/src/blocks_in_conditions.rs +++ b/src/tools/clippy/clippy_lints/src/blocks_in_conditions.rs @@ -1,15 +1,11 @@ -use clippy_utils::diagnostics::{span_lint, span_lint_and_sugg}; +use clippy_utils::diagnostics::span_lint_and_sugg; use clippy_utils::source::snippet_block_with_applicability; -use clippy_utils::ty::implements_trait; -use clippy_utils::visitors::{for_each_expr, Descend}; -use clippy_utils::{get_parent_expr, higher, is_from_proc_macro}; -use core::ops::ControlFlow; +use clippy_utils::{higher, is_from_proc_macro}; use rustc_errors::Applicability; use rustc_hir::{BlockCheckMode, Expr, ExprKind, MatchSource}; use rustc_lint::{LateContext, LateLintPass, LintContext}; use rustc_middle::lint::in_external_macro; use rustc_session::declare_lint_pass; -use rustc_span::sym; declare_clippy_lint! { /// ### What it does @@ -124,30 +120,6 @@ impl<'tcx> LateLintPass<'tcx> for BlocksInConditions { ); } } - } else { - let _: Option = for_each_expr(cond, |e| { - if let ExprKind::Closure(closure) = e.kind { - // do not lint if the closure is called using an iterator (see #1141) - if let Some(parent) = get_parent_expr(cx, e) - && let ExprKind::MethodCall(_, self_arg, _, _) = &parent.kind - && let caller = cx.typeck_results().expr_ty(self_arg) - && let Some(iter_id) = cx.tcx.get_diagnostic_item(sym::Iterator) - && implements_trait(cx, caller, iter_id, &[]) - { - return ControlFlow::Continue(Descend::No); - } - - let body = cx.tcx.hir().body(closure.body); - let ex = &body.value; - if let ExprKind::Block(block, _) = ex.kind { - if !body.value.span.from_expansion() && !block.stmts.is_empty() { - span_lint(cx, BLOCKS_IN_CONDITIONS, ex.span, complex_block_message.clone()); - return ControlFlow::Continue(Descend::No); - } - } - } - ControlFlow::Continue(Descend::Yes) - }); } } } diff --git a/src/tools/clippy/clippy_lints/src/booleans.rs b/src/tools/clippy/clippy_lints/src/booleans.rs index b6341b3fe8e7c..a1c6c0b608f72 100644 --- a/src/tools/clippy/clippy_lints/src/booleans.rs +++ b/src/tools/clippy/clippy_lints/src/booleans.rs @@ -174,6 +174,25 @@ fn check_inverted_bool_in_condition( ); } +fn check_simplify_not(cx: &LateContext<'_>, expr: &Expr<'_>) { + if let ExprKind::Unary(UnOp::Not, inner) = &expr.kind + && !expr.span.from_expansion() + && !inner.span.from_expansion() + && let Some(suggestion) = simplify_not(cx, inner) + && cx.tcx.lint_level_at_node(NONMINIMAL_BOOL, expr.hir_id).0 != Level::Allow + { + span_lint_and_sugg( + cx, + NONMINIMAL_BOOL, + expr.span, + "this boolean expression can be simplified", + "try", + suggestion, + Applicability::MachineApplicable, + ); + } +} + struct NonminimalBoolVisitor<'a, 'tcx> { cx: &'a LateContext<'tcx>, } @@ -232,6 +251,11 @@ impl<'a, 'tcx, 'v> Hir2Qmm<'a, 'tcx, 'v> { _ => (), } } + + if self.cx.typeck_results().expr_ty(e).is_never() { + return Err("contains never type".to_owned()); + } + for (n, expr) in self.terminals.iter().enumerate() { if eq_expr_value(self.cx, e, expr) { #[expect(clippy::cast_possible_truncation)] @@ -542,8 +566,7 @@ impl<'a, 'tcx> NonminimalBoolVisitor<'a, 'tcx> { } }; if improvements.is_empty() { - let mut visitor = NotSimplificationVisitor { cx: self.cx }; - visitor.visit_expr(e); + check_simplify_not(self.cx, e); } else { nonminimal_bool_lint( improvements @@ -586,30 +609,3 @@ fn implements_ord(cx: &LateContext<'_>, expr: &Expr<'_>) -> bool { .get_diagnostic_item(sym::Ord) .map_or(false, |id| implements_trait(cx, ty, id, &[])) } - -struct NotSimplificationVisitor<'a, 'tcx> { - cx: &'a LateContext<'tcx>, -} - -impl<'a, 'tcx> Visitor<'tcx> for NotSimplificationVisitor<'a, 'tcx> { - fn visit_expr(&mut self, expr: &'tcx Expr<'_>) { - if let ExprKind::Unary(UnOp::Not, inner) = &expr.kind - && !expr.span.from_expansion() - && !inner.span.from_expansion() - && let Some(suggestion) = simplify_not(self.cx, inner) - && self.cx.tcx.lint_level_at_node(NONMINIMAL_BOOL, expr.hir_id).0 != Level::Allow - { - span_lint_and_sugg( - self.cx, - NONMINIMAL_BOOL, - expr.span, - "this boolean expression can be simplified", - "try", - suggestion, - Applicability::MachineApplicable, - ); - } - - walk_expr(self, expr); - } -} diff --git a/src/tools/clippy/clippy_lints/src/cargo/lint_groups_priority.rs b/src/tools/clippy/clippy_lints/src/cargo/lint_groups_priority.rs index 0d9eaac882f79..e924542fea2aa 100644 --- a/src/tools/clippy/clippy_lints/src/cargo/lint_groups_priority.rs +++ b/src/tools/clippy/clippy_lints/src/cargo/lint_groups_priority.rs @@ -71,12 +71,6 @@ struct CargoToml { workspace: Workspace, } -#[derive(Default, Debug)] -struct LintsAndGroups { - lints: Vec>, - groups: Vec<(Spanned, Spanned)>, -} - fn toml_span(range: Range, file: &SourceFile) -> Span { Span::new( file.start_pos + BytePos::from_usize(range.start), @@ -86,27 +80,28 @@ fn toml_span(range: Range, file: &SourceFile) -> Span { ) } -fn check_table(cx: &LateContext<'_>, table: LintTable, groups: &FxHashSet<&str>, file: &SourceFile) { - let mut by_priority = BTreeMap::<_, LintsAndGroups>::new(); +fn check_table(cx: &LateContext<'_>, table: LintTable, known_groups: &FxHashSet<&str>, file: &SourceFile) { + let mut lints = Vec::new(); + let mut groups = Vec::new(); for (name, config) in table { - let lints_and_groups = by_priority.entry(config.as_ref().priority()).or_default(); - if groups.contains(name.get_ref().as_str()) { - lints_and_groups.groups.push((name, config)); + if name.get_ref() == "warnings" { + continue; + } + + if known_groups.contains(name.get_ref().as_str()) { + groups.push((name, config)); } else { - lints_and_groups.lints.push(name); + lints.push((name, config.into_inner())); } } - let low_priority = by_priority - .iter() - .find(|(_, lints_and_groups)| !lints_and_groups.lints.is_empty()) - .map_or(-1, |(&lowest_lint_priority, _)| lowest_lint_priority - 1); - for (priority, LintsAndGroups { lints, groups }) in by_priority { - let Some(last_lint_alphabetically) = lints.last() else { - continue; - }; - - for (group, config) in groups { + for (group, group_config) in groups { + let priority = group_config.get_ref().priority(); + let level = group_config.get_ref().level(); + if let Some((conflict, _)) = lints + .iter() + .rfind(|(_, lint_config)| lint_config.priority() == priority && lint_config.level() != level) + { span_lint_and_then( cx, LINT_GROUPS_PRIORITY, @@ -116,22 +111,23 @@ fn check_table(cx: &LateContext<'_>, table: LintTable, groups: &FxHashSet<&str>, group.as_ref() ), |diag| { - let config_span = toml_span(config.span(), file); - if config.as_ref().is_implicit() { + let config_span = toml_span(group_config.span(), file); + + if group_config.as_ref().is_implicit() { diag.span_label(config_span, "has an implicit priority of 0"); } - // add the label to next lint after this group that has the same priority - let lint = lints - .iter() - .filter(|lint| lint.span().start > group.span().start) - .min_by_key(|lint| lint.span().start) - .unwrap_or(last_lint_alphabetically); - diag.span_label(toml_span(lint.span(), file), "has the same priority as this lint"); + diag.span_label(toml_span(conflict.span(), file), "has the same priority as this lint"); diag.note("the order of the lints in the table is ignored by Cargo"); + let mut suggestion = String::new(); + let low_priority = lints + .iter() + .map(|(_, config)| config.priority().saturating_sub(1)) + .min() + .unwrap_or(-1); Serialize::serialize( &LintConfigTable { - level: config.as_ref().level().into(), + level: level.into(), priority: Some(low_priority), }, toml::ser::ValueSerializer::new(&mut suggestion), diff --git a/src/tools/clippy/clippy_lints/src/casts/cast_sign_loss.rs b/src/tools/clippy/clippy_lints/src/casts/cast_sign_loss.rs index 864489ee3fcd5..8bbd41b0db1ee 100644 --- a/src/tools/clippy/clippy_lints/src/casts/cast_sign_loss.rs +++ b/src/tools/clippy/clippy_lints/src/casts/cast_sign_loss.rs @@ -3,7 +3,7 @@ use std::ops::ControlFlow; use clippy_utils::consts::{constant, Constant}; use clippy_utils::diagnostics::span_lint; -use clippy_utils::visitors::{for_each_expr, Descend}; +use clippy_utils::visitors::{for_each_expr_without_closures, Descend}; use clippy_utils::{method_chain_args, sext}; use rustc_hir::{BinOpKind, Expr, ExprKind}; use rustc_lint::LateContext; @@ -266,7 +266,7 @@ fn expr_add_sign(cx: &LateContext<'_>, expr: &Expr<'_>) -> Sign { fn exprs_with_muldiv_binop_peeled<'e>(expr: &'e Expr<'_>) -> Vec<&'e Expr<'e>> { let mut res = vec![]; - for_each_expr(expr, |sub_expr| -> ControlFlow { + for_each_expr_without_closures(expr, |sub_expr| -> ControlFlow { // We don't check for mul/div/rem methods here, but we could. if let ExprKind::Binary(op, lhs, _rhs) = sub_expr.kind { if matches!(op.node, BinOpKind::Mul | BinOpKind::Div) { @@ -315,7 +315,7 @@ fn exprs_with_muldiv_binop_peeled<'e>(expr: &'e Expr<'_>) -> Vec<&'e Expr<'e>> { fn exprs_with_add_binop_peeled<'e>(expr: &'e Expr<'_>) -> Vec<&'e Expr<'e>> { let mut res = vec![]; - for_each_expr(expr, |sub_expr| -> ControlFlow { + for_each_expr_without_closures(expr, |sub_expr| -> ControlFlow { // We don't check for add methods here, but we could. if let ExprKind::Binary(op, _lhs, _rhs) = sub_expr.kind { if matches!(op.node, BinOpKind::Add) { diff --git a/src/tools/clippy/clippy_lints/src/casts/unnecessary_cast.rs b/src/tools/clippy/clippy_lints/src/casts/unnecessary_cast.rs index a7f7bf7854e65..fb0b0cba6a662 100644 --- a/src/tools/clippy/clippy_lints/src/casts/unnecessary_cast.rs +++ b/src/tools/clippy/clippy_lints/src/casts/unnecessary_cast.rs @@ -1,7 +1,7 @@ use clippy_utils::diagnostics::span_lint_and_sugg; use clippy_utils::numeric_literal::NumericLiteral; use clippy_utils::source::snippet_opt; -use clippy_utils::visitors::{for_each_expr, Visitable}; +use clippy_utils::visitors::{for_each_expr_without_closures, Visitable}; use clippy_utils::{get_parent_expr, is_hir_ty_cfg_dependant, is_ty_alias, path_to_local}; use rustc_ast::{LitFloatType, LitIntType, LitKind}; use rustc_errors::Applicability; @@ -245,7 +245,7 @@ fn fp_ty_mantissa_nbits(typ: Ty<'_>) -> u32 { /// TODO: Maybe we should move this to `clippy_utils` so others won't need to go down this dark, /// dark path reimplementing this (or something similar). fn is_cast_from_ty_alias<'tcx>(cx: &LateContext<'tcx>, expr: impl Visitable<'tcx>, cast_from: Ty<'tcx>) -> bool { - for_each_expr(expr, |expr| { + for_each_expr_without_closures(expr, |expr| { // Calls are a `Path`, and usage of locals are a `Path`. So, this checks // - call() as i32 // - local as i32 diff --git a/src/tools/clippy/clippy_lints/src/cognitive_complexity.rs b/src/tools/clippy/clippy_lints/src/cognitive_complexity.rs index ee1bb63b50d30..e41abf422349d 100644 --- a/src/tools/clippy/clippy_lints/src/cognitive_complexity.rs +++ b/src/tools/clippy/clippy_lints/src/cognitive_complexity.rs @@ -3,7 +3,7 @@ use clippy_utils::diagnostics::span_lint_and_help; use clippy_utils::source::snippet_opt; use clippy_utils::ty::is_type_diagnostic_item; -use clippy_utils::visitors::for_each_expr; +use clippy_utils::visitors::for_each_expr_without_closures; use clippy_utils::{get_async_fn_body, is_async_fn, LimitStack}; use core::ops::ControlFlow; use rustc_ast::ast::Attribute; @@ -65,7 +65,7 @@ impl CognitiveComplexity { let mut cc = 1u64; let mut returns = 0u64; - let _: Option = for_each_expr(expr, |e| { + let _: Option = for_each_expr_without_closures(expr, |e| { match e.kind { ExprKind::If(_, _, _) => { cc += 1; diff --git a/src/tools/clippy/clippy_lints/src/collection_is_never_read.rs b/src/tools/clippy/clippy_lints/src/collection_is_never_read.rs index 70856b808810b..28d9f68d504cc 100644 --- a/src/tools/clippy/clippy_lints/src/collection_is_never_read.rs +++ b/src/tools/clippy/clippy_lints/src/collection_is_never_read.rs @@ -1,6 +1,6 @@ use clippy_utils::diagnostics::span_lint; use clippy_utils::ty::{is_type_diagnostic_item, is_type_lang_item}; -use clippy_utils::visitors::{for_each_expr_with_closures, Visitable}; +use clippy_utils::visitors::{for_each_expr, Visitable}; use clippy_utils::{get_enclosing_block, path_to_local_id}; use core::ops::ControlFlow; use rustc_hir::{Body, ExprKind, HirId, LangItem, LetStmt, Node, PatKind}; @@ -82,7 +82,7 @@ fn has_no_read_access<'tcx, T: Visitable<'tcx>>(cx: &LateContext<'tcx>, id: HirI let mut has_read_access = false; // Inspect all expressions and sub-expressions in the block. - for_each_expr_with_closures(cx, block, |expr| { + for_each_expr(cx, block, |expr| { // Ignore expressions that are not simply `id`. if !path_to_local_id(expr, id) { return ControlFlow::Continue(()); diff --git a/src/tools/clippy/clippy_lints/src/copies.rs b/src/tools/clippy/clippy_lints/src/copies.rs index ccf1d9d6f8c0d..480df675d7544 100644 --- a/src/tools/clippy/clippy_lints/src/copies.rs +++ b/src/tools/clippy/clippy_lints/src/copies.rs @@ -1,7 +1,7 @@ use clippy_utils::diagnostics::{span_lint_and_note, span_lint_and_then}; use clippy_utils::source::{first_line_of_span, indent_of, reindent_multiline, snippet, snippet_opt}; use clippy_utils::ty::{needs_ordered_drop, InteriorMut}; -use clippy_utils::visitors::for_each_expr; +use clippy_utils::visitors::for_each_expr_without_closures; use clippy_utils::{ capture_local_usage, eq_expr_value, find_binding_init, get_enclosing_block, hash_expr, hash_stmt, if_sequence, is_else_clause, is_lint_allowed, path_to_local, search_same, ContainsName, HirEqInterExpr, SpanlessEq, @@ -362,7 +362,7 @@ fn eq_binding_names(s: &Stmt<'_>, names: &[(HirId, Symbol)]) -> bool { /// Checks if the statement modifies or moves any of the given locals. fn modifies_any_local<'tcx>(cx: &LateContext<'tcx>, s: &'tcx Stmt<'_>, locals: &HirIdSet) -> bool { - for_each_expr(s, |e| { + for_each_expr_without_closures(s, |e| { if let Some(id) = path_to_local(e) && locals.contains(&id) && !capture_local_usage(cx, e).is_imm_ref() @@ -413,7 +413,7 @@ fn scan_block_for_eq<'tcx>( let mut cond_locals = HirIdSet::default(); for &cond in conds { - let _: Option = for_each_expr(cond, |e| { + let _: Option = for_each_expr_without_closures(cond, |e| { if let Some(id) = path_to_local(e) { cond_locals.insert(id); } diff --git a/src/tools/clippy/clippy_lints/src/declared_lints.rs b/src/tools/clippy/clippy_lints/src/declared_lints.rs index df2ef465700d4..7e43a99e9f24f 100644 --- a/src/tools/clippy/clippy_lints/src/declared_lints.rs +++ b/src/tools/clippy/clippy_lints/src/declared_lints.rs @@ -58,8 +58,6 @@ pub(crate) static LINTS: &[&crate::LintInfo] = &[ crate::attrs::EMPTY_LINE_AFTER_DOC_COMMENTS_INFO, crate::attrs::EMPTY_LINE_AFTER_OUTER_ATTR_INFO, crate::attrs::INLINE_ALWAYS_INFO, - crate::attrs::MAYBE_MISUSED_CFG_INFO, - crate::attrs::MISMATCHED_TARGET_OS_INFO, crate::attrs::MIXED_ATTRIBUTES_STYLE_INFO, crate::attrs::NON_MINIMAL_CFG_INFO, crate::attrs::SHOULD_PANIC_WITHOUT_EXPECT_INFO, @@ -419,6 +417,7 @@ pub(crate) static LINTS: &[&crate::LintInfo] = &[ crate::methods::MAP_UNWRAP_OR_INFO, crate::methods::MUT_MUTEX_LOCK_INFO, crate::methods::NAIVE_BYTECOUNT_INFO, + crate::methods::NEEDLESS_CHARACTER_ITERATION_INFO, crate::methods::NEEDLESS_COLLECT_INFO, crate::methods::NEEDLESS_OPTION_AS_DEREF_INFO, crate::methods::NEEDLESS_OPTION_TAKE_INFO, @@ -449,7 +448,6 @@ pub(crate) static LINTS: &[&crate::LintInfo] = &[ crate::methods::SEEK_TO_START_INSTEAD_OF_REWIND_INFO, crate::methods::SHOULD_IMPLEMENT_TRAIT_INFO, crate::methods::SINGLE_CHAR_ADD_STR_INFO, - crate::methods::SINGLE_CHAR_PATTERN_INFO, crate::methods::SKIP_WHILE_NEXT_INFO, crate::methods::STABLE_SORT_PRIMITIVE_INFO, crate::methods::STRING_EXTEND_CHARS_INFO, @@ -531,6 +529,7 @@ pub(crate) static LINTS: &[&crate::LintInfo] = &[ crate::needless_for_each::NEEDLESS_FOR_EACH_INFO, crate::needless_if::NEEDLESS_IF_INFO, crate::needless_late_init::NEEDLESS_LATE_INIT_INFO, + crate::needless_maybe_sized::NEEDLESS_MAYBE_SIZED_INFO, crate::needless_parens_on_range_literals::NEEDLESS_PARENS_ON_RANGE_LITERALS_INFO, crate::needless_pass_by_ref_mut::NEEDLESS_PASS_BY_REF_MUT_INFO, crate::needless_pass_by_value::NEEDLESS_PASS_BY_VALUE_INFO, @@ -656,6 +655,8 @@ pub(crate) static LINTS: &[&crate::LintInfo] = &[ crate::std_instead_of_core::ALLOC_INSTEAD_OF_CORE_INFO, crate::std_instead_of_core::STD_INSTEAD_OF_ALLOC_INFO, crate::std_instead_of_core::STD_INSTEAD_OF_CORE_INFO, + crate::string_patterns::MANUAL_PATTERN_CHAR_COMPARISON_INFO, + crate::string_patterns::SINGLE_CHAR_PATTERN_INFO, crate::strings::STRING_ADD_INFO, crate::strings::STRING_ADD_ASSIGN_INFO, crate::strings::STRING_FROM_UTF8_AS_BYTES_INFO, diff --git a/src/tools/clippy/clippy_lints/src/deprecated_lints.rs b/src/tools/clippy/clippy_lints/src/deprecated_lints.rs index 9aa5af3190fb2..a0900f46f6aa6 100644 --- a/src/tools/clippy/clippy_lints/src/deprecated_lints.rs +++ b/src/tools/clippy/clippy_lints/src/deprecated_lints.rs @@ -215,3 +215,29 @@ declare_deprecated_lint! { pub WRONG_PUB_SELF_CONVENTION, "set the `avoid-breaking-exported-api` config option to `false` to enable the `wrong_self_convention` lint for public items" } + +declare_deprecated_lint! { + /// ### What it does + /// Nothing. This lint has been deprecated. + /// + /// ### Deprecation reason + /// This lint has been superseded by rustc's own [`unexpected_cfgs`] lint that is able to detect the `#[cfg(features)]` and `#[cfg(tests)]` typos. + /// + /// [`unexpected_cfgs`]: https://doc.rust-lang.org/rustc/lints/listing/warn-by-default.html#unexpected-cfgs + #[clippy::version = "1.80.0"] + pub MAYBE_MISUSED_CFG, + "this lint has been replaced by `unexpected_cfgs`" +} + +declare_deprecated_lint! { + /// ### What it does + /// Nothing. This lint has been deprecated. + /// + /// ### Deprecation reason + /// This lint has been superseded by rustc's own [`unexpected_cfgs`] lint that is able to detect invalid `#[cfg(linux)]` attributes. + /// + /// [`unexpected_cfgs`]: https://doc.rust-lang.org/rustc/lints/listing/warn-by-default.html#unexpected-cfgs + #[clippy::version = "1.80.0"] + pub MISMATCHED_TARGET_OS, + "this lint has been replaced by `unexpected_cfgs`" +} diff --git a/src/tools/clippy/clippy_lints/src/doc/missing_headers.rs b/src/tools/clippy/clippy_lints/src/doc/missing_headers.rs index 010fab803d99c..e3d7484072612 100644 --- a/src/tools/clippy/clippy_lints/src/doc/missing_headers.rs +++ b/src/tools/clippy/clippy_lints/src/doc/missing_headers.rs @@ -37,7 +37,7 @@ pub fn check( cx, MISSING_SAFETY_DOC, span, - "unsafe function's docs miss `# Safety` section", + "unsafe function's docs are missing a `# Safety` section", ), (true, Safety::Safe) => span_lint( cx, diff --git a/src/tools/clippy/clippy_lints/src/eta_reduction.rs b/src/tools/clippy/clippy_lints/src/eta_reduction.rs index 48c4c4206fe88..42ec2c00823c8 100644 --- a/src/tools/clippy/clippy_lints/src/eta_reduction.rs +++ b/src/tools/clippy/clippy_lints/src/eta_reduction.rs @@ -9,8 +9,8 @@ use rustc_hir::{BindingMode, Expr, ExprKind, FnRetTy, Param, PatKind, QPath, Saf use rustc_infer::infer::TyCtxtInferExt; use rustc_lint::{LateContext, LateLintPass}; use rustc_middle::ty::{ - self, Binder, ClosureArgs, ClosureKind, FnSig, GenericArg, GenericArgKind, List, Region, RegionKind, Ty, - TypeVisitableExt, TypeckResults, TyCtxt, + self, Binder, ClosureArgs, ClosureKind, FnSig, GenericArg, GenericArgKind, List, Region, RegionKind, Ty, TyCtxt, + TypeVisitableExt, TypeckResults, }; use rustc_session::declare_lint_pass; use rustc_span::symbol::sym; @@ -123,7 +123,8 @@ impl<'tcx> LateLintPass<'tcx> for EtaReduction { ExprKind::Path(QPath::Resolved(..) | QPath::TypeRelative(..)) ) => { - let callee_ty = typeck.expr_ty(callee).peel_refs(); + let callee_ty_raw = typeck.expr_ty(callee); + let callee_ty = callee_ty_raw.peel_refs(); if matches!(type_diagnostic_name(cx, callee_ty), Some(sym::Arc | sym::Rc)) || !check_inputs(typeck, body.params, None, args) { @@ -170,15 +171,25 @@ impl<'tcx> LateLintPass<'tcx> for EtaReduction { { span_lint_and_then(cx, REDUNDANT_CLOSURE, expr.span, "redundant closure", |diag| { if let Some(mut snippet) = snippet_opt(cx, callee.span) { - if let Ok((ClosureKind::FnMut, _)) = cx.tcx.infer_ctxt().build().type_implements_fn_trait( - cx.param_env, - Binder::bind_with_vars(callee_ty_adjusted, List::empty()), - ty::PredicatePolarity::Positive, - ) && path_to_local(callee).map_or(false, |l| { + if path_to_local(callee).map_or(false, |l| { + // FIXME: Do we really need this `local_used_in` check? + // Isn't it checking something like... `callee(callee)`? + // If somehow this check is needed, add some test for it, + // 'cuz currently nothing changes after deleting this check. local_used_in(cx, l, args) || local_used_after_expr(cx, l, expr) }) { - // Mutable closure is used after current expr; we cannot consume it. - snippet = format!("&mut {snippet}"); + match cx.tcx.infer_ctxt().build().type_implements_fn_trait( + cx.param_env, + Binder::bind_with_vars(callee_ty_adjusted, List::empty()), + ty::PredicatePolarity::Positive, + ) { + // Mutable closure is used after current expr; we cannot consume it. + Ok((ClosureKind::FnMut, _)) => snippet = format!("&mut {snippet}"), + Ok((ClosureKind::Fn, _)) if !callee_ty_raw.is_ref() => { + snippet = format!("&{snippet}"); + }, + _ => (), + } } diag.span_suggestion( expr.span, diff --git a/src/tools/clippy/clippy_lints/src/float_literal.rs b/src/tools/clippy/clippy_lints/src/float_literal.rs index 4ec9bd757ff45..4d301daabe4c5 100644 --- a/src/tools/clippy/clippy_lints/src/float_literal.rs +++ b/src/tools/clippy/clippy_lints/src/float_literal.rs @@ -103,7 +103,7 @@ impl<'tcx> LateLintPass<'tcx> for FloatLiteral { return; } - if is_whole && !sym_str.contains(|c| c == 'e' || c == 'E') { + if is_whole && !sym_str.contains(['e', 'E']) { // Normalize the literal by stripping the fractional portion if sym_str.split('.').next().unwrap() != float_str { // If the type suffix is missing the suggestion would be diff --git a/src/tools/clippy/clippy_lints/src/floating_point_arithmetic.rs b/src/tools/clippy/clippy_lints/src/floating_point_arithmetic.rs index 46d47e217b04a..68bdf88d0a7e4 100644 --- a/src/tools/clippy/clippy_lints/src/floating_point_arithmetic.rs +++ b/src/tools/clippy/clippy_lints/src/floating_point_arithmetic.rs @@ -2,7 +2,8 @@ use clippy_utils::consts::Constant::{Int, F32, F64}; use clippy_utils::consts::{constant, constant_simple, Constant}; use clippy_utils::diagnostics::span_lint_and_sugg; use clippy_utils::{ - eq_expr_value, get_parent_expr, higher, in_constant, is_no_std_crate, numeric_literal, peel_blocks, sugg, + eq_expr_value, get_parent_expr, higher, in_constant, is_inherent_method_call, is_no_std_crate, numeric_literal, + peel_blocks, sugg, }; use rustc_errors::Applicability; use rustc_hir::{BinOpKind, Expr, ExprKind, PathSegment, UnOp}; @@ -759,7 +760,7 @@ impl<'tcx> LateLintPass<'tcx> for FloatingPointArithmetic { if let ExprKind::MethodCall(path, receiver, args, _) = &expr.kind { let recv_ty = cx.typeck_results().expr_ty(receiver); - if recv_ty.is_floating_point() && !is_no_std_crate(cx) { + if recv_ty.is_floating_point() && !is_no_std_crate(cx) && is_inherent_method_call(cx, expr) { match path.ident.name.as_str() { "ln" => check_ln1p(cx, expr, receiver), "log" => check_log_base(cx, expr, receiver, args), diff --git a/src/tools/clippy/clippy_lints/src/format_args.rs b/src/tools/clippy/clippy_lints/src/format_args.rs index 86115807aa4d1..99def199af0c2 100644 --- a/src/tools/clippy/clippy_lints/src/format_args.rs +++ b/src/tools/clippy/clippy_lints/src/format_args.rs @@ -424,14 +424,14 @@ impl<'a, 'tcx> FormatArgsExpr<'a, 'tcx> { count_needed_derefs(receiver_ty, cx.typeck_results().expr_adjustments(receiver).iter()) && implements_trait(cx, target, display_trait_id, &[]) && let Some(sized_trait_id) = cx.tcx.lang_items().sized_trait() - && let Some(receiver_snippet) = snippet_opt(cx, receiver.span) + && let Some(receiver_snippet) = snippet_opt(cx, receiver.span.source_callsite()) { let needs_ref = !implements_trait(cx, receiver_ty, sized_trait_id, &[]); if n_needed_derefs == 0 && !needs_ref { span_lint_and_sugg( cx, TO_STRING_IN_FORMAT_ARGS, - to_string_span.with_lo(receiver.span.hi()), + to_string_span.with_lo(receiver.span.source_callsite().hi()), format!("`to_string` applied to a type that implements `Display` in `{name}!` args"), "remove this", String::new(), diff --git a/src/tools/clippy/clippy_lints/src/functions/must_use.rs b/src/tools/clippy/clippy_lints/src/functions/must_use.rs index e7ec2b3151e6a..cce8617821e2c 100644 --- a/src/tools/clippy/clippy_lints/src/functions/must_use.rs +++ b/src/tools/clippy/clippy_lints/src/functions/must_use.rs @@ -14,7 +14,7 @@ use clippy_utils::attrs::is_proc_macro; use clippy_utils::diagnostics::{span_lint_and_help, span_lint_and_then}; use clippy_utils::source::snippet_opt; use clippy_utils::ty::is_must_use_ty; -use clippy_utils::visitors::for_each_expr; +use clippy_utils::visitors::for_each_expr_without_closures; use clippy_utils::{return_ty, trait_ref_of_method}; use core::ops::ControlFlow; @@ -226,7 +226,7 @@ fn is_mutated_static(e: &hir::Expr<'_>) -> bool { } fn mutates_static<'tcx>(cx: &LateContext<'tcx>, body: &'tcx hir::Body<'_>) -> bool { - for_each_expr(body.value, |e| { + for_each_expr_without_closures(body.value, |e| { use hir::ExprKind::{AddrOf, Assign, AssignOp, Call, MethodCall}; match e.kind { diff --git a/src/tools/clippy/clippy_lints/src/functions/not_unsafe_ptr_arg_deref.rs b/src/tools/clippy/clippy_lints/src/functions/not_unsafe_ptr_arg_deref.rs index b44a5f20ef68e..1aeefe73cf68f 100644 --- a/src/tools/clippy/clippy_lints/src/functions/not_unsafe_ptr_arg_deref.rs +++ b/src/tools/clippy/clippy_lints/src/functions/not_unsafe_ptr_arg_deref.rs @@ -5,7 +5,7 @@ use rustc_span::def_id::LocalDefId; use clippy_utils::diagnostics::span_lint; use clippy_utils::ty::type_is_unsafe_function; -use clippy_utils::visitors::for_each_expr_with_closures; +use clippy_utils::visitors::for_each_expr; use clippy_utils::{iter_input_pats, path_to_local}; use core::ops::ControlFlow; @@ -49,7 +49,7 @@ fn check_raw_ptr<'tcx>( if !raw_ptrs.is_empty() { let typeck = cx.tcx.typeck_body(body.id()); - let _: Option = for_each_expr_with_closures(cx, body.value, |e| { + let _: Option = for_each_expr(cx, body.value, |e| { match e.kind { hir::ExprKind::Call(f, args) if type_is_unsafe_function(cx, typeck.expr_ty(f)) => { for arg in args { diff --git a/src/tools/clippy/clippy_lints/src/implicit_return.rs b/src/tools/clippy/clippy_lints/src/implicit_return.rs index cc342007ec617..2f543781c44c1 100644 --- a/src/tools/clippy/clippy_lints/src/implicit_return.rs +++ b/src/tools/clippy/clippy_lints/src/implicit_return.rs @@ -1,6 +1,6 @@ use clippy_utils::diagnostics::span_lint_hir_and_then; use clippy_utils::source::{snippet_with_applicability, snippet_with_context, walk_span_to_context}; -use clippy_utils::visitors::for_each_expr; +use clippy_utils::visitors::for_each_expr_without_closures; use clippy_utils::{get_async_fn_body, is_async_fn}; use core::ops::ControlFlow; use rustc_errors::Applicability; @@ -153,7 +153,7 @@ fn lint_implicit_returns( ExprKind::Loop(block, ..) => { let mut add_return = false; - let _: Option = for_each_expr(block, |e| { + let _: Option = for_each_expr_without_closures(block, |e| { if let ExprKind::Break(dest, sub_expr) = e.kind { if dest.target_id.ok() == Some(expr.hir_id) { if call_site_span.is_none() && e.span.ctxt() == ctxt { diff --git a/src/tools/clippy/clippy_lints/src/implied_bounds_in_impls.rs b/src/tools/clippy/clippy_lints/src/implied_bounds_in_impls.rs index 2b389d4f9b194..170ecf896b4e1 100644 --- a/src/tools/clippy/clippy_lints/src/implied_bounds_in_impls.rs +++ b/src/tools/clippy/clippy_lints/src/implied_bounds_in_impls.rs @@ -3,8 +3,8 @@ use clippy_utils::source::snippet; use rustc_errors::{Applicability, SuggestionStyle}; use rustc_hir::def_id::DefId; use rustc_hir::{ - GenericArg, GenericBound, GenericBounds, ItemKind, PredicateOrigin, TraitBoundModifier, TyKind, AssocItemConstraint, - WherePredicate, + AssocItemConstraint, GenericArg, GenericBound, GenericBounds, ItemKind, PredicateOrigin, TraitBoundModifier, + TyKind, WherePredicate, }; use rustc_hir_analysis::lower_ty; use rustc_lint::{LateContext, LateLintPass}; @@ -83,8 +83,8 @@ fn emit_lint( let mut sugg = vec![(implied_span_extended, String::new())]; - // We also might need to include associated item constraints that were specified in the implied bound, - // but omitted in the implied-by bound: + // We also might need to include associated item constraints that were specified in the implied + // bound, but omitted in the implied-by bound: // `fn f() -> impl Deref + DerefMut` // If we're going to suggest removing `Deref<..>`, we'll need to put `` on `DerefMut` let omitted_constraints: Vec<_> = implied_constraints diff --git a/src/tools/clippy/clippy_lints/src/indexing_slicing.rs b/src/tools/clippy/clippy_lints/src/indexing_slicing.rs index e3e79749bea60..d54f2af65cdea 100644 --- a/src/tools/clippy/clippy_lints/src/indexing_slicing.rs +++ b/src/tools/clippy/clippy_lints/src/indexing_slicing.rs @@ -2,12 +2,14 @@ use clippy_utils::consts::{constant, Constant}; use clippy_utils::diagnostics::{span_lint, span_lint_and_then}; -use clippy_utils::higher; +use clippy_utils::ty::{deref_chain, get_adt_inherent_method}; +use clippy_utils::{higher, is_from_proc_macro}; use rustc_ast::ast::RangeLimits; use rustc_hir::{Expr, ExprKind}; use rustc_lint::{LateContext, LateLintPass}; -use rustc_middle::ty; +use rustc_middle::ty::{self, Ty}; use rustc_session::impl_lint_pass; +use rustc_span::sym; declare_clippy_lint! { /// ### What it does @@ -100,11 +102,21 @@ impl IndexingSlicing { impl<'tcx> LateLintPass<'tcx> for IndexingSlicing { fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>) { - if self.suppress_restriction_lint_in_const && cx.tcx.hir().is_inside_const_context(expr.hir_id) { + if (self.suppress_restriction_lint_in_const && cx.tcx.hir().is_inside_const_context(expr.hir_id)) + || is_from_proc_macro(cx, expr) + { return; } - if let ExprKind::Index(array, index, _) = &expr.kind { + if let ExprKind::Index(array, index, _) = &expr.kind + && let expr_ty = cx.typeck_results().expr_ty(array) + && let mut deref = deref_chain(cx, expr_ty) + && deref.any(|l| { + l.peel_refs().is_slice() + || l.peel_refs().is_array() + || ty_has_applicable_get_function(cx, l.peel_refs(), expr_ty, expr) + }) + { let note = "the suggestion might not be applicable in constant blocks"; let ty = cx.typeck_results().expr_ty(array).peel_refs(); if let Some(range) = higher::Range::hir(index) { @@ -231,3 +243,33 @@ fn to_const_range(cx: &LateContext<'_>, range: higher::Range<'_>, array_size: u1 (start, end) } + +/// Checks if the output Ty of the `get` method on this Ty (if any) matches the Ty returned by the +/// indexing operation (if any). +fn ty_has_applicable_get_function<'tcx>( + cx: &LateContext<'tcx>, + ty: Ty<'tcx>, + array_ty: Ty<'tcx>, + index_expr: &Expr<'_>, +) -> bool { + if let ty::Adt(_, _) = array_ty.kind() + && let Some(get_output_ty) = get_adt_inherent_method(cx, ty, sym!(get)).map(|m| { + cx.tcx + .fn_sig(m.def_id) + .skip_binder() + .output() + .skip_binder() + }) + && let ty::Adt(def, args) = get_output_ty.kind() + && cx.tcx.is_diagnostic_item(sym::Option, def.0.did) + && let Some(option_generic_param) = args.first() + && let generic_ty = option_generic_param.expect_ty().peel_refs() + // FIXME: ideally this would handle type params and projections properly, for now just assume it's the same type + && (cx.typeck_results().expr_ty(index_expr).peel_refs() == generic_ty.peel_refs() + || matches!(generic_ty.peel_refs().kind(), ty::Param(_) | ty::Alias(_, _))) + { + true + } else { + false + } +} diff --git a/src/tools/clippy/clippy_lints/src/integer_division_remainder_used.rs b/src/tools/clippy/clippy_lints/src/integer_division_remainder_used.rs index cf598d5045ec3..a1215491b48c3 100644 --- a/src/tools/clippy/clippy_lints/src/integer_division_remainder_used.rs +++ b/src/tools/clippy/clippy_lints/src/integer_division_remainder_used.rs @@ -22,7 +22,7 @@ declare_clippy_lint! { /// ```no_run /// let my_div = 10 >> 1; /// ``` - #[clippy::version = "1.78.0"] + #[clippy::version = "1.79.0"] pub INTEGER_DIVISION_REMAINDER_USED, restriction, "use of disallowed default division and remainder operations" diff --git a/src/tools/clippy/clippy_lints/src/iter_without_into_iter.rs b/src/tools/clippy/clippy_lints/src/iter_without_into_iter.rs index 601d0e151aae8..6b03f2597b083 100644 --- a/src/tools/clippy/clippy_lints/src/iter_without_into_iter.rs +++ b/src/tools/clippy/clippy_lints/src/iter_without_into_iter.rs @@ -1,7 +1,7 @@ use clippy_utils::diagnostics::span_lint_and_then; use clippy_utils::get_parent_as_impl; use clippy_utils::source::snippet; -use clippy_utils::ty::{implements_trait, make_normalized_projection}; +use clippy_utils::ty::{deref_chain, get_adt_inherent_method, implements_trait, make_normalized_projection}; use rustc_ast::Mutability; use rustc_errors::Applicability; use rustc_hir::{FnRetTy, ImplItemKind, ImplicitSelfKind, ItemKind, TyKind}; @@ -9,8 +9,7 @@ use rustc_lint::{LateContext, LateLintPass, LintContext}; use rustc_middle::lint::in_external_macro; use rustc_middle::ty::{self, Ty}; use rustc_session::declare_lint_pass; -use rustc_span::{sym, Symbol}; -use std::iter; +use rustc_span::sym; declare_clippy_lint! { /// ### What it does @@ -124,33 +123,6 @@ fn is_ty_exported(cx: &LateContext<'_>, ty: Ty<'_>) -> bool { .is_some_and(|did| cx.effective_visibilities.is_exported(did)) } -/// Returns the deref chain of a type, starting with the type itself. -fn deref_chain<'cx, 'tcx>(cx: &'cx LateContext<'tcx>, ty: Ty<'tcx>) -> impl Iterator> + 'cx { - iter::successors(Some(ty), |&ty| { - if let Some(deref_did) = cx.tcx.lang_items().deref_trait() - && implements_trait(cx, ty, deref_did, &[]) - { - make_normalized_projection(cx.tcx, cx.param_env, deref_did, sym::Target, [ty]) - } else { - None - } - }) -} - -fn adt_has_inherent_method(cx: &LateContext<'_>, ty: Ty<'_>, method_name: Symbol) -> bool { - if let Some(ty_did) = ty.ty_adt_def().map(ty::AdtDef::did) { - cx.tcx.inherent_impls(ty_did).into_iter().flatten().any(|&did| { - cx.tcx - .associated_items(did) - .filter_by_name_unhygienic(method_name) - .next() - .is_some_and(|item| item.kind == ty::AssocKind::Fn) - }) - } else { - false - } -} - impl LateLintPass<'_> for IterWithoutIntoIter { fn check_item(&mut self, cx: &LateContext<'_>, item: &rustc_hir::Item<'_>) { if !in_external_macro(cx.sess(), item.span) @@ -167,7 +139,7 @@ impl LateLintPass<'_> for IterWithoutIntoIter { } && !deref_chain(cx, ty).any(|ty| { // We can't check inherent impls for slices, but we know that they have an `iter(_mut)` method - ty.peel_refs().is_slice() || adt_has_inherent_method(cx, ty, expected_method_name) + ty.peel_refs().is_slice() || get_adt_inherent_method(cx, ty, expected_method_name).is_some() }) && let Some(iter_assoc_span) = imp.items.iter().find_map(|item| { if item.ident.name == sym!(IntoIter) { diff --git a/src/tools/clippy/clippy_lints/src/legacy_numeric_constants.rs b/src/tools/clippy/clippy_lints/src/legacy_numeric_constants.rs index 00124dcdd91dc..eadfeb6e34181 100644 --- a/src/tools/clippy/clippy_lints/src/legacy_numeric_constants.rs +++ b/src/tools/clippy/clippy_lints/src/legacy_numeric_constants.rs @@ -28,7 +28,7 @@ declare_clippy_lint! { /// ```rust /// let eps = f32::EPSILON; /// ``` - #[clippy::version = "1.72.0"] + #[clippy::version = "1.79.0"] pub LEGACY_NUMERIC_CONSTANTS, style, "checks for usage of legacy std numeric constants and methods" diff --git a/src/tools/clippy/clippy_lints/src/lib.deprecated.rs b/src/tools/clippy/clippy_lints/src/lib.deprecated.rs index 80bde1b11384b..0d21261822dd0 100644 --- a/src/tools/clippy/clippy_lints/src/lib.deprecated.rs +++ b/src/tools/clippy/clippy_lints/src/lib.deprecated.rs @@ -67,4 +67,12 @@ "clippy::wrong_pub_self_convention", "set the `avoid-breaking-exported-api` config option to `false` to enable the `wrong_self_convention` lint for public items", ); + store.register_removed( + "clippy::maybe_misused_cfg", + "this lint has been replaced by `unexpected_cfgs`", + ); + store.register_removed( + "clippy::mismatched_target_os", + "this lint has been replaced by `unexpected_cfgs`", + ); } diff --git a/src/tools/clippy/clippy_lints/src/lib.rs b/src/tools/clippy/clippy_lints/src/lib.rs index 3328d642bd855..c65581d5203e9 100644 --- a/src/tools/clippy/clippy_lints/src/lib.rs +++ b/src/tools/clippy/clippy_lints/src/lib.rs @@ -251,6 +251,7 @@ mod needless_else; mod needless_for_each; mod needless_if; mod needless_late_init; +mod needless_maybe_sized; mod needless_parens_on_range_literals; mod needless_pass_by_ref_mut; mod needless_pass_by_value; @@ -325,6 +326,7 @@ mod size_of_in_element_count; mod size_of_ref; mod slow_vector_initialization; mod std_instead_of_core; +mod string_patterns; mod strings; mod strlen_on_c_strings; mod suspicious_operation_groupings; @@ -1058,6 +1060,7 @@ pub fn register_lints(store: &mut rustc_lint::LintStore, conf: &'static Conf) { store.register_late_pass(|_| Box::new(no_mangle_with_rust_abi::NoMangleWithRustAbi)); store.register_late_pass(|_| Box::new(collection_is_never_read::CollectionIsNeverRead)); store.register_late_pass(|_| Box::new(missing_assert_message::MissingAssertMessage)); + store.register_late_pass(|_| Box::new(needless_maybe_sized::NeedlessMaybeSized)); store.register_late_pass(|_| Box::new(redundant_async_block::RedundantAsyncBlock)); store.register_late_pass(|_| Box::new(let_with_type_underscore::UnderscoreTyped)); store.register_late_pass(|_| Box::new(allow_attributes::AllowAttribute)); @@ -1165,6 +1168,7 @@ pub fn register_lints(store: &mut rustc_lint::LintStore, conf: &'static Conf) { ..Default::default() }) }); + store.register_late_pass(|_| Box::new(string_patterns::StringPatterns)); // add lints here, do not remove this comment, it's used in `new_lint` } diff --git a/src/tools/clippy/clippy_lints/src/manual_unwrap_or_default.rs b/src/tools/clippy/clippy_lints/src/manual_unwrap_or_default.rs index 84fb183e3f798..17399fb2cc212 100644 --- a/src/tools/clippy/clippy_lints/src/manual_unwrap_or_default.rs +++ b/src/tools/clippy/clippy_lints/src/manual_unwrap_or_default.rs @@ -43,7 +43,7 @@ declare_clippy_lint! { /// let x: Option> = Some(Vec::new()); /// let y: Vec = x.unwrap_or_default(); /// ``` - #[clippy::version = "1.78.0"] + #[clippy::version = "1.79.0"] pub MANUAL_UNWRAP_OR_DEFAULT, suspicious, "check if a `match` or `if let` can be simplified with `unwrap_or_default`" @@ -57,7 +57,8 @@ fn get_some<'tcx>(cx: &LateContext<'tcx>, pat: &Pat<'tcx>) -> Option { // Since it comes from a pattern binding, we need to get the parent to actually match // against it. && let Some(def_id) = cx.tcx.opt_parent(def_id) - && cx.tcx.lang_items().get(LangItem::OptionSome) == Some(def_id) + && (cx.tcx.lang_items().get(LangItem::OptionSome) == Some(def_id) + || cx.tcx.lang_items().get(LangItem::ResultOk) == Some(def_id)) { let mut bindings = Vec::new(); pat.each_binding(|_, id, _, _| bindings.push(id)); @@ -80,6 +81,14 @@ fn get_none<'tcx>(cx: &LateContext<'tcx>, arm: &Arm<'tcx>) -> Option<&'tcx Expr< && cx.tcx.lang_items().get(LangItem::OptionNone) == Some(def_id) { Some(arm.body) + } else if let PatKind::TupleStruct(QPath::Resolved(_, path), _, _)= arm.pat.kind + && let Some(def_id) = path.res.opt_def_id() + // Since it comes from a pattern binding, we need to get the parent to actually match + // against it. + && let Some(def_id) = cx.tcx.opt_parent(def_id) + && cx.tcx.lang_items().get(LangItem::ResultErr) == Some(def_id) + { + Some(arm.body) } else if let PatKind::Wild = arm.pat.kind { // We consider that the `Some` check will filter it out if it's not right. Some(arm.body) diff --git a/src/tools/clippy/clippy_lints/src/matches/redundant_guards.rs b/src/tools/clippy/clippy_lints/src/matches/redundant_guards.rs index a75cf37945f77..c2c0fbf439d51 100644 --- a/src/tools/clippy/clippy_lints/src/matches/redundant_guards.rs +++ b/src/tools/clippy/clippy_lints/src/matches/redundant_guards.rs @@ -2,7 +2,7 @@ use clippy_config::msrvs::Msrv; use clippy_utils::diagnostics::span_lint_and_then; use clippy_utils::macros::matching_root_macro_call; use clippy_utils::source::snippet; -use clippy_utils::visitors::{for_each_expr, is_local_used}; +use clippy_utils::visitors::{for_each_expr_without_closures, is_local_used}; use clippy_utils::{in_constant, path_to_local}; use rustc_ast::{BorrowKind, LitKind}; use rustc_errors::Applicability; @@ -249,7 +249,7 @@ fn emit_redundant_guards<'tcx>( /// an error in the future, and rustc already actively warns against this (see rust#41620), /// so we don't consider those as usable within patterns for linting purposes. fn expr_can_be_pat(cx: &LateContext<'_>, expr: &Expr<'_>) -> bool { - for_each_expr(expr, |expr| { + for_each_expr_without_closures(expr, |expr| { if match expr.kind { ExprKind::ConstBlock(..) => cx.tcx.features().inline_const_pat, ExprKind::Call(c, ..) if let ExprKind::Path(qpath) = c.kind => { diff --git a/src/tools/clippy/clippy_lints/src/matches/redundant_pattern_match.rs b/src/tools/clippy/clippy_lints/src/matches/redundant_pattern_match.rs index 78973984fb0bb..0e4b2d9d34a02 100644 --- a/src/tools/clippy/clippy_lints/src/matches/redundant_pattern_match.rs +++ b/src/tools/clippy/clippy_lints/src/matches/redundant_pattern_match.rs @@ -3,7 +3,7 @@ use clippy_utils::diagnostics::{span_lint_and_sugg, span_lint_and_then}; use clippy_utils::source::{snippet, walk_span_to_context}; use clippy_utils::sugg::{make_unop, Sugg}; use clippy_utils::ty::{is_type_diagnostic_item, needs_ordered_drop}; -use clippy_utils::visitors::{any_temporaries_need_ordered_drop, for_each_expr}; +use clippy_utils::visitors::{any_temporaries_need_ordered_drop, for_each_expr_without_closures}; use clippy_utils::{higher, is_expn_of, is_trait_method}; use rustc_ast::ast::LitKind; use rustc_errors::Applicability; @@ -283,7 +283,7 @@ pub(super) fn check_match<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>, op // to see that there aren't any let chains anywhere in the guard, as that would break // if we suggest `t.is_none() && (let X = y && z)` for: // `match t { None if let X = y && z => true, _ => false }` - let has_nested_let_chain = for_each_expr(guard, |expr| { + let has_nested_let_chain = for_each_expr_without_closures(guard, |expr| { if matches!(expr.kind, ExprKind::Let(..)) { ControlFlow::Break(()) } else { diff --git a/src/tools/clippy/clippy_lints/src/methods/collapsible_str_replace.rs b/src/tools/clippy/clippy_lints/src/methods/collapsible_str_replace.rs index 5409ede6008b6..1fab6c0e499d4 100644 --- a/src/tools/clippy/clippy_lints/src/methods/collapsible_str_replace.rs +++ b/src/tools/clippy/clippy_lints/src/methods/collapsible_str_replace.rs @@ -1,6 +1,6 @@ use clippy_utils::diagnostics::span_lint_and_sugg; use clippy_utils::source::snippet; -use clippy_utils::visitors::for_each_expr; +use clippy_utils::visitors::for_each_expr_without_closures; use clippy_utils::{eq_expr_value, get_parent_expr}; use core::ops::ControlFlow; use rustc_errors::Applicability; @@ -46,7 +46,7 @@ fn collect_replace_calls<'tcx>( let mut methods = VecDeque::new(); let mut from_args = VecDeque::new(); - let _: Option<()> = for_each_expr(expr, |e| { + let _: Option<()> = for_each_expr_without_closures(expr, |e| { if let Some(("replace", _, [from, to], _, _)) = method_call(e) { if eq_expr_value(cx, to_arg, to) && cx.typeck_results().expr_ty(from).peel_refs().is_char() { methods.push_front(e); diff --git a/src/tools/clippy/clippy_lints/src/methods/mod.rs b/src/tools/clippy/clippy_lints/src/methods/mod.rs index 75a86c0c83448..6200716afbe99 100644 --- a/src/tools/clippy/clippy_lints/src/methods/mod.rs +++ b/src/tools/clippy/clippy_lints/src/methods/mod.rs @@ -66,6 +66,7 @@ mod map_flatten; mod map_identity; mod map_unwrap_or; mod mut_mutex_lock; +mod needless_character_iteration; mod needless_collect; mod needless_option_as_deref; mod needless_option_take; @@ -93,7 +94,6 @@ mod seek_from_current; mod seek_to_start_instead_of_rewind; mod single_char_add_str; mod single_char_insert_string; -mod single_char_pattern; mod single_char_push_string; mod skip_while_next; mod stable_sort_primitive; @@ -1140,38 +1140,6 @@ declare_clippy_lint! { "not returning type containing `Self` in a `new` method" } -declare_clippy_lint! { - /// ### What it does - /// Checks for string methods that receive a single-character - /// `str` as an argument, e.g., `_.split("x")`. - /// - /// ### Why is this bad? - /// While this can make a perf difference on some systems, - /// benchmarks have proven inconclusive. But at least using a - /// char literal makes it clear that we are looking at a single - /// character. - /// - /// ### Known problems - /// Does not catch multi-byte unicode characters. This is by - /// design, on many machines, splitting by a non-ascii char is - /// actually slower. Please do your own measurements instead of - /// relying solely on the results of this lint. - /// - /// ### Example - /// ```rust,ignore - /// _.split("x"); - /// ``` - /// - /// Use instead: - /// ```rust,ignore - /// _.split('x'); - /// ``` - #[clippy::version = "pre 1.29.0"] - pub SINGLE_CHAR_PATTERN, - pedantic, - "using a single-character str where a char could be used, e.g., `_.split(\"x\")`" -} - declare_clippy_lint! { /// ### What it does /// Checks for calling `.step_by(0)` on iterators which panics. @@ -4084,12 +4052,33 @@ declare_clippy_lint! { /// ```no_run /// println!("the string is empty"); /// ``` - #[clippy::version = "1.78.0"] + #[clippy::version = "1.79.0"] pub CONST_IS_EMPTY, suspicious, "is_empty() called on strings known at compile time" } +declare_clippy_lint! { + /// ### What it does + /// Checks if an iterator is used to check if a string is ascii. + /// + /// ### Why is this bad? + /// The `str` type already implements the `is_ascii` method. + /// + /// ### Example + /// ```no_run + /// "foo".chars().all(|c| c.is_ascii()); + /// ``` + /// Use instead: + /// ```no_run + /// "foo".is_ascii(); + /// ``` + #[clippy::version = "1.80.0"] + pub NEEDLESS_CHARACTER_ITERATION, + suspicious, + "is_ascii() called on a char iterator" +} + pub struct Methods { avoid_breaking_exported_api: bool, msrv: Msrv, @@ -4147,7 +4136,6 @@ impl_lint_pass!(Methods => [ FLAT_MAP_OPTION, INEFFICIENT_TO_STRING, NEW_RET_NO_SELF, - SINGLE_CHAR_PATTERN, SINGLE_CHAR_ADD_STR, SEARCH_IS_SOME, FILTER_NEXT, @@ -4255,6 +4243,7 @@ impl_lint_pass!(Methods => [ UNNECESSARY_RESULT_MAP_OR_ELSE, MANUAL_C_STR_LITERALS, UNNECESSARY_GET_THEN_CHECK, + NEEDLESS_CHARACTER_ITERATION, ]); /// Extracts a method call name, args, and `Span` of the method name. @@ -4301,7 +4290,6 @@ impl<'tcx> LateLintPass<'tcx> for Methods { inefficient_to_string::check(cx, expr, method_call.ident.name, receiver, args); single_char_add_str::check(cx, expr, receiver, args); into_iter_on_ref::check(cx, expr, method_span, method_call.ident.name, receiver); - single_char_pattern::check(cx, expr, method_call.ident.name, receiver, args); unnecessary_to_owned::check(cx, expr, method_call.ident.name, receiver, args, &self.msrv); }, ExprKind::Binary(op, lhs, rhs) if op.node == hir::BinOpKind::Eq || op.node == hir::BinOpKind::Ne => { @@ -4462,6 +4450,7 @@ impl Methods { }, ("all", [arg]) => { unused_enumerate_index::check(cx, expr, recv, arg); + needless_character_iteration::check(cx, expr, recv, arg, true); if let Some(("cloned", recv2, [], _, _)) = method_call(recv) { iter_overeager_cloned::check( cx, @@ -4482,6 +4471,7 @@ impl Methods { }, ("any", [arg]) => { unused_enumerate_index::check(cx, expr, recv, arg); + needless_character_iteration::check(cx, expr, recv, arg, false); match method_call(recv) { Some(("cloned", recv2, [], _, _)) => iter_overeager_cloned::check( cx, diff --git a/src/tools/clippy/clippy_lints/src/methods/needless_character_iteration.rs b/src/tools/clippy/clippy_lints/src/methods/needless_character_iteration.rs new file mode 100644 index 0000000000000..e3d7820771547 --- /dev/null +++ b/src/tools/clippy/clippy_lints/src/methods/needless_character_iteration.rs @@ -0,0 +1,124 @@ +use rustc_errors::Applicability; +use rustc_hir::{Closure, Expr, ExprKind, HirId, StmtKind, UnOp}; +use rustc_lint::LateContext; +use rustc_middle::ty; +use rustc_span::Span; + +use super::utils::get_last_chain_binding_hir_id; +use super::NEEDLESS_CHARACTER_ITERATION; +use clippy_utils::diagnostics::span_lint_and_sugg; +use clippy_utils::source::snippet_opt; +use clippy_utils::{match_def_path, path_to_local_id, peel_blocks}; + +fn peels_expr_ref<'a, 'tcx>(mut expr: &'a Expr<'tcx>) -> &'a Expr<'tcx> { + while let ExprKind::AddrOf(_, _, e) = expr.kind { + expr = e; + } + expr +} + +fn handle_expr( + cx: &LateContext<'_>, + expr: &Expr<'_>, + first_param: HirId, + span: Span, + before_chars: Span, + revert: bool, + is_all: bool, +) { + match expr.kind { + ExprKind::MethodCall(method, receiver, [], _) => { + // If we have `!is_ascii`, then only `.any()` should warn. And if the condition is + // `is_ascii`, then only `.all()` should warn. + if revert != is_all + && method.ident.name.as_str() == "is_ascii" + && path_to_local_id(receiver, first_param) + && let char_arg_ty = cx.typeck_results().expr_ty_adjusted(receiver).peel_refs() + && *char_arg_ty.kind() == ty::Char + && let Some(snippet) = snippet_opt(cx, before_chars) + { + span_lint_and_sugg( + cx, + NEEDLESS_CHARACTER_ITERATION, + span, + "checking if a string is ascii using iterators", + "try", + format!("{}{snippet}.is_ascii()", if revert { "!" } else { "" }), + Applicability::MachineApplicable, + ); + } + }, + ExprKind::Block(block, _) => { + if block.stmts.iter().any(|stmt| !matches!(stmt.kind, StmtKind::Let(_))) { + // If there is something else than let bindings, then better not emit the lint. + return; + } + if let Some(block_expr) = block.expr + // First we ensure that this is a "binding chain" (each statement is a binding + // of the previous one) and that it is a binding of the closure argument. + && let Some(last_chain_binding_id) = + get_last_chain_binding_hir_id(first_param, block.stmts) + { + handle_expr( + cx, + block_expr, + last_chain_binding_id, + span, + before_chars, + revert, + is_all, + ); + } + }, + ExprKind::Unary(UnOp::Not, expr) => handle_expr(cx, expr, first_param, span, before_chars, !revert, is_all), + ExprKind::Call(fn_path, [arg]) => { + // If we have `!is_ascii`, then only `.any()` should warn. And if the condition is + // `is_ascii`, then only `.all()` should warn. + if revert != is_all + && let ExprKind::Path(path) = fn_path.kind + && let Some(fn_def_id) = cx.qpath_res(&path, fn_path.hir_id).opt_def_id() + && match_def_path(cx, fn_def_id, &["core", "char", "methods", "", "is_ascii"]) + && path_to_local_id(peels_expr_ref(arg), first_param) + && let Some(snippet) = snippet_opt(cx, before_chars) + { + span_lint_and_sugg( + cx, + NEEDLESS_CHARACTER_ITERATION, + span, + "checking if a string is ascii using iterators", + "try", + format!("{}{snippet}.is_ascii()", if revert { "!" } else { "" }), + Applicability::MachineApplicable, + ); + } + }, + _ => {}, + } +} + +pub(super) fn check(cx: &LateContext<'_>, call_expr: &Expr<'_>, recv: &Expr<'_>, closure_arg: &Expr<'_>, is_all: bool) { + if let ExprKind::Closure(&Closure { body, .. }) = closure_arg.kind + && let body = cx.tcx.hir().body(body) + && let Some(first_param) = body.params.first() + && let ExprKind::MethodCall(method, mut recv, [], _) = recv.kind + && method.ident.name.as_str() == "chars" + && let str_ty = cx.typeck_results().expr_ty_adjusted(recv).peel_refs() + && *str_ty.kind() == ty::Str + { + let expr_start = recv.span; + while let ExprKind::MethodCall(_, new_recv, _, _) = recv.kind { + recv = new_recv; + } + let body_expr = peel_blocks(body.value); + + handle_expr( + cx, + body_expr, + first_param.pat.hir_id, + recv.span.with_hi(call_expr.span.hi()), + recv.span.with_hi(expr_start.hi()), + false, + is_all, + ); + } +} diff --git a/src/tools/clippy/clippy_lints/src/methods/option_map_unwrap_or.rs b/src/tools/clippy/clippy_lints/src/methods/option_map_unwrap_or.rs index ca331f3e7568a..3d326bc99f95c 100644 --- a/src/tools/clippy/clippy_lints/src/methods/option_map_unwrap_or.rs +++ b/src/tools/clippy/clippy_lints/src/methods/option_map_unwrap_or.rs @@ -60,7 +60,7 @@ pub(super) fn check<'tcx>( let map = cx.tcx.hir(); let body = map.body_owned_by(map.enclosing_body_owner(expr.hir_id)); - reference_visitor.visit_body(&body); + reference_visitor.visit_body(body); if reference_visitor.found_reference { return; diff --git a/src/tools/clippy/clippy_lints/src/methods/path_buf_push_overwrite.rs b/src/tools/clippy/clippy_lints/src/methods/path_buf_push_overwrite.rs index 04a27cc98f3c3..2d3007e50b81c 100644 --- a/src/tools/clippy/clippy_lints/src/methods/path_buf_push_overwrite.rs +++ b/src/tools/clippy/clippy_lints/src/methods/path_buf_push_overwrite.rs @@ -27,7 +27,7 @@ pub(super) fn check<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>, arg: &'t lit.span, "calling `push` with '/' or '\\' (file system root) will overwrite the previous path definition", "try", - format!("\"{}\"", pushed_path_lit.trim_start_matches(|c| c == '/' || c == '\\')), + format!("\"{}\"", pushed_path_lit.trim_start_matches(['/', '\\'])), Applicability::MachineApplicable, ); } diff --git a/src/tools/clippy/clippy_lints/src/methods/search_is_some.rs b/src/tools/clippy/clippy_lints/src/methods/search_is_some.rs index f5f1e94bbf455..3b2dd285b8c99 100644 --- a/src/tools/clippy/clippy_lints/src/methods/search_is_some.rs +++ b/src/tools/clippy/clippy_lints/src/methods/search_is_some.rs @@ -2,7 +2,7 @@ use clippy_utils::diagnostics::{span_lint_and_help, span_lint_and_sugg}; use clippy_utils::source::{snippet, snippet_with_applicability}; use clippy_utils::sugg::deref_closure_args; use clippy_utils::ty::is_type_lang_item; -use clippy_utils::{get_parent_expr, is_trait_method, strip_pat_refs}; +use clippy_utils::{is_receiver_of_method_call, is_trait_method, strip_pat_refs}; use hir::ExprKind; use rustc_errors::Applicability; use rustc_hir as hir; @@ -156,13 +156,3 @@ pub(super) fn check<'tcx>( } } } - -fn is_receiver_of_method_call(cx: &LateContext<'_>, expr: &hir::Expr<'_>) -> bool { - if let Some(parent_expr) = get_parent_expr(cx, expr) - && let ExprKind::MethodCall(_, receiver, ..) = parent_expr.kind - && receiver.hir_id == expr.hir_id - { - return true; - } - false -} diff --git a/src/tools/clippy/clippy_lints/src/methods/single_char_insert_string.rs b/src/tools/clippy/clippy_lints/src/methods/single_char_insert_string.rs index 20ec2b74d81e4..e2f76ac114c6a 100644 --- a/src/tools/clippy/clippy_lints/src/methods/single_char_insert_string.rs +++ b/src/tools/clippy/clippy_lints/src/methods/single_char_insert_string.rs @@ -1,8 +1,8 @@ -use super::utils::get_hint_if_single_char_arg; use clippy_utils::diagnostics::span_lint_and_sugg; -use clippy_utils::source::snippet_with_applicability; +use clippy_utils::source::{snippet_with_applicability, str_literal_to_char_literal}; +use rustc_ast::BorrowKind; use rustc_errors::Applicability; -use rustc_hir as hir; +use rustc_hir::{self as hir, ExprKind}; use rustc_lint::LateContext; use super::SINGLE_CHAR_ADD_STR; @@ -10,7 +10,7 @@ use super::SINGLE_CHAR_ADD_STR; /// lint for length-1 `str`s as argument for `insert_str` pub(super) fn check(cx: &LateContext<'_>, expr: &hir::Expr<'_>, receiver: &hir::Expr<'_>, args: &[hir::Expr<'_>]) { let mut applicability = Applicability::MachineApplicable; - if let Some(extension_string) = get_hint_if_single_char_arg(cx, &args[1], &mut applicability, false) { + if let Some(extension_string) = str_literal_to_char_literal(cx, &args[1], &mut applicability, false) { let base_string_snippet = snippet_with_applicability(cx, receiver.span.source_callsite(), "_", &mut applicability); let pos_arg = snippet_with_applicability(cx, args[0].span, "..", &mut applicability); @@ -25,4 +25,43 @@ pub(super) fn check(cx: &LateContext<'_>, expr: &hir::Expr<'_>, receiver: &hir:: applicability, ); } + + if let ExprKind::AddrOf(BorrowKind::Ref, _, arg) = &args[1].kind + && let ExprKind::MethodCall(path_segment, method_arg, _, _) = &arg.kind + && path_segment.ident.name == rustc_span::sym::to_string + && (is_ref_char(cx, method_arg) || is_char(cx, method_arg)) + { + let base_string_snippet = + snippet_with_applicability(cx, receiver.span.source_callsite(), "..", &mut applicability); + let extension_string = + snippet_with_applicability(cx, method_arg.span.source_callsite(), "..", &mut applicability); + let pos_arg = snippet_with_applicability(cx, args[0].span, "..", &mut applicability); + let deref_string = if is_ref_char(cx, method_arg) { "*" } else { "" }; + + let sugg = format!("{base_string_snippet}.insert({pos_arg}, {deref_string}{extension_string})"); + span_lint_and_sugg( + cx, + SINGLE_CHAR_ADD_STR, + expr.span, + "calling `insert_str()` using a single-character converted to string", + "consider using `insert` without `to_string()`", + sugg, + applicability, + ); + } +} + +fn is_ref_char(cx: &LateContext<'_>, expr: &hir::Expr<'_>) -> bool { + if cx.typeck_results().expr_ty(expr).is_ref() + && let rustc_middle::ty::Ref(_, ty, _) = cx.typeck_results().expr_ty(expr).kind() + && ty.is_char() + { + return true; + } + + false +} + +fn is_char(cx: &LateContext<'_>, expr: &hir::Expr<'_>) -> bool { + cx.typeck_results().expr_ty(expr).is_char() } diff --git a/src/tools/clippy/clippy_lints/src/methods/single_char_pattern.rs b/src/tools/clippy/clippy_lints/src/methods/single_char_pattern.rs deleted file mode 100644 index 982a7901c4537..0000000000000 --- a/src/tools/clippy/clippy_lints/src/methods/single_char_pattern.rs +++ /dev/null @@ -1,64 +0,0 @@ -use super::utils::get_hint_if_single_char_arg; -use clippy_utils::diagnostics::span_lint_and_sugg; -use rustc_errors::Applicability; -use rustc_hir as hir; -use rustc_lint::LateContext; -use rustc_middle::ty; -use rustc_span::symbol::Symbol; - -use super::SINGLE_CHAR_PATTERN; - -const PATTERN_METHODS: [(&str, usize); 22] = [ - ("contains", 0), - ("starts_with", 0), - ("ends_with", 0), - ("find", 0), - ("rfind", 0), - ("split", 0), - ("split_inclusive", 0), - ("rsplit", 0), - ("split_terminator", 0), - ("rsplit_terminator", 0), - ("splitn", 1), - ("rsplitn", 1), - ("split_once", 0), - ("rsplit_once", 0), - ("matches", 0), - ("rmatches", 0), - ("match_indices", 0), - ("rmatch_indices", 0), - ("trim_start_matches", 0), - ("trim_end_matches", 0), - ("replace", 0), - ("replacen", 0), -]; - -/// lint for length-1 `str`s for methods in `PATTERN_METHODS` -pub(super) fn check( - cx: &LateContext<'_>, - _expr: &hir::Expr<'_>, - method_name: Symbol, - receiver: &hir::Expr<'_>, - args: &[hir::Expr<'_>], -) { - for &(method, pos) in &PATTERN_METHODS { - if let ty::Ref(_, ty, _) = cx.typeck_results().expr_ty_adjusted(receiver).kind() - && ty.is_str() - && method_name.as_str() == method - && args.len() > pos - && let arg = &args[pos] - && let mut applicability = Applicability::MachineApplicable - && let Some(hint) = get_hint_if_single_char_arg(cx, arg, &mut applicability, true) - { - span_lint_and_sugg( - cx, - SINGLE_CHAR_PATTERN, - arg.span, - "single-character string constant used as pattern", - "consider using a `char`", - hint, - applicability, - ); - } - } -} diff --git a/src/tools/clippy/clippy_lints/src/methods/single_char_push_string.rs b/src/tools/clippy/clippy_lints/src/methods/single_char_push_string.rs index 97c13825bc104..4ae8634305da6 100644 --- a/src/tools/clippy/clippy_lints/src/methods/single_char_push_string.rs +++ b/src/tools/clippy/clippy_lints/src/methods/single_char_push_string.rs @@ -1,8 +1,8 @@ -use super::utils::get_hint_if_single_char_arg; use clippy_utils::diagnostics::span_lint_and_sugg; -use clippy_utils::source::snippet_with_applicability; +use clippy_utils::source::{snippet_with_applicability, str_literal_to_char_literal}; +use rustc_ast::BorrowKind; use rustc_errors::Applicability; -use rustc_hir as hir; +use rustc_hir::{self as hir, ExprKind}; use rustc_lint::LateContext; use super::SINGLE_CHAR_ADD_STR; @@ -10,7 +10,7 @@ use super::SINGLE_CHAR_ADD_STR; /// lint for length-1 `str`s as argument for `push_str` pub(super) fn check(cx: &LateContext<'_>, expr: &hir::Expr<'_>, receiver: &hir::Expr<'_>, args: &[hir::Expr<'_>]) { let mut applicability = Applicability::MachineApplicable; - if let Some(extension_string) = get_hint_if_single_char_arg(cx, &args[0], &mut applicability, false) { + if let Some(extension_string) = str_literal_to_char_literal(cx, &args[0], &mut applicability, false) { let base_string_snippet = snippet_with_applicability(cx, receiver.span.source_callsite(), "..", &mut applicability); let sugg = format!("{base_string_snippet}.push({extension_string})"); @@ -24,4 +24,42 @@ pub(super) fn check(cx: &LateContext<'_>, expr: &hir::Expr<'_>, receiver: &hir:: applicability, ); } + + if let ExprKind::AddrOf(BorrowKind::Ref, _, arg) = &args[0].kind + && let ExprKind::MethodCall(path_segment, method_arg, _, _) = &arg.kind + && path_segment.ident.name == rustc_span::sym::to_string + && (is_ref_char(cx, method_arg) || is_char(cx, method_arg)) + { + let base_string_snippet = + snippet_with_applicability(cx, receiver.span.source_callsite(), "..", &mut applicability); + let extension_string = + snippet_with_applicability(cx, method_arg.span.source_callsite(), "..", &mut applicability); + let deref_string = if is_ref_char(cx, method_arg) { "*" } else { "" }; + + let sugg = format!("{base_string_snippet}.push({deref_string}{extension_string})"); + span_lint_and_sugg( + cx, + SINGLE_CHAR_ADD_STR, + expr.span, + "calling `push_str()` using a single-character converted to string", + "consider using `push` without `to_string()`", + sugg, + applicability, + ); + } +} + +fn is_ref_char(cx: &LateContext<'_>, expr: &hir::Expr<'_>) -> bool { + if cx.typeck_results().expr_ty(expr).is_ref() + && let rustc_middle::ty::Ref(_, ty, _) = cx.typeck_results().expr_ty(expr).kind() + && ty.is_char() + { + return true; + } + + false +} + +fn is_char(cx: &LateContext<'_>, expr: &hir::Expr<'_>) -> bool { + cx.typeck_results().expr_ty(expr).is_char() } diff --git a/src/tools/clippy/clippy_lints/src/methods/str_splitn.rs b/src/tools/clippy/clippy_lints/src/methods/str_splitn.rs index e8c12bbeea0e4..4f42fb73547a7 100644 --- a/src/tools/clippy/clippy_lints/src/methods/str_splitn.rs +++ b/src/tools/clippy/clippy_lints/src/methods/str_splitn.rs @@ -3,7 +3,7 @@ use clippy_utils::consts::{constant, Constant}; use clippy_utils::diagnostics::{span_lint_and_sugg, span_lint_and_then}; use clippy_utils::source::snippet_with_context; use clippy_utils::usage::local_used_after_expr; -use clippy_utils::visitors::{for_each_expr_with_closures, Descend}; +use clippy_utils::visitors::{for_each_expr, Descend}; use clippy_utils::{is_diag_item_method, match_def_path, path_to_local_id, paths}; use core::ops::ControlFlow; use rustc_errors::Applicability; @@ -209,7 +209,7 @@ fn indirect_usage<'tcx>( }) = stmt.kind { let mut path_to_binding = None; - let _: Option = for_each_expr_with_closures(cx, init_expr, |e| { + let _: Option = for_each_expr(cx, init_expr, |e| { if path_to_local_id(e, binding) { path_to_binding = Some(e); } diff --git a/src/tools/clippy/clippy_lints/src/methods/unnecessary_filter_map.rs b/src/tools/clippy/clippy_lints/src/methods/unnecessary_filter_map.rs index daf99d9861424..c9b9d98dbe607 100644 --- a/src/tools/clippy/clippy_lints/src/methods/unnecessary_filter_map.rs +++ b/src/tools/clippy/clippy_lints/src/methods/unnecessary_filter_map.rs @@ -2,7 +2,7 @@ use super::utils::clone_or_copy_needed; use clippy_utils::diagnostics::span_lint; use clippy_utils::ty::is_copy; use clippy_utils::usage::mutated_variables; -use clippy_utils::visitors::{for_each_expr, Descend}; +use clippy_utils::visitors::{for_each_expr_without_closures, Descend}; use clippy_utils::{is_res_lang_ctor, is_trait_method, path_res, path_to_local_id}; use core::ops::ControlFlow; use rustc_hir as hir; @@ -26,7 +26,7 @@ pub(super) fn check<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx hir::Expr<'tcx>, a let (mut found_mapping, mut found_filtering) = check_expression(cx, arg_id, body.value); - let _: Option = for_each_expr(body.value, |e| { + let _: Option = for_each_expr_without_closures(body.value, |e| { if let hir::ExprKind::Ret(Some(e)) = &e.kind { let (found_mapping_res, found_filtering_res) = check_expression(cx, arg_id, e); found_mapping |= found_mapping_res; diff --git a/src/tools/clippy/clippy_lints/src/methods/unnecessary_iter_cloned.rs b/src/tools/clippy/clippy_lints/src/methods/unnecessary_iter_cloned.rs index d1300dd43c283..70885e46e955e 100644 --- a/src/tools/clippy/clippy_lints/src/methods/unnecessary_iter_cloned.rs +++ b/src/tools/clippy/clippy_lints/src/methods/unnecessary_iter_cloned.rs @@ -3,7 +3,7 @@ use clippy_utils::diagnostics::span_lint_and_then; use clippy_utils::higher::ForLoop; use clippy_utils::source::snippet_opt; use clippy_utils::ty::{get_iterator_item_ty, implements_trait}; -use clippy_utils::visitors::for_each_expr; +use clippy_utils::visitors::for_each_expr_without_closures; use clippy_utils::{can_mut_borrow_both, fn_def_id, get_parent_expr, path_to_local}; use core::ops::ControlFlow; use rustc_errors::Applicability; @@ -61,7 +61,7 @@ pub fn check_for_loop_iter( fn is_caller_or_fields_change(cx: &LateContext<'_>, body: &Expr<'_>, caller: &Expr<'_>) -> bool { let mut change = false; if let ExprKind::Block(block, ..) = body.kind { - for_each_expr(block, |e| { + for_each_expr_without_closures(block, |e| { match e.kind { ExprKind::Assign(assignee, _, _) | ExprKind::AssignOp(_, assignee, _) => { change |= !can_mut_borrow_both(cx, caller, assignee); diff --git a/src/tools/clippy/clippy_lints/src/methods/unnecessary_result_map_or_else.rs b/src/tools/clippy/clippy_lints/src/methods/unnecessary_result_map_or_else.rs index cdfaa690d5f4b..c14a87c153414 100644 --- a/src/tools/clippy/clippy_lints/src/methods/unnecessary_result_map_or_else.rs +++ b/src/tools/clippy/clippy_lints/src/methods/unnecessary_result_map_or_else.rs @@ -4,10 +4,11 @@ use clippy_utils::source::snippet; use clippy_utils::ty::is_type_diagnostic_item; use rustc_errors::Applicability; use rustc_hir as hir; -use rustc_hir::{Closure, Expr, ExprKind, HirId, QPath, Stmt, StmtKind}; +use rustc_hir::{Closure, Expr, ExprKind, HirId, QPath}; use rustc_lint::LateContext; use rustc_span::symbol::sym; +use super::utils::get_last_chain_binding_hir_id; use super::UNNECESSARY_RESULT_MAP_OR_ELSE; fn emit_lint(cx: &LateContext<'_>, expr: &Expr<'_>, recv: &Expr<'_>, def_arg: &Expr<'_>) { @@ -25,22 +26,6 @@ fn emit_lint(cx: &LateContext<'_>, expr: &Expr<'_>, recv: &Expr<'_>, def_arg: &E ); } -fn get_last_chain_binding_hir_id(mut hir_id: HirId, statements: &[Stmt<'_>]) -> Option { - for stmt in statements { - if let StmtKind::Let(local) = stmt.kind - && let Some(init) = local.init - && let ExprKind::Path(QPath::Resolved(_, path)) = init.kind - && let hir::def::Res::Local(local_hir_id) = path.res - && local_hir_id == hir_id - { - hir_id = local.pat.hir_id; - } else { - return None; - } - } - Some(hir_id) -} - fn handle_qpath( cx: &LateContext<'_>, expr: &Expr<'_>, diff --git a/src/tools/clippy/clippy_lints/src/methods/utils.rs b/src/tools/clippy/clippy_lints/src/methods/utils.rs index 1a55b7160fb18..0d2b0a3131763 100644 --- a/src/tools/clippy/clippy_lints/src/methods/utils.rs +++ b/src/tools/clippy/clippy_lints/src/methods/utils.rs @@ -1,10 +1,7 @@ -use clippy_utils::source::snippet_with_applicability; use clippy_utils::ty::is_type_diagnostic_item; use clippy_utils::{get_parent_expr, path_to_local_id, usage}; -use rustc_ast::ast; -use rustc_errors::Applicability; use rustc_hir::intravisit::{walk_expr, Visitor}; -use rustc_hir::{BorrowKind, Expr, ExprKind, HirId, Mutability, Pat}; +use rustc_hir::{BorrowKind, Expr, ExprKind, HirId, Mutability, Pat, QPath, Stmt, StmtKind}; use rustc_lint::LateContext; use rustc_middle::hir::nested_filter; use rustc_middle::ty::{self, Ty}; @@ -49,48 +46,6 @@ pub(super) fn derefs_to_slice<'tcx>( } } -pub(super) fn get_hint_if_single_char_arg( - cx: &LateContext<'_>, - arg: &Expr<'_>, - applicability: &mut Applicability, - ascii_only: bool, -) -> Option { - if let ExprKind::Lit(lit) = &arg.kind - && let ast::LitKind::Str(r, style) = lit.node - && let string = r.as_str() - && let len = if ascii_only { - string.len() - } else { - string.chars().count() - } - && len == 1 - { - let snip = snippet_with_applicability(cx, arg.span, string, applicability); - let ch = if let ast::StrStyle::Raw(nhash) = style { - let nhash = nhash as usize; - // for raw string: r##"a"## - &snip[(nhash + 2)..(snip.len() - 1 - nhash)] - } else { - // for regular string: "a" - &snip[1..(snip.len() - 1)] - }; - - let hint = format!( - "'{}'", - match ch { - "'" => "\\'", - r"\" => "\\\\", - "\\\"" => "\"", // no need to escape `"` in `'"'` - _ => ch, - } - ); - - Some(hint) - } else { - None - } -} - /// The core logic of `check_for_loop_iter` in `unnecessary_iter_cloned.rs`, this function wraps a /// use of `CloneOrCopyVisitor`. pub(super) fn clone_or_copy_needed<'tcx>( @@ -175,3 +130,19 @@ impl<'cx, 'tcx> CloneOrCopyVisitor<'cx, 'tcx> { .any(|hir_id| path_to_local_id(expr, *hir_id)) } } + +pub(super) fn get_last_chain_binding_hir_id(mut hir_id: HirId, statements: &[Stmt<'_>]) -> Option { + for stmt in statements { + if let StmtKind::Let(local) = stmt.kind + && let Some(init) = local.init + && let ExprKind::Path(QPath::Resolved(_, path)) = init.kind + && let rustc_hir::def::Res::Local(local_hir_id) = path.res + && local_hir_id == hir_id + { + hir_id = local.pat.hir_id; + } else { + return None; + } + } + Some(hir_id) +} diff --git a/src/tools/clippy/clippy_lints/src/misc_early/zero_prefixed_literal.rs b/src/tools/clippy/clippy_lints/src/misc_early/zero_prefixed_literal.rs index 4f9578d1b2576..61f4684c9e379 100644 --- a/src/tools/clippy/clippy_lints/src/misc_early/zero_prefixed_literal.rs +++ b/src/tools/clippy/clippy_lints/src/misc_early/zero_prefixed_literal.rs @@ -6,7 +6,7 @@ use rustc_span::Span; use super::ZERO_PREFIXED_LITERAL; pub(super) fn check(cx: &EarlyContext<'_>, lit_span: Span, lit_snip: &str) { - let trimmed_lit_snip = lit_snip.trim_start_matches(|c| c == '_' || c == '0'); + let trimmed_lit_snip = lit_snip.trim_start_matches(['_', '0']); span_lint_and_then( cx, ZERO_PREFIXED_LITERAL, @@ -20,7 +20,7 @@ pub(super) fn check(cx: &EarlyContext<'_>, lit_span: Span, lit_snip: &str) { Applicability::MaybeIncorrect, ); // do not advise to use octal form if the literal cannot be expressed in base 8. - if !lit_snip.contains(|c| c == '8' || c == '9') { + if !lit_snip.contains(['8', '9']) { diag.span_suggestion( lit_span, "if you mean to use an octal constant, use `0o`", diff --git a/src/tools/clippy/clippy_lints/src/missing_asserts_for_indexing.rs b/src/tools/clippy/clippy_lints/src/missing_asserts_for_indexing.rs index 752723a0c68ee..94c91b095171f 100644 --- a/src/tools/clippy/clippy_lints/src/missing_asserts_for_indexing.rs +++ b/src/tools/clippy/clippy_lints/src/missing_asserts_for_indexing.rs @@ -4,7 +4,7 @@ use std::ops::ControlFlow; use clippy_utils::comparisons::{normalize_comparison, Rel}; use clippy_utils::diagnostics::span_lint_and_then; use clippy_utils::source::snippet; -use clippy_utils::visitors::for_each_expr; +use clippy_utils::visitors::for_each_expr_without_closures; use clippy_utils::{eq_expr_value, hash_expr, higher}; use rustc_ast::{LitKind, RangeLimits}; use rustc_data_structures::packed::Pu128; @@ -405,7 +405,7 @@ impl LateLintPass<'_> for MissingAssertsForIndexing { fn check_body(&mut self, cx: &LateContext<'_>, body: &Body<'_>) { let mut map = UnhashMap::default(); - for_each_expr(body.value, |expr| { + for_each_expr_without_closures(body.value, |expr| { check_index(cx, expr, &mut map); check_assert(cx, expr, &mut map); ControlFlow::::Continue(()) diff --git a/src/tools/clippy/clippy_lints/src/missing_const_for_fn.rs b/src/tools/clippy/clippy_lints/src/missing_const_for_fn.rs index 9ba19e0a86581..4592324809fa2 100644 --- a/src/tools/clippy/clippy_lints/src/missing_const_for_fn.rs +++ b/src/tools/clippy/clippy_lints/src/missing_const_for_fn.rs @@ -1,7 +1,6 @@ use clippy_config::msrvs::{self, Msrv}; use clippy_utils::diagnostics::span_lint; use clippy_utils::qualify_min_const_fn::is_min_const_fn; -use clippy_utils::ty::has_drop; use clippy_utils::{fn_has_unsatisfiable_preds, is_entrypoint_fn, is_from_proc_macro, trait_ref_of_method}; use rustc_hir as hir; use rustc_hir::def_id::CRATE_DEF_ID; @@ -121,10 +120,7 @@ impl<'tcx> LateLintPass<'tcx> for MissingConstForFn { } }, FnKind::Method(_, sig, ..) => { - if trait_ref_of_method(cx, def_id).is_some() - || already_const(sig.header) - || method_accepts_droppable(cx, def_id) - { + if trait_ref_of_method(cx, def_id).is_some() || already_const(sig.header) { return; } }, @@ -151,26 +147,13 @@ impl<'tcx> LateLintPass<'tcx> for MissingConstForFn { let mir = cx.tcx.optimized_mir(def_id); - if let Err((span, err)) = is_min_const_fn(cx.tcx, mir, &self.msrv) { - if cx.tcx.is_const_fn_raw(def_id.to_def_id()) { - cx.tcx.dcx().span_err(span, err); - } - } else { + if let Ok(()) = is_min_const_fn(cx.tcx, mir, &self.msrv) { span_lint(cx, MISSING_CONST_FOR_FN, span, "this could be a `const fn`"); } } extract_msrv_attr!(LateContext); } -/// Returns true if any of the method parameters is a type that implements `Drop`. The method -/// can't be made const then, because `drop` can't be const-evaluated. -fn method_accepts_droppable(cx: &LateContext<'_>, def_id: LocalDefId) -> bool { - let sig = cx.tcx.fn_sig(def_id).instantiate_identity().skip_binder(); - - // If any of the params are droppable, return true - sig.inputs().iter().any(|&ty| has_drop(cx, ty)) -} - // We don't have to lint on something that's already `const` #[must_use] fn already_const(header: hir::FnHeader) -> bool { diff --git a/src/tools/clippy/clippy_lints/src/missing_fields_in_debug.rs b/src/tools/clippy/clippy_lints/src/missing_fields_in_debug.rs index a64faa124f086..77595b121aadb 100644 --- a/src/tools/clippy/clippy_lints/src/missing_fields_in_debug.rs +++ b/src/tools/clippy/clippy_lints/src/missing_fields_in_debug.rs @@ -110,7 +110,7 @@ fn should_lint<'tcx>( // Is there a call to `DebugStruct::debug_struct`? Do lint if there is. let mut has_debug_struct = false; - for_each_expr(block, |expr| { + for_each_expr(cx, block, |expr| { if let ExprKind::MethodCall(path, recv, ..) = &expr.kind { let recv_ty = typeck_results.expr_ty(recv).peel_refs(); @@ -165,7 +165,7 @@ fn check_struct<'tcx>( let mut has_direct_field_access = false; let mut field_accesses = FxHashSet::default(); - for_each_expr(block, |expr| { + for_each_expr(cx, block, |expr| { if let ExprKind::Field(target, ident) = expr.kind && let target_ty = typeck_results.expr_ty_adjusted(target).peel_refs() && target_ty == self_ty diff --git a/src/tools/clippy/clippy_lints/src/multiple_unsafe_ops_per_block.rs b/src/tools/clippy/clippy_lints/src/multiple_unsafe_ops_per_block.rs index 5b4ef852f0d9b..da74a7c7145a6 100644 --- a/src/tools/clippy/clippy_lints/src/multiple_unsafe_ops_per_block.rs +++ b/src/tools/clippy/clippy_lints/src/multiple_unsafe_ops_per_block.rs @@ -1,5 +1,5 @@ use clippy_utils::diagnostics::span_lint_and_then; -use clippy_utils::visitors::{for_each_expr_with_closures, Descend, Visitable}; +use clippy_utils::visitors::{for_each_expr, Descend, Visitable}; use core::ops::ControlFlow::Continue; use hir::def::{DefKind, Res}; use hir::{BlockCheckMode, ExprKind, QPath, Safety, UnOp}; @@ -96,7 +96,7 @@ fn collect_unsafe_exprs<'tcx>( node: impl Visitable<'tcx>, unsafe_ops: &mut Vec<(&'static str, Span)>, ) { - for_each_expr_with_closures(cx, node, |expr| { + for_each_expr(cx, node, |expr| { match expr.kind { ExprKind::InlineAsm(_) => unsafe_ops.push(("inline assembly used here", expr.span)), diff --git a/src/tools/clippy/clippy_lints/src/needless_bool.rs b/src/tools/clippy/clippy_lints/src/needless_bool.rs index e1866eaa18a7c..9cb4fa41c73f1 100644 --- a/src/tools/clippy/clippy_lints/src/needless_bool.rs +++ b/src/tools/clippy/clippy_lints/src/needless_bool.rs @@ -6,8 +6,8 @@ use clippy_utils::diagnostics::{span_lint, span_lint_and_sugg}; use clippy_utils::source::snippet_with_applicability; use clippy_utils::sugg::Sugg; use clippy_utils::{ - higher, is_block_like, is_else_clause, is_expn_of, is_parent_stmt, peel_blocks, peel_blocks_with_stmt, - span_extract_comment, SpanlessEq, + get_parent_expr, higher, is_block_like, is_else_clause, is_expn_of, is_parent_stmt, is_receiver_of_method_call, + peel_blocks, peel_blocks_with_stmt, span_extract_comment, SpanlessEq, }; use rustc_ast::ast::LitKind; use rustc_errors::Applicability; @@ -154,7 +154,10 @@ impl<'tcx> LateLintPass<'tcx> for NeedlessBool { snip = snip.blockify(); } - if condition_needs_parentheses(cond) && is_parent_stmt(cx, e.hir_id) { + if (condition_needs_parentheses(cond) && is_parent_stmt(cx, e.hir_id)) + || is_receiver_of_method_call(cx, e) + || is_as_argument(cx, e) + { snip = snip.maybe_par(); } @@ -442,3 +445,7 @@ fn fetch_assign<'tcx>(expr: &'tcx Expr<'tcx>) -> Option<(&'tcx Expr<'tcx>, bool) None } } + +fn is_as_argument(cx: &LateContext<'_>, e: &Expr<'_>) -> bool { + matches!(get_parent_expr(cx, e).map(|e| e.kind), Some(ExprKind::Cast(_, _))) +} diff --git a/src/tools/clippy/clippy_lints/src/needless_late_init.rs b/src/tools/clippy/clippy_lints/src/needless_late_init.rs index 5a0ae1a4d6d29..4bfc30fa5cf80 100644 --- a/src/tools/clippy/clippy_lints/src/needless_late_init.rs +++ b/src/tools/clippy/clippy_lints/src/needless_late_init.rs @@ -2,7 +2,7 @@ use clippy_utils::diagnostics::span_lint_and_then; use clippy_utils::path_to_local; use clippy_utils::source::snippet_opt; use clippy_utils::ty::needs_ordered_drop; -use clippy_utils::visitors::{for_each_expr, for_each_expr_with_closures, is_local_used}; +use clippy_utils::visitors::{for_each_expr, for_each_expr_without_closures, is_local_used}; use core::ops::ControlFlow; use rustc_errors::{Applicability, MultiSpan}; use rustc_hir::{ @@ -63,7 +63,7 @@ declare_clippy_lint! { declare_lint_pass!(NeedlessLateInit => [NEEDLESS_LATE_INIT]); fn contains_assign_expr<'tcx>(cx: &LateContext<'tcx>, stmt: &'tcx Stmt<'tcx>) -> bool { - for_each_expr_with_closures(cx, stmt, |e| { + for_each_expr(cx, stmt, |e| { if matches!(e.kind, ExprKind::Assign(..)) { ControlFlow::Break(()) } else { @@ -74,7 +74,7 @@ fn contains_assign_expr<'tcx>(cx: &LateContext<'tcx>, stmt: &'tcx Stmt<'tcx>) -> } fn contains_let(cond: &Expr<'_>) -> bool { - for_each_expr(cond, |e| { + for_each_expr_without_closures(cond, |e| { if matches!(e.kind, ExprKind::Let(_)) { ControlFlow::Break(()) } else { diff --git a/src/tools/clippy/clippy_lints/src/needless_maybe_sized.rs b/src/tools/clippy/clippy_lints/src/needless_maybe_sized.rs new file mode 100644 index 0000000000000..06ae1723a03d4 --- /dev/null +++ b/src/tools/clippy/clippy_lints/src/needless_maybe_sized.rs @@ -0,0 +1,164 @@ +use clippy_utils::diagnostics::span_lint_and_then; +use rustc_errors::Applicability; +use rustc_hir::def_id::{DefId, DefIdMap}; +use rustc_hir::{GenericBound, Generics, PolyTraitRef, TraitBoundModifier, WherePredicate}; +use rustc_lint::{LateContext, LateLintPass}; +use rustc_middle::ty::{ClauseKind, PredicatePolarity}; +use rustc_session::declare_lint_pass; +use rustc_span::symbol::Ident; + +declare_clippy_lint! { + /// ### What it does + /// Lints `?Sized` bounds applied to type parameters that cannot be unsized + /// + /// ### Why is this bad? + /// The `?Sized` bound is misleading because it cannot be satisfied by an + /// unsized type + /// + /// ### Example + /// ```rust + /// // `T` cannot be unsized because `Clone` requires it to be `Sized` + /// fn f(t: &T) {} + /// ``` + /// Use instead: + /// ```rust + /// fn f(t: &T) {} + /// + /// // or choose alternative bounds for `T` so that it can be unsized + /// ``` + #[clippy::version = "1.79.0"] + pub NEEDLESS_MAYBE_SIZED, + suspicious, + "a `?Sized` bound that is unusable due to a `Sized` requirement" +} +declare_lint_pass!(NeedlessMaybeSized => [NEEDLESS_MAYBE_SIZED]); + +#[allow(clippy::struct_field_names)] +struct Bound<'tcx> { + /// The [`DefId`] of the type parameter the bound refers to + param: DefId, + ident: Ident, + + trait_bound: &'tcx PolyTraitRef<'tcx>, + modifier: TraitBoundModifier, + + predicate_pos: usize, + bound_pos: usize, +} + +/// Finds all of the [`Bound`]s that refer to a type parameter and are not from a macro expansion +fn type_param_bounds<'tcx>(generics: &'tcx Generics<'tcx>) -> impl Iterator> { + generics + .predicates + .iter() + .enumerate() + .filter_map(|(predicate_pos, predicate)| { + let WherePredicate::BoundPredicate(bound_predicate) = predicate else { + return None; + }; + + let (param, ident) = bound_predicate.bounded_ty.as_generic_param()?; + + Some( + bound_predicate + .bounds + .iter() + .enumerate() + .filter_map(move |(bound_pos, bound)| match bound { + &GenericBound::Trait(ref trait_bound, modifier) => Some(Bound { + param, + ident, + trait_bound, + modifier, + predicate_pos, + bound_pos, + }), + GenericBound::Outlives(_) => None, + }) + .filter(|bound| !bound.trait_bound.span.from_expansion()), + ) + }) + .flatten() +} + +/// Searches the supertraits of the trait referred to by `trait_bound` recursively, returning the +/// path taken to find a `Sized` bound if one is found +fn path_to_sized_bound(cx: &LateContext<'_>, trait_bound: &PolyTraitRef<'_>) -> Option> { + fn search(cx: &LateContext<'_>, path: &mut Vec) -> bool { + let trait_def_id = *path.last().unwrap(); + + if Some(trait_def_id) == cx.tcx.lang_items().sized_trait() { + return true; + } + + for &(predicate, _) in cx.tcx.super_predicates_of(trait_def_id).predicates { + if let ClauseKind::Trait(trait_predicate) = predicate.kind().skip_binder() + && trait_predicate.polarity == PredicatePolarity::Positive + && !path.contains(&trait_predicate.def_id()) + { + path.push(trait_predicate.def_id()); + if search(cx, path) { + return true; + } + path.pop(); + } + } + + false + } + + let mut path = vec![trait_bound.trait_ref.trait_def_id()?]; + search(cx, &mut path).then_some(path) +} + +impl LateLintPass<'_> for NeedlessMaybeSized { + fn check_generics(&mut self, cx: &LateContext<'_>, generics: &Generics<'_>) { + let Some(sized_trait) = cx.tcx.lang_items().sized_trait() else { + return; + }; + + let maybe_sized_params: DefIdMap<_> = type_param_bounds(generics) + .filter(|bound| { + bound.trait_bound.trait_ref.trait_def_id() == Some(sized_trait) + && bound.modifier == TraitBoundModifier::Maybe + }) + .map(|bound| (bound.param, bound)) + .collect(); + + for bound in type_param_bounds(generics) { + if bound.modifier == TraitBoundModifier::None + && let Some(sized_bound) = maybe_sized_params.get(&bound.param) + && let Some(path) = path_to_sized_bound(cx, bound.trait_bound) + { + span_lint_and_then( + cx, + NEEDLESS_MAYBE_SIZED, + sized_bound.trait_bound.span, + "`?Sized` bound is ignored because of a `Sized` requirement", + |diag| { + let ty_param = sized_bound.ident; + diag.span_note( + bound.trait_bound.span, + format!("`{ty_param}` cannot be unsized because of the bound"), + ); + + for &[current_id, next_id] in path.array_windows() { + let current = cx.tcx.item_name(current_id); + let next = cx.tcx.item_name(next_id); + diag.note(format!("...because `{current}` has the bound `{next}`")); + } + + diag.span_suggestion_verbose( + generics.span_for_bound_removal(sized_bound.predicate_pos, sized_bound.bound_pos), + "change the bounds that require `Sized`, or remove the `?Sized` bound", + "", + Applicability::MaybeIncorrect, + ); + }, + ); + + return; + } + } + } +} diff --git a/src/tools/clippy/clippy_lints/src/needless_pass_by_ref_mut.rs b/src/tools/clippy/clippy_lints/src/needless_pass_by_ref_mut.rs index da6ed5fb96f12..57ba0da533190 100644 --- a/src/tools/clippy/clippy_lints/src/needless_pass_by_ref_mut.rs +++ b/src/tools/clippy/clippy_lints/src/needless_pass_by_ref_mut.rs @@ -1,7 +1,7 @@ use super::needless_pass_by_value::requires_exact_signature; use clippy_utils::diagnostics::span_lint_hir_and_then; use clippy_utils::source::snippet; -use clippy_utils::visitors::for_each_expr_with_closures; +use clippy_utils::visitors::for_each_expr; use clippy_utils::{inherits_cfg, is_from_proc_macro, is_self}; use rustc_data_structures::fx::{FxHashSet, FxIndexMap}; use rustc_errors::Applicability; @@ -205,7 +205,7 @@ impl<'tcx> LateLintPass<'tcx> for NeedlessPassByRefMut<'tcx> { // We retrieve all the closures declared in the function because they will not be found // by `euv::Delegate`. let mut closures: FxHashSet = FxHashSet::default(); - for_each_expr_with_closures(cx, body, |expr| { + for_each_expr(cx, body, |expr| { if let ExprKind::Closure(closure) = expr.kind { closures.insert(closure.def_id); } diff --git a/src/tools/clippy/clippy_lints/src/non_canonical_impls.rs b/src/tools/clippy/clippy_lints/src/non_canonical_impls.rs index 932d6fe54d660..de6a1a36f3e92 100644 --- a/src/tools/clippy/clippy_lints/src/non_canonical_impls.rs +++ b/src/tools/clippy/clippy_lints/src/non_canonical_impls.rs @@ -1,10 +1,11 @@ use clippy_utils::diagnostics::{span_lint_and_sugg, span_lint_and_then}; use clippy_utils::ty::implements_trait; -use clippy_utils::{is_res_lang_ctor, last_path_segment, path_res, std_or_core}; +use clippy_utils::{is_from_proc_macro, is_res_lang_ctor, last_path_segment, path_res, std_or_core}; use rustc_errors::Applicability; use rustc_hir::def_id::LocalDefId; use rustc_hir::{Expr, ExprKind, ImplItem, ImplItemKind, LangItem, Node, UnOp}; -use rustc_lint::{LateContext, LateLintPass}; +use rustc_lint::{LateContext, LateLintPass, LintContext}; +use rustc_middle::lint::in_external_macro; use rustc_middle::ty::EarlyBinder; use rustc_session::declare_lint_pass; use rustc_span::sym; @@ -111,7 +112,7 @@ declare_lint_pass!(NonCanonicalImpls => [NON_CANONICAL_CLONE_IMPL, NON_CANONICAL impl LateLintPass<'_> for NonCanonicalImpls { #[expect(clippy::too_many_lines)] - fn check_impl_item(&mut self, cx: &LateContext<'_>, impl_item: &ImplItem<'_>) { + fn check_impl_item<'tcx>(&mut self, cx: &LateContext<'tcx>, impl_item: &ImplItem<'tcx>) { let Node::Item(item) = cx.tcx.parent_hir_node(impl_item.hir_id()) else { return; }; @@ -128,6 +129,9 @@ impl LateLintPass<'_> for NonCanonicalImpls { let ExprKind::Block(block, ..) = body.value.kind else { return; }; + if in_external_macro(cx.sess(), block.span) || is_from_proc_macro(cx, impl_item) { + return; + } if cx.tcx.is_diagnostic_item(sym::Clone, trait_impl.def_id) && let Some(copy_def_id) = cx.tcx.get_diagnostic_item(sym::Copy) diff --git a/src/tools/clippy/clippy_lints/src/non_copy_const.rs b/src/tools/clippy/clippy_lints/src/non_copy_const.rs index 20a97645af95d..5cb8e7bfab2a9 100644 --- a/src/tools/clippy/clippy_lints/src/non_copy_const.rs +++ b/src/tools/clippy/clippy_lints/src/non_copy_const.rs @@ -7,7 +7,7 @@ use std::ptr; use clippy_utils::diagnostics::span_lint_and_then; use clippy_utils::in_constant; use clippy_utils::macros::macro_backtrace; -use clippy_utils::ty::InteriorMut; +use clippy_utils::ty::{implements_trait, InteriorMut}; use rustc_hir::def::{DefKind, Res}; use rustc_hir::def_id::DefId; use rustc_hir::{ @@ -18,7 +18,7 @@ use rustc_middle::mir::interpret::{ErrorHandled, EvalToValTreeResult, GlobalId}; use rustc_middle::ty::adjustment::Adjust; use rustc_middle::ty::{self, Ty, TyCtxt}; use rustc_session::impl_lint_pass; -use rustc_span::{sym, InnerSpan, Span, DUMMY_SP}; +use rustc_span::{sym, Span, DUMMY_SP}; use rustc_target::abi::VariantIdx; // FIXME: this is a correctness problem but there's no suitable @@ -127,19 +127,19 @@ declare_clippy_lint! { } #[derive(Copy, Clone)] -enum Source { - Item { item: Span }, +enum Source<'tcx> { + Item { item: Span, ty: Ty<'tcx> }, Assoc { item: Span }, Expr { expr: Span }, } -impl Source { +impl Source<'_> { #[must_use] fn lint(&self) -> (&'static Lint, &'static str, Span) { match self { - Self::Item { item } | Self::Assoc { item, .. } => ( + Self::Item { item, .. } | Self::Assoc { item, .. } => ( DECLARE_INTERIOR_MUTABLE_CONST, - "a `const` item should never be interior mutable", + "a `const` item should not be interior mutable", *item, ), Self::Expr { expr } => ( @@ -151,16 +151,24 @@ impl Source { } } -fn lint(cx: &LateContext<'_>, source: Source) { +fn lint<'tcx>(cx: &LateContext<'tcx>, source: Source<'tcx>) { let (lint, msg, span) = source.lint(); span_lint_and_then(cx, lint, span, msg, |diag| { if span.from_expansion() { return; // Don't give suggestions into macros. } match source { - Source::Item { .. } => { - let const_kw_span = span.from_inner(InnerSpan::new(0, 5)); - diag.span_label(const_kw_span, "make this a static item (maybe with lazy_static)"); + Source::Item { ty, .. } => { + let Some(sync_trait) = cx.tcx.lang_items().sync_trait() else { + return; + }; + if implements_trait(cx, ty, sync_trait, &[]) { + diag.help("consider making this a static item"); + } else { + diag.help( + "consider making this `Sync` so that it can go in a static item or using a `thread_local`", + ); + } }, Source::Assoc { .. } => (), Source::Expr { .. } => { @@ -311,7 +319,7 @@ impl<'tcx> LateLintPass<'tcx> for NonCopyConst<'tcx> { && self.interior_mut.is_interior_mut_ty(cx, ty) && Self::is_value_unfrozen_poly(cx, body_id, ty) { - lint(cx, Source::Item { item: it.span }); + lint(cx, Source::Item { item: it.span, ty }); } } } diff --git a/src/tools/clippy/clippy_lints/src/operators/assign_op_pattern.rs b/src/tools/clippy/clippy_lints/src/operators/assign_op_pattern.rs index 910e584a7a0f9..641d881d974b8 100644 --- a/src/tools/clippy/clippy_lints/src/operators/assign_op_pattern.rs +++ b/src/tools/clippy/clippy_lints/src/operators/assign_op_pattern.rs @@ -1,7 +1,7 @@ use clippy_utils::diagnostics::span_lint_and_then; use clippy_utils::source::snippet_opt; use clippy_utils::ty::implements_trait; -use clippy_utils::visitors::for_each_expr; +use clippy_utils::visitors::for_each_expr_without_closures; use clippy_utils::{binop_traits, eq_expr_value, trait_ref_of_method}; use core::ops::ControlFlow; use rustc_errors::Applicability; @@ -62,7 +62,7 @@ pub(super) fn check<'tcx>( }; let mut found = false; - let found_multiple = for_each_expr(e, |e| { + let found_multiple = for_each_expr_without_closures(e, |e| { if eq_expr_value(cx, assignee, e) { if found { return ControlFlow::Break(()); diff --git a/src/tools/clippy/clippy_lints/src/panic_in_result_fn.rs b/src/tools/clippy/clippy_lints/src/panic_in_result_fn.rs index 806638c0505ba..381975199d285 100644 --- a/src/tools/clippy/clippy_lints/src/panic_in_result_fn.rs +++ b/src/tools/clippy/clippy_lints/src/panic_in_result_fn.rs @@ -64,7 +64,7 @@ impl<'tcx> LateLintPass<'tcx> for PanicInResultFn { fn lint_impl_body<'tcx>(cx: &LateContext<'tcx>, impl_span: Span, body: &'tcx hir::Body<'tcx>) { let mut panics = Vec::new(); - let _: Option = for_each_expr(body.value, |e| { + let _: Option = for_each_expr(cx, body.value, |e| { let Some(macro_call) = root_macro_call_first_node(cx, e) else { return ControlFlow::Continue(Descend::Yes); }; diff --git a/src/tools/clippy/clippy_lints/src/redundant_async_block.rs b/src/tools/clippy/clippy_lints/src/redundant_async_block.rs index 0ed957f1f2fb3..313e4083256bc 100644 --- a/src/tools/clippy/clippy_lints/src/redundant_async_block.rs +++ b/src/tools/clippy/clippy_lints/src/redundant_async_block.rs @@ -4,7 +4,7 @@ use clippy_utils::diagnostics::span_lint_and_sugg; use clippy_utils::peel_blocks; use clippy_utils::source::{snippet, walk_span_to_context}; use clippy_utils::ty::implements_trait; -use clippy_utils::visitors::for_each_expr; +use clippy_utils::visitors::for_each_expr_without_closures; use rustc_errors::Applicability; use rustc_hir::{ Closure, ClosureKind, CoroutineDesugaring, CoroutineKind, CoroutineSource, Expr, ExprKind, MatchSource, @@ -107,7 +107,7 @@ fn desugar_await<'tcx>(expr: &'tcx Expr<'_>) -> Option<&'tcx Expr<'tcx>> { if let ExprKind::Match(match_value, _, MatchSource::AwaitDesugar) = expr.kind && let ExprKind::Call(_, [into_future_arg]) = match_value.kind && let ctxt = expr.span.ctxt() - && for_each_expr(into_future_arg, |e| { + && for_each_expr_without_closures(into_future_arg, |e| { walk_span_to_context(e.span, ctxt).map_or(ControlFlow::Break(()), |_| ControlFlow::Continue(())) }) .is_none() diff --git a/src/tools/clippy/clippy_lints/src/reference.rs b/src/tools/clippy/clippy_lints/src/reference.rs index 16086ba6637c3..8f32cf5f2a1db 100644 --- a/src/tools/clippy/clippy_lints/src/reference.rs +++ b/src/tools/clippy/clippy_lints/src/reference.rs @@ -48,6 +48,9 @@ impl EarlyLintPass for DerefAddrOf { fn check_expr(&mut self, cx: &EarlyContext<'_>, e: &Expr) { if let ExprKind::Unary(UnOp::Deref, ref deref_target) = e.kind && let ExprKind::AddrOf(_, ref mutability, ref addrof_target) = without_parens(deref_target).kind + // NOTE(tesuji): `*&` forces rustc to const-promote the array to `.rodata` section. + // See #12854 for details. + && !matches!(addrof_target.kind, ExprKind::Array(_)) && deref_target.span.eq_ctxt(e.span) && !addrof_target.span.from_expansion() { diff --git a/src/tools/clippy/clippy_lints/src/returns.rs b/src/tools/clippy/clippy_lints/src/returns.rs index 48d6fb3c0378a..c11da3147ef4a 100644 --- a/src/tools/clippy/clippy_lints/src/returns.rs +++ b/src/tools/clippy/clippy_lints/src/returns.rs @@ -1,7 +1,7 @@ use clippy_utils::diagnostics::{span_lint_and_sugg, span_lint_hir_and_then}; use clippy_utils::source::{snippet_opt, snippet_with_context}; use clippy_utils::sugg::has_enclosing_paren; -use clippy_utils::visitors::{for_each_expr_with_closures, Descend}; +use clippy_utils::visitors::{for_each_expr, Descend}; use clippy_utils::{ binary_expr_needs_parentheses, fn_def_id, is_from_proc_macro, is_inside_let_else, is_res_lang_ctor, path_res, path_to_local_id, span_contains_cfg, span_find_starting_semi, @@ -436,7 +436,7 @@ fn emit_return_lint( } fn last_statement_borrows<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx Expr<'tcx>) -> bool { - for_each_expr_with_closures(cx, expr, |e| { + for_each_expr(cx, expr, |e| { if let Some(def_id) = fn_def_id(cx, e) && cx .tcx diff --git a/src/tools/clippy/clippy_lints/src/significant_drop_tightening.rs b/src/tools/clippy/clippy_lints/src/significant_drop_tightening.rs index 038eb92d652b4..979d6dc77aede 100644 --- a/src/tools/clippy/clippy_lints/src/significant_drop_tightening.rs +++ b/src/tools/clippy/clippy_lints/src/significant_drop_tightening.rs @@ -1,7 +1,7 @@ use clippy_utils::diagnostics::span_lint_and_then; use clippy_utils::source::{indent_of, snippet}; use clippy_utils::{expr_or_init, get_attr, path_to_local, peel_hir_expr_unary}; -use rustc_data_structures::fx::{FxHashMap, FxHashSet, FxIndexMap}; +use rustc_data_structures::fx::{FxHashMap, FxIndexMap}; use rustc_errors::Applicability; use rustc_hir::def::{DefKind, Res}; use rustc_hir::intravisit::{walk_expr, Visitor}; @@ -12,6 +12,7 @@ use rustc_session::impl_lint_pass; use rustc_span::symbol::Ident; use rustc_span::{sym, Span, DUMMY_SP}; use std::borrow::Cow; +use std::collections::hash_map::Entry; declare_clippy_lint! { /// ### What it does @@ -57,7 +58,6 @@ impl_lint_pass!(SignificantDropTightening<'_> => [SIGNIFICANT_DROP_TIGHTENING]); pub struct SignificantDropTightening<'tcx> { apas: FxIndexMap, /// Auxiliary structure used to avoid having to verify the same type multiple times. - seen_types: FxHashSet>, type_cache: FxHashMap, bool>, } @@ -74,7 +74,7 @@ impl<'tcx> LateLintPass<'tcx> for SignificantDropTightening<'tcx> { self.apas.clear(); let initial_dummy_stmt = dummy_stmt_expr(body.value); let mut ap = AuxParams::new(&mut self.apas, &initial_dummy_stmt); - StmtsChecker::new(&mut ap, cx, &mut self.seen_types, &mut self.type_cache).visit_body(body); + StmtsChecker::new(&mut ap, cx, &mut self.type_cache).visit_body(body); for apa in ap.apas.values() { if apa.counter <= 1 || !apa.has_expensive_expr_after_last_attr { continue; @@ -142,28 +142,25 @@ impl<'tcx> LateLintPass<'tcx> for SignificantDropTightening<'tcx> { /// Checks the existence of the `#[has_significant_drop]` attribute. struct AttrChecker<'cx, 'others, 'tcx> { cx: &'cx LateContext<'tcx>, - seen_types: &'others mut FxHashSet>, type_cache: &'others mut FxHashMap, bool>, } impl<'cx, 'others, 'tcx> AttrChecker<'cx, 'others, 'tcx> { - pub(crate) fn new( - cx: &'cx LateContext<'tcx>, - seen_types: &'others mut FxHashSet>, - type_cache: &'others mut FxHashMap, bool>, - ) -> Self { - seen_types.clear(); - Self { - cx, - seen_types, - type_cache, - } + pub(crate) fn new(cx: &'cx LateContext<'tcx>, type_cache: &'others mut FxHashMap, bool>) -> Self { + Self { cx, type_cache } } fn has_sig_drop_attr(&mut self, ty: Ty<'tcx>) -> bool { - // The borrow checker prevents us from using something fancier like or_insert_with. - if let Some(ty) = self.type_cache.get(&ty) { - return *ty; + let ty = self + .cx + .tcx + .try_normalize_erasing_regions(self.cx.param_env, ty) + .unwrap_or(ty); + match self.type_cache.entry(ty) { + Entry::Occupied(e) => return *e.get(), + Entry::Vacant(e) => { + e.insert(false); + }, } let value = self.has_sig_drop_attr_uncached(ty); self.type_cache.insert(ty, value); @@ -185,7 +182,7 @@ impl<'cx, 'others, 'tcx> AttrChecker<'cx, 'others, 'tcx> { rustc_middle::ty::Adt(a, b) => { for f in a.all_fields() { let ty = f.ty(self.cx.tcx, b); - if !self.has_seen_ty(ty) && self.has_sig_drop_attr(ty) { + if self.has_sig_drop_attr(ty) { return true; } } @@ -205,16 +202,11 @@ impl<'cx, 'others, 'tcx> AttrChecker<'cx, 'others, 'tcx> { _ => false, } } - - fn has_seen_ty(&mut self, ty: Ty<'tcx>) -> bool { - !self.seen_types.insert(ty) - } } struct StmtsChecker<'ap, 'lc, 'others, 'stmt, 'tcx> { ap: &'ap mut AuxParams<'others, 'stmt, 'tcx>, cx: &'lc LateContext<'tcx>, - seen_types: &'others mut FxHashSet>, type_cache: &'others mut FxHashMap, bool>, } @@ -222,15 +214,9 @@ impl<'ap, 'lc, 'others, 'stmt, 'tcx> StmtsChecker<'ap, 'lc, 'others, 'stmt, 'tcx fn new( ap: &'ap mut AuxParams<'others, 'stmt, 'tcx>, cx: &'lc LateContext<'tcx>, - seen_types: &'others mut FxHashSet>, type_cache: &'others mut FxHashMap, bool>, ) -> Self { - Self { - ap, - cx, - seen_types, - type_cache, - } + Self { ap, cx, type_cache } } fn manage_has_expensive_expr_after_last_attr(&mut self) { @@ -288,7 +274,7 @@ impl<'ap, 'lc, 'others, 'stmt, 'tcx> Visitor<'tcx> for StmtsChecker<'ap, 'lc, 'o apa.counter = apa.counter.wrapping_add(1); apa.has_expensive_expr_after_last_attr = false; }; - let mut ac = AttrChecker::new(self.cx, self.seen_types, self.type_cache); + let mut ac = AttrChecker::new(self.cx, self.type_cache); if ac.has_sig_drop_attr(self.cx.typeck_results().expr_ty(expr)) { if let hir::StmtKind::Let(local) = self.ap.curr_stmt.kind && let hir::PatKind::Binding(_, hir_id, ident, _) = local.pat.kind diff --git a/src/tools/clippy/clippy_lints/src/string_patterns.rs b/src/tools/clippy/clippy_lints/src/string_patterns.rs new file mode 100644 index 0000000000000..64b5b8f9f27b4 --- /dev/null +++ b/src/tools/clippy/clippy_lints/src/string_patterns.rs @@ -0,0 +1,227 @@ +use std::ops::ControlFlow; + +use clippy_utils::diagnostics::{span_lint_and_sugg, span_lint_and_then}; +use clippy_utils::eager_or_lazy::switch_to_eager_eval; +use clippy_utils::macros::matching_root_macro_call; +use clippy_utils::path_to_local_id; +use clippy_utils::source::{snippet, str_literal_to_char_literal}; +use clippy_utils::visitors::{for_each_expr, Descend}; +use itertools::Itertools; +use rustc_ast::{BinOpKind, LitKind}; +use rustc_errors::Applicability; +use rustc_hir::{Expr, ExprKind, PatKind}; +use rustc_lint::{LateContext, LateLintPass}; +use rustc_middle::ty; +use rustc_session::declare_lint_pass; +use rustc_span::{sym, Span}; + +declare_clippy_lint! { + /// ### What it does + /// Checks for manual `char` comparison in string patterns + /// + /// ### Why is this bad? + /// This can be written more concisely using a `char` or an array of `char`. + /// This is more readable and more optimized when comparing to only one `char`. + /// + /// ### Example + /// ```no_run + /// "Hello World!".trim_end_matches(|c| c == '.' || c == ',' || c == '!' || c == '?'); + /// ``` + /// Use instead: + /// ```no_run + /// "Hello World!".trim_end_matches(['.', ',', '!', '?']); + /// ``` + #[clippy::version = "1.80.0"] + pub MANUAL_PATTERN_CHAR_COMPARISON, + style, + "manual char comparison in string patterns" +} + +declare_clippy_lint! { + /// ### What it does + /// Checks for string methods that receive a single-character + /// `str` as an argument, e.g., `_.split("x")`. + /// + /// ### Why is this bad? + /// While this can make a perf difference on some systems, + /// benchmarks have proven inconclusive. But at least using a + /// char literal makes it clear that we are looking at a single + /// character. + /// + /// ### Known problems + /// Does not catch multi-byte unicode characters. This is by + /// design, on many machines, splitting by a non-ascii char is + /// actually slower. Please do your own measurements instead of + /// relying solely on the results of this lint. + /// + /// ### Example + /// ```rust,ignore + /// _.split("x"); + /// ``` + /// + /// Use instead: + /// ```rust,ignore + /// _.split('x'); + /// ``` + #[clippy::version = "pre 1.29.0"] + pub SINGLE_CHAR_PATTERN, + pedantic, + "using a single-character str where a char could be used, e.g., `_.split(\"x\")`" +} + +declare_lint_pass!(StringPatterns => [MANUAL_PATTERN_CHAR_COMPARISON, SINGLE_CHAR_PATTERN]); + +const PATTERN_METHODS: [(&str, usize); 22] = [ + ("contains", 0), + ("starts_with", 0), + ("ends_with", 0), + ("find", 0), + ("rfind", 0), + ("split", 0), + ("split_inclusive", 0), + ("rsplit", 0), + ("split_terminator", 0), + ("rsplit_terminator", 0), + ("splitn", 1), + ("rsplitn", 1), + ("split_once", 0), + ("rsplit_once", 0), + ("matches", 0), + ("rmatches", 0), + ("match_indices", 0), + ("rmatch_indices", 0), + ("trim_start_matches", 0), + ("trim_end_matches", 0), + ("replace", 0), + ("replacen", 0), +]; + +fn check_single_char_pattern_lint(cx: &LateContext<'_>, arg: &Expr<'_>) { + let mut applicability = Applicability::MachineApplicable; + if let Some(hint) = str_literal_to_char_literal(cx, arg, &mut applicability, true) { + span_lint_and_sugg( + cx, + SINGLE_CHAR_PATTERN, + arg.span, + "single-character string constant used as pattern", + "consider using a `char`", + hint, + applicability, + ); + } +} + +fn get_char_span<'tcx>(cx: &'_ LateContext<'tcx>, expr: &'tcx Expr<'_>) -> Option { + if cx.typeck_results().expr_ty_adjusted(expr).is_char() + && !expr.span.from_expansion() + && switch_to_eager_eval(cx, expr) + { + Some(expr.span) + } else { + None + } +} + +fn check_manual_pattern_char_comparison(cx: &LateContext<'_>, method_arg: &Expr<'_>) { + if let ExprKind::Closure(closure) = method_arg.kind + && let body = cx.tcx.hir().body(closure.body) + && let Some(PatKind::Binding(_, binding, ..)) = body.params.first().map(|p| p.pat.kind) + { + let mut set_char_spans: Vec = Vec::new(); + + // We want to retrieve all the comparisons done. + // They are ordered in a nested way and so we need to traverse the AST to collect them all. + if for_each_expr(cx, body.value, |sub_expr| -> ControlFlow<(), Descend> { + match sub_expr.kind { + ExprKind::Binary(op, left, right) if op.node == BinOpKind::Eq => { + if path_to_local_id(left, binding) + && let Some(span) = get_char_span(cx, right) + { + set_char_spans.push(span); + ControlFlow::Continue(Descend::No) + } else if path_to_local_id(right, binding) + && let Some(span) = get_char_span(cx, left) + { + set_char_spans.push(span); + ControlFlow::Continue(Descend::No) + } else { + ControlFlow::Break(()) + } + }, + ExprKind::Binary(op, _, _) if op.node == BinOpKind::Or => ControlFlow::Continue(Descend::Yes), + ExprKind::Match(match_value, [arm, _], _) => { + if matching_root_macro_call(cx, sub_expr.span, sym::matches_macro).is_none() + || arm.guard.is_some() + || !path_to_local_id(match_value, binding) + { + return ControlFlow::Break(()); + } + if arm.pat.walk_short(|pat| match pat.kind { + PatKind::Lit(expr) if let ExprKind::Lit(lit) = expr.kind => { + if let LitKind::Char(_) = lit.node { + set_char_spans.push(lit.span); + } + true + }, + PatKind::Or(_) => true, + _ => false, + }) { + ControlFlow::Continue(Descend::No) + } else { + ControlFlow::Break(()) + } + }, + _ => ControlFlow::Break(()), + } + }) + .is_some() + { + return; + } + span_lint_and_then( + cx, + MANUAL_PATTERN_CHAR_COMPARISON, + method_arg.span, + "this manual char comparison can be written more succinctly", + |diag| { + if let [set_char_span] = set_char_spans[..] { + diag.span_suggestion( + method_arg.span, + "consider using a `char`", + snippet(cx, set_char_span, "c"), + Applicability::MachineApplicable, + ); + } else { + diag.span_suggestion( + method_arg.span, + "consider using an array of `char`", + format!( + "[{}]", + set_char_spans.into_iter().map(|span| snippet(cx, span, "c")).join(", ") + ), + Applicability::MachineApplicable, + ); + } + }, + ); + } +} + +impl<'tcx> LateLintPass<'tcx> for StringPatterns { + fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>) { + if !expr.span.from_expansion() + && let ExprKind::MethodCall(method, receiver, args, _) = expr.kind + && let ty::Ref(_, ty, _) = cx.typeck_results().expr_ty_adjusted(receiver).kind() + && ty.is_str() + && let method_name = method.ident.name.as_str() + && let Some(&(_, pos)) = PATTERN_METHODS + .iter() + .find(|(array_method_name, _)| *array_method_name == method_name) + && let Some(arg) = args.get(pos) + { + check_single_char_pattern_lint(cx, arg); + + check_manual_pattern_char_comparison(cx, arg); + } + } +} diff --git a/src/tools/clippy/clippy_lints/src/strings.rs b/src/tools/clippy/clippy_lints/src/strings.rs index f8d36d6b92f61..7da661485abfc 100644 --- a/src/tools/clippy/clippy_lints/src/strings.rs +++ b/src/tools/clippy/clippy_lints/src/strings.rs @@ -399,13 +399,17 @@ impl<'tcx> LateLintPass<'tcx> for StrToString { && let ty::Ref(_, ty, ..) = ty.kind() && ty.is_str() { - span_lint_and_help( + let mut applicability = Applicability::MachineApplicable; + let snippet = snippet_with_applicability(cx, self_arg.span, "..", &mut applicability); + + span_lint_and_sugg( cx, STR_TO_STRING, expr.span, "`to_string()` called on a `&str`", - None, - "consider using `.to_owned()`", + "try", + format!("{snippet}.to_owned()"), + applicability, ); } } diff --git a/src/tools/clippy/clippy_lints/src/suspicious_trait_impl.rs b/src/tools/clippy/clippy_lints/src/suspicious_trait_impl.rs index 3f030b8033187..744d6392e065c 100644 --- a/src/tools/clippy/clippy_lints/src/suspicious_trait_impl.rs +++ b/src/tools/clippy/clippy_lints/src/suspicious_trait_impl.rs @@ -1,5 +1,5 @@ use clippy_utils::diagnostics::span_lint; -use clippy_utils::visitors::for_each_expr; +use clippy_utils::visitors::for_each_expr_without_closures; use clippy_utils::{binop_traits, trait_ref_of_method, BINOP_TRAITS, OP_ASSIGN_TRAITS}; use core::ops::ControlFlow; use rustc_hir as hir; @@ -95,7 +95,7 @@ impl<'tcx> LateLintPass<'tcx> for SuspiciousImpl { fn count_binops(expr: &hir::Expr<'_>) -> u32 { let mut count = 0u32; - let _: Option = for_each_expr(expr, |e| { + let _: Option = for_each_expr_without_closures(expr, |e| { if matches!( e.kind, hir::ExprKind::Binary(..) diff --git a/src/tools/clippy/clippy_lints/src/transmute/missing_transmute_annotations.rs b/src/tools/clippy/clippy_lints/src/transmute/missing_transmute_annotations.rs index f98ea59a15d87..b2892d136fa3a 100644 --- a/src/tools/clippy/clippy_lints/src/transmute/missing_transmute_annotations.rs +++ b/src/tools/clippy/clippy_lints/src/transmute/missing_transmute_annotations.rs @@ -31,7 +31,6 @@ fn get_parent_local_binding_ty<'tcx>(cx: &LateContext<'tcx>, expr_hir_id: HirId) fn is_function_block(cx: &LateContext<'_>, expr_hir_id: HirId) -> bool { let def_id = cx.tcx.hir().enclosing_body_owner(expr_hir_id); if let Some(body) = cx.tcx.hir().maybe_body_owned_by(def_id) { - let body = cx.tcx.hir().body(body.id()); return body.value.peel_blocks().hir_id == expr_hir_id; } false diff --git a/src/tools/clippy/clippy_lints/src/transmute/mod.rs b/src/tools/clippy/clippy_lints/src/transmute/mod.rs index 598032ccdebed..aa329ec33668d 100644 --- a/src/tools/clippy/clippy_lints/src/transmute/mod.rs +++ b/src/tools/clippy/clippy_lints/src/transmute/mod.rs @@ -546,7 +546,7 @@ declare_clippy_lint! { /// let x = std::mem::transmute::<[u16; 2], i32>([1u16, 2u16]); /// # } /// ``` - #[clippy::version = "1.77.0"] + #[clippy::version = "1.79.0"] pub MISSING_TRANSMUTE_ANNOTATIONS, suspicious, "warns if a transmute call doesn't have all generics specified" diff --git a/src/tools/clippy/clippy_lints/src/undocumented_unsafe_blocks.rs b/src/tools/clippy/clippy_lints/src/undocumented_unsafe_blocks.rs index 6cf9229fdd083..93a1089a97073 100644 --- a/src/tools/clippy/clippy_lints/src/undocumented_unsafe_blocks.rs +++ b/src/tools/clippy/clippy_lints/src/undocumented_unsafe_blocks.rs @@ -3,7 +3,7 @@ use std::ops::ControlFlow; use clippy_utils::diagnostics::span_lint_and_help; use clippy_utils::is_lint_allowed; use clippy_utils::source::walk_span_to_context; -use clippy_utils::visitors::{for_each_expr_with_closures, Descend}; +use clippy_utils::visitors::{for_each_expr, Descend}; use hir::HirId; use rustc_data_structures::sync::Lrc; use rustc_hir as hir; @@ -296,7 +296,7 @@ fn expr_has_unnecessary_safety_comment<'tcx>( } // this should roughly be the reverse of `block_parents_have_safety_comment` - if for_each_expr_with_closures(cx, expr, |expr| match expr.kind { + if for_each_expr(cx, expr, |expr| match expr.kind { hir::ExprKind::Block( Block { rules: BlockCheckMode::UnsafeBlock(UnsafeSource::UserProvided), diff --git a/src/tools/clippy/clippy_lints/src/unused_self.rs b/src/tools/clippy/clippy_lints/src/unused_self.rs index a67f53f00aee7..3e6102f5982fa 100644 --- a/src/tools/clippy/clippy_lints/src/unused_self.rs +++ b/src/tools/clippy/clippy_lints/src/unused_self.rs @@ -59,7 +59,7 @@ impl<'tcx> LateLintPass<'tcx> for UnusedSelf { let parent_item = cx.tcx.hir().expect_item(parent); let assoc_item = cx.tcx.associated_item(impl_item.owner_id); let contains_todo = |cx, body: &'_ Body<'_>| -> bool { - clippy_utils::visitors::for_each_expr(body.value, |e| { + clippy_utils::visitors::for_each_expr_without_closures(body.value, |e| { if let Some(macro_call) = root_macro_call_first_node(cx, e) { if cx.tcx.item_name(macro_call.def_id).as_str() == "todo" { ControlFlow::Break(()) diff --git a/src/tools/clippy/clippy_lints/src/unwrap_in_result.rs b/src/tools/clippy/clippy_lints/src/unwrap_in_result.rs index 197ab0f173bd8..f77badd97b7a3 100644 --- a/src/tools/clippy/clippy_lints/src/unwrap_in_result.rs +++ b/src/tools/clippy/clippy_lints/src/unwrap_in_result.rs @@ -77,7 +77,7 @@ fn lint_impl_body<'tcx>(cx: &LateContext<'tcx>, impl_span: Span, impl_item: &'tc let body = cx.tcx.hir().body(body_id); let typeck = cx.tcx.typeck(impl_item.owner_id.def_id); let mut result = Vec::new(); - let _: Option = for_each_expr(body.value, |e| { + let _: Option = for_each_expr(cx, body.value, |e| { // check for `expect` if let Some(arglists) = method_chain_args(e, &["expect"]) { let receiver_ty = typeck.expr_ty(arglists[0].0).peel_refs(); diff --git a/src/tools/clippy/clippy_lints/src/utils/author.rs b/src/tools/clippy/clippy_lints/src/utils/author.rs index 18a31abddd0af..e9d69407df8b5 100644 --- a/src/tools/clippy/clippy_lints/src/utils/author.rs +++ b/src/tools/clippy/clippy_lints/src/utils/author.rs @@ -733,7 +733,7 @@ impl<'a, 'tcx> PrintVisitor<'a, 'tcx> { match stmt.value.kind { StmtKind::Let(local) => { bind!(self, local); - kind!("Local({local})"); + kind!("Let({local})"); self.option(field!(local.init), "init", |init| { self.expr(init); }); diff --git a/src/tools/clippy/clippy_lints/src/utils/internal_lints/lint_without_lint_pass.rs b/src/tools/clippy/clippy_lints/src/utils/internal_lints/lint_without_lint_pass.rs index 9be225759df95..84f84781e7126 100644 --- a/src/tools/clippy/clippy_lints/src/utils/internal_lints/lint_without_lint_pass.rs +++ b/src/tools/clippy/clippy_lints/src/utils/internal_lints/lint_without_lint_pass.rs @@ -213,7 +213,7 @@ impl<'tcx> LateLintPass<'tcx> for LintWithoutLintPass { output: &mut self.registered_lints, cx, }; - let body_id = cx.tcx.hir().body_owned_by( + let body = cx.tcx.hir().body_owned_by( impl_item_refs .iter() .find(|iiref| iiref.ident.as_str() == "get_lints") @@ -222,7 +222,7 @@ impl<'tcx> LateLintPass<'tcx> for LintWithoutLintPass { .owner_id .def_id, ); - collector.visit_expr(cx.tcx.hir().body(body_id).value); + collector.visit_expr(body.value); } } } diff --git a/src/tools/clippy/clippy_lints/src/utils/internal_lints/metadata_collector.rs b/src/tools/clippy/clippy_lints/src/utils/internal_lints/metadata_collector.rs index 5c1ebb922f125..1c149f2045629 100644 --- a/src/tools/clippy/clippy_lints/src/utils/internal_lints/metadata_collector.rs +++ b/src/tools/clippy/clippy_lints/src/utils/internal_lints/metadata_collector.rs @@ -719,7 +719,7 @@ fn get_lint_group_and_level_or_lint( Some(sym::clippy), &std::iter::once(Ident::with_dummy_span(sym::clippy)).collect(), ); - if let CheckLintNameResult::Tool(Ok(lint_lst)) = result { + if let CheckLintNameResult::Tool(lint_lst, None) = result { if let Some(group) = get_lint_group(cx, lint_lst[0]) { if EXCLUDED_LINT_GROUPS.contains(&group.as_str()) { return None; diff --git a/src/tools/clippy/clippy_lints/src/zero_repeat_side_effects.rs b/src/tools/clippy/clippy_lints/src/zero_repeat_side_effects.rs index 8796b8f61d16a..ad041e55bdafb 100644 --- a/src/tools/clippy/clippy_lints/src/zero_repeat_side_effects.rs +++ b/src/tools/clippy/clippy_lints/src/zero_repeat_side_effects.rs @@ -1,7 +1,7 @@ use clippy_utils::diagnostics::span_lint_and_sugg; use clippy_utils::higher::VecArgs; use clippy_utils::source::snippet; -use clippy_utils::visitors::for_each_expr; +use clippy_utils::visitors::for_each_expr_without_closures; use rustc_ast::LitKind; use rustc_errors::Applicability; use rustc_hir::{ExprKind, Node}; @@ -36,7 +36,7 @@ declare_clippy_lint! { /// side_effect(); /// let a: [i32; 0] = []; /// ``` - #[clippy::version = "1.75.0"] + #[clippy::version = "1.79.0"] pub ZERO_REPEAT_SIDE_EFFECTS, suspicious, "usage of zero-sized initializations of arrays or vecs causing side effects" @@ -65,7 +65,7 @@ impl LateLintPass<'_> for ZeroRepeatSideEffects { fn inner_check(cx: &LateContext<'_>, expr: &'_ rustc_hir::Expr<'_>, inner_expr: &'_ rustc_hir::Expr<'_>, is_vec: bool) { // check if expr is a call or has a call inside it - if for_each_expr(inner_expr, |x| { + if for_each_expr_without_closures(inner_expr, |x| { if let ExprKind::Call(_, _) | ExprKind::MethodCall(_, _, _, _) = x.kind { std::ops::ControlFlow::Break(()) } else { diff --git a/src/tools/clippy/clippy_utils/Cargo.toml b/src/tools/clippy/clippy_utils/Cargo.toml index ab883c25338ba..3a3aeb8821643 100644 --- a/src/tools/clippy/clippy_utils/Cargo.toml +++ b/src/tools/clippy/clippy_utils/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "clippy_utils" -version = "0.1.80" +version = "0.1.81" edition = "2021" publish = false diff --git a/src/tools/clippy/clippy_utils/src/consts.rs b/src/tools/clippy/clippy_utils/src/consts.rs index e9e1aa7e4453f..cfd142fe1ff63 100644 --- a/src/tools/clippy/clippy_utils/src/consts.rs +++ b/src/tools/clippy/clippy_utils/src/consts.rs @@ -412,7 +412,8 @@ impl<'a, 'tcx> ConstEvalLateContext<'a, 'tcx> { /// Simple constant folding: Insert an expression, get a constant or none. pub fn expr(&mut self, e: &Expr<'_>) -> Option> { match e.kind { - ExprKind::ConstBlock(ConstBlock { body, .. }) => self.expr(self.lcx.tcx.hir().body(body).value), ExprKind::DropTemps(e) => self.expr(e), + ExprKind::ConstBlock(ConstBlock { body, .. }) => self.expr(self.lcx.tcx.hir().body(body).value), + ExprKind::DropTemps(e) => self.expr(e), ExprKind::Path(ref qpath) => { self.fetch_path_and_apply(qpath, e.hir_id, self.typeck_results.expr_ty(e), |this, result| { let result = mir_to_const(this.lcx, result)?; @@ -490,7 +491,8 @@ impl<'a, 'tcx> ConstEvalLateContext<'a, 'tcx> { /// leaves the local crate. pub fn expr_is_empty(&mut self, e: &Expr<'_>) -> Option { match e.kind { - ExprKind::ConstBlock(ConstBlock { body, .. }) => self.expr_is_empty(self.lcx.tcx.hir().body(body).value), ExprKind::DropTemps(e) => self.expr_is_empty(e), + ExprKind::ConstBlock(ConstBlock { body, .. }) => self.expr_is_empty(self.lcx.tcx.hir().body(body).value), + ExprKind::DropTemps(e) => self.expr_is_empty(e), ExprKind::Path(ref qpath) => { if !self .typeck_results @@ -811,12 +813,8 @@ pub fn mir_to_const<'tcx>(lcx: &LateContext<'tcx>, result: mir::Const<'tcx>) -> ty::Adt(adt_def, _) if adt_def.is_struct() => Some(Constant::Adt(result)), ty::Bool => Some(Constant::Bool(int == ScalarInt::TRUE)), ty::Uint(_) | ty::Int(_) => Some(Constant::Int(int.to_bits(int.size()))), - ty::Float(FloatTy::F32) => Some(Constant::F32(f32::from_bits( - int.try_into().expect("invalid f32 bit representation"), - ))), - ty::Float(FloatTy::F64) => Some(Constant::F64(f64::from_bits( - int.try_into().expect("invalid f64 bit representation"), - ))), + ty::Float(FloatTy::F32) => Some(Constant::F32(f32::from_bits(int.into()))), + ty::Float(FloatTy::F64) => Some(Constant::F64(f64::from_bits(int.into()))), ty::RawPtr(_, _) => Some(Constant::RawPtr(int.to_bits(int.size()))), _ => None, }, diff --git a/src/tools/clippy/clippy_utils/src/hir_utils.rs b/src/tools/clippy/clippy_utils/src/hir_utils.rs index 36634817fc91e..50dd8430ac069 100644 --- a/src/tools/clippy/clippy_utils/src/hir_utils.rs +++ b/src/tools/clippy/clippy_utils/src/hir_utils.rs @@ -7,9 +7,9 @@ use rustc_data_structures::fx::FxHasher; use rustc_hir::def::Res; use rustc_hir::MatchSource::TryDesugar; use rustc_hir::{ - ArrayLen, BinOpKind, BindingMode, Block, BodyId, Closure, Expr, ExprField, ExprKind, FnRetTy, GenericArg, - GenericArgs, HirId, HirIdMap, InlineAsmOperand, LetExpr, Lifetime, LifetimeName, Pat, PatField, PatKind, Path, - PathSegment, PrimTy, QPath, Stmt, StmtKind, Ty, TyKind, AssocItemConstraint, + ArrayLen, AssocItemConstraint, BinOpKind, BindingMode, Block, BodyId, Closure, Expr, ExprField, ExprKind, FnRetTy, + GenericArg, GenericArgs, HirId, HirIdMap, InlineAsmOperand, LetExpr, Lifetime, LifetimeName, Pat, PatField, + PatKind, Path, PathSegment, PrimTy, QPath, Stmt, StmtKind, Ty, TyKind, }; use rustc_lexer::{tokenize, TokenKind}; use rustc_lint::LateContext; @@ -519,7 +519,11 @@ impl HirEqInterExpr<'_, '_, '_> { } fn eq_assoc_type_binding(&mut self, left: &AssocItemConstraint<'_>, right: &AssocItemConstraint<'_>) -> bool { - left.ident.name == right.ident.name && self.eq_ty(left.ty().expect("expected assoc type binding"), right.ty().expect("expected assoc type binding")) + left.ident.name == right.ident.name + && self.eq_ty( + left.ty().expect("expected assoc type binding"), + right.ty().expect("expected assoc type binding"), + ) } fn check_ctxt(&mut self, left: SyntaxContext, right: SyntaxContext) -> bool { diff --git a/src/tools/clippy/clippy_utils/src/lib.rs b/src/tools/clippy/clippy_utils/src/lib.rs index 2f6bf92096776..7dc341ec8d71b 100644 --- a/src/tools/clippy/clippy_utils/src/lib.rs +++ b/src/tools/clippy/clippy_utils/src/lib.rs @@ -126,7 +126,7 @@ use visitors::Visitable; use crate::consts::{constant, mir_to_const, Constant}; use crate::higher::Range; use crate::ty::{adt_and_variant_of_res, can_partially_move_ty, expr_sig, is_copy, is_recursively_primitive_type}; -use crate::visitors::for_each_expr; +use crate::visitors::for_each_expr_without_closures; use rustc_middle::hir::nested_filter; @@ -321,6 +321,15 @@ pub fn match_trait_method(cx: &LateContext<'_>, expr: &Expr<'_>, path: &[&str]) .map_or(false, |trt_id| match_def_path(cx, trt_id, path)) } +/// Checks if the given method call expression calls an inherent method. +pub fn is_inherent_method_call(cx: &LateContext<'_>, expr: &Expr<'_>) -> bool { + if let Some(method_id) = cx.typeck_results().type_dependent_def_id(expr.hir_id) { + cx.tcx.trait_of_item(method_id).is_none() + } else { + false + } +} + /// Checks if a method is defined in an impl of a diagnostic item pub fn is_diag_item_method(cx: &LateContext<'_>, def_id: DefId, diag_item: Symbol) -> bool { if let Some(impl_did) = cx.tcx.impl_of_method(def_id) { @@ -1313,7 +1322,7 @@ pub fn contains_name<'tcx>(name: Symbol, expr: &'tcx Expr<'_>, cx: &LateContext< /// Returns `true` if `expr` contains a return expression pub fn contains_return<'tcx>(expr: impl Visitable<'tcx>) -> bool { - for_each_expr(expr, |e| { + for_each_expr_without_closures(expr, |e| { if matches!(e.kind, ExprKind::Ret(..)) { ControlFlow::Break(()) } else { @@ -3392,3 +3401,14 @@ pub fn binary_expr_needs_parentheses(expr: &Expr<'_>) -> bool { contains_block(expr, false) } + +/// Returns true if the specified expression is in a receiver position. +pub fn is_receiver_of_method_call(cx: &LateContext<'_>, expr: &Expr<'_>) -> bool { + if let Some(parent_expr) = get_parent_expr(cx, expr) + && let ExprKind::MethodCall(_, receiver, ..) = parent_expr.kind + && receiver.hir_id == expr.hir_id + { + return true; + } + false +} diff --git a/src/tools/clippy/clippy_utils/src/macros.rs b/src/tools/clippy/clippy_utils/src/macros.rs index 8daab9b0d92cf..455239cc37f35 100644 --- a/src/tools/clippy/clippy_utils/src/macros.rs +++ b/src/tools/clippy/clippy_utils/src/macros.rs @@ -1,6 +1,6 @@ #![allow(clippy::similar_names)] // `expr` and `expn` -use crate::visitors::{for_each_expr, Descend}; +use crate::visitors::{for_each_expr_without_closures, Descend}; use arrayvec::ArrayVec; use rustc_ast::{FormatArgs, FormatArgument, FormatPlaceholder}; @@ -323,7 +323,7 @@ fn find_assert_args_inner<'a, const N: usize>( Some(inner_name) => find_assert_within_debug_assert(cx, expr, expn, Symbol::intern(inner_name))?, }; let mut args = ArrayVec::new(); - let panic_expn = for_each_expr(expr, |e| { + let panic_expn = for_each_expr_without_closures(expr, |e| { if args.is_full() { match PanicExpn::parse(e) { Some(expn) => ControlFlow::Break(expn), @@ -349,7 +349,7 @@ fn find_assert_within_debug_assert<'a>( expn: ExpnId, assert_name: Symbol, ) -> Option<(&'a Expr<'a>, ExpnId)> { - for_each_expr(expr, |e| { + for_each_expr_without_closures(expr, |e| { if !e.span.from_expansion() { return ControlFlow::Continue(Descend::No); } @@ -397,7 +397,7 @@ impl FormatArgsStorage { /// /// See also [`find_format_arg_expr`] pub fn get(&self, cx: &LateContext<'_>, start: &Expr<'_>, expn_id: ExpnId) -> Option<&FormatArgs> { - let format_args_expr = for_each_expr(start, |expr| { + let format_args_expr = for_each_expr_without_closures(start, |expr| { let ctxt = expr.span.ctxt(); if ctxt.outer_expn().is_descendant_of(expn_id) { if macro_backtrace(expr.span) @@ -439,7 +439,7 @@ pub fn find_format_arg_expr<'hir, 'ast>( parent: _, } = target.expr.span.data(); - for_each_expr(start, |expr| { + for_each_expr_without_closures(start, |expr| { // When incremental compilation is enabled spans gain a parent during AST to HIR lowering, // since we're comparing an AST span to a HIR one we need to ignore the parent field let data = expr.span.data(); diff --git a/src/tools/clippy/clippy_utils/src/ptr.rs b/src/tools/clippy/clippy_utils/src/ptr.rs index 88837d8a143ed..991ea428dc33b 100644 --- a/src/tools/clippy/clippy_utils/src/ptr.rs +++ b/src/tools/clippy/clippy_utils/src/ptr.rs @@ -1,5 +1,5 @@ use crate::source::snippet; -use crate::visitors::{for_each_expr, Descend}; +use crate::visitors::{for_each_expr_without_closures, Descend}; use crate::{path_to_local_id, strip_pat_refs}; use core::ops::ControlFlow; use rustc_hir::{Body, BodyId, ExprKind, HirId, PatKind}; @@ -31,7 +31,7 @@ fn extract_clone_suggestions<'tcx>( body: &'tcx Body<'_>, ) -> Option)>> { let mut spans = Vec::new(); - for_each_expr(body, |e| { + for_each_expr_without_closures(body, |e| { if let ExprKind::MethodCall(seg, recv, [], _) = e.kind && path_to_local_id(recv, id) { diff --git a/src/tools/clippy/clippy_utils/src/qualify_min_const_fn.rs b/src/tools/clippy/clippy_utils/src/qualify_min_const_fn.rs index 81e94725a70cb..42b10f69c0cdf 100644 --- a/src/tools/clippy/clippy_utils/src/qualify_min_const_fn.rs +++ b/src/tools/clippy/clippy_utils/src/qualify_min_const_fn.rs @@ -40,9 +40,13 @@ pub fn is_min_const_fn<'tcx>(tcx: TyCtxt<'tcx>, body: &Body<'tcx>, msrv: &Msrv) )?; for bb in &*body.basic_blocks { - check_terminator(tcx, body, bb.terminator(), msrv)?; - for stmt in &bb.statements { - check_statement(tcx, body, def_id, stmt, msrv)?; + // Cleanup blocks are ignored entirely by const eval, so we can too: + // https://github.com/rust-lang/rust/blob/1dea922ea6e74f99a0e97de5cdb8174e4dea0444/compiler/rustc_const_eval/src/transform/check_consts/check.rs#L382 + if !bb.is_cleanup { + check_terminator(tcx, body, bb.terminator(), msrv)?; + for stmt in &bb.statements { + check_statement(tcx, body, def_id, stmt, msrv)?; + } } } Ok(()) diff --git a/src/tools/clippy/clippy_utils/src/source.rs b/src/tools/clippy/clippy_utils/src/source.rs index fd67e039c29a9..e2e5cde947d83 100644 --- a/src/tools/clippy/clippy_utils/src/source.rs +++ b/src/tools/clippy/clippy_utils/src/source.rs @@ -2,6 +2,7 @@ #![allow(clippy::module_name_repetitions)] +use rustc_ast::{LitKind, StrStyle}; use rustc_data_structures::sync::Lrc; use rustc_errors::Applicability; use rustc_hir::{BlockCheckMode, Expr, ExprKind, UnsafeSource}; @@ -500,6 +501,50 @@ pub fn expand_past_previous_comma(cx: &LateContext<'_>, span: Span) -> Span { extended.with_lo(extended.lo() - BytePos(1)) } +/// Converts `expr` to a `char` literal if it's a `str` literal containing a single +/// character (or a single byte with `ascii_only`) +pub fn str_literal_to_char_literal( + cx: &LateContext<'_>, + expr: &Expr<'_>, + applicability: &mut Applicability, + ascii_only: bool, +) -> Option { + if let ExprKind::Lit(lit) = &expr.kind + && let LitKind::Str(r, style) = lit.node + && let string = r.as_str() + && let len = if ascii_only { + string.len() + } else { + string.chars().count() + } + && len == 1 + { + let snip = snippet_with_applicability(cx, expr.span, string, applicability); + let ch = if let StrStyle::Raw(nhash) = style { + let nhash = nhash as usize; + // for raw string: r##"a"## + &snip[(nhash + 2)..(snip.len() - 1 - nhash)] + } else { + // for regular string: "a" + &snip[1..(snip.len() - 1)] + }; + + let hint = format!( + "'{}'", + match ch { + "'" => "\\'", + r"\" => "\\\\", + "\\\"" => "\"", // no need to escape `"` in `'"'` + _ => ch, + } + ); + + Some(hint) + } else { + None + } +} + #[cfg(test)] mod test { use super::{reindent_multiline, without_block_comments}; diff --git a/src/tools/clippy/clippy_utils/src/ty.rs b/src/tools/clippy/clippy_utils/src/ty.rs index 6e5626297c959..7d4332a3d9de8 100644 --- a/src/tools/clippy/clippy_utils/src/ty.rs +++ b/src/tools/clippy/clippy_utils/src/ty.rs @@ -17,9 +17,9 @@ use rustc_middle::mir::ConstValue; use rustc_middle::traits::EvaluationResult; use rustc_middle::ty::layout::ValidityRequirement; use rustc_middle::ty::{ - self, AdtDef, AliasTy, AssocKind, Binder, BoundRegion, FnSig, GenericArg, GenericArgKind, GenericArgsRef, - GenericParamDefKind, IntTy, ParamEnv, Region, RegionKind, TraitRef, Ty, TyCtxt, TypeSuperVisitable, TypeVisitable, - TypeVisitableExt, TypeVisitor, UintTy, Upcast, VariantDef, VariantDiscr, + self, AdtDef, AliasTy, AssocItem, AssocKind, Binder, BoundRegion, FnSig, GenericArg, GenericArgKind, + GenericArgsRef, GenericParamDefKind, IntTy, ParamEnv, Region, RegionKind, TraitRef, Ty, TyCtxt, TypeSuperVisitable, + TypeVisitable, TypeVisitableExt, TypeVisitor, UintTy, Upcast, VariantDef, VariantDiscr, }; use rustc_span::symbol::Ident; use rustc_span::{sym, Span, Symbol, DUMMY_SP}; @@ -861,7 +861,6 @@ impl core::ops::Add for EnumValue { } /// Attempts to read the given constant as though it were an enum value. -#[expect(clippy::cast_possible_truncation, clippy::cast_possible_wrap)] pub fn read_explicit_enum_value(tcx: TyCtxt<'_>, id: DefId) -> Option { if let Ok(ConstValue::Scalar(Scalar::Int(value))) = tcx.const_eval_poly(id) { match tcx.type_of(id).instantiate_identity().kind() { @@ -1314,3 +1313,39 @@ pub fn normalize_with_regions<'tcx>(tcx: TyCtxt<'tcx>, param_env: ParamEnv<'tcx> pub fn is_manually_drop(ty: Ty<'_>) -> bool { ty.ty_adt_def().map_or(false, AdtDef::is_manually_drop) } + +/// Returns the deref chain of a type, starting with the type itself. +pub fn deref_chain<'cx, 'tcx>(cx: &'cx LateContext<'tcx>, ty: Ty<'tcx>) -> impl Iterator> + 'cx { + iter::successors(Some(ty), |&ty| { + if let Some(deref_did) = cx.tcx.lang_items().deref_trait() + && implements_trait(cx, ty, deref_did, &[]) + { + make_normalized_projection(cx.tcx, cx.param_env, deref_did, sym::Target, [ty]) + } else { + None + } + }) +} + +/// Checks if a Ty<'_> has some inherent method Symbol. +/// This does not look for impls in the type's `Deref::Target` type. +/// If you need this, you should wrap this call in `clippy_utils::ty::deref_chain().any(...)`. +pub fn get_adt_inherent_method<'a>(cx: &'a LateContext<'_>, ty: Ty<'_>, method_name: Symbol) -> Option<&'a AssocItem> { + if let Some(ty_did) = ty.ty_adt_def().map(AdtDef::did) { + cx.tcx + .inherent_impls(ty_did) + .into_iter() + .flatten() + .map(|&did| { + cx.tcx + .associated_items(did) + .filter_by_name_unhygienic(method_name) + .next() + .filter(|item| item.kind == AssocKind::Fn) + }) + .next() + .flatten() + } else { + None + } +} diff --git a/src/tools/clippy/clippy_utils/src/ty/type_certainty/mod.rs b/src/tools/clippy/clippy_utils/src/ty/type_certainty/mod.rs index 8021930345026..cba61c841efc7 100644 --- a/src/tools/clippy/clippy_utils/src/ty/type_certainty/mod.rs +++ b/src/tools/clippy/clippy_utils/src/ty/type_certainty/mod.rs @@ -206,8 +206,18 @@ fn path_segment_certainty( // Checking `res_generics_def_id(..)` before calling `generics_of` avoids an ICE. if cx.tcx.res_generics_def_id(path_segment.res).is_some() { let generics = cx.tcx.generics_of(def_id); - let count = generics.own_params.len() - usize::from(generics.host_effect_index.is_some()); - let lhs = if (parent_certainty.is_certain() || generics.parent_count == 0) && count == 0 { + + let own_count = generics.own_params.len() + - usize::from(generics.host_effect_index.is_some_and(|index| { + // Check that the host index actually belongs to this resolution. + // E.g. for `Add::add`, host_effect_index is `Some(2)`, but it's part of the parent `Add` + // trait's generics. + // Add params: [Self#0, Rhs#1, host#2] parent_count=0, count=3 + // Add::add params: [] parent_count=3, count=3 + // (3..3).contains(&host_effect_index) => false + (generics.parent_count..generics.count()).contains(&index) + })); + let lhs = if (parent_certainty.is_certain() || generics.parent_count == 0) && own_count == 0 { Certainty::Certain(None) } else { Certainty::Uncertain diff --git a/src/tools/clippy/clippy_utils/src/usage.rs b/src/tools/clippy/clippy_utils/src/usage.rs index 2a25d51d8e509..fbf3d95365acb 100644 --- a/src/tools/clippy/clippy_utils/src/usage.rs +++ b/src/tools/clippy/clippy_utils/src/usage.rs @@ -1,4 +1,4 @@ -use crate::visitors::{for_each_expr, for_each_expr_with_closures, Descend, Visitable}; +use crate::visitors::{for_each_expr, for_each_expr_without_closures, Descend, Visitable}; use crate::{self as utils, get_enclosing_loop_or_multi_call_closure}; use core::ops::ControlFlow; use hir::def::Res; @@ -145,7 +145,7 @@ impl<'a, 'tcx> Visitor<'tcx> for BindingUsageFinder<'a, 'tcx> { } pub fn contains_return_break_continue_macro(expression: &Expr<'_>) -> bool { - for_each_expr(expression, |e| { + for_each_expr_without_closures(expression, |e| { match e.kind { ExprKind::Ret(..) | ExprKind::Break(..) | ExprKind::Continue(..) => ControlFlow::Break(()), // Something special could be done here to handle while or for loop @@ -159,7 +159,7 @@ pub fn contains_return_break_continue_macro(expression: &Expr<'_>) -> bool { } pub fn local_used_in<'tcx>(cx: &LateContext<'tcx>, local_id: HirId, v: impl Visitable<'tcx>) -> bool { - for_each_expr_with_closures(cx, v, |e| { + for_each_expr(cx, v, |e| { if utils::path_to_local_id(e, local_id) { ControlFlow::Break(()) } else { @@ -184,7 +184,7 @@ pub fn local_used_after_expr(cx: &LateContext<'_>, local_id: HirId, after: &Expr let loop_start = get_enclosing_loop_or_multi_call_closure(cx, after).map(|e| e.hir_id); let mut past_expr = false; - for_each_expr_with_closures(cx, block, |e| { + for_each_expr(cx, block, |e| { if past_expr { if utils::path_to_local_id(e, local_id) { ControlFlow::Break(()) diff --git a/src/tools/clippy/clippy_utils/src/visitors.rs b/src/tools/clippy/clippy_utils/src/visitors.rs index 90b56297bb556..3a39e178515db 100644 --- a/src/tools/clippy/clippy_utils/src/visitors.rs +++ b/src/tools/clippy/clippy_utils/src/visitors.rs @@ -100,7 +100,7 @@ visitable_ref!(Stmt, visit_stmt); /// Calls the given function once for each expression contained. This does not enter any bodies or /// nested items. -pub fn for_each_expr<'tcx, B, C: Continue>( +pub fn for_each_expr_without_closures<'tcx, B, C: Continue>( node: impl Visitable<'tcx>, f: impl FnMut(&'tcx Expr<'tcx>) -> ControlFlow, ) -> Option { @@ -134,7 +134,7 @@ pub fn for_each_expr<'tcx, B, C: Continue>( /// Calls the given function once for each expression contained. This will enter bodies, but not /// nested items. -pub fn for_each_expr_with_closures<'tcx, B, C: Continue>( +pub fn for_each_expr<'tcx, B, C: Continue>( cx: &LateContext<'tcx>, node: impl Visitable<'tcx>, f: impl FnMut(&'tcx Expr<'tcx>) -> ControlFlow, @@ -181,7 +181,7 @@ pub fn for_each_expr_with_closures<'tcx, B, C: Continue>( /// returns `true` if expr contains match expr desugared from try fn contains_try(expr: &Expr<'_>) -> bool { - for_each_expr(expr, |e| { + for_each_expr_without_closures(expr, |e| { if matches!(e.kind, ExprKind::Match(_, _, hir::MatchSource::TryDesugar(_))) { ControlFlow::Break(()) } else { @@ -286,7 +286,7 @@ where /// Checks if the given resolved path is used in the given body. pub fn is_res_used(cx: &LateContext<'_>, res: Res, body: BodyId) -> bool { - for_each_expr_with_closures(cx, cx.tcx.hir().body(body).value, |e| { + for_each_expr(cx, cx.tcx.hir().body(body).value, |e| { if let ExprKind::Path(p) = &e.kind { if cx.qpath_res(p, e.hir_id) == res { return ControlFlow::Break(()); @@ -299,7 +299,7 @@ pub fn is_res_used(cx: &LateContext<'_>, res: Res, body: BodyId) -> bool { /// Checks if the given local is used. pub fn is_local_used<'tcx>(cx: &LateContext<'tcx>, visitable: impl Visitable<'tcx>, id: HirId) -> bool { - for_each_expr_with_closures(cx, visitable, |e| { + for_each_expr(cx, visitable, |e| { if path_to_local_id(e, id) { ControlFlow::Break(()) } else { @@ -757,7 +757,7 @@ pub fn for_each_local_assignment<'tcx, B>( } pub fn contains_break_or_continue(expr: &Expr<'_>) -> bool { - for_each_expr(expr, |e| { + for_each_expr_without_closures(expr, |e| { if matches!(e.kind, ExprKind::Break(..) | ExprKind::Continue(..)) { ControlFlow::Break(()) } else { @@ -776,7 +776,7 @@ pub fn local_used_once<'tcx>( ) -> Option<&'tcx Expr<'tcx>> { let mut expr = None; - let cf = for_each_expr_with_closures(cx, visitable, |e| { + let cf = for_each_expr(cx, visitable, |e| { if path_to_local_id(e, id) && expr.replace(e).is_some() { ControlFlow::Break(()) } else { diff --git a/src/tools/clippy/declare_clippy_lint/Cargo.toml b/src/tools/clippy/declare_clippy_lint/Cargo.toml index c8c734c3a7c9f..86d945c14a58a 100644 --- a/src/tools/clippy/declare_clippy_lint/Cargo.toml +++ b/src/tools/clippy/declare_clippy_lint/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "declare_clippy_lint" -version = "0.1.80" +version = "0.1.81" edition = "2021" publish = false diff --git a/src/tools/clippy/lintcheck/README.md b/src/tools/clippy/lintcheck/README.md index 37cc045380949..61b581ba0faec 100644 --- a/src/tools/clippy/lintcheck/README.md +++ b/src/tools/clippy/lintcheck/README.md @@ -1,6 +1,6 @@ ## `cargo lintcheck` -Runs clippy on a fixed set of crates read from +Runs Clippy on a fixed set of crates read from `lintcheck/lintcheck_crates.toml` and saves logs of the lint warnings into the repo. We can then check the diff and spot new or disappearing warnings. @@ -84,7 +84,7 @@ This lets us spot bad suggestions or false positives automatically in some cases > Note: Fix mode implies `--all-targets`, so it can fix as much code as it can. -Please note that the target dir should be cleaned afterwards since clippy will modify +Please note that the target dir should be cleaned afterwards since Clippy will modify the downloaded sources which can lead to unexpected results when running lintcheck again afterwards. ### Recursive mode diff --git a/src/tools/clippy/rust-toolchain b/src/tools/clippy/rust-toolchain index dd8b9ece773e7..842c2f3de0d10 100644 --- a/src/tools/clippy/rust-toolchain +++ b/src/tools/clippy/rust-toolchain @@ -1,3 +1,3 @@ [toolchain] -channel = "nightly-2024-05-30" +channel = "nightly-2024-06-13" components = ["cargo", "llvm-tools", "rust-src", "rust-std", "rustc", "rustc-dev", "rustfmt"] diff --git a/src/tools/clippy/tests/ui-cargo/lint_groups_priority/fail/Cargo.stderr b/src/tools/clippy/tests/ui-cargo/lint_groups_priority/fail/Cargo.stderr index 9177e99f8e6e6..4fe7f6f7a9edb 100644 --- a/src/tools/clippy/tests/ui-cargo/lint_groups_priority/fail/Cargo.stderr +++ b/src/tools/clippy/tests/ui-cargo/lint_groups_priority/fail/Cargo.stderr @@ -1,17 +1,18 @@ error: lint group `rust_2018_idioms` has the same priority (0) as a lint - --> Cargo.toml:7:1 - | -7 | rust_2018_idioms = "warn" - | ^^^^^^^^^^^^^^^^ ------ has an implicit priority of 0 -8 | bare_trait_objects = "allow" - | ------------------ has the same priority as this lint - | - = note: the order of the lints in the table is ignored by Cargo - = note: `#[deny(clippy::lint_groups_priority)]` on by default + --> Cargo.toml:7:1 + | +7 | rust_2018_idioms = "warn" + | ^^^^^^^^^^^^^^^^ ------ has an implicit priority of 0 +... +12 | unused_attributes = { level = "allow" } + | ----------------- has the same priority as this lint + | + = note: the order of the lints in the table is ignored by Cargo + = note: `#[deny(clippy::lint_groups_priority)]` on by default help: to have lints override the group set `rust_2018_idioms` to a lower priority - | -7 | rust_2018_idioms = { level = "warn", priority = -1 } - | ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + | +7 | rust_2018_idioms = { level = "warn", priority = -1 } + | ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ error: lint group `unused` has the same priority (0) as a lint --> Cargo.toml:10:1 @@ -29,45 +30,45 @@ help: to have lints override the group set `unused` to a lower priority | ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ error: lint group `pedantic` has the same priority (-1) as a lint - --> Cargo.toml:19:1 + --> Cargo.toml:15:1 | -19 | pedantic = { level = "warn", priority = -1 } +15 | pedantic = { level = "warn", priority = -1 } | ^^^^^^^^ -20 | similar_names = { level = "allow", priority = -1 } +16 | similar_names = { level = "allow", priority = -1 } | ------------- has the same priority as this lint | = note: the order of the lints in the table is ignored by Cargo help: to have lints override the group set `pedantic` to a lower priority | -19 | pedantic = { level = "warn", priority = -2 } +15 | pedantic = { level = "warn", priority = -2 } | ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ error: lint group `rust_2018_idioms` has the same priority (0) as a lint - --> Cargo.toml:23:1 + --> Cargo.toml:19:1 | -23 | rust_2018_idioms = "warn" +19 | rust_2018_idioms = "warn" | ^^^^^^^^^^^^^^^^ ------ has an implicit priority of 0 -24 | bare_trait_objects = "allow" +20 | bare_trait_objects = "allow" | ------------------ has the same priority as this lint | = note: the order of the lints in the table is ignored by Cargo help: to have lints override the group set `rust_2018_idioms` to a lower priority | -23 | rust_2018_idioms = { level = "warn", priority = -1 } +19 | rust_2018_idioms = { level = "warn", priority = -1 } | ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ error: lint group `pedantic` has the same priority (0) as a lint - --> Cargo.toml:27:1 + --> Cargo.toml:23:1 | -27 | pedantic = "warn" +23 | pedantic = "warn" | ^^^^^^^^ ------ has an implicit priority of 0 -28 | similar_names = "allow" +24 | similar_names = "allow" | ------------- has the same priority as this lint | = note: the order of the lints in the table is ignored by Cargo help: to have lints override the group set `pedantic` to a lower priority | -27 | pedantic = { level = "warn", priority = -1 } +23 | pedantic = { level = "warn", priority = -1 } | ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ error: could not compile `fail` (lib) due to 5 previous errors diff --git a/src/tools/clippy/tests/ui-cargo/lint_groups_priority/fail/Cargo.toml b/src/tools/clippy/tests/ui-cargo/lint_groups_priority/fail/Cargo.toml index e4d4af9cd234a..c87662f822e16 100644 --- a/src/tools/clippy/tests/ui-cargo/lint_groups_priority/fail/Cargo.toml +++ b/src/tools/clippy/tests/ui-cargo/lint_groups_priority/fail/Cargo.toml @@ -11,10 +11,6 @@ unused = { level = "deny" } unused_braces = { level = "allow", priority = 1 } unused_attributes = { level = "allow" } -# `warnings` is not a group so the order it is passed does not matter -warnings = "deny" -deprecated = "allow" - [lints.clippy] pedantic = { level = "warn", priority = -1 } similar_names = { level = "allow", priority = -1 } diff --git a/src/tools/clippy/tests/ui-cargo/lint_groups_priority/pass/Cargo.toml b/src/tools/clippy/tests/ui-cargo/lint_groups_priority/pass/Cargo.toml index e9fcf803d9369..979c915cf0c13 100644 --- a/src/tools/clippy/tests/ui-cargo/lint_groups_priority/pass/Cargo.toml +++ b/src/tools/clippy/tests/ui-cargo/lint_groups_priority/pass/Cargo.toml @@ -3,6 +3,13 @@ name = "pass" version = "0.1.0" publish = false +[lints.rust] +# Warnings does not conflict with any group or lint +warnings = "deny" +# Groups & lints at the same level do not conflict +rust_2018_idioms = "warn" +unsafe_code = "warn" + [lints.clippy] pedantic = { level = "warn", priority = -1 } style = { level = "warn", priority = 1 } diff --git a/src/tools/clippy/tests/ui-toml/private-doc-errors/doc_lints.rs b/src/tools/clippy/tests/ui-toml/private-doc-errors/doc_lints.rs index ae4c3f84c2966..79c8751468de2 100644 --- a/src/tools/clippy/tests/ui-toml/private-doc-errors/doc_lints.rs +++ b/src/tools/clippy/tests/ui-toml/private-doc-errors/doc_lints.rs @@ -47,7 +47,7 @@ pub mod __macro { pub struct T; impl T { pub unsafe fn f() {} - //~^ ERROR: unsafe function's docs miss `# Safety` section + //~^ ERROR: unsafe function's docs are missing a `# Safety` section } } diff --git a/src/tools/clippy/tests/ui-toml/private-doc-errors/doc_lints.stderr b/src/tools/clippy/tests/ui-toml/private-doc-errors/doc_lints.stderr index 65ec1a7bebbf1..a8ee09b9df78f 100644 --- a/src/tools/clippy/tests/ui-toml/private-doc-errors/doc_lints.stderr +++ b/src/tools/clippy/tests/ui-toml/private-doc-errors/doc_lints.stderr @@ -51,7 +51,7 @@ note: the lint level is defined here LL | clippy::missing_panics_doc | ^^^^^^^^^^^^^^^^^^^^^^^^^^ -error: unsafe function's docs miss `# Safety` section +error: unsafe function's docs are missing a `# Safety` section --> tests/ui-toml/private-doc-errors/doc_lints.rs:49:9 | LL | pub unsafe fn f() {} diff --git a/src/tools/clippy/tests/ui-toml/type_repetition_in_bounds/main.rs b/src/tools/clippy/tests/ui-toml/type_repetition_in_bounds/main.rs index 2454c10382df7..7f93d2071c9db 100644 --- a/src/tools/clippy/tests/ui-toml/type_repetition_in_bounds/main.rs +++ b/src/tools/clippy/tests/ui-toml/type_repetition_in_bounds/main.rs @@ -1,3 +1,4 @@ +#![allow(clippy::needless_maybe_sized)] #![warn(clippy::type_repetition_in_bounds)] fn f() diff --git a/src/tools/clippy/tests/ui-toml/type_repetition_in_bounds/main.stderr b/src/tools/clippy/tests/ui-toml/type_repetition_in_bounds/main.stderr index 6005f76b94be8..c5102c39d1cff 100644 --- a/src/tools/clippy/tests/ui-toml/type_repetition_in_bounds/main.stderr +++ b/src/tools/clippy/tests/ui-toml/type_repetition_in_bounds/main.stderr @@ -1,5 +1,5 @@ error: this type has already been used as a bound predicate - --> tests/ui-toml/type_repetition_in_bounds/main.rs:13:5 + --> tests/ui-toml/type_repetition_in_bounds/main.rs:14:5 | LL | T: Unpin + PartialEq, | ^^^^^^^^^^^^^^^^^^^^ diff --git a/src/tools/clippy/tests/ui/author.stdout b/src/tools/clippy/tests/ui/author.stdout index d448db097a7e7..eed704e82fe1b 100644 --- a/src/tools/clippy/tests/ui/author.stdout +++ b/src/tools/clippy/tests/ui/author.stdout @@ -1,4 +1,4 @@ -if let StmtKind::Local(local) = stmt.kind +if let StmtKind::Let(local) = stmt.kind && let Some(init) = local.init && let ExprKind::Cast(expr, cast_ty) = init.kind && let TyKind::Path(ref qpath) = cast_ty.kind diff --git a/src/tools/clippy/tests/ui/author/blocks.stdout b/src/tools/clippy/tests/ui/author/blocks.stdout index 80b928dd6cb56..6bf48d5ba4ef8 100644 --- a/src/tools/clippy/tests/ui/author/blocks.stdout +++ b/src/tools/clippy/tests/ui/author/blocks.stdout @@ -1,12 +1,12 @@ if let ExprKind::Block(block, None) = expr.kind && block.stmts.len() == 3 - && let StmtKind::Local(local) = block.stmts[0].kind + && let StmtKind::Let(local) = block.stmts[0].kind && let Some(init) = local.init && let ExprKind::Lit(ref lit) = init.kind && let LitKind::Int(42, LitIntType::Signed(IntTy::I32)) = lit.node && let PatKind::Binding(BindingMode::NONE, _, name, None) = local.pat.kind && name.as_str() == "x" - && let StmtKind::Local(local1) = block.stmts[1].kind + && let StmtKind::Let(local1) = block.stmts[1].kind && let Some(init1) = local1.init && let ExprKind::Lit(ref lit1) = init1.kind && let LitKind::Float(_, LitFloatType::Suffixed(FloatTy::F32)) = lit1.node @@ -22,7 +22,7 @@ if let ExprKind::Block(block, None) = expr.kind } if let ExprKind::Block(block, None) = expr.kind && block.stmts.len() == 1 - && let StmtKind::Local(local) = block.stmts[0].kind + && let StmtKind::Let(local) = block.stmts[0].kind && let Some(init) = local.init && let ExprKind::Call(func, args) = init.kind && let ExprKind::Path(ref qpath) = func.kind diff --git a/src/tools/clippy/tests/ui/author/call.stdout b/src/tools/clippy/tests/ui/author/call.stdout index f040f6330a64d..59d4da490fe54 100644 --- a/src/tools/clippy/tests/ui/author/call.stdout +++ b/src/tools/clippy/tests/ui/author/call.stdout @@ -1,4 +1,4 @@ -if let StmtKind::Local(local) = stmt.kind +if let StmtKind::Let(local) = stmt.kind && let Some(init) = local.init && let ExprKind::Call(func, args) = init.kind && let ExprKind::Path(ref qpath) = func.kind diff --git a/src/tools/clippy/tests/ui/author/if.stdout b/src/tools/clippy/tests/ui/author/if.stdout index 5d79618820d80..a85dcddd3315f 100644 --- a/src/tools/clippy/tests/ui/author/if.stdout +++ b/src/tools/clippy/tests/ui/author/if.stdout @@ -1,4 +1,4 @@ -if let StmtKind::Local(local) = stmt.kind +if let StmtKind::Let(local) = stmt.kind && let Some(init) = local.init && let ExprKind::If(cond, then, Some(else_expr)) = init.kind && let ExprKind::DropTemps(expr) = cond.kind diff --git a/src/tools/clippy/tests/ui/author/issue_3849.stdout b/src/tools/clippy/tests/ui/author/issue_3849.stdout index 32a3127b85a3e..a5a8c0304ee40 100644 --- a/src/tools/clippy/tests/ui/author/issue_3849.stdout +++ b/src/tools/clippy/tests/ui/author/issue_3849.stdout @@ -1,4 +1,4 @@ -if let StmtKind::Local(local) = stmt.kind +if let StmtKind::Let(local) = stmt.kind && let Some(init) = local.init && let ExprKind::Call(func, args) = init.kind && let ExprKind::Path(ref qpath) = func.kind diff --git a/src/tools/clippy/tests/ui/author/loop.stdout b/src/tools/clippy/tests/ui/author/loop.stdout index 631105a2238de..609d24910610c 100644 --- a/src/tools/clippy/tests/ui/author/loop.stdout +++ b/src/tools/clippy/tests/ui/author/loop.stdout @@ -12,7 +12,7 @@ if let Some(higher::ForLoop { pat: pat, arg: arg, body: body, .. }) = higher::Fo && let LitKind::Int(10, LitIntType::Unsuffixed) = lit1.node && let ExprKind::Block(block, None) = body.kind && block.stmts.len() == 1 - && let StmtKind::Local(local) = block.stmts[0].kind + && let StmtKind::Let(local) = block.stmts[0].kind && let Some(init) = local.init && let ExprKind::Path(ref qpath1) = init.kind && match_qpath(qpath1, &["y"]) diff --git a/src/tools/clippy/tests/ui/author/macro_in_closure.stdout b/src/tools/clippy/tests/ui/author/macro_in_closure.stdout index b90c830e03079..66caf382d897b 100644 --- a/src/tools/clippy/tests/ui/author/macro_in_closure.stdout +++ b/src/tools/clippy/tests/ui/author/macro_in_closure.stdout @@ -1,4 +1,4 @@ -if let StmtKind::Local(local) = stmt.kind +if let StmtKind::Let(local) = stmt.kind && let Some(init) = local.init && let ExprKind::Closure { capture_clause: CaptureBy::Ref, fn_decl: fn_decl, body: body_id, closure_kind: ClosureKind::Closure, .. } = init.kind && let FnRetTy::DefaultReturn(_) = fn_decl.output diff --git a/src/tools/clippy/tests/ui/author/matches.stdout b/src/tools/clippy/tests/ui/author/matches.stdout index 30e4a9b2560ac..91b3b6f6877eb 100644 --- a/src/tools/clippy/tests/ui/author/matches.stdout +++ b/src/tools/clippy/tests/ui/author/matches.stdout @@ -1,4 +1,4 @@ -if let StmtKind::Local(local) = stmt.kind +if let StmtKind::Let(local) = stmt.kind && let Some(init) = local.init && let ExprKind::Match(scrutinee, arms, MatchSource::Normal) = init.kind && let ExprKind::Lit(ref lit) = scrutinee.kind @@ -16,7 +16,7 @@ if let StmtKind::Local(local) = stmt.kind && arms[1].guard.is_none() && let ExprKind::Block(block, None) = arms[1].body.kind && block.stmts.len() == 1 - && let StmtKind::Local(local1) = block.stmts[0].kind + && let StmtKind::Let(local1) = block.stmts[0].kind && let Some(init1) = local1.init && let ExprKind::Lit(ref lit4) = init1.kind && let LitKind::Int(3, LitIntType::Unsuffixed) = lit4.node diff --git a/src/tools/clippy/tests/ui/auxiliary/proc_macro_derive.rs b/src/tools/clippy/tests/ui/auxiliary/proc_macro_derive.rs index 79a95d775b11e..4c3df47226909 100644 --- a/src/tools/clippy/tests/ui/auxiliary/proc_macro_derive.rs +++ b/src/tools/clippy/tests/ui/auxiliary/proc_macro_derive.rs @@ -169,3 +169,16 @@ pub fn derive_ignored_unit_pattern(_: TokenStream) -> TokenStream { } } } + +#[proc_macro_derive(NonCanonicalClone)] +pub fn non_canonical_clone_derive(_: TokenStream) -> TokenStream { + quote! { + struct NonCanonicalClone; + impl Clone for NonCanonicalClone { + fn clone(&self) -> Self { + todo!() + } + } + impl Copy for NonCanonicalClone {} + } +} diff --git a/src/tools/clippy/tests/ui/auxiliary/proc_macros.rs b/src/tools/clippy/tests/ui/auxiliary/proc_macros.rs index 6e6919cd295c4..ed7412f7c4076 100644 --- a/src/tools/clippy/tests/ui/auxiliary/proc_macros.rs +++ b/src/tools/clippy/tests/ui/auxiliary/proc_macros.rs @@ -58,7 +58,7 @@ fn group_with_span(delimiter: Delimiter, stream: TokenStream, span: Span) -> Gro const ESCAPE_CHAR: char = '$'; /// Takes a single token followed by a sequence of tokens. Returns the sequence of tokens with their -/// span set to that of the first token. Tokens may be escaped with either `#ident` or `#(tokens)`. +/// span set to that of the first token. Tokens may be escaped with either `$ident` or `$(tokens)`. #[proc_macro] pub fn with_span(input: TokenStream) -> TokenStream { let mut iter = input.into_iter(); @@ -72,7 +72,7 @@ pub fn with_span(input: TokenStream) -> TokenStream { } /// Takes a sequence of tokens and return the tokens with the span set such that they appear to be -/// from an external macro. Tokens may be escaped with either `#ident` or `#(tokens)`. +/// from an external macro. Tokens may be escaped with either `$ident` or `$(tokens)`. #[proc_macro] pub fn external(input: TokenStream) -> TokenStream { let mut res = TokenStream::new(); @@ -84,7 +84,7 @@ pub fn external(input: TokenStream) -> TokenStream { } /// Copies all the tokens, replacing all their spans with the given span. Tokens can be escaped -/// either by `#ident` or `#(tokens)`. +/// either by `$ident` or `$(tokens)`. fn write_with_span(s: Span, mut input: IntoIter, out: &mut TokenStream) -> Result<()> { while let Some(tt) = input.next() { match tt { diff --git a/src/tools/clippy/tests/ui/blocks_in_conditions.fixed b/src/tools/clippy/tests/ui/blocks_in_conditions.fixed index a2da5f9c5fb98..af8e65270d091 100644 --- a/src/tools/clippy/tests/ui/blocks_in_conditions.fixed +++ b/src/tools/clippy/tests/ui/blocks_in_conditions.fixed @@ -117,4 +117,17 @@ mod issue_12016 { } } +fn in_closure() { + let v = vec![1, 2, 3]; + if v.into_iter() + .filter(|x| { + let y = x + 1; + y > 3 + }) + .any(|x| x == 5) + { + println!("contains 4!"); + } +} + fn main() {} diff --git a/src/tools/clippy/tests/ui/blocks_in_conditions.rs b/src/tools/clippy/tests/ui/blocks_in_conditions.rs index 608ca4cf267f6..6adae951a2901 100644 --- a/src/tools/clippy/tests/ui/blocks_in_conditions.rs +++ b/src/tools/clippy/tests/ui/blocks_in_conditions.rs @@ -117,4 +117,17 @@ mod issue_12016 { } } +fn in_closure() { + let v = vec![1, 2, 3]; + if v.into_iter() + .filter(|x| { + let y = x + 1; + y > 3 + }) + .any(|x| x == 5) + { + println!("contains 4!"); + } +} + fn main() {} diff --git a/src/tools/clippy/tests/ui/blocks_in_conditions_closure.rs b/src/tools/clippy/tests/ui/blocks_in_conditions_closure.rs deleted file mode 100644 index db31e4ae1a9a1..0000000000000 --- a/src/tools/clippy/tests/ui/blocks_in_conditions_closure.rs +++ /dev/null @@ -1,89 +0,0 @@ -#![warn(clippy::blocks_in_conditions)] -#![allow( - unused, - clippy::let_and_return, - clippy::needless_if, - clippy::unnecessary_literal_unwrap -)] - -fn predicate bool, T>(pfn: F, val: T) -> bool { - pfn(val) -} - -fn pred_test() { - let v = 3; - let sky = "blue"; - // This is a sneaky case, where the block isn't directly in the condition, - // but is actually inside a closure that the condition is using. - // The same principle applies -- add some extra expressions to make sure - // linter isn't confused by them. - if v == 3 - && sky == "blue" - && predicate( - |x| { - //~^ ERROR: in an `if` condition, avoid complex blocks or closures with blocks - //~| NOTE: `-D clippy::blocks-in-conditions` implied by `-D warnings` - let target = 3; - x == target - }, - v, - ) - {} - - if predicate( - |x| { - //~^ ERROR: in an `if` condition, avoid complex blocks or closures with blocks; in - let target = 3; - x == target - }, - v, - ) {} -} - -fn closure_without_block() { - if predicate(|x| x == 3, 6) {} -} - -fn macro_in_closure() { - let option = Some(true); - - if option.unwrap_or_else(|| unimplemented!()) { - unimplemented!() - } -} - -fn closure(_: impl FnMut()) -> bool { - true -} - -fn function_with_empty_closure() { - if closure(|| {}) {} -} - -// issue #11814 -fn match_with_pred() { - let v = 3; - match Some(predicate( - |x| { - //~^ ERROR: in a `match` scrutinee, avoid complex blocks or closures with blocks - let target = 3; - x == target - }, - v, - )) { - Some(true) => 1, - Some(false) => 2, - None => 3, - }; -} - -#[rustfmt::skip] -fn main() { - let mut range = 0..10; - range.all(|i| {i < 10} ); - - let v = vec![1, 2, 3]; - if v.into_iter().any(|x| {x == 4}) { - println!("contains 4!"); - } -} diff --git a/src/tools/clippy/tests/ui/blocks_in_conditions_closure.stderr b/src/tools/clippy/tests/ui/blocks_in_conditions_closure.stderr deleted file mode 100644 index 2faae680ec021..0000000000000 --- a/src/tools/clippy/tests/ui/blocks_in_conditions_closure.stderr +++ /dev/null @@ -1,39 +0,0 @@ -error: in an `if` condition, avoid complex blocks or closures with blocks; instead, move the block or closure higher and bind it with a `let` - --> tests/ui/blocks_in_conditions_closure.rs:23:17 - | -LL | |x| { - | _________________^ -LL | | -LL | | -LL | | let target = 3; -LL | | x == target -LL | | }, - | |_____________^ - | - = note: `-D clippy::blocks-in-conditions` implied by `-D warnings` - = help: to override `-D warnings` add `#[allow(clippy::blocks_in_conditions)]` - -error: in an `if` condition, avoid complex blocks or closures with blocks; instead, move the block or closure higher and bind it with a `let` - --> tests/ui/blocks_in_conditions_closure.rs:34:13 - | -LL | |x| { - | _____________^ -LL | | -LL | | let target = 3; -LL | | x == target -LL | | }, - | |_________^ - -error: in a `match` scrutinee, avoid complex blocks or closures with blocks; instead, move the block or closure higher and bind it with a `let` - --> tests/ui/blocks_in_conditions_closure.rs:67:13 - | -LL | |x| { - | _____________^ -LL | | -LL | | let target = 3; -LL | | x == target -LL | | }, - | |_________^ - -error: aborting due to 3 previous errors - diff --git a/src/tools/clippy/tests/ui/cfg_features.fixed b/src/tools/clippy/tests/ui/cfg_features.fixed deleted file mode 100644 index 0fe38f169f9c8..0000000000000 --- a/src/tools/clippy/tests/ui/cfg_features.fixed +++ /dev/null @@ -1,29 +0,0 @@ -#![warn(clippy::maybe_misused_cfg)] - -fn main() { - #[cfg(feature = "not-really-a-feature")] - //~^ ERROR: 'feature' may be misspelled as 'features' - //~| NOTE: `-D clippy::maybe-misused-cfg` implied by `-D warnings` - let _ = 1 + 2; - - #[cfg(all(feature = "right", feature = "wrong"))] - //~^ ERROR: 'feature' may be misspelled as 'features' - let _ = 1 + 2; - - #[cfg(all(feature = "wrong1", any(feature = "right", feature = "wrong2", feature, features)))] - //~^ ERROR: 'feature' may be misspelled as 'features' - //~| ERROR: 'feature' may be misspelled as 'features' - let _ = 1 + 2; - - #[cfg(test)] - //~^ ERROR: 'test' may be misspelled as 'tests' - let _ = 2; - #[cfg(test)] - //~^ ERROR: 'test' may be misspelled as 'Test' - let _ = 2; - - #[cfg(all(test, test))] - //~^ ERROR: 'test' may be misspelled as 'tests' - //~| ERROR: 'test' may be misspelled as 'Test' - let _ = 2; -} diff --git a/src/tools/clippy/tests/ui/cfg_features.rs b/src/tools/clippy/tests/ui/cfg_features.rs deleted file mode 100644 index 9c0db035eac41..0000000000000 --- a/src/tools/clippy/tests/ui/cfg_features.rs +++ /dev/null @@ -1,29 +0,0 @@ -#![warn(clippy::maybe_misused_cfg)] - -fn main() { - #[cfg(features = "not-really-a-feature")] - //~^ ERROR: 'feature' may be misspelled as 'features' - //~| NOTE: `-D clippy::maybe-misused-cfg` implied by `-D warnings` - let _ = 1 + 2; - - #[cfg(all(feature = "right", features = "wrong"))] - //~^ ERROR: 'feature' may be misspelled as 'features' - let _ = 1 + 2; - - #[cfg(all(features = "wrong1", any(feature = "right", features = "wrong2", feature, features)))] - //~^ ERROR: 'feature' may be misspelled as 'features' - //~| ERROR: 'feature' may be misspelled as 'features' - let _ = 1 + 2; - - #[cfg(tests)] - //~^ ERROR: 'test' may be misspelled as 'tests' - let _ = 2; - #[cfg(Test)] - //~^ ERROR: 'test' may be misspelled as 'Test' - let _ = 2; - - #[cfg(all(tests, Test))] - //~^ ERROR: 'test' may be misspelled as 'tests' - //~| ERROR: 'test' may be misspelled as 'Test' - let _ = 2; -} diff --git a/src/tools/clippy/tests/ui/cfg_features.stderr b/src/tools/clippy/tests/ui/cfg_features.stderr deleted file mode 100644 index d576271f1a291..0000000000000 --- a/src/tools/clippy/tests/ui/cfg_features.stderr +++ /dev/null @@ -1,53 +0,0 @@ -error: 'feature' may be misspelled as 'features' - --> tests/ui/cfg_features.rs:4:11 - | -LL | #[cfg(features = "not-really-a-feature")] - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: did you mean: `feature = "not-really-a-feature"` - | - = note: `-D clippy::maybe-misused-cfg` implied by `-D warnings` - = help: to override `-D warnings` add `#[allow(clippy::maybe_misused_cfg)]` - -error: 'feature' may be misspelled as 'features' - --> tests/ui/cfg_features.rs:9:34 - | -LL | #[cfg(all(feature = "right", features = "wrong"))] - | ^^^^^^^^^^^^^^^^^^ help: did you mean: `feature = "wrong"` - -error: 'feature' may be misspelled as 'features' - --> tests/ui/cfg_features.rs:13:15 - | -LL | #[cfg(all(features = "wrong1", any(feature = "right", features = "wrong2", feature, features)))] - | ^^^^^^^^^^^^^^^^^^^ help: did you mean: `feature = "wrong1"` - -error: 'feature' may be misspelled as 'features' - --> tests/ui/cfg_features.rs:13:59 - | -LL | #[cfg(all(features = "wrong1", any(feature = "right", features = "wrong2", feature, features)))] - | ^^^^^^^^^^^^^^^^^^^ help: did you mean: `feature = "wrong2"` - -error: 'test' may be misspelled as 'tests' - --> tests/ui/cfg_features.rs:18:11 - | -LL | #[cfg(tests)] - | ^^^^^ help: did you mean: `test` - -error: 'test' may be misspelled as 'Test' - --> tests/ui/cfg_features.rs:21:11 - | -LL | #[cfg(Test)] - | ^^^^ help: did you mean: `test` - -error: 'test' may be misspelled as 'tests' - --> tests/ui/cfg_features.rs:25:15 - | -LL | #[cfg(all(tests, Test))] - | ^^^^^ help: did you mean: `test` - -error: 'test' may be misspelled as 'Test' - --> tests/ui/cfg_features.rs:25:22 - | -LL | #[cfg(all(tests, Test))] - | ^^^^ help: did you mean: `test` - -error: aborting due to 8 previous errors - diff --git a/src/tools/clippy/tests/ui/crashes/ice-6252.stderr b/src/tools/clippy/tests/ui/crashes/ice-6252.stderr index ce3b9495eb1ea..cd2031af1c6da 100644 --- a/src/tools/clippy/tests/ui/crashes/ice-6252.stderr +++ b/src/tools/clippy/tests/ui/crashes/ice-6252.stderr @@ -4,9 +4,7 @@ error[E0412]: cannot find type `PhantomData` in this scope LL | _n: PhantomData, | ^^^^^^^^^^^ not found in this scope | -help: consider importing one of these items - | -LL + use core::marker::PhantomData; +help: consider importing this struct | LL + use std::marker::PhantomData; | diff --git a/src/tools/clippy/tests/ui/crashes/ice-9445.rs b/src/tools/clippy/tests/ui/crashes/ice-9445.rs index b6afbd33c79fb..c67b22f6f8c47 100644 --- a/src/tools/clippy/tests/ui/crashes/ice-9445.rs +++ b/src/tools/clippy/tests/ui/crashes/ice-9445.rs @@ -1,5 +1,3 @@ const UNINIT: core::mem::MaybeUninit> = core::mem::MaybeUninit::uninit(); -//~^ ERROR: a `const` item should never be interior mutable -//~| NOTE: `-D clippy::declare-interior-mutable-const` implied by `-D warnings` fn main() {} diff --git a/src/tools/clippy/tests/ui/crashes/ice-9445.stderr b/src/tools/clippy/tests/ui/crashes/ice-9445.stderr index d6957e9549d69..76689cd6f5c22 100644 --- a/src/tools/clippy/tests/ui/crashes/ice-9445.stderr +++ b/src/tools/clippy/tests/ui/crashes/ice-9445.stderr @@ -1,11 +1,10 @@ -error: a `const` item should never be interior mutable +error: a `const` item should not be interior mutable --> tests/ui/crashes/ice-9445.rs:1:1 | LL | const UNINIT: core::mem::MaybeUninit> = core::mem::MaybeUninit::uninit(); - | -----^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - | | - | make this a static item (maybe with lazy_static) + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | + = help: consider making this `Sync` so that it can go in a static item or using a `thread_local` = note: `-D clippy::declare-interior-mutable-const` implied by `-D warnings` = help: to override `-D warnings` add `#[allow(clippy::declare_interior_mutable_const)]` diff --git a/src/tools/clippy/tests/ui/crashes/mut_mut_macro.rs b/src/tools/clippy/tests/ui/crashes/mut_mut_macro.rs deleted file mode 100644 index 92821b6ecbbab..0000000000000 --- a/src/tools/clippy/tests/ui/crashes/mut_mut_macro.rs +++ /dev/null @@ -1,33 +0,0 @@ -#![deny(clippy::mut_mut, clippy::zero_ptr)] -#![allow(dead_code)] - -// FIXME: compiletest + extern crates doesn't work together. To make this test work, it would need -// the following three lines and the lazy_static crate. -// -// #[macro_use] -// extern crate lazy_static; -// use std::collections::HashMap; - -/// ensure that we don't suggest `is_null` inside constants -/// FIXME: once const fn is stable, suggest these functions again in constants - -const BAA: *const i32 = 0 as *const i32; -static mut BAR: *const i32 = BAA; -static mut FOO: *const i32 = 0 as *const i32; - -#[allow(unused_variables, unused_mut)] -fn main() { - /* - lazy_static! { - static ref MUT_MAP : HashMap = { - let mut m = HashMap::new(); - m.insert(0, "zero"); - m - }; - static ref MUT_COUNT : usize = MUT_MAP.len(); - } - assert_eq!(*MUT_COUNT, 1); - */ - // FIXME: don't lint in array length, requires `check_body` - //let _ = [""; (42.0 < f32::NAN) as usize]; -} diff --git a/src/tools/clippy/tests/ui/declare_interior_mutable_const/enums.stderr b/src/tools/clippy/tests/ui/declare_interior_mutable_const/enums.stderr index 6c0dce6b5eafb..22329172c3af0 100644 --- a/src/tools/clippy/tests/ui/declare_interior_mutable_const/enums.stderr +++ b/src/tools/clippy/tests/ui/declare_interior_mutable_const/enums.stderr @@ -1,87 +1,84 @@ -error: a `const` item should never be interior mutable +error: a `const` item should not be interior mutable --> tests/ui/declare_interior_mutable_const/enums.rs:12:1 | LL | const UNFROZEN_VARIANT: OptionalCell = OptionalCell::Unfrozen(Cell::new(true)); - | -----^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - | | - | make this a static item (maybe with lazy_static) + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | + = help: consider making this `Sync` so that it can go in a static item or using a `thread_local` = note: `-D clippy::declare-interior-mutable-const` implied by `-D warnings` = help: to override `-D warnings` add `#[allow(clippy::declare_interior_mutable_const)]` -error: a `const` item should never be interior mutable +error: a `const` item should not be interior mutable --> tests/ui/declare_interior_mutable_const/enums.rs:23:1 | LL | const UNFROZEN_VARIANT_FROM_FN: OptionalCell = unfrozen_variant(); - | -----^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - | | - | make this a static item (maybe with lazy_static) + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | + = help: consider making this `Sync` so that it can go in a static item or using a `thread_local` -error: a `const` item should never be interior mutable +error: a `const` item should not be interior mutable --> tests/ui/declare_interior_mutable_const/enums.rs:45:1 | -LL | const NESTED_UNFROZEN_VARIANT: NestedOutermost = NestedOutermost { - | ^---- - | | - | _make this a static item (maybe with lazy_static) - | | +LL | / const NESTED_UNFROZEN_VARIANT: NestedOutermost = NestedOutermost { LL | | LL | | outer: NestedOuter::NestedInner(NestedInner { LL | | inner: NestedInnermost::Unfrozen(AtomicUsize::new(2)), LL | | }), LL | | }; | |__^ + | + = help: consider making this a static item -error: a `const` item should never be interior mutable +error: a `const` item should not be interior mutable --> tests/ui/declare_interior_mutable_const/enums.rs:60:5 | LL | const TO_BE_UNFROZEN_VARIANT: OptionalCell; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -error: a `const` item should never be interior mutable +error: a `const` item should not be interior mutable --> tests/ui/declare_interior_mutable_const/enums.rs:61:5 | LL | const TO_BE_FROZEN_VARIANT: OptionalCell; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -error: a `const` item should never be interior mutable +error: a `const` item should not be interior mutable --> tests/ui/declare_interior_mutable_const/enums.rs:64:5 | LL | const DEFAULTED_ON_UNFROZEN_VARIANT: OptionalCell = OptionalCell::Unfrozen(Cell::new(false)); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -error: a `const` item should never be interior mutable +error: a `const` item should not be interior mutable --> tests/ui/declare_interior_mutable_const/enums.rs:90:5 | LL | const TO_BE_UNFROZEN_VARIANT: Option = Some(Self::ToBeUnfrozen::new(4)); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -error: a `const` item should never be interior mutable +error: a `const` item should not be interior mutable --> tests/ui/declare_interior_mutable_const/enums.rs:102:5 | LL | const UNFROZEN_VARIANT: BothOfCellAndGeneric = BothOfCellAndGeneric::Unfrozen(Cell::new(std::ptr::null())); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -error: a `const` item should never be interior mutable +error: a `const` item should not be interior mutable --> tests/ui/declare_interior_mutable_const/enums.rs:105:5 | LL | const GENERIC_VARIANT: BothOfCellAndGeneric = BothOfCellAndGeneric::Generic(std::ptr::null()); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -error: a `const` item should never be interior mutable +error: a `const` item should not be interior mutable --> tests/ui/declare_interior_mutable_const/enums.rs:111:5 | LL | const NO_ENUM: Cell<*const T> = Cell::new(std::ptr::null()); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -error: a `const` item should never be interior mutable +error: a `const` item should not be interior mutable --> tests/ui/declare_interior_mutable_const/enums.rs:118:5 | LL | / const UNFROZEN_VARIANT: BothOfCellAndGeneric = LL | | BothOfCellAndGeneric::Unfrozen(Cell::new(std::ptr::null())); | |____________________________________________________________________^ -error: a `const` item should never be interior mutable +error: a `const` item should not be interior mutable --> tests/ui/declare_interior_mutable_const/enums.rs:120:5 | LL | const GENERIC_VARIANT: BothOfCellAndGeneric = BothOfCellAndGeneric::Generic(std::ptr::null()); diff --git a/src/tools/clippy/tests/ui/declare_interior_mutable_const/others.stderr b/src/tools/clippy/tests/ui/declare_interior_mutable_const/others.stderr index 9dba0c952214b..1f2b9561ce509 100644 --- a/src/tools/clippy/tests/ui/declare_interior_mutable_const/others.stderr +++ b/src/tools/clippy/tests/ui/declare_interior_mutable_const/others.stderr @@ -1,31 +1,30 @@ -error: a `const` item should never be interior mutable +error: a `const` item should not be interior mutable --> tests/ui/declare_interior_mutable_const/others.rs:9:1 | LL | const ATOMIC: AtomicUsize = AtomicUsize::new(5); - | -----^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - | | - | make this a static item (maybe with lazy_static) + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | + = help: consider making this a static item = note: `-D clippy::declare-interior-mutable-const` implied by `-D warnings` = help: to override `-D warnings` add `#[allow(clippy::declare_interior_mutable_const)]` -error: a `const` item should never be interior mutable +error: a `const` item should not be interior mutable --> tests/ui/declare_interior_mutable_const/others.rs:10:1 | LL | const CELL: Cell = Cell::new(6); - | -----^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - | | - | make this a static item (maybe with lazy_static) + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | + = help: consider making this `Sync` so that it can go in a static item or using a `thread_local` -error: a `const` item should never be interior mutable +error: a `const` item should not be interior mutable --> tests/ui/declare_interior_mutable_const/others.rs:11:1 | LL | const ATOMIC_TUPLE: ([AtomicUsize; 1], Vec, u8) = ([ATOMIC], Vec::new(), 7); - | -----^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - | | - | make this a static item (maybe with lazy_static) + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | + = help: consider making this a static item -error: a `const` item should never be interior mutable +error: a `const` item should not be interior mutable --> tests/ui/declare_interior_mutable_const/others.rs:16:9 | LL | const $name: $ty = $e; @@ -36,7 +35,7 @@ LL | declare_const!(_ONCE: Once = Once::new()); | = note: this error originates in the macro `declare_const` (in Nightly builds, run with -Z macro-backtrace for more info) -error: a `const` item should never be interior mutable +error: a `const` item should not be interior mutable --> tests/ui/declare_interior_mutable_const/others.rs:44:13 | LL | const _BAZ: Cell = Cell::new(0); diff --git a/src/tools/clippy/tests/ui/declare_interior_mutable_const/traits.stderr b/src/tools/clippy/tests/ui/declare_interior_mutable_const/traits.stderr index 1d1e9e2002fa6..4a793d985e5ec 100644 --- a/src/tools/clippy/tests/ui/declare_interior_mutable_const/traits.stderr +++ b/src/tools/clippy/tests/ui/declare_interior_mutable_const/traits.stderr @@ -1,4 +1,4 @@ -error: a `const` item should never be interior mutable +error: a `const` item should not be interior mutable --> tests/ui/declare_interior_mutable_const/traits.rs:16:5 | LL | const ATOMIC: AtomicUsize; @@ -7,7 +7,7 @@ LL | const ATOMIC: AtomicUsize; = note: `-D clippy::declare-interior-mutable-const` implied by `-D warnings` = help: to override `-D warnings` add `#[allow(clippy::declare_interior_mutable_const)]` -error: a `const` item should never be interior mutable +error: a `const` item should not be interior mutable --> tests/ui/declare_interior_mutable_const/traits.rs:9:9 | LL | const $name: $ty = $e; @@ -18,67 +18,67 @@ LL | declare_const!(ANOTHER_ATOMIC: AtomicUsize = Self::ATOMIC); | = note: this error originates in the macro `declare_const` (in Nightly builds, run with -Z macro-backtrace for more info) -error: a `const` item should never be interior mutable +error: a `const` item should not be interior mutable --> tests/ui/declare_interior_mutable_const/traits.rs:44:5 | LL | const TO_BE_CONCRETE: AtomicUsize = AtomicUsize::new(11); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -error: a `const` item should never be interior mutable +error: a `const` item should not be interior mutable --> tests/ui/declare_interior_mutable_const/traits.rs:69:5 | LL | const TO_BE_UNFROZEN: Self::ToBeUnfrozen = AtomicUsize::new(13); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -error: a `const` item should never be interior mutable +error: a `const` item should not be interior mutable --> tests/ui/declare_interior_mutable_const/traits.rs:70:5 | LL | const WRAPPED_TO_BE_UNFROZEN: Wrapper = Wrapper(AtomicUsize::new(14)); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -error: a `const` item should never be interior mutable +error: a `const` item should not be interior mutable --> tests/ui/declare_interior_mutable_const/traits.rs:89:5 | LL | const BOUNDED: T::ToBeBounded; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -error: a `const` item should never be interior mutable +error: a `const` item should not be interior mutable --> tests/ui/declare_interior_mutable_const/traits.rs:117:5 | LL | const SELF: Self = AtomicUsize::new(17); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -error: a `const` item should never be interior mutable +error: a `const` item should not be interior mutable --> tests/ui/declare_interior_mutable_const/traits.rs:118:5 | LL | const WRAPPED_SELF: Option = Some(AtomicUsize::new(21)); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -error: a `const` item should never be interior mutable +error: a `const` item should not be interior mutable --> tests/ui/declare_interior_mutable_const/traits.rs:124:5 | LL | const DIRECT: Cell; | ^^^^^^^^^^^^^^^^^^^^^^ -error: a `const` item should never be interior mutable +error: a `const` item should not be interior mutable --> tests/ui/declare_interior_mutable_const/traits.rs:125:5 | LL | const INDIRECT: Cell<*const T>; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -error: a `const` item should never be interior mutable +error: a `const` item should not be interior mutable --> tests/ui/declare_interior_mutable_const/traits.rs:129:5 | LL | const DIRECT: Cell = Cell::new(T::DEFAULT); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -error: a `const` item should never be interior mutable +error: a `const` item should not be interior mutable --> tests/ui/declare_interior_mutable_const/traits.rs:141:5 | LL | const ATOMIC: AtomicUsize = AtomicUsize::new(18); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -error: a `const` item should never be interior mutable +error: a `const` item should not be interior mutable --> tests/ui/declare_interior_mutable_const/traits.rs:147:5 | LL | const BOUNDED_ASSOC_TYPE: T::ToBeBounded = AtomicUsize::new(19); diff --git a/src/tools/clippy/tests/ui/deprecated.rs b/src/tools/clippy/tests/ui/deprecated.rs index 07270bd76362a..d3c34fb371674 100644 --- a/src/tools/clippy/tests/ui/deprecated.rs +++ b/src/tools/clippy/tests/ui/deprecated.rs @@ -18,5 +18,7 @@ #![warn(clippy::filter_map)] #![warn(clippy::pub_enum_variant_names)] #![warn(clippy::wrong_pub_self_convention)] +#![warn(clippy::maybe_misused_cfg)] +#![warn(clippy::mismatched_target_os)] fn main() {} diff --git a/src/tools/clippy/tests/ui/deprecated.stderr b/src/tools/clippy/tests/ui/deprecated.stderr index a9cf04bea5257..49b90c70c06ef 100644 --- a/src/tools/clippy/tests/ui/deprecated.stderr +++ b/src/tools/clippy/tests/ui/deprecated.stderr @@ -97,5 +97,17 @@ error: lint `clippy::wrong_pub_self_convention` has been removed: set the `avoid LL | #![warn(clippy::wrong_pub_self_convention)] | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -error: aborting due to 16 previous errors +error: lint `clippy::maybe_misused_cfg` has been removed: this lint has been replaced by `unexpected_cfgs` + --> tests/ui/deprecated.rs:21:9 + | +LL | #![warn(clippy::maybe_misused_cfg)] + | ^^^^^^^^^^^^^^^^^^^^^^^^^ + +error: lint `clippy::mismatched_target_os` has been removed: this lint has been replaced by `unexpected_cfgs` + --> tests/ui/deprecated.rs:22:9 + | +LL | #![warn(clippy::mismatched_target_os)] + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +error: aborting due to 18 previous errors diff --git a/src/tools/clippy/tests/ui/deref_addrof.fixed b/src/tools/clippy/tests/ui/deref_addrof.fixed index aa1cf19b76f93..b6278c6ca8a52 100644 --- a/src/tools/clippy/tests/ui/deref_addrof.fixed +++ b/src/tools/clippy/tests/ui/deref_addrof.fixed @@ -43,6 +43,10 @@ fn main() { let b = *aref; let _ = unsafe { *core::ptr::addr_of!(a) }; + + let _repeat = [0; 64]; + // do NOT lint for array as sematic differences with/out `*&`. + let _arr = *&[0, 1, 2, 3, 4]; } #[derive(Copy, Clone)] diff --git a/src/tools/clippy/tests/ui/deref_addrof.rs b/src/tools/clippy/tests/ui/deref_addrof.rs index 38796aef390e3..572b0fdb10273 100644 --- a/src/tools/clippy/tests/ui/deref_addrof.rs +++ b/src/tools/clippy/tests/ui/deref_addrof.rs @@ -43,6 +43,10 @@ fn main() { let b = **&aref; let _ = unsafe { *core::ptr::addr_of!(a) }; + + let _repeat = *&[0; 64]; + // do NOT lint for array as sematic differences with/out `*&`. + let _arr = *&[0, 1, 2, 3, 4]; } #[derive(Copy, Clone)] diff --git a/src/tools/clippy/tests/ui/deref_addrof.stderr b/src/tools/clippy/tests/ui/deref_addrof.stderr index 5e3cb417aa0e1..20069f746c81c 100644 --- a/src/tools/clippy/tests/ui/deref_addrof.stderr +++ b/src/tools/clippy/tests/ui/deref_addrof.stderr @@ -50,7 +50,13 @@ LL | let b = **&aref; | ^^^^^^ help: try: `aref` error: immediately dereferencing a reference - --> tests/ui/deref_addrof.rs:53:17 + --> tests/ui/deref_addrof.rs:47:19 + | +LL | let _repeat = *&[0; 64]; + | ^^^^^^^^^ help: try: `[0; 64]` + +error: immediately dereferencing a reference + --> tests/ui/deref_addrof.rs:57:17 | LL | inline!(*& $(@expr self)) | ^^^^^^^^^^^^^^^^ help: try: `$(@expr self)` @@ -58,12 +64,12 @@ LL | inline!(*& $(@expr self)) = note: this error originates in the macro `__inline_mac_impl` (in Nightly builds, run with -Z macro-backtrace for more info) error: immediately dereferencing a reference - --> tests/ui/deref_addrof.rs:57:17 + --> tests/ui/deref_addrof.rs:61:17 | LL | inline!(*&mut $(@expr self)) | ^^^^^^^^^^^^^^^^^^^ help: try: `$(@expr self)` | = note: this error originates in the macro `__inline_mac_impl` (in Nightly builds, run with -Z macro-backtrace for more info) -error: aborting due to 10 previous errors +error: aborting due to 11 previous errors diff --git a/src/tools/clippy/tests/ui/doc_unsafe.stderr b/src/tools/clippy/tests/ui/doc_unsafe.stderr index 4fcbe716951f6..929afbceb879d 100644 --- a/src/tools/clippy/tests/ui/doc_unsafe.stderr +++ b/src/tools/clippy/tests/ui/doc_unsafe.stderr @@ -1,4 +1,4 @@ -error: unsafe function's docs miss `# Safety` section +error: unsafe function's docs are missing a `# Safety` section --> tests/ui/doc_unsafe.rs:9:1 | LL | pub unsafe fn destroy_the_planet() { @@ -7,13 +7,13 @@ LL | pub unsafe fn destroy_the_planet() { = note: `-D clippy::missing-safety-doc` implied by `-D warnings` = help: to override `-D warnings` add `#[allow(clippy::missing_safety_doc)]` -error: unsafe function's docs miss `# Safety` section +error: unsafe function's docs are missing a `# Safety` section --> tests/ui/doc_unsafe.rs:32:5 | LL | pub unsafe fn republished() { | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ -error: unsafe function's docs miss `# Safety` section +error: unsafe function's docs are missing a `# Safety` section --> tests/ui/doc_unsafe.rs:40:5 | LL | unsafe fn woefully_underdocumented(self); @@ -25,13 +25,13 @@ error: docs for unsafe trait missing `# Safety` section LL | pub unsafe trait UnsafeTrait { | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -error: unsafe function's docs miss `# Safety` section +error: unsafe function's docs are missing a `# Safety` section --> tests/ui/doc_unsafe.rs:76:5 | LL | pub unsafe fn more_undocumented_unsafe() -> Self { | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -error: unsafe function's docs miss `# Safety` section +error: unsafe function's docs are missing a `# Safety` section --> tests/ui/doc_unsafe.rs:92:9 | LL | pub unsafe fn whee() { diff --git a/src/tools/clippy/tests/ui/double_neg.rs b/src/tools/clippy/tests/ui/double_neg.rs index da82890443eb8..3be8c62887381 100644 --- a/src/tools/clippy/tests/ui/double_neg.rs +++ b/src/tools/clippy/tests/ui/double_neg.rs @@ -5,6 +5,6 @@ fn main() { -x; -(-x); --x; - //~^ ERROR: `--x` could be misinterpreted as pre-decrement by C programmers, is usuall + //~^ ERROR: `--x` could be misinterpreted as pre-decrement by C programmers, is usually //~| NOTE: `-D clippy::double-neg` implied by `-D warnings` } diff --git a/src/tools/clippy/tests/ui/eta.fixed b/src/tools/clippy/tests/ui/eta.fixed index da28ec2e653a7..7126f2799455f 100644 --- a/src/tools/clippy/tests/ui/eta.fixed +++ b/src/tools/clippy/tests/ui/eta.fixed @@ -471,3 +471,14 @@ mod issue_10854 { } } } + +mod issue_12853 { + fn f_by_value(f: F) { + let x = Box::new(|| None.map(&f)); + x(); + } + fn f_by_ref(f: &F) { + let x = Box::new(|| None.map(f)); + x(); + } +} diff --git a/src/tools/clippy/tests/ui/eta.rs b/src/tools/clippy/tests/ui/eta.rs index f924100f8f419..0787abf5f3e37 100644 --- a/src/tools/clippy/tests/ui/eta.rs +++ b/src/tools/clippy/tests/ui/eta.rs @@ -471,3 +471,14 @@ mod issue_10854 { } } } + +mod issue_12853 { + fn f_by_value(f: F) { + let x = Box::new(|| None.map(|x| f(x))); + x(); + } + fn f_by_ref(f: &F) { + let x = Box::new(|| None.map(|x| f(x))); + x(); + } +} diff --git a/src/tools/clippy/tests/ui/eta.stderr b/src/tools/clippy/tests/ui/eta.stderr index d9a8768a68217..c757601042f16 100644 --- a/src/tools/clippy/tests/ui/eta.stderr +++ b/src/tools/clippy/tests/ui/eta.stderr @@ -190,5 +190,17 @@ error: redundant closure LL | test.map(|t| t.method()) | ^^^^^^^^^^^^^^ help: replace the closure with the method itself: `crate::issue_10854::d::Test::method` -error: aborting due to 31 previous errors +error: redundant closure + --> tests/ui/eta.rs:477:38 + | +LL | let x = Box::new(|| None.map(|x| f(x))); + | ^^^^^^^^ help: replace the closure with the function itself: `&f` + +error: redundant closure + --> tests/ui/eta.rs:481:38 + | +LL | let x = Box::new(|| None.map(|x| f(x))); + | ^^^^^^^^ help: replace the closure with the function itself: `f` + +error: aborting due to 33 previous errors diff --git a/src/tools/clippy/tests/ui/floating_point_log.fixed b/src/tools/clippy/tests/ui/floating_point_log.fixed index 01f0fc5c671ad..15cc47eef0dd0 100644 --- a/src/tools/clippy/tests/ui/floating_point_log.fixed +++ b/src/tools/clippy/tests/ui/floating_point_log.fixed @@ -55,4 +55,19 @@ fn check_ln1p() { let _ = (1.0 + x - 2.0).ln(); } +fn issue12881() { + pub trait MyLog { + fn log(&self) -> Self; + } + + impl MyLog for f32 { + fn log(&self) -> Self { + 4. + } + } + + let x = 2.0; + x.log(); +} + fn main() {} diff --git a/src/tools/clippy/tests/ui/floating_point_log.rs b/src/tools/clippy/tests/ui/floating_point_log.rs index 197e3e1ff9097..1241af8285932 100644 --- a/src/tools/clippy/tests/ui/floating_point_log.rs +++ b/src/tools/clippy/tests/ui/floating_point_log.rs @@ -55,4 +55,19 @@ fn check_ln1p() { let _ = (1.0 + x - 2.0).ln(); } +fn issue12881() { + pub trait MyLog { + fn log(&self) -> Self; + } + + impl MyLog for f32 { + fn log(&self) -> Self { + 4. + } + } + + let x = 2.0; + x.log(); +} + fn main() {} diff --git a/src/tools/clippy/tests/ui/format_args.fixed b/src/tools/clippy/tests/ui/format_args.fixed index cab20b11e0731..4d812f6bf1dce 100644 --- a/src/tools/clippy/tests/ui/format_args.fixed +++ b/src/tools/clippy/tests/ui/format_args.fixed @@ -104,6 +104,7 @@ fn main() { println!("{foo}{bar}", foo = "foo", bar = "bar"); println!("{foo}{bar}", bar = "bar", foo = "foo"); println!("{foo}{bar}", bar = "bar", foo = "foo"); + println!("{}", my_other_macro!()); // negative tests println!("error: something failed at {}", Somewhere.to_string()); diff --git a/src/tools/clippy/tests/ui/format_args.rs b/src/tools/clippy/tests/ui/format_args.rs index bc3645cb2c2bc..d242623feb62a 100644 --- a/src/tools/clippy/tests/ui/format_args.rs +++ b/src/tools/clippy/tests/ui/format_args.rs @@ -104,6 +104,7 @@ fn main() { println!("{foo}{bar}", foo = "foo", bar = "bar".to_string()); println!("{foo}{bar}", bar = "bar".to_string(), foo = "foo"); println!("{foo}{bar}", bar = "bar", foo = "foo".to_string()); + println!("{}", my_other_macro!().to_string()); // negative tests println!("error: something failed at {}", Somewhere.to_string()); diff --git a/src/tools/clippy/tests/ui/format_args.stderr b/src/tools/clippy/tests/ui/format_args.stderr index f20cf9eca2f9d..91a45e2700811 100644 --- a/src/tools/clippy/tests/ui/format_args.stderr +++ b/src/tools/clippy/tests/ui/format_args.stderr @@ -127,29 +127,35 @@ error: `to_string` applied to a type that implements `Display` in `println!` arg LL | println!("{foo}{bar}", bar = "bar", foo = "foo".to_string()); | ^^^^^^^^^^^^ help: remove this +error: `to_string` applied to a type that implements `Display` in `println!` args + --> tests/ui/format_args.rs:107:37 + | +LL | println!("{}", my_other_macro!().to_string()); + | ^^^^^^^^^^^^ help: remove this + error: `to_string` applied to a type that implements `Display` in `print!` args - --> tests/ui/format_args.rs:118:37 + --> tests/ui/format_args.rs:119:37 | LL | print!("{}", (Location::caller().to_string())); | ^^^^^^^^^^^^ help: remove this error: `to_string` applied to a type that implements `Display` in `print!` args - --> tests/ui/format_args.rs:119:39 + --> tests/ui/format_args.rs:120:39 | LL | print!("{}", ((Location::caller()).to_string())); | ^^^^^^^^^^^^ help: remove this error: `to_string` applied to a type that implements `Display` in `format!` args - --> tests/ui/format_args.rs:147:38 + --> tests/ui/format_args.rs:148:38 | LL | let x = format!("{} {}", a, b.to_string()); | ^^^^^^^^^^^^ help: remove this error: `to_string` applied to a type that implements `Display` in `println!` args - --> tests/ui/format_args.rs:161:24 + --> tests/ui/format_args.rs:162:24 | LL | println!("{}", original[..10].to_string()); | ^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use this: `&original[..10]` -error: aborting due to 25 previous errors +error: aborting due to 26 previous errors diff --git a/src/tools/clippy/tests/ui/indexing_slicing_index.rs b/src/tools/clippy/tests/ui/indexing_slicing_index.rs index 2e726141649e7..2af5fcc82a9bf 100644 --- a/src/tools/clippy/tests/ui/indexing_slicing_index.rs +++ b/src/tools/clippy/tests/ui/indexing_slicing_index.rs @@ -1,4 +1,5 @@ //@compile-flags: -Zdeduplicate-diagnostics=yes +//@aux-build: proc_macros.rs #![warn(clippy::indexing_slicing)] // We also check the out_of_bounds_indexing lint here, because it lints similar things and @@ -11,6 +12,9 @@ clippy::useless_vec )] +extern crate proc_macros; +use proc_macros::with_span; + const ARR: [i32; 2] = [1, 2]; const REF: &i32 = &ARR[idx()]; // This should be linted, since `suppress-restriction-lint-in-const` default is false. //~^ ERROR: indexing may panic @@ -22,6 +26,22 @@ const fn idx4() -> usize { 4 } +with_span!( + span + + fn dont_lint_proc_macro_array() { + let x = [1, 2, 3, 4]; + let index: usize = 1; + x[index]; + x[10]; + + let x = vec![0; 5]; + let index: usize = 1; + x[index]; + x[10]; + } +); + fn main() { let x = [1, 2, 3, 4]; let index: usize = 1; diff --git a/src/tools/clippy/tests/ui/indexing_slicing_index.stderr b/src/tools/clippy/tests/ui/indexing_slicing_index.stderr index 386f91becf14d..71677584d25bb 100644 --- a/src/tools/clippy/tests/ui/indexing_slicing_index.stderr +++ b/src/tools/clippy/tests/ui/indexing_slicing_index.stderr @@ -1,5 +1,5 @@ error: indexing may panic - --> tests/ui/indexing_slicing_index.rs:15:20 + --> tests/ui/indexing_slicing_index.rs:19:20 | LL | const REF: &i32 = &ARR[idx()]; // This should be linted, since `suppress-restriction-lint-in-const` default is false. | ^^^^^^^^^^ @@ -10,19 +10,19 @@ LL | const REF: &i32 = &ARR[idx()]; // This should be linted, since `suppress-re = help: to override `-D warnings` add `#[allow(clippy::indexing_slicing)]` error[E0080]: evaluation of `main::{constant#3}` failed - --> tests/ui/indexing_slicing_index.rs:47:14 + --> tests/ui/indexing_slicing_index.rs:67:14 | LL | const { &ARR[idx4()] }; | ^^^^^^^^^^^ index out of bounds: the length is 2 but the index is 4 note: erroneous constant encountered - --> tests/ui/indexing_slicing_index.rs:47:5 + --> tests/ui/indexing_slicing_index.rs:67:5 | LL | const { &ARR[idx4()] }; | ^^^^^^^^^^^^^^^^^^^^^^ error: indexing may panic - --> tests/ui/indexing_slicing_index.rs:28:5 + --> tests/ui/indexing_slicing_index.rs:48:5 | LL | x[index]; | ^^^^^^^^ @@ -30,7 +30,7 @@ LL | x[index]; = help: consider using `.get(n)` or `.get_mut(n)` instead error: index is out of bounds - --> tests/ui/indexing_slicing_index.rs:31:5 + --> tests/ui/indexing_slicing_index.rs:51:5 | LL | x[4]; | ^^^^ @@ -39,13 +39,13 @@ LL | x[4]; = help: to override `-D warnings` add `#[allow(clippy::out_of_bounds_indexing)]` error: index is out of bounds - --> tests/ui/indexing_slicing_index.rs:33:5 + --> tests/ui/indexing_slicing_index.rs:53:5 | LL | x[1 << 3]; | ^^^^^^^^^ error: indexing may panic - --> tests/ui/indexing_slicing_index.rs:44:14 + --> tests/ui/indexing_slicing_index.rs:64:14 | LL | const { &ARR[idx()] }; | ^^^^^^^^^^ @@ -54,7 +54,7 @@ LL | const { &ARR[idx()] }; = note: the suggestion might not be applicable in constant blocks error: indexing may panic - --> tests/ui/indexing_slicing_index.rs:47:14 + --> tests/ui/indexing_slicing_index.rs:67:14 | LL | const { &ARR[idx4()] }; | ^^^^^^^^^^^ @@ -63,13 +63,13 @@ LL | const { &ARR[idx4()] }; = note: the suggestion might not be applicable in constant blocks error: index is out of bounds - --> tests/ui/indexing_slicing_index.rs:54:5 + --> tests/ui/indexing_slicing_index.rs:74:5 | LL | y[4]; | ^^^^ error: indexing may panic - --> tests/ui/indexing_slicing_index.rs:57:5 + --> tests/ui/indexing_slicing_index.rs:77:5 | LL | v[0]; | ^^^^ @@ -77,7 +77,7 @@ LL | v[0]; = help: consider using `.get(n)` or `.get_mut(n)` instead error: indexing may panic - --> tests/ui/indexing_slicing_index.rs:59:5 + --> tests/ui/indexing_slicing_index.rs:79:5 | LL | v[10]; | ^^^^^ @@ -85,7 +85,7 @@ LL | v[10]; = help: consider using `.get(n)` or `.get_mut(n)` instead error: indexing may panic - --> tests/ui/indexing_slicing_index.rs:61:5 + --> tests/ui/indexing_slicing_index.rs:81:5 | LL | v[1 << 3]; | ^^^^^^^^^ @@ -93,13 +93,13 @@ LL | v[1 << 3]; = help: consider using `.get(n)` or `.get_mut(n)` instead error: index is out of bounds - --> tests/ui/indexing_slicing_index.rs:69:5 + --> tests/ui/indexing_slicing_index.rs:89:5 | LL | x[N]; | ^^^^ error: indexing may panic - --> tests/ui/indexing_slicing_index.rs:72:5 + --> tests/ui/indexing_slicing_index.rs:92:5 | LL | v[N]; | ^^^^ @@ -107,7 +107,7 @@ LL | v[N]; = help: consider using `.get(n)` or `.get_mut(n)` instead error: indexing may panic - --> tests/ui/indexing_slicing_index.rs:74:5 + --> tests/ui/indexing_slicing_index.rs:94:5 | LL | v[M]; | ^^^^ @@ -115,7 +115,7 @@ LL | v[M]; = help: consider using `.get(n)` or `.get_mut(n)` instead error: index is out of bounds - --> tests/ui/indexing_slicing_index.rs:78:13 + --> tests/ui/indexing_slicing_index.rs:98:13 | LL | let _ = x[4]; | ^^^^ diff --git a/src/tools/clippy/tests/ui/indexing_slicing_slice.rs b/src/tools/clippy/tests/ui/indexing_slicing_slice.rs index fc591021ed6b0..f37bcc4aa0caf 100644 --- a/src/tools/clippy/tests/ui/indexing_slicing_slice.rs +++ b/src/tools/clippy/tests/ui/indexing_slicing_slice.rs @@ -1,8 +1,111 @@ +//@aux-build: proc_macros.rs + #![warn(clippy::indexing_slicing)] // We also check the out_of_bounds_indexing lint here, because it lints similar things and // we want to avoid false positives. #![warn(clippy::out_of_bounds_indexing)] -#![allow(clippy::no_effect, clippy::unnecessary_operation, clippy::useless_vec)] +#![allow( + clippy::no_effect, + clippy::unnecessary_operation, + clippy::useless_vec, + unused_must_use, + unused +)] +#![warn(clippy::indexing_slicing)] + +extern crate proc_macros; +use proc_macros::with_span; + +use std::ops::Index; + +struct BoolMap { + false_value: T, + true_value: T, +} + +impl Index for BoolMap { + type Output = T; + fn index(&self, index: bool) -> &T { + if index { &self.true_value } else { &self.false_value } + } +} + +struct BoolMapWithGet { + false_value: T, + true_value: T, +} + +impl Index for BoolMapWithGet { + type Output = T; + fn index(&self, index: bool) -> &Self::Output { + if index { &self.true_value } else { &self.false_value } + } +} + +impl BoolMapWithGet { + fn get(&self, index: bool) -> Option<&T> { + if index { + Some(&self.true_value) + } else { + Some(&self.false_value) + } + } +} + +struct S(T); +impl S { + fn get() -> Option { + unimplemented!() + } +} +impl Index for S { + type Output = T; + fn index(&self, _index: i32) -> &Self::Output { + &self.0 + } +} + +struct Y(T); +impl Y { + fn get() -> Option { + unimplemented!() + } +} +impl Index for Y { + type Output = T; + fn index(&self, _index: i32) -> &Self::Output { + &self.0 + } +} + +struct Z(T); +impl Z { + fn get() -> T2 { + unimplemented!() + } +} +impl Index for Z { + type Output = T; + fn index(&self, _index: i32) -> &Self::Output { + &self.0 + } +} + +with_span!( + span + + fn dont_lint_proc_macro() { + let x = [1, 2, 3, 4]; + let index: usize = 1; + &x[index..]; + &x[..10]; + + let x = vec![0; 5]; + let index: usize = 1; + &x[index..]; + &x[..10]; + } +); fn main() { let x = [1, 2, 3, 4]; @@ -51,4 +154,28 @@ fn main() { //~^ ERROR: slicing may panic &v[..]; // Ok, should not produce stderr. + + let map = BoolMap { + false_value: 2, + true_value: 4, + }; + + map[true]; // Ok, because `get` does not exist (custom indexing) + + let map_with_get = BoolMapWithGet { + false_value: 2, + true_value: 4, + }; + + // Lint on this, because `get` does exist with same signature + map_with_get[true]; + + let s = S::(1); + s[0]; + + let y = Y::(1); + y[0]; + + let z = Z::(1); + z[0]; } diff --git a/src/tools/clippy/tests/ui/indexing_slicing_slice.stderr b/src/tools/clippy/tests/ui/indexing_slicing_slice.stderr index 790d4a41f5b1e..1e72506746ecb 100644 --- a/src/tools/clippy/tests/ui/indexing_slicing_slice.stderr +++ b/src/tools/clippy/tests/ui/indexing_slicing_slice.stderr @@ -1,5 +1,5 @@ error: slicing may panic - --> tests/ui/indexing_slicing_slice.rs:12:6 + --> tests/ui/indexing_slicing_slice.rs:115:6 | LL | &x[index..]; | ^^^^^^^^^^ @@ -9,7 +9,7 @@ LL | &x[index..]; = help: to override `-D warnings` add `#[allow(clippy::indexing_slicing)]` error: slicing may panic - --> tests/ui/indexing_slicing_slice.rs:14:6 + --> tests/ui/indexing_slicing_slice.rs:117:6 | LL | &x[..index]; | ^^^^^^^^^^ @@ -17,7 +17,7 @@ LL | &x[..index]; = help: consider using `.get(..n)`or `.get_mut(..n)` instead error: slicing may panic - --> tests/ui/indexing_slicing_slice.rs:16:6 + --> tests/ui/indexing_slicing_slice.rs:119:6 | LL | &x[index_from..index_to]; | ^^^^^^^^^^^^^^^^^^^^^^^ @@ -25,7 +25,7 @@ LL | &x[index_from..index_to]; = help: consider using `.get(n..m)` or `.get_mut(n..m)` instead error: slicing may panic - --> tests/ui/indexing_slicing_slice.rs:18:6 + --> tests/ui/indexing_slicing_slice.rs:121:6 | LL | &x[index_from..][..index_to]; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -33,7 +33,7 @@ LL | &x[index_from..][..index_to]; = help: consider using `.get(..n)`or `.get_mut(..n)` instead error: slicing may panic - --> tests/ui/indexing_slicing_slice.rs:18:6 + --> tests/ui/indexing_slicing_slice.rs:121:6 | LL | &x[index_from..][..index_to]; | ^^^^^^^^^^^^^^^ @@ -41,7 +41,7 @@ LL | &x[index_from..][..index_to]; = help: consider using `.get(n..)` or .get_mut(n..)` instead error: slicing may panic - --> tests/ui/indexing_slicing_slice.rs:21:6 + --> tests/ui/indexing_slicing_slice.rs:124:6 | LL | &x[5..][..10]; | ^^^^^^^^^^^^ @@ -49,7 +49,7 @@ LL | &x[5..][..10]; = help: consider using `.get(..n)`or `.get_mut(..n)` instead error: range is out of bounds - --> tests/ui/indexing_slicing_slice.rs:21:8 + --> tests/ui/indexing_slicing_slice.rs:124:8 | LL | &x[5..][..10]; | ^ @@ -58,7 +58,7 @@ LL | &x[5..][..10]; = help: to override `-D warnings` add `#[allow(clippy::out_of_bounds_indexing)]` error: slicing may panic - --> tests/ui/indexing_slicing_slice.rs:25:6 + --> tests/ui/indexing_slicing_slice.rs:128:6 | LL | &x[0..][..3]; | ^^^^^^^^^^^ @@ -66,7 +66,7 @@ LL | &x[0..][..3]; = help: consider using `.get(..n)`or `.get_mut(..n)` instead error: slicing may panic - --> tests/ui/indexing_slicing_slice.rs:27:6 + --> tests/ui/indexing_slicing_slice.rs:130:6 | LL | &x[1..][..5]; | ^^^^^^^^^^^ @@ -74,19 +74,19 @@ LL | &x[1..][..5]; = help: consider using `.get(..n)`or `.get_mut(..n)` instead error: range is out of bounds - --> tests/ui/indexing_slicing_slice.rs:35:12 + --> tests/ui/indexing_slicing_slice.rs:138:12 | LL | &y[0..=4]; | ^ error: range is out of bounds - --> tests/ui/indexing_slicing_slice.rs:37:11 + --> tests/ui/indexing_slicing_slice.rs:140:11 | LL | &y[..=4]; | ^ error: slicing may panic - --> tests/ui/indexing_slicing_slice.rs:43:6 + --> tests/ui/indexing_slicing_slice.rs:146:6 | LL | &v[10..100]; | ^^^^^^^^^^ @@ -94,7 +94,7 @@ LL | &v[10..100]; = help: consider using `.get(n..m)` or `.get_mut(n..m)` instead error: slicing may panic - --> tests/ui/indexing_slicing_slice.rs:45:6 + --> tests/ui/indexing_slicing_slice.rs:148:6 | LL | &x[10..][..100]; | ^^^^^^^^^^^^^^ @@ -102,13 +102,13 @@ LL | &x[10..][..100]; = help: consider using `.get(..n)`or `.get_mut(..n)` instead error: range is out of bounds - --> tests/ui/indexing_slicing_slice.rs:45:8 + --> tests/ui/indexing_slicing_slice.rs:148:8 | LL | &x[10..][..100]; | ^^ error: slicing may panic - --> tests/ui/indexing_slicing_slice.rs:48:6 + --> tests/ui/indexing_slicing_slice.rs:151:6 | LL | &v[10..]; | ^^^^^^^ @@ -116,12 +116,36 @@ LL | &v[10..]; = help: consider using `.get(n..)` or .get_mut(n..)` instead error: slicing may panic - --> tests/ui/indexing_slicing_slice.rs:50:6 + --> tests/ui/indexing_slicing_slice.rs:153:6 | LL | &v[..100]; | ^^^^^^^^ | = help: consider using `.get(..n)`or `.get_mut(..n)` instead -error: aborting due to 16 previous errors +error: indexing may panic + --> tests/ui/indexing_slicing_slice.rs:171:5 + | +LL | map_with_get[true]; + | ^^^^^^^^^^^^^^^^^^ + | + = help: consider using `.get(n)` or `.get_mut(n)` instead + +error: indexing may panic + --> tests/ui/indexing_slicing_slice.rs:174:5 + | +LL | s[0]; + | ^^^^ + | + = help: consider using `.get(n)` or `.get_mut(n)` instead + +error: indexing may panic + --> tests/ui/indexing_slicing_slice.rs:177:5 + | +LL | y[0]; + | ^^^^ + | + = help: consider using `.get(n)` or `.get_mut(n)` instead + +error: aborting due to 19 previous errors diff --git a/src/tools/clippy/tests/ui/infinite_loops.rs b/src/tools/clippy/tests/ui/infinite_loops.rs index 52fbbaa8e31e9..b2d522fa011b7 100644 --- a/src/tools/clippy/tests/ui/infinite_loops.rs +++ b/src/tools/clippy/tests/ui/infinite_loops.rs @@ -137,7 +137,7 @@ fn can_break_both_inner_and_outer(cond: bool) { } fn break_wrong_loop(cond: bool) { - // 'inner has statement to break 'outer loop, but it was breaked early by a labeled child loop + // 'inner has statement to break 'outer loop, but it was broken out of early by a labeled child loop 'outer: loop { loop { //~^ ERROR: infinite loop detected diff --git a/src/tools/clippy/tests/ui/iter_over_hash_type.rs b/src/tools/clippy/tests/ui/iter_over_hash_type.rs index 7000c8bf96f8d..65bae1df42188 100644 --- a/src/tools/clippy/tests/ui/iter_over_hash_type.rs +++ b/src/tools/clippy/tests/ui/iter_over_hash_type.rs @@ -59,7 +59,7 @@ fn main() { let _ = x; } - // shouldnt fire + // shouldn't fire for x in &vec { let _ = x; } diff --git a/src/tools/clippy/tests/ui/manual_pattern_char_comparison.fixed b/src/tools/clippy/tests/ui/manual_pattern_char_comparison.fixed new file mode 100644 index 0000000000000..588226b87e87f --- /dev/null +++ b/src/tools/clippy/tests/ui/manual_pattern_char_comparison.fixed @@ -0,0 +1,49 @@ +#![warn(clippy::manual_pattern_char_comparison)] + +struct NotStr; + +impl NotStr { + fn find(&self, _: impl FnMut(char) -> bool) {} +} + +fn main() { + let sentence = "Hello, world!"; + sentence.trim_end_matches(['.', ',', '!', '?']); + sentence.split(['\n', 'X']); + sentence.split(['\n', 'X']); + sentence.splitn(3, 'X'); + sentence.splitn(3, |c: char| c.is_whitespace() || c == 'X'); + let char_compare = 'X'; + sentence.splitn(3, char_compare); + sentence.split(['\n', 'X', 'Y']); + sentence.splitn(3, 'X'); + sentence.splitn(3, ['X', 'W']); + sentence.find('🎈'); + + let not_str = NotStr; + not_str.find(|c: char| c == 'X'); + + "".find(|c| c == 'a' || c > 'z'); + + let x = true; + "".find(|c| c == 'a' || x || c == 'b'); + + let d = 'd'; + "".find(|c| c == 'a' || d == 'b'); + + "".find(|c| match c { + 'a' | 'b' => true, + _ => c.is_ascii(), + }); + + "".find(|c| matches!(c, 'a' | 'b' if false)); + + "".find(|c| matches!(c, 'a' | '1'..'4')); + "".find(|c| c == 'a' || matches!(c, '1'..'4')); + macro_rules! m { + ($e:expr) => { + $e == '?' + }; + } + "".find(|c| m!(c)); +} diff --git a/src/tools/clippy/tests/ui/manual_pattern_char_comparison.rs b/src/tools/clippy/tests/ui/manual_pattern_char_comparison.rs new file mode 100644 index 0000000000000..5078f3ee27f36 --- /dev/null +++ b/src/tools/clippy/tests/ui/manual_pattern_char_comparison.rs @@ -0,0 +1,49 @@ +#![warn(clippy::manual_pattern_char_comparison)] + +struct NotStr; + +impl NotStr { + fn find(&self, _: impl FnMut(char) -> bool) {} +} + +fn main() { + let sentence = "Hello, world!"; + sentence.trim_end_matches(|c: char| c == '.' || c == ',' || c == '!' || c == '?'); + sentence.split(|c: char| c == '\n' || c == 'X'); + sentence.split(|c| c == '\n' || c == 'X'); + sentence.splitn(3, |c: char| c == 'X'); + sentence.splitn(3, |c: char| c.is_whitespace() || c == 'X'); + let char_compare = 'X'; + sentence.splitn(3, |c: char| c == char_compare); + sentence.split(|c: char| matches!(c, '\n' | 'X' | 'Y')); + sentence.splitn(3, |c: char| matches!(c, 'X')); + sentence.splitn(3, |c: char| matches!(c, 'X' | 'W')); + sentence.find(|c| c == '🎈'); + + let not_str = NotStr; + not_str.find(|c: char| c == 'X'); + + "".find(|c| c == 'a' || c > 'z'); + + let x = true; + "".find(|c| c == 'a' || x || c == 'b'); + + let d = 'd'; + "".find(|c| c == 'a' || d == 'b'); + + "".find(|c| match c { + 'a' | 'b' => true, + _ => c.is_ascii(), + }); + + "".find(|c| matches!(c, 'a' | 'b' if false)); + + "".find(|c| matches!(c, 'a' | '1'..'4')); + "".find(|c| c == 'a' || matches!(c, '1'..'4')); + macro_rules! m { + ($e:expr) => { + $e == '?' + }; + } + "".find(|c| m!(c)); +} diff --git a/src/tools/clippy/tests/ui/manual_pattern_char_comparison.stderr b/src/tools/clippy/tests/ui/manual_pattern_char_comparison.stderr new file mode 100644 index 0000000000000..b6b51794a11f5 --- /dev/null +++ b/src/tools/clippy/tests/ui/manual_pattern_char_comparison.stderr @@ -0,0 +1,59 @@ +error: this manual char comparison can be written more succinctly + --> tests/ui/manual_pattern_char_comparison.rs:11:31 + | +LL | sentence.trim_end_matches(|c: char| c == '.' || c == ',' || c == '!' || c == '?'); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using an array of `char`: `['.', ',', '!', '?']` + | + = note: `-D clippy::manual-pattern-char-comparison` implied by `-D warnings` + = help: to override `-D warnings` add `#[allow(clippy::manual_pattern_char_comparison)]` + +error: this manual char comparison can be written more succinctly + --> tests/ui/manual_pattern_char_comparison.rs:12:20 + | +LL | sentence.split(|c: char| c == '\n' || c == 'X'); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using an array of `char`: `['\n', 'X']` + +error: this manual char comparison can be written more succinctly + --> tests/ui/manual_pattern_char_comparison.rs:13:20 + | +LL | sentence.split(|c| c == '\n' || c == 'X'); + | ^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using an array of `char`: `['\n', 'X']` + +error: this manual char comparison can be written more succinctly + --> tests/ui/manual_pattern_char_comparison.rs:14:24 + | +LL | sentence.splitn(3, |c: char| c == 'X'); + | ^^^^^^^^^^^^^^^^^^ help: consider using a `char`: `'X'` + +error: this manual char comparison can be written more succinctly + --> tests/ui/manual_pattern_char_comparison.rs:17:24 + | +LL | sentence.splitn(3, |c: char| c == char_compare); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using a `char`: `char_compare` + +error: this manual char comparison can be written more succinctly + --> tests/ui/manual_pattern_char_comparison.rs:18:20 + | +LL | sentence.split(|c: char| matches!(c, '\n' | 'X' | 'Y')); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using an array of `char`: `['\n', 'X', 'Y']` + +error: this manual char comparison can be written more succinctly + --> tests/ui/manual_pattern_char_comparison.rs:19:24 + | +LL | sentence.splitn(3, |c: char| matches!(c, 'X')); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using a `char`: `'X'` + +error: this manual char comparison can be written more succinctly + --> tests/ui/manual_pattern_char_comparison.rs:20:24 + | +LL | sentence.splitn(3, |c: char| matches!(c, 'X' | 'W')); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using an array of `char`: `['X', 'W']` + +error: this manual char comparison can be written more succinctly + --> tests/ui/manual_pattern_char_comparison.rs:21:19 + | +LL | sentence.find(|c| c == '🎈'); + | ^^^^^^^^^^^^^ help: consider using a `char`: `'🎈'` + +error: aborting due to 9 previous errors + diff --git a/src/tools/clippy/tests/ui/manual_unwrap_or_default.fixed b/src/tools/clippy/tests/ui/manual_unwrap_or_default.fixed index d6e736ba9cc2b..663de1a5f0677 100644 --- a/src/tools/clippy/tests/ui/manual_unwrap_or_default.fixed +++ b/src/tools/clippy/tests/ui/manual_unwrap_or_default.fixed @@ -26,6 +26,12 @@ fn main() { Some(x) => x, None => &[], }; + + let x: Result = Ok(String::new()); + x.unwrap_or_default(); + + let x: Result = Ok(String::new()); + x.unwrap_or_default(); } // Issue #12531 diff --git a/src/tools/clippy/tests/ui/manual_unwrap_or_default.rs b/src/tools/clippy/tests/ui/manual_unwrap_or_default.rs index 462d5d90ee771..75ffe09be9d4d 100644 --- a/src/tools/clippy/tests/ui/manual_unwrap_or_default.rs +++ b/src/tools/clippy/tests/ui/manual_unwrap_or_default.rs @@ -47,6 +47,21 @@ fn main() { Some(x) => x, None => &[], }; + + let x: Result = Ok(String::new()); + match x { + //~^ ERROR: match can be simplified with `.unwrap_or_default()` + Ok(v) => v, + Err(_) => String::new(), + }; + + let x: Result = Ok(String::new()); + if let Ok(v) = x { + //~^ ERROR: if let can be simplified with `.unwrap_or_default()` + v + } else { + String::new() + }; } // Issue #12531 diff --git a/src/tools/clippy/tests/ui/manual_unwrap_or_default.stderr b/src/tools/clippy/tests/ui/manual_unwrap_or_default.stderr index 3f1da444301f6..9e3b1be5cb9be 100644 --- a/src/tools/clippy/tests/ui/manual_unwrap_or_default.stderr +++ b/src/tools/clippy/tests/ui/manual_unwrap_or_default.stderr @@ -53,7 +53,28 @@ LL | | }; | |_____^ help: replace it with: `x.unwrap_or_default()` error: match can be simplified with `.unwrap_or_default()` - --> tests/ui/manual_unwrap_or_default.rs:56:20 + --> tests/ui/manual_unwrap_or_default.rs:52:5 + | +LL | / match x { +LL | | +LL | | Ok(v) => v, +LL | | Err(_) => String::new(), +LL | | }; + | |_____^ help: replace it with: `x.unwrap_or_default()` + +error: if let can be simplified with `.unwrap_or_default()` + --> tests/ui/manual_unwrap_or_default.rs:59:5 + | +LL | / if let Ok(v) = x { +LL | | +LL | | v +LL | | } else { +LL | | String::new() +LL | | }; + | |_____^ help: replace it with: `x.unwrap_or_default()` + +error: match can be simplified with `.unwrap_or_default()` + --> tests/ui/manual_unwrap_or_default.rs:71:20 | LL | Some(_) => match *b { | ____________________^ @@ -62,5 +83,5 @@ LL | | _ => 0, LL | | }, | |_________^ help: replace it with: `(*b).unwrap_or_default()` -error: aborting due to 6 previous errors +error: aborting due to 8 previous errors diff --git a/src/tools/clippy/tests/ui/match_same_arms2.fixed b/src/tools/clippy/tests/ui/match_same_arms2.fixed index fba0cf33b3c26..09e960ddd6a98 100644 --- a/src/tools/clippy/tests/ui/match_same_arms2.fixed +++ b/src/tools/clippy/tests/ui/match_same_arms2.fixed @@ -239,3 +239,20 @@ fn main() { _ => false, }; } + +// issue #8919, fixed on https://github.com/rust-lang/rust/pull/97312 +mod with_lifetime { + enum MaybeStaticStr<'a> { + Static(&'static str), + Borrowed(&'a str), + } + + impl<'a> MaybeStaticStr<'a> { + fn get(&self) -> &'a str { + match *self { + MaybeStaticStr::Borrowed(s) | MaybeStaticStr::Static(s) => s, + //~^ ERROR: this match arm has an identical body to another arm + } + } + } +} diff --git a/src/tools/clippy/tests/ui/match_same_arms2.rs b/src/tools/clippy/tests/ui/match_same_arms2.rs index 8a4e3b325bbff..cc7425135cc45 100644 --- a/src/tools/clippy/tests/ui/match_same_arms2.rs +++ b/src/tools/clippy/tests/ui/match_same_arms2.rs @@ -262,3 +262,21 @@ fn main() { _ => false, }; } + +// issue #8919, fixed on https://github.com/rust-lang/rust/pull/97312 +mod with_lifetime { + enum MaybeStaticStr<'a> { + Static(&'static str), + Borrowed(&'a str), + } + + impl<'a> MaybeStaticStr<'a> { + fn get(&self) -> &'a str { + match *self { + MaybeStaticStr::Static(s) => s, + MaybeStaticStr::Borrowed(s) => s, + //~^ ERROR: this match arm has an identical body to another arm + } + } + } +} diff --git a/src/tools/clippy/tests/ui/match_same_arms2.stderr b/src/tools/clippy/tests/ui/match_same_arms2.stderr index 3d15176ccf997..a5d137c658b79 100644 --- a/src/tools/clippy/tests/ui/match_same_arms2.stderr +++ b/src/tools/clippy/tests/ui/match_same_arms2.stderr @@ -221,5 +221,21 @@ help: and remove this obsolete arm LL - 0 => cfg!(not_enable), | -error: aborting due to 13 previous errors +error: this match arm has an identical body to another arm + --> tests/ui/match_same_arms2.rs:277:17 + | +LL | MaybeStaticStr::Borrowed(s) => s, + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | + = help: try changing either arm body +help: or try merging the arm patterns + | +LL | MaybeStaticStr::Borrowed(s) | MaybeStaticStr::Static(s) => s, + | ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +help: and remove this obsolete arm + | +LL - MaybeStaticStr::Static(s) => s, + | + +error: aborting due to 14 previous errors diff --git a/src/tools/clippy/tests/ui/mismatched_target_os_non_unix.fixed b/src/tools/clippy/tests/ui/mismatched_target_os_non_unix.fixed deleted file mode 100644 index de02b2bee31fc..0000000000000 --- a/src/tools/clippy/tests/ui/mismatched_target_os_non_unix.fixed +++ /dev/null @@ -1,25 +0,0 @@ -#![warn(clippy::mismatched_target_os)] -#![allow(unused)] - -#[cfg(target_os = "hermit")] -fn hermit() {} - -#[cfg(target_os = "wasi")] -fn wasi() {} - -#[cfg(target_os = "none")] -fn none() {} - -// list with conditions -#[cfg(all(not(windows), target_os = "wasi"))] -fn list() {} - -// windows is a valid target family, should be ignored -#[cfg(windows)] -fn windows() {} - -// correct use, should be ignored -#[cfg(target_os = "hermit")] -fn correct() {} - -fn main() {} diff --git a/src/tools/clippy/tests/ui/mismatched_target_os_non_unix.rs b/src/tools/clippy/tests/ui/mismatched_target_os_non_unix.rs deleted file mode 100644 index a960518751bfc..0000000000000 --- a/src/tools/clippy/tests/ui/mismatched_target_os_non_unix.rs +++ /dev/null @@ -1,25 +0,0 @@ -#![warn(clippy::mismatched_target_os)] -#![allow(unused)] - -#[cfg(hermit)] -fn hermit() {} - -#[cfg(wasi)] -fn wasi() {} - -#[cfg(none)] -fn none() {} - -// list with conditions -#[cfg(all(not(windows), wasi))] -fn list() {} - -// windows is a valid target family, should be ignored -#[cfg(windows)] -fn windows() {} - -// correct use, should be ignored -#[cfg(target_os = "hermit")] -fn correct() {} - -fn main() {} diff --git a/src/tools/clippy/tests/ui/mismatched_target_os_non_unix.stderr b/src/tools/clippy/tests/ui/mismatched_target_os_non_unix.stderr deleted file mode 100644 index 7f7a4e9d6f623..0000000000000 --- a/src/tools/clippy/tests/ui/mismatched_target_os_non_unix.stderr +++ /dev/null @@ -1,37 +0,0 @@ -error: operating system used in target family position - --> tests/ui/mismatched_target_os_non_unix.rs:4:1 - | -LL | #[cfg(hermit)] - | ^^^^^^------^^ - | | - | help: try: `target_os = "hermit"` - | - = note: `-D clippy::mismatched-target-os` implied by `-D warnings` - = help: to override `-D warnings` add `#[allow(clippy::mismatched_target_os)]` - -error: operating system used in target family position - --> tests/ui/mismatched_target_os_non_unix.rs:7:1 - | -LL | #[cfg(wasi)] - | ^^^^^^----^^ - | | - | help: try: `target_os = "wasi"` - -error: operating system used in target family position - --> tests/ui/mismatched_target_os_non_unix.rs:10:1 - | -LL | #[cfg(none)] - | ^^^^^^----^^ - | | - | help: try: `target_os = "none"` - -error: operating system used in target family position - --> tests/ui/mismatched_target_os_non_unix.rs:14:1 - | -LL | #[cfg(all(not(windows), wasi))] - | ^^^^^^^^^^^^^^^^^^^^^^^^----^^^ - | | - | help: try: `target_os = "wasi"` - -error: aborting due to 4 previous errors - diff --git a/src/tools/clippy/tests/ui/mismatched_target_os_unix.fixed b/src/tools/clippy/tests/ui/mismatched_target_os_unix.fixed deleted file mode 100644 index b945c4d9619da..0000000000000 --- a/src/tools/clippy/tests/ui/mismatched_target_os_unix.fixed +++ /dev/null @@ -1,60 +0,0 @@ -#![warn(clippy::mismatched_target_os)] -#![allow(unused)] - -#[cfg(target_os = "linux")] -fn linux() {} - -#[cfg(target_os = "freebsd")] -fn freebsd() {} - -#[cfg(target_os = "dragonfly")] -fn dragonfly() {} - -#[cfg(target_os = "openbsd")] -fn openbsd() {} - -#[cfg(target_os = "netbsd")] -fn netbsd() {} - -#[cfg(target_os = "macos")] -fn macos() {} - -#[cfg(target_os = "ios")] -fn ios() {} - -#[cfg(target_os = "android")] -fn android() {} - -#[cfg(target_os = "emscripten")] -fn emscripten() {} - -#[cfg(target_os = "fuchsia")] -fn fuchsia() {} - -#[cfg(target_os = "haiku")] -fn haiku() {} - -#[cfg(target_os = "illumos")] -fn illumos() {} - -#[cfg(target_os = "l4re")] -fn l4re() {} - -#[cfg(target_os = "redox")] -fn redox() {} - -#[cfg(target_os = "solaris")] -fn solaris() {} - -#[cfg(target_os = "vxworks")] -fn vxworks() {} - -// list with conditions -#[cfg(all(not(any(target_os = "solaris", target_os = "linux")), target_os = "freebsd"))] -fn list() {} - -// correct use, should be ignored -#[cfg(target_os = "freebsd")] -fn correct() {} - -fn main() {} diff --git a/src/tools/clippy/tests/ui/mismatched_target_os_unix.rs b/src/tools/clippy/tests/ui/mismatched_target_os_unix.rs deleted file mode 100644 index 34307facd6549..0000000000000 --- a/src/tools/clippy/tests/ui/mismatched_target_os_unix.rs +++ /dev/null @@ -1,60 +0,0 @@ -#![warn(clippy::mismatched_target_os)] -#![allow(unused)] - -#[cfg(linux)] -fn linux() {} - -#[cfg(freebsd)] -fn freebsd() {} - -#[cfg(dragonfly)] -fn dragonfly() {} - -#[cfg(openbsd)] -fn openbsd() {} - -#[cfg(netbsd)] -fn netbsd() {} - -#[cfg(macos)] -fn macos() {} - -#[cfg(ios)] -fn ios() {} - -#[cfg(android)] -fn android() {} - -#[cfg(emscripten)] -fn emscripten() {} - -#[cfg(fuchsia)] -fn fuchsia() {} - -#[cfg(haiku)] -fn haiku() {} - -#[cfg(illumos)] -fn illumos() {} - -#[cfg(l4re)] -fn l4re() {} - -#[cfg(redox)] -fn redox() {} - -#[cfg(solaris)] -fn solaris() {} - -#[cfg(vxworks)] -fn vxworks() {} - -// list with conditions -#[cfg(all(not(any(solaris, linux)), freebsd))] -fn list() {} - -// correct use, should be ignored -#[cfg(target_os = "freebsd")] -fn correct() {} - -fn main() {} diff --git a/src/tools/clippy/tests/ui/mismatched_target_os_unix.stderr b/src/tools/clippy/tests/ui/mismatched_target_os_unix.stderr deleted file mode 100644 index 3071bad1324b8..0000000000000 --- a/src/tools/clippy/tests/ui/mismatched_target_os_unix.stderr +++ /dev/null @@ -1,184 +0,0 @@ -error: operating system used in target family position - --> tests/ui/mismatched_target_os_unix.rs:4:1 - | -LL | #[cfg(linux)] - | ^^^^^^-----^^ - | | - | help: try: `target_os = "linux"` - | - = help: did you mean `unix`? - = note: `-D clippy::mismatched-target-os` implied by `-D warnings` - = help: to override `-D warnings` add `#[allow(clippy::mismatched_target_os)]` - -error: operating system used in target family position - --> tests/ui/mismatched_target_os_unix.rs:7:1 - | -LL | #[cfg(freebsd)] - | ^^^^^^-------^^ - | | - | help: try: `target_os = "freebsd"` - | - = help: did you mean `unix`? - -error: operating system used in target family position - --> tests/ui/mismatched_target_os_unix.rs:10:1 - | -LL | #[cfg(dragonfly)] - | ^^^^^^---------^^ - | | - | help: try: `target_os = "dragonfly"` - | - = help: did you mean `unix`? - -error: operating system used in target family position - --> tests/ui/mismatched_target_os_unix.rs:13:1 - | -LL | #[cfg(openbsd)] - | ^^^^^^-------^^ - | | - | help: try: `target_os = "openbsd"` - | - = help: did you mean `unix`? - -error: operating system used in target family position - --> tests/ui/mismatched_target_os_unix.rs:16:1 - | -LL | #[cfg(netbsd)] - | ^^^^^^------^^ - | | - | help: try: `target_os = "netbsd"` - | - = help: did you mean `unix`? - -error: operating system used in target family position - --> tests/ui/mismatched_target_os_unix.rs:19:1 - | -LL | #[cfg(macos)] - | ^^^^^^-----^^ - | | - | help: try: `target_os = "macos"` - | - = help: did you mean `unix`? - -error: operating system used in target family position - --> tests/ui/mismatched_target_os_unix.rs:22:1 - | -LL | #[cfg(ios)] - | ^^^^^^---^^ - | | - | help: try: `target_os = "ios"` - | - = help: did you mean `unix`? - -error: operating system used in target family position - --> tests/ui/mismatched_target_os_unix.rs:25:1 - | -LL | #[cfg(android)] - | ^^^^^^-------^^ - | | - | help: try: `target_os = "android"` - | - = help: did you mean `unix`? - -error: operating system used in target family position - --> tests/ui/mismatched_target_os_unix.rs:28:1 - | -LL | #[cfg(emscripten)] - | ^^^^^^----------^^ - | | - | help: try: `target_os = "emscripten"` - | - = help: did you mean `unix`? - -error: operating system used in target family position - --> tests/ui/mismatched_target_os_unix.rs:31:1 - | -LL | #[cfg(fuchsia)] - | ^^^^^^-------^^ - | | - | help: try: `target_os = "fuchsia"` - | - = help: did you mean `unix`? - -error: operating system used in target family position - --> tests/ui/mismatched_target_os_unix.rs:34:1 - | -LL | #[cfg(haiku)] - | ^^^^^^-----^^ - | | - | help: try: `target_os = "haiku"` - | - = help: did you mean `unix`? - -error: operating system used in target family position - --> tests/ui/mismatched_target_os_unix.rs:37:1 - | -LL | #[cfg(illumos)] - | ^^^^^^-------^^ - | | - | help: try: `target_os = "illumos"` - | - = help: did you mean `unix`? - -error: operating system used in target family position - --> tests/ui/mismatched_target_os_unix.rs:40:1 - | -LL | #[cfg(l4re)] - | ^^^^^^----^^ - | | - | help: try: `target_os = "l4re"` - | - = help: did you mean `unix`? - -error: operating system used in target family position - --> tests/ui/mismatched_target_os_unix.rs:43:1 - | -LL | #[cfg(redox)] - | ^^^^^^-----^^ - | | - | help: try: `target_os = "redox"` - | - = help: did you mean `unix`? - -error: operating system used in target family position - --> tests/ui/mismatched_target_os_unix.rs:46:1 - | -LL | #[cfg(solaris)] - | ^^^^^^-------^^ - | | - | help: try: `target_os = "solaris"` - | - = help: did you mean `unix`? - -error: operating system used in target family position - --> tests/ui/mismatched_target_os_unix.rs:49:1 - | -LL | #[cfg(vxworks)] - | ^^^^^^-------^^ - | | - | help: try: `target_os = "vxworks"` - | - = help: did you mean `unix`? - -error: operating system used in target family position - --> tests/ui/mismatched_target_os_unix.rs:53:1 - | -LL | #[cfg(all(not(any(solaris, linux)), freebsd))] - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - | - = help: did you mean `unix`? -help: try - | -LL | #[cfg(all(not(any(target_os = "solaris", linux)), freebsd))] - | ~~~~~~~~~~~~~~~~~~~~~ -help: try - | -LL | #[cfg(all(not(any(solaris, target_os = "linux")), freebsd))] - | ~~~~~~~~~~~~~~~~~~~ -help: try - | -LL | #[cfg(all(not(any(solaris, linux)), target_os = "freebsd"))] - | ~~~~~~~~~~~~~~~~~~~~~ - -error: aborting due to 17 previous errors - diff --git a/src/tools/clippy/tests/ui/missing_const_for_fn/could_be_const.rs b/src/tools/clippy/tests/ui/missing_const_for_fn/could_be_const.rs index 06dbbeb31c0d5..58e639cc7fd1f 100644 --- a/src/tools/clippy/tests/ui/missing_const_for_fn/could_be_const.rs +++ b/src/tools/clippy/tests/ui/missing_const_for_fn/could_be_const.rs @@ -141,3 +141,33 @@ mod msrv { let _ = unsafe { bar.val }; } } + +mod issue12677 { + pub struct Wrapper { + pub strings: Vec, + } + + impl Wrapper { + #[must_use] + pub fn new(strings: Vec) -> Self { + Self { strings } + } + + #[must_use] + pub fn empty() -> Self { + Self { strings: Vec::new() } + } + } + + pub struct Other { + pub text: String, + pub vec: Vec, + } + + impl Other { + pub fn new(text: String) -> Self { + let vec = Vec::new(); + Self { text, vec } + } + } +} diff --git a/src/tools/clippy/tests/ui/missing_const_for_fn/could_be_const.stderr b/src/tools/clippy/tests/ui/missing_const_for_fn/could_be_const.stderr index b2cade3056373..1c61c3e871324 100644 --- a/src/tools/clippy/tests/ui/missing_const_for_fn/could_be_const.stderr +++ b/src/tools/clippy/tests/ui/missing_const_for_fn/could_be_const.stderr @@ -130,5 +130,30 @@ LL | | let _ = unsafe { bar.val }; LL | | } | |_____^ -error: aborting due to 14 previous errors +error: this could be a `const fn` + --> tests/ui/missing_const_for_fn/could_be_const.rs:152:9 + | +LL | / pub fn new(strings: Vec) -> Self { +LL | | Self { strings } +LL | | } + | |_________^ + +error: this could be a `const fn` + --> tests/ui/missing_const_for_fn/could_be_const.rs:157:9 + | +LL | / pub fn empty() -> Self { +LL | | Self { strings: Vec::new() } +LL | | } + | |_________^ + +error: this could be a `const fn` + --> tests/ui/missing_const_for_fn/could_be_const.rs:168:9 + | +LL | / pub fn new(text: String) -> Self { +LL | | let vec = Vec::new(); +LL | | Self { text, vec } +LL | | } + | |_________^ + +error: aborting due to 17 previous errors diff --git a/src/tools/clippy/tests/ui/missing_fields_in_debug.rs b/src/tools/clippy/tests/ui/missing_fields_in_debug.rs index e91e8ab7f475e..68867ec819d14 100644 --- a/src/tools/clippy/tests/ui/missing_fields_in_debug.rs +++ b/src/tools/clippy/tests/ui/missing_fields_in_debug.rs @@ -4,6 +4,7 @@ use std::fmt; use std::marker::PhantomData; use std::ops::Deref; +use std::thread::LocalKey; struct NamedStruct1Ignored { data: u8, @@ -191,4 +192,21 @@ impl fmt::Debug for WithPD { } } +struct InClosure { + a: u8, + b: String, +} + +impl fmt::Debug for InClosure { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + let mut d = f.debug_struct("InClosure"); + d.field("a", &self.a); + let mut c = || { + d.field("b", &self.b); + }; + c(); + d.finish() + } +} + fn main() {} diff --git a/src/tools/clippy/tests/ui/missing_fields_in_debug.stderr b/src/tools/clippy/tests/ui/missing_fields_in_debug.stderr index 6f8a9abe9228d..8c1810909dd86 100644 --- a/src/tools/clippy/tests/ui/missing_fields_in_debug.stderr +++ b/src/tools/clippy/tests/ui/missing_fields_in_debug.stderr @@ -1,5 +1,5 @@ error: manual `Debug` impl does not include all fields - --> tests/ui/missing_fields_in_debug.rs:13:1 + --> tests/ui/missing_fields_in_debug.rs:14:1 | LL | / impl fmt::Debug for NamedStruct1Ignored { LL | | @@ -11,7 +11,7 @@ LL | | } | |_^ | note: this field is unused - --> tests/ui/missing_fields_in_debug.rs:10:5 + --> tests/ui/missing_fields_in_debug.rs:11:5 | LL | hidden: u32, | ^^^^^^^^^^^ @@ -21,7 +21,7 @@ LL | hidden: u32, = help: to override `-D warnings` add `#[allow(clippy::missing_fields_in_debug)]` error: manual `Debug` impl does not include all fields - --> tests/ui/missing_fields_in_debug.rs:32:1 + --> tests/ui/missing_fields_in_debug.rs:33:1 | LL | / impl fmt::Debug for NamedStructMultipleIgnored { LL | | @@ -33,17 +33,17 @@ LL | | } | |_^ | note: this field is unused - --> tests/ui/missing_fields_in_debug.rs:26:5 + --> tests/ui/missing_fields_in_debug.rs:27:5 | LL | hidden: u32, | ^^^^^^^^^^^ note: this field is unused - --> tests/ui/missing_fields_in_debug.rs:27:5 + --> tests/ui/missing_fields_in_debug.rs:28:5 | LL | hidden2: String, | ^^^^^^^^^^^^^^^ note: this field is unused - --> tests/ui/missing_fields_in_debug.rs:29:5 + --> tests/ui/missing_fields_in_debug.rs:30:5 | LL | hidden4: ((((u8), u16), u32), u64), | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -51,7 +51,7 @@ LL | hidden4: ((((u8), u16), u32), u64), = help: consider calling `.finish_non_exhaustive()` if you intend to ignore fields error: manual `Debug` impl does not include all fields - --> tests/ui/missing_fields_in_debug.rs:94:1 + --> tests/ui/missing_fields_in_debug.rs:95:1 | LL | / impl fmt::Debug for MultiExprDebugImpl { LL | | @@ -63,7 +63,7 @@ LL | | } | |_^ | note: this field is unused - --> tests/ui/missing_fields_in_debug.rs:90:5 + --> tests/ui/missing_fields_in_debug.rs:91:5 | LL | b: String, | ^^^^^^^^^ diff --git a/src/tools/clippy/tests/ui/needless_bool/fixable.fixed b/src/tools/clippy/tests/ui/needless_bool/fixable.fixed index 3059de8f89c49..ec63c4fd6a268 100644 --- a/src/tools/clippy/tests/ui/needless_bool/fixable.fixed +++ b/src/tools/clippy/tests/ui/needless_bool/fixable.fixed @@ -131,3 +131,15 @@ fn needless_bool_condition() -> bool { foo() } + +fn issue12846() { + let a = true; + let b = false; + + // parentheses are needed here + let _x = (a && b).then(|| todo!()); + let _x = (a && b) as u8; + + // parentheses are not needed here + let _x = a.then(|| todo!()); +} diff --git a/src/tools/clippy/tests/ui/needless_bool/fixable.rs b/src/tools/clippy/tests/ui/needless_bool/fixable.rs index b2cbe86e2235b..8694aa7159080 100644 --- a/src/tools/clippy/tests/ui/needless_bool/fixable.rs +++ b/src/tools/clippy/tests/ui/needless_bool/fixable.rs @@ -191,3 +191,15 @@ fn needless_bool_condition() -> bool { foo() } + +fn issue12846() { + let a = true; + let b = false; + + // parentheses are needed here + let _x = if a && b { true } else { false }.then(|| todo!()); + let _x = if a && b { true } else { false } as u8; + + // parentheses are not needed here + let _x = if a { true } else { false }.then(|| todo!()); +} diff --git a/src/tools/clippy/tests/ui/needless_bool/fixable.stderr b/src/tools/clippy/tests/ui/needless_bool/fixable.stderr index 9746e931f50f0..99b5b99834486 100644 --- a/src/tools/clippy/tests/ui/needless_bool/fixable.stderr +++ b/src/tools/clippy/tests/ui/needless_bool/fixable.stderr @@ -191,5 +191,23 @@ error: this if-then-else expression returns a bool literal LL | if unsafe { no(4) } & 1 != 0 { true } else { false } | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: you can reduce it to: `(unsafe { no(4) } & 1 != 0)` -error: aborting due to 21 previous errors +error: this if-then-else expression returns a bool literal + --> tests/ui/needless_bool/fixable.rs:200:14 + | +LL | let _x = if a && b { true } else { false }.then(|| todo!()); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: you can reduce it to: `(a && b)` + +error: this if-then-else expression returns a bool literal + --> tests/ui/needless_bool/fixable.rs:201:14 + | +LL | let _x = if a && b { true } else { false } as u8; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: you can reduce it to: `(a && b)` + +error: this if-then-else expression returns a bool literal + --> tests/ui/needless_bool/fixable.rs:204:14 + | +LL | let _x = if a { true } else { false }.then(|| todo!()); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: you can reduce it to: `a` + +error: aborting due to 24 previous errors diff --git a/src/tools/clippy/tests/ui/needless_character_iteration.fixed b/src/tools/clippy/tests/ui/needless_character_iteration.fixed new file mode 100644 index 0000000000000..f0bf84a41d7ed --- /dev/null +++ b/src/tools/clippy/tests/ui/needless_character_iteration.fixed @@ -0,0 +1,57 @@ +#![warn(clippy::needless_character_iteration)] +#![allow(clippy::map_identity, clippy::unnecessary_operation)] + +#[derive(Default)] +struct S { + field: &'static str, +} + +impl S { + fn field(&self) -> &str { + self.field + } +} + +fn magic(_: char) {} + +fn main() { + "foo".is_ascii(); + //~^ ERROR: checking if a string is ascii using iterators + !"foo".is_ascii(); + //~^ ERROR: checking if a string is ascii using iterators + "foo".is_ascii(); + //~^ ERROR: checking if a string is ascii using iterators + !"foo".is_ascii(); + //~^ ERROR: checking if a string is ascii using iterators + + let s = String::new(); + s.is_ascii(); + //~^ ERROR: checking if a string is ascii using iterators + !"foo".to_string().is_ascii(); + //~^ ERROR: checking if a string is ascii using iterators + + "foo".is_ascii(); + !"foo".is_ascii(); + + S::default().field().is_ascii(); + //~^ ERROR: checking if a string is ascii using iterators + + // Should not lint! + "foo".chars().all(|c| { + let x = c; + magic(x); + x.is_ascii() + }); + + // Should not lint! + "foo".chars().all(|c| c.is_ascii() && c.is_alphabetic()); + + // Should not lint! + "foo".chars().map(|c| c).all(|c| !char::is_ascii(&c)); + + // Should not lint! + "foo".chars().all(|c| !c.is_ascii()); + + // Should not lint! + "foo".chars().any(|c| c.is_ascii()); +} diff --git a/src/tools/clippy/tests/ui/needless_character_iteration.rs b/src/tools/clippy/tests/ui/needless_character_iteration.rs new file mode 100644 index 0000000000000..2805d2438b4ab --- /dev/null +++ b/src/tools/clippy/tests/ui/needless_character_iteration.rs @@ -0,0 +1,65 @@ +#![warn(clippy::needless_character_iteration)] +#![allow(clippy::map_identity, clippy::unnecessary_operation)] + +#[derive(Default)] +struct S { + field: &'static str, +} + +impl S { + fn field(&self) -> &str { + self.field + } +} + +fn magic(_: char) {} + +fn main() { + "foo".chars().all(|c| c.is_ascii()); + //~^ ERROR: checking if a string is ascii using iterators + "foo".chars().any(|c| !c.is_ascii()); + //~^ ERROR: checking if a string is ascii using iterators + "foo".chars().all(|c| char::is_ascii(&c)); + //~^ ERROR: checking if a string is ascii using iterators + "foo".chars().any(|c| !char::is_ascii(&c)); + //~^ ERROR: checking if a string is ascii using iterators + + let s = String::new(); + s.chars().all(|c| c.is_ascii()); + //~^ ERROR: checking if a string is ascii using iterators + "foo".to_string().chars().any(|c| !c.is_ascii()); + //~^ ERROR: checking if a string is ascii using iterators + + "foo".chars().all(|c| { + //~^ ERROR: checking if a string is ascii using iterators + let x = c; + x.is_ascii() + }); + "foo".chars().any(|c| { + //~^ ERROR: checking if a string is ascii using iterators + let x = c; + !x.is_ascii() + }); + + S::default().field().chars().all(|x| x.is_ascii()); + //~^ ERROR: checking if a string is ascii using iterators + + // Should not lint! + "foo".chars().all(|c| { + let x = c; + magic(x); + x.is_ascii() + }); + + // Should not lint! + "foo".chars().all(|c| c.is_ascii() && c.is_alphabetic()); + + // Should not lint! + "foo".chars().map(|c| c).all(|c| !char::is_ascii(&c)); + + // Should not lint! + "foo".chars().all(|c| !c.is_ascii()); + + // Should not lint! + "foo".chars().any(|c| c.is_ascii()); +} diff --git a/src/tools/clippy/tests/ui/needless_character_iteration.stderr b/src/tools/clippy/tests/ui/needless_character_iteration.stderr new file mode 100644 index 0000000000000..7966033555f5b --- /dev/null +++ b/src/tools/clippy/tests/ui/needless_character_iteration.stderr @@ -0,0 +1,67 @@ +error: checking if a string is ascii using iterators + --> tests/ui/needless_character_iteration.rs:18:5 + | +LL | "foo".chars().all(|c| c.is_ascii()); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `"foo".is_ascii()` + | + = note: `-D clippy::needless-character-iteration` implied by `-D warnings` + = help: to override `-D warnings` add `#[allow(clippy::needless_character_iteration)]` + +error: checking if a string is ascii using iterators + --> tests/ui/needless_character_iteration.rs:20:5 + | +LL | "foo".chars().any(|c| !c.is_ascii()); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `!"foo".is_ascii()` + +error: checking if a string is ascii using iterators + --> tests/ui/needless_character_iteration.rs:22:5 + | +LL | "foo".chars().all(|c| char::is_ascii(&c)); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `"foo".is_ascii()` + +error: checking if a string is ascii using iterators + --> tests/ui/needless_character_iteration.rs:24:5 + | +LL | "foo".chars().any(|c| !char::is_ascii(&c)); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `!"foo".is_ascii()` + +error: checking if a string is ascii using iterators + --> tests/ui/needless_character_iteration.rs:28:5 + | +LL | s.chars().all(|c| c.is_ascii()); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `s.is_ascii()` + +error: checking if a string is ascii using iterators + --> tests/ui/needless_character_iteration.rs:30:5 + | +LL | "foo".to_string().chars().any(|c| !c.is_ascii()); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `!"foo".to_string().is_ascii()` + +error: checking if a string is ascii using iterators + --> tests/ui/needless_character_iteration.rs:33:5 + | +LL | / "foo".chars().all(|c| { +LL | | +LL | | let x = c; +LL | | x.is_ascii() +LL | | }); + | |______^ help: try: `"foo".is_ascii()` + +error: checking if a string is ascii using iterators + --> tests/ui/needless_character_iteration.rs:38:5 + | +LL | / "foo".chars().any(|c| { +LL | | +LL | | let x = c; +LL | | !x.is_ascii() +LL | | }); + | |______^ help: try: `!"foo".is_ascii()` + +error: checking if a string is ascii using iterators + --> tests/ui/needless_character_iteration.rs:44:5 + | +LL | S::default().field().chars().all(|x| x.is_ascii()); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `S::default().field().is_ascii()` + +error: aborting due to 9 previous errors + diff --git a/src/tools/clippy/tests/ui/needless_maybe_sized.fixed b/src/tools/clippy/tests/ui/needless_maybe_sized.fixed new file mode 100644 index 0000000000000..4d24a7cee619b --- /dev/null +++ b/src/tools/clippy/tests/ui/needless_maybe_sized.fixed @@ -0,0 +1,116 @@ +//@aux-build:proc_macros.rs + +#![allow(unused, clippy::multiple_bound_locations)] +#![warn(clippy::needless_maybe_sized)] + +extern crate proc_macros; +use proc_macros::external; + +fn directly(t: &T) {} + +trait A: Sized {} +trait B: A {} + +fn depth_1(t: &T) {} +fn depth_2(t: &T) {} + +// We only need to show one +fn multiple_paths(t: &T) {} + +fn in_where(t: &T) +where + T: Sized, +{ +} + +fn mixed_1(t: &T) +{ +} + +fn mixed_2(t: &T) +where + T: Sized, +{ +} + +fn mixed_3(t: &T) +where + T: Sized, +{ +} + +struct Struct(T); + +impl Struct { + fn method(&self) {} +} + +enum Enum { + Variant(&'static T), +} + +union Union<'a, T: Sized> { + a: &'a T, +} + +trait Trait { + fn trait_method() {} + + type GAT; + + type Assoc: Sized + ?Sized; // False negative +} + +trait SecondInTrait: Send + Sized {} +fn second_in_trait() {} + +fn impl_trait(_: &(impl Sized)) {} + +trait GenericTrait: Sized {} +fn in_generic_trait, U>() {} + +mod larger_graph { + // C1 C2 Sized + // \ /\ / + // B1 B2 + // \ / + // A1 + + trait C1 {} + trait C2 {} + trait B1: C1 + C2 {} + trait B2: C2 + Sized {} + trait A1: B1 + B2 {} + + fn larger_graph() {} +} + +// Should not lint + +fn sized() {} +fn maybe_sized() {} + +struct SeparateBounds(T); +impl SeparateBounds {} + +trait P {} +trait Q: P {} + +fn ok_depth_1() {} +fn ok_depth_2() {} + +external! { + fn in_macro(t: &T) {} + + fn with_local_clone(t: &T) {} +} + +#[derive(Clone)] +struct InDerive { + t: T, +} + +struct Refined(T); +impl Refined {} + +fn main() {} diff --git a/src/tools/clippy/tests/ui/needless_maybe_sized.rs b/src/tools/clippy/tests/ui/needless_maybe_sized.rs new file mode 100644 index 0000000000000..ef66f9a4f2aec --- /dev/null +++ b/src/tools/clippy/tests/ui/needless_maybe_sized.rs @@ -0,0 +1,119 @@ +//@aux-build:proc_macros.rs + +#![allow(unused, clippy::multiple_bound_locations)] +#![warn(clippy::needless_maybe_sized)] + +extern crate proc_macros; +use proc_macros::external; + +fn directly(t: &T) {} + +trait A: Sized {} +trait B: A {} + +fn depth_1(t: &T) {} +fn depth_2(t: &T) {} + +// We only need to show one +fn multiple_paths(t: &T) {} + +fn in_where(t: &T) +where + T: Sized + ?Sized, +{ +} + +fn mixed_1(t: &T) +where + T: ?Sized, +{ +} + +fn mixed_2(t: &T) +where + T: Sized, +{ +} + +fn mixed_3(t: &T) +where + T: Sized, + T: ?Sized, +{ +} + +struct Struct(T); + +impl Struct { + fn method(&self) {} +} + +enum Enum { + Variant(&'static T), +} + +union Union<'a, T: Sized + ?Sized> { + a: &'a T, +} + +trait Trait { + fn trait_method() {} + + type GAT; + + type Assoc: Sized + ?Sized; // False negative +} + +trait SecondInTrait: Send + Sized {} +fn second_in_trait() {} + +fn impl_trait(_: &(impl Sized + ?Sized)) {} + +trait GenericTrait: Sized {} +fn in_generic_trait + ?Sized, U>() {} + +mod larger_graph { + // C1 C2 Sized + // \ /\ / + // B1 B2 + // \ / + // A1 + + trait C1 {} + trait C2 {} + trait B1: C1 + C2 {} + trait B2: C2 + Sized {} + trait A1: B1 + B2 {} + + fn larger_graph() {} +} + +// Should not lint + +fn sized() {} +fn maybe_sized() {} + +struct SeparateBounds(T); +impl SeparateBounds {} + +trait P {} +trait Q: P {} + +fn ok_depth_1() {} +fn ok_depth_2() {} + +external! { + fn in_macro(t: &T) {} + + fn with_local_clone(t: &T) {} +} + +#[derive(Clone)] +struct InDerive { + t: T, +} + +struct Refined(T); +impl Refined {} + +fn main() {} diff --git a/src/tools/clippy/tests/ui/needless_maybe_sized.stderr b/src/tools/clippy/tests/ui/needless_maybe_sized.stderr new file mode 100644 index 0000000000000..3b1d2b49b0622 --- /dev/null +++ b/src/tools/clippy/tests/ui/needless_maybe_sized.stderr @@ -0,0 +1,353 @@ +error: `?Sized` bound is ignored because of a `Sized` requirement + --> tests/ui/needless_maybe_sized.rs:9:24 + | +LL | fn directly(t: &T) {} + | ^^^^^^ + | +note: `T` cannot be unsized because of the bound + --> tests/ui/needless_maybe_sized.rs:9:16 + | +LL | fn directly(t: &T) {} + | ^^^^^ + = note: `-D clippy::needless-maybe-sized` implied by `-D warnings` + = help: to override `-D warnings` add `#[allow(clippy::needless_maybe_sized)]` +help: change the bounds that require `Sized`, or remove the `?Sized` bound + | +LL - fn directly(t: &T) {} +LL + fn directly(t: &T) {} + | + +error: `?Sized` bound is ignored because of a `Sized` requirement + --> tests/ui/needless_maybe_sized.rs:14:19 + | +LL | fn depth_1(t: &T) {} + | ^^^^^^ + | +note: `T` cannot be unsized because of the bound + --> tests/ui/needless_maybe_sized.rs:14:15 + | +LL | fn depth_1(t: &T) {} + | ^ + = note: ...because `A` has the bound `Sized` +help: change the bounds that require `Sized`, or remove the `?Sized` bound + | +LL - fn depth_1(t: &T) {} +LL + fn depth_1(t: &T) {} + | + +error: `?Sized` bound is ignored because of a `Sized` requirement + --> tests/ui/needless_maybe_sized.rs:15:19 + | +LL | fn depth_2(t: &T) {} + | ^^^^^^ + | +note: `T` cannot be unsized because of the bound + --> tests/ui/needless_maybe_sized.rs:15:15 + | +LL | fn depth_2(t: &T) {} + | ^ + = note: ...because `B` has the bound `A` + = note: ...because `A` has the bound `Sized` +help: change the bounds that require `Sized`, or remove the `?Sized` bound + | +LL - fn depth_2(t: &T) {} +LL + fn depth_2(t: &T) {} + | + +error: `?Sized` bound is ignored because of a `Sized` requirement + --> tests/ui/needless_maybe_sized.rs:18:30 + | +LL | fn multiple_paths(t: &T) {} + | ^^^^^^ + | +note: `T` cannot be unsized because of the bound + --> tests/ui/needless_maybe_sized.rs:18:22 + | +LL | fn multiple_paths(t: &T) {} + | ^ + = note: ...because `A` has the bound `Sized` +help: change the bounds that require `Sized`, or remove the `?Sized` bound + | +LL - fn multiple_paths(t: &T) {} +LL + fn multiple_paths(t: &T) {} + | + +error: `?Sized` bound is ignored because of a `Sized` requirement + --> tests/ui/needless_maybe_sized.rs:22:16 + | +LL | T: Sized + ?Sized, + | ^^^^^^ + | +note: `T` cannot be unsized because of the bound + --> tests/ui/needless_maybe_sized.rs:22:8 + | +LL | T: Sized + ?Sized, + | ^^^^^ +help: change the bounds that require `Sized`, or remove the `?Sized` bound + | +LL - T: Sized + ?Sized, +LL + T: Sized, + | + +error: `?Sized` bound is ignored because of a `Sized` requirement + --> tests/ui/needless_maybe_sized.rs:28:8 + | +LL | T: ?Sized, + | ^^^^^^ + | +note: `T` cannot be unsized because of the bound + --> tests/ui/needless_maybe_sized.rs:26:15 + | +LL | fn mixed_1(t: &T) + | ^^^^^ +help: change the bounds that require `Sized`, or remove the `?Sized` bound + | +LL - where +LL - T: ?Sized, + | + +error: `?Sized` bound is ignored because of a `Sized` requirement + --> tests/ui/needless_maybe_sized.rs:32:15 + | +LL | fn mixed_2(t: &T) + | ^^^^^^ + | +note: `T` cannot be unsized because of the bound + --> tests/ui/needless_maybe_sized.rs:34:8 + | +LL | T: Sized, + | ^^^^^ +help: change the bounds that require `Sized`, or remove the `?Sized` bound + | +LL - fn mixed_2(t: &T) +LL + fn mixed_2(t: &T) + | + +error: `?Sized` bound is ignored because of a `Sized` requirement + --> tests/ui/needless_maybe_sized.rs:41:8 + | +LL | T: ?Sized, + | ^^^^^^ + | +note: `T` cannot be unsized because of the bound + --> tests/ui/needless_maybe_sized.rs:40:8 + | +LL | T: Sized, + | ^^^^^ +help: change the bounds that require `Sized`, or remove the `?Sized` bound + | +LL - T: Sized, +LL - T: ?Sized, +LL + T: Sized, + | + +error: `?Sized` bound is ignored because of a `Sized` requirement + --> tests/ui/needless_maybe_sized.rs:45:26 + | +LL | struct Struct(T); + | ^^^^^^ + | +note: `T` cannot be unsized because of the bound + --> tests/ui/needless_maybe_sized.rs:45:18 + | +LL | struct Struct(T); + | ^^^^^ +help: change the bounds that require `Sized`, or remove the `?Sized` bound + | +LL - struct Struct(T); +LL + struct Struct(T); + | + +error: `?Sized` bound is ignored because of a `Sized` requirement + --> tests/ui/needless_maybe_sized.rs:47:17 + | +LL | impl Struct { + | ^^^^^^ + | +note: `T` cannot be unsized because of the bound + --> tests/ui/needless_maybe_sized.rs:47:9 + | +LL | impl Struct { + | ^^^^^ +help: change the bounds that require `Sized`, or remove the `?Sized` bound + | +LL - impl Struct { +LL + impl Struct { + | + +error: `?Sized` bound is ignored because of a `Sized` requirement + --> tests/ui/needless_maybe_sized.rs:48:26 + | +LL | fn method(&self) {} + | ^^^^^^ + | +note: `U` cannot be unsized because of the bound + --> tests/ui/needless_maybe_sized.rs:48:18 + | +LL | fn method(&self) {} + | ^^^^^ +help: change the bounds that require `Sized`, or remove the `?Sized` bound + | +LL - fn method(&self) {} +LL + fn method(&self) {} + | + +error: `?Sized` bound is ignored because of a `Sized` requirement + --> tests/ui/needless_maybe_sized.rs:51:22 + | +LL | enum Enum { + | ^^^^^^ + | +note: `T` cannot be unsized because of the bound + --> tests/ui/needless_maybe_sized.rs:51:14 + | +LL | enum Enum { + | ^^^^^ +help: change the bounds that require `Sized`, or remove the `?Sized` bound + | +LL - enum Enum { +LL + enum Enum { + | + +error: `?Sized` bound is ignored because of a `Sized` requirement + --> tests/ui/needless_maybe_sized.rs:55:28 + | +LL | union Union<'a, T: Sized + ?Sized> { + | ^^^^^^ + | +note: `T` cannot be unsized because of the bound + --> tests/ui/needless_maybe_sized.rs:55:20 + | +LL | union Union<'a, T: Sized + ?Sized> { + | ^^^^^ +help: change the bounds that require `Sized`, or remove the `?Sized` bound + | +LL - union Union<'a, T: Sized + ?Sized> { +LL + union Union<'a, T: Sized> { + | + +error: `?Sized` bound is ignored because of a `Sized` requirement + --> tests/ui/needless_maybe_sized.rs:59:24 + | +LL | trait Trait { + | ^^^^^^ + | +note: `T` cannot be unsized because of the bound + --> tests/ui/needless_maybe_sized.rs:59:16 + | +LL | trait Trait { + | ^^^^^ +help: change the bounds that require `Sized`, or remove the `?Sized` bound + | +LL - trait Trait { +LL + trait Trait { + | + +error: `?Sized` bound is ignored because of a `Sized` requirement + --> tests/ui/needless_maybe_sized.rs:60:32 + | +LL | fn trait_method() {} + | ^^^^^^ + | +note: `U` cannot be unsized because of the bound + --> tests/ui/needless_maybe_sized.rs:60:24 + | +LL | fn trait_method() {} + | ^^^^^ +help: change the bounds that require `Sized`, or remove the `?Sized` bound + | +LL - fn trait_method() {} +LL + fn trait_method() {} + | + +error: `?Sized` bound is ignored because of a `Sized` requirement + --> tests/ui/needless_maybe_sized.rs:62:25 + | +LL | type GAT; + | ^^^^^^ + | +note: `U` cannot be unsized because of the bound + --> tests/ui/needless_maybe_sized.rs:62:17 + | +LL | type GAT; + | ^^^^^ +help: change the bounds that require `Sized`, or remove the `?Sized` bound + | +LL - type GAT; +LL + type GAT; + | + +error: `?Sized` bound is ignored because of a `Sized` requirement + --> tests/ui/needless_maybe_sized.rs:68:23 + | +LL | fn second_in_trait() {} + | ^^^^^^ + | +note: `T` cannot be unsized because of the bound + --> tests/ui/needless_maybe_sized.rs:68:32 + | +LL | fn second_in_trait() {} + | ^^^^^^^^^^^^^ + = note: ...because `SecondInTrait` has the bound `Sized` +help: change the bounds that require `Sized`, or remove the `?Sized` bound + | +LL - fn second_in_trait() {} +LL + fn second_in_trait() {} + | + +error: `?Sized` bound is ignored because of a `Sized` requirement + --> tests/ui/needless_maybe_sized.rs:70:33 + | +LL | fn impl_trait(_: &(impl Sized + ?Sized)) {} + | ^^^^^^ + | +note: `impl Sized + ?Sized` cannot be unsized because of the bound + --> tests/ui/needless_maybe_sized.rs:70:25 + | +LL | fn impl_trait(_: &(impl Sized + ?Sized)) {} + | ^^^^^ +help: change the bounds that require `Sized`, or remove the `?Sized` bound + | +LL - fn impl_trait(_: &(impl Sized + ?Sized)) {} +LL + fn impl_trait(_: &(impl Sized)) {} + | + +error: `?Sized` bound is ignored because of a `Sized` requirement + --> tests/ui/needless_maybe_sized.rs:73:42 + | +LL | fn in_generic_trait + ?Sized, U>() {} + | ^^^^^^ + | +note: `T` cannot be unsized because of the bound + --> tests/ui/needless_maybe_sized.rs:73:24 + | +LL | fn in_generic_trait + ?Sized, U>() {} + | ^^^^^^^^^^^^^^^ + = note: ...because `GenericTrait` has the bound `Sized` +help: change the bounds that require `Sized`, or remove the `?Sized` bound + | +LL - fn in_generic_trait + ?Sized, U>() {} +LL + fn in_generic_trait, U>() {} + | + +error: `?Sized` bound is ignored because of a `Sized` requirement + --> tests/ui/needless_maybe_sized.rs:88:29 + | +LL | fn larger_graph() {} + | ^^^^^^ + | +note: `T` cannot be unsized because of the bound + --> tests/ui/needless_maybe_sized.rs:88:24 + | +LL | fn larger_graph() {} + | ^^ + = note: ...because `A1` has the bound `B2` + = note: ...because `B2` has the bound `Sized` +help: change the bounds that require `Sized`, or remove the `?Sized` bound + | +LL - fn larger_graph() {} +LL + fn larger_graph() {} + | + +error: aborting due to 20 previous errors + diff --git a/src/tools/clippy/tests/ui/new_ret_no_self.rs b/src/tools/clippy/tests/ui/new_ret_no_self.rs index b944f531ef660..175b14d815a2c 100644 --- a/src/tools/clippy/tests/ui/new_ret_no_self.rs +++ b/src/tools/clippy/tests/ui/new_ret_no_self.rs @@ -390,9 +390,7 @@ mod issue7344 { impl RetImplTraitSelf2 { // should not trigger lint - fn new(t: T) -> impl Trait2<(), Self> { - unimplemented!() - } + fn new(t: T) -> impl Trait2<(), Self> {} } struct RetImplTraitNoSelf2(T); @@ -401,7 +399,6 @@ mod issue7344 { // should trigger lint fn new(t: T) -> impl Trait2<(), i32> { //~^ ERROR: methods called `new` usually return `Self` - unimplemented!() } } diff --git a/src/tools/clippy/tests/ui/new_ret_no_self.stderr b/src/tools/clippy/tests/ui/new_ret_no_self.stderr index d440a9f45fcdb..3597ad65838f6 100644 --- a/src/tools/clippy/tests/ui/new_ret_no_self.stderr +++ b/src/tools/clippy/tests/ui/new_ret_no_self.stderr @@ -96,11 +96,10 @@ LL | | } | |_________^ error: methods called `new` usually return `Self` - --> tests/ui/new_ret_no_self.rs:402:9 + --> tests/ui/new_ret_no_self.rs:400:9 | LL | / fn new(t: T) -> impl Trait2<(), i32> { LL | | -LL | | unimplemented!() LL | | } | |_________^ diff --git a/src/tools/clippy/tests/ui/non_canonical_clone_impl.fixed b/src/tools/clippy/tests/ui/non_canonical_clone_impl.fixed index 7d1be412e54fd..11616f28825b0 100644 --- a/src/tools/clippy/tests/ui/non_canonical_clone_impl.fixed +++ b/src/tools/clippy/tests/ui/non_canonical_clone_impl.fixed @@ -1,7 +1,11 @@ +//@aux-build:proc_macro_derive.rs #![allow(clippy::clone_on_copy, unused)] #![allow(clippy::assigning_clones)] #![no_main] +extern crate proc_macros; +use proc_macros::with_span; + // lint struct A(u32); @@ -95,3 +99,19 @@ impl Clone for Uwu { } impl Copy for Uwu {} + +// should skip proc macros, see https://github.com/rust-lang/rust-clippy/issues/12788 +#[derive(proc_macro_derive::NonCanonicalClone)] +pub struct G; + +with_span!( + span + + #[derive(Copy)] + struct H; + impl Clone for H { + fn clone(&self) -> Self { + todo!() + } + } +); diff --git a/src/tools/clippy/tests/ui/non_canonical_clone_impl.rs b/src/tools/clippy/tests/ui/non_canonical_clone_impl.rs index beae05efb2fbc..a36c7ed44c247 100644 --- a/src/tools/clippy/tests/ui/non_canonical_clone_impl.rs +++ b/src/tools/clippy/tests/ui/non_canonical_clone_impl.rs @@ -1,7 +1,11 @@ +//@aux-build:proc_macro_derive.rs #![allow(clippy::clone_on_copy, unused)] #![allow(clippy::assigning_clones)] #![no_main] +extern crate proc_macros; +use proc_macros::with_span; + // lint struct A(u32); @@ -105,3 +109,19 @@ impl Clone for Uwu { } impl Copy for Uwu {} + +// should skip proc macros, see https://github.com/rust-lang/rust-clippy/issues/12788 +#[derive(proc_macro_derive::NonCanonicalClone)] +pub struct G; + +with_span!( + span + + #[derive(Copy)] + struct H; + impl Clone for H { + fn clone(&self) -> Self { + todo!() + } + } +); diff --git a/src/tools/clippy/tests/ui/non_canonical_clone_impl.stderr b/src/tools/clippy/tests/ui/non_canonical_clone_impl.stderr index 6bfc99d988bb7..f7cad58150f7d 100644 --- a/src/tools/clippy/tests/ui/non_canonical_clone_impl.stderr +++ b/src/tools/clippy/tests/ui/non_canonical_clone_impl.stderr @@ -1,5 +1,5 @@ error: non-canonical implementation of `clone` on a `Copy` type - --> tests/ui/non_canonical_clone_impl.rs:10:29 + --> tests/ui/non_canonical_clone_impl.rs:14:29 | LL | fn clone(&self) -> Self { | _____________________________^ @@ -11,7 +11,7 @@ LL | | } = help: to override `-D warnings` add `#[allow(clippy::non_canonical_clone_impl)]` error: unnecessary implementation of `clone_from` on a `Copy` type - --> tests/ui/non_canonical_clone_impl.rs:14:5 + --> tests/ui/non_canonical_clone_impl.rs:18:5 | LL | / fn clone_from(&mut self, source: &Self) { LL | | source.clone(); @@ -20,7 +20,7 @@ LL | | } | |_____^ help: remove it error: non-canonical implementation of `clone` on a `Copy` type - --> tests/ui/non_canonical_clone_impl.rs:81:29 + --> tests/ui/non_canonical_clone_impl.rs:85:29 | LL | fn clone(&self) -> Self { | _____________________________^ @@ -29,7 +29,7 @@ LL | | } | |_____^ help: change this to: `{ *self }` error: unnecessary implementation of `clone_from` on a `Copy` type - --> tests/ui/non_canonical_clone_impl.rs:85:5 + --> tests/ui/non_canonical_clone_impl.rs:89:5 | LL | / fn clone_from(&mut self, source: &Self) { LL | | source.clone(); diff --git a/src/tools/clippy/tests/ui/nonminimal_bool_methods.fixed b/src/tools/clippy/tests/ui/nonminimal_bool_methods.fixed index aba599678e391..cc91ba6ec66e1 100644 --- a/src/tools/clippy/tests/ui/nonminimal_bool_methods.fixed +++ b/src/tools/clippy/tests/ui/nonminimal_bool_methods.fixed @@ -1,5 +1,3 @@ -//@compile-flags: -Zdeduplicate-diagnostics=yes - #![allow(unused, clippy::diverging_sub_expression, clippy::needless_if)] #![warn(clippy::nonminimal_bool)] diff --git a/src/tools/clippy/tests/ui/nonminimal_bool_methods.rs b/src/tools/clippy/tests/ui/nonminimal_bool_methods.rs index 35f22db1d36ab..c812f6f0ca4f5 100644 --- a/src/tools/clippy/tests/ui/nonminimal_bool_methods.rs +++ b/src/tools/clippy/tests/ui/nonminimal_bool_methods.rs @@ -1,5 +1,3 @@ -//@compile-flags: -Zdeduplicate-diagnostics=yes - #![allow(unused, clippy::diverging_sub_expression, clippy::needless_if)] #![warn(clippy::nonminimal_bool)] diff --git a/src/tools/clippy/tests/ui/nonminimal_bool_methods.stderr b/src/tools/clippy/tests/ui/nonminimal_bool_methods.stderr index 18da4e0d380bc..d7adc0638b373 100644 --- a/src/tools/clippy/tests/ui/nonminimal_bool_methods.stderr +++ b/src/tools/clippy/tests/ui/nonminimal_bool_methods.stderr @@ -1,5 +1,5 @@ error: this boolean expression can be simplified - --> tests/ui/nonminimal_bool_methods.rs:10:13 + --> tests/ui/nonminimal_bool_methods.rs:8:13 | LL | let _ = !a.is_some(); | ^^^^^^^^^^^^ help: try: `a.is_none()` @@ -8,91 +8,91 @@ LL | let _ = !a.is_some(); = help: to override `-D warnings` add `#[allow(clippy::nonminimal_bool)]` error: this boolean expression can be simplified - --> tests/ui/nonminimal_bool_methods.rs:12:13 + --> tests/ui/nonminimal_bool_methods.rs:10:13 | LL | let _ = !a.is_none(); | ^^^^^^^^^^^^ help: try: `a.is_some()` error: this boolean expression can be simplified - --> tests/ui/nonminimal_bool_methods.rs:14:13 + --> tests/ui/nonminimal_bool_methods.rs:12:13 | LL | let _ = !b.is_err(); | ^^^^^^^^^^^ help: try: `b.is_ok()` error: this boolean expression can be simplified - --> tests/ui/nonminimal_bool_methods.rs:16:13 + --> tests/ui/nonminimal_bool_methods.rs:14:13 | LL | let _ = !b.is_ok(); | ^^^^^^^^^^ help: try: `b.is_err()` error: this boolean expression can be simplified - --> tests/ui/nonminimal_bool_methods.rs:18:13 + --> tests/ui/nonminimal_bool_methods.rs:16:13 | LL | let _ = !(a.is_some() && !c); | ^^^^^^^^^^^^^^^^^^^^ help: try: `a.is_none() || c` error: this boolean expression can be simplified - --> tests/ui/nonminimal_bool_methods.rs:19:13 + --> tests/ui/nonminimal_bool_methods.rs:17:13 | LL | let _ = !(a.is_some() || !c); | ^^^^^^^^^^^^^^^^^^^^ help: try: `a.is_none() && c` error: this boolean expression can be simplified - --> tests/ui/nonminimal_bool_methods.rs:20:26 + --> tests/ui/nonminimal_bool_methods.rs:18:26 | LL | let _ = !(!c ^ c) || !a.is_some(); | ^^^^^^^^^^^^ help: try: `a.is_none()` error: this boolean expression can be simplified - --> tests/ui/nonminimal_bool_methods.rs:21:25 + --> tests/ui/nonminimal_bool_methods.rs:19:25 | LL | let _ = (!c ^ c) || !a.is_some(); | ^^^^^^^^^^^^ help: try: `a.is_none()` error: this boolean expression can be simplified - --> tests/ui/nonminimal_bool_methods.rs:22:23 + --> tests/ui/nonminimal_bool_methods.rs:20:23 | LL | let _ = !c ^ c || !a.is_some(); | ^^^^^^^^^^^^ help: try: `a.is_none()` error: this boolean expression can be simplified - --> tests/ui/nonminimal_bool_methods.rs:94:8 + --> tests/ui/nonminimal_bool_methods.rs:92:8 | LL | if !res.is_ok() {} | ^^^^^^^^^^^^ help: try: `res.is_err()` error: this boolean expression can be simplified - --> tests/ui/nonminimal_bool_methods.rs:95:8 + --> tests/ui/nonminimal_bool_methods.rs:93:8 | LL | if !res.is_err() {} | ^^^^^^^^^^^^^ help: try: `res.is_ok()` error: this boolean expression can be simplified - --> tests/ui/nonminimal_bool_methods.rs:98:8 + --> tests/ui/nonminimal_bool_methods.rs:96:8 | LL | if !res.is_some() {} | ^^^^^^^^^^^^^^ help: try: `res.is_none()` error: this boolean expression can be simplified - --> tests/ui/nonminimal_bool_methods.rs:99:8 + --> tests/ui/nonminimal_bool_methods.rs:97:8 | LL | if !res.is_none() {} | ^^^^^^^^^^^^^^ help: try: `res.is_some()` error: this boolean expression can be simplified - --> tests/ui/nonminimal_bool_methods.rs:115:8 + --> tests/ui/nonminimal_bool_methods.rs:113:8 | LL | if !(a as u64 >= b) {} | ^^^^^^^^^^^^^^^^ help: try: `(a as u64) < b` error: this boolean expression can be simplified - --> tests/ui/nonminimal_bool_methods.rs:116:8 + --> tests/ui/nonminimal_bool_methods.rs:114:8 | LL | if !((a as u64) >= b) {} | ^^^^^^^^^^^^^^^^^^ help: try: `(a as u64) < b` error: this boolean expression can be simplified - --> tests/ui/nonminimal_bool_methods.rs:117:8 + --> tests/ui/nonminimal_bool_methods.rs:115:8 | LL | if !(a as u64 <= b) {} | ^^^^^^^^^^^^^^^^ help: try: `a as u64 > b` diff --git a/src/tools/clippy/tests/ui/or_fun_call.fixed b/src/tools/clippy/tests/ui/or_fun_call.fixed index e7ba54864ab0e..7657ef470c589 100644 --- a/src/tools/clippy/tests/ui/or_fun_call.fixed +++ b/src/tools/clippy/tests/ui/or_fun_call.fixed @@ -311,4 +311,11 @@ mod lazy { } } +fn host_effect() { + // #12877 - make sure we don't ICE in type_certainty + use std::ops::Add; + + Add::::add(1, 1).add(i32::MIN); +} + fn main() {} diff --git a/src/tools/clippy/tests/ui/or_fun_call.rs b/src/tools/clippy/tests/ui/or_fun_call.rs index 196632133d52a..97cf496d3ac7c 100644 --- a/src/tools/clippy/tests/ui/or_fun_call.rs +++ b/src/tools/clippy/tests/ui/or_fun_call.rs @@ -311,4 +311,11 @@ mod lazy { } } +fn host_effect() { + // #12877 - make sure we don't ICE in type_certainty + use std::ops::Add; + + Add::::add(1, 1).add(i32::MIN); +} + fn main() {} diff --git a/src/tools/clippy/tests/ui/overly_complex_bool_expr.fixed b/src/tools/clippy/tests/ui/overly_complex_bool_expr.fixed index e44f6063156a7..439b1145431c6 100644 --- a/src/tools/clippy/tests/ui/overly_complex_bool_expr.fixed +++ b/src/tools/clippy/tests/ui/overly_complex_bool_expr.fixed @@ -37,3 +37,13 @@ fn check_expect() { #[expect(clippy::overly_complex_bool_expr)] let _ = a < b && a >= b; } + +#[allow(clippy::never_loop)] +fn check_never_type() { + loop { + _ = (break) || true; + } + loop { + _ = (return) || true; + } +} diff --git a/src/tools/clippy/tests/ui/overly_complex_bool_expr.rs b/src/tools/clippy/tests/ui/overly_complex_bool_expr.rs index f010a8537e7f7..b96fd1adf1180 100644 --- a/src/tools/clippy/tests/ui/overly_complex_bool_expr.rs +++ b/src/tools/clippy/tests/ui/overly_complex_bool_expr.rs @@ -37,3 +37,13 @@ fn check_expect() { #[expect(clippy::overly_complex_bool_expr)] let _ = a < b && a >= b; } + +#[allow(clippy::never_loop)] +fn check_never_type() { + loop { + _ = (break) || true; + } + loop { + _ = (return) || true; + } +} diff --git a/src/tools/clippy/tests/ui/panic_in_result_fn.rs b/src/tools/clippy/tests/ui/panic_in_result_fn.rs index 41e2f5226899d..aaaf9a109acbb 100644 --- a/src/tools/clippy/tests/ui/panic_in_result_fn.rs +++ b/src/tools/clippy/tests/ui/panic_in_result_fn.rs @@ -56,6 +56,11 @@ fn function_result_with_panic() -> Result // should emit lint panic!("error"); } +fn in_closure() -> Result { + let c = || panic!(); + c() +} + fn todo() { println!("something"); } diff --git a/src/tools/clippy/tests/ui/panic_in_result_fn.stderr b/src/tools/clippy/tests/ui/panic_in_result_fn.stderr index cd2234bdfb13c..2d49b5ab1b8f1 100644 --- a/src/tools/clippy/tests/ui/panic_in_result_fn.stderr +++ b/src/tools/clippy/tests/ui/panic_in_result_fn.stderr @@ -34,5 +34,21 @@ note: return Err() instead of panicking LL | panic!("error"); | ^^^^^^^^^^^^^^^ -error: aborting due to 2 previous errors +error: used `panic!()` or assertion in a function that returns `Result` + --> tests/ui/panic_in_result_fn.rs:59:1 + | +LL | / fn in_closure() -> Result { +LL | | let c = || panic!(); +LL | | c() +LL | | } + | |_^ + | + = help: `panic!()` or assertions should not be used in a function that returns `Result` as `Result` is expected to return an error instead of crashing +note: return Err() instead of panicking + --> tests/ui/panic_in_result_fn.rs:60:16 + | +LL | let c = || panic!(); + | ^^^^^^^^ + +error: aborting due to 3 previous errors diff --git a/src/tools/clippy/tests/ui/search_is_some.rs b/src/tools/clippy/tests/ui/search_is_some.rs index e8a0920b645d1..9a9aaba56adc5 100644 --- a/src/tools/clippy/tests/ui/search_is_some.rs +++ b/src/tools/clippy/tests/ui/search_is_some.rs @@ -1,5 +1,6 @@ //@aux-build:option_helpers.rs #![warn(clippy::search_is_some)] +#![allow(clippy::manual_pattern_char_comparison)] #![allow(clippy::useless_vec)] #![allow(dead_code)] extern crate option_helpers; diff --git a/src/tools/clippy/tests/ui/search_is_some.stderr b/src/tools/clippy/tests/ui/search_is_some.stderr index b5f84d23284ac..b5ef553417701 100644 --- a/src/tools/clippy/tests/ui/search_is_some.stderr +++ b/src/tools/clippy/tests/ui/search_is_some.stderr @@ -1,5 +1,5 @@ error: called `is_some()` after searching an `Iterator` with `find` - --> tests/ui/search_is_some.rs:15:13 + --> tests/ui/search_is_some.rs:16:13 | LL | let _ = v.iter().find(|&x| { | _____________^ @@ -13,7 +13,7 @@ LL | | ).is_some(); = help: to override `-D warnings` add `#[allow(clippy::search_is_some)]` error: called `is_some()` after searching an `Iterator` with `position` - --> tests/ui/search_is_some.rs:21:13 + --> tests/ui/search_is_some.rs:22:13 | LL | let _ = v.iter().position(|&x| { | _____________^ @@ -25,7 +25,7 @@ LL | | ).is_some(); = help: this is more succinctly expressed by calling `any()` error: called `is_some()` after searching an `Iterator` with `rposition` - --> tests/ui/search_is_some.rs:27:13 + --> tests/ui/search_is_some.rs:28:13 | LL | let _ = v.iter().rposition(|&x| { | _____________^ @@ -37,13 +37,13 @@ LL | | ).is_some(); = help: this is more succinctly expressed by calling `any()` error: called `is_some()` after searching an `Iterator` with `find` - --> tests/ui/search_is_some.rs:42:20 + --> tests/ui/search_is_some.rs:43:20 | LL | let _ = (0..1).find(some_closure).is_some(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using: `any(some_closure)` error: called `is_none()` after searching an `Iterator` with `find` - --> tests/ui/search_is_some.rs:52:13 + --> tests/ui/search_is_some.rs:53:13 | LL | let _ = v.iter().find(|&x| { | _____________^ @@ -55,7 +55,7 @@ LL | | ).is_none(); = help: this is more succinctly expressed by calling `any()` with negation error: called `is_none()` after searching an `Iterator` with `position` - --> tests/ui/search_is_some.rs:58:13 + --> tests/ui/search_is_some.rs:59:13 | LL | let _ = v.iter().position(|&x| { | _____________^ @@ -67,7 +67,7 @@ LL | | ).is_none(); = help: this is more succinctly expressed by calling `any()` with negation error: called `is_none()` after searching an `Iterator` with `rposition` - --> tests/ui/search_is_some.rs:64:13 + --> tests/ui/search_is_some.rs:65:13 | LL | let _ = v.iter().rposition(|&x| { | _____________^ @@ -79,7 +79,7 @@ LL | | ).is_none(); = help: this is more succinctly expressed by calling `any()` with negation error: called `is_none()` after searching an `Iterator` with `find` - --> tests/ui/search_is_some.rs:79:13 + --> tests/ui/search_is_some.rs:80:13 | LL | let _ = (0..1).find(some_closure).is_none(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using: `!(0..1).any(some_closure)` diff --git a/src/tools/clippy/tests/ui/single_char_add_str.fixed b/src/tools/clippy/tests/ui/single_char_add_str.fixed index eafd17f538744..aef15252b1bce 100644 --- a/src/tools/clippy/tests/ui/single_char_add_str.fixed +++ b/src/tools/clippy/tests/ui/single_char_add_str.fixed @@ -21,6 +21,12 @@ fn main() { string.push('\u{0052}'); string.push('a'); + let c_ref = &'a'; + string.push(*c_ref); + let c = 'a'; + string.push(c); + string.push('a'); + get_string!().push('ö'); // `insert_str` tests @@ -41,5 +47,9 @@ fn main() { string.insert(Y, '"'); string.insert(Y, '\''); + string.insert(0, *c_ref); + string.insert(0, c); + string.insert(0, 'a'); + get_string!().insert(1, '?'); } diff --git a/src/tools/clippy/tests/ui/single_char_add_str.rs b/src/tools/clippy/tests/ui/single_char_add_str.rs index 5326c7cf24c64..7f97250dacd48 100644 --- a/src/tools/clippy/tests/ui/single_char_add_str.rs +++ b/src/tools/clippy/tests/ui/single_char_add_str.rs @@ -21,6 +21,12 @@ fn main() { string.push_str("\u{0052}"); string.push_str(r##"a"##); + let c_ref = &'a'; + string.push_str(&c_ref.to_string()); + let c = 'a'; + string.push_str(&c.to_string()); + string.push_str(&'a'.to_string()); + get_string!().push_str("ö"); // `insert_str` tests @@ -41,5 +47,9 @@ fn main() { string.insert_str(Y, r##"""##); string.insert_str(Y, r##"'"##); + string.insert_str(0, &c_ref.to_string()); + string.insert_str(0, &c.to_string()); + string.insert_str(0, &'a'.to_string()); + get_string!().insert_str(1, "?"); } diff --git a/src/tools/clippy/tests/ui/single_char_add_str.stderr b/src/tools/clippy/tests/ui/single_char_add_str.stderr index 89d75f20f55a7..7791c67578aa2 100644 --- a/src/tools/clippy/tests/ui/single_char_add_str.stderr +++ b/src/tools/clippy/tests/ui/single_char_add_str.stderr @@ -31,65 +31,101 @@ error: calling `push_str()` using a single-character string literal LL | string.push_str(r##"a"##); | ^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using `push` with a character literal: `string.push('a')` +error: calling `push_str()` using a single-character converted to string + --> tests/ui/single_char_add_str.rs:25:5 + | +LL | string.push_str(&c_ref.to_string()); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using `push` without `to_string()`: `string.push(*c_ref)` + +error: calling `push_str()` using a single-character converted to string + --> tests/ui/single_char_add_str.rs:27:5 + | +LL | string.push_str(&c.to_string()); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using `push` without `to_string()`: `string.push(c)` + +error: calling `push_str()` using a single-character converted to string + --> tests/ui/single_char_add_str.rs:28:5 + | +LL | string.push_str(&'a'.to_string()); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using `push` without `to_string()`: `string.push('a')` + error: calling `push_str()` using a single-character string literal - --> tests/ui/single_char_add_str.rs:24:5 + --> tests/ui/single_char_add_str.rs:30:5 | LL | get_string!().push_str("ö"); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using `push` with a character literal: `get_string!().push('ö')` error: calling `insert_str()` using a single-character string literal - --> tests/ui/single_char_add_str.rs:29:5 + --> tests/ui/single_char_add_str.rs:35:5 | LL | string.insert_str(0, "R"); | ^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using `insert` with a character literal: `string.insert(0, 'R')` error: calling `insert_str()` using a single-character string literal - --> tests/ui/single_char_add_str.rs:30:5 + --> tests/ui/single_char_add_str.rs:36:5 | LL | string.insert_str(1, "'"); | ^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using `insert` with a character literal: `string.insert(1, '\'')` error: calling `insert_str()` using a single-character string literal - --> tests/ui/single_char_add_str.rs:35:5 + --> tests/ui/single_char_add_str.rs:41:5 | LL | string.insert_str(0, "\x52"); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using `insert` with a character literal: `string.insert(0, '\x52')` error: calling `insert_str()` using a single-character string literal - --> tests/ui/single_char_add_str.rs:36:5 + --> tests/ui/single_char_add_str.rs:42:5 | LL | string.insert_str(0, "\u{0052}"); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using `insert` with a character literal: `string.insert(0, '\u{0052}')` error: calling `insert_str()` using a single-character string literal - --> tests/ui/single_char_add_str.rs:38:5 + --> tests/ui/single_char_add_str.rs:44:5 | LL | string.insert_str(x, r##"a"##); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using `insert` with a character literal: `string.insert(x, 'a')` error: calling `insert_str()` using a single-character string literal - --> tests/ui/single_char_add_str.rs:40:5 + --> tests/ui/single_char_add_str.rs:46:5 | LL | string.insert_str(Y, r##"a"##); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using `insert` with a character literal: `string.insert(Y, 'a')` error: calling `insert_str()` using a single-character string literal - --> tests/ui/single_char_add_str.rs:41:5 + --> tests/ui/single_char_add_str.rs:47:5 | LL | string.insert_str(Y, r##"""##); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using `insert` with a character literal: `string.insert(Y, '"')` error: calling `insert_str()` using a single-character string literal - --> tests/ui/single_char_add_str.rs:42:5 + --> tests/ui/single_char_add_str.rs:48:5 | LL | string.insert_str(Y, r##"'"##); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using `insert` with a character literal: `string.insert(Y, '\'')` +error: calling `insert_str()` using a single-character converted to string + --> tests/ui/single_char_add_str.rs:50:5 + | +LL | string.insert_str(0, &c_ref.to_string()); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using `insert` without `to_string()`: `string.insert(0, *c_ref)` + +error: calling `insert_str()` using a single-character converted to string + --> tests/ui/single_char_add_str.rs:51:5 + | +LL | string.insert_str(0, &c.to_string()); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using `insert` without `to_string()`: `string.insert(0, c)` + +error: calling `insert_str()` using a single-character converted to string + --> tests/ui/single_char_add_str.rs:52:5 + | +LL | string.insert_str(0, &'a'.to_string()); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using `insert` without `to_string()`: `string.insert(0, 'a')` + error: calling `insert_str()` using a single-character string literal - --> tests/ui/single_char_add_str.rs:44:5 + --> tests/ui/single_char_add_str.rs:54:5 | LL | get_string!().insert_str(1, "?"); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using `insert` with a character literal: `get_string!().insert(1, '?')` -error: aborting due to 15 previous errors +error: aborting due to 21 previous errors diff --git a/src/tools/clippy/tests/ui/str_to_string.fixed b/src/tools/clippy/tests/ui/str_to_string.fixed new file mode 100644 index 0000000000000..52e40b45a8bdd --- /dev/null +++ b/src/tools/clippy/tests/ui/str_to_string.fixed @@ -0,0 +1,9 @@ +#![warn(clippy::str_to_string)] + +fn main() { + let hello = "hello world".to_owned(); + //~^ ERROR: `to_string()` called on a `&str` + let msg = &hello[..]; + msg.to_owned(); + //~^ ERROR: `to_string()` called on a `&str` +} diff --git a/src/tools/clippy/tests/ui/str_to_string.stderr b/src/tools/clippy/tests/ui/str_to_string.stderr index 13b73622d6982..a761d96cd6b12 100644 --- a/src/tools/clippy/tests/ui/str_to_string.stderr +++ b/src/tools/clippy/tests/ui/str_to_string.stderr @@ -2,9 +2,8 @@ error: `to_string()` called on a `&str` --> tests/ui/str_to_string.rs:4:17 | LL | let hello = "hello world".to_string(); - | ^^^^^^^^^^^^^^^^^^^^^^^^^ + | ^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `"hello world".to_owned()` | - = help: consider using `.to_owned()` = note: `-D clippy::str-to-string` implied by `-D warnings` = help: to override `-D warnings` add `#[allow(clippy::str_to_string)]` @@ -12,9 +11,7 @@ error: `to_string()` called on a `&str` --> tests/ui/str_to_string.rs:7:5 | LL | msg.to_string(); - | ^^^^^^^^^^^^^^^ - | - = help: consider using `.to_owned()` + | ^^^^^^^^^^^^^^^ help: try: `msg.to_owned()` error: aborting due to 2 previous errors diff --git a/src/tools/clippy/tests/ui/type_repetition_in_bounds.rs b/src/tools/clippy/tests/ui/type_repetition_in_bounds.rs index 0039c805b7df8..d325887bfba3f 100644 --- a/src/tools/clippy/tests/ui/type_repetition_in_bounds.rs +++ b/src/tools/clippy/tests/ui/type_repetition_in_bounds.rs @@ -1,5 +1,9 @@ #![deny(clippy::type_repetition_in_bounds)] -#![allow(clippy::extra_unused_type_parameters, clippy::multiple_bound_locations)] +#![allow( + clippy::extra_unused_type_parameters, + clippy::multiple_bound_locations, + clippy::needless_maybe_sized +)] use serde::Deserialize; use std::ops::{Add, AddAssign, Div, DivAssign, Mul, MulAssign, Sub, SubAssign}; diff --git a/src/tools/clippy/tests/ui/type_repetition_in_bounds.stderr b/src/tools/clippy/tests/ui/type_repetition_in_bounds.stderr index e9c6b41aaa8ec..77944c9504579 100644 --- a/src/tools/clippy/tests/ui/type_repetition_in_bounds.stderr +++ b/src/tools/clippy/tests/ui/type_repetition_in_bounds.stderr @@ -1,5 +1,5 @@ error: this type has already been used as a bound predicate - --> tests/ui/type_repetition_in_bounds.rs:10:5 + --> tests/ui/type_repetition_in_bounds.rs:14:5 | LL | T: Clone, | ^^^^^^^^ @@ -12,7 +12,7 @@ LL | #![deny(clippy::type_repetition_in_bounds)] | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: this type has already been used as a bound predicate - --> tests/ui/type_repetition_in_bounds.rs:28:5 + --> tests/ui/type_repetition_in_bounds.rs:32:5 | LL | Self: Copy + Default + Ord, | ^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -20,7 +20,7 @@ LL | Self: Copy + Default + Ord, = help: consider combining the bounds: `Self: Clone + Copy + Default + Ord` error: this type has already been used as a bound predicate - --> tests/ui/type_repetition_in_bounds.rs:103:5 + --> tests/ui/type_repetition_in_bounds.rs:107:5 | LL | T: Clone, | ^^^^^^^^ @@ -28,7 +28,7 @@ LL | T: Clone, = help: consider combining the bounds: `T: ?Sized + Clone` error: this type has already been used as a bound predicate - --> tests/ui/type_repetition_in_bounds.rs:109:5 + --> tests/ui/type_repetition_in_bounds.rs:113:5 | LL | T: ?Sized, | ^^^^^^^^^ @@ -36,7 +36,7 @@ LL | T: ?Sized, = help: consider combining the bounds: `T: Clone + ?Sized` error: this type has already been used as a bound predicate - --> tests/ui/type_repetition_in_bounds.rs:135:9 + --> tests/ui/type_repetition_in_bounds.rs:139:9 | LL | T: Trait, Box<[String]>, bool> + 'static, | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ diff --git a/src/tools/clippy/tests/ui/unnecessary_clippy_cfg.rs b/src/tools/clippy/tests/ui/unnecessary_clippy_cfg.rs index ff960520f5e72..9915f8b843efd 100644 --- a/src/tools/clippy/tests/ui/unnecessary_clippy_cfg.rs +++ b/src/tools/clippy/tests/ui/unnecessary_clippy_cfg.rs @@ -5,18 +5,18 @@ //~^ ERROR: no need to put clippy lints behind a `clippy` cfg #![cfg_attr(clippy, deny(dead_code, clippy::non_minimal_cfg))] //~^ ERROR: no need to put clippy lints behind a `clippy` cfg -#![cfg_attr(clippy, deny(dead_code, clippy::non_minimal_cfg, clippy::maybe_misused_cfg))] +#![cfg_attr(clippy, deny(dead_code, clippy::non_minimal_cfg))] //~^ ERROR: no need to put clippy lints behind a `clippy` cfg -#![cfg_attr(clippy, deny(clippy::non_minimal_cfg, clippy::maybe_misused_cfg))] +#![cfg_attr(clippy, deny(clippy::non_minimal_cfg))] //~^ ERROR: no need to put clippy lints behind a `clippy` cfg #[cfg_attr(clippy, deny(clippy::non_minimal_cfg))] //~^ ERROR: no need to put clippy lints behind a `clippy` cfg #[cfg_attr(clippy, deny(dead_code, clippy::non_minimal_cfg))] //~^ ERROR: no need to put clippy lints behind a `clippy` cfg -#[cfg_attr(clippy, deny(dead_code, clippy::non_minimal_cfg, clippy::maybe_misused_cfg))] +#[cfg_attr(clippy, deny(dead_code, clippy::non_minimal_cfg))] //~^ ERROR: no need to put clippy lints behind a `clippy` cfg -#[cfg_attr(clippy, deny(clippy::non_minimal_cfg, clippy::maybe_misused_cfg))] +#[cfg_attr(clippy, deny(clippy::non_minimal_cfg))] //~^ ERROR: no need to put clippy lints behind a `clippy` cfg pub struct Bar; diff --git a/src/tools/clippy/tests/ui/unnecessary_clippy_cfg.stderr b/src/tools/clippy/tests/ui/unnecessary_clippy_cfg.stderr index 3d58c9eb5daec..16a8616529565 100644 --- a/src/tools/clippy/tests/ui/unnecessary_clippy_cfg.stderr +++ b/src/tools/clippy/tests/ui/unnecessary_clippy_cfg.stderr @@ -18,16 +18,16 @@ LL | #[cfg_attr(clippy, deny(dead_code, clippy::non_minimal_cfg))] error: no need to put clippy lints behind a `clippy` cfg --> tests/ui/unnecessary_clippy_cfg.rs:17:36 | -LL | #[cfg_attr(clippy, deny(dead_code, clippy::non_minimal_cfg, clippy::maybe_misused_cfg))] - | ^^^^^^^^^^^^^^^^^^^^^^^ ^^^^^^^^^^^^^^^^^^^^^^^^^ +LL | #[cfg_attr(clippy, deny(dead_code, clippy::non_minimal_cfg))] + | ^^^^^^^^^^^^^^^^^^^^^^^ | - = note: write instead: `#[deny(clippy::non_minimal_cfg,clippy::maybe_misused_cfg)]` + = note: write instead: `#[deny(clippy::non_minimal_cfg)]` error: no need to put clippy lints behind a `clippy` cfg --> tests/ui/unnecessary_clippy_cfg.rs:19:1 | -LL | #[cfg_attr(clippy, deny(clippy::non_minimal_cfg, clippy::maybe_misused_cfg))] - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: replace with: `#[deny(clippy::non_minimal_cfg, clippy::maybe_misused_cfg)]` +LL | #[cfg_attr(clippy, deny(clippy::non_minimal_cfg))] + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: replace with: `#[deny(clippy::non_minimal_cfg)]` error: no need to put clippy lints behind a `clippy` cfg --> tests/ui/unnecessary_clippy_cfg.rs:4:1 @@ -46,21 +46,21 @@ LL | #![cfg_attr(clippy, deny(dead_code, clippy::non_minimal_cfg))] error: no need to put clippy lints behind a `clippy` cfg --> tests/ui/unnecessary_clippy_cfg.rs:8:37 | -LL | #![cfg_attr(clippy, deny(dead_code, clippy::non_minimal_cfg, clippy::maybe_misused_cfg))] - | ^^^^^^^^^^^^^^^^^^^^^^^ ^^^^^^^^^^^^^^^^^^^^^^^^^ +LL | #![cfg_attr(clippy, deny(dead_code, clippy::non_minimal_cfg))] + | ^^^^^^^^^^^^^^^^^^^^^^^ | - = note: write instead: `#![deny(clippy::non_minimal_cfg,clippy::maybe_misused_cfg)]` + = note: write instead: `#![deny(clippy::non_minimal_cfg)]` error: no need to put clippy lints behind a `clippy` cfg --> tests/ui/unnecessary_clippy_cfg.rs:10:1 | -LL | #![cfg_attr(clippy, deny(clippy::non_minimal_cfg, clippy::maybe_misused_cfg))] - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: replace with: `#![deny(clippy::non_minimal_cfg, clippy::maybe_misused_cfg)]` +LL | #![cfg_attr(clippy, deny(clippy::non_minimal_cfg))] + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: replace with: `#![deny(clippy::non_minimal_cfg)]` error: duplicated attribute --> tests/ui/unnecessary_clippy_cfg.rs:8:26 | -LL | #![cfg_attr(clippy, deny(dead_code, clippy::non_minimal_cfg, clippy::maybe_misused_cfg))] +LL | #![cfg_attr(clippy, deny(dead_code, clippy::non_minimal_cfg))] | ^^^^^^^^^ | note: first defined here @@ -71,7 +71,7 @@ LL | #![cfg_attr(clippy, deny(dead_code, clippy::non_minimal_cfg))] help: remove this attribute --> tests/ui/unnecessary_clippy_cfg.rs:8:26 | -LL | #![cfg_attr(clippy, deny(dead_code, clippy::non_minimal_cfg, clippy::maybe_misused_cfg))] +LL | #![cfg_attr(clippy, deny(dead_code, clippy::non_minimal_cfg))] | ^^^^^^^^^ = note: `-D clippy::duplicated-attributes` implied by `-D warnings` = help: to override `-D warnings` add `#[allow(clippy::duplicated_attributes)]` @@ -79,7 +79,7 @@ LL | #![cfg_attr(clippy, deny(dead_code, clippy::non_minimal_cfg, clippy::maybe_ error: duplicated attribute --> tests/ui/unnecessary_clippy_cfg.rs:17:25 | -LL | #[cfg_attr(clippy, deny(dead_code, clippy::non_minimal_cfg, clippy::maybe_misused_cfg))] +LL | #[cfg_attr(clippy, deny(dead_code, clippy::non_minimal_cfg))] | ^^^^^^^^^ | note: first defined here @@ -90,7 +90,7 @@ LL | #[cfg_attr(clippy, deny(dead_code, clippy::non_minimal_cfg))] help: remove this attribute --> tests/ui/unnecessary_clippy_cfg.rs:17:25 | -LL | #[cfg_attr(clippy, deny(dead_code, clippy::non_minimal_cfg, clippy::maybe_misused_cfg))] +LL | #[cfg_attr(clippy, deny(dead_code, clippy::non_minimal_cfg))] | ^^^^^^^^^ error: aborting due to 10 previous errors diff --git a/src/tools/clippy/tests/ui/unwrap_in_result.rs b/src/tools/clippy/tests/ui/unwrap_in_result.rs index a19db46c667d0..62c6d959c84b6 100644 --- a/src/tools/clippy/tests/ui/unwrap_in_result.rs +++ b/src/tools/clippy/tests/ui/unwrap_in_result.rs @@ -38,6 +38,11 @@ impl A { } None } + + fn in_closure(a: Option) -> Option { + let c = || a.unwrap(); + Some(c()) + } } fn main() { diff --git a/src/tools/clippy/tests/ui/unwrap_in_result.stderr b/src/tools/clippy/tests/ui/unwrap_in_result.stderr index 29c7a9373aa7b..752177aaca57e 100644 --- a/src/tools/clippy/tests/ui/unwrap_in_result.stderr +++ b/src/tools/clippy/tests/ui/unwrap_in_result.stderr @@ -38,5 +38,21 @@ note: potential non-recoverable error(s) LL | let i = i_str.parse::().expect("not a number"); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -error: aborting due to 2 previous errors +error: used unwrap or expect in a function that returns result or option + --> tests/ui/unwrap_in_result.rs:42:5 + | +LL | / fn in_closure(a: Option) -> Option { +LL | | let c = || a.unwrap(); +LL | | Some(c()) +LL | | } + | |_____^ + | + = help: unwrap and expect should not be used in a function that returns result or option +note: potential non-recoverable error(s) + --> tests/ui/unwrap_in_result.rs:43:20 + | +LL | let c = || a.unwrap(); + | ^^^^^^^^^^ + +error: aborting due to 3 previous errors diff --git a/src/tools/clippy/tests/ui/useless_conversion_try.rs b/src/tools/clippy/tests/ui/useless_conversion_try.rs index 803d3b39f375d..23edeae12b83a 100644 --- a/src/tools/clippy/tests/ui/useless_conversion_try.rs +++ b/src/tools/clippy/tests/ui/useless_conversion_try.rs @@ -1,5 +1,9 @@ #![deny(clippy::useless_conversion)] -#![allow(clippy::needless_if, clippy::unnecessary_fallible_conversions)] +#![allow( + clippy::needless_if, + clippy::unnecessary_fallible_conversions, + clippy::manual_unwrap_or_default +)] fn test_generic(val: T) -> T { let _ = T::try_from(val).unwrap(); diff --git a/src/tools/clippy/tests/ui/useless_conversion_try.stderr b/src/tools/clippy/tests/ui/useless_conversion_try.stderr index 11fb8f38ea5c2..30a43629dbd6a 100644 --- a/src/tools/clippy/tests/ui/useless_conversion_try.stderr +++ b/src/tools/clippy/tests/ui/useless_conversion_try.stderr @@ -1,5 +1,5 @@ error: useless conversion to the same type: `T` - --> tests/ui/useless_conversion_try.rs:5:13 + --> tests/ui/useless_conversion_try.rs:9:13 | LL | let _ = T::try_from(val).unwrap(); | ^^^^^^^^^^^^^^^^ @@ -12,7 +12,7 @@ LL | #![deny(clippy::useless_conversion)] | ^^^^^^^^^^^^^^^^^^^^^^^^^^ error: useless conversion to the same type: `T` - --> tests/ui/useless_conversion_try.rs:7:5 + --> tests/ui/useless_conversion_try.rs:11:5 | LL | val.try_into().unwrap() | ^^^^^^^^^^^^^^ @@ -20,7 +20,7 @@ LL | val.try_into().unwrap() = help: consider removing `.try_into()` error: useless conversion to the same type: `std::string::String` - --> tests/ui/useless_conversion_try.rs:30:21 + --> tests/ui/useless_conversion_try.rs:34:21 | LL | let _: String = "foo".to_string().try_into().unwrap(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -28,7 +28,7 @@ LL | let _: String = "foo".to_string().try_into().unwrap(); = help: consider removing `.try_into()` error: useless conversion to the same type: `std::string::String` - --> tests/ui/useless_conversion_try.rs:32:21 + --> tests/ui/useless_conversion_try.rs:36:21 | LL | let _: String = TryFrom::try_from("foo".to_string()).unwrap(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -36,7 +36,7 @@ LL | let _: String = TryFrom::try_from("foo".to_string()).unwrap(); = help: consider removing `TryFrom::try_from()` error: useless conversion to the same type: `std::string::String` - --> tests/ui/useless_conversion_try.rs:34:13 + --> tests/ui/useless_conversion_try.rs:38:13 | LL | let _ = String::try_from("foo".to_string()).unwrap(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -44,7 +44,7 @@ LL | let _ = String::try_from("foo".to_string()).unwrap(); = help: consider removing `String::try_from()` error: useless conversion to the same type: `std::string::String` - --> tests/ui/useless_conversion_try.rs:36:13 + --> tests/ui/useless_conversion_try.rs:40:13 | LL | let _ = String::try_from(format!("A: {:04}", 123)).unwrap(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -52,7 +52,7 @@ LL | let _ = String::try_from(format!("A: {:04}", 123)).unwrap(); = help: consider removing `String::try_from()` error: useless conversion to the same type: `std::string::String` - --> tests/ui/useless_conversion_try.rs:38:21 + --> tests/ui/useless_conversion_try.rs:42:21 | LL | let _: String = format!("Hello {}", "world").try_into().unwrap(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -60,7 +60,7 @@ LL | let _: String = format!("Hello {}", "world").try_into().unwrap(); = help: consider removing `.try_into()` error: useless conversion to the same type: `std::string::String` - --> tests/ui/useless_conversion_try.rs:40:21 + --> tests/ui/useless_conversion_try.rs:44:21 | LL | let _: String = String::new().try_into().unwrap(); | ^^^^^^^^^^^^^^^^^^^^^^^^ @@ -68,7 +68,7 @@ LL | let _: String = String::new().try_into().unwrap(); = help: consider removing `.try_into()` error: useless conversion to the same type: `std::string::String` - --> tests/ui/useless_conversion_try.rs:42:27 + --> tests/ui/useless_conversion_try.rs:46:27 | LL | let _: String = match String::from("_").try_into() { | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ diff --git a/src/tools/clippy/util/gh-pages/script.js b/src/tools/clippy/util/gh-pages/script.js index 7fd779fe9a46e..7cca298df8e45 100644 --- a/src/tools/clippy/util/gh-pages/script.js +++ b/src/tools/clippy/util/gh-pages/script.js @@ -397,7 +397,7 @@ $scope.bySearch = function (lint, index, array) { let searchStr = $scope.search; // It can be `null` I haven't missed this value - if (searchStr == null || searchStr.length < 3) { + if (searchStr == null) { return true; } searchStr = searchStr.toLowerCase(); diff --git a/src/tools/compiletest/src/common.rs b/src/tools/compiletest/src/common.rs index b0047770564c4..da7f03441e72f 100644 --- a/src/tools/compiletest/src/common.rs +++ b/src/tools/compiletest/src/common.rs @@ -582,7 +582,7 @@ impl TargetCfgs { name, Some( value - .strip_suffix("\"") + .strip_suffix('\"') .expect("key-value pair should be properly quoted"), ), ) diff --git a/src/tools/compiletest/src/header.rs b/src/tools/compiletest/src/header.rs index da0196dad2ff7..5469b9f1a0a2c 100644 --- a/src/tools/compiletest/src/header.rs +++ b/src/tools/compiletest/src/header.rs @@ -14,6 +14,7 @@ use crate::common::{Config, Debugger, FailMode, Mode, PassMode}; use crate::header::cfg::parse_cfg_name_directive; use crate::header::cfg::MatchOutcome; use crate::header::needs::CachedNeedsConditions; +use crate::util::static_regex; use crate::{extract_cdb_version, extract_gdb_version}; mod cfg; @@ -81,7 +82,7 @@ impl EarlyProps { panic!("errors encountered during EarlyProps parsing"); } - return props; + props } } @@ -381,7 +382,7 @@ impl TestProps { // Individual flags can be single-quoted to preserve spaces; see // . flags - .split("'") + .split('\'') .enumerate() .flat_map(|(i, f)| { if i % 2 == 1 { vec![f] } else { f.split_whitespace().collect() } @@ -612,7 +613,7 @@ impl TestProps { for key in &["RUST_TEST_NOCAPTURE", "RUST_TEST_THREADS"] { if let Ok(val) = env::var(key) { - if self.exec_env.iter().find(|&&(ref x, _)| x == key).is_none() { + if !self.exec_env.iter().any(|&(ref x, _)| x == key) { self.exec_env.push(((*key).to_owned(), val)) } } @@ -990,7 +991,7 @@ pub(crate) fn check_directive(directive_ln: &str) -> CheckDirectiveResult<'_> { let trailing = post.trim().split_once(' ').map(|(pre, _)| pre).unwrap_or(post); let trailing_directive = { // 1. is the directive name followed by a space? (to exclude `:`) - matches!(directive_ln.get(directive_name.len()..), Some(s) if s.starts_with(" ")) + matches!(directive_ln.get(directive_name.len()..), Some(s) if s.starts_with(' ')) // 2. is what is after that directive also a directive (ex: "only-x86 only-arm") && KNOWN_DIRECTIVE_NAMES.contains(&trailing) } @@ -1022,9 +1023,6 @@ fn iter_header( if mode == Mode::CoverageRun { let extra_directives: &[&str] = &[ "needs-profiler-support", - // FIXME(mati865): MinGW GCC miscompiles compiler-rt profiling library but with Clang it works - // properly. Since we only have GCC on the CI ignore the test for now. - "ignore-windows-gnu", // FIXME(pietroalbini): this test currently does not work on cross-compiled // targets because remote-test is not capable of sending back the *.profraw // files generated by the LLVM instrumentation. @@ -1186,11 +1184,11 @@ impl Config { } } - fn parse_custom_normalization(&self, mut line: &str, prefix: &str) -> Option<(String, String)> { + fn parse_custom_normalization(&self, line: &str, prefix: &str) -> Option<(String, String)> { if parse_cfg_name_directive(self, line, prefix).outcome == MatchOutcome::Match { - let from = parse_normalization_string(&mut line)?; - let to = parse_normalization_string(&mut line)?; - Some((from, to)) + let (regex, replacement) = parse_normalize_rule(line) + .unwrap_or_else(|| panic!("couldn't parse custom normalization rule: `{line}`")); + Some((regex, replacement)) } else { None } @@ -1311,24 +1309,29 @@ fn expand_variables(mut value: String, config: &Config) -> String { value } -/// Finds the next quoted string `"..."` in `line`, and extract the content from it. Move the `line` -/// variable after the end of the quoted string. -/// -/// # Examples -/// -/// ``` -/// let mut s = "normalize-stderr-32bit: \"something (32 bits)\" -> \"something ($WORD bits)\"."; -/// let first = parse_normalization_string(&mut s); -/// assert_eq!(first, Some("something (32 bits)".to_owned())); -/// assert_eq!(s, " -> \"something ($WORD bits)\"."); +/// Parses the regex and replacement values of a `//@ normalize-*` header, +/// in the format: +/// ```text +/// normalize-*: "REGEX" -> "REPLACEMENT" /// ``` -fn parse_normalization_string(line: &mut &str) -> Option { - // FIXME support escapes in strings. - let begin = line.find('"')? + 1; - let end = line[begin..].find('"')? + begin; - let result = line[begin..end].to_owned(); - *line = &line[end + 1..]; - Some(result) +fn parse_normalize_rule(header: &str) -> Option<(String, String)> { + // FIXME(#126370): A colon after the header name should be mandatory, but + // currently is not, and there are many tests that lack the colon. + // FIXME: Support escaped double-quotes in strings. + let captures = static_regex!( + r#"(?x) # (verbose mode regex) + ^ + [^:\s]+:?\s* # (header name followed by optional colon) + "(?[^"]*)" # "REGEX" + \s+->\s+ # -> + "(?[^"]*)" # "REPLACEMENT" + $ + "# + ) + .captures(header)?; + let regex = captures["regex"].to_owned(); + let replacement = captures["replacement"].to_owned(); + Some((regex, replacement)) } pub fn extract_llvm_version(version: &str) -> Option { @@ -1357,7 +1360,7 @@ pub fn extract_llvm_version_from_binary(binary_path: &str) -> Option { } let version = String::from_utf8(output.stdout).ok()?; for line in version.lines() { - if let Some(version) = line.split("LLVM version ").skip(1).next() { + if let Some(version) = line.split("LLVM version ").nth(1) { return extract_llvm_version(version); } } @@ -1388,7 +1391,7 @@ where let min = parse(min)?; let max = match max { - Some(max) if max.is_empty() => return None, + Some("") => return None, Some(max) => parse(max)?, _ => min, }; @@ -1460,12 +1463,12 @@ pub fn make_test_description( decision!(ignore_gdb(config, ln)); decision!(ignore_lldb(config, ln)); - if config.target == "wasm32-unknown-unknown" { - if config.parse_name_directive(ln, directives::CHECK_RUN_RESULTS) { - decision!(IgnoreDecision::Ignore { - reason: "ignored on WASM as the run results cannot be checked there".into(), - }); - } + if config.target == "wasm32-unknown-unknown" + && config.parse_name_directive(ln, directives::CHECK_RUN_RESULTS) + { + decision!(IgnoreDecision::Ignore { + reason: "ignored on WASM as the run results cannot be checked there".into(), + }); } should_fail |= config.parse_name_directive(ln, "should-fail"); diff --git a/src/tools/compiletest/src/header/cfg.rs b/src/tools/compiletest/src/header/cfg.rs index 510043e3bfd8f..522c52b1de2a7 100644 --- a/src/tools/compiletest/src/header/cfg.rs +++ b/src/tools/compiletest/src/header/cfg.rs @@ -58,7 +58,7 @@ pub(super) fn parse_cfg_name_directive<'a>( // Some of the matchers might be "" depending on what the target information is. To avoid // problems we outright reject empty directives. - if name == "" { + if name.is_empty() { return ParsedNameDirective::not_a_directive(); } diff --git a/src/tools/compiletest/src/header/tests.rs b/src/tools/compiletest/src/header/tests.rs index 8a37a4d6d3135..61a85b84ad64c 100644 --- a/src/tools/compiletest/src/header/tests.rs +++ b/src/tools/compiletest/src/header/tests.rs @@ -3,7 +3,7 @@ use std::path::Path; use std::str::FromStr; use crate::common::{Config, Debugger, Mode}; -use crate::header::{parse_normalization_string, EarlyProps, HeadersCache}; +use crate::header::{parse_normalize_rule, EarlyProps, HeadersCache}; use super::iter_header; @@ -32,35 +32,41 @@ fn make_test_description( } #[test] -fn test_parse_normalization_string() { - let mut s = "normalize-stderr-32bit: \"something (32 bits)\" -> \"something ($WORD bits)\"."; - let first = parse_normalization_string(&mut s); - assert_eq!(first, Some("something (32 bits)".to_owned())); - assert_eq!(s, " -> \"something ($WORD bits)\"."); - - // Nothing to normalize (No quotes) - let mut s = "normalize-stderr-32bit: something (32 bits) -> something ($WORD bits)."; - let first = parse_normalization_string(&mut s); - assert_eq!(first, None); - assert_eq!(s, r#"normalize-stderr-32bit: something (32 bits) -> something ($WORD bits)."#); - - // Nothing to normalize (Only a single quote) - let mut s = "normalize-stderr-32bit: \"something (32 bits) -> something ($WORD bits)."; - let first = parse_normalization_string(&mut s); - assert_eq!(first, None); - assert_eq!(s, "normalize-stderr-32bit: \"something (32 bits) -> something ($WORD bits)."); - - // Nothing to normalize (Three quotes) - let mut s = "normalize-stderr-32bit: \"something (32 bits)\" -> \"something ($WORD bits)."; - let first = parse_normalization_string(&mut s); - assert_eq!(first, Some("something (32 bits)".to_owned())); - assert_eq!(s, " -> \"something ($WORD bits)."); - - // Nothing to normalize (No quotes, 16-bit) - let mut s = "normalize-stderr-16bit: something (16 bits) -> something ($WORD bits)."; - let first = parse_normalization_string(&mut s); - assert_eq!(first, None); - assert_eq!(s, r#"normalize-stderr-16bit: something (16 bits) -> something ($WORD bits)."#); +fn test_parse_normalize_rule() { + let good_data = &[ + ( + r#"normalize-stderr-32bit: "something (32 bits)" -> "something ($WORD bits)""#, + "something (32 bits)", + "something ($WORD bits)", + ), + // FIXME(#126370): A colon after the header name should be mandatory, + // but currently is not, and there are many tests that lack the colon. + ( + r#"normalize-stderr-32bit "something (32 bits)" -> "something ($WORD bits)""#, + "something (32 bits)", + "something ($WORD bits)", + ), + ]; + + for &(input, expected_regex, expected_replacement) in good_data { + let parsed = parse_normalize_rule(input); + let parsed = + parsed.as_ref().map(|(regex, replacement)| (regex.as_str(), replacement.as_str())); + assert_eq!(parsed, Some((expected_regex, expected_replacement))); + } + + let bad_data = &[ + r#"normalize-stderr-16bit: something (16 bits) -> something ($WORD bits)"#, + r#"normalize-stderr-32bit: something (32 bits) -> something ($WORD bits)"#, + r#"normalize-stderr-32bit: "something (32 bits) -> something ($WORD bits)"#, + r#"normalize-stderr-32bit: "something (32 bits)" -> "something ($WORD bits)"#, + r#"normalize-stderr-32bit: "something (32 bits)" -> "something ($WORD bits)"."#, + ]; + + for &input in bad_data { + let parsed = parse_normalize_rule(input); + assert_eq!(parsed, None); + } } #[derive(Default)] diff --git a/src/tools/compiletest/src/lib.rs b/src/tools/compiletest/src/lib.rs index 62e71e9b59ddb..0cf05b32e9681 100644 --- a/src/tools/compiletest/src/lib.rs +++ b/src/tools/compiletest/src/lib.rs @@ -1147,7 +1147,7 @@ fn extract_lldb_version(full_version_line: &str) -> Option<(u32, bool)> { } fn not_a_digit(c: char) -> bool { - !c.is_digit(10) + !c.is_ascii_digit() } fn check_overlapping_tests(found_paths: &HashSet) { diff --git a/src/tools/compiletest/src/read2.rs b/src/tools/compiletest/src/read2.rs index 3f1921cb6bd5a..8c06339f3c36d 100644 --- a/src/tools/compiletest/src/read2.rs +++ b/src/tools/compiletest/src/read2.rs @@ -6,7 +6,6 @@ mod tests; pub use self::imp::read2; use std::io::{self, Write}; -use std::mem::replace; use std::process::{Child, Output}; #[derive(Copy, Clone, Debug)] @@ -101,10 +100,10 @@ impl ProcOutput { return; } - let mut head = replace(bytes, Vec::new()); + let mut head = std::mem::take(bytes); // Don't truncate if this as a whole line. // That should make it less likely that we cut a JSON line in half. - if head.last() != Some(&('\n' as u8)) { + if head.last() != Some(&b'\n') { head.truncate(MAX_OUT_LEN); } let skipped = new_len - head.len(); diff --git a/src/tools/compiletest/src/read2/tests.rs b/src/tools/compiletest/src/read2/tests.rs index 5ad2db3cb830b..9e052ff069b99 100644 --- a/src/tools/compiletest/src/read2/tests.rs +++ b/src/tools/compiletest/src/read2/tests.rs @@ -64,9 +64,9 @@ fn test_abbreviate_filterss_are_detected() { #[test] fn test_abbreviate_filters_avoid_abbreviations() { let mut out = ProcOutput::new(); - let filters = &[std::iter::repeat('a').take(64).collect::()]; + let filters = &["a".repeat(64)]; - let mut expected = vec![b'.'; MAX_OUT_LEN - FILTERED_PATHS_PLACEHOLDER_LEN as usize]; + let mut expected = vec![b'.'; MAX_OUT_LEN - FILTERED_PATHS_PLACEHOLDER_LEN]; expected.extend_from_slice(filters[0].as_bytes()); out.extend(&expected, filters); @@ -81,7 +81,7 @@ fn test_abbreviate_filters_avoid_abbreviations() { #[test] fn test_abbreviate_filters_can_still_cause_abbreviations() { let mut out = ProcOutput::new(); - let filters = &[std::iter::repeat('a').take(64).collect::()]; + let filters = &["a".repeat(64)]; let mut input = vec![b'.'; MAX_OUT_LEN]; input.extend_from_slice(filters[0].as_bytes()); diff --git a/src/tools/compiletest/src/runtest.rs b/src/tools/compiletest/src/runtest.rs index dbe016b8305a2..72b57d91c234e 100644 --- a/src/tools/compiletest/src/runtest.rs +++ b/src/tools/compiletest/src/runtest.rs @@ -15,7 +15,7 @@ use crate::errors::{self, Error, ErrorKind}; use crate::header::TestProps; use crate::json; use crate::read2::{read2_abbreviated, Truncated}; -use crate::util::{add_dylib_path, copy_dir_all, dylib_env_var, logv, PathBufExt}; +use crate::util::{add_dylib_path, copy_dir_all, dylib_env_var, logv, static_regex, PathBufExt}; use crate::ColorConfig; use colored::Colorize; use miropt_test_tools::{files_for_miropt_test, MiroptTest, MiroptTestFile}; @@ -48,14 +48,6 @@ use debugger::DebuggerCommands; #[cfg(test)] mod tests; -macro_rules! static_regex { - ($re:literal) => {{ - static RE: ::std::sync::OnceLock<::regex::Regex> = ::std::sync::OnceLock::new(); - RE.get_or_init(|| ::regex::Regex::new($re).unwrap()) - }}; -} -use static_regex; - const FAKE_SRC_BASE: &str = "fake-test-src-base"; #[cfg(windows)] @@ -382,11 +374,11 @@ impl<'test> TestCx<'test> { // if a test does not crash, consider it an error if proc_res.status.success() || matches!(proc_res.status.code(), Some(1 | 0)) { - self.fatal(&format!( + self.fatal( "test no longer crashes/triggers ICE! Please give it a mearningful name, \ add a doc-comment to the start of the test explaining why it exists and \ - move it to tests/ui or wherever you see fit." - )); + move it to tests/ui or wherever you see fit.", + ); } } @@ -705,10 +697,10 @@ impl<'test> TestCx<'test> { // since it is extensively used in the testsuite. check_cfg.push_str("cfg(FALSE"); for revision in &self.props.revisions { - check_cfg.push_str(","); - check_cfg.push_str(&normalize_revision(&revision)); + check_cfg.push(','); + check_cfg.push_str(&normalize_revision(revision)); } - check_cfg.push_str(")"); + check_cfg.push(')'); cmd.args(&["--check-cfg", &check_cfg]); } @@ -826,7 +818,7 @@ impl<'test> TestCx<'test> { // Append the other `cdb-command:`s for line in &dbg_cmds.commands { script_str.push_str(line); - script_str.push_str("\n"); + script_str.push('\n'); } script_str.push_str("qq\n"); // Quit the debugger (including remote debugger, if any) @@ -1208,7 +1200,7 @@ impl<'test> TestCx<'test> { // Append the other commands for line in &dbg_cmds.commands { script_str.push_str(line); - script_str.push_str("\n"); + script_str.push('\n'); } // Finally, quit the debugger @@ -1258,7 +1250,7 @@ impl<'test> TestCx<'test> { // Remove options that are either unwanted (-O) or may lead to duplicates due to RUSTFLAGS. let options_to_remove = ["-O".to_owned(), "-g".to_owned(), "--debuginfo".to_owned()]; - options.iter().filter(|x| !options_to_remove.contains(x)).map(|x| x.clone()).collect() + options.iter().filter(|x| !options_to_remove.contains(x)).cloned().collect() } fn maybe_add_external_args(&self, cmd: &mut Command, args: &Vec) { @@ -2512,8 +2504,8 @@ impl<'test> TestCx<'test> { // This works with both `--emit asm` (as default output name for the assembly) // and `ptx-linker` because the latter can write output at requested location. let output_path = self.output_base_name().with_extension(extension); - let output_file = TargetLocation::ThisFile(output_path.clone()); - output_file + + TargetLocation::ThisFile(output_path.clone()) } } @@ -2760,7 +2752,7 @@ impl<'test> TestCx<'test> { for entry in walkdir::WalkDir::new(dir) { let entry = entry.expect("failed to read file"); if entry.file_type().is_file() - && entry.path().extension().and_then(|p| p.to_str()) == Some("html".into()) + && entry.path().extension().and_then(|p| p.to_str()) == Some("html") { let status = Command::new("tidy").args(&tidy_args).arg(entry.path()).status().unwrap(); @@ -2791,8 +2783,7 @@ impl<'test> TestCx<'test> { &compare_dir, self.config.verbose, |file_type, extension| { - file_type.is_file() - && (extension == Some("html".into()) || extension == Some("js".into())) + file_type.is_file() && (extension == Some("html") || extension == Some("js")) }, ) { return; @@ -2838,11 +2829,11 @@ impl<'test> TestCx<'test> { } match String::from_utf8(line.clone()) { Ok(line) => { - if line.starts_with("+") { + if line.starts_with('+') { write!(&mut out, "{}", line.green()).unwrap(); - } else if line.starts_with("-") { + } else if line.starts_with('-') { write!(&mut out, "{}", line.red()).unwrap(); - } else if line.starts_with("@") { + } else if line.starts_with('@') { write!(&mut out, "{}", line.blue()).unwrap(); } else { out.write_all(line.as_bytes()).unwrap(); @@ -2915,7 +2906,7 @@ impl<'test> TestCx<'test> { && line.ends_with(';') { if let Some(ref mut other_files) = other_files { - other_files.push(line.rsplit("mod ").next().unwrap().replace(";", "")); + other_files.push(line.rsplit("mod ").next().unwrap().replace(';', "")); } None } else { @@ -3147,7 +3138,7 @@ impl<'test> TestCx<'test> { let mut string = String::new(); for cgu in cgus { string.push_str(&cgu[..]); - string.push_str(" "); + string.push(' '); } string @@ -3180,10 +3171,7 @@ impl<'test> TestCx<'test> { // CGUs joined with "--". This function splits such composite CGU names // and handles each component individually. fn remove_crate_disambiguators_from_set_of_cgu_names(cgus: &str) -> String { - cgus.split("--") - .map(|cgu| remove_crate_disambiguator_from_cgu(cgu)) - .collect::>() - .join("--") + cgus.split("--").map(remove_crate_disambiguator_from_cgu).collect::>().join("--") } } @@ -3365,7 +3353,7 @@ impl<'test> TestCx<'test> { // endif } - if self.config.target.contains("msvc") && self.config.cc != "" { + if self.config.target.contains("msvc") && !self.config.cc.is_empty() { // We need to pass a path to `lib.exe`, so assume that `cc` is `cl.exe` // and that `lib.exe` lives next to it. let lib = Path::new(&self.config.cc).parent().unwrap().join("lib.exe"); @@ -3551,6 +3539,10 @@ impl<'test> TestCx<'test> { .env("TARGET_RPATH_DIR", cwd.join(&self.config.run_lib_path)) .env("LLVM_COMPONENTS", &self.config.llvm_components); + // In test code we want to be very pedantic about values being silently discarded that are + // annotated with `#[must_use]`. + cmd.arg("-Dunused_must_use"); + if std::env::var_os("COMPILETEST_FORCE_STAGE0").is_some() { let mut stage0_sysroot = build_root.clone(); stage0_sysroot.push("stage0-sysroot"); @@ -3643,7 +3635,7 @@ impl<'test> TestCx<'test> { // endif } - if self.config.target.contains("msvc") && self.config.cc != "" { + if self.config.target.contains("msvc") && !self.config.cc.is_empty() { // We need to pass a path to `lib.exe`, so assume that `cc` is `cl.exe` // and that `lib.exe` lives next to it. let lib = Path::new(&self.config.cc).parent().unwrap().join("lib.exe"); @@ -3834,7 +3826,7 @@ impl<'test> TestCx<'test> { && !self.props.dont_check_compiler_stderr { self.fatal_proc_rec( - &format!("compiler output got truncated, cannot compare with reference file"), + "compiler output got truncated, cannot compare with reference file", &proc_res, ); } @@ -4015,8 +4007,8 @@ impl<'test> TestCx<'test> { crate_name.to_str().expect("crate name implies file name must be valid UTF-8"); // replace `a.foo` -> `a__foo` for crate name purposes. // replace `revision-name-with-dashes` -> `revision_name_with_underscore` - let crate_name = crate_name.replace(".", "__"); - let crate_name = crate_name.replace("-", "_"); + let crate_name = crate_name.replace('.', "__"); + let crate_name = crate_name.replace('-', "_"); rustc.arg("--crate-name"); rustc.arg(crate_name); } @@ -4064,7 +4056,7 @@ impl<'test> TestCx<'test> { fn check_mir_dump(&self, test_info: MiroptTest) { let test_dir = self.testpaths.file.parent().unwrap(); let test_crate = - self.testpaths.file.file_stem().unwrap().to_str().unwrap().replace("-", "_"); + self.testpaths.file.file_stem().unwrap().to_str().unwrap().replace('-', "_"); let MiroptTest { run_filecheck, suffix, files, passes: _ } = test_info; diff --git a/src/tools/compiletest/src/runtest/coverage.rs b/src/tools/compiletest/src/runtest/coverage.rs index 8bd7c7e808d3f..6ee147da5a965 100644 --- a/src/tools/compiletest/src/runtest/coverage.rs +++ b/src/tools/compiletest/src/runtest/coverage.rs @@ -7,7 +7,8 @@ use std::process::Command; use glob::glob; use crate::common::{UI_COVERAGE, UI_COVERAGE_MAP}; -use crate::runtest::{static_regex, Emit, ProcRes, TestCx, WillExecute}; +use crate::runtest::{Emit, ProcRes, TestCx, WillExecute}; +use crate::util::static_regex; impl<'test> TestCx<'test> { fn coverage_dump_path(&self) -> &Path { diff --git a/src/tools/compiletest/src/runtest/debugger.rs b/src/tools/compiletest/src/runtest/debugger.rs index eebe5f3580b30..ed6cc97a8abba 100644 --- a/src/tools/compiletest/src/runtest/debugger.rs +++ b/src/tools/compiletest/src/runtest/debugger.rs @@ -148,5 +148,5 @@ fn check_single_line(line: &str, check_line: &str) -> bool { rest = &rest[pos + current_fragment.len()..]; } - if !can_end_anywhere && !rest.is_empty() { false } else { true } + can_end_anywhere || rest.is_empty() } diff --git a/src/tools/compiletest/src/tests.rs b/src/tools/compiletest/src/tests.rs index e6725dba26051..4292f234adc78 100644 --- a/src/tools/compiletest/src/tests.rs +++ b/src/tools/compiletest/src/tests.rs @@ -58,11 +58,11 @@ fn test_extract_lldb_version() { #[test] fn is_test_test() { - assert_eq!(true, is_test(&OsString::from("a_test.rs"))); - assert_eq!(false, is_test(&OsString::from(".a_test.rs"))); - assert_eq!(false, is_test(&OsString::from("a_cat.gif"))); - assert_eq!(false, is_test(&OsString::from("#a_dog_gif"))); - assert_eq!(false, is_test(&OsString::from("~a_temp_file"))); + assert!(is_test(&OsString::from("a_test.rs"))); + assert!(!is_test(&OsString::from(".a_test.rs"))); + assert!(!is_test(&OsString::from("a_cat.gif"))); + assert!(!is_test(&OsString::from("#a_dog_gif"))); + assert!(!is_test(&OsString::from("~a_temp_file"))); } #[test] diff --git a/src/tools/compiletest/src/util.rs b/src/tools/compiletest/src/util.rs index ec20bda8c1896..cdec49a51d75b 100644 --- a/src/tools/compiletest/src/util.rs +++ b/src/tools/compiletest/src/util.rs @@ -90,3 +90,11 @@ pub fn copy_dir_all(src: impl AsRef, dst: impl AsRef) -> std::io::Re } Ok(()) } + +macro_rules! static_regex { + ($re:literal) => {{ + static RE: ::std::sync::OnceLock<::regex::Regex> = ::std::sync::OnceLock::new(); + RE.get_or_init(|| ::regex::Regex::new($re).unwrap()) + }}; +} +pub(crate) use static_regex; diff --git a/src/tools/generate-windows-sys/Cargo.toml b/src/tools/generate-windows-sys/Cargo.toml index 8b971d6efe7e8..ebf3082fb4f24 100644 --- a/src/tools/generate-windows-sys/Cargo.toml +++ b/src/tools/generate-windows-sys/Cargo.toml @@ -4,4 +4,4 @@ version = "0.1.0" edition = "2021" [dependencies.windows-bindgen] -version = "0.56.0" +version = "0.57.0" diff --git a/src/tools/jsondoclint/src/validator.rs b/src/tools/jsondoclint/src/validator.rs index 5e35ce242fe4e..1713a4d812c4b 100644 --- a/src/tools/jsondoclint/src/validator.rs +++ b/src/tools/jsondoclint/src/validator.rs @@ -418,15 +418,13 @@ impl<'a> Validator<'a> { } else { self.fail_expecting(id, expected); } - } else { - if !self.missing_ids.contains(id) { - self.missing_ids.insert(id); + } else if !self.missing_ids.contains(id) { + self.missing_ids.insert(id); - let sels = json_find::find_selector(&self.krate_json, &Value::String(id.0.clone())); - assert_ne!(sels.len(), 0); + let sels = json_find::find_selector(&self.krate_json, &Value::String(id.0.clone())); + assert_ne!(sels.len(), 0); - self.fail(id, ErrorKind::NotFound(sels)) - } + self.fail(id, ErrorKind::NotFound(sels)) } } diff --git a/src/tools/linkchecker/Cargo.toml b/src/tools/linkchecker/Cargo.toml index 05049aabc7d9c..f1be6e9e749d4 100644 --- a/src/tools/linkchecker/Cargo.toml +++ b/src/tools/linkchecker/Cargo.toml @@ -9,4 +9,4 @@ path = "main.rs" [dependencies] regex = "1" -html5ever = "0.26.0" +html5ever = "0.27.0" diff --git a/src/tools/linkchecker/main.rs b/src/tools/linkchecker/main.rs index 32f935de73025..7321bd1bb52f2 100644 --- a/src/tools/linkchecker/main.rs +++ b/src/tools/linkchecker/main.rs @@ -503,7 +503,7 @@ fn maybe_redirect(source: &str) -> Option { fn parse_html(source: &str, sink: Sink) -> Sink { let tendril: ByteTendril = source.as_bytes().into(); - let mut input = BufferQueue::new(); + let mut input = BufferQueue::default(); input.push_back(tendril.try_reinterpret().unwrap()); let mut tok = Tokenizer::new(sink, TokenizerOpts::default()); diff --git a/src/tools/lint-docs/src/groups.rs b/src/tools/lint-docs/src/groups.rs index 73f5738469ed1..f246d71d499b4 100644 --- a/src/tools/lint-docs/src/groups.rs +++ b/src/tools/lint-docs/src/groups.rs @@ -121,13 +121,13 @@ impl<'a> LintExtractor<'a> { }; to_link.extend(group_lints); let brackets: Vec<_> = group_lints.iter().map(|l| format!("[{}]", l)).collect(); - write!(result, "| {} | {} | {} |\n", group_name, description, brackets.join(", ")) + writeln!(result, "| {} | {} | {} |", group_name, description, brackets.join(", ")) .unwrap(); } result.push('\n'); result.push_str("[warn-by-default]: listing/warn-by-default.md\n"); for lint_name in to_link { - let lint_def = match lints.iter().find(|l| l.name == lint_name.replace("-", "_")) { + let lint_def = match lints.iter().find(|l| l.name == lint_name.replace('-', "_")) { Some(def) => def, None => { let msg = format!( @@ -144,9 +144,9 @@ impl<'a> LintExtractor<'a> { } } }; - write!( + writeln!( result, - "[{}]: listing/{}#{}\n", + "[{}]: listing/{}#{}", lint_name, lint_def.level.doc_filename(), lint_name diff --git a/src/tools/lint-docs/src/lib.rs b/src/tools/lint-docs/src/lib.rs index c79b377727abf..72d6a495e7e79 100644 --- a/src/tools/lint-docs/src/lib.rs +++ b/src/tools/lint-docs/src/lib.rs @@ -84,8 +84,8 @@ impl Lint { for &expected in &["### Example", "### Explanation", "{{produces}}"] { if expected == "{{produces}}" && self.is_ignored() { if self.doc_contains("{{produces}}") { - return Err(format!( - "the lint example has `ignore`, but also contains the {{{{produces}}}} marker\n\ + return Err( + "the lint example has `ignore`, but also contains the {{produces}} marker\n\ \n\ The documentation generator cannot generate the example output when the \ example is ignored.\n\ @@ -111,7 +111,7 @@ impl Lint { Replacing the output with the text of the example you \ compiled manually yourself.\n\ " - ).into()); + .into()); } continue; } @@ -519,11 +519,11 @@ impl<'a> LintExtractor<'a> { let mut these_lints: Vec<_> = lints.iter().filter(|lint| lint.level == level).collect(); these_lints.sort_unstable_by_key(|lint| &lint.name); for lint in &these_lints { - write!(result, "* [`{}`](#{})\n", lint.name, lint.name.replace("_", "-")).unwrap(); + writeln!(result, "* [`{}`](#{})", lint.name, lint.name.replace('_', "-")).unwrap(); } result.push('\n'); for lint in &these_lints { - write!(result, "## {}\n\n", lint.name.replace("_", "-")).unwrap(); + write!(result, "## {}\n\n", lint.name.replace('_', "-")).unwrap(); for line in &lint.doc { result.push_str(line); result.push('\n'); @@ -583,7 +583,7 @@ fn add_rename_redirect(level: Level, output: &mut String) { let filename = level.doc_filename().replace(".md", ".html"); output.push_str(RENAME_START); for (from, to) in *names { - write!(output, " \"#{from}\": \"{filename}#{to}\",\n").unwrap(); + writeln!(output, " \"#{from}\": \"{filename}#{to}\",").unwrap(); } output.push_str(RENAME_END); } diff --git a/src/tools/miri/rust-version b/src/tools/miri/rust-version index e49680ba75a5e..c1796cfd82a67 100644 --- a/src/tools/miri/rust-version +++ b/src/tools/miri/rust-version @@ -1 +1 @@ -f6b4b71ef10307201b52c17b0f9dcf9557cd90ba +e794b0f8557c187b5909d889aa35071f81e0a4cc diff --git a/src/tools/miri/src/helpers.rs b/src/tools/miri/src/helpers.rs index 87b53d87ac87e..843aff024958a 100644 --- a/src/tools/miri/src/helpers.rs +++ b/src/tools/miri/src/helpers.rs @@ -7,7 +7,7 @@ use std::time::Duration; use rand::RngCore; -use rustc_apfloat::ieee::{Double, Single}; +use rustc_apfloat::ieee::{Double, Half, Quad, Single}; use rustc_apfloat::Float; use rustc_hir::{ def::{DefKind, Namespace}, @@ -1201,12 +1201,14 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { }; let (val, status) = match fty { - FloatTy::F16 => unimplemented!("f16_f128"), + FloatTy::F16 => + float_to_int_inner::(this, src.to_scalar().to_f16()?, cast_to, round), FloatTy::F32 => float_to_int_inner::(this, src.to_scalar().to_f32()?, cast_to, round), FloatTy::F64 => float_to_int_inner::(this, src.to_scalar().to_f64()?, cast_to, round), - FloatTy::F128 => unimplemented!("f16_f128"), + FloatTy::F128 => + float_to_int_inner::(this, src.to_scalar().to_f128()?, cast_to, round), }; if status.intersects( diff --git a/src/tools/miri/src/lib.rs b/src/tools/miri/src/lib.rs index 11cbbde06aa08..f8410db4dd0f9 100644 --- a/src/tools/miri/src/lib.rs +++ b/src/tools/miri/src/lib.rs @@ -13,6 +13,7 @@ #![feature(lint_reasons)] #![feature(trait_upcasting)] #![feature(strict_overflow_ops)] +#![feature(is_none_or)] // Configure clippy and other lints #![allow( clippy::collapsible_else_if, diff --git a/src/tools/miri/src/shims/foreign_items.rs b/src/tools/miri/src/shims/foreign_items.rs index b8d85a1950297..5a293344cc849 100644 --- a/src/tools/miri/src/shims/foreign_items.rs +++ b/src/tools/miri/src/shims/foreign_items.rs @@ -412,12 +412,12 @@ trait EvalContextExtPriv<'tcx>: crate::MiriInterpCxExt<'tcx> { // If the newly promised alignment is bigger than the native alignment of this // allocation, and bigger than the previously promised alignment, then set it. if align > alloc_align - && !this + && this .machine .symbolic_alignment .get_mut() .get(&alloc_id) - .is_some_and(|&(_, old_align)| align <= old_align) + .is_none_or(|&(_, old_align)| align > old_align) { this.machine.symbolic_alignment.get_mut().insert(alloc_id, (offset, align)); } diff --git a/src/tools/miri/tests/fail/function_calls/exported_symbol_bad_unwind2.both.stderr b/src/tools/miri/tests/fail/function_calls/exported_symbol_bad_unwind2.both.stderr index d88781ed22549..112a9687837ec 100644 --- a/src/tools/miri/tests/fail/function_calls/exported_symbol_bad_unwind2.both.stderr +++ b/src/tools/miri/tests/fail/function_calls/exported_symbol_bad_unwind2.both.stderr @@ -16,7 +16,7 @@ LL | ABORT(); = note: inside `std::sys::pal::PLATFORM::abort_internal` at RUSTLIB/std/src/sys/pal/PLATFORM/mod.rs:LL:CC = note: inside `std::panicking::rust_panic_with_hook` at RUSTLIB/std/src/panicking.rs:LL:CC = note: inside closure at RUSTLIB/std/src/panicking.rs:LL:CC - = note: inside `std::sys_common::backtrace::__rust_end_short_backtrace::<{closure@std::panicking::begin_panic_handler::{closure#0}}, !>` at RUSTLIB/std/src/sys_common/backtrace.rs:LL:CC + = note: inside `std::sys::backtrace::__rust_end_short_backtrace::<{closure@std::panicking::begin_panic_handler::{closure#0}}, !>` at RUSTLIB/std/src/sys/backtrace.rs:LL:CC = note: inside `std::panicking::begin_panic_handler` at RUSTLIB/std/src/panicking.rs:LL:CC = note: inside `core::panicking::panic_nounwind` at RUSTLIB/core/src/panicking.rs:LL:CC = note: inside `core::panicking::panic_cannot_unwind` at RUSTLIB/core/src/panicking.rs:LL:CC diff --git a/src/tools/miri/tests/fail/function_calls/exported_symbol_bad_unwind2.definition.stderr b/src/tools/miri/tests/fail/function_calls/exported_symbol_bad_unwind2.definition.stderr index d88781ed22549..112a9687837ec 100644 --- a/src/tools/miri/tests/fail/function_calls/exported_symbol_bad_unwind2.definition.stderr +++ b/src/tools/miri/tests/fail/function_calls/exported_symbol_bad_unwind2.definition.stderr @@ -16,7 +16,7 @@ LL | ABORT(); = note: inside `std::sys::pal::PLATFORM::abort_internal` at RUSTLIB/std/src/sys/pal/PLATFORM/mod.rs:LL:CC = note: inside `std::panicking::rust_panic_with_hook` at RUSTLIB/std/src/panicking.rs:LL:CC = note: inside closure at RUSTLIB/std/src/panicking.rs:LL:CC - = note: inside `std::sys_common::backtrace::__rust_end_short_backtrace::<{closure@std::panicking::begin_panic_handler::{closure#0}}, !>` at RUSTLIB/std/src/sys_common/backtrace.rs:LL:CC + = note: inside `std::sys::backtrace::__rust_end_short_backtrace::<{closure@std::panicking::begin_panic_handler::{closure#0}}, !>` at RUSTLIB/std/src/sys/backtrace.rs:LL:CC = note: inside `std::panicking::begin_panic_handler` at RUSTLIB/std/src/panicking.rs:LL:CC = note: inside `core::panicking::panic_nounwind` at RUSTLIB/core/src/panicking.rs:LL:CC = note: inside `core::panicking::panic_cannot_unwind` at RUSTLIB/core/src/panicking.rs:LL:CC diff --git a/src/tools/miri/tests/fail/intrinsics/uninit_uninhabited_type.stderr b/src/tools/miri/tests/fail/intrinsics/uninit_uninhabited_type.stderr index 447f7cae6ce9d..8dd76edafea20 100644 --- a/src/tools/miri/tests/fail/intrinsics/uninit_uninhabited_type.stderr +++ b/src/tools/miri/tests/fail/intrinsics/uninit_uninhabited_type.stderr @@ -13,7 +13,7 @@ LL | ABORT(); = note: inside `std::sys::pal::PLATFORM::abort_internal` at RUSTLIB/std/src/sys/pal/PLATFORM/mod.rs:LL:CC = note: inside `std::panicking::rust_panic_with_hook` at RUSTLIB/std/src/panicking.rs:LL:CC = note: inside closure at RUSTLIB/std/src/panicking.rs:LL:CC - = note: inside `std::sys_common::backtrace::__rust_end_short_backtrace::<{closure@std::panicking::begin_panic_handler::{closure#0}}, !>` at RUSTLIB/std/src/sys_common/backtrace.rs:LL:CC + = note: inside `std::sys::backtrace::__rust_end_short_backtrace::<{closure@std::panicking::begin_panic_handler::{closure#0}}, !>` at RUSTLIB/std/src/sys/backtrace.rs:LL:CC = note: inside `std::panicking::begin_panic_handler` at RUSTLIB/std/src/panicking.rs:LL:CC = note: inside `core::panicking::panic_nounwind` at RUSTLIB/core/src/panicking.rs:LL:CC note: inside `main` diff --git a/src/tools/miri/tests/fail/intrinsics/zero_fn_ptr.stderr b/src/tools/miri/tests/fail/intrinsics/zero_fn_ptr.stderr index bae34149807fc..55f66a275b6be 100644 --- a/src/tools/miri/tests/fail/intrinsics/zero_fn_ptr.stderr +++ b/src/tools/miri/tests/fail/intrinsics/zero_fn_ptr.stderr @@ -13,7 +13,7 @@ LL | ABORT(); = note: inside `std::sys::pal::PLATFORM::abort_internal` at RUSTLIB/std/src/sys/pal/PLATFORM/mod.rs:LL:CC = note: inside `std::panicking::rust_panic_with_hook` at RUSTLIB/std/src/panicking.rs:LL:CC = note: inside closure at RUSTLIB/std/src/panicking.rs:LL:CC - = note: inside `std::sys_common::backtrace::__rust_end_short_backtrace::<{closure@std::panicking::begin_panic_handler::{closure#0}}, !>` at RUSTLIB/std/src/sys_common/backtrace.rs:LL:CC + = note: inside `std::sys::backtrace::__rust_end_short_backtrace::<{closure@std::panicking::begin_panic_handler::{closure#0}}, !>` at RUSTLIB/std/src/sys/backtrace.rs:LL:CC = note: inside `std::panicking::begin_panic_handler` at RUSTLIB/std/src/panicking.rs:LL:CC = note: inside `core::panicking::panic_nounwind` at RUSTLIB/core/src/panicking.rs:LL:CC note: inside `main` diff --git a/src/tools/miri/tests/fail/panic/double_panic.stderr b/src/tools/miri/tests/fail/panic/double_panic.stderr index 3b7a1511fa0b6..5829c1897bbab 100644 --- a/src/tools/miri/tests/fail/panic/double_panic.stderr +++ b/src/tools/miri/tests/fail/panic/double_panic.stderr @@ -18,7 +18,7 @@ LL | ABORT(); = note: inside `std::sys::pal::PLATFORM::abort_internal` at RUSTLIB/std/src/sys/pal/PLATFORM/mod.rs:LL:CC = note: inside `std::panicking::rust_panic_with_hook` at RUSTLIB/std/src/panicking.rs:LL:CC = note: inside closure at RUSTLIB/std/src/panicking.rs:LL:CC - = note: inside `std::sys_common::backtrace::__rust_end_short_backtrace::<{closure@std::panicking::begin_panic_handler::{closure#0}}, !>` at RUSTLIB/std/src/sys_common/backtrace.rs:LL:CC + = note: inside `std::sys::backtrace::__rust_end_short_backtrace::<{closure@std::panicking::begin_panic_handler::{closure#0}}, !>` at RUSTLIB/std/src/sys/backtrace.rs:LL:CC = note: inside `std::panicking::begin_panic_handler` at RUSTLIB/std/src/panicking.rs:LL:CC = note: inside `core::panicking::panic_nounwind_nobacktrace` at RUSTLIB/core/src/panicking.rs:LL:CC = note: inside `core::panicking::panic_in_cleanup` at RUSTLIB/core/src/panicking.rs:LL:CC diff --git a/src/tools/miri/tests/fail/panic/panic_abort1.stderr b/src/tools/miri/tests/fail/panic/panic_abort1.stderr index 7694cc70b227a..d4abf19cd1e5d 100644 --- a/src/tools/miri/tests/fail/panic/panic_abort1.stderr +++ b/src/tools/miri/tests/fail/panic/panic_abort1.stderr @@ -14,7 +14,7 @@ LL | ABORT(); = note: inside `std::panicking::rust_panic` at RUSTLIB/std/src/panicking.rs:LL:CC = note: inside `std::panicking::rust_panic_with_hook` at RUSTLIB/std/src/panicking.rs:LL:CC = note: inside closure at RUSTLIB/std/src/panicking.rs:LL:CC - = note: inside `std::sys_common::backtrace::__rust_end_short_backtrace::<{closure@std::panicking::begin_panic_handler::{closure#0}}, !>` at RUSTLIB/std/src/sys_common/backtrace.rs:LL:CC + = note: inside `std::sys::backtrace::__rust_end_short_backtrace::<{closure@std::panicking::begin_panic_handler::{closure#0}}, !>` at RUSTLIB/std/src/sys/backtrace.rs:LL:CC = note: inside `std::panicking::begin_panic_handler` at RUSTLIB/std/src/panicking.rs:LL:CC note: inside `main` --> $DIR/panic_abort1.rs:LL:CC diff --git a/src/tools/miri/tests/fail/panic/panic_abort2.stderr b/src/tools/miri/tests/fail/panic/panic_abort2.stderr index e6a4380ea5187..507f17abf4e7e 100644 --- a/src/tools/miri/tests/fail/panic/panic_abort2.stderr +++ b/src/tools/miri/tests/fail/panic/panic_abort2.stderr @@ -14,7 +14,7 @@ LL | ABORT(); = note: inside `std::panicking::rust_panic` at RUSTLIB/std/src/panicking.rs:LL:CC = note: inside `std::panicking::rust_panic_with_hook` at RUSTLIB/std/src/panicking.rs:LL:CC = note: inside closure at RUSTLIB/std/src/panicking.rs:LL:CC - = note: inside `std::sys_common::backtrace::__rust_end_short_backtrace::<{closure@std::panicking::begin_panic_handler::{closure#0}}, !>` at RUSTLIB/std/src/sys_common/backtrace.rs:LL:CC + = note: inside `std::sys::backtrace::__rust_end_short_backtrace::<{closure@std::panicking::begin_panic_handler::{closure#0}}, !>` at RUSTLIB/std/src/sys/backtrace.rs:LL:CC = note: inside `std::panicking::begin_panic_handler` at RUSTLIB/std/src/panicking.rs:LL:CC note: inside `main` --> $DIR/panic_abort2.rs:LL:CC diff --git a/src/tools/miri/tests/fail/panic/panic_abort3.stderr b/src/tools/miri/tests/fail/panic/panic_abort3.stderr index 23e2021eeef85..a5d8b4d2eebd0 100644 --- a/src/tools/miri/tests/fail/panic/panic_abort3.stderr +++ b/src/tools/miri/tests/fail/panic/panic_abort3.stderr @@ -14,7 +14,7 @@ LL | ABORT(); = note: inside `std::panicking::rust_panic` at RUSTLIB/std/src/panicking.rs:LL:CC = note: inside `std::panicking::rust_panic_with_hook` at RUSTLIB/std/src/panicking.rs:LL:CC = note: inside closure at RUSTLIB/std/src/panicking.rs:LL:CC - = note: inside `std::sys_common::backtrace::__rust_end_short_backtrace::<{closure@std::panicking::begin_panic_handler::{closure#0}}, !>` at RUSTLIB/std/src/sys_common/backtrace.rs:LL:CC + = note: inside `std::sys::backtrace::__rust_end_short_backtrace::<{closure@std::panicking::begin_panic_handler::{closure#0}}, !>` at RUSTLIB/std/src/sys/backtrace.rs:LL:CC = note: inside `std::panicking::begin_panic_handler` at RUSTLIB/std/src/panicking.rs:LL:CC note: inside `main` --> $DIR/panic_abort3.rs:LL:CC diff --git a/src/tools/miri/tests/fail/panic/panic_abort4.stderr b/src/tools/miri/tests/fail/panic/panic_abort4.stderr index 20a0ddb901926..62fbbf942cb07 100644 --- a/src/tools/miri/tests/fail/panic/panic_abort4.stderr +++ b/src/tools/miri/tests/fail/panic/panic_abort4.stderr @@ -14,7 +14,7 @@ LL | ABORT(); = note: inside `std::panicking::rust_panic` at RUSTLIB/std/src/panicking.rs:LL:CC = note: inside `std::panicking::rust_panic_with_hook` at RUSTLIB/std/src/panicking.rs:LL:CC = note: inside closure at RUSTLIB/std/src/panicking.rs:LL:CC - = note: inside `std::sys_common::backtrace::__rust_end_short_backtrace::<{closure@std::panicking::begin_panic_handler::{closure#0}}, !>` at RUSTLIB/std/src/sys_common/backtrace.rs:LL:CC + = note: inside `std::sys::backtrace::__rust_end_short_backtrace::<{closure@std::panicking::begin_panic_handler::{closure#0}}, !>` at RUSTLIB/std/src/sys/backtrace.rs:LL:CC = note: inside `std::panicking::begin_panic_handler` at RUSTLIB/std/src/panicking.rs:LL:CC note: inside `main` --> $DIR/panic_abort4.rs:LL:CC diff --git a/src/tools/miri/tests/fail/terminate-terminator.stderr b/src/tools/miri/tests/fail/terminate-terminator.stderr index f737adc561d9c..a5fa0b3e07a6e 100644 --- a/src/tools/miri/tests/fail/terminate-terminator.stderr +++ b/src/tools/miri/tests/fail/terminate-terminator.stderr @@ -18,7 +18,7 @@ LL | ABORT(); = note: inside `std::sys::pal::PLATFORM::abort_internal` at RUSTLIB/std/src/sys/pal/PLATFORM/mod.rs:LL:CC = note: inside `std::panicking::rust_panic_with_hook` at RUSTLIB/std/src/panicking.rs:LL:CC = note: inside closure at RUSTLIB/std/src/panicking.rs:LL:CC - = note: inside `std::sys_common::backtrace::__rust_end_short_backtrace::<{closure@std::panicking::begin_panic_handler::{closure#0}}, !>` at RUSTLIB/std/src/sys_common/backtrace.rs:LL:CC + = note: inside `std::sys::backtrace::__rust_end_short_backtrace::<{closure@std::panicking::begin_panic_handler::{closure#0}}, !>` at RUSTLIB/std/src/sys/backtrace.rs:LL:CC = note: inside `std::panicking::begin_panic_handler` at RUSTLIB/std/src/panicking.rs:LL:CC = note: inside `core::panicking::panic_nounwind` at RUSTLIB/core/src/panicking.rs:LL:CC = note: inside `core::panicking::panic_cannot_unwind` at RUSTLIB/core/src/panicking.rs:LL:CC diff --git a/src/tools/miri/tests/fail/unwind-action-terminate.stderr b/src/tools/miri/tests/fail/unwind-action-terminate.stderr index 7e722f7be3288..547d550d3d0d8 100644 --- a/src/tools/miri/tests/fail/unwind-action-terminate.stderr +++ b/src/tools/miri/tests/fail/unwind-action-terminate.stderr @@ -16,7 +16,7 @@ LL | ABORT(); = note: inside `std::sys::pal::PLATFORM::abort_internal` at RUSTLIB/std/src/sys/pal/PLATFORM/mod.rs:LL:CC = note: inside `std::panicking::rust_panic_with_hook` at RUSTLIB/std/src/panicking.rs:LL:CC = note: inside closure at RUSTLIB/std/src/panicking.rs:LL:CC - = note: inside `std::sys_common::backtrace::__rust_end_short_backtrace::<{closure@std::panicking::begin_panic_handler::{closure#0}}, !>` at RUSTLIB/std/src/sys_common/backtrace.rs:LL:CC + = note: inside `std::sys::backtrace::__rust_end_short_backtrace::<{closure@std::panicking::begin_panic_handler::{closure#0}}, !>` at RUSTLIB/std/src/sys/backtrace.rs:LL:CC = note: inside `std::panicking::begin_panic_handler` at RUSTLIB/std/src/panicking.rs:LL:CC = note: inside `core::panicking::panic_nounwind` at RUSTLIB/core/src/panicking.rs:LL:CC = note: inside `core::panicking::panic_cannot_unwind` at RUSTLIB/core/src/panicking.rs:LL:CC diff --git a/src/tools/miri/tests/pass/backtrace/backtrace-api-v0.stderr b/src/tools/miri/tests/pass/backtrace/backtrace-api-v0.stderr index bc24d6de734db..c05950ebdc746 100644 --- a/src/tools/miri/tests/pass/backtrace/backtrace-api-v0.stderr +++ b/src/tools/miri/tests/pass/backtrace/backtrace-api-v0.stderr @@ -4,7 +4,7 @@ $DIR/backtrace-api-v0.rs:LL:CC (func_b) $DIR/backtrace-api-v0.rs:LL:CC (func_a) $DIR/backtrace-api-v0.rs:LL:CC (main) RUSTLIB/core/src/ops/function.rs:LL:CC (>::call_once - shim(fn())) -RUSTLIB/std/src/sys_common/backtrace.rs:LL:CC (std::sys_common::backtrace::__rust_begin_short_backtrace) +RUSTLIB/std/src/sys/backtrace.rs:LL:CC (std::sys::backtrace::__rust_begin_short_backtrace) RUSTLIB/std/src/rt.rs:LL:CC (std::rt::lang_start::{closure#0}) RUSTLIB/core/src/ops/function.rs:LL:CC (std::ops::function::impls::call_once) RUSTLIB/std/src/panicking.rs:LL:CC (std::panicking::r#try::do_call) diff --git a/src/tools/miri/tests/pass/backtrace/backtrace-api-v1.stderr b/src/tools/miri/tests/pass/backtrace/backtrace-api-v1.stderr index 246e54becd820..b56d983d42984 100644 --- a/src/tools/miri/tests/pass/backtrace/backtrace-api-v1.stderr +++ b/src/tools/miri/tests/pass/backtrace/backtrace-api-v1.stderr @@ -4,7 +4,7 @@ $DIR/backtrace-api-v1.rs:LL:CC (func_b) $DIR/backtrace-api-v1.rs:LL:CC (func_a) $DIR/backtrace-api-v1.rs:LL:CC (main) RUSTLIB/core/src/ops/function.rs:LL:CC (>::call_once - shim(fn())) -RUSTLIB/std/src/sys_common/backtrace.rs:LL:CC (std::sys_common::backtrace::__rust_begin_short_backtrace) +RUSTLIB/std/src/sys/backtrace.rs:LL:CC (std::sys::backtrace::__rust_begin_short_backtrace) RUSTLIB/std/src/rt.rs:LL:CC (std::rt::lang_start::{closure#0}) RUSTLIB/core/src/ops/function.rs:LL:CC (std::ops::function::impls::call_once) RUSTLIB/std/src/panicking.rs:LL:CC (std::panicking::r#try::do_call) diff --git a/src/tools/miri/tests/pass/backtrace/backtrace-global-alloc.stderr b/src/tools/miri/tests/pass/backtrace/backtrace-global-alloc.stderr index c48061d64d088..b06dd1da3c645 100644 --- a/src/tools/miri/tests/pass/backtrace/backtrace-global-alloc.stderr +++ b/src/tools/miri/tests/pass/backtrace/backtrace-global-alloc.stderr @@ -2,8 +2,8 @@ at $DIR/backtrace-global-alloc.rs:LL:CC 1: >::call_once - shim(fn()) at RUSTLIB/core/src/ops/function.rs:LL:CC - 2: std::sys_common::backtrace::__rust_begin_short_backtrace - at RUSTLIB/std/src/sys_common/backtrace.rs:LL:CC + 2: std::sys::backtrace::__rust_begin_short_backtrace + at RUSTLIB/std/src/sys/backtrace.rs:LL:CC 3: std::rt::lang_start::{closure#0} at RUSTLIB/std/src/rt.rs:LL:CC 4: std::ops::function::impls::call_once diff --git a/src/tools/miri/tests/pass/backtrace/backtrace-std.stderr b/src/tools/miri/tests/pass/backtrace/backtrace-std.stderr index 4596cadb958d8..84bdda59fce9a 100644 --- a/src/tools/miri/tests/pass/backtrace/backtrace-std.stderr +++ b/src/tools/miri/tests/pass/backtrace/backtrace-std.stderr @@ -10,8 +10,8 @@ at $DIR/backtrace-std.rs:LL:CC 5: >::call_once - shim(fn()) at RUSTLIB/core/src/ops/function.rs:LL:CC - 6: std::sys_common::backtrace::__rust_begin_short_backtrace - at RUSTLIB/std/src/sys_common/backtrace.rs:LL:CC + 6: std::sys::backtrace::__rust_begin_short_backtrace + at RUSTLIB/std/src/sys/backtrace.rs:LL:CC 7: std::rt::lang_start::{closure#0} at RUSTLIB/std/src/rt.rs:LL:CC 8: std::ops::function::impls::call_once diff --git a/src/tools/miri/tests/pass/float.rs b/src/tools/miri/tests/pass/float.rs index 8aea9b3e6f9f1..5464627fa1446 100644 --- a/src/tools/miri/tests/pass/float.rs +++ b/src/tools/miri/tests/pass/float.rs @@ -1,6 +1,8 @@ #![feature(stmt_expr_attributes)] #![feature(float_gamma)] #![feature(core_intrinsics)] +#![feature(f128)] +#![feature(f16)] #![allow(arithmetic_overflow)] use std::fmt::Debug; @@ -41,103 +43,23 @@ trait FloatToInt: Copy { unsafe fn cast_unchecked(self) -> Int; } -impl FloatToInt for f32 { - fn cast(self) -> i8 { - self as _ - } - unsafe fn cast_unchecked(self) -> i8 { - self.to_int_unchecked() - } -} -impl FloatToInt for f32 { - fn cast(self) -> i32 { - self as _ - } - unsafe fn cast_unchecked(self) -> i32 { - self.to_int_unchecked() - } -} -impl FloatToInt for f32 { - fn cast(self) -> u32 { - self as _ - } - unsafe fn cast_unchecked(self) -> u32 { - self.to_int_unchecked() - } -} -impl FloatToInt for f32 { - fn cast(self) -> i64 { - self as _ - } - unsafe fn cast_unchecked(self) -> i64 { - self.to_int_unchecked() - } -} -impl FloatToInt for f32 { - fn cast(self) -> u64 { - self as _ - } - unsafe fn cast_unchecked(self) -> u64 { - self.to_int_unchecked() - } +macro_rules! float_to_int { + ($fty:ty => $($ity:ty),+ $(,)?) => { + $( + impl FloatToInt<$ity> for $fty { + fn cast(self) -> $ity { + self as _ + } + unsafe fn cast_unchecked(self) -> $ity { + self.to_int_unchecked() + } + } + )* + }; } -impl FloatToInt for f64 { - fn cast(self) -> i8 { - self as _ - } - unsafe fn cast_unchecked(self) -> i8 { - self.to_int_unchecked() - } -} -impl FloatToInt for f64 { - fn cast(self) -> i32 { - self as _ - } - unsafe fn cast_unchecked(self) -> i32 { - self.to_int_unchecked() - } -} -impl FloatToInt for f64 { - fn cast(self) -> u32 { - self as _ - } - unsafe fn cast_unchecked(self) -> u32 { - self.to_int_unchecked() - } -} -impl FloatToInt for f64 { - fn cast(self) -> i64 { - self as _ - } - unsafe fn cast_unchecked(self) -> i64 { - self.to_int_unchecked() - } -} -impl FloatToInt for f64 { - fn cast(self) -> u64 { - self as _ - } - unsafe fn cast_unchecked(self) -> u64 { - self.to_int_unchecked() - } -} -impl FloatToInt for f64 { - fn cast(self) -> i128 { - self as _ - } - unsafe fn cast_unchecked(self) -> i128 { - self.to_int_unchecked() - } -} -impl FloatToInt for f64 { - fn cast(self) -> u128 { - self as _ - } - unsafe fn cast_unchecked(self) -> u128 { - self.to_int_unchecked() - } -} +float_to_int!(f32 => i8, u8, i16, u16, i32, u32, i64, u64, i128, u128); +float_to_int!(f64 => i8, u8, i16, u16, i32, u32, i64, u64, i128, u128); /// Test this cast both via `as` and via `approx_unchecked` (i.e., it must not saturate). #[track_caller] @@ -153,18 +75,29 @@ where fn basic() { // basic arithmetic + assert_eq(6.0_f16 * 6.0_f16, 36.0_f16); assert_eq(6.0_f32 * 6.0_f32, 36.0_f32); assert_eq(6.0_f64 * 6.0_f64, 36.0_f64); + assert_eq(6.0_f128 * 6.0_f128, 36.0_f128); + assert_eq(-{ 5.0_f16 }, -5.0_f16); assert_eq(-{ 5.0_f32 }, -5.0_f32); assert_eq(-{ 5.0_f64 }, -5.0_f64); + assert_eq(-{ 5.0_f128 }, -5.0_f128); + // infinities, NaN + // FIXME(f16_f128): add when constants and `is_infinite` are available assert!((5.0_f32 / 0.0).is_infinite()); assert_ne!({ 5.0_f32 / 0.0 }, { -5.0_f32 / 0.0 }); assert!((5.0_f64 / 0.0).is_infinite()); assert_ne!({ 5.0_f64 / 0.0 }, { 5.0_f64 / -0.0 }); assert_ne!(f32::NAN, f32::NAN); assert_ne!(f64::NAN, f64::NAN); + // negative zero + let posz = 0.0f16; + let negz = -0.0f16; + assert_eq(posz, negz); + assert_ne!(posz.to_bits(), negz.to_bits()); let posz = 0.0f32; let negz = -0.0f32; assert_eq(posz, negz); @@ -173,15 +106,30 @@ fn basic() { let negz = -0.0f64; assert_eq(posz, negz); assert_ne!(posz.to_bits(), negz.to_bits()); + let posz = 0.0f128; + let negz = -0.0f128; + assert_eq(posz, negz); + assert_ne!(posz.to_bits(), negz.to_bits()); + // byte-level transmute - let x: u64 = unsafe { std::mem::transmute(42.0_f64) }; - let y: f64 = unsafe { std::mem::transmute(x) }; - assert_eq(y, 42.0_f64); + let x: u16 = unsafe { std::mem::transmute(42.0_f16) }; + let y: f16 = unsafe { std::mem::transmute(x) }; + assert_eq(y, 42.0_f16); let x: u32 = unsafe { std::mem::transmute(42.0_f32) }; let y: f32 = unsafe { std::mem::transmute(x) }; assert_eq(y, 42.0_f32); + let x: u64 = unsafe { std::mem::transmute(42.0_f64) }; + let y: f64 = unsafe { std::mem::transmute(x) }; + assert_eq(y, 42.0_f64); + let x: u128 = unsafe { std::mem::transmute(42.0_f128) }; + let y: f128 = unsafe { std::mem::transmute(x) }; + assert_eq(y, 42.0_f128); // `%` sign behavior, some of this used to be buggy + assert!((black_box(1.0f16) % 1.0).is_sign_positive()); + assert!((black_box(1.0f16) % -1.0).is_sign_positive()); + assert!((black_box(-1.0f16) % 1.0).is_sign_negative()); + assert!((black_box(-1.0f16) % -1.0).is_sign_negative()); assert!((black_box(1.0f32) % 1.0).is_sign_positive()); assert!((black_box(1.0f32) % -1.0).is_sign_positive()); assert!((black_box(-1.0f32) % 1.0).is_sign_negative()); @@ -190,7 +138,12 @@ fn basic() { assert!((black_box(1.0f64) % -1.0).is_sign_positive()); assert!((black_box(-1.0f64) % 1.0).is_sign_negative()); assert!((black_box(-1.0f64) % -1.0).is_sign_negative()); + assert!((black_box(1.0f128) % 1.0).is_sign_positive()); + assert!((black_box(1.0f128) % -1.0).is_sign_positive()); + assert!((black_box(-1.0f128) % 1.0).is_sign_negative()); + assert!((black_box(-1.0f128) % -1.0).is_sign_negative()); + // FIXME(f16_f128): add when `abs` is available assert_eq!((-1.0f32).abs(), 1.0f32); assert_eq!(34.2f64.abs(), 34.2f64); } diff --git a/src/tools/opt-dist/src/training.rs b/src/tools/opt-dist/src/training.rs index 89f4d8957c8bf..1237951b3f042 100644 --- a/src/tools/opt-dist/src/training.rs +++ b/src/tools/opt-dist/src/training.rs @@ -216,11 +216,9 @@ pub fn gather_bolt_profiles( log::info!("Profile file count: {}", profiles.len()); // Delete the gathered profiles - for profile in glob::glob(&format!("{profile_prefix}*"))?.into_iter() { - if let Ok(profile) = profile { - if let Err(error) = std::fs::remove_file(&profile) { - log::error!("Cannot delete BOLT profile {}: {error:?}", profile.display()); - } + for profile in glob::glob(&format!("{profile_prefix}*"))?.flatten() { + if let Err(error) = std::fs::remove_file(&profile) { + log::error!("Cannot delete BOLT profile {}: {error:?}", profile.display()); } } diff --git a/src/tools/remote-test-client/src/main.rs b/src/tools/remote-test-client/src/main.rs index 590c735596ed9..dd2c09c430b61 100644 --- a/src/tools/remote-test-client/src/main.rs +++ b/src/tools/remote-test-client/src/main.rs @@ -317,13 +317,11 @@ fn run(support_lib_count: usize, exe: String, all_args: Vec) { t!(io::copy(&mut (&mut client).take(amt), &mut stdout)); t!(stdout.flush()); } + } else if amt == 0 { + stderr_done = true; } else { - if amt == 0 { - stderr_done = true; - } else { - t!(io::copy(&mut (&mut client).take(amt), &mut stderr)); - t!(stderr.flush()); - } + t!(io::copy(&mut (&mut client).take(amt), &mut stderr)); + t!(stderr.flush()); } } diff --git a/src/tools/remote-test-server/src/main.rs b/src/tools/remote-test-server/src/main.rs index 68d7aa56c438b..79f96c5022382 100644 --- a/src/tools/remote-test-server/src/main.rs +++ b/src/tools/remote-test-server/src/main.rs @@ -282,7 +282,7 @@ fn handle_run(socket: TcpStream, work: &Path, tmp: &Path, lock: &Mutex<()>, conf cmd.env(library_path, env::join_paths(paths).unwrap()); // Some tests assume RUST_TEST_TMPDIR exists - cmd.env("RUST_TEST_TMPDIR", tmp.to_owned()); + cmd.env("RUST_TEST_TMPDIR", tmp); let socket = Arc::new(Mutex::new(reader.into_inner())); diff --git a/src/tools/run-make-support/CHANGELOG.md b/src/tools/run-make-support/CHANGELOG.md index a37de9fda80d9..c1b7b618a9217 100644 --- a/src/tools/run-make-support/CHANGELOG.md +++ b/src/tools/run-make-support/CHANGELOG.md @@ -10,6 +10,22 @@ changes to the support library). This support library will probably never reach 1.0. Please bump the minor version in `Cargo.toml` if you make any breaking changes or other significant changes, or bump the patch version for bug fixes. +## [0.2.0] - 2024-06-11 + +### Added + +- Added `fs_wrapper` module which provides panic-on-fail helpers for their respective `std::fs` + counterparts, the motivation is to: + - Reduce littering `.unwrap()` or `.expect()` everywhere for fs operations + - Help the test writer avoid forgetting to check fs results (even though enforced by + `-Dunused_must_use`) + - Provide better panic messages by default +- Added `path()` helper which creates a `Path` relative to `cwd()` (but is less noisy). + +### Changed + +- Marked many functions with `#[must_use]`, and rmake.rs are now compiled with `-Dunused_must_use`. + ## [0.1.0] - 2024-06-09 ### Changed diff --git a/src/tools/run-make-support/Cargo.toml b/src/tools/run-make-support/Cargo.toml index 5450620e7f002..2f7f51442f164 100644 --- a/src/tools/run-make-support/Cargo.toml +++ b/src/tools/run-make-support/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "run_make_support" -version = "0.1.0" +version = "0.2.0" edition = "2021" [dependencies] diff --git a/src/tools/run-make-support/src/cc.rs b/src/tools/run-make-support/src/cc.rs index 8694740cfc306..31b9e8a23b88b 100644 --- a/src/tools/run-make-support/src/cc.rs +++ b/src/tools/run-make-support/src/cc.rs @@ -15,6 +15,7 @@ pub fn cc() -> Cc { /// A platform-specific C compiler invocation builder. The specific C compiler used is /// passed down from compiletest. #[derive(Debug)] +#[must_use] pub struct Cc { cmd: Command, } diff --git a/src/tools/run-make-support/src/clang.rs b/src/tools/run-make-support/src/clang.rs index a31004659c175..c23e41ebe2191 100644 --- a/src/tools/run-make-support/src/clang.rs +++ b/src/tools/run-make-support/src/clang.rs @@ -11,6 +11,7 @@ pub fn clang() -> Clang { /// A `clang` invocation builder. #[derive(Debug)] +#[must_use] pub struct Clang { cmd: Command, } diff --git a/src/tools/run-make-support/src/command.rs b/src/tools/run-make-support/src/command.rs index d689dc2f979a7..dab18dca2ff99 100644 --- a/src/tools/run-make-support/src/command.rs +++ b/src/tools/run-make-support/src/command.rs @@ -6,7 +6,7 @@ use std::path::Path; use std::process::{Command as StdCommand, ExitStatus, Output, Stdio}; use crate::drop_bomb::DropBomb; -use crate::{assert_not_contains, handle_failed_output}; +use crate::{assert_contains, assert_not_contains, handle_failed_output}; /// This is a custom command wrapper that simplifies working with commands and makes it easier to /// ensure that we check the exit status of executed processes. @@ -148,14 +148,17 @@ pub struct CompletedProcess { } impl CompletedProcess { + #[must_use] pub fn stdout_utf8(&self) -> String { String::from_utf8(self.output.stdout.clone()).expect("stdout is not valid UTF-8") } + #[must_use] pub fn stderr_utf8(&self) -> String { String::from_utf8(self.output.stderr.clone()).expect("stderr is not valid UTF-8") } + #[must_use] pub fn status(&self) -> ExitStatus { self.output.status } @@ -167,6 +170,12 @@ impl CompletedProcess { self } + #[track_caller] + pub fn assert_stdout_contains>(self, needle: S) -> Self { + assert_contains(&self.stdout_utf8(), needle.as_ref()); + self + } + #[track_caller] pub fn assert_stdout_not_contains>(&self, needle: S) -> &Self { assert_not_contains(&self.stdout_utf8(), needle.as_ref()); @@ -182,7 +191,7 @@ impl CompletedProcess { #[track_caller] pub fn assert_stderr_contains>(&self, needle: S) -> &Self { - assert!(self.stderr_utf8().contains(needle.as_ref())); + assert_contains(&self.stderr_utf8(), needle.as_ref()); self } diff --git a/src/tools/run-make-support/src/diff/mod.rs b/src/tools/run-make-support/src/diff/mod.rs index 0fb6fec9d58cd..3e0bdc1c6f64c 100644 --- a/src/tools/run-make-support/src/diff/mod.rs +++ b/src/tools/run-make-support/src/diff/mod.rs @@ -1,8 +1,9 @@ use regex::Regex; use similar::TextDiff; -use std::path::Path; +use std::path::{Path, PathBuf}; use crate::drop_bomb::DropBomb; +use crate::fs_wrapper; #[cfg(test)] mod tests; @@ -13,9 +14,11 @@ pub fn diff() -> Diff { } #[derive(Debug)] +#[must_use] pub struct Diff { expected: Option, expected_name: Option, + expected_file: Option, actual: Option, actual_name: Option, normalizers: Vec<(String, String)>, @@ -29,6 +32,7 @@ impl Diff { Self { expected: None, expected_name: None, + expected_file: None, actual: None, actual_name: None, normalizers: Vec::new(), @@ -39,9 +43,10 @@ impl Diff { /// Specify the expected output for the diff from a file. pub fn expected_file>(&mut self, path: P) -> &mut Self { let path = path.as_ref(); - let content = std::fs::read_to_string(path).expect("failed to read file"); + let content = fs_wrapper::read_to_string(path); let name = path.to_string_lossy().to_string(); + self.expected_file = Some(path.into()); self.expected = Some(content); self.expected_name = Some(name); self @@ -57,10 +62,7 @@ impl Diff { /// Specify the actual output for the diff from a file. pub fn actual_file>(&mut self, path: P) -> &mut Self { let path = path.as_ref(); - let content = match std::fs::read_to_string(path) { - Ok(c) => c, - Err(e) => panic!("failed to read `{}`: {:?}", path.display(), e), - }; + let content = fs_wrapper::read_to_string(path); let name = path.to_string_lossy().to_string(); self.actual = Some(content); @@ -103,6 +105,15 @@ impl Diff { .to_string(); if !output.is_empty() { + // If we can bless (meaning we have a file to write into and the `RUSTC_BLESS_TEST` + // environment variable set), then we write into the file and return. + if let Some(ref expected_file) = self.expected_file { + if std::env::var("RUSTC_BLESS_TEST").is_ok() { + println!("Blessing `{}`", expected_file.display()); + fs_wrapper::write(expected_file, actual); + return; + } + } panic!( "test failed: `{}` is different from `{}`\n\n{}", expected_name, actual_name, output diff --git a/src/tools/run-make-support/src/lib.rs b/src/tools/run-make-support/src/lib.rs index b7a936a1e115d..ba4524c150c46 100644 --- a/src/tools/run-make-support/src/lib.rs +++ b/src/tools/run-make-support/src/lib.rs @@ -37,6 +37,7 @@ pub use rustc::{aux_build, rustc, Rustc}; pub use rustdoc::{bare_rustdoc, rustdoc, Rustdoc}; #[track_caller] +#[must_use] pub fn env_var(name: &str) -> String { match env::var(name) { Ok(v) => v, @@ -45,6 +46,7 @@ pub fn env_var(name: &str) -> String { } #[track_caller] +#[must_use] pub fn env_var_os(name: &str) -> OsString { match env::var_os(name) { Some(v) => v, @@ -53,32 +55,38 @@ pub fn env_var_os(name: &str) -> OsString { } /// `TARGET` +#[must_use] pub fn target() -> String { env_var("TARGET") } /// Check if target is windows-like. +#[must_use] pub fn is_windows() -> bool { target().contains("windows") } /// Check if target uses msvc. +#[must_use] pub fn is_msvc() -> bool { target().contains("msvc") } /// Check if target uses macOS. +#[must_use] pub fn is_darwin() -> bool { target().contains("darwin") } #[track_caller] +#[must_use] pub fn python_command() -> Command { let python_path = env_var("PYTHON"); Command::new(python_path) } #[track_caller] +#[must_use] pub fn htmldocck() -> Command { let mut python = python_command(); python.arg(source_root().join("src/etc/htmldocck.py")); @@ -91,11 +99,41 @@ pub fn path>(p: P) -> PathBuf { } /// Path to the root rust-lang/rust source checkout. +#[must_use] pub fn source_root() -> PathBuf { env_var("SOURCE_ROOT").into() } +/// Creates a new symlink to a path on the filesystem, adjusting for Windows or Unix. +#[cfg(target_family = "windows")] +pub fn create_symlink, Q: AsRef>(original: P, link: Q) { + if link.as_ref().exists() { + std::fs::remove_dir(link.as_ref()).unwrap(); + } + use std::os::windows::fs; + fs::symlink_file(original.as_ref(), link.as_ref()).expect(&format!( + "failed to create symlink {:?} for {:?}", + link.as_ref().display(), + original.as_ref().display(), + )); +} + +/// Creates a new symlink to a path on the filesystem, adjusting for Windows or Unix. +#[cfg(target_family = "unix")] +pub fn create_symlink, Q: AsRef>(original: P, link: Q) { + if link.as_ref().exists() { + std::fs::remove_dir(link.as_ref()).unwrap(); + } + use std::os::unix::fs; + fs::symlink(original.as_ref(), link.as_ref()).expect(&format!( + "failed to create symlink {:?} for {:?}", + link.as_ref().display(), + original.as_ref().display(), + )); +} + /// Construct the static library name based on the platform. +#[must_use] pub fn static_lib_name(name: &str) -> String { // See tools.mk (irrelevant lines omitted): // @@ -120,6 +158,7 @@ pub fn static_lib_name(name: &str) -> String { } /// Construct the dynamic library name based on the platform. +#[must_use] pub fn dynamic_lib_name(name: &str) -> String { // See tools.mk (irrelevant lines omitted): // @@ -146,6 +185,7 @@ pub fn dynamic_lib_name(name: &str) -> String { } } +#[must_use] pub fn dynamic_lib_extension() -> &'static str { if is_darwin() { "dylib" @@ -157,16 +197,19 @@ pub fn dynamic_lib_extension() -> &'static str { } /// Generate the name a rust library (rlib) would have. +#[must_use] pub fn rust_lib_name(name: &str) -> String { format!("lib{name}.rlib") } /// Construct the binary name based on platform. +#[must_use] pub fn bin_name(name: &str) -> String { if is_windows() { format!("{name}.exe") } else { name.to_string() } } /// Return the current working directory. +#[must_use] pub fn cwd() -> PathBuf { env::current_dir().unwrap() } @@ -174,6 +217,7 @@ pub fn cwd() -> PathBuf { /// Use `cygpath -w` on a path to get a Windows path string back. This assumes that `cygpath` is /// available on the platform! #[track_caller] +#[must_use] pub fn cygpath_windows>(path: P) -> String { let caller = panic::Location::caller(); let mut cygpath = Command::new("cygpath"); @@ -189,6 +233,7 @@ pub fn cygpath_windows>(path: P) -> String { /// Run `uname`. This assumes that `uname` is available on the platform! #[track_caller] +#[must_use] pub fn uname() -> String { let caller = panic::Location::caller(); let mut uname = Command::new("uname"); @@ -287,6 +332,18 @@ pub fn read_dir(dir: impl AsRef, callback: F) { } } +/// Check that `haystack` contains `needle`. Panic otherwise. +#[track_caller] +pub fn assert_contains(haystack: &str, needle: &str) { + if !haystack.contains(needle) { + eprintln!("=== HAYSTACK ==="); + eprintln!("{}", haystack); + eprintln!("=== NEEDLE ==="); + eprintln!("{}", needle); + panic!("needle was not found in haystack"); + } +} + /// Check that `haystack` does not contain `needle`. Panic otherwise. #[track_caller] pub fn assert_not_contains(haystack: &str, needle: &str) { diff --git a/src/tools/run-make-support/src/llvm.rs b/src/tools/run-make-support/src/llvm.rs index 414251abda294..664093e072d72 100644 --- a/src/tools/run-make-support/src/llvm.rs +++ b/src/tools/run-make-support/src/llvm.rs @@ -4,18 +4,21 @@ use crate::{env_var, Command}; /// Construct a new `llvm-readobj` invocation. This assumes that `llvm-readobj` is available /// at `$LLVM_BIN_DIR/llvm-readobj`. +#[track_caller] pub fn llvm_readobj() -> LlvmReadobj { LlvmReadobj::new() } /// Construct a new `llvm-profdata` invocation. This assumes that `llvm-profdata` is available /// at `$LLVM_BIN_DIR/llvm-profdata`. +#[track_caller] pub fn llvm_profdata() -> LlvmProfdata { LlvmProfdata::new() } /// Construct a new `llvm-filecheck` invocation. This assumes that `llvm-filecheck` is available /// at `$LLVM_FILECHECK`. +#[track_caller] pub fn llvm_filecheck() -> LlvmFilecheck { LlvmFilecheck::new() } @@ -55,6 +58,7 @@ pub fn llvm_bin_dir() -> PathBuf { impl LlvmReadobj { /// Construct a new `llvm-readobj` invocation. This assumes that `llvm-readobj` is available /// at `$LLVM_BIN_DIR/llvm-readobj`. + #[track_caller] pub fn new() -> Self { let llvm_readobj = llvm_bin_dir().join("llvm-readobj"); let cmd = Command::new(llvm_readobj); @@ -77,6 +81,7 @@ impl LlvmReadobj { impl LlvmProfdata { /// Construct a new `llvm-profdata` invocation. This assumes that `llvm-profdata` is available /// at `$LLVM_BIN_DIR/llvm-profdata`. + #[track_caller] pub fn new() -> Self { let llvm_profdata = llvm_bin_dir().join("llvm-profdata"); let cmd = Command::new(llvm_profdata); @@ -107,6 +112,7 @@ impl LlvmProfdata { impl LlvmFilecheck { /// Construct a new `llvm-filecheck` invocation. This assumes that `llvm-filecheck` is available /// at `$LLVM_FILECHECK`. + #[track_caller] pub fn new() -> Self { let llvm_filecheck = env_var("LLVM_FILECHECK"); let cmd = Command::new(llvm_filecheck); diff --git a/src/tools/run-make-support/src/llvm_readobj.rs b/src/tools/run-make-support/src/llvm_readobj.rs deleted file mode 100644 index 57ddfc205e66a..0000000000000 --- a/src/tools/run-make-support/src/llvm_readobj.rs +++ /dev/null @@ -1,44 +0,0 @@ -use std::path::{Path, PathBuf}; - -use crate::command::Command; -use crate::env_var; - -/// Construct a new `llvm-readobj` invocation. This assumes that `llvm-readobj` is available -/// at `$LLVM_BIN_DIR/llvm-readobj`. -#[track_caller] -pub fn llvm_readobj() -> LlvmReadobj { - LlvmReadobj::new() -} - -/// A `llvm-readobj` invocation builder. -#[derive(Debug)] -pub struct LlvmReadobj { - cmd: Command, -} - -crate::impl_common_helpers!(LlvmReadobj); - -impl LlvmReadobj { - /// Construct a new `llvm-readobj` invocation. This assumes that `llvm-readobj` is available - /// at `$LLVM_BIN_DIR/llvm-readobj`. - #[track_caller] - pub fn new() -> Self { - let llvm_bin_dir = env_var("LLVM_BIN_DIR"); - let llvm_bin_dir = PathBuf::from(llvm_bin_dir); - let llvm_readobj = llvm_bin_dir.join("llvm-readobj"); - let cmd = Command::new(llvm_readobj); - Self { cmd } - } - - /// Provide an input file. - pub fn input>(&mut self, path: P) -> &mut Self { - self.cmd.arg(path.as_ref()); - self - } - - /// Pass `--file-header` to display file headers. - pub fn file_header(&mut self) -> &mut Self { - self.cmd.arg("--file-header"); - self - } -} diff --git a/src/tools/run-make-support/src/rustc.rs b/src/tools/run-make-support/src/rustc.rs index c27af966f39b5..331e1a5ab8b32 100644 --- a/src/tools/run-make-support/src/rustc.rs +++ b/src/tools/run-make-support/src/rustc.rs @@ -18,6 +18,7 @@ pub fn aux_build() -> Rustc { /// A `rustc` invocation builder. #[derive(Debug)] +#[must_use] pub struct Rustc { cmd: Command, } diff --git a/src/tools/run-make-support/src/rustdoc.rs b/src/tools/run-make-support/src/rustdoc.rs index 332906f739a9d..930785612545b 100644 --- a/src/tools/run-make-support/src/rustdoc.rs +++ b/src/tools/run-make-support/src/rustdoc.rs @@ -17,6 +17,7 @@ pub fn rustdoc() -> Rustdoc { } #[derive(Debug)] +#[must_use] pub struct Rustdoc { cmd: Command, } diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/display.rs b/src/tools/rust-analyzer/crates/hir-ty/src/display.rs index 5a9621bb69a47..241690d00896d 100644 --- a/src/tools/rust-analyzer/crates/hir-ty/src/display.rs +++ b/src/tools/rust-analyzer/crates/hir-ty/src/display.rs @@ -1387,6 +1387,7 @@ fn generic_args_sans_defaults<'ga>( } // otherwise, if the arg is equal to the param default, hide it (unless the // default is an error which can happen for the trait Self type) + #[allow(unstable_name_collisions)] default_parameters.get(i).is_none_or(|default_parameter| { // !is_err(default_parameter.skip_binders()) // && diff --git a/src/tools/tidy/config/requirements.in b/src/tools/tidy/config/requirements.in index 882e09dae4594..047617c65598f 100644 --- a/src/tools/tidy/config/requirements.in +++ b/src/tools/tidy/config/requirements.in @@ -1,10 +1,10 @@ # requirements.in This is the source file for our pinned version requirements # file "requirements.txt" To regenerate that file, pip-tools is required -# (`python -m pip install pip-tools`). Once installed, run: `pip-compile -# --generate-hashes src/tools/tidy/config/requirements.in` +# (`python -m pip install pip-tools==7.4.1`). Once installed, run: `pip-compile +# --generate-hashes --strip-extras src/tools/tidy/config/requirements.in` # # Note: this generation step should be run with the oldest supported python -# version (currently 3.7) to ensure backward compatibility +# version (currently 3.9) to ensure backward compatibility black==23.3.0 ruff==0.0.272 diff --git a/src/tools/tidy/config/requirements.txt b/src/tools/tidy/config/requirements.txt index 9fd617ad62192..a53c98cac7a06 100644 --- a/src/tools/tidy/config/requirements.txt +++ b/src/tools/tidy/config/requirements.txt @@ -1,8 +1,8 @@ # -# This file is autogenerated by pip-compile with Python 3.11 +# This file is autogenerated by pip-compile with Python 3.9 # by the following command: # -# pip-compile --generate-hashes src/tools/tidy/config/requirements.in +# pip-compile --generate-hashes --strip-extras src/tools/tidy/config/requirements.in # black==23.3.0 \ --hash=sha256:064101748afa12ad2291c2b91c960be28b817c0c7eaa35bec09cc63aa56493c5 \ @@ -35,10 +35,6 @@ click==8.1.3 \ --hash=sha256:7682dc8afb30297001674575ea00d1814d808d6a36af415a82bd481d37ba7b8e \ --hash=sha256:bb4d8133cb15a609f44e8213d9b391b0809795062913b383c62be0ee95b1db48 # via black -importlib-metadata==6.7.0 \ - --hash=sha256:1aaf550d4f73e5d6783e7acb77aec43d49da8017410afae93822cc9cca98c4d4 \ - --hash=sha256:cb52082e659e97afc5dac71e79de97d8681de3aa07ff18578330904a9d18e5b5 - # via click mypy-extensions==1.0.0 \ --hash=sha256:4392f6c0eb8a5668a69e23d168ffa70f0be9ccfd32b5cc2d26a34ae5b844552d \ --hash=sha256:75dbf8955dc00442a438fc4d0666508a9a97b6bd41aa2f0ffe9d2f2725af0782 @@ -78,40 +74,7 @@ tomli==2.0.1 \ --hash=sha256:939de3e7a6161af0c887ef91b7d41a53e7c5a1ca976325f429cb46ea9bc30ecc \ --hash=sha256:de526c12914f0c550d15924c62d72abc48d6fe7364aa87328337a31007fe8a4f # via black -typed-ast==1.5.4 \ - --hash=sha256:0261195c2062caf107831e92a76764c81227dae162c4f75192c0d489faf751a2 \ - --hash=sha256:0fdbcf2fef0ca421a3f5912555804296f0b0960f0418c440f5d6d3abb549f3e1 \ - --hash=sha256:183afdf0ec5b1b211724dfef3d2cad2d767cbefac291f24d69b00546c1837fb6 \ - --hash=sha256:211260621ab1cd7324e0798d6be953d00b74e0428382991adfddb352252f1d62 \ - --hash=sha256:267e3f78697a6c00c689c03db4876dd1efdfea2f251a5ad6555e82a26847b4ac \ - --hash=sha256:2efae9db7a8c05ad5547d522e7dbe62c83d838d3906a3716d1478b6c1d61388d \ - --hash=sha256:370788a63915e82fd6f212865a596a0fefcbb7d408bbbb13dea723d971ed8bdc \ - --hash=sha256:39e21ceb7388e4bb37f4c679d72707ed46c2fbf2a5609b8b8ebc4b067d977df2 \ - --hash=sha256:3e123d878ba170397916557d31c8f589951e353cc95fb7f24f6bb69adc1a8a97 \ - --hash=sha256:4879da6c9b73443f97e731b617184a596ac1235fe91f98d279a7af36c796da35 \ - --hash=sha256:4e964b4ff86550a7a7d56345c7864b18f403f5bd7380edf44a3c1fb4ee7ac6c6 \ - --hash=sha256:639c5f0b21776605dd6c9dbe592d5228f021404dafd377e2b7ac046b0349b1a1 \ - --hash=sha256:669dd0c4167f6f2cd9f57041e03c3c2ebf9063d0757dc89f79ba1daa2bfca9d4 \ - --hash=sha256:6778e1b2f81dfc7bc58e4b259363b83d2e509a65198e85d5700dfae4c6c8ff1c \ - --hash=sha256:683407d92dc953c8a7347119596f0b0e6c55eb98ebebd9b23437501b28dcbb8e \ - --hash=sha256:79b1e0869db7c830ba6a981d58711c88b6677506e648496b1f64ac7d15633aec \ - --hash=sha256:7d5d014b7daa8b0bf2eaef684295acae12b036d79f54178b92a2b6a56f92278f \ - --hash=sha256:98f80dee3c03455e92796b58b98ff6ca0b2a6f652120c263efdba4d6c5e58f72 \ - --hash=sha256:a94d55d142c9265f4ea46fab70977a1944ecae359ae867397757d836ea5a3f47 \ - --hash=sha256:a9916d2bb8865f973824fb47436fa45e1ebf2efd920f2b9f99342cb7fab93f72 \ - --hash=sha256:c542eeda69212fa10a7ada75e668876fdec5f856cd3d06829e6aa64ad17c8dfe \ - --hash=sha256:cf4afcfac006ece570e32d6fa90ab74a17245b83dfd6655a6f68568098345ff6 \ - --hash=sha256:ebd9d7f80ccf7a82ac5f88c521115cc55d84e35bf8b446fcd7836eb6b98929a3 \ - --hash=sha256:ed855bbe3eb3715fca349c80174cfcfd699c2f9de574d40527b8429acae23a66 +typing-extensions==4.12.2 \ + --hash=sha256:04e5ca0351e0f3f85c6853954072df659d0d13fac324d0072316b67d7794700d \ + --hash=sha256:1a7ead55c7e559dd4dee8856e3a88b41225abfe1ce8df57b7c13915fe121ffb8 # via black -typing-extensions==4.6.3 \ - --hash=sha256:88a4153d8505aabbb4e13aacb7c486c2b4a33ca3b3f807914a9b4c844c471c26 \ - --hash=sha256:d91d5919357fe7f681a9f2b5b4cb2a5f1ef0a1e9f59c4d8ff0d3491e05c0ffd5 - # via - # black - # importlib-metadata - # platformdirs -zipp==3.15.0 \ - --hash=sha256:112929ad649da941c23de50f356a2b5570c954b65150642bccdd66bf194d224b \ - --hash=sha256:48904fc76a60e542af151aded95726c1a5c34ed43ab4134b597665c86d7ad556 - # via importlib-metadata diff --git a/src/tools/tidy/src/allowed_run_make_makefiles.txt b/src/tools/tidy/src/allowed_run_make_makefiles.txt index d4c3a970c70ec..fdd0be79a4de7 100644 --- a/src/tools/tidy/src/allowed_run_make_makefiles.txt +++ b/src/tools/tidy/src/allowed_run_make_makefiles.txt @@ -1,5 +1,4 @@ run-make/allocator-shim-circular-deps/Makefile -run-make/allow-non-lint-warnings-cmdline/Makefile run-make/archive-duplicate-names/Makefile run-make/atomic-lock-free/Makefile run-make/branch-protection-check-IBT/Makefile @@ -12,13 +11,11 @@ run-make/c-unwind-abi-catch-panic/Makefile run-make/cat-and-grep-sanity-check/Makefile run-make/cdylib-dylib-linkage/Makefile run-make/cdylib-fewer-symbols/Makefile -run-make/codegen-options-parsing/Makefile run-make/comment-section/Makefile run-make/compiler-lookup-paths-2/Makefile run-make/compiler-lookup-paths/Makefile run-make/compiler-rt-works-on-mingw/Makefile run-make/compressed-debuginfo/Makefile -run-make/const_fn_mir/Makefile run-make/crate-hash-rustc-version/Makefile run-make/crate-name-priority/Makefile run-make/cross-lang-lto-clang/Makefile @@ -27,13 +24,11 @@ run-make/cross-lang-lto-upstream-rlibs/Makefile run-make/cross-lang-lto/Makefile run-make/debug-assertions/Makefile run-make/debugger-visualizer-dep-info/Makefile -run-make/dep-graph/Makefile run-make/dep-info-doesnt-run-much/Makefile run-make/dep-info-spaces/Makefile run-make/dep-info/Makefile run-make/dump-ice-to-disk/Makefile run-make/dump-mono-stats/Makefile -run-make/duplicate-output-flavors/Makefile run-make/dylib-chain/Makefile run-make/emit-path-unhashed/Makefile run-make/emit-shared-files/Makefile @@ -226,9 +221,6 @@ run-make/std-core-cycle/Makefile run-make/symbol-mangling-hashed/Makefile run-make/symbol-visibility/Makefile run-make/symbols-include-type-name/Makefile -run-make/symlinked-extern/Makefile -run-make/symlinked-libraries/Makefile -run-make/symlinked-rlib/Makefile run-make/sysroot-crates-are-unstable/Makefile run-make/target-cpu-native/Makefile run-make/target-specs/Makefile diff --git a/src/tools/tidy/src/alphabetical.rs b/src/tools/tidy/src/alphabetical.rs index 150a9594350ed..a29286fa2c596 100644 --- a/src/tools/tidy/src/alphabetical.rs +++ b/src/tools/tidy/src/alphabetical.rs @@ -88,7 +88,7 @@ fn check_section<'a>( let trimmed_line = line.trim_start_matches(' '); if trimmed_line.starts_with("//") - || (trimmed_line.starts_with("#") && !trimmed_line.starts_with("#!")) + || (trimmed_line.starts_with('#') && !trimmed_line.starts_with("#!")) || trimmed_line.starts_with(is_close_bracket) { continue; diff --git a/src/tools/tidy/src/bins.rs b/src/tools/tidy/src/bins.rs index 64ba79dc1857e..c82e8b6fee98e 100644 --- a/src/tools/tidy/src/bins.rs +++ b/src/tools/tidy/src/bins.rs @@ -61,7 +61,7 @@ mod os_impl { fs::remove_file(&path).expect("Deleted temp file"); // If the file is executable, then we assume that this // filesystem does not track executability, so skip this check. - return if exec { Unsupported } else { Supported }; + if exec { Unsupported } else { Supported } } Err(e) => { // If the directory is read-only or we otherwise don't have rights, @@ -76,7 +76,7 @@ mod os_impl { panic!("unable to create temporary file `{:?}`: {:?}", path, e); } - }; + } } for &source_dir in sources { @@ -92,7 +92,7 @@ mod os_impl { } } - return true; + true } // FIXME: check when rust-installer test sh files will be removed, diff --git a/src/tools/tidy/src/deps.rs b/src/tools/tidy/src/deps.rs index 2dd3d17f9e3e7..7337c9843c7b6 100644 --- a/src/tools/tidy/src/deps.rs +++ b/src/tools/tidy/src/deps.rs @@ -699,11 +699,9 @@ fn check_permitted_dependencies( for dep in deps { let dep = pkg_from_id(metadata, dep); // If this path is in-tree, we don't require it to be explicitly permitted. - if dep.source.is_some() { - if !permitted_dependencies.contains(dep.name.as_str()) { - tidy_error!(bad, "Dependency for {descr} not explicitly permitted: {}", dep.id); - has_permitted_dep_error = true; - } + if dep.source.is_some() && !permitted_dependencies.contains(dep.name.as_str()) { + tidy_error!(bad, "Dependency for {descr} not explicitly permitted: {}", dep.id); + has_permitted_dep_error = true; } } diff --git a/src/tools/tidy/src/error_codes.rs b/src/tools/tidy/src/error_codes.rs index 39f7e70b69393..47e2be761e6ab 100644 --- a/src/tools/tidy/src/error_codes.rs +++ b/src/tools/tidy/src/error_codes.rs @@ -308,11 +308,9 @@ fn check_error_codes_tests( for line in file.lines() { let s = line.trim(); // Assuming the line starts with `error[E`, we can substring the error code out. - if s.starts_with("error[E") { - if &s[6..11] == code { - found_code = true; - break; - } + if s.starts_with("error[E") && &s[6..11] == code { + found_code = true; + break; }; } diff --git a/src/tools/tidy/src/ext_tool_checks.rs b/src/tools/tidy/src/ext_tool_checks.rs index 2c97a39f1008b..995ad58cb6219 100644 --- a/src/tools/tidy/src/ext_tool_checks.rs +++ b/src/tools/tidy/src/ext_tool_checks.rs @@ -24,9 +24,8 @@ use std::io; use std::path::{Path, PathBuf}; use std::process::Command; -/// Minimum python revision is 3.7 for ruff -const MIN_PY_REV: (u32, u32) = (3, 7); -const MIN_PY_REV_STR: &str = "≥3.7"; +const MIN_PY_REV: (u32, u32) = (3, 9); +const MIN_PY_REV_STR: &str = "≥3.9"; /// Path to find the python executable within a virtual environment #[cfg(target_os = "windows")] @@ -78,9 +77,9 @@ fn check_impl( let mut py_path = None; let (cfg_args, file_args): (Vec<_>, Vec<_>) = pos_args - .into_iter() + .iter() .map(OsStr::new) - .partition(|arg| arg.to_str().is_some_and(|s| s.starts_with("-"))); + .partition(|arg| arg.to_str().is_some_and(|s| s.starts_with('-'))); if python_lint || python_fmt { let venv_path = outdir.join("venv"); @@ -223,17 +222,8 @@ fn get_or_create_venv(venv_path: &Path, src_reqs_path: &Path) -> Result Result<(), Error> { /// Preferred python versions in order. Newest to oldest then current /// development versions - const TRY_PY: &[&str] = &[ - "python3.11", - "python3.10", - "python3.9", - "python3.8", - "python3.7", - "python3", - "python", - "python3.12", - "python3.13", - ]; + const TRY_PY: &[&str] = + &["python3.11", "python3.10", "python3.9", "python3", "python", "python3.12", "python3.13"]; let mut sys_py = None; let mut found = Vec::new(); @@ -274,13 +264,19 @@ fn create_venv_at_path(path: &Path) -> Result<(), Error> { if out.status.success() { return Ok(()); } - let err = if String::from_utf8_lossy(&out.stderr).contains("No module named virtualenv") { - Error::Generic(format!( + + let stderr = String::from_utf8_lossy(&out.stderr); + let err = if stderr.contains("No module named virtualenv") { + Error::Generic( "virtualenv not found: you may need to install it \ (`python3 -m pip install venv`)" - )) + .to_owned(), + ) } else { - Error::Generic(format!("failed to create venv at '{}' using {sys_py}", path.display())) + Error::Generic(format!( + "failed to create venv at '{}' using {sys_py}: {stderr}", + path.display() + )) }; Err(err) } diff --git a/src/tools/tidy/src/issues.txt b/src/tools/tidy/src/issues.txt index a6ba8959f0c5d..3c7284ce6db60 100644 --- a/src/tools/tidy/src/issues.txt +++ b/src/tools/tidy/src/issues.txt @@ -2760,7 +2760,6 @@ ui/lint/issue-1866.rs ui/lint/issue-19102.rs ui/lint/issue-20343.rs ui/lint/issue-30302.rs -ui/lint/issue-31924-non-snake-ffi.rs ui/lint/issue-34798.rs ui/lint/issue-35075.rs ui/lint/issue-47775-nested-macro-unnecessary-parens-arg.rs @@ -2769,7 +2768,6 @@ ui/lint/issue-54099-camel-case-underscore-types.rs ui/lint/issue-57410-1.rs ui/lint/issue-57410.rs ui/lint/issue-63364.rs -ui/lint/issue-66362-no-snake-case-warning-for-field-puns.rs ui/lint/issue-70819-dont-override-forbid-in-same-scope.rs ui/lint/issue-79546-fuel-ice.rs ui/lint/issue-79744.rs @@ -2777,7 +2775,6 @@ ui/lint/issue-80988.rs ui/lint/issue-81218.rs ui/lint/issue-83477.rs ui/lint/issue-87274-paren-parent.rs -ui/lint/issue-89469.rs ui/lint/issue-90614-accept-allow-text-direction-codepoint-in-comment-lint.rs ui/lint/issue-97094.rs ui/lint/issue-99387.rs diff --git a/src/tools/tidy/src/style.rs b/src/tools/tidy/src/style.rs index 2d3888ec75f25..7bcb85335e07d 100644 --- a/src/tools/tidy/src/style.rs +++ b/src/tools/tidy/src/style.rs @@ -463,10 +463,13 @@ pub fn check(path: &Path, bad: &mut bool) { } } // for now we just check libcore - if trimmed.contains("unsafe {") && !trimmed.starts_with("//") && !last_safety_comment { - if file.components().any(|c| c.as_os_str() == "core") && !is_test { - suppressible_tidy_err!(err, skip_undocumented_unsafe, "undocumented unsafe"); - } + if trimmed.contains("unsafe {") + && !trimmed.starts_with("//") + && !last_safety_comment + && file.components().any(|c| c.as_os_str() == "core") + && !is_test + { + suppressible_tidy_err!(err, skip_undocumented_unsafe, "undocumented unsafe"); } if trimmed.contains("// SAFETY:") { last_safety_comment = true; @@ -487,10 +490,10 @@ pub fn check(path: &Path, bad: &mut bool) { "copyright notices attributed to the Rust Project Developers are deprecated" ); } - if !file.components().any(|c| c.as_os_str() == "rustc_baked_icu_data") { - if is_unexplained_ignore(&extension, line) { - err(UNEXPLAINED_IGNORE_DOCTEST_INFO); - } + if !file.components().any(|c| c.as_os_str() == "rustc_baked_icu_data") + && is_unexplained_ignore(&extension, line) + { + err(UNEXPLAINED_IGNORE_DOCTEST_INFO); } if filename.ends_with(".cpp") && line.contains("llvm_unreachable") { @@ -525,26 +528,24 @@ pub fn check(path: &Path, bad: &mut bool) { backtick_count += comment_text.chars().filter(|ch| *ch == '`').count(); } comment_block = Some((start_line, backtick_count)); - } else { - if let Some((start_line, backtick_count)) = comment_block.take() { - if backtick_count % 2 == 1 { - let mut err = |msg: &str| { - tidy_error!(bad, "{}:{start_line}: {msg}", file.display()); - }; - let block_len = (i + 1) - start_line; - if block_len == 1 { - suppressible_tidy_err!( - err, - skip_odd_backticks, - "comment with odd number of backticks" - ); - } else { - suppressible_tidy_err!( - err, - skip_odd_backticks, - "{block_len}-line comment block with odd number of backticks" - ); - } + } else if let Some((start_line, backtick_count)) = comment_block.take() { + if backtick_count % 2 == 1 { + let mut err = |msg: &str| { + tidy_error!(bad, "{}:{start_line}: {msg}", file.display()); + }; + let block_len = (i + 1) - start_line; + if block_len == 1 { + suppressible_tidy_err!( + err, + skip_odd_backticks, + "comment with odd number of backticks" + ); + } else { + suppressible_tidy_err!( + err, + skip_odd_backticks, + "{block_len}-line comment block with odd number of backticks" + ); } } } diff --git a/src/tools/tidy/src/walk.rs b/src/tools/tidy/src/walk.rs index 63a0383416652..1cecf998e284b 100644 --- a/src/tools/tidy/src/walk.rs +++ b/src/tools/tidy/src/walk.rs @@ -79,13 +79,11 @@ pub(crate) fn walk_no_read( let walker = walker.filter_entry(move |e| { !skip(e.path(), e.file_type().map(|ft| ft.is_dir()).unwrap_or(false)) }); - for entry in walker.build() { - if let Ok(entry) = entry { - if entry.file_type().map_or(true, |kind| kind.is_dir() || kind.is_symlink()) { - continue; - } - f(&entry); + for entry in walker.build().flatten() { + if entry.file_type().map_or(true, |kind| kind.is_dir() || kind.is_symlink()) { + continue; } + f(&entry); } } @@ -97,11 +95,9 @@ pub(crate) fn walk_dir( ) { let mut walker = ignore::WalkBuilder::new(path); let walker = walker.filter_entry(move |e| !skip(e.path())); - for entry in walker.build() { - if let Ok(entry) = entry { - if entry.path().is_dir() { - f(&entry); - } + for entry in walker.build().flatten() { + if entry.path().is_dir() { + f(&entry); } } } diff --git a/src/tools/tidy/src/x_version.rs b/src/tools/tidy/src/x_version.rs index c470d502a6548..55bfbed8b0e10 100644 --- a/src/tools/tidy/src/x_version.rs +++ b/src/tools/tidy/src/x_version.rs @@ -52,7 +52,7 @@ pub fn check(root: &Path, cargo: &Path, bad: &mut bool) { ); } } else { - return tidy_error!(bad, "failed to check version of `x`: {}", cargo_list.status); + tidy_error!(bad, "failed to check version of `x`: {}", cargo_list.status) } } diff --git a/tests/assembly/asm/x86-types.rs b/tests/assembly/asm/x86-types.rs index 2b4ebb05349ba..8e229614420b6 100644 --- a/tests/assembly/asm/x86-types.rs +++ b/tests/assembly/asm/x86-types.rs @@ -7,7 +7,7 @@ //@ compile-flags: -C llvm-args=--x86-asm-syntax=intel //@ compile-flags: -C target-feature=+avx512bw -#![feature(no_core, lang_items, rustc_attrs, repr_simd)] +#![feature(no_core, lang_items, rustc_attrs, repr_simd, f16, f128)] #![crate_type = "rlib"] #![no_core] #![allow(asm_sub_register, non_camel_case_types)] @@ -41,6 +41,8 @@ pub struct i32x4(i32, i32, i32, i32); #[repr(simd)] pub struct i64x2(i64, i64); #[repr(simd)] +pub struct f16x8(f16, f16, f16, f16, f16, f16, f16, f16); +#[repr(simd)] pub struct f32x4(f32, f32, f32, f32); #[repr(simd)] pub struct f64x2(f64, f64); @@ -87,6 +89,8 @@ pub struct i32x8(i32, i32, i32, i32, i32, i32, i32, i32); #[repr(simd)] pub struct i64x4(i64, i64, i64, i64); #[repr(simd)] +pub struct f16x16(f16, f16, f16, f16, f16, f16, f16, f16, f16, f16, f16, f16, f16, f16, f16, f16); +#[repr(simd)] pub struct f32x8(f32, f32, f32, f32, f32, f32, f32, f32); #[repr(simd)] pub struct f64x4(f64, f64, f64, f64); @@ -198,35 +202,59 @@ pub struct i32x16(i32, i32, i32, i32, i32, i32, i32, i32, i32, i32, i32, i32, i3 #[repr(simd)] pub struct i64x8(i64, i64, i64, i64, i64, i64, i64, i64); #[repr(simd)] +pub struct f16x32( + f16, + f16, + f16, + f16, + f16, + f16, + f16, + f16, + f16, + f16, + f16, + f16, + f16, + f16, + f16, + f16, + f16, + f16, + f16, + f16, + f16, + f16, + f16, + f16, + f16, + f16, + f16, + f16, + f16, + f16, + f16, + f16, +); +#[repr(simd)] pub struct f32x16(f32, f32, f32, f32, f32, f32, f32, f32, f32, f32, f32, f32, f32, f32, f32, f32); #[repr(simd)] pub struct f64x8(f64, f64, f64, f64, f64, f64, f64, f64); -impl Copy for i8 {} -impl Copy for i16 {} -impl Copy for i32 {} -impl Copy for f32 {} -impl Copy for i64 {} -impl Copy for f64 {} -impl Copy for ptr {} -impl Copy for i8x16 {} -impl Copy for i16x8 {} -impl Copy for i32x4 {} -impl Copy for i64x2 {} -impl Copy for f32x4 {} -impl Copy for f64x2 {} -impl Copy for i8x32 {} -impl Copy for i16x16 {} -impl Copy for i32x8 {} -impl Copy for i64x4 {} -impl Copy for f32x8 {} -impl Copy for f64x4 {} -impl Copy for i8x64 {} -impl Copy for i16x32 {} -impl Copy for i32x16 {} -impl Copy for i64x8 {} -impl Copy for f32x16 {} -impl Copy for f64x8 {} +macro_rules! impl_copy { + ($($ty:ident)*) => { + $( + impl Copy for $ty {} + )* + }; +} + +impl_copy!( + i8 i16 f16 i32 f32 i64 f64 f128 ptr + i8x16 i16x8 i32x4 i64x2 f16x8 f32x4 f64x2 + i8x32 i16x16 i32x8 i64x4 f16x16 f32x8 f64x4 + i8x64 i16x32 i32x16 i64x8 f16x32 f32x16 f64x8 +); extern "C" { fn extern_func(); @@ -292,6 +320,13 @@ macro_rules! check_reg { // CHECK: #NO_APP check!(reg_i16 i16 reg "mov"); +// CHECK-LABEL: reg_f16: +// CHECK: #APP +// x86_64: mov r{{[a-z0-9]+}}, r{{[a-z0-9]+}} +// i686: mov e{{[a-z0-9]+}}, e{{[a-z0-9]+}} +// CHECK: #NO_APP +check!(reg_f16 f16 reg "mov"); + // CHECK-LABEL: reg_i32: // CHECK: #APP // x86_64: mov r{{[a-z0-9]+}}, r{{[a-z0-9]+}} @@ -334,6 +369,13 @@ check!(reg_ptr ptr reg "mov"); // CHECK: #NO_APP check!(reg_abcd_i16 i16 reg_abcd "mov"); +// CHECK-LABEL: reg_abcd_f16: +// CHECK: #APP +// x86_64: mov r{{[a-z0-9]+}}, r{{[a-z0-9]+}} +// i686: mov e{{[a-z0-9]+}}, e{{[a-z0-9]+}} +// CHECK: #NO_APP +check!(reg_abcd_f16 f16 reg_abcd "mov"); + // CHECK-LABEL: reg_abcd_i32: // CHECK: #APP // x86_64: mov r{{[a-z0-9]+}}, r{{[a-z0-9]+}} @@ -375,6 +417,12 @@ check!(reg_abcd_ptr ptr reg_abcd "mov"); // CHECK: #NO_APP check!(reg_byte i8 reg_byte "mov"); +// CHECK-LABEL: xmm_reg_f16: +// CHECK: #APP +// CHECK: movaps xmm{{[0-9]+}}, xmm{{[0-9]+}} +// CHECK: #NO_APP +check!(xmm_reg_f16 f16 xmm_reg "movaps"); + // CHECK-LABEL: xmm_reg_i32: // CHECK: #APP // CHECK: movaps xmm{{[0-9]+}}, xmm{{[0-9]+}} @@ -399,6 +447,12 @@ check!(xmm_reg_i64 i64 xmm_reg "movaps"); // CHECK: #NO_APP check!(xmm_reg_f64 f64 xmm_reg "movaps"); +// CHECK-LABEL: xmm_reg_f128: +// CHECK: #APP +// CHECK: movaps xmm{{[0-9]+}}, xmm{{[0-9]+}} +// CHECK: #NO_APP +check!(xmm_reg_f128 f128 xmm_reg "movaps"); + // CHECK-LABEL: xmm_reg_ptr: // CHECK: #APP // CHECK: movaps xmm{{[0-9]+}}, xmm{{[0-9]+}} @@ -429,6 +483,12 @@ check!(xmm_reg_i32x4 i32x4 xmm_reg "movaps"); // CHECK: #NO_APP check!(xmm_reg_i64x2 i64x2 xmm_reg "movaps"); +// CHECK-LABEL: xmm_reg_f16x8: +// CHECK: #APP +// CHECK: movaps xmm{{[0-9]+}}, xmm{{[0-9]+}} +// CHECK: #NO_APP +check!(xmm_reg_f16x8 f16x8 xmm_reg "movaps"); + // CHECK-LABEL: xmm_reg_f32x4: // CHECK: #APP // CHECK: movaps xmm{{[0-9]+}}, xmm{{[0-9]+}} @@ -441,6 +501,12 @@ check!(xmm_reg_f32x4 f32x4 xmm_reg "movaps"); // CHECK: #NO_APP check!(xmm_reg_f64x2 f64x2 xmm_reg "movaps"); +// CHECK-LABEL: ymm_reg_f16: +// CHECK: #APP +// CHECK: vmovaps ymm{{[0-9]+}}, ymm{{[0-9]+}} +// CHECK: #NO_APP +check!(ymm_reg_f16 f16 ymm_reg "vmovaps"); + // CHECK-LABEL: ymm_reg_i32: // CHECK: #APP // CHECK: vmovaps ymm{{[0-9]+}}, ymm{{[0-9]+}} @@ -465,6 +531,12 @@ check!(ymm_reg_i64 i64 ymm_reg "vmovaps"); // CHECK: #NO_APP check!(ymm_reg_f64 f64 ymm_reg "vmovaps"); +// CHECK-LABEL: ymm_reg_f128: +// CHECK: #APP +// CHECK: vmovaps ymm{{[0-9]+}}, ymm{{[0-9]+}} +// CHECK: #NO_APP +check!(ymm_reg_f128 f128 ymm_reg "vmovaps"); + // CHECK-LABEL: ymm_reg_ptr: // CHECK: #APP // CHECK: vmovaps ymm{{[0-9]+}}, ymm{{[0-9]+}} @@ -495,6 +567,12 @@ check!(ymm_reg_i32x4 i32x4 ymm_reg "vmovaps"); // CHECK: #NO_APP check!(ymm_reg_i64x2 i64x2 ymm_reg "vmovaps"); +// CHECK-LABEL: ymm_reg_f16x8: +// CHECK: #APP +// CHECK: vmovaps ymm{{[0-9]+}}, ymm{{[0-9]+}} +// CHECK: #NO_APP +check!(ymm_reg_f16x8 f16x8 ymm_reg "vmovaps"); + // CHECK-LABEL: ymm_reg_f32x4: // CHECK: #APP // CHECK: vmovaps ymm{{[0-9]+}}, ymm{{[0-9]+}} @@ -531,6 +609,12 @@ check!(ymm_reg_i32x8 i32x8 ymm_reg "vmovaps"); // CHECK: #NO_APP check!(ymm_reg_i64x4 i64x4 ymm_reg "vmovaps"); +// CHECK-LABEL: ymm_reg_f16x16: +// CHECK: #APP +// CHECK: vmovaps ymm{{[0-9]+}}, ymm{{[0-9]+}} +// CHECK: #NO_APP +check!(ymm_reg_f16x16 f16x16 ymm_reg "vmovaps"); + // CHECK-LABEL: ymm_reg_f32x8: // CHECK: #APP // CHECK: vmovaps ymm{{[0-9]+}}, ymm{{[0-9]+}} @@ -543,6 +627,12 @@ check!(ymm_reg_f32x8 f32x8 ymm_reg "vmovaps"); // CHECK: #NO_APP check!(ymm_reg_f64x4 f64x4 ymm_reg "vmovaps"); +// CHECK-LABEL: zmm_reg_f16: +// CHECK: #APP +// CHECK: vmovaps zmm{{[0-9]+}}, zmm{{[0-9]+}} +// CHECK: #NO_APP +check!(zmm_reg_f16 f16 zmm_reg "vmovaps"); + // CHECK-LABEL: zmm_reg_i32: // CHECK: #APP // CHECK: vmovaps zmm{{[0-9]+}}, zmm{{[0-9]+}} @@ -567,6 +657,12 @@ check!(zmm_reg_i64 i64 zmm_reg "vmovaps"); // CHECK: #NO_APP check!(zmm_reg_f64 f64 zmm_reg "vmovaps"); +// CHECK-LABEL: zmm_reg_f128: +// CHECK: #APP +// CHECK: vmovaps zmm{{[0-9]+}}, zmm{{[0-9]+}} +// CHECK: #NO_APP +check!(zmm_reg_f128 f128 zmm_reg "vmovaps"); + // CHECK-LABEL: zmm_reg_ptr: // CHECK: #APP // CHECK: vmovaps zmm{{[0-9]+}}, zmm{{[0-9]+}} @@ -597,6 +693,12 @@ check!(zmm_reg_i32x4 i32x4 zmm_reg "vmovaps"); // CHECK: #NO_APP check!(zmm_reg_i64x2 i64x2 zmm_reg "vmovaps"); +// CHECK-LABEL: zmm_reg_f16x8: +// CHECK: #APP +// CHECK: vmovaps zmm{{[0-9]+}}, zmm{{[0-9]+}} +// CHECK: #NO_APP +check!(zmm_reg_f16x8 f16x8 zmm_reg "vmovaps"); + // CHECK-LABEL: zmm_reg_f32x4: // CHECK: #APP // CHECK: vmovaps zmm{{[0-9]+}}, zmm{{[0-9]+}} @@ -633,6 +735,12 @@ check!(zmm_reg_i32x8 i32x8 zmm_reg "vmovaps"); // CHECK: #NO_APP check!(zmm_reg_i64x4 i64x4 zmm_reg "vmovaps"); +// CHECK-LABEL: zmm_reg_f16x16: +// CHECK: #APP +// CHECK: vmovaps zmm{{[0-9]+}}, zmm{{[0-9]+}} +// CHECK: #NO_APP +check!(zmm_reg_f16x16 f16x16 zmm_reg "vmovaps"); + // CHECK-LABEL: zmm_reg_f32x8: // CHECK: #APP // CHECK: vmovaps zmm{{[0-9]+}}, zmm{{[0-9]+}} @@ -669,6 +777,12 @@ check!(zmm_reg_i32x16 i32x16 zmm_reg "vmovaps"); // CHECK: #NO_APP check!(zmm_reg_i64x8 i64x8 zmm_reg "vmovaps"); +// CHECK-LABEL: zmm_reg_f16x32: +// CHECK: #APP +// CHECK: vmovaps zmm{{[0-9]+}}, zmm{{[0-9]+}} +// CHECK: #NO_APP +check!(zmm_reg_f16x32 f16x32 zmm_reg "vmovaps"); + // CHECK-LABEL: zmm_reg_f32x16: // CHECK: #APP // CHECK: vmovaps zmm{{[0-9]+}}, zmm{{[0-9]+}} @@ -717,6 +831,12 @@ check!(kreg_ptr ptr kreg "kmovq"); // CHECK: #NO_APP check_reg!(eax_i16 i16 "eax" "mov"); +// CHECK-LABEL: eax_f16: +// CHECK: #APP +// CHECK: mov eax, eax +// CHECK: #NO_APP +check_reg!(eax_f16 f16 "eax" "mov"); + // CHECK-LABEL: eax_i32: // CHECK: #APP // CHECK: mov eax, eax @@ -756,6 +876,12 @@ check_reg!(eax_ptr ptr "eax" "mov"); #[cfg(i686)] check_reg!(ah_byte i8 "ah" "mov"); +// CHECK-LABEL: xmm0_f16: +// CHECK: #APP +// CHECK: movaps xmm0, xmm0 +// CHECK: #NO_APP +check_reg!(xmm0_f16 f16 "xmm0" "movaps"); + // CHECK-LABEL: xmm0_i32: // CHECK: #APP // CHECK: movaps xmm0, xmm0 @@ -780,6 +906,12 @@ check_reg!(xmm0_i64 i64 "xmm0" "movaps"); // CHECK: #NO_APP check_reg!(xmm0_f64 f64 "xmm0" "movaps"); +// CHECK-LABEL: xmm0_f128: +// CHECK: #APP +// CHECK: movaps xmm0, xmm0 +// CHECK: #NO_APP +check_reg!(xmm0_f128 f128 "xmm0" "movaps"); + // CHECK-LABEL: xmm0_ptr: // CHECK: #APP // CHECK: movaps xmm0, xmm0 @@ -810,6 +942,12 @@ check_reg!(xmm0_i32x4 i32x4 "xmm0" "movaps"); // CHECK: #NO_APP check_reg!(xmm0_i64x2 i64x2 "xmm0" "movaps"); +// CHECK-LABEL: xmm0_f16x8: +// CHECK: #APP +// CHECK: movaps xmm0, xmm0 +// CHECK: #NO_APP +check_reg!(xmm0_f16x8 f16x8 "xmm0" "movaps"); + // CHECK-LABEL: xmm0_f32x4: // CHECK: #APP // CHECK: movaps xmm0, xmm0 @@ -822,6 +960,12 @@ check_reg!(xmm0_f32x4 f32x4 "xmm0" "movaps"); // CHECK: #NO_APP check_reg!(xmm0_f64x2 f64x2 "xmm0" "movaps"); +// CHECK-LABEL: ymm0_f16: +// CHECK: #APP +// CHECK: vmovaps ymm0, ymm0 +// CHECK: #NO_APP +check_reg!(ymm0_f16 f16 "ymm0" "vmovaps"); + // CHECK-LABEL: ymm0_i32: // CHECK: #APP // CHECK: vmovaps ymm0, ymm0 @@ -846,6 +990,12 @@ check_reg!(ymm0_i64 i64 "ymm0" "vmovaps"); // CHECK: #NO_APP check_reg!(ymm0_f64 f64 "ymm0" "vmovaps"); +// CHECK-LABEL: ymm0_f128: +// CHECK: #APP +// CHECK: vmovaps ymm0, ymm0 +// CHECK: #NO_APP +check_reg!(ymm0_f128 f128 "ymm0" "vmovaps"); + // CHECK-LABEL: ymm0_ptr: // CHECK: #APP // CHECK: vmovaps ymm0, ymm0 @@ -876,6 +1026,12 @@ check_reg!(ymm0_i32x4 i32x4 "ymm0" "vmovaps"); // CHECK: #NO_APP check_reg!(ymm0_i64x2 i64x2 "ymm0" "vmovaps"); +// CHECK-LABEL: ymm0_f16x8: +// CHECK: #APP +// CHECK: vmovaps ymm0, ymm0 +// CHECK: #NO_APP +check_reg!(ymm0_f16x8 f16x8 "ymm0" "vmovaps"); + // CHECK-LABEL: ymm0_f32x4: // CHECK: #APP // CHECK: vmovaps ymm0, ymm0 @@ -912,6 +1068,12 @@ check_reg!(ymm0_i32x8 i32x8 "ymm0" "vmovaps"); // CHECK: #NO_APP check_reg!(ymm0_i64x4 i64x4 "ymm0" "vmovaps"); +// CHECK-LABEL: ymm0_f16x16: +// CHECK: #APP +// CHECK: vmovaps ymm0, ymm0 +// CHECK: #NO_APP +check_reg!(ymm0_f16x16 f16x16 "ymm0" "vmovaps"); + // CHECK-LABEL: ymm0_f32x8: // CHECK: #APP // CHECK: vmovaps ymm0, ymm0 @@ -924,6 +1086,12 @@ check_reg!(ymm0_f32x8 f32x8 "ymm0" "vmovaps"); // CHECK: #NO_APP check_reg!(ymm0_f64x4 f64x4 "ymm0" "vmovaps"); +// CHECK-LABEL: zmm0_f16: +// CHECK: #APP +// CHECK: vmovaps zmm0, zmm0 +// CHECK: #NO_APP +check_reg!(zmm0_f16 f16 "zmm0" "vmovaps"); + // CHECK-LABEL: zmm0_i32: // CHECK: #APP // CHECK: vmovaps zmm0, zmm0 @@ -948,6 +1116,12 @@ check_reg!(zmm0_i64 i64 "zmm0" "vmovaps"); // CHECK: #NO_APP check_reg!(zmm0_f64 f64 "zmm0" "vmovaps"); +// CHECK-LABEL: zmm0_f128: +// CHECK: #APP +// CHECK: vmovaps zmm0, zmm0 +// CHECK: #NO_APP +check_reg!(zmm0_f128 f128 "zmm0" "vmovaps"); + // CHECK-LABEL: zmm0_ptr: // CHECK: #APP // CHECK: vmovaps zmm0, zmm0 @@ -978,6 +1152,12 @@ check_reg!(zmm0_i32x4 i32x4 "zmm0" "vmovaps"); // CHECK: #NO_APP check_reg!(zmm0_i64x2 i64x2 "zmm0" "vmovaps"); +// CHECK-LABEL: zmm0_f16x8: +// CHECK: #APP +// CHECK: vmovaps zmm0, zmm0 +// CHECK: #NO_APP +check_reg!(zmm0_f16x8 f16x8 "zmm0" "vmovaps"); + // CHECK-LABEL: zmm0_f32x4: // CHECK: #APP // CHECK: vmovaps zmm0, zmm0 @@ -1014,6 +1194,12 @@ check_reg!(zmm0_i32x8 i32x8 "zmm0" "vmovaps"); // CHECK: #NO_APP check_reg!(zmm0_i64x4 i64x4 "zmm0" "vmovaps"); +// CHECK-LABEL: zmm0_f16x16: +// CHECK: #APP +// CHECK: vmovaps zmm0, zmm0 +// CHECK: #NO_APP +check_reg!(zmm0_f16x16 f16x16 "zmm0" "vmovaps"); + // CHECK-LABEL: zmm0_f32x8: // CHECK: #APP // CHECK: vmovaps zmm0, zmm0 @@ -1050,6 +1236,12 @@ check_reg!(zmm0_i32x16 i32x16 "zmm0" "vmovaps"); // CHECK: #NO_APP check_reg!(zmm0_i64x8 i64x8 "zmm0" "vmovaps"); +// CHECK-LABEL: zmm0_f16x32: +// CHECK: #APP +// CHECK: vmovaps zmm0, zmm0 +// CHECK: #NO_APP +check_reg!(zmm0_f16x32 f16x32 "zmm0" "vmovaps"); + // CHECK-LABEL: zmm0_f32x16: // CHECK: #APP // CHECK: vmovaps zmm0, zmm0 diff --git a/tests/assembly/issue-83585-small-pod-struct-equality.rs b/tests/assembly/issue-83585-small-pod-struct-equality.rs new file mode 100644 index 0000000000000..14bec1337f0bf --- /dev/null +++ b/tests/assembly/issue-83585-small-pod-struct-equality.rs @@ -0,0 +1,27 @@ +//@ assembly-output: emit-asm +//@ compile-flags: -Copt-level=3 +//@ only-x86_64 + +#![crate_type = "lib"] + +type T = u8; +type T1 = (T, T, T, T, T, T, T, T); + +// CHECK-LABEL: foo1a +// CHECK: cmpq +// CHECK-NEXT: sete +// CHECK-NEXT: {{retq|popq}} +#[no_mangle] +pub fn foo1a(a: T1, b: T1) -> bool { + a == b +} + +// CHECK-LABEL: foo1b +// CHECK: movq +// CHECK: cmpq +// CHECK-NEXT: sete +// CHECK-NEXT: {{retq|popq}} +#[no_mangle] +pub fn foo1b(a: &T1, b: &T1) -> bool { + a == b +} diff --git a/tests/assembly/targets/targets-elf.rs b/tests/assembly/targets/targets-elf.rs index 4c54fe639e3e6..b069e667bf5d5 100644 --- a/tests/assembly/targets/targets-elf.rs +++ b/tests/assembly/targets/targets-elf.rs @@ -228,6 +228,9 @@ //@ revisions: i686_unknown_openbsd //@ [i686_unknown_openbsd] compile-flags: --target i686-unknown-openbsd //@ [i686_unknown_openbsd] needs-llvm-components: x86 +//@ revisions: i686_unknown_redox +//@ [i686_unknown_redox] compile-flags: --target i686-unknown-redox +//@ [i686_unknown_redox] needs-llvm-components: x86 //@ revisions: i686_wrs_vxworks //@ [i686_wrs_vxworks] compile-flags: --target i686-wrs-vxworks //@ [i686_wrs_vxworks] needs-llvm-components: x86 diff --git a/tests/codegen/instrument-coverage/instrument-coverage-off.rs b/tests/codegen/instrument-coverage/instrument-coverage-off.rs index 616e3295e5b1a..e44d6c6587480 100644 --- a/tests/codegen/instrument-coverage/instrument-coverage-off.rs +++ b/tests/codegen/instrument-coverage/instrument-coverage-off.rs @@ -1,5 +1,6 @@ // Test that `-Cinstrument-coverage=off` does not add coverage instrumentation to LLVM IR. +//@ compile-flags: -Zno-profiler-runtime //@ revisions: n no off false_ zero //@ [n] compile-flags: -Cinstrument-coverage=n //@ [no] compile-flags: -Cinstrument-coverage=no diff --git a/tests/codegen/instrument-coverage/instrument-coverage.rs b/tests/codegen/instrument-coverage/instrument-coverage.rs index 65fa437d25066..23d23651c72ff 100644 --- a/tests/codegen/instrument-coverage/instrument-coverage.rs +++ b/tests/codegen/instrument-coverage/instrument-coverage.rs @@ -1,6 +1,6 @@ // Test that `-Cinstrument-coverage` creates expected __llvm_profile_filename symbol in LLVM IR. -//@ needs-profiler-support +//@ compile-flags: -Zno-profiler-runtime //@ revisions: default y yes on true_ all //@ [default] compile-flags: -Cinstrument-coverage //@ [y] compile-flags: -Cinstrument-coverage=y @@ -9,8 +9,8 @@ //@ [true_] compile-flags: -Cinstrument-coverage=true //@ [all] compile-flags: -Cinstrument-coverage=all -// CHECK: @__llvm_profile_filename = {{.*}}"default_%m_%p.profraw\00"{{.*}} -// CHECK: @__llvm_coverage_mapping +// CHECK-DAG: @__llvm_coverage_mapping +// CHECK-DAG: @__llvm_profile_filename = {{.*}}"default_%m_%p.profraw\00"{{.*}} #![crate_type = "lib"] diff --git a/tests/codegen/instrument-coverage/testprog.rs b/tests/codegen/instrument-coverage/testprog.rs index acc4f35d90543..eea4d9cb3cf05 100644 --- a/tests/codegen/instrument-coverage/testprog.rs +++ b/tests/codegen/instrument-coverage/testprog.rs @@ -1,5 +1,5 @@ //@ edition: 2021 -//@ needs-profiler-support +//@ compile-flags: -Zno-profiler-runtime //@ compile-flags: -Cinstrument-coverage -Copt-level=0 //@ revisions: LINUX DARWIN WINDOWS diff --git a/tests/codegen/issues/issue-109328-split_first.rs b/tests/codegen/issues/issue-109328-split_first.rs new file mode 100644 index 0000000000000..7f7957593d2de --- /dev/null +++ b/tests/codegen/issues/issue-109328-split_first.rs @@ -0,0 +1,16 @@ +//@ compile-flags: -O + +#![crate_type = "lib"] + +// CHECK-LABEL: @foo +// CHECK-NEXT: {{.*}}: +// CHECK-NEXT: getelementptr inbounds +// CHECK-NEXT: load [[TYPE:i(32|64)]] +// CHECK-NEXT: icmp eq [[TYPE]] +// CHECK-NEXT: br i1 +#[no_mangle] +pub fn foo(input: &mut &[u64]) -> Option { + let (first, rest) = input.split_first()?; + *input = rest; + Some(*first) +} diff --git a/tests/codegen/issues/issue-110797-enum-jump-same.rs b/tests/codegen/issues/issue-110797-enum-jump-same.rs new file mode 100644 index 0000000000000..f34b191ac709e --- /dev/null +++ b/tests/codegen/issues/issue-110797-enum-jump-same.rs @@ -0,0 +1,26 @@ +//@ compile-flags: -O +//@ min-llvm-version: 18 + +#![crate_type = "lib"] + +pub enum K { + A(Box<[i32]>), + B(Box<[u8]>), + C(Box<[String]>), + D(Box<[u16]>), +} + +// CHECK-LABEL: @get_len +// CHECK-NEXT: {{.*}}: +// CHECK-NEXT: getelementptr inbounds +// CHECK-NEXT: load [[TYPE:i(32|64)]] +// CHECK-NEXT: ret [[TYPE]] +#[no_mangle] +pub fn get_len(arg: &K) -> usize { + match arg { + K::A(ref lst) => lst.len(), + K::B(ref lst) => lst.len(), + K::C(ref lst) => lst.len(), + K::D(ref lst) => lst.len(), + } +} diff --git a/tests/codegen/issues/issue-111508-vec-tryinto-array.rs b/tests/codegen/issues/issue-111508-vec-tryinto-array.rs new file mode 100644 index 0000000000000..6415724b40ad5 --- /dev/null +++ b/tests/codegen/issues/issue-111508-vec-tryinto-array.rs @@ -0,0 +1,22 @@ +//@ compile-flags: -O +// This regress since Rust version 1.72. +//@ min-llvm-version: 18.1.4 + +#![crate_type = "lib"] + +use std::convert::TryInto; + +const N: usize = 24; + +// CHECK-LABEL: @example +// CHECK-NOT: unwrap_failed +#[no_mangle] +pub fn example(a: Vec) -> u8 { + if a.len() != 32 { + return 0; + } + + let a: [u8; 32] = a.try_into().unwrap(); + + a[15] + a[N] +} diff --git a/tests/codegen/issues/issue-112509-slice-get-andthen-get.rs b/tests/codegen/issues/issue-112509-slice-get-andthen-get.rs new file mode 100644 index 0000000000000..ae02c3fb79e72 --- /dev/null +++ b/tests/codegen/issues/issue-112509-slice-get-andthen-get.rs @@ -0,0 +1,12 @@ +//@ compile-flags: -O +#![crate_type = "lib"] + +// CHECK-LABEL: @write_u8_variant_a +// CHECK-NEXT: {{.*}}: +// CHECK-NEXT: getelementptr +// CHECK-NEXT: icmp ugt +#[no_mangle] +pub fn write_u8_variant_a(bytes: &mut [u8], buf: u8, offset: usize) -> Option<&mut [u8]> { + let buf = buf.to_le_bytes(); + bytes.get_mut(offset..).and_then(|bytes| bytes.get_mut(..buf.len())) +} diff --git a/tests/codegen/issues/issue-113757-bounds-check-after-cmp-max.rs b/tests/codegen/issues/issue-113757-bounds-check-after-cmp-max.rs new file mode 100644 index 0000000000000..d495adf99804c --- /dev/null +++ b/tests/codegen/issues/issue-113757-bounds-check-after-cmp-max.rs @@ -0,0 +1,18 @@ +// in Rust 1.73, -O and opt-level=3 optimizes differently +//@ compile-flags: -C opt-level=3 +#![crate_type = "lib"] + +use std::cmp::max; + +// CHECK-LABEL: @foo +// CHECK-NOT: slice_start_index_len_fail +// CHECK-NOT: unreachable +#[no_mangle] +pub fn foo(v: &mut Vec, size: usize) -> Option<&mut [u8]> { + if v.len() > max(1, size) { + let start = v.len() - size; + Some(&mut v[start..]) + } else { + None + } +} diff --git a/tests/codegen/issues/issue-118392.rs b/tests/codegen/issues/issue-118392.rs new file mode 100644 index 0000000000000..2cbb1f8b2043e --- /dev/null +++ b/tests/codegen/issues/issue-118392.rs @@ -0,0 +1,11 @@ +//@ compile-flags: -O +//@ min-llvm-version: 18 +#![crate_type = "lib"] + +// CHECK-LABEL: @div2 +// CHECK: ashr i32 %a, 1 +// CHECK-NEXT: ret i32 +#[no_mangle] +pub fn div2(a: i32) -> i32 { + a.div_euclid(2) +} diff --git a/tests/codegen/issues/issue-36010-some-box-is_some.rs b/tests/codegen/issues/issue-36010-some-box-is_some.rs new file mode 100644 index 0000000000000..44c01096f15ae --- /dev/null +++ b/tests/codegen/issues/issue-36010-some-box-is_some.rs @@ -0,0 +1,28 @@ +#![crate_type = "lib"] + +//@ compile-flags: -O + +use std::mem; + +fn foo(a: &mut T, b: T) -> bool { + let b = Some(mem::replace(a, b)); + let ret = b.is_some(); + mem::forget(b); + return ret; +} + +// CHECK-LABEL: @foo_u32 +// CHECK: store i32 +// CHECK-NEXT: ret i1 true +#[no_mangle] +pub fn foo_u32(a: &mut u32, b: u32) -> bool { + foo(a, b) +} + +// CHECK-LABEL: @foo_box +// CHECK: store ptr +// CHECK-NEXT: ret i1 true +#[no_mangle] +pub fn foo_box(a: &mut Box, b: Box) -> bool { + foo(a, b) +} diff --git a/tests/codegen/issues/issue-68667-unwrap-combinators.rs b/tests/codegen/issues/issue-68667-unwrap-combinators.rs new file mode 100644 index 0000000000000..6bd4c566a0c28 --- /dev/null +++ b/tests/codegen/issues/issue-68667-unwrap-combinators.rs @@ -0,0 +1,15 @@ +#![crate_type = "lib"] + +//@ compile-flags: -O + +// MIR inlining now optimizes this code. + +// CHECK-LABEL: @unwrap_combinators +// CHECK: icmp +// CHECK-NEXT: icmp +// CHECK-NEXT: select i1 +// CHECK-NEXT: ret i1 +#[no_mangle] +pub fn unwrap_combinators(a: Option, b: i32) -> bool { + a.map(|t| t >= b).unwrap_or(false) +} diff --git a/tests/codegen/issues/issue-74938-array-split-at.rs b/tests/codegen/issues/issue-74938-array-split-at.rs new file mode 100644 index 0000000000000..2675e404ced3b --- /dev/null +++ b/tests/codegen/issues/issue-74938-array-split-at.rs @@ -0,0 +1,14 @@ +//@ compile-flags: -O + +#![crate_type = "lib"] + +const N: usize = 3; +pub type T = u8; + +// CHECK-LABEL: @split_multiple +// CHECK-NOT: unreachable +#[no_mangle] +pub fn split_multiple(slice: &[T]) -> (&[T], &[T]) { + let len = slice.len() / N; + slice.split_at(len * N) +} diff --git a/tests/codegen/issues/issue-93036-assert-index.rs b/tests/codegen/issues/issue-93036-assert-index.rs new file mode 100644 index 0000000000000..7a2ea08726688 --- /dev/null +++ b/tests/codegen/issues/issue-93036-assert-index.rs @@ -0,0 +1,14 @@ +//@ compile-flags: -O + +#![crate_type = "lib"] + +#[no_mangle] +// CHECK-LABEL: @foo +// CHECK-NOT: unreachable +pub fn foo(arr: &mut [u32]) { + for i in 0..arr.len() { + for j in 0..i { + assert!(j < arr.len()); + } + } +} diff --git a/tests/codegen/naked-fn/naked-nocoverage.rs b/tests/codegen/naked-fn/naked-nocoverage.rs index e8d3b5834fa3a..d73c5b7fd26d1 100644 --- a/tests/codegen/naked-fn/naked-nocoverage.rs +++ b/tests/codegen/naked-fn/naked-nocoverage.rs @@ -2,7 +2,7 @@ // Regression test for issue #105170. // //@ needs-asm-support -//@ needs-profiler-support +//@ compile-flags: -Zno-profiler-runtime //@ compile-flags: -Cinstrument-coverage #![crate_type = "lib"] #![feature(naked_functions)] diff --git a/tests/codegen/pgo-counter-bias.rs b/tests/codegen/pgo-counter-bias.rs index 87d31073d5ae1..48e815dda0483 100644 --- a/tests/codegen/pgo-counter-bias.rs +++ b/tests/codegen/pgo-counter-bias.rs @@ -2,7 +2,7 @@ //@ ignore-apple -runtime-counter-relocation not honored on Mach-O //@ compile-flags: -Cprofile-generate -Cllvm-args=-runtime-counter-relocation -Clto=fat -//@ needs-profiler-support +//@ compile-flags: -Zno-profiler-runtime //@ no-prefer-dynamic // CHECK: @__llvm_profile_counter_bias = {{.*}}global diff --git a/tests/codegen/pgo-instrumentation.rs b/tests/codegen/pgo-instrumentation.rs index b1906c145c6be..a8f12ccce1cb4 100644 --- a/tests/codegen/pgo-instrumentation.rs +++ b/tests/codegen/pgo-instrumentation.rs @@ -1,6 +1,6 @@ // Test that `-Cprofile-generate` creates expected instrumentation artifacts in LLVM IR. -//@ needs-profiler-support +//@ compile-flags: -Zno-profiler-runtime //@ compile-flags: -Cprofile-generate -Ccodegen-units=1 // CHECK: @__llvm_profile_raw_version = diff --git a/tests/codegen/slice-pointer-nonnull-unwrap.rs b/tests/codegen/slice-pointer-nonnull-unwrap.rs new file mode 100644 index 0000000000000..2c4a959685f96 --- /dev/null +++ b/tests/codegen/slice-pointer-nonnull-unwrap.rs @@ -0,0 +1,19 @@ +//@ compile-flags: -O +//@ min-llvm-version: 18 +#![crate_type = "lib"] + +use std::ptr::NonNull; + +// CHECK-LABEL: @slice_ptr_len_1 +// CHECK-NEXT: {{.*}}: +// CHECK-NEXT: ret {{i(32|64)}} %ptr.1 +#[no_mangle] +pub fn slice_ptr_len_1(ptr: *const [u8]) -> usize { + let ptr = ptr.cast_mut(); + if let Some(ptr) = NonNull::new(ptr) { + ptr.len() + } else { + // We know ptr is null, so we know ptr.wrapping_byte_add(1) is not null. + NonNull::new(ptr.wrapping_byte_add(1)).unwrap().len() + } +} diff --git a/tests/crashes/109812.rs b/tests/crashes/109812.rs deleted file mode 100644 index c29b874652153..0000000000000 --- a/tests/crashes/109812.rs +++ /dev/null @@ -1,22 +0,0 @@ -//@ known-bug: #109812 - -#![warn(rust_2021_incompatible_closure_captures)] - -enum Either { - One(X), - Two(X), -} - -struct X(Y); - -struct Y; - -fn move_into_fnmut() { - let x = X(Y); - - consume_fnmut(|| { - let Either::Two(ref mut _t) = x; - - let X(mut _t) = x; - }); -} diff --git a/tests/crashes/124583.rs b/tests/crashes/124583.rs deleted file mode 100644 index ffd9d7521add2..0000000000000 --- a/tests/crashes/124583.rs +++ /dev/null @@ -1,5 +0,0 @@ -//@ known-bug: rust-lang/rust#124583 - -fn main() { - let _ = -(-0.0f16); -} diff --git a/tests/crashes/125811.rs b/tests/crashes/125811.rs deleted file mode 100644 index eb764e8d15228..0000000000000 --- a/tests/crashes/125811.rs +++ /dev/null @@ -1,34 +0,0 @@ -//@ known-bug: rust-lang/rust#125811 -mod assert { - use std::mem::{Assume, BikeshedIntrinsicFrom}; - - pub fn is_transmutable() - where - Dst: BikeshedIntrinsicFrom, - { - } -} - -#[repr(C)] -struct Zst; - -enum V0 { - B(!), -} - -enum V2 { - V = 2, -} - -enum Lopsided { - Smol(Zst), - Lorg(V0), -} - -#[repr(C)] -#[repr(C)] -struct Dst(Lopsided, V2); - -fn should_pad_variants() { - assert::is_transmutable::(); -} diff --git a/tests/crashes/125914.rs b/tests/crashes/125914.rs deleted file mode 100644 index 77ccb9fb0978d..0000000000000 --- a/tests/crashes/125914.rs +++ /dev/null @@ -1,20 +0,0 @@ -//@ known-bug: rust-lang/rust#125914 -enum AstKind<'ast> { - ExprInt, -} - -enum Foo { - Bar(isize), - Baz, -} - -enum Other { - Other1(Foo), - Other2(AstKind), -} - -fn main() { - match Other::Other1(Foo::Baz) { - ::Other::Other2(::Foo::Bar(..)) => {} - } -} diff --git a/tests/crashes/126062.rs b/tests/crashes/126062.rs new file mode 100644 index 0000000000000..9f1bec1d46e40 --- /dev/null +++ b/tests/crashes/126062.rs @@ -0,0 +1,11 @@ +//@ known-bug: rust-lang/rust#126062 +struct Fail(Fail); +impl Fail { + const C: () = panic!(); +} + +fn f() { + if false { + let _val = &Fail::::C; + } +} diff --git a/tests/crashes/126148.rs b/tests/crashes/126148.rs new file mode 100644 index 0000000000000..79f8887b40154 --- /dev/null +++ b/tests/crashes/126148.rs @@ -0,0 +1,23 @@ +//@ known-bug: rust-lang/rust#126148 + +#![feature(effects)] +use std::ops::{FromResidual, Try}; + +struct TryMe; +struct Error; + +impl const FromResidual for TryMe {} + +impl const Try for TryMe { + type Output = (); + type Residual = Error; +} + +const fn t() -> TryMe { + TryMe?; + TryMe +} + +const _: () = { + t(); +}; diff --git a/tests/crashes/126182.rs b/tests/crashes/126182.rs new file mode 100644 index 0000000000000..2219a6cb5fa19 --- /dev/null +++ b/tests/crashes/126182.rs @@ -0,0 +1,10 @@ +//@ known-bug: rust-lang/rust#126182 + +#![feature(generic_const_exprs)] +#![allow(incomplete_features)] + +struct Cond; + +struct Thing>(T); + +impl Thing {} diff --git a/tests/crashes/126267.rs b/tests/crashes/126267.rs new file mode 100644 index 0000000000000..c0604b90a6701 --- /dev/null +++ b/tests/crashes/126267.rs @@ -0,0 +1,30 @@ +//@ known-bug: rust-lang/rust#126267 + +#![feature(transmutability)] +#![crate_type = "lib"] + +pub enum ApiError {} +pub struct TokioError { + b: bool, +} +pub enum Error { + Api { source: ApiError }, + Ethereum, + Tokio { source: TokioError }, +} + +mod assert { + use std::mem::BikeshedIntrinsicFrom; + + pub fn is_transmutable() + where + Dst: BikeshedIntrinsicFrom, // safety is NOT assumed + { + } +} + +fn test() { + struct Src; + type Dst = Error; + assert::is_transmutable::(); +} diff --git a/tests/crashes/126269.rs b/tests/crashes/126269.rs new file mode 100644 index 0000000000000..ca4b76eb930d1 --- /dev/null +++ b/tests/crashes/126269.rs @@ -0,0 +1,12 @@ +//@ known-bug: rust-lang/rust#126269 +#![feature(coerce_unsized)] + +pub enum Foo { + Bar([T; usize::MAX]), +} + +use std::ops::CoerceUnsized; + +impl CoerceUnsized for T {} + +fn main() {} diff --git a/tests/crashes/126272.rs b/tests/crashes/126272.rs new file mode 100644 index 0000000000000..3412c7d8f0f41 --- /dev/null +++ b/tests/crashes/126272.rs @@ -0,0 +1,28 @@ +//@ known-bug: rust-lang/rust#126272 + +#![feature(adt_const_params)] +#![allow(incomplete_features)] + +use std::marker::ConstParamTy; + +#[derive(Debug, PartialEq, Eq, ConstParamTy)] +struct Foo { + value: i32, + nested: &'static Bar, +} + +#[derive(Debug, PartialEq, Eq, ConstParamTy)] +struct Bar(T); + +struct Test; + +fn main() { + let x: Test< + { + Foo { + value: 3, + nested: &Bar(4), + } + }, + > = Test; +} diff --git a/tests/crashes/126359.rs b/tests/crashes/126359.rs new file mode 100644 index 0000000000000..4b28c466b55c3 --- /dev/null +++ b/tests/crashes/126359.rs @@ -0,0 +1,9 @@ +//@ known-bug: rust-lang/rust#126359 + +struct OppOrder { + arr: [T; N], +} + +fn main() { + let _ = OppOrder::<3, u32> { arr: [0, 0, 0] }; +} diff --git a/tests/crashes/126376.rs b/tests/crashes/126376.rs new file mode 100644 index 0000000000000..028dde6d438e3 --- /dev/null +++ b/tests/crashes/126376.rs @@ -0,0 +1,14 @@ +//@ known-bug: rust-lang/rust#126376 +mod a { + pub mod b { + pub mod c { + pub trait D {} + } + } +} + +use a::*; +use e as b; +use b::c::D as e; + +fn e() {} diff --git a/tests/crashes/126377.rs b/tests/crashes/126377.rs new file mode 100644 index 0000000000000..f8b9b693b6550 --- /dev/null +++ b/tests/crashes/126377.rs @@ -0,0 +1,29 @@ +//@ known-bug: rust-lang/rust#126377 + +#![feature(effects)] +#![feature(generic_const_exprs)] + +mod assert { + use std::mem::{Assume, BikeshedIntrinsicFrom}; + + pub fn is_transmutable< + Src, + Dst, + const ASSUME_ALIGNMENT: bool, + const ASSUME_LIFETIMES: bool, + const ASSUME_SAFETY: bool, + const ASSUME_VALIDITY: bool, + >() + where + Dst: BikeshedIntrinsicFrom< + Src, + { } + >, + {} +} + +const fn from_options() -> Assume { + #[repr(C)] struct Src; + #[repr(C)] struct Dst; + assert::is_transmutable::(); +} diff --git a/tests/crashes/126385.rs b/tests/crashes/126385.rs new file mode 100644 index 0000000000000..9e74e88c1ffe1 --- /dev/null +++ b/tests/crashes/126385.rs @@ -0,0 +1,10 @@ +//@ known-bug: rust-lang/rust#126385 +pub struct MyStruct<'field> { + field: &'_ [u32], +} + +impl MyStruct<'_> { + pub fn _<'a>(field: &'a[u32]) -> Self { + Self{field} + } +} diff --git a/tests/crashes/126389.rs b/tests/crashes/126389.rs new file mode 100644 index 0000000000000..7aa6ecad9a31c --- /dev/null +++ b/tests/crashes/126389.rs @@ -0,0 +1,15 @@ +//@ known-bug: rust-lang/rust#126389 + +mod a { + pub mod b { + pub mod c {} + } +} + +use a::*; + +use b::c; + +use c as b; + +fn c() {} diff --git a/tests/crashes/126416.rs b/tests/crashes/126416.rs new file mode 100644 index 0000000000000..9b6c5169d444e --- /dev/null +++ b/tests/crashes/126416.rs @@ -0,0 +1,20 @@ +//@ known-bug: rust-lang/rust#126416 + +trait Output<'a, T: 'a> { + type Type; +} + +struct Wrapper; + +impl Wrapper { + fn do_something_wrapper(&mut self, _: F) + where + F: for<'a> FnOnce(>::Type), + { + } +} + +fn main() { + let mut wrapper = Wrapper; + wrapper.do_something_wrapper(|value| ()); +} diff --git a/tests/crashes/126521.rs b/tests/crashes/126521.rs new file mode 100644 index 0000000000000..0a025aabcf2ee --- /dev/null +++ b/tests/crashes/126521.rs @@ -0,0 +1,11 @@ +//@ known-bug: rust-lang/rust#126521 +macro_rules! foo { + ($val:ident) => { + true; + }; +} + +fn main() { + #[expect(semicolon_in_expressions_from_macros)] + let _ = foo!(x); +} diff --git a/tests/debuginfo/collapse-debuginfo-static-external.rs b/tests/debuginfo/collapse-debuginfo-static-external.rs new file mode 100644 index 0000000000000..2209bb9bd9481 --- /dev/null +++ b/tests/debuginfo/collapse-debuginfo-static-external.rs @@ -0,0 +1,24 @@ +//@ ignore-lldb + +// Test that static debug info is not collapsed with #[collapse_debuginfo(external)] + +//@ compile-flags:-g + +// === GDB TESTS =================================================================================== + +// gdb-command:info line collapse_debuginfo_static_external::FOO +// gdb-check:[...]Line 15[...] + +#[collapse_debuginfo(external)] +macro_rules! decl_foo { + () => { + static FOO: u32 = 0; + }; +} + +decl_foo!(); + +fn main() { + // prevent FOO from getting optimized out + std::hint::black_box(&FOO); +} diff --git a/tests/debuginfo/collapse-debuginfo-static.rs b/tests/debuginfo/collapse-debuginfo-static.rs new file mode 100644 index 0000000000000..e6469da4785e7 --- /dev/null +++ b/tests/debuginfo/collapse-debuginfo-static.rs @@ -0,0 +1,24 @@ +//@ ignore-lldb + +// Test that static debug info is collapsed with #[collapse_debuginfo(yes)] + +//@ compile-flags:-g + +// === GDB TESTS =================================================================================== + +// gdb-command:info line collapse_debuginfo_static::FOO +// gdb-check:[...]Line 19[...] + +#[collapse_debuginfo(yes)] +macro_rules! decl_foo { + () => { + static FOO: u32 = 0; + }; +} + +decl_foo!(); + +fn main() { + // prevent FOO from getting optimized out + std::hint::black_box(&FOO); +} diff --git a/tests/mir-opt/pre-codegen/slice_index.rs b/tests/mir-opt/pre-codegen/slice_index.rs index 04bbbff57b34b..886e57a3380c1 100644 --- a/tests/mir-opt/pre-codegen/slice_index.rs +++ b/tests/mir-opt/pre-codegen/slice_index.rs @@ -1,5 +1,4 @@ -// skip-filecheck -//@ compile-flags: -O -C debuginfo=0 -Zmir-opt-level=2 +//@ compile-flags: -O -C debuginfo=0 -Zmir-opt-level=2 -Z ub-checks=yes // EMIT_MIR_FOR_EACH_PANIC_STRATEGY #![crate_type = "lib"] @@ -9,21 +8,39 @@ use std::ops::Range; // EMIT_MIR slice_index.slice_index_usize.PreCodegen.after.mir pub fn slice_index_usize(slice: &[u32], index: usize) -> u32 { + // CHECK-LABEL: slice_index_usize + // CHECK: [[LEN:_[0-9]+]] = Len((*_1)) + // CHECK: Lt(_2, [[LEN]]) + // CHECK-NOT: precondition_check + // CHECK: _0 = (*_1)[_2]; slice[index] } // EMIT_MIR slice_index.slice_get_mut_usize.PreCodegen.after.mir pub fn slice_get_mut_usize(slice: &mut [u32], index: usize) -> Option<&mut u32> { + // CHECK-LABEL: slice_get_mut_usize + // CHECK: [[LEN:_[0-9]+]] = Len((*_1)) + // CHECK: Lt(_2, move [[LEN]]) + // CHECK-NOT: precondition_check slice.get_mut(index) } // EMIT_MIR slice_index.slice_index_range.PreCodegen.after.mir pub fn slice_index_range(slice: &[u32], index: Range) -> &[u32] { + // CHECK-LABEL: slice_index_range &slice[index] } // EMIT_MIR slice_index.slice_get_unchecked_mut_range.PreCodegen.after.mir pub unsafe fn slice_get_unchecked_mut_range(slice: &mut [u32], index: Range) -> &mut [u32] { + // CHECK-LABEL: slice_get_unchecked_mut_range + // CHECK: [[START:_[0-9]+]] = move (_2.0: usize); + // CHECK: [[END:_[0-9]+]] = move (_2.1: usize); + // CHECK: precondition_check + // CHECK: [[LEN:_[0-9]+]] = SubUnchecked([[END]], [[START]]); + // CHECK: [[PTR:_[0-9]+]] = Offset({{_[0-9]+}}, [[START]]); + // CHECK: [[SLICE:_[0-9]+]] = *mut [u32] from ([[PTR]], [[LEN]]) + // CHECK: _0 = &mut (*[[SLICE]]); slice.get_unchecked_mut(index) } @@ -32,5 +49,12 @@ pub unsafe fn slice_ptr_get_unchecked_range( slice: *const [u32], index: Range, ) -> *const [u32] { + // CHECK-LABEL: slice_ptr_get_unchecked_range + // CHECK: [[START:_[0-9]+]] = move (_2.0: usize); + // CHECK: [[END:_[0-9]+]] = move (_2.1: usize); + // CHECK: precondition_check + // CHECK: [[LEN:_[0-9]+]] = SubUnchecked([[END]], [[START]]); + // CHECK: [[PTR:_[0-9]+]] = Offset({{_[0-9]+}}, [[START]]); + // CHECK: _0 = *const [u32] from ([[PTR]], [[LEN]]) slice.get_unchecked(index) } diff --git a/tests/mir-opt/pre-codegen/slice_index.slice_get_mut_usize.PreCodegen.after.panic-abort.mir b/tests/mir-opt/pre-codegen/slice_index.slice_get_mut_usize.PreCodegen.after.panic-abort.mir index 7e20817cf2301..f2ef2b0cc3c6c 100644 --- a/tests/mir-opt/pre-codegen/slice_index.slice_get_mut_usize.PreCodegen.after.panic-abort.mir +++ b/tests/mir-opt/pre-codegen/slice_index.slice_get_mut_usize.PreCodegen.after.panic-abort.mir @@ -5,13 +5,54 @@ fn slice_get_mut_usize(_1: &mut [u32], _2: usize) -> Option<&mut u32> { debug index => _2; let mut _0: std::option::Option<&mut u32>; scope 1 (inlined core::slice::::get_mut::) { + scope 2 (inlined >::get_mut) { + let mut _3: usize; + let mut _4: bool; + let mut _5: *mut [u32]; + let mut _7: *mut u32; + let mut _8: &mut u32; + scope 3 (inlined core::slice::index::get_mut_noubcheck::) { + let _6: *mut u32; + scope 4 { + } + } + } } bb0: { - _0 = >::get_mut(move _2, move _1) -> [return: bb1, unwind unreachable]; + StorageLive(_7); + StorageLive(_4); + StorageLive(_3); + _3 = Len((*_1)); + _4 = Lt(_2, move _3); + switchInt(move _4) -> [0: bb1, otherwise: bb2]; } bb1: { + StorageDead(_3); + _0 = const Option::<&mut u32>::None; + goto -> bb3; + } + + bb2: { + StorageDead(_3); + StorageLive(_8); + StorageLive(_5); + _5 = &raw mut (*_1); + StorageLive(_6); + _6 = _5 as *mut u32 (PtrToPtr); + _7 = Offset(_6, _2); + StorageDead(_6); + StorageDead(_5); + _8 = &mut (*_7); + _0 = Option::<&mut u32>::Some(move _8); + StorageDead(_8); + goto -> bb3; + } + + bb3: { + StorageDead(_4); + StorageDead(_7); return; } } diff --git a/tests/mir-opt/pre-codegen/slice_index.slice_get_mut_usize.PreCodegen.after.panic-unwind.mir b/tests/mir-opt/pre-codegen/slice_index.slice_get_mut_usize.PreCodegen.after.panic-unwind.mir index 2f65b8c640170..f2ef2b0cc3c6c 100644 --- a/tests/mir-opt/pre-codegen/slice_index.slice_get_mut_usize.PreCodegen.after.panic-unwind.mir +++ b/tests/mir-opt/pre-codegen/slice_index.slice_get_mut_usize.PreCodegen.after.panic-unwind.mir @@ -5,13 +5,54 @@ fn slice_get_mut_usize(_1: &mut [u32], _2: usize) -> Option<&mut u32> { debug index => _2; let mut _0: std::option::Option<&mut u32>; scope 1 (inlined core::slice::::get_mut::) { + scope 2 (inlined >::get_mut) { + let mut _3: usize; + let mut _4: bool; + let mut _5: *mut [u32]; + let mut _7: *mut u32; + let mut _8: &mut u32; + scope 3 (inlined core::slice::index::get_mut_noubcheck::) { + let _6: *mut u32; + scope 4 { + } + } + } } bb0: { - _0 = >::get_mut(move _2, move _1) -> [return: bb1, unwind continue]; + StorageLive(_7); + StorageLive(_4); + StorageLive(_3); + _3 = Len((*_1)); + _4 = Lt(_2, move _3); + switchInt(move _4) -> [0: bb1, otherwise: bb2]; } bb1: { + StorageDead(_3); + _0 = const Option::<&mut u32>::None; + goto -> bb3; + } + + bb2: { + StorageDead(_3); + StorageLive(_8); + StorageLive(_5); + _5 = &raw mut (*_1); + StorageLive(_6); + _6 = _5 as *mut u32 (PtrToPtr); + _7 = Offset(_6, _2); + StorageDead(_6); + StorageDead(_5); + _8 = &mut (*_7); + _0 = Option::<&mut u32>::Some(move _8); + StorageDead(_8); + goto -> bb3; + } + + bb3: { + StorageDead(_4); + StorageDead(_7); return; } } diff --git a/tests/mir-opt/pre-codegen/slice_index.slice_get_unchecked_mut_range.PreCodegen.after.panic-abort.mir b/tests/mir-opt/pre-codegen/slice_index.slice_get_unchecked_mut_range.PreCodegen.after.panic-abort.mir index ef3f4a2172005..5e0398d11147f 100644 --- a/tests/mir-opt/pre-codegen/slice_index.slice_get_unchecked_mut_range.PreCodegen.after.panic-abort.mir +++ b/tests/mir-opt/pre-codegen/slice_index.slice_get_unchecked_mut_range.PreCodegen.after.panic-abort.mir @@ -4,20 +4,62 @@ fn slice_get_unchecked_mut_range(_1: &mut [u32], _2: std::ops::Range) -> debug slice => _1; debug index => _2; let mut _0: &mut [u32]; + let mut _3: usize; + let mut _4: usize; scope 1 (inlined core::slice::::get_unchecked_mut::>) { - let mut _3: *mut [u32]; - let mut _4: *mut [u32]; + let mut _5: *mut [u32]; + let mut _12: *mut [u32]; + scope 2 (inlined as SliceIndex<[u32]>>::get_unchecked_mut) { + let mut _7: usize; + let _8: (); + let _9: usize; + scope 3 { + scope 6 (inlined core::slice::index::get_offset_len_mut_noubcheck::) { + let _11: *mut u32; + scope 7 { + } + scope 8 (inlined core::slice::index::get_mut_noubcheck::) { + let _10: *mut u32; + scope 9 { + } + } + } + } + scope 4 (inlined std::ptr::mut_ptr::::len) { + let mut _6: *const [u32]; + scope 5 (inlined std::ptr::metadata::<[u32]>) { + } + } + } } bb0: { - StorageLive(_3); - _3 = &raw mut (*_1); - _4 = as SliceIndex<[u32]>>::get_unchecked_mut(move _2, move _3) -> [return: bb1, unwind unreachable]; + _3 = move (_2.0: usize); + _4 = move (_2.1: usize); + StorageLive(_5); + _5 = &raw mut (*_1); + StorageLive(_9); + StorageLive(_7); + StorageLive(_6); + _6 = _5 as *const [u32] (PointerCoercion(MutToConstPointer)); + _7 = PtrMetadata(_6); + StorageDead(_6); + _8 = as SliceIndex<[T]>>::get_unchecked_mut::precondition_check(_3, _4, move _7) -> [return: bb1, unwind unreachable]; } bb1: { - StorageDead(_3); - _0 = &mut (*_4); + StorageDead(_7); + _9 = SubUnchecked(_4, _3); + StorageLive(_11); + StorageLive(_10); + _10 = _5 as *mut u32 (PtrToPtr); + _11 = Offset(_10, _3); + StorageDead(_10); + _12 = *mut [u32] from (_11, _9); + StorageDead(_11); + StorageDead(_9); + StorageDead(_5); + _0 = &mut (*_12); return; } } diff --git a/tests/mir-opt/pre-codegen/slice_index.slice_get_unchecked_mut_range.PreCodegen.after.panic-unwind.mir b/tests/mir-opt/pre-codegen/slice_index.slice_get_unchecked_mut_range.PreCodegen.after.panic-unwind.mir index 9e93a43ac725b..5e0398d11147f 100644 --- a/tests/mir-opt/pre-codegen/slice_index.slice_get_unchecked_mut_range.PreCodegen.after.panic-unwind.mir +++ b/tests/mir-opt/pre-codegen/slice_index.slice_get_unchecked_mut_range.PreCodegen.after.panic-unwind.mir @@ -4,20 +4,62 @@ fn slice_get_unchecked_mut_range(_1: &mut [u32], _2: std::ops::Range) -> debug slice => _1; debug index => _2; let mut _0: &mut [u32]; + let mut _3: usize; + let mut _4: usize; scope 1 (inlined core::slice::::get_unchecked_mut::>) { - let mut _3: *mut [u32]; - let mut _4: *mut [u32]; + let mut _5: *mut [u32]; + let mut _12: *mut [u32]; + scope 2 (inlined as SliceIndex<[u32]>>::get_unchecked_mut) { + let mut _7: usize; + let _8: (); + let _9: usize; + scope 3 { + scope 6 (inlined core::slice::index::get_offset_len_mut_noubcheck::) { + let _11: *mut u32; + scope 7 { + } + scope 8 (inlined core::slice::index::get_mut_noubcheck::) { + let _10: *mut u32; + scope 9 { + } + } + } + } + scope 4 (inlined std::ptr::mut_ptr::::len) { + let mut _6: *const [u32]; + scope 5 (inlined std::ptr::metadata::<[u32]>) { + } + } + } } bb0: { - StorageLive(_3); - _3 = &raw mut (*_1); - _4 = as SliceIndex<[u32]>>::get_unchecked_mut(move _2, move _3) -> [return: bb1, unwind continue]; + _3 = move (_2.0: usize); + _4 = move (_2.1: usize); + StorageLive(_5); + _5 = &raw mut (*_1); + StorageLive(_9); + StorageLive(_7); + StorageLive(_6); + _6 = _5 as *const [u32] (PointerCoercion(MutToConstPointer)); + _7 = PtrMetadata(_6); + StorageDead(_6); + _8 = as SliceIndex<[T]>>::get_unchecked_mut::precondition_check(_3, _4, move _7) -> [return: bb1, unwind unreachable]; } bb1: { - StorageDead(_3); - _0 = &mut (*_4); + StorageDead(_7); + _9 = SubUnchecked(_4, _3); + StorageLive(_11); + StorageLive(_10); + _10 = _5 as *mut u32 (PtrToPtr); + _11 = Offset(_10, _3); + StorageDead(_10); + _12 = *mut [u32] from (_11, _9); + StorageDead(_11); + StorageDead(_9); + StorageDead(_5); + _0 = &mut (*_12); return; } } diff --git a/tests/mir-opt/pre-codegen/slice_index.slice_ptr_get_unchecked_range.PreCodegen.after.panic-abort.mir b/tests/mir-opt/pre-codegen/slice_index.slice_ptr_get_unchecked_range.PreCodegen.after.panic-abort.mir index 650069ee6cea3..c61bebe6cc3c0 100644 --- a/tests/mir-opt/pre-codegen/slice_index.slice_ptr_get_unchecked_range.PreCodegen.after.panic-abort.mir +++ b/tests/mir-opt/pre-codegen/slice_index.slice_ptr_get_unchecked_range.PreCodegen.after.panic-abort.mir @@ -4,14 +4,52 @@ fn slice_ptr_get_unchecked_range(_1: *const [u32], _2: std::ops::Range) - debug slice => _1; debug index => _2; let mut _0: *const [u32]; + let mut _3: usize; + let mut _4: usize; scope 1 (inlined std::ptr::const_ptr::::get_unchecked::>) { + scope 2 (inlined as SliceIndex<[u32]>>::get_unchecked) { + let mut _5: usize; + let _6: (); + let _7: usize; + scope 3 { + scope 6 (inlined core::slice::index::get_offset_len_noubcheck::) { + let _9: *const u32; + scope 7 { + } + scope 8 (inlined core::slice::index::get_noubcheck::) { + let _8: *const u32; + scope 9 { + } + } + } + } + scope 4 (inlined std::ptr::const_ptr::::len) { + scope 5 (inlined std::ptr::metadata::<[u32]>) { + } + } + } } bb0: { - _0 = as SliceIndex<[u32]>>::get_unchecked(move _2, move _1) -> [return: bb1, unwind unreachable]; + _3 = move (_2.0: usize); + _4 = move (_2.1: usize); + StorageLive(_7); + StorageLive(_5); + _5 = PtrMetadata(_1); + _6 = as SliceIndex<[T]>>::get_unchecked::precondition_check(_3, _4, move _5) -> [return: bb1, unwind unreachable]; } bb1: { + StorageDead(_5); + _7 = SubUnchecked(_4, _3); + StorageLive(_9); + StorageLive(_8); + _8 = _1 as *const u32 (PtrToPtr); + _9 = Offset(_8, _3); + StorageDead(_8); + _0 = *const [u32] from (_9, _7); + StorageDead(_9); + StorageDead(_7); return; } } diff --git a/tests/mir-opt/pre-codegen/slice_index.slice_ptr_get_unchecked_range.PreCodegen.after.panic-unwind.mir b/tests/mir-opt/pre-codegen/slice_index.slice_ptr_get_unchecked_range.PreCodegen.after.panic-unwind.mir index 74e8158e75430..c61bebe6cc3c0 100644 --- a/tests/mir-opt/pre-codegen/slice_index.slice_ptr_get_unchecked_range.PreCodegen.after.panic-unwind.mir +++ b/tests/mir-opt/pre-codegen/slice_index.slice_ptr_get_unchecked_range.PreCodegen.after.panic-unwind.mir @@ -4,14 +4,52 @@ fn slice_ptr_get_unchecked_range(_1: *const [u32], _2: std::ops::Range) - debug slice => _1; debug index => _2; let mut _0: *const [u32]; + let mut _3: usize; + let mut _4: usize; scope 1 (inlined std::ptr::const_ptr::::get_unchecked::>) { + scope 2 (inlined as SliceIndex<[u32]>>::get_unchecked) { + let mut _5: usize; + let _6: (); + let _7: usize; + scope 3 { + scope 6 (inlined core::slice::index::get_offset_len_noubcheck::) { + let _9: *const u32; + scope 7 { + } + scope 8 (inlined core::slice::index::get_noubcheck::) { + let _8: *const u32; + scope 9 { + } + } + } + } + scope 4 (inlined std::ptr::const_ptr::::len) { + scope 5 (inlined std::ptr::metadata::<[u32]>) { + } + } + } } bb0: { - _0 = as SliceIndex<[u32]>>::get_unchecked(move _2, move _1) -> [return: bb1, unwind continue]; + _3 = move (_2.0: usize); + _4 = move (_2.1: usize); + StorageLive(_7); + StorageLive(_5); + _5 = PtrMetadata(_1); + _6 = as SliceIndex<[T]>>::get_unchecked::precondition_check(_3, _4, move _5) -> [return: bb1, unwind unreachable]; } bb1: { + StorageDead(_5); + _7 = SubUnchecked(_4, _3); + StorageLive(_9); + StorageLive(_8); + _8 = _1 as *const u32 (PtrToPtr); + _9 = Offset(_8, _3); + StorageDead(_8); + _0 = *const [u32] from (_9, _7); + StorageDead(_9); + StorageDead(_7); return; } } diff --git a/tests/run-make/allow-non-lint-warnings-cmdline/Makefile b/tests/run-make/allow-non-lint-warnings-cmdline/Makefile deleted file mode 100644 index 78b9a7b989895..0000000000000 --- a/tests/run-make/allow-non-lint-warnings-cmdline/Makefile +++ /dev/null @@ -1,12 +0,0 @@ -# ignore-cross-compile -include ../tools.mk - -# Test that -A warnings makes the 'empty trait list for derive' warning go away -OUT=$(shell $(RUSTC) foo.rs -A warnings 2>&1 | grep "warning" ) - -all: foo - test -z '$(OUT)' - -# This is just to make sure the above command actually succeeds -foo: - $(RUSTC) foo.rs -A warnings diff --git a/tests/run-make/codegen-options-parsing/Makefile b/tests/run-make/codegen-options-parsing/Makefile deleted file mode 100644 index beaf233502bb7..0000000000000 --- a/tests/run-make/codegen-options-parsing/Makefile +++ /dev/null @@ -1,34 +0,0 @@ -# This test intentionally feeds invalid inputs to codegen and checks if the error message outputs contain specific helpful indications. - -# ignore-cross-compile -include ../tools.mk - -all: - #Option taking a number - $(RUSTC) -C codegen-units dummy.rs 2>&1 | \ - $(CGREP) 'codegen option `codegen-units` requires a number' - $(RUSTC) -C codegen-units= dummy.rs 2>&1 | \ - $(CGREP) 'incorrect value `` for codegen option `codegen-units` - a number was expected' - $(RUSTC) -C codegen-units=foo dummy.rs 2>&1 | \ - $(CGREP) 'incorrect value `foo` for codegen option `codegen-units` - a number was expected' - $(RUSTC) -C codegen-units=1 dummy.rs - #Option taking a string - $(RUSTC) -C extra-filename dummy.rs 2>&1 | \ - $(CGREP) 'codegen option `extra-filename` requires a string' - $(RUSTC) -C extra-filename= dummy.rs 2>&1 - $(RUSTC) -C extra-filename=foo dummy.rs 2>&1 - #Option taking no argument - $(RUSTC) -C lto= dummy.rs 2>&1 | \ - $(CGREP) 'codegen option `lto` - either a boolean (`yes`, `no`, `on`, `off`, etc), `thin`, `fat`, or omitted' - $(RUSTC) -C lto=1 dummy.rs 2>&1 | \ - $(CGREP) 'codegen option `lto` - either a boolean (`yes`, `no`, `on`, `off`, etc), `thin`, `fat`, or omitted' - $(RUSTC) -C lto=foo dummy.rs 2>&1 | \ - $(CGREP) 'codegen option `lto` - either a boolean (`yes`, `no`, `on`, `off`, etc), `thin`, `fat`, or omitted' - $(RUSTC) -C lto dummy.rs - - # Should not link dead code... - $(RUSTC) --print link-args dummy.rs 2>&1 | \ - $(CGREP) -e '--gc-sections|-z[^ ]* [^ ]*|-dead_strip|/OPT:REF' - # ... unless you specifically ask to keep it - $(RUSTC) --print link-args -C link-dead-code dummy.rs 2>&1 | \ - $(CGREP) -ve '--gc-sections|-z[^ ]* [^ ]*|-dead_strip|/OPT:REF' diff --git a/tests/run-make/codegen-options-parsing/rmake.rs b/tests/run-make/codegen-options-parsing/rmake.rs new file mode 100644 index 0000000000000..c78b41a88dc69 --- /dev/null +++ b/tests/run-make/codegen-options-parsing/rmake.rs @@ -0,0 +1,56 @@ +// This test intentionally feeds invalid inputs to codegen and checks if the error message outputs +// contain specific helpful indications. + +//@ ignore-cross-compile + +use run_make_support::regex::Regex; +use run_make_support::rustc; + +fn main() { + // Option taking a number. + rustc() + .input("dummy.rs") + .arg("-Ccodegen-units") + .run_fail() + .assert_stderr_contains("codegen option `codegen-units` requires a number"); + rustc().input("dummy.rs").arg("-Ccodegen-units=").run_fail().assert_stderr_contains( + "incorrect value `` for codegen option `codegen-units` - a number was expected", + ); + rustc().input("dummy.rs").arg("-Ccodegen-units=foo").run_fail().assert_stderr_contains( + "incorrect value `foo` for codegen option `codegen-units` - a number was expected", + ); + rustc().input("dummy.rs").arg("-Ccodegen-units=1").run(); + + // Option taking a string. + rustc() + .input("dummy.rs") + .arg("-Cextra-filename") + .run_fail() + .assert_stderr_contains("codegen option `extra-filename` requires a string"); + rustc().input("dummy.rs").arg("-Cextra-filename=").run(); + rustc().input("dummy.rs").arg("-Cextra-filename=foo").run(); + + // Option taking no argument. + rustc().input("dummy.rs").arg("-Clto=").run_fail().assert_stderr_contains( + "codegen option `lto` - either a boolean (`yes`, `no`, `on`, `off`, etc), `thin`, \ + `fat`, or omitted", + ); + rustc().input("dummy.rs").arg("-Clto=1").run_fail().assert_stderr_contains( + "codegen option `lto` - either a boolean (`yes`, `no`, `on`, `off`, etc), `thin`, \ + `fat`, or omitted", + ); + rustc().input("dummy.rs").arg("-Clto=foo").run_fail().assert_stderr_contains( + "codegen option `lto` - either a boolean (`yes`, `no`, `on`, `off`, etc), `thin`, \ + `fat`, or omitted", + ); + rustc().input("dummy.rs").arg("-Clto").run(); + + let regex = Regex::new("--gc-sections|-z[^ ]* [^ ]*|-dead_strip|/OPT:REF").unwrap(); + // Should not link dead code... + let stdout = rustc().input("dummy.rs").print("link-args").run().stdout_utf8(); + assert!(regex.is_match(&stdout)); + // ... unless you specifically ask to keep it + let stdout = + rustc().input("dummy.rs").print("link-args").arg("-Clink-dead-code").run().stdout_utf8(); + assert!(!regex.is_match(&stdout)); +} diff --git a/tests/run-make/const_fn_mir/Makefile b/tests/run-make/const_fn_mir/Makefile deleted file mode 100644 index 3399446130d74..0000000000000 --- a/tests/run-make/const_fn_mir/Makefile +++ /dev/null @@ -1,6 +0,0 @@ -# needs-unwind -Cpanic=abort gives different MIR output -include ../tools.mk - -all: - $(RUSTC) main.rs --emit=mir -o "$(TMPDIR)"/dump.mir - $(RUSTC_TEST_OP) "$(TMPDIR)"/dump.mir dump.mir diff --git a/tests/run-make/const_fn_mir/rmake.rs b/tests/run-make/const_fn_mir/rmake.rs new file mode 100644 index 0000000000000..a4cc4299b1b01 --- /dev/null +++ b/tests/run-make/const_fn_mir/rmake.rs @@ -0,0 +1,8 @@ +// The `needs-unwind -Cpanic=abort` gives a different MIR output. + +use run_make_support::{cwd, diff, rustc}; + +fn main() { + rustc().input("main.rs").emit("mir").output("dump-actual.mir").run(); + diff().expected_file("dump.mir").actual_file("dump-actual.mir").run(); +} diff --git a/tests/run-make/dep-graph/Makefile b/tests/run-make/dep-graph/Makefile deleted file mode 100644 index d06333f4454b0..0000000000000 --- a/tests/run-make/dep-graph/Makefile +++ /dev/null @@ -1,12 +0,0 @@ -include ../tools.mk - -# ignore-cross-compile - -# Just verify that we successfully run and produce dep graphs when requested. - -all: - RUST_DEP_GRAPH=$(TMPDIR)/dep-graph $(RUSTC) \ - -Cincremental=$(TMPDIR)/incr \ - -Zquery-dep-graph -Zdump-dep-graph foo.rs - test -f $(TMPDIR)/dep-graph.txt - test -f $(TMPDIR)/dep-graph.dot diff --git a/tests/run-make/dep-graph/rmake.rs b/tests/run-make/dep-graph/rmake.rs new file mode 100644 index 0000000000000..351418997f1dd --- /dev/null +++ b/tests/run-make/dep-graph/rmake.rs @@ -0,0 +1,18 @@ +// Just verify that we successfully run and produce dep graphs when requested. + +//@ ignore-cross-compile + +use run_make_support::{path, rustc}; + +fn main() { + rustc() + .input("foo.rs") + .incremental(path("incr")) + .arg("-Zquery-dep-graph") + .arg("-Zdump-dep-graph") + .env("RUST_DEP_GRAPH", path("dep-graph")) + .run(); + + assert!(path("dep-graph.txt").is_file()); + assert!(path("dep-graph.dot").is_file()); +} diff --git a/tests/run-make/duplicate-output-flavors/Makefile b/tests/run-make/duplicate-output-flavors/Makefile deleted file mode 100644 index e33279966c971..0000000000000 --- a/tests/run-make/duplicate-output-flavors/Makefile +++ /dev/null @@ -1,5 +0,0 @@ -include ../tools.mk - -all: - $(RUSTC) --crate-type=rlib foo.rs - $(RUSTC) --crate-type=rlib,rlib foo.rs diff --git a/tests/run-make/duplicate-output-flavors/rmake.rs b/tests/run-make/duplicate-output-flavors/rmake.rs new file mode 100644 index 0000000000000..09545228807bc --- /dev/null +++ b/tests/run-make/duplicate-output-flavors/rmake.rs @@ -0,0 +1,6 @@ +use run_make_support::rustc; + +fn main() { + rustc().input("foo.rs").crate_type("rlib").run(); + rustc().input("foo.rs").crate_type("rlib,rlib").run(); +} diff --git a/tests/run-make/optimization-remarks-dir-pgo/Makefile b/tests/run-make/optimization-remarks-dir-pgo/Makefile index 3bc3d7d142887..57ffd6e70f00b 100644 --- a/tests/run-make/optimization-remarks-dir-pgo/Makefile +++ b/tests/run-make/optimization-remarks-dir-pgo/Makefile @@ -1,10 +1,6 @@ # needs-profiler-support -# ignore-windows-gnu # ignore-cross-compile -# FIXME(mati865): MinGW GCC miscompiles compiler-rt profiling library but with Clang it works -# properly. Since we only have GCC on the CI ignore the test for now. - include ../tools.mk PROFILE_DIR=$(TMPDIR)/profiles diff --git a/tests/run-make/pgo-branch-weights/rmake.rs b/tests/run-make/pgo-branch-weights/rmake.rs index 55f6e7e56c5ae..d3cb79c39afa9 100644 --- a/tests/run-make/pgo-branch-weights/rmake.rs +++ b/tests/run-make/pgo-branch-weights/rmake.rs @@ -10,10 +10,6 @@ //@ needs-profiler-support //@ ignore-cross-compile -// FIXME(Oneirical): This test has problems generating profdata on mingw. -// For more information, see https://github.com/rust-lang/rust/pull/122613 -//@ ignore-windows-gnu - use run_make_support::{fs_wrapper, llvm_filecheck, llvm_profdata, run_with_args, rustc}; use std::path::Path; diff --git a/tests/run-make/pgo-gen-lto/Makefile b/tests/run-make/pgo-gen-lto/Makefile index 8b647846af3b3..54164c995222a 100644 --- a/tests/run-make/pgo-gen-lto/Makefile +++ b/tests/run-make/pgo-gen-lto/Makefile @@ -1,10 +1,6 @@ # needs-profiler-support -# ignore-windows-gnu # ignore-cross-compile -# FIXME(mati865): MinGW GCC miscompiles compiler-rt profiling library but with Clang it works -# properly. Since we only have GCC on the CI ignore the test for now. - include ../tools.mk COMPILE_FLAGS=-Copt-level=3 -Clto=fat -Cprofile-generate="$(TMPDIR)" diff --git a/tests/run-make/pgo-gen-no-imp-symbols/Makefile b/tests/run-make/pgo-gen-no-imp-symbols/Makefile index 7f72b11b611ed..d2baa145ba506 100644 --- a/tests/run-make/pgo-gen-no-imp-symbols/Makefile +++ b/tests/run-make/pgo-gen-no-imp-symbols/Makefile @@ -1,8 +1,6 @@ -# needs-profiler-support - include ../tools.mk -COMPILE_FLAGS=-O -Ccodegen-units=1 -Cprofile-generate="$(TMPDIR)" +COMPILE_FLAGS=-O -Ccodegen-units=1 -Cprofile-generate="$(TMPDIR)" -Zno-profiler-runtime all: $(RUSTC) $(COMPILE_FLAGS) --emit=llvm-ir test.rs diff --git a/tests/run-make/pgo-gen/Makefile b/tests/run-make/pgo-gen/Makefile index bf32cfdb802f5..c1d456986fb28 100644 --- a/tests/run-make/pgo-gen/Makefile +++ b/tests/run-make/pgo-gen/Makefile @@ -1,10 +1,6 @@ # needs-profiler-support -# ignore-windows-gnu # ignore-cross-compile -# FIXME(mati865): MinGW GCC miscompiles compiler-rt profiling library but with Clang it works -# properly. Since we only have GCC on the CI ignore the test for now. - include ../tools.mk COMPILE_FLAGS=-g -Cprofile-generate="$(TMPDIR)" diff --git a/tests/run-make/pgo-indirect-call-promotion/Makefile b/tests/run-make/pgo-indirect-call-promotion/Makefile index 542eb244d3959..8d1e69c4aba37 100644 --- a/tests/run-make/pgo-indirect-call-promotion/Makefile +++ b/tests/run-make/pgo-indirect-call-promotion/Makefile @@ -1,10 +1,6 @@ # needs-profiler-support -# ignore-windows-gnu # ignore-cross-compile -# FIXME(mati865): MinGW GCC miscompiles compiler-rt profiling library but with Clang it works -# properly. Since we only have GCC on the CI ignore the test for now. - include ../tools.mk all: diff --git a/tests/run-make/pgo-use/Makefile b/tests/run-make/pgo-use/Makefile index 9f440118daee3..92098a4019c47 100644 --- a/tests/run-make/pgo-use/Makefile +++ b/tests/run-make/pgo-use/Makefile @@ -1,10 +1,6 @@ # needs-profiler-support -# ignore-windows-gnu # ignore-cross-compile -# FIXME(mati865): MinGW GCC miscompiles compiler-rt profiling library but with Clang it works -# properly. Since we only have GCC on the CI ignore the test for now. - include ../tools.mk # This test makes sure that PGO profiling data leads to cold functions being diff --git a/tests/run-make/symlinked-extern/Makefile b/tests/run-make/symlinked-extern/Makefile deleted file mode 100644 index 28c764b84e8b7..0000000000000 --- a/tests/run-make/symlinked-extern/Makefile +++ /dev/null @@ -1,12 +0,0 @@ -# ignore-cross-compile -include ../tools.mk - -# ignore-windows -# `ln` is actually `cp` on msys. - -all: - $(RUSTC) foo.rs - mkdir -p $(TMPDIR)/other - ln -nsf $(TMPDIR)/libfoo.rlib $(TMPDIR)/other - $(RUSTC) bar.rs -L $(TMPDIR) - $(RUSTC) baz.rs --extern foo=$(TMPDIR)/other/libfoo.rlib -L $(TMPDIR) diff --git a/tests/run-make/symlinked-extern/rmake.rs b/tests/run-make/symlinked-extern/rmake.rs new file mode 100644 index 0000000000000..98f69aefbe622 --- /dev/null +++ b/tests/run-make/symlinked-extern/rmake.rs @@ -0,0 +1,21 @@ +// Crates that are resolved normally have their path canonicalized and all +// symlinks resolved. This did not happen for paths specified +// using the --extern option to rustc, which could lead to rustc thinking +// that it encountered two different versions of a crate, when it's +// actually the same version found through different paths. +// See https://github.com/rust-lang/rust/pull/16505 + +// This test checks that --extern and symlinks together +// can result in successful compilation. + +//@ ignore-cross-compile + +use run_make_support::{create_symlink, cwd, fs_wrapper, rustc}; + +fn main() { + rustc().input("foo.rs").run(); + fs_wrapper::create_dir_all("other"); + create_symlink("libfoo.rlib", "other"); + rustc().input("bar.rs").library_search_path(cwd()).run(); + rustc().input("baz.rs").extern_("foo", "other").library_search_path(cwd()).run(); +} diff --git a/tests/run-make/symlinked-libraries/Makefile b/tests/run-make/symlinked-libraries/Makefile deleted file mode 100644 index fb0b6127e6f5c..0000000000000 --- a/tests/run-make/symlinked-libraries/Makefile +++ /dev/null @@ -1,11 +0,0 @@ -# ignore-cross-compile -include ../tools.mk - -# ignore-windows -# `ln` is actually `cp` on msys. - -all: - $(RUSTC) foo.rs -C prefer-dynamic - mkdir -p $(TMPDIR)/other - ln -nsf $(TMPDIR)/$(call DYLIB_GLOB,foo) $(TMPDIR)/other - $(RUSTC) bar.rs -L $(TMPDIR)/other diff --git a/tests/run-make/symlinked-libraries/rmake.rs b/tests/run-make/symlinked-libraries/rmake.rs new file mode 100644 index 0000000000000..eaf0c44206a5f --- /dev/null +++ b/tests/run-make/symlinked-libraries/rmake.rs @@ -0,0 +1,16 @@ +// When a directory and a symlink simultaneously exist with the same name, +// setting that name as the library search path should not cause rustc +// to avoid looking in the symlink and cause an error. This test creates +// a directory and a symlink named "other", and places the library in the symlink. +// If it succeeds, the library was successfully found. +// See https://github.com/rust-lang/rust/issues/12459 + +//@ ignore-cross-compile +use run_make_support::{create_symlink, dynamic_lib_name, fs_wrapper, rustc}; + +fn main() { + rustc().input("foo.rs").arg("-Cprefer-dynamic").run(); + fs_wrapper::create_dir_all("other"); + create_symlink(dynamic_lib_name("foo"), "other"); + rustc().input("bar.rs").library_search_path("other").run(); +} diff --git a/tests/run-make/symlinked-rlib/Makefile b/tests/run-make/symlinked-rlib/Makefile deleted file mode 100644 index a8565f683c3e8..0000000000000 --- a/tests/run-make/symlinked-rlib/Makefile +++ /dev/null @@ -1,10 +0,0 @@ -# ignore-cross-compile -include ../tools.mk - -# ignore-windows -# `ln` is actually `cp` on msys. - -all: - $(RUSTC) foo.rs --crate-type=rlib -o $(TMPDIR)/foo.xxx - ln -nsf $(TMPDIR)/foo.xxx $(TMPDIR)/libfoo.rlib - $(RUSTC) bar.rs -L $(TMPDIR) diff --git a/tests/run-make/symlinked-rlib/rmake.rs b/tests/run-make/symlinked-rlib/rmake.rs new file mode 100644 index 0000000000000..3759ca25928a1 --- /dev/null +++ b/tests/run-make/symlinked-rlib/rmake.rs @@ -0,0 +1,16 @@ +// Rustc did not recognize libraries which were symlinked +// to files having extension other than .rlib. This was fixed +// in #32828. This test creates a symlink to "foo.xxx", which has +// an unusual file extension, and checks that rustc can successfully +// use it as an rlib library. +// See https://github.com/rust-lang/rust/pull/32828 + +//@ ignore-cross-compile + +use run_make_support::{create_symlink, cwd, rustc}; + +fn main() { + rustc().input("foo.rs").crate_type("rlib").output("foo.xxx").run(); + create_symlink("foo.xxx", "libfoo.rlib"); + rustc().input("bar.rs").library_search_path(cwd()).run(); +} diff --git a/tests/run-make/track-pgo-dep-info/Makefile b/tests/run-make/track-pgo-dep-info/Makefile index 6c7f67d0f0a9d..3afe3662fa753 100644 --- a/tests/run-make/track-pgo-dep-info/Makefile +++ b/tests/run-make/track-pgo-dep-info/Makefile @@ -1,5 +1,4 @@ # needs-profiler-support -# ignore-windows-gnu include ../tools.mk diff --git a/tests/rustdoc-gui/help-page.goml b/tests/rustdoc-gui/help-page.goml deleted file mode 100644 index 09d33af139cdd..0000000000000 --- a/tests/rustdoc-gui/help-page.goml +++ /dev/null @@ -1,69 +0,0 @@ -// This test ensures that opening the help page in its own tab works. -include: "utils.goml" -go-to: "file://" + |DOC_PATH| + "/help.html" -set-window-size: (1000, 1000) // Try desktop size first. -wait-for: "#help" -assert-css: ("#help", {"display": "block"}) -assert-css: ("#help dd", {"font-size": "16px"}) -click: "#help-button > a" -assert-css: ("#help", {"display": "block"}) -compare-elements-property: (".sub", "#help", ["offsetWidth"]) -compare-elements-position: (".sub", "#help", ["x"]) -set-window-size: (500, 1000) // Try mobile next. -assert-css: ("#help", {"display": "block"}) -compare-elements-property: (".sub", "#help", ["offsetWidth"]) -compare-elements-position: (".sub", "#help", ["x"]) - -// Checking the color of the elements of the help menu. -show-text: true -define-function: ( - "check-colors", - [theme, color, background, box_shadow], - block { - call-function: ("switch-theme", {"theme": |theme|}) - assert-css: ("#help kbd", { - "color": |color|, - "background-color": |background|, - "box-shadow": |box_shadow| + " 0px -1px 0px 0px inset", - }, ALL) - }, -) - -call-function: ("check-colors", { - "theme": "ayu", - "color": "#c5c5c5", - "background": "#314559", - "box_shadow": "#5c6773", -}) -call-function: ("check-colors", { - "theme": "dark", - "color": "#000", - "background": "#fafbfc", - "box_shadow": "#c6cbd1", -}) -call-function: ("check-colors", { - "theme": "light", - "color": "#000", - "background": "#fafbfc", - "box_shadow": "#c6cbd1", -}) - -// This test ensures that opening the help popover without switching pages works. -go-to: "file://" + |DOC_PATH| + "/test_docs/index.html" -set-window-size: (1000, 1000) // Only supported on desktop. -assert-false: "#help" -click: "#help-button > a" -assert-css: ("#help", {"display": "block"}) -assert-css: ("#help dd", {"font-size": "16px"}) -click: "#help-button > a" -assert-css: ("#help", {"display": "none"}) -compare-elements-property-false: (".sub", "#help", ["offsetWidth"]) -compare-elements-position-false: (".sub", "#help", ["x"]) - -// This test ensures that the "the rustdoc book" anchor link within the help popover works. -go-to: "file://" + |DOC_PATH| + "/test_docs/index.html" -set-window-size: (1000, 1000) // Popover only appears when the screen width is >700px. -assert-false: "#help" -click: "#help-button > a" -click: "//*[@id='help']//a[text()='the rustdoc book']" -wait-for-document-property: ({"URL": "https://doc.rust-lang.org/"}, STARTS_WITH) diff --git a/tests/ui-fulldeps/stable-mir/check_def_ty.rs b/tests/ui-fulldeps/stable-mir/check_def_ty.rs new file mode 100644 index 0000000000000..9f45b62d34345 --- /dev/null +++ b/tests/ui-fulldeps/stable-mir/check_def_ty.rs @@ -0,0 +1,114 @@ +//@ run-pass +//! Test that users are able to use stable mir APIs to retrieve type information from a crate item +//! definition. + +//@ ignore-stage1 +//@ ignore-cross-compile +//@ ignore-remote +//@ ignore-windows-gnu mingw has troubles with linking https://github.com/rust-lang/rust/pull/116837 +//@ edition: 2021 + +#![feature(rustc_private)] +#![feature(assert_matches)] +#![feature(control_flow_enum)] + +#[macro_use] +extern crate rustc_smir; +extern crate rustc_driver; +extern crate rustc_interface; +extern crate stable_mir; + +use rustc_smir::rustc_internal; +use stable_mir::ty::{Ty, ForeignItemKind}; +use stable_mir::*; +use std::io::Write; +use std::ops::ControlFlow; + +const CRATE_NAME: &str = "crate_def_ty"; + +/// Test if we can retrieve type information from different definitions. +fn test_def_tys() -> ControlFlow<()> { + let items = stable_mir::all_local_items(); + for item in &items { + // Type from crate items. + let ty = item.ty(); + match item.name().as_str() { + "STATIC_STR" => assert!(ty.kind().is_ref()), + "CONST_U32" => assert!(ty.kind().is_integral()), + "main" => { check_fn_def(ty) } + _ => unreachable!("Unexpected item: `{item:?}`") + } + } + + let foreign_items = stable_mir::local_crate().foreign_modules(); + for item in foreign_items[0].module().items() { + // Type from foreign items. + let ty = item.ty(); + let item_kind = item.kind(); + let name = item.name(); + match item_kind { + ForeignItemKind::Fn(fn_def) => { + assert_eq!(&name, "extern_fn"); + assert_eq!(ty, fn_def.ty()); + check_fn_def(ty) + } + ForeignItemKind::Static(def) => { + assert_eq!(&name, "EXT_STATIC"); + assert_eq!(ty, def.ty()); + assert!(ty.kind().is_integral()) + } + _ => unreachable!("Unexpected kind: {item_kind:?}") + }; + } + + ControlFlow::Continue(()) +} + +fn check_fn_def(ty: Ty) { + let kind = ty.kind(); + let (def, args) = kind.fn_def().expect(&format!("Expected function type, but found: {ty}")); + assert!(def.ty().kind().is_fn()); + assert_eq!(def.ty_with_args(args), ty); +} + +/// This test will generate and analyze a dummy crate using the stable mir. +/// For that, it will first write the dummy crate into a file. +/// Then it will create a `StableMir` using custom arguments and then +/// it will run the compiler. +fn main() { + let path = "defs_ty_input.rs"; + generate_input(&path).unwrap(); + let args = vec![ + "rustc".to_string(), + "-Cpanic=abort".to_string(), + "--crate-name".to_string(), + CRATE_NAME.to_string(), + path.to_string(), + ]; + run!(args, test_def_tys).unwrap(); +} + +fn generate_input(path: &str) -> std::io::Result<()> { + let mut file = std::fs::File::create(path)?; + write!( + file, + r#" + // We would like to check intrinsic definition. + #![feature(core_intrinsics)] + static STATIC_STR: &str = "foo"; + const CONST_U32: u32 = 0u32; + + fn main() {{ + let _c = core::char::from_u32(99); + let _v = Vec::::new(); + let _i = std::intrinsics::size_of::(); + }} + + extern "C" {{ + fn extern_fn(x: i32) -> i32; + static EXT_STATIC: i32; + }} + "# + )?; + Ok(()) +} diff --git a/tests/ui-fulldeps/stable-mir/check_intrinsics.rs b/tests/ui-fulldeps/stable-mir/check_intrinsics.rs index 7e247ce0c75d2..d7f37f36681bd 100644 --- a/tests/ui-fulldeps/stable-mir/check_intrinsics.rs +++ b/tests/ui-fulldeps/stable-mir/check_intrinsics.rs @@ -55,16 +55,19 @@ fn test_intrinsics() -> ControlFlow<()> { /// /// If by any chance this test breaks because you changed how an intrinsic is implemented, please /// update the test to invoke a different intrinsic. +/// +/// In StableMIR, we only expose intrinsic body if they are not marked with +/// `rustc_intrinsic_must_be_overridden`. fn check_instance(instance: &Instance) { assert_eq!(instance.kind, InstanceKind::Intrinsic); let name = instance.intrinsic_name().unwrap(); if instance.has_body() { let Some(body) = instance.body() else { unreachable!("Expected a body") }; assert!(!body.blocks.is_empty()); - assert_matches!(name.as_str(), "likely" | "vtable_size"); + assert_eq!(&name, "likely"); } else { assert!(instance.body().is_none()); - assert_eq!(&name, "size_of_val"); + assert_matches!(name.as_str(), "size_of_val" | "vtable_size"); } } @@ -75,11 +78,13 @@ fn check_def(fn_def: FnDef) { let name = intrinsic.fn_name(); match name.as_str() { - "likely" | "size_of_val" => { + "likely" => { assert!(!intrinsic.must_be_overridden()); + assert!(fn_def.has_body()); } - "vtable_size" => { + "vtable_size" | "size_of_val" => { assert!(intrinsic.must_be_overridden()); + assert!(!fn_def.has_body()); } _ => unreachable!("Unexpected intrinsic: {}", name), } @@ -96,9 +101,9 @@ impl<'a> MirVisitor for CallsVisitor<'a> { TerminatorKind::Call { func, .. } => { let TyKind::RigidTy(RigidTy::FnDef(def, args)) = func.ty(self.locals).unwrap().kind() - else { - return; - }; + else { + return; + }; self.calls.push((def, args.clone())); } _ => {} diff --git a/tests/ui-fulldeps/stable-mir/check_transform.rs b/tests/ui-fulldeps/stable-mir/check_transform.rs index b203e76e54f45..1d3e4c6845ba8 100644 --- a/tests/ui-fulldeps/stable-mir/check_transform.rs +++ b/tests/ui-fulldeps/stable-mir/check_transform.rs @@ -21,7 +21,7 @@ extern crate stable_mir; use rustc_smir::rustc_internal; use stable_mir::mir::alloc::GlobalAlloc; use stable_mir::mir::mono::Instance; -use stable_mir::mir::{Body, Constant, Operand, Rvalue, StatementKind, TerminatorKind}; +use stable_mir::mir::{Body, ConstOperand, Operand, Rvalue, StatementKind, TerminatorKind}; use stable_mir::ty::{ConstantKind, MirConst}; use stable_mir::{CrateDef, CrateItems, ItemKind}; use std::convert::TryFrom; @@ -72,7 +72,7 @@ fn check_msg(body: &Body, expected: &str) { .unwrap() } }; - let ConstantKind::Allocated(alloc) = msg_const.literal.kind() else { + let ConstantKind::Allocated(alloc) = msg_const.const_.kind() else { unreachable!() }; assert_eq!(alloc.provenance.ptrs.len(), 1); @@ -96,8 +96,8 @@ fn change_panic_msg(mut body: Body, new_msg: &str) -> Body { match &mut bb.terminator.kind { TerminatorKind::Call { args, .. } => { let new_const = MirConst::from_str(new_msg); - args[0] = Operand::Constant(Constant { - literal: new_const, + args[0] = Operand::Constant(ConstOperand { + const_: new_const, span: bb.terminator.span, user_ty: None, }); diff --git a/tests/run-make/allow-non-lint-warnings-cmdline/foo.rs b/tests/ui/allow-non-lint-warnings.rs similarity index 60% rename from tests/run-make/allow-non-lint-warnings-cmdline/foo.rs rename to tests/ui/allow-non-lint-warnings.rs index 02e8ccabf7921..f8f5a78ebff26 100644 --- a/tests/run-make/allow-non-lint-warnings-cmdline/foo.rs +++ b/tests/ui/allow-non-lint-warnings.rs @@ -1,3 +1,6 @@ +//@ compile-flags: -Awarnings +//@ check-pass + #[derive()] #[derive(Copy, Clone)] pub struct Foo; diff --git a/tests/ui/asm/x86_64/type-check-3.stderr b/tests/ui/asm/x86_64/type-check-3.stderr index 34bfcd71caca7..202b97ca5c0e8 100644 --- a/tests/ui/asm/x86_64/type-check-3.stderr +++ b/tests/ui/asm/x86_64/type-check-3.stderr @@ -4,7 +4,7 @@ error: type `i128` cannot be used with this register class LL | asm!("{}", in(reg) 0i128); | ^^^^^ | - = note: register class `reg` supports these types: i16, i32, i64, f32, f64 + = note: register class `reg` supports these types: i16, i32, i64, f16, f32, f64 error: type `__m128` cannot be used with this register class --> $DIR/type-check-3.rs:16:28 @@ -12,7 +12,7 @@ error: type `__m128` cannot be used with this register class LL | asm!("{}", in(reg) _mm_setzero_ps()); | ^^^^^^^^^^^^^^^^ | - = note: register class `reg` supports these types: i16, i32, i64, f32, f64 + = note: register class `reg` supports these types: i16, i32, i64, f16, f32, f64 error: type `__m256` cannot be used with this register class --> $DIR/type-check-3.rs:18:28 @@ -20,7 +20,7 @@ error: type `__m256` cannot be used with this register class LL | asm!("{}", in(reg) _mm256_setzero_ps()); | ^^^^^^^^^^^^^^^^^^^ | - = note: register class `reg` supports these types: i16, i32, i64, f32, f64 + = note: register class `reg` supports these types: i16, i32, i64, f16, f32, f64 error: type `u8` cannot be used with this register class --> $DIR/type-check-3.rs:20:32 @@ -28,7 +28,7 @@ error: type `u8` cannot be used with this register class LL | asm!("{}", in(xmm_reg) 0u8); | ^^^ | - = note: register class `xmm_reg` supports these types: i32, i64, f32, f64, i8x16, i16x8, i32x4, i64x2, f32x4, f64x2 + = note: register class `xmm_reg` supports these types: i32, i64, f16, f32, f64, f128, i8x16, i16x8, i32x4, i64x2, f16x8, f32x4, f64x2 error: `avx512bw` target feature is not enabled --> $DIR/type-check-3.rs:29:29 @@ -81,7 +81,7 @@ error: type `i8` cannot be used with this register class LL | asm!("{}", in(reg) 0i8); | ^^^ | - = note: register class `reg` supports these types: i16, i32, i64, f32, f64 + = note: register class `reg` supports these types: i16, i32, i64, f16, f32, f64 = help: consider using the `reg_byte` register class instead error: incompatible types for asm inout argument diff --git a/tests/ui/associated-type-bounds/no-gat-position.rs b/tests/ui/associated-type-bounds/no-gat-position.rs index cb62c88246813..ec9214897fa8f 100644 --- a/tests/ui/associated-type-bounds/no-gat-position.rs +++ b/tests/ui/associated-type-bounds/no-gat-position.rs @@ -5,6 +5,7 @@ pub trait Iter { fn next<'a>(&'a mut self) -> Option>; //~^ ERROR associated item constraints are not allowed here + //~| HELP consider removing this associated item constraint } impl Iter for () { diff --git a/tests/ui/associated-type-bounds/no-gat-position.stderr b/tests/ui/associated-type-bounds/no-gat-position.stderr index e167ac1fda458..39a2f89f9acf0 100644 --- a/tests/ui/associated-type-bounds/no-gat-position.stderr +++ b/tests/ui/associated-type-bounds/no-gat-position.stderr @@ -3,6 +3,11 @@ error[E0229]: associated item constraints are not allowed here | LL | fn next<'a>(&'a mut self) -> Option>; | ^^^^^^^^^ associated item constraint not allowed here + | +help: consider removing this associated item constraint + | +LL | fn next<'a>(&'a mut self) -> Option>; + | ~~~~~~~~~~~ error: aborting due to 1 previous error diff --git a/tests/ui/associated-types/associated-types-eq-2.rs b/tests/ui/associated-types/associated-types-eq-2.rs index f0a7d1e46b1bb..88eb298106100 100644 --- a/tests/ui/associated-types/associated-types-eq-2.rs +++ b/tests/ui/associated-types/associated-types-eq-2.rs @@ -76,7 +76,6 @@ trait Tr3 { impl Tr3 for Bar { } @@ -92,7 +91,6 @@ impl Tr3 for Qux { // matches the const param ident but the constraint is a type arg impl Tr3 for Bar { //~^ ERROR associated item constraints are not allowed here -//~| ERROR trait takes 3 generic arguments but 0 generic arguments were supplied } // Test for when equality constraint's ident diff --git a/tests/ui/associated-types/associated-types-eq-2.stderr b/tests/ui/associated-types/associated-types-eq-2.stderr index 53e4e59128ea6..69b1b533450c7 100644 --- a/tests/ui/associated-types/associated-types-eq-2.stderr +++ b/tests/ui/associated-types/associated-types-eq-2.stderr @@ -5,7 +5,6 @@ LL | impl Tr3 for Bar { | |____^ | @@ -14,7 +13,7 @@ LL | | = 42, T2 = Qux, T3 = usize> for Bar { = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date error[E0658]: associated const equality is incomplete - --> $DIR/associated-types-eq-2.rs:85:10 + --> $DIR/associated-types-eq-2.rs:84:10 | LL | impl Tr3 for Qux { | ^^^^^^ @@ -24,7 +23,7 @@ LL | impl Tr3 for Qux { = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date error[E0658]: associated const equality is incomplete - --> $DIR/associated-types-eq-2.rs:100:14 + --> $DIR/associated-types-eq-2.rs:98:14 | LL | impl Tr3<42, T2 = 42, T3 = usize> for Bar { | ^^^^^^^ @@ -34,7 +33,7 @@ LL | impl Tr3<42, T2 = 42, T3 = usize> for Bar { = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date error[E0658]: associated const equality is incomplete - --> $DIR/associated-types-eq-2.rs:108:10 + --> $DIR/associated-types-eq-2.rs:106:10 | LL | impl Tr3 for Bar { | ^^^^^^ @@ -190,22 +189,6 @@ help: to use `GenericTerm` as a generic argument specify it directly LL | impl Tr2> for Bar { | ~~~~~~~~~~~~~~~~ -error[E0107]: trait takes 3 generic arguments but 0 generic arguments were supplied - --> $DIR/associated-types-eq-2.rs:76:6 - | -LL | impl Tr3 $DIR/associated-types-eq-2.rs:69:7 - | -LL | trait Tr3 { - | ^^^ ------------ -- -- -help: add missing generic arguments - | -LL | impl Tr3 $DIR/associated-types-eq-2.rs:76:10 | @@ -213,7 +196,6 @@ LL | impl Tr3 for Bar { | |____^ associated item constraint not allowed here | @@ -223,7 +205,7 @@ LL | impl Tr3<42, T2 = Qux, T3 = usize> for Bar { | ~~ error[E0107]: trait takes 3 generic arguments but 0 generic arguments were supplied - --> $DIR/associated-types-eq-2.rs:85:6 + --> $DIR/associated-types-eq-2.rs:84:6 | LL | impl Tr3 for Qux { | ^^^ expected 3 generic arguments @@ -239,7 +221,7 @@ LL | impl Tr3 for Qux { | ++++++++++ error[E0229]: associated item constraints are not allowed here - --> $DIR/associated-types-eq-2.rs:85:10 + --> $DIR/associated-types-eq-2.rs:84:10 | LL | impl Tr3 for Qux { | ^^^^^^ associated item constraint not allowed here @@ -249,24 +231,8 @@ help: consider removing this associated item binding LL | impl Tr3 for Qux { | ~~~~~~~ -error[E0107]: trait takes 3 generic arguments but 0 generic arguments were supplied - --> $DIR/associated-types-eq-2.rs:93:6 - | -LL | impl Tr3 for Bar { - | ^^^ expected 3 generic arguments - | -note: trait defined here, with 3 generic parameters: `N`, `T2`, `T3` - --> $DIR/associated-types-eq-2.rs:69:7 - | -LL | trait Tr3 { - | ^^^ ------------ -- -- -help: add missing generic arguments - | -LL | impl Tr3 for Bar { - | ++++++++++ - error[E0229]: associated item constraints are not allowed here - --> $DIR/associated-types-eq-2.rs:93:10 + --> $DIR/associated-types-eq-2.rs:92:10 | LL | impl Tr3 for Bar { | ^^^^^^^ associated item constraint not allowed here @@ -277,7 +243,7 @@ LL | impl Tr3 for Bar { | ~~~~~~~~ error[E0107]: trait takes 3 generic arguments but 1 generic argument was supplied - --> $DIR/associated-types-eq-2.rs:100:6 + --> $DIR/associated-types-eq-2.rs:98:6 | LL | impl Tr3<42, T2 = 42, T3 = usize> for Bar { | ^^^ -- supplied 1 generic argument @@ -295,7 +261,7 @@ LL | impl Tr3<42, T2, T3, T2 = 42, T3 = usize> for Bar { | ++++++++ error[E0229]: associated item constraints are not allowed here - --> $DIR/associated-types-eq-2.rs:100:14 + --> $DIR/associated-types-eq-2.rs:98:14 | LL | impl Tr3<42, T2 = 42, T3 = usize> for Bar { | ^^^^^^^ associated item constraint not allowed here @@ -306,7 +272,7 @@ LL | impl Tr3<42, T2 = 42, T3 = usize> for Bar { | ~~~~~~~~~ error[E0107]: trait takes 3 generic arguments but 0 generic arguments were supplied - --> $DIR/associated-types-eq-2.rs:108:6 + --> $DIR/associated-types-eq-2.rs:106:6 | LL | impl Tr3 for Bar { | ^^^ expected 3 generic arguments @@ -322,7 +288,7 @@ LL | impl Tr3 for Bar { | ++++++++++ error[E0229]: associated item constraints are not allowed here - --> $DIR/associated-types-eq-2.rs:108:10 + --> $DIR/associated-types-eq-2.rs:106:10 | LL | impl Tr3 for Bar { | ^^^^^^ associated item constraint not allowed here @@ -333,13 +299,13 @@ LL | impl Tr3 for Bar { | ~~~~~~~ error[E0107]: struct takes 1 generic argument but 0 generic arguments were supplied - --> $DIR/associated-types-eq-2.rs:119:13 + --> $DIR/associated-types-eq-2.rs:117:13 | LL | impl<'a, T> St<'a , T = Qux> { | ^^ expected 1 generic argument | note: struct defined here, with 1 generic parameter: `T` - --> $DIR/associated-types-eq-2.rs:117:8 + --> $DIR/associated-types-eq-2.rs:115:8 | LL | struct St<'a, T> { v: &'a T } | ^^ - @@ -349,7 +315,7 @@ LL | impl<'a, T> St<'a, T , T = Qux> { | +++ error[E0229]: associated item constraints are not allowed here - --> $DIR/associated-types-eq-2.rs:119:21 + --> $DIR/associated-types-eq-2.rs:117:21 | LL | impl<'a, T> St<'a , T = Qux> { | ^^^^^^^ associated item constraint not allowed here @@ -359,7 +325,7 @@ help: to use `Qux` as a generic argument specify it directly LL | impl<'a, T> St<'a , Qux> { | ~~~ -error: aborting due to 27 previous errors +error: aborting due to 25 previous errors Some errors have detailed explanations: E0046, E0107, E0229, E0658. For more information about an error, try `rustc --explain E0046`. diff --git a/tests/ui/associated-types/defaults-unsound-62211-1.next.stderr b/tests/ui/associated-types/defaults-unsound-62211-1.next.stderr index 0fc1bb0b00f3c..010f51df15ad3 100644 --- a/tests/ui/associated-types/defaults-unsound-62211-1.next.stderr +++ b/tests/ui/associated-types/defaults-unsound-62211-1.next.stderr @@ -31,18 +31,6 @@ help: consider further restricting `Self` LL | trait UncheckedCopy: Sized + AddAssign<&'static str> { | +++++++++++++++++++++++++ -error[E0271]: type mismatch resolving `::Target == str` - --> $DIR/defaults-unsound-62211-1.rs:24:96 - | -LL | type Output: Copy + Deref + AddAssign<&'static str> + From + Display = Self; - | ^^^^ types differ - | -note: required by a bound in `UncheckedCopy::Output` - --> $DIR/defaults-unsound-62211-1.rs:24:31 - | -LL | type Output: Copy + Deref + AddAssign<&'static str> + From + Display = Self; - | ^^^^^^^^^^^^ required by this bound in `UncheckedCopy::Output` - error[E0277]: the trait bound `Self: Deref` is not satisfied --> $DIR/defaults-unsound-62211-1.rs:24:96 | @@ -50,10 +38,10 @@ LL | type Output: Copy + Deref + AddAssign<&'static str> + Fro | ^^^^ the trait `Deref` is not implemented for `Self` | note: required by a bound in `UncheckedCopy::Output` - --> $DIR/defaults-unsound-62211-1.rs:24:25 + --> $DIR/defaults-unsound-62211-1.rs:24:31 | LL | type Output: Copy + Deref + AddAssign<&'static str> + From + Display = Self; - | ^^^^^^^^^^^^^^^^^^^ required by this bound in `UncheckedCopy::Output` + | ^^^^^^^^^^^^ required by this bound in `UncheckedCopy::Output` help: consider further restricting `Self` | LL | trait UncheckedCopy: Sized + Deref { @@ -75,7 +63,6 @@ help: consider further restricting `Self` LL | trait UncheckedCopy: Sized + Copy { | ++++++ -error: aborting due to 5 previous errors +error: aborting due to 4 previous errors -Some errors have detailed explanations: E0271, E0277. -For more information about an error, try `rustc --explain E0271`. +For more information about this error, try `rustc --explain E0277`. diff --git a/tests/ui/associated-types/defaults-unsound-62211-1.rs b/tests/ui/associated-types/defaults-unsound-62211-1.rs index f054611ed7807..124bac0ea721c 100644 --- a/tests/ui/associated-types/defaults-unsound-62211-1.rs +++ b/tests/ui/associated-types/defaults-unsound-62211-1.rs @@ -26,7 +26,6 @@ trait UncheckedCopy: Sized { //~| ERROR the trait bound `Self: Deref` is not satisfied //~| ERROR cannot add-assign `&'static str` to `Self` //~| ERROR `Self` doesn't implement `std::fmt::Display` - //[next]~| ERROR type mismatch resolving `::Target == str` // We said the Output type was Copy, so we can Copy it freely! fn unchecked_copy(other: &Self::Output) -> Self::Output { diff --git a/tests/ui/associated-types/defaults-unsound-62211-2.next.stderr b/tests/ui/associated-types/defaults-unsound-62211-2.next.stderr index 751352d7c16da..9347894657078 100644 --- a/tests/ui/associated-types/defaults-unsound-62211-2.next.stderr +++ b/tests/ui/associated-types/defaults-unsound-62211-2.next.stderr @@ -31,18 +31,6 @@ help: consider further restricting `Self` LL | trait UncheckedCopy: Sized + AddAssign<&'static str> { | +++++++++++++++++++++++++ -error[E0271]: type mismatch resolving `::Target == str` - --> $DIR/defaults-unsound-62211-2.rs:24:96 - | -LL | type Output: Copy + Deref + AddAssign<&'static str> + From + Display = Self; - | ^^^^ types differ - | -note: required by a bound in `UncheckedCopy::Output` - --> $DIR/defaults-unsound-62211-2.rs:24:31 - | -LL | type Output: Copy + Deref + AddAssign<&'static str> + From + Display = Self; - | ^^^^^^^^^^^^ required by this bound in `UncheckedCopy::Output` - error[E0277]: the trait bound `Self: Deref` is not satisfied --> $DIR/defaults-unsound-62211-2.rs:24:96 | @@ -50,10 +38,10 @@ LL | type Output: Copy + Deref + AddAssign<&'static str> + Fro | ^^^^ the trait `Deref` is not implemented for `Self` | note: required by a bound in `UncheckedCopy::Output` - --> $DIR/defaults-unsound-62211-2.rs:24:25 + --> $DIR/defaults-unsound-62211-2.rs:24:31 | LL | type Output: Copy + Deref + AddAssign<&'static str> + From + Display = Self; - | ^^^^^^^^^^^^^^^^^^^ required by this bound in `UncheckedCopy::Output` + | ^^^^^^^^^^^^ required by this bound in `UncheckedCopy::Output` help: consider further restricting `Self` | LL | trait UncheckedCopy: Sized + Deref { @@ -75,7 +63,6 @@ help: consider further restricting `Self` LL | trait UncheckedCopy: Sized + Copy { | ++++++ -error: aborting due to 5 previous errors +error: aborting due to 4 previous errors -Some errors have detailed explanations: E0271, E0277. -For more information about an error, try `rustc --explain E0271`. +For more information about this error, try `rustc --explain E0277`. diff --git a/tests/ui/associated-types/defaults-unsound-62211-2.rs b/tests/ui/associated-types/defaults-unsound-62211-2.rs index 956f14df0d543..998c39b5bad37 100644 --- a/tests/ui/associated-types/defaults-unsound-62211-2.rs +++ b/tests/ui/associated-types/defaults-unsound-62211-2.rs @@ -26,7 +26,6 @@ trait UncheckedCopy: Sized { //~| ERROR the trait bound `Self: Deref` is not satisfied //~| ERROR cannot add-assign `&'static str` to `Self` //~| ERROR `Self` doesn't implement `std::fmt::Display` - //[next]~| ERROR type mismatch resolving `::Target == str` // We said the Output type was Copy, so we can Copy it freely! fn unchecked_copy(other: &Self::Output) -> Self::Output { diff --git a/tests/ui/associated-types/issue-54108.next.stderr b/tests/ui/associated-types/issue-54108.next.stderr index 9f6f00e7ca8f3..5e2fa551afe30 100644 --- a/tests/ui/associated-types/issue-54108.next.stderr +++ b/tests/ui/associated-types/issue-54108.next.stderr @@ -1,15 +1,3 @@ -error[E0271]: type mismatch resolving `<::ActualSize as Add>::Output == ::ActualSize` - --> $DIR/issue-54108.rs:23:17 - | -LL | type Size = ::ActualSize; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ types differ - | -note: required by a bound in `Encoder::Size` - --> $DIR/issue-54108.rs:8:20 - | -LL | type Size: Add; - | ^^^^^^^^^^^^^^^^^^^ required by this bound in `Encoder::Size` - error[E0277]: cannot add `::ActualSize` to `::ActualSize` --> $DIR/issue-54108.rs:23:17 | @@ -18,16 +6,15 @@ LL | type Size = ::ActualSize; | = help: the trait `Add` is not implemented for `::ActualSize` note: required by a bound in `Encoder::Size` - --> $DIR/issue-54108.rs:8:16 + --> $DIR/issue-54108.rs:8:20 | LL | type Size: Add; - | ^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `Encoder::Size` + | ^^^^^^^^^^^^^^^^^^^ required by this bound in `Encoder::Size` help: consider further restricting the associated type | LL | T: SubEncoder, ::ActualSize: Add | ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ -error: aborting due to 2 previous errors +error: aborting due to 1 previous error -Some errors have detailed explanations: E0271, E0277. -For more information about an error, try `rustc --explain E0271`. +For more information about this error, try `rustc --explain E0277`. diff --git a/tests/ui/associated-types/issue-54108.rs b/tests/ui/associated-types/issue-54108.rs index 7c652fd7f49b6..bcc54f333621c 100644 --- a/tests/ui/associated-types/issue-54108.rs +++ b/tests/ui/associated-types/issue-54108.rs @@ -22,7 +22,6 @@ where { type Size = ::ActualSize; //~^ ERROR: cannot add `::ActualSize` to `::ActualSize` - //[next]~| ERROR type mismatch resolving `<::ActualSize as Add>::Output == ::ActualSize` fn foo(&self) -> Self::Size { self.bar() + self.bar() diff --git a/tests/ui/async-await/return-type-notation/rtn-in-impl-signature.stderr b/tests/ui/async-await/return-type-notation/rtn-in-impl-signature.stderr index b07c5735dff6b..54960ae60bcca 100644 --- a/tests/ui/async-await/return-type-notation/rtn-in-impl-signature.stderr +++ b/tests/ui/async-await/return-type-notation/rtn-in-impl-signature.stderr @@ -12,6 +12,11 @@ error[E0229]: associated item constraints are not allowed here | LL | impl Super1<'_, bar(): Send> for () {} | ^^^^^^^^^^^ associated item constraint not allowed here + | +help: consider removing this associated item constraint + | +LL | impl Super1<'_, bar(): Send> for () {} + | ~~~~~~~~~~~~~ error[E0046]: not all trait items implemented, missing: `bar` --> $DIR/rtn-in-impl-signature.rs:10:1 diff --git a/tests/ui/auto-traits/typeck-default-trait-impl-precedence.stderr b/tests/ui/auto-traits/typeck-default-trait-impl-precedence.stderr index 47bb1a059be5a..4773ac4ccf720 100644 --- a/tests/ui/auto-traits/typeck-default-trait-impl-precedence.stderr +++ b/tests/ui/auto-traits/typeck-default-trait-impl-precedence.stderr @@ -2,7 +2,7 @@ error[E0277]: the trait bound `&'static u32: Defaulted` is not satisfied --> $DIR/typeck-default-trait-impl-precedence.rs:19:20 | LL | is_defaulted::<&'static u32>(); - | ^^^^^^^^^^^^ the trait `Signed` is not implemented for `&'static u32`, which is required by `&'static u32: Defaulted` + | ^^^^^^^^^^^^ the trait `Signed` is not implemented for `u32`, which is required by `&'static u32: Defaulted` | note: required for `&'static u32` to implement `Defaulted` --> $DIR/typeck-default-trait-impl-precedence.rs:10:19 diff --git a/tests/ui/binop/binary-op-suggest-deref.stderr b/tests/ui/binop/binary-op-suggest-deref.stderr index 47af51e2106b2..ec17074e3050f 100644 --- a/tests/ui/binop/binary-op-suggest-deref.stderr +++ b/tests/ui/binop/binary-op-suggest-deref.stderr @@ -303,10 +303,10 @@ LL | let _ = FOO & (*"Sized".to_string().into_boxed_str()); | = help: the trait `BitAnd` is not implemented for `i32` = help: the following other types implement trait `BitAnd`: - <&'a i32 as BitAnd> - <&i32 as BitAnd<&i32>> - > - + `&'a i32` implements `BitAnd` + `&i32` implements `BitAnd<&i32>` + `i32` implements `BitAnd<&i32>` + `i32` implements `BitAnd` error[E0277]: the size for values of type `str` cannot be known at compilation time --> $DIR/binary-op-suggest-deref.rs:78:17 diff --git a/tests/ui/binop/binop-mul-i32-f32.stderr b/tests/ui/binop/binop-mul-i32-f32.stderr index 29e1ff918340b..33d8fba172ce2 100644 --- a/tests/ui/binop/binop-mul-i32-f32.stderr +++ b/tests/ui/binop/binop-mul-i32-f32.stderr @@ -6,10 +6,10 @@ LL | x * y | = help: the trait `Mul` is not implemented for `i32` = help: the following other types implement trait `Mul`: - <&'a i32 as Mul> - <&i32 as Mul<&i32>> - > - + `&'a i32` implements `Mul` + `&i32` implements `Mul<&i32>` + `i32` implements `Mul<&i32>` + `i32` implements `Mul` error: aborting due to 1 previous error diff --git a/tests/ui/binop/shift-various-bad-types.stderr b/tests/ui/binop/shift-various-bad-types.stderr index 38db66f86b461..7313cb3fb84f3 100644 --- a/tests/ui/binop/shift-various-bad-types.stderr +++ b/tests/ui/binop/shift-various-bad-types.stderr @@ -6,14 +6,14 @@ LL | 22 >> p.char; | = help: the trait `Shr` is not implemented for `{integer}` = help: the following other types implement trait `Shr`: - <&'a i128 as Shr> - <&'a i128 as Shr> - <&'a i128 as Shr> - <&'a i128 as Shr> - <&'a i128 as Shr> - <&'a i128 as Shr> - <&'a i128 as Shr> - <&'a i128 as Shr> + `&'a i128` implements `Shr` + `&'a i128` implements `Shr` + `&'a i128` implements `Shr` + `&'a i128` implements `Shr` + `&'a i128` implements `Shr` + `&'a i128` implements `Shr` + `&'a i128` implements `Shr` + `&'a i128` implements `Shr` and 568 others error[E0277]: no implementation for `{integer} >> &str` @@ -24,14 +24,14 @@ LL | 22 >> p.str; | = help: the trait `Shr<&str>` is not implemented for `{integer}` = help: the following other types implement trait `Shr`: - <&'a i128 as Shr> - <&'a i128 as Shr> - <&'a i128 as Shr> - <&'a i128 as Shr> - <&'a i128 as Shr> - <&'a i128 as Shr> - <&'a i128 as Shr> - <&'a i128 as Shr> + `&'a i128` implements `Shr` + `&'a i128` implements `Shr` + `&'a i128` implements `Shr` + `&'a i128` implements `Shr` + `&'a i128` implements `Shr` + `&'a i128` implements `Shr` + `&'a i128` implements `Shr` + `&'a i128` implements `Shr` and 568 others error[E0277]: no implementation for `{integer} >> &Panolpy` @@ -42,14 +42,14 @@ LL | 22 >> p; | = help: the trait `Shr<&Panolpy>` is not implemented for `{integer}` = help: the following other types implement trait `Shr`: - <&'a i128 as Shr> - <&'a i128 as Shr> - <&'a i128 as Shr> - <&'a i128 as Shr> - <&'a i128 as Shr> - <&'a i128 as Shr> - <&'a i128 as Shr> - <&'a i128 as Shr> + `&'a i128` implements `Shr` + `&'a i128` implements `Shr` + `&'a i128` implements `Shr` + `&'a i128` implements `Shr` + `&'a i128` implements `Shr` + `&'a i128` implements `Shr` + `&'a i128` implements `Shr` + `&'a i128` implements `Shr` and 568 others error[E0308]: mismatched types diff --git a/tests/ui/coherence/indirect-impl-for-trait-obj-coherence.next.stderr b/tests/ui/coherence/indirect-impl-for-trait-obj-coherence.next.stderr index 6e41561f1a7b6..b6636d4de86eb 100644 --- a/tests/ui/coherence/indirect-impl-for-trait-obj-coherence.next.stderr +++ b/tests/ui/coherence/indirect-impl-for-trait-obj-coherence.next.stderr @@ -1,8 +1,8 @@ -error[E0284]: type annotations needed: cannot satisfy ` as Object>::Output == T` +error[E0284]: type annotations needed: cannot normalize ` as Object>::Output` --> $DIR/indirect-impl-for-trait-obj-coherence.rs:25:41 | LL | foo::, U>(x) - | ^ cannot satisfy ` as Object>::Output == T` + | ^ cannot normalize ` as Object>::Output` error: aborting due to 1 previous error diff --git a/tests/ui/coherence/indirect-impl-for-trait-obj-coherence.rs b/tests/ui/coherence/indirect-impl-for-trait-obj-coherence.rs index 0b66a6e783032..abfd51c2008bb 100644 --- a/tests/ui/coherence/indirect-impl-for-trait-obj-coherence.rs +++ b/tests/ui/coherence/indirect-impl-for-trait-obj-coherence.rs @@ -23,7 +23,7 @@ fn foo(x: >::Output) -> U { #[allow(dead_code)] fn transmute(x: T) -> U { foo::, U>(x) - //[next]~^ ERROR type annotations needed: cannot satisfy ` as Object>::Output == T` + //[next]~^ ERROR type annotations needed: cannot normalize ` as Object>::Output` } fn main() {} diff --git a/tests/ui/coherence/occurs-check/associated-type.next.stderr b/tests/ui/coherence/occurs-check/associated-type.next.stderr index f32bb1301da59..bd65cee58d9b4 100644 --- a/tests/ui/coherence/occurs-check/associated-type.next.stderr +++ b/tests/ui/coherence/occurs-check/associated-type.next.stderr @@ -16,11 +16,11 @@ LL | | for<'a> *const T: ToUnit<'a>, | = note: this behavior recently changed as a result of a bug fix; see rust-lang/rust#56105 for details -error[E0284]: type annotations needed: cannot satisfy ` fn(&'a (), ()) as Overlap fn(&'a (), ())>>::Assoc == usize` +error[E0284]: type annotations needed: cannot normalize ` fn(&'a (), ()) as Overlap fn(&'a (), ())>>::Assoc` --> $DIR/associated-type.rs:44:59 | LL | foo:: fn(&'a (), ()), for<'a> fn(&'a (), ())>(3usize); - | ^^^^^^ cannot satisfy ` fn(&'a (), ()) as Overlap fn(&'a (), ())>>::Assoc == usize` + | ^^^^^^ cannot normalize ` fn(&'a (), ()) as Overlap fn(&'a (), ())>>::Assoc` error: aborting due to 2 previous errors diff --git a/tests/ui/coherence/occurs-check/associated-type.rs b/tests/ui/coherence/occurs-check/associated-type.rs index ac1236c554af2..df03d5f60a028 100644 --- a/tests/ui/coherence/occurs-check/associated-type.rs +++ b/tests/ui/coherence/occurs-check/associated-type.rs @@ -42,5 +42,5 @@ fn foo, U>(x: T::Assoc) -> T::Assoc { fn main() { foo:: fn(&'a (), ()), for<'a> fn(&'a (), ())>(3usize); - //[next]~^ ERROR: cannot satisfy + //[next]~^ ERROR: cannot normalize } diff --git a/tests/ui/const-generics/exhaustive-value.stderr b/tests/ui/const-generics/exhaustive-value.stderr index acaa0cf1a508d..791bb19ffe866 100644 --- a/tests/ui/const-generics/exhaustive-value.stderr +++ b/tests/ui/const-generics/exhaustive-value.stderr @@ -5,14 +5,14 @@ LL | <() as Foo>::test() | ^^ the trait `Foo` is not implemented for `()` | = help: the following other types implement trait `Foo`: - <() as Foo<0>> - <() as Foo<100>> - <() as Foo<101>> - <() as Foo<102>> - <() as Foo<103>> - <() as Foo<104>> - <() as Foo<105>> - <() as Foo<106>> + `()` implements `Foo<0>` + `()` implements `Foo<100>` + `()` implements `Foo<101>` + `()` implements `Foo<102>` + `()` implements `Foo<103>` + `()` implements `Foo<104>` + `()` implements `Foo<105>` + `()` implements `Foo<106>` and 248 others error: aborting due to 1 previous error diff --git a/tests/ui/const-generics/issues/issue-82956.stderr b/tests/ui/const-generics/issues/issue-82956.stderr index d0fc7112426a9..a956fc741f4d4 100644 --- a/tests/ui/const-generics/issues/issue-82956.stderr +++ b/tests/ui/const-generics/issues/issue-82956.stderr @@ -4,7 +4,7 @@ error[E0433]: failed to resolve: use of undeclared type `IntoIter` LL | let mut iter = IntoIter::new(self); | ^^^^^^^^ use of undeclared type `IntoIter` | -help: consider importing one of these items +help: consider importing one of these structs | LL + use std::array::IntoIter; | diff --git a/tests/ui/const-generics/parser-error-recovery/issue-89013-no-kw.rs b/tests/ui/const-generics/parser-error-recovery/issue-89013-no-kw.rs index fbf1553c182cf..c15482f92dca6 100644 --- a/tests/ui/const-generics/parser-error-recovery/issue-89013-no-kw.rs +++ b/tests/ui/const-generics/parser-error-recovery/issue-89013-no-kw.rs @@ -7,8 +7,7 @@ struct Bar; const T: usize = 42; impl Foo for Bar { -//~^ ERROR trait takes 1 generic argument but 0 generic arguments were supplied -//~| ERROR associated item constraints are not allowed here +//~^ ERROR associated item constraints are not allowed here //~| ERROR associated const equality is incomplete fn do_x(&self) -> [u8; 3] { [0u8; 3] diff --git a/tests/ui/const-generics/parser-error-recovery/issue-89013-no-kw.stderr b/tests/ui/const-generics/parser-error-recovery/issue-89013-no-kw.stderr index a132859b412f1..78cddcc234c6e 100644 --- a/tests/ui/const-generics/parser-error-recovery/issue-89013-no-kw.stderr +++ b/tests/ui/const-generics/parser-error-recovery/issue-89013-no-kw.stderr @@ -8,22 +8,6 @@ LL | impl Foo for Bar { = help: add `#![feature(associated_const_equality)]` to the crate attributes to enable = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date -error[E0107]: trait takes 1 generic argument but 0 generic arguments were supplied - --> $DIR/issue-89013-no-kw.rs:9:6 - | -LL | impl Foo for Bar { - | ^^^ expected 1 generic argument - | -note: trait defined here, with 1 generic parameter: `N` - --> $DIR/issue-89013-no-kw.rs:1:7 - | -LL | trait Foo { - | ^^^ -------------- -help: add missing generic argument - | -LL | impl Foo for Bar { - | ++ - error[E0229]: associated item constraints are not allowed here --> $DIR/issue-89013-no-kw.rs:9:10 | @@ -35,7 +19,7 @@ help: to use `3` as a generic argument specify it directly LL | impl Foo<3> for Bar { | ~ -error: aborting due to 3 previous errors +error: aborting due to 2 previous errors -Some errors have detailed explanations: E0107, E0229, E0658. -For more information about an error, try `rustc --explain E0107`. +Some errors have detailed explanations: E0229, E0658. +For more information about an error, try `rustc --explain E0229`. diff --git a/tests/ui/const-generics/parser-error-recovery/issue-89013.rs b/tests/ui/const-generics/parser-error-recovery/issue-89013.rs index c9c7ff3a1704f..6302f7f2ad5d2 100644 --- a/tests/ui/const-generics/parser-error-recovery/issue-89013.rs +++ b/tests/ui/const-generics/parser-error-recovery/issue-89013.rs @@ -8,7 +8,6 @@ const T: usize = 42; impl Foo for Bar { //~^ ERROR expected lifetime, type, or constant, found keyword `const` -//~| ERROR trait takes 1 generic //~| ERROR associated item constraints are not allowed here //~| ERROR associated const equality is incomplete fn do_x(&self) -> [u8; 3] { diff --git a/tests/ui/const-generics/parser-error-recovery/issue-89013.stderr b/tests/ui/const-generics/parser-error-recovery/issue-89013.stderr index 2fdd12085652f..387eb226e70ed 100644 --- a/tests/ui/const-generics/parser-error-recovery/issue-89013.stderr +++ b/tests/ui/const-generics/parser-error-recovery/issue-89013.stderr @@ -20,22 +20,6 @@ LL | impl Foo for Bar { = help: add `#![feature(associated_const_equality)]` to the crate attributes to enable = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date -error[E0107]: trait takes 1 generic argument but 0 generic arguments were supplied - --> $DIR/issue-89013.rs:9:6 - | -LL | impl Foo for Bar { - | ^^^ expected 1 generic argument - | -note: trait defined here, with 1 generic parameter: `N` - --> $DIR/issue-89013.rs:1:7 - | -LL | trait Foo { - | ^^^ -------------- -help: add missing generic argument - | -LL | impl Foo for Bar { - | ++ - error[E0229]: associated item constraints are not allowed here --> $DIR/issue-89013.rs:9:10 | @@ -47,7 +31,7 @@ help: to use `3` as a generic argument specify it directly LL | impl Foo<3> for Bar { | ~ -error: aborting due to 4 previous errors +error: aborting due to 3 previous errors -Some errors have detailed explanations: E0107, E0229, E0658. -For more information about an error, try `rustc --explain E0107`. +Some errors have detailed explanations: E0229, E0658. +For more information about an error, try `rustc --explain E0229`. diff --git a/tests/ui/consts/const-eval/const-eval-overflow-3b.stderr b/tests/ui/consts/const-eval/const-eval-overflow-3b.stderr index 05f33c33946a8..0d9b718cd067f 100644 --- a/tests/ui/consts/const-eval/const-eval-overflow-3b.stderr +++ b/tests/ui/consts/const-eval/const-eval-overflow-3b.stderr @@ -12,10 +12,10 @@ LL | = [0; (i8::MAX + 1u8) as usize]; | = help: the trait `Add` is not implemented for `i8` = help: the following other types implement trait `Add`: - <&'a i8 as Add> - <&i8 as Add<&i8>> - > - + `&'a i8` implements `Add` + `&i8` implements `Add<&i8>` + `i8` implements `Add<&i8>` + `i8` implements `Add` error: aborting due to 2 previous errors diff --git a/tests/ui/consts/const-eval/const-eval-overflow-4b.stderr b/tests/ui/consts/const-eval/const-eval-overflow-4b.stderr index d019f5920b517..32fe30dc88247 100644 --- a/tests/ui/consts/const-eval/const-eval-overflow-4b.stderr +++ b/tests/ui/consts/const-eval/const-eval-overflow-4b.stderr @@ -12,10 +12,10 @@ LL | : [u32; (i8::MAX as i8 + 1u8) as usize] | = help: the trait `Add` is not implemented for `i8` = help: the following other types implement trait `Add`: - <&'a i8 as Add> - <&i8 as Add<&i8>> - > - + `&'a i8` implements `Add` + `&i8` implements `Add<&i8>` + `i8` implements `Add<&i8>` + `i8` implements `Add` error[E0604]: only `u8` can be cast as `char`, not `i8` --> $DIR/const-eval-overflow-4b.rs:22:13 diff --git a/tests/ui/consts/const_refs_to_static-ice-121413.rs b/tests/ui/consts/const_refs_to_static-ice-121413.rs index 8a24fb799b6b8..8fc3912efd08e 100644 --- a/tests/ui/consts/const_refs_to_static-ice-121413.rs +++ b/tests/ui/consts/const_refs_to_static-ice-121413.rs @@ -5,12 +5,16 @@ // ignore-tidy-linelength #![feature(const_refs_to_static)] const REF_INTERIOR_MUT: &usize = { + //~^ HELP consider importing this struct static FOO: Sync = AtomicUsize::new(0); //~^ ERROR failed to resolve: use of undeclared type `AtomicUsize` //~| WARN trait objects without an explicit `dyn` are deprecated //~| ERROR the size for values of type `(dyn Sync + 'static)` cannot be known at compilation time //~| ERROR the size for values of type `(dyn Sync + 'static)` cannot be known at compilation time //~| WARN this is accepted in the current edition (Rust 2015) but is a hard error in Rust 2021! + //~| HELP if this is an object-safe trait, use `dyn` + //~| HELP the trait `Sized` is not implemented for `(dyn Sync + 'static)` + //~| HELP the trait `Sized` is not implemented for `(dyn Sync + 'static)` unsafe { &*(&FOO as *const _ as *const usize) } }; pub fn main() {} diff --git a/tests/ui/consts/const_refs_to_static-ice-121413.stderr b/tests/ui/consts/const_refs_to_static-ice-121413.stderr index c977c698a92e9..fbe32a70293aa 100644 --- a/tests/ui/consts/const_refs_to_static-ice-121413.stderr +++ b/tests/ui/consts/const_refs_to_static-ice-121413.stderr @@ -1,5 +1,5 @@ error[E0433]: failed to resolve: use of undeclared type `AtomicUsize` - --> $DIR/const_refs_to_static-ice-121413.rs:8:24 + --> $DIR/const_refs_to_static-ice-121413.rs:9:24 | LL | static FOO: Sync = AtomicUsize::new(0); | ^^^^^^^^^^^ use of undeclared type `AtomicUsize` @@ -10,7 +10,7 @@ LL + use std::sync::atomic::AtomicUsize; | warning: trait objects without an explicit `dyn` are deprecated - --> $DIR/const_refs_to_static-ice-121413.rs:8:17 + --> $DIR/const_refs_to_static-ice-121413.rs:9:17 | LL | static FOO: Sync = AtomicUsize::new(0); | ^^^^ @@ -24,7 +24,7 @@ LL | static FOO: dyn Sync = AtomicUsize::new(0); | +++ error[E0277]: the size for values of type `(dyn Sync + 'static)` cannot be known at compilation time - --> $DIR/const_refs_to_static-ice-121413.rs:8:17 + --> $DIR/const_refs_to_static-ice-121413.rs:9:17 | LL | static FOO: Sync = AtomicUsize::new(0); | ^^^^ doesn't have a size known at compile-time @@ -32,7 +32,7 @@ LL | static FOO: Sync = AtomicUsize::new(0); = help: the trait `Sized` is not implemented for `(dyn Sync + 'static)` error[E0277]: the size for values of type `(dyn Sync + 'static)` cannot be known at compilation time - --> $DIR/const_refs_to_static-ice-121413.rs:8:24 + --> $DIR/const_refs_to_static-ice-121413.rs:9:24 | LL | static FOO: Sync = AtomicUsize::new(0); | ^^^^^^^^^^^^^^^^^^^ doesn't have a size known at compile-time diff --git a/tests/ui/consts/dangling-alloc-id-ice.rs b/tests/ui/consts/dangling-alloc-id-ice.rs index 6b07b8b3cc80d..76d6f33baf34b 100644 --- a/tests/ui/consts/dangling-alloc-id-ice.rs +++ b/tests/ui/consts/dangling-alloc-id-ice.rs @@ -10,7 +10,7 @@ union Foo<'a> { } const FOO: &() = { - //~^ ERROR encountered dangling pointer + //~^ ERROR it is undefined behavior to use this value let y = (); unsafe { Foo { y: &y }.long_live_the_unit } }; diff --git a/tests/ui/consts/dangling-alloc-id-ice.stderr b/tests/ui/consts/dangling-alloc-id-ice.stderr index de31acf9fa441..881c0b162edca 100644 --- a/tests/ui/consts/dangling-alloc-id-ice.stderr +++ b/tests/ui/consts/dangling-alloc-id-ice.stderr @@ -1,8 +1,14 @@ -error: encountered dangling pointer in final value of constant +error[E0080]: it is undefined behavior to use this value --> $DIR/dangling-alloc-id-ice.rs:12:1 | LL | const FOO: &() = { - | ^^^^^^^^^^^^^^ + | ^^^^^^^^^^^^^^ constructing invalid value: encountered a dangling reference (use-after-free) + | + = 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: $SIZE, align: $ALIGN) { + HEX_DUMP + } error: aborting due to 1 previous error +For more information about this error, try `rustc --explain E0080`. diff --git a/tests/ui/consts/dangling-zst-ice-issue-126393.rs b/tests/ui/consts/dangling-zst-ice-issue-126393.rs new file mode 100644 index 0000000000000..917aa0572fc0d --- /dev/null +++ b/tests/ui/consts/dangling-zst-ice-issue-126393.rs @@ -0,0 +1,15 @@ +// Strip out raw byte dumps to make comparison platform-independent: +//@ normalize-stderr-test "(the raw bytes of the constant) \(size: [0-9]*, align: [0-9]*\)" -> "$1 (size: $$SIZE, align: $$ALIGN)" +//@ normalize-stderr-test "([0-9a-f][0-9a-f] |╾─*A(LLOC)?[0-9]+(\+[a-z0-9]+)?()?─*╼ )+ *│.*" -> "HEX_DUMP" +//@ normalize-stderr-test "HEX_DUMP\s*\n\s*HEX_DUMP" -> "HEX_DUMP" + +pub struct Wrapper; +pub static MAGIC_FFI_REF: &'static Wrapper = unsafe { +//~^ERROR: it is undefined behavior to use this value + std::mem::transmute(&{ + let y = 42; + y + }) +}; + +fn main() {} diff --git a/tests/ui/consts/dangling-zst-ice-issue-126393.stderr b/tests/ui/consts/dangling-zst-ice-issue-126393.stderr new file mode 100644 index 0000000000000..d32b427f14ef7 --- /dev/null +++ b/tests/ui/consts/dangling-zst-ice-issue-126393.stderr @@ -0,0 +1,14 @@ +error[E0080]: it is undefined behavior to use this value + --> $DIR/dangling-zst-ice-issue-126393.rs:7:1 + | +LL | pub static MAGIC_FFI_REF: &'static Wrapper = unsafe { + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value: encountered a dangling reference (use-after-free) + | + = 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: $SIZE, align: $ALIGN) { + HEX_DUMP + } + +error: aborting due to 1 previous error + +For more information about this error, try `rustc --explain E0080`. diff --git a/tests/ui/consts/too_generic_eval_ice.stderr b/tests/ui/consts/too_generic_eval_ice.stderr index 54dffa3befcfa..58a61b938d6cb 100644 --- a/tests/ui/consts/too_generic_eval_ice.stderr +++ b/tests/ui/consts/too_generic_eval_ice.stderr @@ -22,14 +22,14 @@ LL | [5; Self::HOST_SIZE] == [6; 0] | = help: the trait `PartialEq<[{integer}; 0]>` is not implemented for `[{integer}; Self::HOST_SIZE]` = help: the following other types implement trait `PartialEq`: - <&[T] as PartialEq>> - <&[T] as PartialEq<[U; N]>> - <&mut [T] as PartialEq>> - <&mut [T] as PartialEq<[U; N]>> - <[T; N] as PartialEq<&[U]>> - <[T; N] as PartialEq<&mut [U]>> - <[T; N] as PartialEq<[U; N]>> - <[T; N] as PartialEq<[U]>> + `&[T]` implements `PartialEq>` + `&[T]` implements `PartialEq<[U; N]>` + `&mut [T]` implements `PartialEq>` + `&mut [T]` implements `PartialEq<[U; N]>` + `[T; N]` implements `PartialEq<&[U]>` + `[T; N]` implements `PartialEq<&mut [U]>` + `[T; N]` implements `PartialEq<[U; N]>` + `[T; N]` implements `PartialEq<[U]>` and 3 others error: aborting due to 3 previous errors diff --git a/tests/ui/delegation/macro-inside-list.rs b/tests/ui/delegation/macro-inside-list.rs index 16c74d396ef00..d07a4e47dd4cd 100644 --- a/tests/ui/delegation/macro-inside-list.rs +++ b/tests/ui/delegation/macro-inside-list.rs @@ -14,9 +14,9 @@ struct S(u8); // Macro expansion works inside delegation items. macro_rules! u8 { () => { u8 } } -macro_rules! self_0 { () => { &self.0 } } +macro_rules! self_0 { ($self:ident) => { &$self.0 } } impl Trait for S { - reuse ::{foo, bar} { self_0!() } + reuse ::{foo, bar} { self_0!(self) } } fn main() { diff --git a/tests/ui/delegation/not-supported.rs b/tests/ui/delegation/not-supported.rs index 5f78de97638b5..25d7a4cb89557 100644 --- a/tests/ui/delegation/not-supported.rs +++ b/tests/ui/delegation/not-supported.rs @@ -70,12 +70,16 @@ mod opaque { pub fn opaque_arg(_: impl Trait) -> i32 { 0 } pub fn opaque_ret() -> impl Trait { unimplemented!() } + //~^ warn: this function depends on never type fallback being `()` + //~| warn: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! } reuse to_reuse::opaque_arg; //~^ ERROR delegation with early bound generics is not supported yet trait ToReuse { fn opaque_ret() -> impl Trait { unimplemented!() } + //~^ warn: this function depends on never type fallback being `()` + //~| warn: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! } // FIXME: Inherited `impl Trait`s create query cycles when used inside trait impls. diff --git a/tests/ui/delegation/not-supported.stderr b/tests/ui/delegation/not-supported.stderr index e2cb04f977b1e..4ce01fd5d8827 100644 --- a/tests/ui/delegation/not-supported.stderr +++ b/tests/ui/delegation/not-supported.stderr @@ -107,7 +107,7 @@ LL | reuse Trait::foo2 { &self.0 } | ^^^^ error: delegation with early bound generics is not supported yet - --> $DIR/not-supported.rs:74:21 + --> $DIR/not-supported.rs:76:21 | LL | pub fn opaque_arg(_: impl Trait) -> i32 { 0 } | --------------------------------------- callee defined here @@ -115,46 +115,77 @@ LL | pub fn opaque_arg(_: impl Trait) -> i32 { 0 } LL | reuse to_reuse::opaque_arg; | ^^^^^^^^^^ -error[E0391]: cycle detected when computing type of `opaque::::{synthetic#0}` - --> $DIR/not-supported.rs:83:25 +warning: this function depends on never type fallback being `()` + --> $DIR/not-supported.rs:80:9 + | +LL | fn opaque_ret() -> impl Trait { unimplemented!() } + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | + = 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 #123748 + = help: specify the types explicitly +note: in edition 2024, the requirement `!: opaque::Trait` will fail + --> $DIR/not-supported.rs:80:28 + | +LL | fn opaque_ret() -> impl Trait { unimplemented!() } + | ^^^^^^^^^^ + = note: `#[warn(dependency_on_unit_never_type_fallback)]` on by default + +error[E0391]: cycle detected when computing type of `opaque::::{synthetic#0}` + --> $DIR/not-supported.rs:87:25 | LL | reuse to_reuse::opaque_ret; | ^^^^^^^^^^ | note: ...which requires comparing an impl and trait method signature, inferring any hidden `impl Trait` types in the process... - --> $DIR/not-supported.rs:83:25 + --> $DIR/not-supported.rs:87:25 | LL | reuse to_reuse::opaque_ret; | ^^^^^^^^^^ - = note: ...which again requires computing type of `opaque::::{synthetic#0}`, completing the cycle -note: cycle used when checking that `opaque::` is well-formed - --> $DIR/not-supported.rs:82:5 + = note: ...which again requires computing type of `opaque::::{synthetic#0}`, completing the cycle +note: cycle used when checking that `opaque::` is well-formed + --> $DIR/not-supported.rs:86:5 | LL | impl ToReuse for u8 { | ^^^^^^^^^^^^^^^^^^^ = note: see https://rustc-dev-guide.rust-lang.org/overview.html#queries and https://rustc-dev-guide.rust-lang.org/query.html for more information -error[E0391]: cycle detected when computing type of `opaque::::{synthetic#0}` - --> $DIR/not-supported.rs:86:24 +warning: this function depends on never type fallback being `()` + --> $DIR/not-supported.rs:72:9 + | +LL | pub fn opaque_ret() -> impl Trait { unimplemented!() } + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | + = 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 #123748 + = help: specify the types explicitly +note: in edition 2024, the requirement `!: opaque::Trait` will fail + --> $DIR/not-supported.rs:72:32 + | +LL | pub fn opaque_ret() -> impl Trait { unimplemented!() } + | ^^^^^^^^^^ + +error[E0391]: cycle detected when computing type of `opaque::::{synthetic#0}` + --> $DIR/not-supported.rs:90:24 | LL | reuse ToReuse::opaque_ret; | ^^^^^^^^^^ | note: ...which requires comparing an impl and trait method signature, inferring any hidden `impl Trait` types in the process... - --> $DIR/not-supported.rs:86:24 + --> $DIR/not-supported.rs:90:24 | LL | reuse ToReuse::opaque_ret; | ^^^^^^^^^^ - = note: ...which again requires computing type of `opaque::::{synthetic#0}`, completing the cycle -note: cycle used when checking that `opaque::` is well-formed - --> $DIR/not-supported.rs:85:5 + = note: ...which again requires computing type of `opaque::::{synthetic#0}`, completing the cycle +note: cycle used when checking that `opaque::` is well-formed + --> $DIR/not-supported.rs:89:5 | LL | impl ToReuse for u16 { | ^^^^^^^^^^^^^^^^^^^^ = note: see https://rustc-dev-guide.rust-lang.org/overview.html#queries and https://rustc-dev-guide.rust-lang.org/query.html for more information error: recursive delegation is not supported yet - --> $DIR/not-supported.rs:99:22 + --> $DIR/not-supported.rs:103:22 | LL | pub reuse to_reuse2::foo; | --- callee defined here @@ -162,7 +193,7 @@ LL | pub reuse to_reuse2::foo; LL | reuse to_reuse1::foo; | ^^^ -error: aborting due to 16 previous errors +error: aborting due to 16 previous errors; 2 warnings emitted Some errors have detailed explanations: E0049, E0195, E0391. For more information about an error, try `rustc --explain E0049`. diff --git a/tests/ui/delegation/self-hygiene.rs b/tests/ui/delegation/self-hygiene.rs new file mode 100644 index 0000000000000..dac6c319416a3 --- /dev/null +++ b/tests/ui/delegation/self-hygiene.rs @@ -0,0 +1,20 @@ +#![feature(fn_delegation)] +#![allow(incomplete_features)] + +macro_rules! emit_self { () => { self } } +//~^ ERROR expected value, found module `self` +//~| ERROR expected value, found module `self` + +struct S; +impl S { + fn method(self) { + emit_self!(); + } +} + +fn foo(arg: u8) {} +reuse foo as bar { + emit_self!() +} + +fn main() {} diff --git a/tests/ui/delegation/self-hygiene.stderr b/tests/ui/delegation/self-hygiene.stderr new file mode 100644 index 0000000000000..fa64b7d1d7f7b --- /dev/null +++ b/tests/ui/delegation/self-hygiene.stderr @@ -0,0 +1,31 @@ +error[E0424]: expected value, found module `self` + --> $DIR/self-hygiene.rs:4:34 + | +LL | macro_rules! emit_self { () => { self } } + | ^^^^ `self` value is a keyword only available in methods with a `self` parameter +... +LL | / fn method(self) { +LL | | emit_self!(); + | | ------------ in this macro invocation +LL | | } + | |_____- this function has a `self` parameter, but a macro invocation can only access identifiers it receives from parameters + | + = note: this error originates in the macro `emit_self` (in Nightly builds, run with -Z macro-backtrace for more info) + +error[E0424]: expected value, found module `self` + --> $DIR/self-hygiene.rs:4:34 + | +LL | macro_rules! emit_self { () => { self } } + | ^^^^ `self` value is a keyword only available in methods with a `self` parameter +... +LL | / reuse foo as bar { +LL | | emit_self!() + | | ------------ in this macro invocation +LL | | } + | |_- delegation supports a `self` parameter, but a macro invocation can only access identifiers it receives from parameters + | + = note: this error originates in the macro `emit_self` (in Nightly builds, run with -Z macro-backtrace for more info) + +error: aborting due to 2 previous errors + +For more information about this error, try `rustc --explain E0424`. diff --git a/tests/ui/diagnostic_namespace/do_not_recommend/as_expression.next.stderr b/tests/ui/diagnostic_namespace/do_not_recommend/as_expression.next.stderr index 568cb8931a198..d189d2dbdedc8 100644 --- a/tests/ui/diagnostic_namespace/do_not_recommend/as_expression.next.stderr +++ b/tests/ui/diagnostic_namespace/do_not_recommend/as_expression.next.stderr @@ -25,7 +25,7 @@ LL | SelectInt.check("bar"); = help: the trait `AsExpression` is implemented for `&str` = help: for that trait implementation, expected `Text`, found `Integer` -error[E0271]: type mismatch resolving `<&str as AsExpression<::SqlType>>::Expression == _` +error[E0271]: type mismatch resolving `::SqlType == Text` --> $DIR/as_expression.rs:57:5 | LL | SelectInt.check("bar"); diff --git a/tests/ui/did_you_mean/issue-21659-show-relevant-trait-impls-1.stderr b/tests/ui/did_you_mean/issue-21659-show-relevant-trait-impls-1.stderr index 9cbce93c8e009..9d335b391eb19 100644 --- a/tests/ui/did_you_mean/issue-21659-show-relevant-trait-impls-1.stderr +++ b/tests/ui/did_you_mean/issue-21659-show-relevant-trait-impls-1.stderr @@ -7,8 +7,8 @@ LL | f1.foo(1usize); | required by a bound introduced by this call | = help: the following other types implement trait `Foo`: - > - > + `Bar` implements `Foo` + `Bar` implements `Foo` error: aborting due to 1 previous error diff --git a/tests/ui/did_you_mean/issue-21659-show-relevant-trait-impls-2.stderr b/tests/ui/did_you_mean/issue-21659-show-relevant-trait-impls-2.stderr index a2b7d804cb8c2..f9d7180796015 100644 --- a/tests/ui/did_you_mean/issue-21659-show-relevant-trait-impls-2.stderr +++ b/tests/ui/did_you_mean/issue-21659-show-relevant-trait-impls-2.stderr @@ -7,12 +7,12 @@ LL | f1.foo(1usize); | required by a bound introduced by this call | = help: the following other types implement trait `Foo`: - > - > - > - > - > - > + `Bar` implements `Foo` + `Bar` implements `Foo` + `Bar` implements `Foo` + `Bar` implements `Foo` + `Bar` implements `Foo` + `Bar` implements `Foo` error: aborting due to 1 previous error diff --git a/tests/ui/did_you_mean/issue-39802-show-5-trait-impls.stderr b/tests/ui/did_you_mean/issue-39802-show-5-trait-impls.stderr index 7229b9ac986ac..b502030443954 100644 --- a/tests/ui/did_you_mean/issue-39802-show-5-trait-impls.stderr +++ b/tests/ui/did_you_mean/issue-39802-show-5-trait-impls.stderr @@ -7,11 +7,11 @@ LL | Foo::::bar(&1i8); | required by a bound introduced by this call | = help: the following other types implement trait `Foo`: - > - > - > - > - > + `i8` implements `Foo` + `i8` implements `Foo` + `i8` implements `Foo` + `i8` implements `Foo` + `i8` implements `Foo` error[E0277]: the trait bound `u8: Foo` is not satisfied --> $DIR/issue-39802-show-5-trait-impls.rs:25:21 @@ -22,10 +22,10 @@ LL | Foo::::bar(&1u8); | required by a bound introduced by this call | = help: the following other types implement trait `Foo`: - > - > - > - > + `u8` implements `Foo` + `u8` implements `Foo` + `u8` implements `Foo` + `u8` implements `Foo` error[E0277]: the trait bound `bool: Foo` is not satisfied --> $DIR/issue-39802-show-5-trait-impls.rs:26:21 @@ -36,12 +36,12 @@ LL | Foo::::bar(&true); | required by a bound introduced by this call | = help: the following other types implement trait `Foo`: - > - > - > - > - > - > + `bool` implements `Foo` + `bool` implements `Foo` + `bool` implements `Foo` + `bool` implements `Foo` + `bool` implements `Foo` + `bool` implements `Foo` error: aborting due to 3 previous errors diff --git a/tests/ui/did_you_mean/issue-56028-there-is-an-enum-variant.stderr b/tests/ui/did_you_mean/issue-56028-there-is-an-enum-variant.stderr index 5c610f36322dc..b1a15b8594a0a 100644 --- a/tests/ui/did_you_mean/issue-56028-there-is-an-enum-variant.stderr +++ b/tests/ui/did_you_mean/issue-56028-there-is-an-enum-variant.stderr @@ -22,7 +22,7 @@ error[E0425]: cannot find value `Set` in this scope LL | fn setup() -> Set { Set } | ^^^ not found in this scope | -help: consider importing one of these items +help: consider importing one of these unit variants | LL + use AffixHeart::Set; | diff --git a/tests/ui/editions/never-type-fallback-breaking.e2021.stderr b/tests/ui/editions/never-type-fallback-breaking.e2021.stderr new file mode 100644 index 0000000000000..134fd098b7e4a --- /dev/null +++ b/tests/ui/editions/never-type-fallback-breaking.e2021.stderr @@ -0,0 +1,33 @@ +warning: this function depends on never type fallback being `()` + --> $DIR/never-type-fallback-breaking.rs:15:1 + | +LL | fn m() { + | ^^^^^^ + | + = 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 #123748 + = help: specify the types explicitly +note: in edition 2024, the requirement `!: Default` will fail + --> $DIR/never-type-fallback-breaking.rs:19:17 + | +LL | true => Default::default(), + | ^^^^^^^^^^^^^^^^^^ + = note: `#[warn(dependency_on_unit_never_type_fallback)]` on by default + +warning: this function depends on never type fallback being `()` + --> $DIR/never-type-fallback-breaking.rs:27:1 + | +LL | fn q() -> Option<()> { + | ^^^^^^^^^^^^^^^^^^^^ + | + = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! + = note: for more information, see issue #123748 + = help: specify the types explicitly +note: in edition 2024, the requirement `!: Default` will fail + --> $DIR/never-type-fallback-breaking.rs:34:5 + | +LL | deserialize()?; + | ^^^^^^^^^^^^^ + +warning: 2 warnings emitted + diff --git a/tests/ui/editions/never-type-fallback-breaking.e2024.stderr b/tests/ui/editions/never-type-fallback-breaking.e2024.stderr index e9a8882eb6ca1..461e4ae0bdf6d 100644 --- a/tests/ui/editions/never-type-fallback-breaking.e2024.stderr +++ b/tests/ui/editions/never-type-fallback-breaking.e2024.stderr @@ -1,5 +1,5 @@ error[E0277]: the trait bound `!: Default` is not satisfied - --> $DIR/never-type-fallback-breaking.rs:17:17 + --> $DIR/never-type-fallback-breaking.rs:19:17 | LL | true => Default::default(), | ^^^^^^^^^^^^^^^^^^ the trait `Default` is not implemented for `!` @@ -8,7 +8,7 @@ LL | true => Default::default(), = help: did you intend to use the type `()` here instead? error[E0277]: the trait bound `!: Default` is not satisfied - --> $DIR/never-type-fallback-breaking.rs:30:5 + --> $DIR/never-type-fallback-breaking.rs:34:5 | LL | deserialize()?; | ^^^^^^^^^^^^^ the trait `Default` is not implemented for `!` @@ -16,7 +16,7 @@ LL | deserialize()?; = note: this error might have been caused by changes to Rust's type-inference algorithm (see issue #48950 for more information) = help: did you intend to use the type `()` here instead? note: required by a bound in `deserialize` - --> $DIR/never-type-fallback-breaking.rs:26:23 + --> $DIR/never-type-fallback-breaking.rs:30:23 | LL | fn deserialize() -> Option { | ^^^^^^^ required by this bound in `deserialize` diff --git a/tests/ui/editions/never-type-fallback-breaking.rs b/tests/ui/editions/never-type-fallback-breaking.rs index 7dfa4702807b5..7b4a1b1de0487 100644 --- a/tests/ui/editions/never-type-fallback-breaking.rs +++ b/tests/ui/editions/never-type-fallback-breaking.rs @@ -13,6 +13,8 @@ fn main() { } fn m() { + //[e2021]~^ this function depends on never type fallback being `()` + //[e2021]~| this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! let x = match true { true => Default::default(), //[e2024]~^ error: the trait bound `!: Default` is not satisfied @@ -23,6 +25,8 @@ fn m() { } fn q() -> Option<()> { + //[e2021]~^ this function depends on never type fallback being `()` + //[e2021]~| this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! fn deserialize() -> Option { Some(T::default()) } diff --git a/tests/ui/feature-gates/feature-gate-macro-metavar-expr-concat.rs b/tests/ui/feature-gates/feature-gate-macro-metavar-expr-concat.rs new file mode 100644 index 0000000000000..e700999ae4bd8 --- /dev/null +++ b/tests/ui/feature-gates/feature-gate-macro-metavar-expr-concat.rs @@ -0,0 +1,9 @@ +macro_rules! join { + ($lhs:ident, $rhs:ident) => { + let ${concat($lhs, $rhs)}: () = (); + //~^ ERROR the `concat` meta-variable expression is unstable + }; +} + +fn main() { +} diff --git a/tests/ui/feature-gates/feature-gate-macro-metavar-expr-concat.stderr b/tests/ui/feature-gates/feature-gate-macro-metavar-expr-concat.stderr new file mode 100644 index 0000000000000..5b2589d8c89be --- /dev/null +++ b/tests/ui/feature-gates/feature-gate-macro-metavar-expr-concat.stderr @@ -0,0 +1,13 @@ +error[E0658]: the `concat` meta-variable expression is unstable + --> $DIR/feature-gate-macro-metavar-expr-concat.rs:3:14 + | +LL | let ${concat($lhs, $rhs)}: () = (); + | ^^^^^^^^^^^^^^^^^^^^ + | + = note: see issue #124225 for more information + = help: add `#![feature(macro_metavar_expr_concat)]` to the crate attributes to enable + = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date + +error: aborting due to 1 previous error + +For more information about this error, try `rustc --explain E0658`. diff --git a/tests/ui/generic-associated-types/assume-gat-normalization-for-nested-goals.next.stderr b/tests/ui/generic-associated-types/assume-gat-normalization-for-nested-goals.next.stderr index 2c372b6c3a78e..9b5d84b5b090e 100644 --- a/tests/ui/generic-associated-types/assume-gat-normalization-for-nested-goals.next.stderr +++ b/tests/ui/generic-associated-types/assume-gat-normalization-for-nested-goals.next.stderr @@ -2,7 +2,7 @@ error[E0277]: the trait bound `i32: Baz` is not satisfied --> $DIR/assume-gat-normalization-for-nested-goals.rs:9:30 | LL | type Bar: Baz = i32; - | ^^^ the trait `Eq` is not implemented for `i32`, which is required by `i32: Baz` + | ^^^ the trait `Eq` is not implemented for `::Bar<()>`, which is required by `i32: Baz` | note: required for `i32` to implement `Baz` --> $DIR/assume-gat-normalization-for-nested-goals.rs:16:23 diff --git a/tests/ui/generic-associated-types/static-lifetime-tip-with-default-type.rs b/tests/ui/generic-associated-types/static-lifetime-tip-with-default-type.rs new file mode 100644 index 0000000000000..68879a0af292a --- /dev/null +++ b/tests/ui/generic-associated-types/static-lifetime-tip-with-default-type.rs @@ -0,0 +1,26 @@ +//@ error-pattern: r#T: 'static +//@ error-pattern: r#K: 'static +//@ error-pattern: T: 'static= + +// https://github.com/rust-lang/rust/issues/124785 + +struct Foo(&'static T, &'static K); +//~^ ERROR: the parameter type `T` may not live long enough +//~| ERROR: the parameter type `K` may not live long enough + +struct Bar(&'static r#T, &'static r#K); +//~^ ERROR: the parameter type `T` may not live long enough +//~| ERROR: the parameter type `K` may not live long enough + +struct Boo(&'static T); +//~^ ERROR: the parameter type `T` may not live long enough + +struct Far(&'static T); +//~^ ERROR: the parameter type `T` may not live long enough + +struct S<'a, K: 'a = i32>(&'static K); +//~^ ERROR: lifetime parameter `'a` is never used +//~| ERROR: the parameter type `K` may not live long enough + +fn main() {} diff --git a/tests/ui/generic-associated-types/static-lifetime-tip-with-default-type.stderr b/tests/ui/generic-associated-types/static-lifetime-tip-with-default-type.stderr new file mode 100644 index 0000000000000..7d985a9013f19 --- /dev/null +++ b/tests/ui/generic-associated-types/static-lifetime-tip-with-default-type.stderr @@ -0,0 +1,110 @@ +error[E0310]: the parameter type `T` may not live long enough + --> $DIR/static-lifetime-tip-with-default-type.rs:7:24 + | +LL | struct Foo(&'static T, &'static K); + | ^^^^^^^^^^ + | | + | the parameter type `T` must be valid for the static lifetime... + | ...so that the reference type `&'static T` does not outlive the data it points at + | +help: consider adding an explicit lifetime bound + | +LL | struct Foo(&'static T, &'static K); + | +++++++++ + +error[E0310]: the parameter type `K` may not live long enough + --> $DIR/static-lifetime-tip-with-default-type.rs:7:36 + | +LL | struct Foo(&'static T, &'static K); + | ^^^^^^^^^^ + | | + | the parameter type `K` must be valid for the static lifetime... + | ...so that the reference type `&'static K` does not outlive the data it points at + | +help: consider adding an explicit lifetime bound + | +LL | struct Foo(&'static T, &'static K); + | +++++++++ + +error[E0310]: the parameter type `T` may not live long enough + --> $DIR/static-lifetime-tip-with-default-type.rs:11:28 + | +LL | struct Bar(&'static r#T, &'static r#K); + | ^^^^^^^^^^^^ + | | + | the parameter type `T` must be valid for the static lifetime... + | ...so that the reference type `&'static T` does not outlive the data it points at + | +help: consider adding an explicit lifetime bound + | +LL | struct Bar(&'static r#T, &'static r#K); + | +++++++++ + +error[E0310]: the parameter type `K` may not live long enough + --> $DIR/static-lifetime-tip-with-default-type.rs:11:42 + | +LL | struct Bar(&'static r#T, &'static r#K); + | ^^^^^^^^^^^^ + | | + | the parameter type `K` must be valid for the static lifetime... + | ...so that the reference type `&'static K` does not outlive the data it points at + | +help: consider adding an explicit lifetime bound + | +LL | struct Bar(&'static r#T, &'static r#K); + | +++++++++ + +error[E0310]: the parameter type `T` may not live long enough + --> $DIR/static-lifetime-tip-with-default-type.rs:15:20 + | +LL | struct Boo(&'static T); + | ^^^^^^^^^^ + | | + | the parameter type `T` must be valid for the static lifetime... + | ...so that the reference type `&'static T` does not outlive the data it points at + | +help: consider adding an explicit lifetime bound + | +LL | struct Boo(&'static T); + | +++++++++ + +error[E0310]: the parameter type `T` may not live long enough + --> $DIR/static-lifetime-tip-with-default-type.rs:19:8 + | +LL | = i32>(&'static T); + | ^^^^^^^^^^ + | | + | the parameter type `T` must be valid for the static lifetime... + | ...so that the reference type `&'static T` does not outlive the data it points at + | +help: consider adding an explicit lifetime bound + | +LL | struct Far $DIR/static-lifetime-tip-with-default-type.rs:22:27 + | +LL | struct S<'a, K: 'a = i32>(&'static K); + | ^^^^^^^^^^ + | | + | the parameter type `K` must be valid for the static lifetime... + | ...so that the reference type `&'static K` does not outlive the data it points at + | +help: consider adding an explicit lifetime bound + | +LL | struct S<'a, K: 'a + 'static = i32>(&'static K); + | +++++++++ + +error[E0392]: lifetime parameter `'a` is never used + --> $DIR/static-lifetime-tip-with-default-type.rs:22:10 + | +LL | struct S<'a, K: 'a = i32>(&'static K); + | ^^ unused lifetime parameter + | + = help: consider removing `'a`, referring to it in a field, or using a marker such as `PhantomData` + +error: aborting due to 8 previous errors + +Some errors have detailed explanations: E0310, E0392. +For more information about an error, try `rustc --explain E0310`. diff --git a/tests/ui/generics/impl-block-params-declared-in-wrong-spot-issue-113073.rs b/tests/ui/generics/impl-block-params-declared-in-wrong-spot-issue-113073.rs new file mode 100644 index 0000000000000..3a5b60e5763b3 --- /dev/null +++ b/tests/ui/generics/impl-block-params-declared-in-wrong-spot-issue-113073.rs @@ -0,0 +1,33 @@ +trait Foo {} + +impl Foo for String {} +//~^ ERROR associated item constraints are not allowed here +//~| HELP declare the type parameter right after the `impl` keyword + +impl Foo for u8 {} +//~^ ERROR associated item constraints are not allowed here +//~| HELP declare the type parameter right after the `impl` keyword +//~| ERROR use of undeclared lifetime name `'a` +//~| HELP consider introducing lifetime `'a` here + +impl Foo for u16 {} +//~^ ERROR associated item constraints are not allowed here +//~| HELP declare the type parameter right after the `impl` keyword + +impl<'a> Foo for u32 {} +//~^ ERROR associated item constraints are not allowed here +//~| HELP declare the type parameter right after the `impl` keyword + +trait Bar {} + +impl Bar for String {} +//~^ ERROR associated item constraints are not allowed here +//~| HELP declare the type parameter right after the `impl` keyword + +impl Bar for u8 {} +//~^ ERROR trait takes 2 generic arguments but 1 generic argument was supplied +//~| HELP add missing generic argument +//~| ERROR associated item constraints are not allowed here +//~| HELP declare the type parameter right after the `impl` keyword + +fn main() {} diff --git a/tests/ui/generics/impl-block-params-declared-in-wrong-spot-issue-113073.stderr b/tests/ui/generics/impl-block-params-declared-in-wrong-spot-issue-113073.stderr new file mode 100644 index 0000000000000..dfc6761e17e7f --- /dev/null +++ b/tests/ui/generics/impl-block-params-declared-in-wrong-spot-issue-113073.stderr @@ -0,0 +1,96 @@ +error[E0261]: use of undeclared lifetime name `'a` + --> $DIR/impl-block-params-declared-in-wrong-spot-issue-113073.rs:7:13 + | +LL | impl Foo for u8 {} + | - ^^ undeclared lifetime + | | + | help: consider introducing lifetime `'a` here: `<'a>` + +error[E0229]: associated item constraints are not allowed here + --> $DIR/impl-block-params-declared-in-wrong-spot-issue-113073.rs:3:10 + | +LL | impl Foo for String {} + | ^^^^^^^^^^ associated item constraint not allowed here + | +help: declare the type parameter right after the `impl` keyword + | +LL | impl Foo for String {} + | ++++++++++++ ~ + +error[E0229]: associated item constraints are not allowed here + --> $DIR/impl-block-params-declared-in-wrong-spot-issue-113073.rs:7:10 + | +LL | impl Foo for u8 {} + | ^^^^^^^^^^^^^^^ associated item constraint not allowed here + | +help: declare the type parameter right after the `impl` keyword + | +LL | impl<'a, T: 'a + Default> Foo for u8 {} + | +++++++++++++++++++++ ~ + +error[E0229]: associated item constraints are not allowed here + --> $DIR/impl-block-params-declared-in-wrong-spot-issue-113073.rs:13:13 + | +LL | impl Foo for u16 {} + | ^^^^^^^^^^ associated item constraint not allowed here + | +help: declare the type parameter right after the `impl` keyword + | +LL | impl Foo for u16 {} + | ++++++++++++ ~ + +error[E0229]: associated item constraints are not allowed here + --> $DIR/impl-block-params-declared-in-wrong-spot-issue-113073.rs:17:14 + | +LL | impl<'a> Foo for u32 {} + | ^^^^^^^^^^^^^^^ associated item constraint not allowed here + | +help: declare the type parameter right after the `impl` keyword + | +LL | impl<'a, 'a, T: 'a + Default> Foo for u32 {} + | +++++++++++++++++++++ ~ + +error[E0229]: associated item constraints are not allowed here + --> $DIR/impl-block-params-declared-in-wrong-spot-issue-113073.rs:23:10 + | +LL | impl Bar for String {} + | ^^^^^^^^^^ associated item constraint not allowed here + | +help: declare the type parameter right after the `impl` keyword + | +LL | impl Bar for String {} + | ++++++++++++ ~ + +error[E0107]: trait takes 2 generic arguments but 1 generic argument was supplied + --> $DIR/impl-block-params-declared-in-wrong-spot-issue-113073.rs:27:9 + | +LL | impl Bar for u8 {} + | ^^^ - supplied 1 generic argument + | | + | expected 2 generic arguments + | +note: trait defined here, with 2 generic parameters: `T`, `K` + --> $DIR/impl-block-params-declared-in-wrong-spot-issue-113073.rs:21:7 + | +LL | trait Bar {} + | ^^^ - - +help: add missing generic argument + | +LL | impl Bar for u8 {} + | +++ + +error[E0229]: associated item constraints are not allowed here + --> $DIR/impl-block-params-declared-in-wrong-spot-issue-113073.rs:27:16 + | +LL | impl Bar for u8 {} + | ^^^^^^^^^^ associated item constraint not allowed here + | +help: declare the type parameter right after the `impl` keyword + | +LL | impl Bar for u8 {} + | ++++++++++++ ~ + +error: aborting due to 8 previous errors + +Some errors have detailed explanations: E0107, E0229, E0261. +For more information about an error, try `rustc --explain E0107`. diff --git a/tests/ui/higher-ranked/trait-bounds/rigid-equate-projections-in-higher-ranked-fn-signature.next.stderr b/tests/ui/higher-ranked/trait-bounds/rigid-equate-projections-in-higher-ranked-fn-signature.next.stderr index 14a3d5e178d43..31d74d1c022a1 100644 --- a/tests/ui/higher-ranked/trait-bounds/rigid-equate-projections-in-higher-ranked-fn-signature.next.stderr +++ b/tests/ui/higher-ranked/trait-bounds/rigid-equate-projections-in-higher-ranked-fn-signature.next.stderr @@ -1,8 +1,8 @@ -error[E0284]: type annotations needed: cannot satisfy `for<'a> <_ as Trait<'a>>::Assoc <: >::Assoc` +error[E0284]: type annotations needed: cannot satisfy `for<'a> <_ as Trait<'a>>::Assoc normalizes-to >::Assoc` --> $DIR/rigid-equate-projections-in-higher-ranked-fn-signature.rs:27:50 | LL | let _: for<'a> fn(<_ as Trait<'a>>::Assoc) = foo::(); - | ^^^^^^^^^^ cannot satisfy `for<'a> <_ as Trait<'a>>::Assoc <: >::Assoc` + | ^^^^^^^^^^ cannot satisfy `for<'a> <_ as Trait<'a>>::Assoc normalizes-to >::Assoc` error: aborting due to 1 previous error diff --git a/tests/ui/hygiene/extern-prelude-from-opaque-fail-2018.stderr b/tests/ui/hygiene/extern-prelude-from-opaque-fail-2018.stderr index 78e6376bca2e8..cc229764ad3fb 100644 --- a/tests/ui/hygiene/extern-prelude-from-opaque-fail-2018.stderr +++ b/tests/ui/hygiene/extern-prelude-from-opaque-fail-2018.stderr @@ -24,8 +24,7 @@ LL | fn f() { my_core::mem::drop(0); } LL | a!(); | ---- in this macro invocation | - = help: consider importing one of these items: - core::mem + = help: consider importing this module: std::mem = note: this error originates in the macro `a` (in Nightly builds, run with -Z macro-backtrace for more info) @@ -35,9 +34,7 @@ error[E0433]: failed to resolve: use of undeclared crate or module `my_core` LL | fn f() { my_core::mem::drop(0); } | ^^^^^^^ use of undeclared crate or module `my_core` | -help: consider importing one of these items - | -LL + use core::mem; +help: consider importing this module | LL + use std::mem; | diff --git a/tests/ui/impl-trait/associated-type-undefine.rs b/tests/ui/impl-trait/associated-type-undefine.rs new file mode 100644 index 0000000000000..c8f07021fbf16 --- /dev/null +++ b/tests/ui/impl-trait/associated-type-undefine.rs @@ -0,0 +1,28 @@ +#![feature(impl_trait_in_assoc_type)] + +trait Foo: Sized { + type Bar; + type Gat; + fn foo(self) -> (::Gat, ::Gat); +} + +impl Foo for u32 { + type Bar = (); + type Gat = (); + fn foo(self) -> (::Gat, ::Gat) { + ((), ()) + } +} + +impl Foo for () { + type Bar = impl Sized; + type Gat = ::Bar; + // Because we encounter `Gat` first, we never walk into another `Gat` + // again, thus missing the opaque type that we could be defining. + fn foo(self) -> (::Gat, ::Gat) { + ((), ()) + //~^ ERROR: mismatched types + } +} + +fn main() {} diff --git a/tests/ui/impl-trait/associated-type-undefine.stderr b/tests/ui/impl-trait/associated-type-undefine.stderr new file mode 100644 index 0000000000000..5d9d525eb93bf --- /dev/null +++ b/tests/ui/impl-trait/associated-type-undefine.stderr @@ -0,0 +1,20 @@ +error[E0308]: mismatched types + --> $DIR/associated-type-undefine.rs:23:14 + | +LL | type Bar = impl Sized; + | ---------- the expected opaque type +... +LL | ((), ()) + | ^^ expected opaque type, found `()` + | + = note: expected opaque type `<() as Foo>::Bar` + found unit type `()` +note: this item must have the opaque type in its signature in order to be able to register hidden types + --> $DIR/associated-type-undefine.rs:22:8 + | +LL | fn foo(self) -> (::Gat, ::Gat) { + | ^^^ + +error: aborting due to 1 previous error + +For more information about this error, try `rustc --explain E0308`. diff --git a/tests/ui/impl-trait/call_method_ambiguous.next.stderr b/tests/ui/impl-trait/call_method_ambiguous.next.stderr new file mode 100644 index 0000000000000..cd222aa7ae9fc --- /dev/null +++ b/tests/ui/impl-trait/call_method_ambiguous.next.stderr @@ -0,0 +1,17 @@ +error[E0282]: type annotations needed + --> $DIR/call_method_ambiguous.rs:29:13 + | +LL | let mut iter = foo(n - 1, m); + | ^^^^^^^^ +LL | +LL | assert_eq!(iter.get(), 1); + | ---- type must be known at this point + | +help: consider giving `iter` an explicit type + | +LL | let mut iter: /* Type */ = foo(n - 1, m); + | ++++++++++++ + +error: aborting due to 1 previous error + +For more information about this error, try `rustc --explain E0282`. diff --git a/tests/ui/impl-trait/call_method_ambiguous.rs b/tests/ui/impl-trait/call_method_ambiguous.rs new file mode 100644 index 0000000000000..c26c01e002d85 --- /dev/null +++ b/tests/ui/impl-trait/call_method_ambiguous.rs @@ -0,0 +1,39 @@ +//@ revisions: current next +//@[next] compile-flags: -Znext-solver +//@[current] run-pass + +#![feature(precise_capturing)] +#![allow(incomplete_features)] + +trait Get { + fn get(&mut self) -> u32; +} + +impl Get for () { + fn get(&mut self) -> u32 { + 0 + } +} + +impl Get for &mut T +where + T: Get, +{ + fn get(&mut self) -> u32 { + T::get(self) + 1 + } +} + +fn foo(n: usize, m: &mut ()) -> impl use<'_> Get { + if n > 0 { + let mut iter = foo(n - 1, m); + //[next]~^ type annotations needed + assert_eq!(iter.get(), 1); + } + m +} + +fn main() { + let g = foo(1, &mut ()).get(); + assert_eq!(g, 1); +} diff --git a/tests/ui/impl-trait/call_method_on_inherent_impl.next.stderr b/tests/ui/impl-trait/call_method_on_inherent_impl.next.stderr new file mode 100644 index 0000000000000..271051f120abc --- /dev/null +++ b/tests/ui/impl-trait/call_method_on_inherent_impl.next.stderr @@ -0,0 +1,17 @@ +error[E0282]: type annotations needed + --> $DIR/call_method_on_inherent_impl.rs:18:13 + | +LL | let x = my_foo(); + | ^ +LL | +LL | x.my_debug(); + | - type must be known at this point + | +help: consider giving `x` an explicit type + | +LL | let x: /* Type */ = my_foo(); + | ++++++++++++ + +error: aborting due to 1 previous error + +For more information about this error, try `rustc --explain E0282`. diff --git a/tests/ui/impl-trait/call_method_on_inherent_impl.rs b/tests/ui/impl-trait/call_method_on_inherent_impl.rs new file mode 100644 index 0000000000000..17f7cad660db1 --- /dev/null +++ b/tests/ui/impl-trait/call_method_on_inherent_impl.rs @@ -0,0 +1,25 @@ +//@ revisions: current next +//@[next] compile-flags: -Znext-solver +//@[current] check-pass + +trait MyDebug { + fn my_debug(&self); +} + +impl MyDebug for T +where + T: std::fmt::Debug, +{ + fn my_debug(&self) {} +} + +fn my_foo() -> impl std::fmt::Debug { + if false { + let x = my_foo(); + //[next]~^ type annotations needed + x.my_debug(); + } + () +} + +fn main() {} diff --git a/tests/ui/impl-trait/call_method_on_inherent_impl_on_rigid_type.current.stderr b/tests/ui/impl-trait/call_method_on_inherent_impl_on_rigid_type.current.stderr new file mode 100644 index 0000000000000..6ecb2b05fc56b --- /dev/null +++ b/tests/ui/impl-trait/call_method_on_inherent_impl_on_rigid_type.current.stderr @@ -0,0 +1,16 @@ +error[E0599]: no method named `my_debug` found for reference `&impl Debug` in the current scope + --> $DIR/call_method_on_inherent_impl_on_rigid_type.rs:16:11 + | +LL | x.my_debug(); + | ^^^^^^^^ method not found in `&impl Debug` + | + = help: items from traits can only be used if the trait is implemented and in scope +note: `MyDebug` defines an item `my_debug`, perhaps you need to implement it + --> $DIR/call_method_on_inherent_impl_on_rigid_type.rs:4:1 + | +LL | trait MyDebug { + | ^^^^^^^^^^^^^ + +error: aborting due to 1 previous error + +For more information about this error, try `rustc --explain E0599`. diff --git a/tests/ui/impl-trait/call_method_on_inherent_impl_on_rigid_type.next.stderr b/tests/ui/impl-trait/call_method_on_inherent_impl_on_rigid_type.next.stderr new file mode 100644 index 0000000000000..5fb0b8f1d14b2 --- /dev/null +++ b/tests/ui/impl-trait/call_method_on_inherent_impl_on_rigid_type.next.stderr @@ -0,0 +1,17 @@ +error[E0282]: type annotations needed for `&_` + --> $DIR/call_method_on_inherent_impl_on_rigid_type.rs:14:13 + | +LL | let x = &my_foo(); + | ^ +LL | +LL | x.my_debug(); + | -------- type must be known at this point + | +help: consider giving `x` an explicit type, where the placeholders `_` are specified + | +LL | let x: &_ = &my_foo(); + | ++++ + +error: aborting due to 1 previous error + +For more information about this error, try `rustc --explain E0282`. diff --git a/tests/ui/impl-trait/call_method_on_inherent_impl_on_rigid_type.rs b/tests/ui/impl-trait/call_method_on_inherent_impl_on_rigid_type.rs new file mode 100644 index 0000000000000..7fb2ff3b2bcc6 --- /dev/null +++ b/tests/ui/impl-trait/call_method_on_inherent_impl_on_rigid_type.rs @@ -0,0 +1,22 @@ +//@ revisions: current next +//@[next] compile-flags: -Znext-solver + +trait MyDebug { + fn my_debug(&self); +} + +impl MyDebug for &() { + fn my_debug(&self) {} +} + +fn my_foo() -> impl std::fmt::Debug { + if false { + let x = &my_foo(); + //[next]~^ ERROR: type annotations needed + x.my_debug(); + //[current]~^ ERROR: no method named `my_debug` + } + () +} + +fn main() {} diff --git a/tests/ui/impl-trait/call_method_on_inherent_impl_ref.current.stderr b/tests/ui/impl-trait/call_method_on_inherent_impl_ref.current.stderr new file mode 100644 index 0000000000000..fe6e166cb4fa1 --- /dev/null +++ b/tests/ui/impl-trait/call_method_on_inherent_impl_ref.current.stderr @@ -0,0 +1,40 @@ +error[E0599]: no method named `my_debug` found for opaque type `impl Debug` in the current scope + --> $DIR/call_method_on_inherent_impl_ref.rs:20:11 + | +LL | fn my_debug(&self); + | -------- the method is available for `&impl Debug` here +... +LL | x.my_debug(); + | ^^^^^^^^ method not found in `impl Debug` + | + = help: items from traits can only be used if the trait is implemented and in scope +note: `MyDebug` defines an item `my_debug`, perhaps you need to implement it + --> $DIR/call_method_on_inherent_impl_ref.rs:4:1 + | +LL | trait MyDebug { + | ^^^^^^^^^^^^^ + +error[E0391]: cycle detected when computing type of opaque `my_foo::{opaque#0}` + --> $DIR/call_method_on_inherent_impl_ref.rs:15:16 + | +LL | fn my_foo() -> impl std::fmt::Debug { + | ^^^^^^^^^^^^^^^^^^^^ + | +note: ...which requires type-checking `my_foo`... + --> $DIR/call_method_on_inherent_impl_ref.rs:20:9 + | +LL | x.my_debug(); + | ^ + = note: ...which requires evaluating trait selection obligation `my_foo::{opaque#0}: core::marker::Unpin`... + = note: ...which again requires computing type of opaque `my_foo::{opaque#0}`, completing the cycle +note: cycle used when computing type of `my_foo::{opaque#0}` + --> $DIR/call_method_on_inherent_impl_ref.rs:15:16 + | +LL | fn my_foo() -> impl std::fmt::Debug { + | ^^^^^^^^^^^^^^^^^^^^ + = note: see https://rustc-dev-guide.rust-lang.org/overview.html#queries and https://rustc-dev-guide.rust-lang.org/query.html for more information + +error: aborting due to 2 previous errors + +Some errors have detailed explanations: E0391, E0599. +For more information about an error, try `rustc --explain E0391`. diff --git a/tests/ui/impl-trait/call_method_on_inherent_impl_ref.next.stderr b/tests/ui/impl-trait/call_method_on_inherent_impl_ref.next.stderr new file mode 100644 index 0000000000000..327f6ca3450f1 --- /dev/null +++ b/tests/ui/impl-trait/call_method_on_inherent_impl_ref.next.stderr @@ -0,0 +1,31 @@ +error[E0282]: type annotations needed + --> $DIR/call_method_on_inherent_impl_ref.rs:18:13 + | +LL | let x = my_foo(); + | ^ +LL | +LL | x.my_debug(); + | - type must be known at this point + | +help: consider giving `x` an explicit type + | +LL | let x: /* Type */ = my_foo(); + | ++++++++++++ + +error[E0282]: type annotations needed for `&_` + --> $DIR/call_method_on_inherent_impl_ref.rs:28:13 + | +LL | let x = &my_bar(); + | ^ +LL | +LL | x.my_debug(); + | -------- type must be known at this point + | +help: consider giving `x` an explicit type, where the placeholders `_` are specified + | +LL | let x: &_ = &my_bar(); + | ++++ + +error: aborting due to 2 previous errors + +For more information about this error, try `rustc --explain E0282`. diff --git a/tests/ui/impl-trait/call_method_on_inherent_impl_ref.rs b/tests/ui/impl-trait/call_method_on_inherent_impl_ref.rs new file mode 100644 index 0000000000000..40ad21532a4e2 --- /dev/null +++ b/tests/ui/impl-trait/call_method_on_inherent_impl_ref.rs @@ -0,0 +1,35 @@ +//@ revisions: current next +//@[next] compile-flags: -Znext-solver + +trait MyDebug { + fn my_debug(&self); +} + +impl MyDebug for &T +where + T: std::fmt::Debug, +{ + fn my_debug(&self) {} +} + +fn my_foo() -> impl std::fmt::Debug { + //[current]~^ cycle + if false { + let x = my_foo(); + //[next]~^ type annotations needed + x.my_debug(); + //[current]~^ no method named `my_debug` found + } + () +} + +fn my_bar() -> impl std::fmt::Debug { + if false { + let x = &my_bar(); + //[next]~^ type annotations needed + x.my_debug(); + } + () +} + +fn main() {} diff --git a/tests/ui/impl-trait/call_method_without_import.no_import.stderr b/tests/ui/impl-trait/call_method_without_import.no_import.stderr new file mode 100644 index 0000000000000..72982b695bbb0 --- /dev/null +++ b/tests/ui/impl-trait/call_method_without_import.no_import.stderr @@ -0,0 +1,37 @@ +error[E0599]: no method named `fmt` found for opaque type `impl Debug` in the current scope + --> $DIR/call_method_without_import.rs:17:11 + | +LL | x.fmt(f); + | ^^^ method not found in `impl Debug` + --> $SRC_DIR/core/src/fmt/mod.rs:LL:COL + | + = note: the method is available for `impl Debug` here + | + = help: items from traits can only be used if the trait is in scope +help: trait `Debug` which provides `fmt` is implemented but not in scope; perhaps you want to import it + | +LL + use std::fmt::Debug; + | + +error[E0599]: no method named `fmt` found for mutable reference `&mut impl Debug` in the current scope + --> $DIR/call_method_without_import.rs:26:11 + | +LL | x.fmt(f); + | ^^^ method not found in `&mut impl Debug` + | + = help: items from traits can only be used if the trait is in scope +help: the following traits which provide `fmt` are implemented but not in scope; perhaps you want to import one of them + | +LL + use std::fmt::Binary; + | +LL + use std::fmt::Debug; + | +LL + use std::fmt::Display; + | +LL + use std::fmt::LowerExp; + | + and 5 other candidates + +error: aborting due to 2 previous errors + +For more information about this error, try `rustc --explain E0599`. diff --git a/tests/ui/impl-trait/call_method_without_import.rs b/tests/ui/impl-trait/call_method_without_import.rs new file mode 100644 index 0000000000000..d62777ea2835d --- /dev/null +++ b/tests/ui/impl-trait/call_method_without_import.rs @@ -0,0 +1,42 @@ +//! Test that opaque types only pick up methods from traits in their bounds +//! if the trait is imported. +//! +//! FIXME: always look through the bounds of an opaque type to see if there are +//! methods that could be called on any of the bound traits, irrespective of +//! imported traits. + +//@ revisions: import no_import +//@[import] check-pass + +#[cfg(import)] +use std::fmt::Debug as _; + +fn foo(f: &mut std::fmt::Formatter<'_>) -> impl std::fmt::Debug { + if false { + let x = foo(f); + x.fmt(f); + //[no_import]~^ ERROR: no method named `fmt` found + } + () +} + +fn foo1(f: &mut std::fmt::Formatter<'_>) -> impl std::fmt::Debug { + if false { + let x = &mut foo(f); + x.fmt(f); + //[no_import]~^ ERROR: no method named `fmt` found + } + () +} + +// inconsistent with this +fn bar(t: impl std::fmt::Debug, f: &mut std::fmt::Formatter<'_>) { + t.fmt(f); +} + +// and the desugared version, of course +fn baz(t: T, f: &mut std::fmt::Formatter<'_>) { + t.fmt(f); +} + +fn main() {} diff --git a/tests/ui/impl-trait/equality.stderr b/tests/ui/impl-trait/equality.stderr index 69f4cbbbf4294..12d886a002454 100644 --- a/tests/ui/impl-trait/equality.stderr +++ b/tests/ui/impl-trait/equality.stderr @@ -30,10 +30,10 @@ LL | n + sum_to(n - 1) | = help: the trait `Add` is not implemented for `u32` = help: the following other types implement trait `Add`: - <&'a u32 as Add> - <&u32 as Add<&u32>> - > - + `&'a u32` implements `Add` + `&u32` implements `Add<&u32>` + `u32` implements `Add<&u32>` + `u32` implements `Add` error: aborting due to 2 previous errors; 1 warning emitted diff --git a/tests/ui/impl-trait/method-resolution.rs b/tests/ui/impl-trait/method-resolution.rs new file mode 100644 index 0000000000000..60fbacd86462b --- /dev/null +++ b/tests/ui/impl-trait/method-resolution.rs @@ -0,0 +1,26 @@ +//! Since there is only one possible `bar` method, we invoke it and subsequently +//! constrain `foo`'s RPIT to `u32`. + +//@ revisions: current next +//@[next] compile-flags: -Znext-solver +//@ check-pass + +trait Trait {} + +impl Trait for u32 {} + +struct Bar(T); + +impl Bar { + fn bar(self) {} +} + +fn foo(x: bool) -> Bar { + if x { + let x = foo(false); + x.bar(); + } + todo!() +} + +fn main() {} diff --git a/tests/ui/impl-trait/method-resolution2.next.stderr b/tests/ui/impl-trait/method-resolution2.next.stderr new file mode 100644 index 0000000000000..223430e1658b4 --- /dev/null +++ b/tests/ui/impl-trait/method-resolution2.next.stderr @@ -0,0 +1,20 @@ +error[E0034]: multiple applicable items in scope + --> $DIR/method-resolution2.rs:25:11 + | +LL | x.bar(); + | ^^^ multiple `bar` found + | +note: candidate #1 is defined in an impl for the type `Bar` + --> $DIR/method-resolution2.rs:19:5 + | +LL | fn bar(self) {} + | ^^^^^^^^^^^^ +note: candidate #2 is defined in an impl for the type `Bar` + --> $DIR/method-resolution2.rs:15:5 + | +LL | fn bar(self) {} + | ^^^^^^^^^^^^ + +error: aborting due to 1 previous error + +For more information about this error, try `rustc --explain E0034`. diff --git a/tests/ui/impl-trait/method-resolution2.rs b/tests/ui/impl-trait/method-resolution2.rs new file mode 100644 index 0000000000000..88d4f3d9896c7 --- /dev/null +++ b/tests/ui/impl-trait/method-resolution2.rs @@ -0,0 +1,31 @@ +//! Check that the method call does not constrain the RPIT to `i32`, even though +//! `i32` is the only type that satisfies the RPIT's trait bounds. + +//@ revisions: current next +//@[next] compile-flags: -Znext-solver +//@[current] check-pass + +trait Trait {} + +impl Trait for i32 {} + +struct Bar(T); + +impl Bar { + fn bar(self) {} +} + +impl Bar { + fn bar(self) {} +} + +fn foo(x: bool) -> Bar { + if x { + let x = foo(false); + x.bar(); + //[next]~^ ERROR: multiple applicable items in scope + } + Bar(42_i32) +} + +fn main() {} diff --git a/tests/ui/impl-trait/method-resolution3.current.stderr b/tests/ui/impl-trait/method-resolution3.current.stderr new file mode 100644 index 0000000000000..87dd862ef8f4f --- /dev/null +++ b/tests/ui/impl-trait/method-resolution3.current.stderr @@ -0,0 +1,20 @@ +error[E0034]: multiple applicable items in scope + --> $DIR/method-resolution3.rs:21:11 + | +LL | x.bar(); + | ^^^ multiple `bar` found + | +note: candidate #1 is defined in an impl for the type `Bar` + --> $DIR/method-resolution3.rs:15:5 + | +LL | fn bar(self) {} + | ^^^^^^^^^^^^ +note: candidate #2 is defined in an impl for the type `Bar` + --> $DIR/method-resolution3.rs:11:5 + | +LL | fn bar(self) {} + | ^^^^^^^^^^^^ + +error: aborting due to 1 previous error + +For more information about this error, try `rustc --explain E0034`. diff --git a/tests/ui/impl-trait/method-resolution3.next.stderr b/tests/ui/impl-trait/method-resolution3.next.stderr new file mode 100644 index 0000000000000..87dd862ef8f4f --- /dev/null +++ b/tests/ui/impl-trait/method-resolution3.next.stderr @@ -0,0 +1,20 @@ +error[E0034]: multiple applicable items in scope + --> $DIR/method-resolution3.rs:21:11 + | +LL | x.bar(); + | ^^^ multiple `bar` found + | +note: candidate #1 is defined in an impl for the type `Bar` + --> $DIR/method-resolution3.rs:15:5 + | +LL | fn bar(self) {} + | ^^^^^^^^^^^^ +note: candidate #2 is defined in an impl for the type `Bar` + --> $DIR/method-resolution3.rs:11:5 + | +LL | fn bar(self) {} + | ^^^^^^^^^^^^ + +error: aborting due to 1 previous error + +For more information about this error, try `rustc --explain E0034`. diff --git a/tests/ui/impl-trait/method-resolution3.rs b/tests/ui/impl-trait/method-resolution3.rs new file mode 100644 index 0000000000000..8c47ef4fc75c7 --- /dev/null +++ b/tests/ui/impl-trait/method-resolution3.rs @@ -0,0 +1,27 @@ +//! Check that we consider `Bar` to successfully unify +//! with both `Bar` and `Bar` (in isolation), so we bail +//! out with ambiguity. + +//@ revisions: current next +//@[next] compile-flags: -Znext-solver + +struct Bar(T); + +impl Bar { + fn bar(self) {} +} + +impl Bar { + fn bar(self) {} +} + +fn foo(x: bool) -> Bar { + if x { + let x = foo(false); + x.bar(); + //~^ ERROR: multiple applicable items in scope + } + todo!() +} + +fn main() {} diff --git a/tests/ui/impl-trait/method-resolution4.next.stderr b/tests/ui/impl-trait/method-resolution4.next.stderr new file mode 100644 index 0000000000000..b48de0af3579d --- /dev/null +++ b/tests/ui/impl-trait/method-resolution4.next.stderr @@ -0,0 +1,22 @@ +error[E0282]: type annotations needed + --> $DIR/method-resolution4.rs:13:9 + | +LL | foo(false).next().unwrap(); + | ^^^^^^^^^^ cannot infer type + +error[E0308]: mismatched types + --> $DIR/method-resolution4.rs:16:5 + | +LL | fn foo(b: bool) -> impl Iterator { + | ------------------------ the expected opaque type +... +LL | std::iter::empty() + | ^^^^^^^^^^^^^^^^^^ types differ + | + = note: expected opaque type `impl Iterator` + found struct `std::iter::Empty<_>` + +error: aborting due to 2 previous errors + +Some errors have detailed explanations: E0282, E0308. +For more information about an error, try `rustc --explain E0282`. diff --git a/tests/ui/impl-trait/method-resolution4.rs b/tests/ui/impl-trait/method-resolution4.rs new file mode 100644 index 0000000000000..91884eb59fd63 --- /dev/null +++ b/tests/ui/impl-trait/method-resolution4.rs @@ -0,0 +1,20 @@ +//! The recursive method call yields the opaque type. The +//! `next` method call then constrains the hidden type to `&mut _` +//! because `next` takes `&mut self`. We never resolve the inference +//! variable, but get a type mismatch when comparing `&mut _` with +//! `std::iter::Empty`. + +//@ revisions: current next +//@[next] compile-flags: -Znext-solver +//@[current] check-pass + +fn foo(b: bool) -> impl Iterator { + if b { + foo(false).next().unwrap(); + //[next]~^ type annotations needed + } + std::iter::empty() + //[next]~^ mismatched types +} + +fn main() {} diff --git a/tests/ui/impl-trait/nested_impl_trait.stderr b/tests/ui/impl-trait/nested_impl_trait.stderr index 1f9a2a5e9d600..a53312e5c0bd4 100644 --- a/tests/ui/impl-trait/nested_impl_trait.stderr +++ b/tests/ui/impl-trait/nested_impl_trait.stderr @@ -46,7 +46,7 @@ error[E0277]: the trait bound `impl Into: Into` is not satisfie --> $DIR/nested_impl_trait.rs:6:46 | LL | fn bad_in_ret_position(x: impl Into) -> impl Into { x } - | ^^^^^^^^^^^^^^^^^^^^^ the trait `From>` is not implemented for `impl Into`, which is required by `impl Into: Into` + | ^^^^^^^^^^^^^^^^^^^^^ the trait `From>` is not implemented for `impl Debug`, which is required by `impl Into: Into` | = help: the trait `Into` is implemented for `T` = note: required for `impl Into` to implement `Into` @@ -55,7 +55,7 @@ error[E0277]: the trait bound `impl Into: Into` is not satisfie --> $DIR/nested_impl_trait.rs:19:34 | LL | fn bad(x: impl Into) -> impl Into { x } - | ^^^^^^^^^^^^^^^^^^^^^ the trait `From>` is not implemented for `impl Into`, which is required by `impl Into: Into` + | ^^^^^^^^^^^^^^^^^^^^^ the trait `From>` is not implemented for `impl Debug`, which is required by `impl Into: Into` | = help: the trait `Into` is implemented for `T` = note: required for `impl Into` to implement `Into` diff --git a/tests/ui/impl-trait/recursive-parent-trait-method-call.rs b/tests/ui/impl-trait/recursive-parent-trait-method-call.rs new file mode 100644 index 0000000000000..4da9a06a4659b --- /dev/null +++ b/tests/ui/impl-trait/recursive-parent-trait-method-call.rs @@ -0,0 +1,42 @@ +//! This test checks that we can resolve the `boxed` method call to `FutureExt`, +//! because we know that the anonymous future does not implement `StreamExt`. + +//@ edition: 2021 +//@ check-pass + +use std::future::Future; +use std::pin::Pin; + +trait FutureExt: Future + Sized + Send + 'static { + fn boxed(self) -> Pin + Send + 'static>> { + Box::pin(self) + } +} + +trait StreamExt: Future + Sized + Send + 'static { + fn boxed(self) -> Pin + Send + 'static>> { + Box::pin(self) + } +} + +impl FutureExt for T {} + +fn go(i: usize) -> impl Future + Send + 'static { + async move { + if i != 0 { + spawn(async move { + let fut = go(i - 1).boxed(); + fut.await; + }) + .await; + } + } +} + +pub fn spawn( + _: impl Future + Send + 'static, +) -> impl Future + Send + 'static { + async move { todo!() } +} + +fn main() {} diff --git a/tests/ui/imports/cycle-import-in-std-1.stderr b/tests/ui/imports/cycle-import-in-std-1.stderr index d4e6f32cc109e..a7dfc6231bace 100644 --- a/tests/ui/imports/cycle-import-in-std-1.stderr +++ b/tests/ui/imports/cycle-import-in-std-1.stderr @@ -4,8 +4,7 @@ error[E0432]: unresolved import `ops` LL | use ops::{self as std}; | ^^^^^^^^^^^ no external crate `ops` | - = help: consider importing one of these items instead: - core::ops + = help: consider importing this module instead: std::ops error: aborting due to 1 previous error diff --git a/tests/ui/imports/cycle-import-in-std-2.stderr b/tests/ui/imports/cycle-import-in-std-2.stderr index dc0270dffe4a7..8d94693cd51d4 100644 --- a/tests/ui/imports/cycle-import-in-std-2.stderr +++ b/tests/ui/imports/cycle-import-in-std-2.stderr @@ -4,8 +4,7 @@ error[E0432]: unresolved import `ops` LL | use ops::{self as std}; | ^^^^^^^^^^^ no external crate `ops` | - = help: consider importing one of these items instead: - core::ops + = help: consider importing this module instead: std::ops error: aborting due to 1 previous error diff --git a/tests/ui/imports/import-alias-issue-121168.edition2018.stderr b/tests/ui/imports/import-alias-issue-121168.edition2018.stderr index b61a0e3edd524..e14e700c33d81 100644 --- a/tests/ui/imports/import-alias-issue-121168.edition2018.stderr +++ b/tests/ui/imports/import-alias-issue-121168.edition2018.stderr @@ -4,7 +4,7 @@ error[E0412]: cannot find type `Foo` in this scope LL | let _: Foo = todo!(); | ^^^ not found in this scope | -help: consider importing one of these items +help: consider importing one of these structs | LL + use crate::nice_crate_name::Foo; | diff --git a/tests/ui/imports/import-alias-issue-121168.edition2021.stderr b/tests/ui/imports/import-alias-issue-121168.edition2021.stderr index b61a0e3edd524..e14e700c33d81 100644 --- a/tests/ui/imports/import-alias-issue-121168.edition2021.stderr +++ b/tests/ui/imports/import-alias-issue-121168.edition2021.stderr @@ -4,7 +4,7 @@ error[E0412]: cannot find type `Foo` in this scope LL | let _: Foo = todo!(); | ^^^ not found in this scope | -help: consider importing one of these items +help: consider importing one of these structs | LL + use crate::nice_crate_name::Foo; | diff --git a/tests/ui/imports/issue-56125.stderr b/tests/ui/imports/issue-56125.stderr index d2a0f436c42d0..0c4a569c7ea71 100644 --- a/tests/ui/imports/issue-56125.stderr +++ b/tests/ui/imports/issue-56125.stderr @@ -4,16 +4,16 @@ error[E0432]: unresolved import `empty::issue_56125` LL | use empty::issue_56125; | ^^^^^^^^^^^^^^^^^^ no `issue_56125` in `m3::empty` | -help: consider importing one of these items instead +help: consider importing one of these modules instead | +LL | use crate::m3::last_segment::issue_56125; + | ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +LL | use crate::m3::non_last_segment::non_last_segment::issue_56125; + | ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ LL | use ::issue_56125::issue_56125; | ~~~~~~~~~~~~~~~~~~~~~~~~~~ LL | use ::issue_56125::last_segment::issue_56125; | ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ -LL | use ::issue_56125::non_last_segment::non_last_segment::issue_56125; - | ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ -LL | use crate::m3::last_segment::issue_56125; - | ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ and 1 other candidate error[E0659]: `issue_56125` is ambiguous diff --git a/tests/ui/instrument-coverage/coverage-options.rs b/tests/ui/instrument-coverage/coverage-options.rs index 8f523a5fd11a0..7615a0fb2751c 100644 --- a/tests/ui/instrument-coverage/coverage-options.rs +++ b/tests/ui/instrument-coverage/coverage-options.rs @@ -1,6 +1,5 @@ -//@ needs-profiler-support //@ revisions: block branch condition mcdc bad -//@ compile-flags -Cinstrument-coverage +//@ compile-flags -Cinstrument-coverage -Zno-profiler-runtime //@ [block] check-pass //@ [block] compile-flags: -Zcoverage-options=block diff --git a/tests/ui/instrument-coverage/on-values.rs b/tests/ui/instrument-coverage/on-values.rs index a6793b2c304f2..53b149fd39cce 100644 --- a/tests/ui/instrument-coverage/on-values.rs +++ b/tests/ui/instrument-coverage/on-values.rs @@ -1,5 +1,5 @@ //@ check-pass -//@ needs-profiler-support +//@ compile-flags: -Zno-profiler-runtime //@ revisions: default y yes on true_ all //@ [default] compile-flags: -Cinstrument-coverage //@ [y] compile-flags: -Cinstrument-coverage=y diff --git a/tests/ui/issues/issue-11771.stderr b/tests/ui/issues/issue-11771.stderr index d4a4647f6a10d..8205ee0c38d53 100644 --- a/tests/ui/issues/issue-11771.stderr +++ b/tests/ui/issues/issue-11771.stderr @@ -6,14 +6,14 @@ LL | 1 + | = help: the trait `Add<()>` is not implemented for `{integer}` = help: the following other types implement trait `Add`: - <&'a f128 as Add> - <&'a f16 as Add> - <&'a f32 as Add> - <&'a f64 as Add> - <&'a i128 as Add> - <&'a i16 as Add> - <&'a i32 as Add> - <&'a i64 as Add> + `&'a f128` implements `Add` + `&'a f16` implements `Add` + `&'a f32` implements `Add` + `&'a f64` implements `Add` + `&'a i128` implements `Add` + `&'a i16` implements `Add` + `&'a i32` implements `Add` + `&'a i64` implements `Add` and 56 others error[E0277]: cannot add `()` to `{integer}` @@ -24,14 +24,14 @@ LL | 1 + | = help: the trait `Add<()>` is not implemented for `{integer}` = help: the following other types implement trait `Add`: - <&'a f128 as Add> - <&'a f16 as Add> - <&'a f32 as Add> - <&'a f64 as Add> - <&'a i128 as Add> - <&'a i16 as Add> - <&'a i32 as Add> - <&'a i64 as Add> + `&'a f128` implements `Add` + `&'a f16` implements `Add` + `&'a f32` implements `Add` + `&'a f64` implements `Add` + `&'a i128` implements `Add` + `&'a i16` implements `Add` + `&'a i32` implements `Add` + `&'a i64` implements `Add` and 56 others error: aborting due to 2 previous errors diff --git a/tests/ui/issues/issue-24352.stderr b/tests/ui/issues/issue-24352.stderr index a9f886158e1d0..2e7dc254d914d 100644 --- a/tests/ui/issues/issue-24352.stderr +++ b/tests/ui/issues/issue-24352.stderr @@ -6,10 +6,10 @@ LL | 1.0f64 - 1 | = help: the trait `Sub<{integer}>` is not implemented for `f64` = help: the following other types implement trait `Sub`: - <&'a f64 as Sub> - <&f64 as Sub<&f64>> - > - + `&'a f64` implements `Sub` + `&f64` implements `Sub<&f64>` + `f64` implements `Sub<&f64>` + `f64` implements `Sub` help: consider using a floating-point literal by writing it with `.0` | LL | 1.0f64 - 1.0 diff --git a/tests/ui/issues/issue-50582.stderr b/tests/ui/issues/issue-50582.stderr index b765d2f087d0a..7203fdeb0bbca 100644 --- a/tests/ui/issues/issue-50582.stderr +++ b/tests/ui/issues/issue-50582.stderr @@ -16,14 +16,14 @@ LL | Vec::<[(); 1 + for x in 0..1 {}]>::new(); | = help: the trait `Add<()>` is not implemented for `{integer}` = help: the following other types implement trait `Add`: - <&'a f128 as Add> - <&'a f16 as Add> - <&'a f32 as Add> - <&'a f64 as Add> - <&'a i128 as Add> - <&'a i16 as Add> - <&'a i32 as Add> - <&'a i64 as Add> + `&'a f128` implements `Add` + `&'a f16` implements `Add` + `&'a f32` implements `Add` + `&'a f64` implements `Add` + `&'a i128` implements `Add` + `&'a i16` implements `Add` + `&'a i32` implements `Add` + `&'a i64` implements `Add` and 56 others error: aborting due to 2 previous errors diff --git a/tests/ui/iterators/invalid-iterator-chain-fixable.stderr b/tests/ui/iterators/invalid-iterator-chain-fixable.stderr index 4d1e4207fdcb1..a7685e4938d88 100644 --- a/tests/ui/iterators/invalid-iterator-chain-fixable.stderr +++ b/tests/ui/iterators/invalid-iterator-chain-fixable.stderr @@ -33,8 +33,8 @@ LL | println!("{}", scores.sum::()); | = help: the trait `Sum<()>` is not implemented for `i32` = help: the following other types implement trait `Sum`: - > - + `i32` implements `Sum<&'a i32>` + `i32` implements `Sum` note: the method call chain might not have had the expected associated types --> $DIR/invalid-iterator-chain-fixable.rs:14:10 | @@ -66,8 +66,8 @@ LL | .sum::(), | = help: the trait `Sum<()>` is not implemented for `i32` = help: the following other types implement trait `Sum`: - > - + `i32` implements `Sum<&'a i32>` + `i32` implements `Sum` note: the method call chain might not have had the expected associated types --> $DIR/invalid-iterator-chain-fixable.rs:23:14 | @@ -99,8 +99,8 @@ LL | println!("{}", vec![0, 1].iter().map(|x| { x; }).sum::()); | = help: the trait `Sum<()>` is not implemented for `i32` = help: the following other types implement trait `Sum`: - > - + `i32` implements `Sum<&'a i32>` + `i32` implements `Sum` note: the method call chain might not have had the expected associated types --> $DIR/invalid-iterator-chain-fixable.rs:27:38 | diff --git a/tests/ui/iterators/invalid-iterator-chain-with-int-infer.stderr b/tests/ui/iterators/invalid-iterator-chain-with-int-infer.stderr index 9381a98e07782..189f089ba51a7 100644 --- a/tests/ui/iterators/invalid-iterator-chain-with-int-infer.stderr +++ b/tests/ui/iterators/invalid-iterator-chain-with-int-infer.stderr @@ -8,8 +8,8 @@ LL | let x = Some(()).iter().map(|()| 1).sum::(); | = help: the trait `Sum<{integer}>` is not implemented for `f32` = help: the following other types implement trait `Sum`: - > - + `f32` implements `Sum<&'a f32>` + `f32` implements `Sum` note: the method call chain might not have had the expected associated types --> $DIR/invalid-iterator-chain-with-int-infer.rs:2:29 | diff --git a/tests/ui/iterators/invalid-iterator-chain.stderr b/tests/ui/iterators/invalid-iterator-chain.stderr index 6129a724f447c..f72a9f702dcec 100644 --- a/tests/ui/iterators/invalid-iterator-chain.stderr +++ b/tests/ui/iterators/invalid-iterator-chain.stderr @@ -33,8 +33,8 @@ LL | println!("{}", scores.sum::()); | = help: the trait `Sum<()>` is not implemented for `i32` = help: the following other types implement trait `Sum`: - > - + `i32` implements `Sum<&'a i32>` + `i32` implements `Sum` note: the method call chain might not have had the expected associated types --> $DIR/invalid-iterator-chain.rs:12:10 | @@ -65,8 +65,8 @@ LL | .sum::(), | = help: the trait `Sum<()>` is not implemented for `i32` = help: the following other types implement trait `Sum`: - > - + `i32` implements `Sum<&'a i32>` + `i32` implements `Sum` note: the method call chain might not have had the expected associated types --> $DIR/invalid-iterator-chain.rs:25:14 | @@ -104,8 +104,8 @@ LL | .sum::(), | = help: the trait `Sum` is not implemented for `i32` = help: the following other types implement trait `Sum`: - > - + `i32` implements `Sum<&'a i32>` + `i32` implements `Sum` note: the method call chain might not have had the expected associated types --> $DIR/invalid-iterator-chain.rs:33:14 | @@ -134,8 +134,8 @@ LL | println!("{}", vec![0, 1].iter().map(|x| { x; }).sum::()); | = help: the trait `Sum<()>` is not implemented for `i32` = help: the following other types implement trait `Sum`: - > - + `i32` implements `Sum<&'a i32>` + `i32` implements `Sum` note: the method call chain might not have had the expected associated types --> $DIR/invalid-iterator-chain.rs:38:38 | @@ -162,8 +162,8 @@ LL | println!("{}", vec![(), ()].iter().sum::()); | = help: the trait `Sum<&()>` is not implemented for `i32` = help: the following other types implement trait `Sum`: - > - + `i32` implements `Sum<&'a i32>` + `i32` implements `Sum` note: the method call chain might not have had the expected associated types --> $DIR/invalid-iterator-chain.rs:39:33 | diff --git a/tests/ui/kindck/kindck-send-object.stderr b/tests/ui/kindck/kindck-send-object.stderr index 9f1ff4f3644cc..7d0c711abc4c3 100644 --- a/tests/ui/kindck/kindck-send-object.stderr +++ b/tests/ui/kindck/kindck-send-object.stderr @@ -4,7 +4,7 @@ error[E0277]: `&'static (dyn Dummy + 'static)` cannot be sent between threads sa LL | assert_send::<&'static (dyn Dummy + 'static)>(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ `&'static (dyn Dummy + 'static)` cannot be sent between threads safely | - = help: the trait `Sync` is not implemented for `&'static (dyn Dummy + 'static)`, which is required by `&'static (dyn Dummy + 'static): Send` + = help: the trait `Sync` is not implemented for `(dyn Dummy + 'static)`, which is required by `&'static (dyn Dummy + 'static): Send` = note: required for `&'static (dyn Dummy + 'static)` to implement `Send` note: required by a bound in `assert_send` --> $DIR/kindck-send-object.rs:5:18 diff --git a/tests/ui/kindck/kindck-send-object1.stderr b/tests/ui/kindck/kindck-send-object1.stderr index f2aa814676fc3..7f39dab2086a1 100644 --- a/tests/ui/kindck/kindck-send-object1.stderr +++ b/tests/ui/kindck/kindck-send-object1.stderr @@ -4,7 +4,7 @@ error[E0277]: `&'a (dyn Dummy + 'a)` cannot be sent between threads safely LL | assert_send::<&'a dyn Dummy>(); | ^^^^^^^^^^^^^ `&'a (dyn Dummy + 'a)` cannot be sent between threads safely | - = help: the trait `Sync` is not implemented for `&'a (dyn Dummy + 'a)`, which is required by `&'a (dyn Dummy + 'a): Send` + = help: the trait `Sync` is not implemented for `(dyn Dummy + 'a)`, which is required by `&'a (dyn Dummy + 'a): Send` = note: required for `&'a (dyn Dummy + 'a)` to implement `Send` note: required by a bound in `assert_send` --> $DIR/kindck-send-object1.rs:5:18 diff --git a/tests/ui/kindck/kindck-send-object2.stderr b/tests/ui/kindck/kindck-send-object2.stderr index cd4d74360f867..a481a132ccefb 100644 --- a/tests/ui/kindck/kindck-send-object2.stderr +++ b/tests/ui/kindck/kindck-send-object2.stderr @@ -4,7 +4,7 @@ error[E0277]: `&'static (dyn Dummy + 'static)` cannot be sent between threads sa LL | assert_send::<&'static dyn Dummy>(); | ^^^^^^^^^^^^^^^^^^ `&'static (dyn Dummy + 'static)` cannot be sent between threads safely | - = help: the trait `Sync` is not implemented for `&'static (dyn Dummy + 'static)`, which is required by `&'static (dyn Dummy + 'static): Send` + = help: the trait `Sync` is not implemented for `(dyn Dummy + 'static)`, which is required by `&'static (dyn Dummy + 'static): Send` = note: required for `&'static (dyn Dummy + 'static)` to implement `Send` note: required by a bound in `assert_send` --> $DIR/kindck-send-object2.rs:3:18 diff --git a/tests/ui/lazy-type-alias/trailing-where-clause.stderr b/tests/ui/lazy-type-alias/trailing-where-clause.stderr index 534df382eb6e9..9fabbe91d25a4 100644 --- a/tests/ui/lazy-type-alias/trailing-where-clause.stderr +++ b/tests/ui/lazy-type-alias/trailing-where-clause.stderr @@ -5,12 +5,12 @@ LL | let _: Alias<()>; | ^^ the trait `From<()>` is not implemented for `String` | = help: the following other types implement trait `From`: - > - > - > - >> - >> - > + `String` implements `From<&String>` + `String` implements `From<&mut str>` + `String` implements `From<&str>` + `String` implements `From>` + `String` implements `From>` + `String` implements `From` note: required by a bound in `Alias` --> $DIR/trailing-where-clause.rs:8:13 | diff --git a/tests/ui/lint/dead-code/allow-unconstructed-pub-struct.rs b/tests/ui/lint/dead-code/allow-unconstructed-pub-struct.rs new file mode 100644 index 0000000000000..8cd1524045b15 --- /dev/null +++ b/tests/ui/lint/dead-code/allow-unconstructed-pub-struct.rs @@ -0,0 +1,33 @@ +//@ check-pass + +mod ffi { + use super::*; + + extern "C" { + pub fn DomPromise_AddRef(promise: *const Promise); + pub fn DomPromise_Release(promise: *const Promise); + } +} + +#[repr(C)] +#[allow(unused)] +pub struct Promise { + private: [u8; 0], + __nosync: ::std::marker::PhantomData<::std::rc::Rc>, +} + +pub unsafe trait RefCounted { + unsafe fn addref(&self); + unsafe fn release(&self); +} + +unsafe impl RefCounted for Promise { + unsafe fn addref(&self) { + ffi::DomPromise_AddRef(self) + } + unsafe fn release(&self) { + ffi::DomPromise_Release(self) + } +} + +fn main() {} diff --git a/tests/ui/lint/non-local-defs/cargo-update.stderr b/tests/ui/lint/non-local-defs/cargo-update.stderr index 888fd2e61837f..afd37d03a231c 100644 --- a/tests/ui/lint/non-local-defs/cargo-update.stderr +++ b/tests/ui/lint/non-local-defs/cargo-update.stderr @@ -8,9 +8,10 @@ LL | non_local_macro::non_local_impl!(LocalStruct); | `Debug` is not local | move the `impl` block outside of this constant `_IMPL_DEBUG` | + = note: the macro `non_local_macro::non_local_impl` defines the non-local `impl`, and may need to be changed + = note: the macro `non_local_macro::non_local_impl` may come from an old version of the `non_local_macro` crate, try updating your dependency with `cargo update -p non_local_macro` = note: `impl` may be usable in bounds, etc. from outside the expression, which might e.g. make something constructible that previously wasn't, because it's still on a publicly-visible type = note: an `impl` is never scoped, even when it is nested inside an item, as it may impact type checking outside of that item, which can be the case if neither the trait or the self type are at the same nesting level as the `impl` - = note: the macro `non_local_macro::non_local_impl` may come from an old version of the `non_local_macro` crate, try updating your dependency with `cargo update -p non_local_macro` = note: items in an anonymous const item (`const _: () = { ... }`) are treated as in the same scope as the anonymous const's declaration = note: this lint may become deny-by-default in the edition 2024 and higher, see the tracking issue = note: `#[warn(non_local_definitions)]` on by default diff --git a/tests/ui/lint/non-local-defs/inside-macro_rules.stderr b/tests/ui/lint/non-local-defs/inside-macro_rules.stderr index b52301d1aa086..fa9ba2cb785d9 100644 --- a/tests/ui/lint/non-local-defs/inside-macro_rules.stderr +++ b/tests/ui/lint/non-local-defs/inside-macro_rules.stderr @@ -12,6 +12,7 @@ LL | impl MacroTrait for OutsideStruct {} LL | m!(); | ---- in this macro invocation | + = note: the macro `m` defines the non-local `impl`, and may need to be changed = note: `impl` may be usable in bounds, etc. from outside the expression, which might e.g. make something constructible that previously wasn't, because it's still on a publicly-visible type = note: an `impl` is never scoped, even when it is nested inside an item, as it may impact type checking outside of that item, which can be the case if neither the trait or the self type are at the same nesting level as the `impl` = note: this lint may become deny-by-default in the edition 2024 and higher, see the tracking issue diff --git a/tests/ui/lint/issue-89469.rs b/tests/ui/lint/non-snake-case/allow-snake-case-field-destructuring-issue-89469.rs similarity index 100% rename from tests/ui/lint/issue-89469.rs rename to tests/ui/lint/non-snake-case/allow-snake-case-field-destructuring-issue-89469.rs diff --git a/tests/ui/lint/lint-non-snake-case-crate-bin.rs b/tests/ui/lint/non-snake-case/lint-non-snake-case-crate-bin.rs similarity index 100% rename from tests/ui/lint/lint-non-snake-case-crate-bin.rs rename to tests/ui/lint/non-snake-case/lint-non-snake-case-crate-bin.rs diff --git a/tests/ui/lint/lint-non-snake-case-crate-bin2.rs b/tests/ui/lint/non-snake-case/lint-non-snake-case-crate-bin2.rs similarity index 100% rename from tests/ui/lint/lint-non-snake-case-crate-bin2.rs rename to tests/ui/lint/non-snake-case/lint-non-snake-case-crate-bin2.rs diff --git a/tests/ui/lint/lint-non-snake-case-crate-bin3.rs b/tests/ui/lint/non-snake-case/lint-non-snake-case-crate-bin3.rs similarity index 100% rename from tests/ui/lint/lint-non-snake-case-crate-bin3.rs rename to tests/ui/lint/non-snake-case/lint-non-snake-case-crate-bin3.rs diff --git a/tests/ui/lint/lint-non-snake-case-crate-cdylib.rs b/tests/ui/lint/non-snake-case/lint-non-snake-case-crate-cdylib.rs similarity index 100% rename from tests/ui/lint/lint-non-snake-case-crate-cdylib.rs rename to tests/ui/lint/non-snake-case/lint-non-snake-case-crate-cdylib.rs diff --git a/tests/ui/lint/lint-non-snake-case-crate-cdylib.stderr b/tests/ui/lint/non-snake-case/lint-non-snake-case-crate-cdylib.stderr similarity index 100% rename from tests/ui/lint/lint-non-snake-case-crate-cdylib.stderr rename to tests/ui/lint/non-snake-case/lint-non-snake-case-crate-cdylib.stderr diff --git a/tests/ui/lint/lint-non-snake-case-crate-dylib.rs b/tests/ui/lint/non-snake-case/lint-non-snake-case-crate-dylib.rs similarity index 100% rename from tests/ui/lint/lint-non-snake-case-crate-dylib.rs rename to tests/ui/lint/non-snake-case/lint-non-snake-case-crate-dylib.rs diff --git a/tests/ui/lint/lint-non-snake-case-crate-dylib.stderr b/tests/ui/lint/non-snake-case/lint-non-snake-case-crate-dylib.stderr similarity index 100% rename from tests/ui/lint/lint-non-snake-case-crate-dylib.stderr rename to tests/ui/lint/non-snake-case/lint-non-snake-case-crate-dylib.stderr diff --git a/tests/ui/lint/lint-non-snake-case-crate-lib.rs b/tests/ui/lint/non-snake-case/lint-non-snake-case-crate-lib.rs similarity index 100% rename from tests/ui/lint/lint-non-snake-case-crate-lib.rs rename to tests/ui/lint/non-snake-case/lint-non-snake-case-crate-lib.rs diff --git a/tests/ui/lint/lint-non-snake-case-crate-lib.stderr b/tests/ui/lint/non-snake-case/lint-non-snake-case-crate-lib.stderr similarity index 100% rename from tests/ui/lint/lint-non-snake-case-crate-lib.stderr rename to tests/ui/lint/non-snake-case/lint-non-snake-case-crate-lib.stderr diff --git a/tests/ui/lint/lint-non-snake-case-crate-proc-macro.rs b/tests/ui/lint/non-snake-case/lint-non-snake-case-crate-proc-macro.rs similarity index 100% rename from tests/ui/lint/lint-non-snake-case-crate-proc-macro.rs rename to tests/ui/lint/non-snake-case/lint-non-snake-case-crate-proc-macro.rs diff --git a/tests/ui/lint/lint-non-snake-case-crate-proc-macro.stderr b/tests/ui/lint/non-snake-case/lint-non-snake-case-crate-proc-macro.stderr similarity index 100% rename from tests/ui/lint/lint-non-snake-case-crate-proc-macro.stderr rename to tests/ui/lint/non-snake-case/lint-non-snake-case-crate-proc-macro.stderr diff --git a/tests/ui/lint/lint-non-snake-case-crate-rlib.rs b/tests/ui/lint/non-snake-case/lint-non-snake-case-crate-rlib.rs similarity index 100% rename from tests/ui/lint/lint-non-snake-case-crate-rlib.rs rename to tests/ui/lint/non-snake-case/lint-non-snake-case-crate-rlib.rs diff --git a/tests/ui/lint/lint-non-snake-case-crate-rlib.stderr b/tests/ui/lint/non-snake-case/lint-non-snake-case-crate-rlib.stderr similarity index 100% rename from tests/ui/lint/lint-non-snake-case-crate-rlib.stderr rename to tests/ui/lint/non-snake-case/lint-non-snake-case-crate-rlib.stderr diff --git a/tests/ui/lint/lint-non-snake-case-crate-staticlib.rs b/tests/ui/lint/non-snake-case/lint-non-snake-case-crate-staticlib.rs similarity index 100% rename from tests/ui/lint/lint-non-snake-case-crate-staticlib.rs rename to tests/ui/lint/non-snake-case/lint-non-snake-case-crate-staticlib.rs diff --git a/tests/ui/lint/lint-non-snake-case-crate-staticlib.stderr b/tests/ui/lint/non-snake-case/lint-non-snake-case-crate-staticlib.stderr similarity index 100% rename from tests/ui/lint/lint-non-snake-case-crate-staticlib.stderr rename to tests/ui/lint/non-snake-case/lint-non-snake-case-crate-staticlib.stderr diff --git a/tests/ui/lint/lint-non-snake-case-functions.rs b/tests/ui/lint/non-snake-case/lint-non-snake-case-functions.rs similarity index 100% rename from tests/ui/lint/lint-non-snake-case-functions.rs rename to tests/ui/lint/non-snake-case/lint-non-snake-case-functions.rs diff --git a/tests/ui/lint/lint-non-snake-case-functions.stderr b/tests/ui/lint/non-snake-case/lint-non-snake-case-functions.stderr similarity index 100% rename from tests/ui/lint/lint-non-snake-case-functions.stderr rename to tests/ui/lint/non-snake-case/lint-non-snake-case-functions.stderr diff --git a/tests/ui/lint/lint-non-snake-case-identifiers-suggestion-reserved.rs b/tests/ui/lint/non-snake-case/lint-non-snake-case-identifiers-suggestion-reserved.rs similarity index 100% rename from tests/ui/lint/lint-non-snake-case-identifiers-suggestion-reserved.rs rename to tests/ui/lint/non-snake-case/lint-non-snake-case-identifiers-suggestion-reserved.rs diff --git a/tests/ui/lint/lint-non-snake-case-identifiers-suggestion-reserved.stderr b/tests/ui/lint/non-snake-case/lint-non-snake-case-identifiers-suggestion-reserved.stderr similarity index 100% rename from tests/ui/lint/lint-non-snake-case-identifiers-suggestion-reserved.stderr rename to tests/ui/lint/non-snake-case/lint-non-snake-case-identifiers-suggestion-reserved.stderr diff --git a/tests/ui/lint/lint-non-snake-case-lifetimes.rs b/tests/ui/lint/non-snake-case/lint-non-snake-case-lifetimes.rs similarity index 100% rename from tests/ui/lint/lint-non-snake-case-lifetimes.rs rename to tests/ui/lint/non-snake-case/lint-non-snake-case-lifetimes.rs diff --git a/tests/ui/lint/lint-non-snake-case-lifetimes.stderr b/tests/ui/lint/non-snake-case/lint-non-snake-case-lifetimes.stderr similarity index 100% rename from tests/ui/lint/lint-non-snake-case-lifetimes.stderr rename to tests/ui/lint/non-snake-case/lint-non-snake-case-lifetimes.stderr diff --git a/tests/ui/lint/lint-non-snake-case-modules.rs b/tests/ui/lint/non-snake-case/lint-non-snake-case-modules.rs similarity index 100% rename from tests/ui/lint/lint-non-snake-case-modules.rs rename to tests/ui/lint/non-snake-case/lint-non-snake-case-modules.rs diff --git a/tests/ui/lint/lint-non-snake-case-modules.stderr b/tests/ui/lint/non-snake-case/lint-non-snake-case-modules.stderr similarity index 100% rename from tests/ui/lint/lint-non-snake-case-modules.stderr rename to tests/ui/lint/non-snake-case/lint-non-snake-case-modules.stderr diff --git a/tests/ui/lint/lint-non-snake-case-no-lowercase-equivalent.rs b/tests/ui/lint/non-snake-case/lint-non-snake-case-no-lowercase-equivalent.rs similarity index 100% rename from tests/ui/lint/lint-non-snake-case-no-lowercase-equivalent.rs rename to tests/ui/lint/non-snake-case/lint-non-snake-case-no-lowercase-equivalent.rs diff --git a/tests/ui/lint/lint-nonstandard-style-unicode-2.rs b/tests/ui/lint/non-snake-case/lint-nonstandard-style-unicode-2.rs similarity index 100% rename from tests/ui/lint/lint-nonstandard-style-unicode-2.rs rename to tests/ui/lint/non-snake-case/lint-nonstandard-style-unicode-2.rs diff --git a/tests/ui/lint/lint-nonstandard-style-unicode-2.stderr b/tests/ui/lint/non-snake-case/lint-nonstandard-style-unicode-2.stderr similarity index 100% rename from tests/ui/lint/lint-nonstandard-style-unicode-2.stderr rename to tests/ui/lint/non-snake-case/lint-nonstandard-style-unicode-2.stderr diff --git a/tests/ui/lint/lint-uppercase-variables.rs b/tests/ui/lint/non-snake-case/lint-uppercase-variables.rs similarity index 100% rename from tests/ui/lint/lint-uppercase-variables.rs rename to tests/ui/lint/non-snake-case/lint-uppercase-variables.rs diff --git a/tests/ui/lint/lint-uppercase-variables.stderr b/tests/ui/lint/non-snake-case/lint-uppercase-variables.stderr similarity index 100% rename from tests/ui/lint/lint-uppercase-variables.stderr rename to tests/ui/lint/non-snake-case/lint-uppercase-variables.stderr diff --git a/tests/ui/lint/issue-66362-no-snake-case-warning-for-field-puns.rs b/tests/ui/lint/non-snake-case/no-snake-case-warning-for-field-puns-issue-66362.rs similarity index 100% rename from tests/ui/lint/issue-66362-no-snake-case-warning-for-field-puns.rs rename to tests/ui/lint/non-snake-case/no-snake-case-warning-for-field-puns-issue-66362.rs diff --git a/tests/ui/lint/issue-66362-no-snake-case-warning-for-field-puns.stderr b/tests/ui/lint/non-snake-case/no-snake-case-warning-for-field-puns-issue-66362.stderr similarity index 80% rename from tests/ui/lint/issue-66362-no-snake-case-warning-for-field-puns.stderr rename to tests/ui/lint/non-snake-case/no-snake-case-warning-for-field-puns-issue-66362.stderr index 09dc3640f99a6..cbbcf9909185a 100644 --- a/tests/ui/lint/issue-66362-no-snake-case-warning-for-field-puns.stderr +++ b/tests/ui/lint/non-snake-case/no-snake-case-warning-for-field-puns-issue-66362.stderr @@ -1,29 +1,29 @@ error: structure field `lowerCamelCaseName` should have a snake case name - --> $DIR/issue-66362-no-snake-case-warning-for-field-puns.rs:7:9 + --> $DIR/no-snake-case-warning-for-field-puns-issue-66362.rs:7:9 | LL | lowerCamelCaseName: bool, | ^^^^^^^^^^^^^^^^^^ help: convert the identifier to snake case: `lower_camel_case_name` | note: the lint level is defined here - --> $DIR/issue-66362-no-snake-case-warning-for-field-puns.rs:1:9 + --> $DIR/no-snake-case-warning-for-field-puns-issue-66362.rs:1:9 | LL | #![deny(non_snake_case)] | ^^^^^^^^^^^^^^ error: variable `lowerCamelCaseBinding` should have a snake case name - --> $DIR/issue-66362-no-snake-case-warning-for-field-puns.rs:20:38 + --> $DIR/no-snake-case-warning-for-field-puns-issue-66362.rs:20:38 | LL | Foo::Good { snake_case_name: lowerCamelCaseBinding } => { } | ^^^^^^^^^^^^^^^^^^^^^ help: convert the identifier to snake case: `lower_camel_case_binding` error: variable `anotherLowerCamelCaseBinding` should have a snake case name - --> $DIR/issue-66362-no-snake-case-warning-for-field-puns.rs:24:41 + --> $DIR/no-snake-case-warning-for-field-puns-issue-66362.rs:24:41 | LL | if let Foo::Good { snake_case_name: anotherLowerCamelCaseBinding } = b { } | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: convert the identifier to snake case: `another_lower_camel_case_binding` error: variable `yetAnotherLowerCamelCaseBinding` should have a snake case name - --> $DIR/issue-66362-no-snake-case-warning-for-field-puns.rs:27:43 + --> $DIR/no-snake-case-warning-for-field-puns-issue-66362.rs:27:43 | LL | if let Foo::Bad { lowerCamelCaseName: yetAnotherLowerCamelCaseBinding } = b { } | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: convert the identifier to snake case: `yet_another_lower_camel_case_binding` diff --git a/tests/ui/lint/issue-31924-non-snake-ffi.rs b/tests/ui/lint/non-snake-case/non-snake-ffi-issue-31924.rs similarity index 100% rename from tests/ui/lint/issue-31924-non-snake-ffi.rs rename to tests/ui/lint/non-snake-case/non-snake-ffi-issue-31924.rs diff --git a/tests/ui/lint/use_suggestion_json.stderr b/tests/ui/lint/use_suggestion_json.stderr index acc36550642d6..4683e5dd8f3c2 100644 --- a/tests/ui/lint/use_suggestion_json.stderr +++ b/tests/ui/lint/use_suggestion_json.stderr @@ -95,7 +95,7 @@ mod foo { ], "children": [ { - "message": "consider importing one of these items", + "message": "consider importing one of these structs", "code": null, "level": "help", "spans": [ @@ -386,7 +386,7 @@ mod foo { \u001b[0m\u001b[1m\u001b[38;5;12mLL\u001b[0m\u001b[0m \u001b[0m\u001b[0m\u001b[1m\u001b[38;5;12m|\u001b[0m\u001b[0m \u001b[0m\u001b[0m let x: Iter;\u001b[0m \u001b[0m \u001b[0m\u001b[0m\u001b[1m\u001b[38;5;12m|\u001b[0m\u001b[0m \u001b[0m\u001b[0m\u001b[1m\u001b[38;5;9m^^^^\u001b[0m\u001b[0m \u001b[0m\u001b[0m\u001b[1m\u001b[38;5;9mnot found in this scope\u001b[0m \u001b[0m \u001b[0m\u001b[0m\u001b[1m\u001b[38;5;12m|\u001b[0m -\u001b[0m\u001b[1m\u001b[38;5;14mhelp\u001b[0m\u001b[0m: consider importing one of these items\u001b[0m +\u001b[0m\u001b[1m\u001b[38;5;14mhelp\u001b[0m\u001b[0m: consider importing one of these structs\u001b[0m \u001b[0m \u001b[0m\u001b[0m\u001b[1m\u001b[38;5;12m|\u001b[0m \u001b[0m\u001b[1m\u001b[38;5;12mLL\u001b[0m\u001b[0m \u001b[0m\u001b[0m\u001b[38;5;10m+ use std::collections::binary_heap::Iter;\u001b[0m \u001b[0m \u001b[0m\u001b[0m\u001b[1m\u001b[38;5;12m|\u001b[0m diff --git a/tests/ui/macros/macro-metavar-expr-concat/allowed-operations.rs b/tests/ui/macros/macro-metavar-expr-concat/allowed-operations.rs new file mode 100644 index 0000000000000..e44eeffb01be8 --- /dev/null +++ b/tests/ui/macros/macro-metavar-expr-concat/allowed-operations.rs @@ -0,0 +1,58 @@ +//@ run-pass + +#![allow(dead_code, non_camel_case_types, non_upper_case_globals)] +#![feature(macro_metavar_expr_concat)] + +macro_rules! create_things { + ($lhs:ident) => { + struct ${concat($lhs, _separated_idents_in_a_struct)} { + foo: i32, + ${concat($lhs, _separated_idents_in_a_field)}: i32, + } + + mod ${concat($lhs, _separated_idents_in_a_module)} { + pub const FOO: () = (); + } + + fn ${concat($lhs, _separated_idents_in_a_fn)}() {} + }; +} + +macro_rules! many_idents { + ($a:ident, $c:ident) => { + const ${concat($a, B, $c, D)}: i32 = 1; + }; +} + +macro_rules! valid_tts { + ($_0:tt, $_1:tt) => { + const ${concat($_0, $_1)}: i32 = 1; + } +} + +macro_rules! without_dollar_sign_is_an_ident { + ($ident:ident) => { + const ${concat(VAR, ident)}: i32 = 1; + const ${concat(VAR, $ident)}: i32 = 2; + }; +} + +fn main() { + create_things!(behold); + behold_separated_idents_in_a_fn(); + let _ = behold_separated_idents_in_a_module::FOO; + let _ = behold_separated_idents_in_a_struct { + foo: 1, + behold_separated_idents_in_a_field: 2, + }; + + many_idents!(A, C); + assert_eq!(ABCD, 1); + + valid_tts!(X, YZ); + assert_eq!(XYZ, 1); + + without_dollar_sign_is_an_ident!(_123); + assert_eq!(VARident, 1); + assert_eq!(VAR_123, 2); +} diff --git a/tests/ui/macros/macro-metavar-expr-concat/hygiene.rs b/tests/ui/macros/macro-metavar-expr-concat/hygiene.rs new file mode 100644 index 0000000000000..24b0e36498a3e --- /dev/null +++ b/tests/ui/macros/macro-metavar-expr-concat/hygiene.rs @@ -0,0 +1,13 @@ +#![feature(macro_metavar_expr_concat)] + +macro_rules! join { + ($lhs:ident, $rhs:ident) => { + ${concat($lhs, $rhs)} + //~^ ERROR cannot find value `abcdef` in this scope + }; +} + +fn main() { + let abcdef = 1; + let _another = join!(abc, def); +} diff --git a/tests/ui/macros/macro-metavar-expr-concat/hygiene.stderr b/tests/ui/macros/macro-metavar-expr-concat/hygiene.stderr new file mode 100644 index 0000000000000..ef2326dce857f --- /dev/null +++ b/tests/ui/macros/macro-metavar-expr-concat/hygiene.stderr @@ -0,0 +1,14 @@ +error[E0425]: cannot find value `abcdef` in this scope + --> $DIR/hygiene.rs:5:10 + | +LL | ${concat($lhs, $rhs)} + | ^^^^^^^^^^^^^^^^^^^^ not found in this scope +... +LL | let _another = join!(abc, def); + | --------------- in this macro invocation + | + = note: this error originates in the macro `join` (in Nightly builds, run with -Z macro-backtrace for more info) + +error: aborting due to 1 previous error + +For more information about this error, try `rustc --explain E0425`. diff --git a/tests/ui/macros/macro-metavar-expr-concat/raw-identifiers.rs b/tests/ui/macros/macro-metavar-expr-concat/raw-identifiers.rs new file mode 100644 index 0000000000000..f72b9baca89f8 --- /dev/null +++ b/tests/ui/macros/macro-metavar-expr-concat/raw-identifiers.rs @@ -0,0 +1,81 @@ +#![feature(macro_metavar_expr_concat)] + +macro_rules! idents_01 { + ($rhs:ident) => { + let ${concat(abc, $rhs)}: () = (); + //~^ ERROR `${concat(..)}` currently does not support raw identifiers + }; +} + +macro_rules! idents_10 { + ($lhs:ident) => { + let ${concat($lhs, abc)}: () = (); + //~^ ERROR `${concat(..)}` currently does not support raw identifiers + }; +} + +macro_rules! idents_11 { + ($lhs:ident, $rhs:ident) => { + let ${concat($lhs, $rhs)}: () = (); + //~^ ERROR `${concat(..)}` currently does not support raw identifiers + //~| ERROR `${concat(..)}` currently does not support raw identifiers + //~| ERROR `${concat(..)}` currently does not support raw identifiers + }; +} + +macro_rules! no_params { + () => { + let ${concat(r#abc, abc)}: () = (); + //~^ ERROR `${concat(..)}` currently does not support raw identifiers + //~| ERROR expected pattern, found `$` + + let ${concat(abc, r#abc)}: () = (); + //~^ ERROR `${concat(..)}` currently does not support raw identifiers + + let ${concat(r#abc, r#abc)}: () = (); + //~^ ERROR `${concat(..)}` currently does not support raw identifiers + }; +} + +macro_rules! tts_01 { + ($rhs:tt) => { + let ${concat(abc, $rhs)}: () = (); + //~^ ERROR `${concat(..)}` currently does not support raw identifiers + }; +} + +macro_rules! tts_10 { + ($lhs:tt) => { + let ${concat($lhs, abc)}: () = (); + //~^ ERROR `${concat(..)}` currently does not support raw identifiers + }; +} + +macro_rules! tts_11 { + ($lhs:tt, $rhs:tt) => { + let ${concat($lhs, $rhs)}: () = (); + //~^ ERROR `${concat(..)}` currently does not support raw identifiers + //~| ERROR `${concat(..)}` currently does not support raw identifiers + //~| ERROR `${concat(..)}` currently does not support raw identifiers + }; +} + +fn main() { + idents_01!(r#_c); + + idents_10!(r#_c); + + idents_11!(r#_c, d); + idents_11!(_e, r#f); + idents_11!(r#_g, r#h); + + tts_01!(r#_c); + + tts_10!(r#_c); + + tts_11!(r#_c, d); + tts_11!(_e, r#f); + tts_11!(r#_g, r#h); + + no_params!(); +} diff --git a/tests/ui/macros/macro-metavar-expr-concat/raw-identifiers.stderr b/tests/ui/macros/macro-metavar-expr-concat/raw-identifiers.stderr new file mode 100644 index 0000000000000..dd525cf0801be --- /dev/null +++ b/tests/ui/macros/macro-metavar-expr-concat/raw-identifiers.stderr @@ -0,0 +1,95 @@ +error: `${concat(..)}` currently does not support raw identifiers + --> $DIR/raw-identifiers.rs:28:22 + | +LL | let ${concat(r#abc, abc)}: () = (); + | ^^^^^ + +error: `${concat(..)}` currently does not support raw identifiers + --> $DIR/raw-identifiers.rs:32:27 + | +LL | let ${concat(abc, r#abc)}: () = (); + | ^^^^^ + +error: `${concat(..)}` currently does not support raw identifiers + --> $DIR/raw-identifiers.rs:35:22 + | +LL | let ${concat(r#abc, r#abc)}: () = (); + | ^^^^^ + +error: `${concat(..)}` currently does not support raw identifiers + --> $DIR/raw-identifiers.rs:5:28 + | +LL | let ${concat(abc, $rhs)}: () = (); + | ^^^ + +error: `${concat(..)}` currently does not support raw identifiers + --> $DIR/raw-identifiers.rs:12:23 + | +LL | let ${concat($lhs, abc)}: () = (); + | ^^^ + +error: `${concat(..)}` currently does not support raw identifiers + --> $DIR/raw-identifiers.rs:19:23 + | +LL | let ${concat($lhs, $rhs)}: () = (); + | ^^^ + +error: `${concat(..)}` currently does not support raw identifiers + --> $DIR/raw-identifiers.rs:19:29 + | +LL | let ${concat($lhs, $rhs)}: () = (); + | ^^^ + +error: `${concat(..)}` currently does not support raw identifiers + --> $DIR/raw-identifiers.rs:19:23 + | +LL | let ${concat($lhs, $rhs)}: () = (); + | ^^^ + | + = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no` + +error: `${concat(..)}` currently does not support raw identifiers + --> $DIR/raw-identifiers.rs:42:28 + | +LL | let ${concat(abc, $rhs)}: () = (); + | ^^^ + +error: `${concat(..)}` currently does not support raw identifiers + --> $DIR/raw-identifiers.rs:49:23 + | +LL | let ${concat($lhs, abc)}: () = (); + | ^^^ + +error: `${concat(..)}` currently does not support raw identifiers + --> $DIR/raw-identifiers.rs:56:23 + | +LL | let ${concat($lhs, $rhs)}: () = (); + | ^^^ + +error: `${concat(..)}` currently does not support raw identifiers + --> $DIR/raw-identifiers.rs:56:29 + | +LL | let ${concat($lhs, $rhs)}: () = (); + | ^^^ + +error: `${concat(..)}` currently does not support raw identifiers + --> $DIR/raw-identifiers.rs:56:23 + | +LL | let ${concat($lhs, $rhs)}: () = (); + | ^^^ + | + = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no` + +error: expected pattern, found `$` + --> $DIR/raw-identifiers.rs:28:13 + | +LL | let ${concat(r#abc, abc)}: () = (); + | ^ expected pattern +... +LL | no_params!(); + | ------------ in this macro invocation + | + = note: this error originates in the macro `no_params` (in Nightly builds, run with -Z macro-backtrace for more info) + +error: aborting due to 14 previous errors + diff --git a/tests/ui/macros/macro-metavar-expr-concat/syntax-errors.rs b/tests/ui/macros/macro-metavar-expr-concat/syntax-errors.rs new file mode 100644 index 0000000000000..bf47442ea76fb --- /dev/null +++ b/tests/ui/macros/macro-metavar-expr-concat/syntax-errors.rs @@ -0,0 +1,50 @@ +#![feature(macro_metavar_expr_concat)] + +macro_rules! wrong_concat_declarations { + ($ex:expr) => { + ${concat()} + //~^ ERROR expected identifier + + ${concat(aaaa)} + //~^ ERROR `concat` must have at least two elements + + ${concat(aaaa,)} + //~^ ERROR expected identifier + + ${concat(aaaa, 1)} + //~^ ERROR expected identifier + + ${concat(_, aaaa)} + + ${concat(aaaa aaaa)} + //~^ ERROR expected comma + + ${concat($ex)} + //~^ ERROR `concat` must have at least two elements + + ${concat($ex, aaaa)} + //~^ ERROR `${concat(..)}` currently only accepts identifiers + + ${concat($ex, aaaa 123)} + //~^ ERROR expected comma + + ${concat($ex, aaaa,)} + //~^ ERROR expected identifier + + ${concat($ex, aaaa, 123)} + //~^ ERROR expected identifier + }; +} + +macro_rules! dollar_sign_without_referenced_ident { + ($ident:ident) => { + const ${concat(FOO, $foo)}: i32 = 2; + //~^ ERROR variable `foo` is not recognized in meta-variable expression + }; +} + +fn main() { + wrong_concat_declarations!(1); + + dollar_sign_without_referenced_ident!(VAR); +} diff --git a/tests/ui/macros/macro-metavar-expr-concat/syntax-errors.stderr b/tests/ui/macros/macro-metavar-expr-concat/syntax-errors.stderr new file mode 100644 index 0000000000000..b216a86d59abe --- /dev/null +++ b/tests/ui/macros/macro-metavar-expr-concat/syntax-errors.stderr @@ -0,0 +1,68 @@ +error: expected identifier + --> $DIR/syntax-errors.rs:5:10 + | +LL | ${concat()} + | ^^^^^^^^^^ + +error: `concat` must have at least two elements + --> $DIR/syntax-errors.rs:8:11 + | +LL | ${concat(aaaa)} + | ^^^^^^ + +error: expected identifier + --> $DIR/syntax-errors.rs:11:10 + | +LL | ${concat(aaaa,)} + | ^^^^^^^^^^^^^^^ + +error: expected identifier, found `1` + --> $DIR/syntax-errors.rs:14:24 + | +LL | ${concat(aaaa, 1)} + | ^ help: try removing `1` + +error: expected comma + --> $DIR/syntax-errors.rs:19:10 + | +LL | ${concat(aaaa aaaa)} + | ^^^^^^^^^^^^^^^^^^^ + +error: `concat` must have at least two elements + --> $DIR/syntax-errors.rs:22:11 + | +LL | ${concat($ex)} + | ^^^^^^ + +error: expected comma + --> $DIR/syntax-errors.rs:28:10 + | +LL | ${concat($ex, aaaa 123)} + | ^^^^^^^^^^^^^^^^^^^^^^^ + +error: expected identifier + --> $DIR/syntax-errors.rs:31:10 + | +LL | ${concat($ex, aaaa,)} + | ^^^^^^^^^^^^^^^^^^^^ + +error: expected identifier, found `123` + --> $DIR/syntax-errors.rs:34:29 + | +LL | ${concat($ex, aaaa, 123)} + | ^^^ help: try removing `123` + +error: `${concat(..)}` currently only accepts identifiers or meta-variables as parameters + --> $DIR/syntax-errors.rs:25:19 + | +LL | ${concat($ex, aaaa)} + | ^^ + +error: variable `foo` is not recognized in meta-variable expression + --> $DIR/syntax-errors.rs:41:30 + | +LL | const ${concat(FOO, $foo)}: i32 = 2; + | ^^^ + +error: aborting due to 11 previous errors + diff --git a/tests/ui/macros/rfc-3086-metavar-expr/syntax-errors.stderr b/tests/ui/macros/rfc-3086-metavar-expr/syntax-errors.stderr index 3fa3839bae2e5..8e4ba192d79f5 100644 --- a/tests/ui/macros/rfc-3086-metavar-expr/syntax-errors.stderr +++ b/tests/ui/macros/rfc-3086-metavar-expr/syntax-errors.stderr @@ -191,10 +191,10 @@ LL | ( $( $i:ident ),* ) => { ${ aaaaaaaaaaaaaa(i) } }; | ^^^^^^^^^^^^^^ help: supported expressions are count, ignore, index and len error: expected identifier - --> $DIR/syntax-errors.rs:118:31 + --> $DIR/syntax-errors.rs:118:33 | LL | ( $( $i:ident ),* ) => { ${ {} } }; - | ^^^^^^ + | ^^ error: `count` can not be placed inside the inner-most repetition --> $DIR/syntax-errors.rs:12:24 diff --git a/tests/ui/methods/opaque_param_in_ufc.rs b/tests/ui/methods/opaque_param_in_ufc.rs index a4b27a0131fd0..b170e6805f646 100644 --- a/tests/ui/methods/opaque_param_in_ufc.rs +++ b/tests/ui/methods/opaque_param_in_ufc.rs @@ -1,4 +1,7 @@ #![feature(type_alias_impl_trait)] + +//@ check-pass + struct Foo(T); impl Foo { @@ -15,14 +18,11 @@ fn bar() -> Bar { impl Foo { fn foo() -> Bar { Self::method(); - //~^ ERROR: no function or associated item named `method` found for struct `Foo` Foo::::method(); - //~^ ERROR: no function or associated item named `method` found for struct `Foo` let x = Foo(bar()); Foo::method2(x); let x = Self(bar()); Self::method2(x); - //~^ ERROR: no function or associated item named `method2` found for struct `Foo` todo!() } } diff --git a/tests/ui/methods/opaque_param_in_ufc.stderr b/tests/ui/methods/opaque_param_in_ufc.stderr deleted file mode 100644 index 7e5bbbac8a9ab..0000000000000 --- a/tests/ui/methods/opaque_param_in_ufc.stderr +++ /dev/null @@ -1,36 +0,0 @@ -error[E0599]: no function or associated item named `method` found for struct `Foo` in the current scope - --> $DIR/opaque_param_in_ufc.rs:17:15 - | -LL | struct Foo(T); - | ------------- function or associated item `method` not found for this struct -... -LL | Self::method(); - | ^^^^^^ function or associated item not found in `Foo` - | - = note: the function or associated item was found for - - `Foo` - -error[E0599]: no function or associated item named `method` found for struct `Foo` in the current scope - --> $DIR/opaque_param_in_ufc.rs:19:21 - | -LL | struct Foo(T); - | ------------- function or associated item `method` not found for this struct -... -LL | Foo::::method(); - | ^^^^^^ function or associated item not found in `Foo` - | - = note: the function or associated item was found for - - `Foo` - -error[E0599]: no function or associated item named `method2` found for struct `Foo` in the current scope - --> $DIR/opaque_param_in_ufc.rs:24:15 - | -LL | struct Foo(T); - | ------------- function or associated item `method2` not found for this struct -... -LL | Self::method2(x); - | ^^^^^^^ function or associated item not found in `Foo` - -error: aborting due to 3 previous errors - -For more information about this error, try `rustc --explain E0599`. diff --git a/tests/ui/mismatched_types/binops.stderr b/tests/ui/mismatched_types/binops.stderr index 099c580a0565e..92f21a67c3707 100644 --- a/tests/ui/mismatched_types/binops.stderr +++ b/tests/ui/mismatched_types/binops.stderr @@ -6,14 +6,14 @@ LL | 1 + Some(1); | = help: the trait `Add>` is not implemented for `{integer}` = help: the following other types implement trait `Add`: - <&'a f128 as Add> - <&'a f16 as Add> - <&'a f32 as Add> - <&'a f64 as Add> - <&'a i128 as Add> - <&'a i16 as Add> - <&'a i32 as Add> - <&'a i64 as Add> + `&'a f128` implements `Add` + `&'a f16` implements `Add` + `&'a f32` implements `Add` + `&'a f64` implements `Add` + `&'a i128` implements `Add` + `&'a i16` implements `Add` + `&'a i32` implements `Add` + `&'a i64` implements `Add` and 56 others error[E0277]: cannot subtract `Option<{integer}>` from `usize` @@ -24,10 +24,10 @@ LL | 2 as usize - Some(1); | = help: the trait `Sub>` is not implemented for `usize` = help: the following other types implement trait `Sub`: - <&'a usize as Sub> - <&usize as Sub<&usize>> - > - + `&'a usize` implements `Sub` + `&usize` implements `Sub<&usize>` + `usize` implements `Sub<&usize>` + `usize` implements `Sub` error[E0277]: cannot multiply `{integer}` by `()` --> $DIR/binops.rs:4:7 @@ -37,14 +37,14 @@ LL | 3 * (); | = help: the trait `Mul<()>` is not implemented for `{integer}` = help: the following other types implement trait `Mul`: - <&'a f128 as Mul> - <&'a f16 as Mul> - <&'a f32 as Mul> - <&'a f64 as Mul> - <&'a i128 as Mul> - <&'a i16 as Mul> - <&'a i32 as Mul> - <&'a i64 as Mul> + `&'a f128` implements `Mul` + `&'a f16` implements `Mul` + `&'a f32` implements `Mul` + `&'a f64` implements `Mul` + `&'a i128` implements `Mul` + `&'a i16` implements `Mul` + `&'a i32` implements `Mul` + `&'a i64` implements `Mul` and 57 others error[E0277]: cannot divide `{integer}` by `&str` @@ -55,14 +55,14 @@ LL | 4 / ""; | = help: the trait `Div<&str>` is not implemented for `{integer}` = help: the following other types implement trait `Div`: - <&'a f128 as Div> - <&'a f16 as Div> - <&'a f32 as Div> - <&'a f64 as Div> - <&'a i128 as Div> - <&'a i16 as Div> - <&'a i32 as Div> - <&'a i64 as Div> + `&'a f128` implements `Div` + `&'a f16` implements `Div` + `&'a f32` implements `Div` + `&'a f64` implements `Div` + `&'a i128` implements `Div` + `&'a i16` implements `Div` + `&'a i32` implements `Div` + `&'a i64` implements `Div` and 62 others error[E0277]: can't compare `{integer}` with `String` diff --git a/tests/ui/namespace/namespace-mix.stderr b/tests/ui/namespace/namespace-mix.stderr index 4eff08ead42ce..b80363fe8f848 100644 --- a/tests/ui/namespace/namespace-mix.stderr +++ b/tests/ui/namespace/namespace-mix.stderr @@ -12,7 +12,7 @@ help: a tuple struct with a similar name exists | LL | check(m1::TS); | ~~ -help: consider importing one of these items instead +help: consider importing one of these constants instead | LL + use m2::S; | @@ -40,7 +40,7 @@ help: a tuple struct with a similar name exists | LL | check(xm1::TS); | ~~ -help: consider importing one of these items instead +help: consider importing one of these constants instead | LL + use m2::S; | @@ -66,7 +66,7 @@ help: a tuple variant with a similar name exists | LL | check(m7::TV); | ~~ -help: consider importing one of these items instead +help: consider importing one of these constants instead | LL + use m8::V; | @@ -94,7 +94,7 @@ help: a tuple variant with a similar name exists | LL | check(xm7::TV); | ~~ -help: consider importing one of these items instead +help: consider importing one of these constants instead | LL + use m8::V; | diff --git a/tests/ui/never_type/defaulted-never-note.fallback.stderr b/tests/ui/never_type/defaulted-never-note.fallback.stderr index 92fa9068cfd5e..fe9a924f64a0f 100644 --- a/tests/ui/never_type/defaulted-never-note.fallback.stderr +++ b/tests/ui/never_type/defaulted-never-note.fallback.stderr @@ -1,5 +1,5 @@ error[E0277]: the trait bound `!: ImplementedForUnitButNotNever` is not satisfied - --> $DIR/defaulted-never-note.rs:30:9 + --> $DIR/defaulted-never-note.rs:32:9 | LL | foo(_x); | --- ^^ the trait `ImplementedForUnitButNotNever` is not implemented for `!` diff --git a/tests/ui/never_type/defaulted-never-note.nofallback.stderr b/tests/ui/never_type/defaulted-never-note.nofallback.stderr new file mode 100644 index 0000000000000..d88615186dd63 --- /dev/null +++ b/tests/ui/never_type/defaulted-never-note.nofallback.stderr @@ -0,0 +1,18 @@ +warning: this function depends on never type fallback being `()` + --> $DIR/defaulted-never-note.rs:28:1 + | +LL | fn smeg() { + | ^^^^^^^^^ + | + = 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 #123748 + = help: specify the types explicitly +note: in edition 2024, the requirement `!: ImplementedForUnitButNotNever` will fail + --> $DIR/defaulted-never-note.rs:32:9 + | +LL | foo(_x); + | ^^ + = note: `#[warn(dependency_on_unit_never_type_fallback)]` on by default + +warning: 1 warning emitted + diff --git a/tests/ui/never_type/defaulted-never-note.rs b/tests/ui/never_type/defaulted-never-note.rs index f4e5273b33a76..40861e73b393c 100644 --- a/tests/ui/never_type/defaulted-never-note.rs +++ b/tests/ui/never_type/defaulted-never-note.rs @@ -26,6 +26,8 @@ fn foo(_t: T) {} //[fallback]~^ NOTE required by this bound in `foo` //[fallback]~| NOTE required by a bound in `foo` fn smeg() { + //[nofallback]~^ warn: this function depends on never type fallback being `()` + //[nofallback]~| warn: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! let _x = return; foo(_x); //[fallback]~^ ERROR the trait bound diff --git a/tests/ui/never_type/dependency-on-fallback-to-unit.rs b/tests/ui/never_type/dependency-on-fallback-to-unit.rs new file mode 100644 index 0000000000000..5448d0be2c6de --- /dev/null +++ b/tests/ui/never_type/dependency-on-fallback-to-unit.rs @@ -0,0 +1,28 @@ +//@ check-pass + +fn main() { + def(); + _ = question_mark(); +} + +fn def() { + //~^ warn: this function depends on never type fallback being `()` + //~| warn: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! + match true { + false => <_>::default(), + true => return, + }; +} + +// +// +fn question_mark() -> Result<(), ()> { + //~^ warn: this function depends on never type fallback being `()` + //~| warn: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! + deserialize()?; + Ok(()) +} + +fn deserialize() -> Result { + Ok(T::default()) +} diff --git a/tests/ui/never_type/dependency-on-fallback-to-unit.stderr b/tests/ui/never_type/dependency-on-fallback-to-unit.stderr new file mode 100644 index 0000000000000..ec49137ba7953 --- /dev/null +++ b/tests/ui/never_type/dependency-on-fallback-to-unit.stderr @@ -0,0 +1,33 @@ +warning: this function depends on never type fallback being `()` + --> $DIR/dependency-on-fallback-to-unit.rs:8:1 + | +LL | fn def() { + | ^^^^^^^^ + | + = 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 #123748 + = help: specify the types explicitly +note: in edition 2024, the requirement `!: Default` will fail + --> $DIR/dependency-on-fallback-to-unit.rs:12:19 + | +LL | false => <_>::default(), + | ^ + = note: `#[warn(dependency_on_unit_never_type_fallback)]` on by default + +warning: this function depends on never type fallback being `()` + --> $DIR/dependency-on-fallback-to-unit.rs:19:1 + | +LL | fn question_mark() -> Result<(), ()> { + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | + = 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 #123748 + = help: specify the types explicitly +note: in edition 2024, the requirement `!: Default` will fail + --> $DIR/dependency-on-fallback-to-unit.rs:22:5 + | +LL | deserialize()?; + | ^^^^^^^^^^^^^ + +warning: 2 warnings emitted + diff --git a/tests/ui/never_type/diverging-fallback-control-flow.nofallback.stderr b/tests/ui/never_type/diverging-fallback-control-flow.nofallback.stderr new file mode 100644 index 0000000000000..2a3c5edc21847 --- /dev/null +++ b/tests/ui/never_type/diverging-fallback-control-flow.nofallback.stderr @@ -0,0 +1,33 @@ +warning: this function depends on never type fallback being `()` + --> $DIR/diverging-fallback-control-flow.rs:30:1 + | +LL | fn assignment() { + | ^^^^^^^^^^^^^^^ + | + = 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 #123748 + = help: specify the types explicitly +note: in edition 2024, the requirement `!: UnitDefault` will fail + --> $DIR/diverging-fallback-control-flow.rs:36:13 + | +LL | x = UnitDefault::default(); + | ^^^^^^^^^^^^^^^^^^^^^^ + = note: `#[warn(dependency_on_unit_never_type_fallback)]` on by default + +warning: this function depends on never type fallback being `()` + --> $DIR/diverging-fallback-control-flow.rs:42:1 + | +LL | fn assignment_rev() { + | ^^^^^^^^^^^^^^^^^^^ + | + = 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 #123748 + = help: specify the types explicitly +note: in edition 2024, the requirement `!: UnitDefault` will fail + --> $DIR/diverging-fallback-control-flow.rs:50:13 + | +LL | x = UnitDefault::default(); + | ^^^^^^^^^^^^^^^^^^^^^^ + +warning: 2 warnings emitted + diff --git a/tests/ui/never_type/diverging-fallback-control-flow.rs b/tests/ui/never_type/diverging-fallback-control-flow.rs index e209a9908850a..575e2e9273cf4 100644 --- a/tests/ui/never_type/diverging-fallback-control-flow.rs +++ b/tests/ui/never_type/diverging-fallback-control-flow.rs @@ -28,6 +28,8 @@ impl UnitDefault for () { } fn assignment() { + //[nofallback]~^ warn: this function depends on never type fallback being `()` + //[nofallback]~| warn: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! let x; if true { @@ -38,6 +40,8 @@ fn assignment() { } fn assignment_rev() { + //[nofallback]~^ warn: this function depends on never type fallback being `()` + //[nofallback]~| warn: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! let x; if true { diff --git a/tests/ui/never_type/diverging-fallback-no-leak.fallback.stderr b/tests/ui/never_type/diverging-fallback-no-leak.fallback.stderr index 01abf2e17f1e8..c5463814475c7 100644 --- a/tests/ui/never_type/diverging-fallback-no-leak.fallback.stderr +++ b/tests/ui/never_type/diverging-fallback-no-leak.fallback.stderr @@ -1,5 +1,5 @@ error[E0277]: the trait bound `!: Test` is not satisfied - --> $DIR/diverging-fallback-no-leak.rs:17:23 + --> $DIR/diverging-fallback-no-leak.rs:20:23 | LL | unconstrained_arg(return); | ----------------- ^^^^^^ the trait `Test` is not implemented for `!` diff --git a/tests/ui/never_type/diverging-fallback-no-leak.nofallback.stderr b/tests/ui/never_type/diverging-fallback-no-leak.nofallback.stderr new file mode 100644 index 0000000000000..11245cc7aabf9 --- /dev/null +++ b/tests/ui/never_type/diverging-fallback-no-leak.nofallback.stderr @@ -0,0 +1,18 @@ +warning: this function depends on never type fallback being `()` + --> $DIR/diverging-fallback-no-leak.rs:14:1 + | +LL | fn main() { + | ^^^^^^^^^ + | + = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! + = note: for more information, see issue #123748 + = help: specify the types explicitly +note: in edition 2024, the requirement `!: Test` will fail + --> $DIR/diverging-fallback-no-leak.rs:20:23 + | +LL | unconstrained_arg(return); + | ^^^^^^ + = note: `#[warn(dependency_on_unit_never_type_fallback)]` on by default + +warning: 1 warning emitted + diff --git a/tests/ui/never_type/diverging-fallback-no-leak.rs b/tests/ui/never_type/diverging-fallback-no-leak.rs index 425437da2077b..c6d59c7f2738f 100644 --- a/tests/ui/never_type/diverging-fallback-no-leak.rs +++ b/tests/ui/never_type/diverging-fallback-no-leak.rs @@ -12,6 +12,9 @@ impl Test for () {} fn unconstrained_arg(_: T) {} fn main() { + //[nofallback]~^ warn: this function depends on never type fallback being `()` + //[nofallback]~| warn: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! + // Here the type variable falls back to `!`, // and hence we get a type error. unconstrained_arg(return); diff --git a/tests/ui/never_type/diverging-fallback-unconstrained-return.nofallback.stderr b/tests/ui/never_type/diverging-fallback-unconstrained-return.nofallback.stderr new file mode 100644 index 0000000000000..b485c94df4d6f --- /dev/null +++ b/tests/ui/never_type/diverging-fallback-unconstrained-return.nofallback.stderr @@ -0,0 +1,18 @@ +warning: this function depends on never type fallback being `()` + --> $DIR/diverging-fallback-unconstrained-return.rs:28:1 + | +LL | fn main() { + | ^^^^^^^^^ + | + = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! + = note: for more information, see issue #123748 + = help: specify the types explicitly +note: in edition 2024, the requirement `!: UnitReturn` will fail + --> $DIR/diverging-fallback-unconstrained-return.rs:39:23 + | +LL | let _ = if true { unconstrained_return() } else { panic!() }; + | ^^^^^^^^^^^^^^^^^^^^^^ + = note: `#[warn(dependency_on_unit_never_type_fallback)]` on by default + +warning: 1 warning emitted + diff --git a/tests/ui/never_type/diverging-fallback-unconstrained-return.rs b/tests/ui/never_type/diverging-fallback-unconstrained-return.rs index aeb6ee6e26efd..927991db5138d 100644 --- a/tests/ui/never_type/diverging-fallback-unconstrained-return.rs +++ b/tests/ui/never_type/diverging-fallback-unconstrained-return.rs @@ -26,6 +26,9 @@ fn unconstrained_return() -> T { } fn main() { + //[nofallback]~^ warn: this function depends on never type fallback being `()` + //[nofallback]~| warn: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! + // In Ye Olde Days, the `T` parameter of `unconstrained_return` // winds up "entangled" with the `!` type that results from // `panic!`, and hence falls back to `()`. This is kind of unfortunate diff --git a/tests/ui/never_type/fallback-closure-ret.nofallback.stderr b/tests/ui/never_type/fallback-closure-ret.nofallback.stderr new file mode 100644 index 0000000000000..3fb5536dee7e3 --- /dev/null +++ b/tests/ui/never_type/fallback-closure-ret.nofallback.stderr @@ -0,0 +1,18 @@ +warning: this function depends on never type fallback being `()` + --> $DIR/fallback-closure-ret.rs:21:1 + | +LL | fn main() { + | ^^^^^^^^^ + | + = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! + = note: for more information, see issue #123748 + = help: specify the types explicitly +note: in edition 2024, the requirement `!: Bar` will fail + --> $DIR/fallback-closure-ret.rs:24:5 + | +LL | foo(|| panic!()); + | ^^^^^^^^^^^^^^^^ + = note: `#[warn(dependency_on_unit_never_type_fallback)]` on by default + +warning: 1 warning emitted + diff --git a/tests/ui/never_type/fallback-closure-ret.rs b/tests/ui/never_type/fallback-closure-ret.rs index dcf38e03a137e..30f9ac54d0bbb 100644 --- a/tests/ui/never_type/fallback-closure-ret.rs +++ b/tests/ui/never_type/fallback-closure-ret.rs @@ -12,12 +12,14 @@ #![cfg_attr(fallback, feature(never_type_fallback))] -trait Bar { } -impl Bar for () { } -impl Bar for u32 { } +trait Bar {} +impl Bar for () {} +impl Bar for u32 {} fn foo(_: impl Fn() -> R) {} fn main() { + //[nofallback]~^ warn: this function depends on never type fallback being `()` + //[nofallback]~| warn: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! foo(|| panic!()); } diff --git a/tests/ui/never_type/impl_trait_fallback.rs b/tests/ui/never_type/impl_trait_fallback.rs index ce06f8f7817ff..fbe13dbe2acee 100644 --- a/tests/ui/never_type/impl_trait_fallback.rs +++ b/tests/ui/never_type/impl_trait_fallback.rs @@ -6,5 +6,7 @@ trait T {} impl T for () {} fn should_ret_unit() -> impl T { + //~^ warn: this function depends on never type fallback being `()` + //~| warn: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! panic!() } diff --git a/tests/ui/never_type/impl_trait_fallback.stderr b/tests/ui/never_type/impl_trait_fallback.stderr new file mode 100644 index 0000000000000..4496746e018e6 --- /dev/null +++ b/tests/ui/never_type/impl_trait_fallback.stderr @@ -0,0 +1,18 @@ +warning: this function depends on never type fallback being `()` + --> $DIR/impl_trait_fallback.rs:8:1 + | +LL | fn should_ret_unit() -> impl T { + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | + = 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 #123748 + = help: specify the types explicitly +note: in edition 2024, the requirement `!: T` will fail + --> $DIR/impl_trait_fallback.rs:8:25 + | +LL | fn should_ret_unit() -> impl T { + | ^^^^^^ + = note: `#[warn(dependency_on_unit_never_type_fallback)]` on by default + +warning: 1 warning emitted + diff --git a/tests/ui/never_type/issue-13352.stderr b/tests/ui/never_type/issue-13352.stderr index 1b979d9344628..7134e4d40a6a7 100644 --- a/tests/ui/never_type/issue-13352.stderr +++ b/tests/ui/never_type/issue-13352.stderr @@ -6,10 +6,10 @@ LL | 2_usize + (loop {}); | = help: the trait `Add<()>` is not implemented for `usize` = help: the following other types implement trait `Add`: - <&'a usize as Add> - <&usize as Add<&usize>> - > - + `&'a usize` implements `Add` + `&usize` implements `Add<&usize>` + `usize` implements `Add<&usize>` + `usize` implements `Add` error: aborting due to 1 previous error diff --git a/tests/ui/numbers-arithmetic/f16-f128-lit.rs b/tests/ui/numbers-arithmetic/f16-f128-lit.rs index 762436edb1663..7fd20d91d8248 100644 --- a/tests/ui/numbers-arithmetic/f16-f128-lit.rs +++ b/tests/ui/numbers-arithmetic/f16-f128-lit.rs @@ -1,3 +1,5 @@ +// Make sure negation happens correctly. Also included: +// issue: rust-lang/rust#124583 //@ run-pass #![feature(f16)] @@ -8,9 +10,11 @@ fn main() { assert_eq!((-0.0_f16).to_bits(), 0x8000); assert_eq!(10.0_f16.to_bits(), 0x4900); assert_eq!((-10.0_f16).to_bits(), 0xC900); + assert_eq!((-(-0.0f16)).to_bits(), 0x0000); assert_eq!(0.0_f128.to_bits(), 0x0000_0000_0000_0000_0000_0000_0000_0000); assert_eq!((-0.0_f128).to_bits(), 0x8000_0000_0000_0000_0000_0000_0000_0000); assert_eq!(10.0_f128.to_bits(), 0x4002_4000_0000_0000_0000_0000_0000_0000); assert_eq!((-10.0_f128).to_bits(), 0xC002_4000_0000_0000_0000_0000_0000_0000); + assert_eq!((-(-0.0f128)).to_bits(), 0x0000_0000_0000_0000_0000_0000_0000_0000); } diff --git a/tests/ui/numbers-arithmetic/not-suggest-float-literal.stderr b/tests/ui/numbers-arithmetic/not-suggest-float-literal.stderr index 14685a3f9371a..a910666bd56ce 100644 --- a/tests/ui/numbers-arithmetic/not-suggest-float-literal.stderr +++ b/tests/ui/numbers-arithmetic/not-suggest-float-literal.stderr @@ -6,10 +6,10 @@ LL | x + 100.0 | = help: the trait `Add<{float}>` is not implemented for `u8` = help: the following other types implement trait `Add`: - <&'a u8 as Add> - <&u8 as Add<&u8>> - > - + `&'a u8` implements `Add` + `&u8` implements `Add<&u8>` + `u8` implements `Add<&u8>` + `u8` implements `Add` error[E0277]: cannot add `&str` to `f64` --> $DIR/not-suggest-float-literal.rs:6:7 @@ -19,10 +19,10 @@ LL | x + "foo" | = help: the trait `Add<&str>` is not implemented for `f64` = help: the following other types implement trait `Add`: - <&'a f64 as Add> - <&f64 as Add<&f64>> - > - + `&'a f64` implements `Add` + `&f64` implements `Add<&f64>` + `f64` implements `Add<&f64>` + `f64` implements `Add` error[E0277]: cannot add `{integer}` to `f64` --> $DIR/not-suggest-float-literal.rs:11:7 @@ -32,10 +32,10 @@ LL | x + y | = help: the trait `Add<{integer}>` is not implemented for `f64` = help: the following other types implement trait `Add`: - <&'a f64 as Add> - <&f64 as Add<&f64>> - > - + `&'a f64` implements `Add` + `&f64` implements `Add<&f64>` + `f64` implements `Add<&f64>` + `f64` implements `Add` error[E0277]: cannot subtract `{float}` from `u8` --> $DIR/not-suggest-float-literal.rs:15:7 @@ -45,10 +45,10 @@ LL | x - 100.0 | = help: the trait `Sub<{float}>` is not implemented for `u8` = help: the following other types implement trait `Sub`: - <&'a u8 as Sub> - <&u8 as Sub<&u8>> - > - + `&'a u8` implements `Sub` + `&u8` implements `Sub<&u8>` + `u8` implements `Sub<&u8>` + `u8` implements `Sub` error[E0277]: cannot subtract `&str` from `f64` --> $DIR/not-suggest-float-literal.rs:19:7 @@ -58,10 +58,10 @@ LL | x - "foo" | = help: the trait `Sub<&str>` is not implemented for `f64` = help: the following other types implement trait `Sub`: - <&'a f64 as Sub> - <&f64 as Sub<&f64>> - > - + `&'a f64` implements `Sub` + `&f64` implements `Sub<&f64>` + `f64` implements `Sub<&f64>` + `f64` implements `Sub` error[E0277]: cannot subtract `{integer}` from `f64` --> $DIR/not-suggest-float-literal.rs:24:7 @@ -71,10 +71,10 @@ LL | x - y | = help: the trait `Sub<{integer}>` is not implemented for `f64` = help: the following other types implement trait `Sub`: - <&'a f64 as Sub> - <&f64 as Sub<&f64>> - > - + `&'a f64` implements `Sub` + `&f64` implements `Sub<&f64>` + `f64` implements `Sub<&f64>` + `f64` implements `Sub` error[E0277]: cannot multiply `u8` by `{float}` --> $DIR/not-suggest-float-literal.rs:28:7 @@ -84,10 +84,10 @@ LL | x * 100.0 | = help: the trait `Mul<{float}>` is not implemented for `u8` = help: the following other types implement trait `Mul`: - <&'a u8 as Mul> - <&u8 as Mul<&u8>> - > - + `&'a u8` implements `Mul` + `&u8` implements `Mul<&u8>` + `u8` implements `Mul<&u8>` + `u8` implements `Mul` error[E0277]: cannot multiply `f64` by `&str` --> $DIR/not-suggest-float-literal.rs:32:7 @@ -97,10 +97,10 @@ LL | x * "foo" | = help: the trait `Mul<&str>` is not implemented for `f64` = help: the following other types implement trait `Mul`: - <&'a f64 as Mul> - <&f64 as Mul<&f64>> - > - + `&'a f64` implements `Mul` + `&f64` implements `Mul<&f64>` + `f64` implements `Mul<&f64>` + `f64` implements `Mul` error[E0277]: cannot multiply `f64` by `{integer}` --> $DIR/not-suggest-float-literal.rs:37:7 @@ -110,10 +110,10 @@ LL | x * y | = help: the trait `Mul<{integer}>` is not implemented for `f64` = help: the following other types implement trait `Mul`: - <&'a f64 as Mul> - <&f64 as Mul<&f64>> - > - + `&'a f64` implements `Mul` + `&f64` implements `Mul<&f64>` + `f64` implements `Mul<&f64>` + `f64` implements `Mul` error[E0277]: cannot divide `u8` by `{float}` --> $DIR/not-suggest-float-literal.rs:41:7 @@ -123,11 +123,11 @@ LL | x / 100.0 | = help: the trait `Div<{float}>` is not implemented for `u8` = help: the following other types implement trait `Div`: - <&'a u8 as Div> - <&u8 as Div<&u8>> - > - >> - + `&'a u8` implements `Div` + `&u8` implements `Div<&u8>` + `u8` implements `Div<&u8>` + `u8` implements `Div>` + `u8` implements `Div` error[E0277]: cannot divide `f64` by `&str` --> $DIR/not-suggest-float-literal.rs:45:7 @@ -137,10 +137,10 @@ LL | x / "foo" | = help: the trait `Div<&str>` is not implemented for `f64` = help: the following other types implement trait `Div`: - <&'a f64 as Div> - <&f64 as Div<&f64>> - > - + `&'a f64` implements `Div` + `&f64` implements `Div<&f64>` + `f64` implements `Div<&f64>` + `f64` implements `Div` error[E0277]: cannot divide `f64` by `{integer}` --> $DIR/not-suggest-float-literal.rs:50:7 @@ -150,10 +150,10 @@ LL | x / y | = help: the trait `Div<{integer}>` is not implemented for `f64` = help: the following other types implement trait `Div`: - <&'a f64 as Div> - <&f64 as Div<&f64>> - > - + `&'a f64` implements `Div` + `&f64` implements `Div<&f64>` + `f64` implements `Div<&f64>` + `f64` implements `Div` error: aborting due to 12 previous errors diff --git a/tests/ui/numbers-arithmetic/suggest-float-literal.stderr b/tests/ui/numbers-arithmetic/suggest-float-literal.stderr index 03779d356371a..8585ac485dbb2 100644 --- a/tests/ui/numbers-arithmetic/suggest-float-literal.stderr +++ b/tests/ui/numbers-arithmetic/suggest-float-literal.stderr @@ -6,10 +6,10 @@ LL | x + 100 | = help: the trait `Add<{integer}>` is not implemented for `f32` = help: the following other types implement trait `Add`: - <&'a f32 as Add> - <&f32 as Add<&f32>> - > - + `&'a f32` implements `Add` + `&f32` implements `Add<&f32>` + `f32` implements `Add<&f32>` + `f32` implements `Add` help: consider using a floating-point literal by writing it with `.0` | LL | x + 100.0 @@ -23,10 +23,10 @@ LL | x + 100 | = help: the trait `Add<{integer}>` is not implemented for `f64` = help: the following other types implement trait `Add`: - <&'a f64 as Add> - <&f64 as Add<&f64>> - > - + `&'a f64` implements `Add` + `&f64` implements `Add<&f64>` + `f64` implements `Add<&f64>` + `f64` implements `Add` help: consider using a floating-point literal by writing it with `.0` | LL | x + 100.0 @@ -40,10 +40,10 @@ LL | x - 100 | = help: the trait `Sub<{integer}>` is not implemented for `f32` = help: the following other types implement trait `Sub`: - <&'a f32 as Sub> - <&f32 as Sub<&f32>> - > - + `&'a f32` implements `Sub` + `&f32` implements `Sub<&f32>` + `f32` implements `Sub<&f32>` + `f32` implements `Sub` help: consider using a floating-point literal by writing it with `.0` | LL | x - 100.0 @@ -57,10 +57,10 @@ LL | x - 100 | = help: the trait `Sub<{integer}>` is not implemented for `f64` = help: the following other types implement trait `Sub`: - <&'a f64 as Sub> - <&f64 as Sub<&f64>> - > - + `&'a f64` implements `Sub` + `&f64` implements `Sub<&f64>` + `f64` implements `Sub<&f64>` + `f64` implements `Sub` help: consider using a floating-point literal by writing it with `.0` | LL | x - 100.0 @@ -74,10 +74,10 @@ LL | x * 100 | = help: the trait `Mul<{integer}>` is not implemented for `f32` = help: the following other types implement trait `Mul`: - <&'a f32 as Mul> - <&f32 as Mul<&f32>> - > - + `&'a f32` implements `Mul` + `&f32` implements `Mul<&f32>` + `f32` implements `Mul<&f32>` + `f32` implements `Mul` help: consider using a floating-point literal by writing it with `.0` | LL | x * 100.0 @@ -91,10 +91,10 @@ LL | x * 100 | = help: the trait `Mul<{integer}>` is not implemented for `f64` = help: the following other types implement trait `Mul`: - <&'a f64 as Mul> - <&f64 as Mul<&f64>> - > - + `&'a f64` implements `Mul` + `&f64` implements `Mul<&f64>` + `f64` implements `Mul<&f64>` + `f64` implements `Mul` help: consider using a floating-point literal by writing it with `.0` | LL | x * 100.0 @@ -108,10 +108,10 @@ LL | x / 100 | = help: the trait `Div<{integer}>` is not implemented for `f32` = help: the following other types implement trait `Div`: - <&'a f32 as Div> - <&f32 as Div<&f32>> - > - + `&'a f32` implements `Div` + `&f32` implements `Div<&f32>` + `f32` implements `Div<&f32>` + `f32` implements `Div` help: consider using a floating-point literal by writing it with `.0` | LL | x / 100.0 @@ -125,10 +125,10 @@ LL | x / 100 | = help: the trait `Div<{integer}>` is not implemented for `f64` = help: the following other types implement trait `Div`: - <&'a f64 as Div> - <&f64 as Div<&f64>> - > - + `&'a f64` implements `Div` + `&f64` implements `Div<&f64>` + `f64` implements `Div<&f64>` + `f64` implements `Div` help: consider using a floating-point literal by writing it with `.0` | LL | x / 100.0 diff --git a/tests/ui/on-unimplemented/multiple-impls.stderr b/tests/ui/on-unimplemented/multiple-impls.stderr index b50dc251baaca..ba4e43ff3594f 100644 --- a/tests/ui/on-unimplemented/multiple-impls.stderr +++ b/tests/ui/on-unimplemented/multiple-impls.stderr @@ -8,8 +8,8 @@ LL | Index::index(&[] as &[i32], 2u32); | = help: the trait `Index` is not implemented for `[i32]` = help: the following other types implement trait `Index`: - <[i32] as Index>> - <[i32] as Index>> + `[i32]` implements `Index>` + `[i32]` implements `Index>` error[E0277]: the trait bound `[i32]: Index>` is not satisfied --> $DIR/multiple-impls.rs:36:33 @@ -21,8 +21,8 @@ LL | Index::index(&[] as &[i32], Foo(2u32)); | = help: the trait `Index>` is not implemented for `[i32]` = help: the following other types implement trait `Index`: - <[i32] as Index>> - <[i32] as Index>> + `[i32]` implements `Index>` + `[i32]` implements `Index>` error[E0277]: the trait bound `[i32]: Index>` is not satisfied --> $DIR/multiple-impls.rs:39:33 @@ -34,8 +34,8 @@ LL | Index::index(&[] as &[i32], Bar(2u32)); | = help: the trait `Index>` is not implemented for `[i32]` = help: the following other types implement trait `Index`: - <[i32] as Index>> - <[i32] as Index>> + `[i32]` implements `Index>` + `[i32]` implements `Index>` error[E0277]: the trait bound `[i32]: Index` is not satisfied --> $DIR/multiple-impls.rs:33:5 @@ -45,8 +45,8 @@ LL | Index::index(&[] as &[i32], 2u32); | = help: the trait `Index` is not implemented for `[i32]` = help: the following other types implement trait `Index`: - <[i32] as Index>> - <[i32] as Index>> + `[i32]` implements `Index>` + `[i32]` implements `Index>` error[E0277]: the trait bound `[i32]: Index>` is not satisfied --> $DIR/multiple-impls.rs:36:5 @@ -56,8 +56,8 @@ LL | Index::index(&[] as &[i32], Foo(2u32)); | = help: the trait `Index>` is not implemented for `[i32]` = help: the following other types implement trait `Index`: - <[i32] as Index>> - <[i32] as Index>> + `[i32]` implements `Index>` + `[i32]` implements `Index>` error[E0277]: the trait bound `[i32]: Index>` is not satisfied --> $DIR/multiple-impls.rs:39:5 @@ -67,8 +67,8 @@ LL | Index::index(&[] as &[i32], Bar(2u32)); | = help: the trait `Index>` is not implemented for `[i32]` = help: the following other types implement trait `Index`: - <[i32] as Index>> - <[i32] as Index>> + `[i32]` implements `Index>` + `[i32]` implements `Index>` error: aborting due to 6 previous errors diff --git a/tests/ui/on-unimplemented/slice-index.stderr b/tests/ui/on-unimplemented/slice-index.stderr index f17f3cfce8de6..0f8d105abef1b 100644 --- a/tests/ui/on-unimplemented/slice-index.stderr +++ b/tests/ui/on-unimplemented/slice-index.stderr @@ -17,8 +17,8 @@ LL | x[..1i32]; | = help: the trait `SliceIndex<[i32]>` is not implemented for `RangeTo`, which is required by `[i32]: Index<_>` = help: the following other types implement trait `SliceIndex`: - as SliceIndex<[T]>> - as SliceIndex> + `RangeTo` implements `SliceIndex<[T]>` + `RangeTo` implements `SliceIndex` = note: required for `[i32]` to implement `Index>` error: aborting due to 2 previous errors diff --git a/tests/ui/on-unimplemented/sum.stderr b/tests/ui/on-unimplemented/sum.stderr index 65bab458cf188..f8e266a872782 100644 --- a/tests/ui/on-unimplemented/sum.stderr +++ b/tests/ui/on-unimplemented/sum.stderr @@ -8,8 +8,8 @@ LL | vec![(), ()].iter().sum::(); | = help: the trait `Sum<&()>` is not implemented for `i32` = help: the following other types implement trait `Sum`: - > - + `i32` implements `Sum<&'a i32>` + `i32` implements `Sum` note: the method call chain might not have had the expected associated types --> $DIR/sum.rs:4:18 | @@ -30,8 +30,8 @@ LL | vec![(), ()].iter().product::(); | = help: the trait `Product<&()>` is not implemented for `i32` = help: the following other types implement trait `Product`: - > - + `i32` implements `Product<&'a i32>` + `i32` implements `Product` note: the method call chain might not have had the expected associated types --> $DIR/sum.rs:7:18 | diff --git a/tests/crashes/124004.rs b/tests/ui/pattern/box-pattern-type-mismatch.rs similarity index 74% rename from tests/crashes/124004.rs rename to tests/ui/pattern/box-pattern-type-mismatch.rs index 1fcf078594578..6c98050325638 100644 --- a/tests/crashes/124004.rs +++ b/tests/ui/pattern/box-pattern-type-mismatch.rs @@ -1,10 +1,11 @@ -//@ known-bug: #124004 +//! This test used to ICE #124004 #![feature(box_patterns)] use std::ops::{ Deref }; struct X(dyn Iterator); +//~^ ERROR: use of undeclared lifetime name `'a` impl Deref for X { type Target = isize; diff --git a/tests/ui/pattern/box-pattern-type-mismatch.stderr b/tests/ui/pattern/box-pattern-type-mismatch.stderr new file mode 100644 index 0000000000000..14f7dbbd839c0 --- /dev/null +++ b/tests/ui/pattern/box-pattern-type-mismatch.stderr @@ -0,0 +1,19 @@ +error[E0261]: use of undeclared lifetime name `'a` + --> $DIR/box-pattern-type-mismatch.rs:7:31 + | +LL | struct X(dyn Iterator); + | ^^ undeclared lifetime + | + = note: for more information on higher-ranked polymorphism, visit https://doc.rust-lang.org/nomicon/hrtb.html +help: consider making the bound lifetime-generic with a new `'a` lifetime + | +LL | struct X(dyn for<'a> Iterator); + | +++++++ +help: consider introducing lifetime `'a` here + | +LL | struct X<'a>(dyn Iterator); + | ++++ + +error: aborting due to 1 previous error + +For more information about this error, try `rustc --explain E0261`. diff --git a/tests/ui/pattern/missing_lifetime.rs b/tests/ui/pattern/missing_lifetime.rs new file mode 100644 index 0000000000000..081f667d8f6a9 --- /dev/null +++ b/tests/ui/pattern/missing_lifetime.rs @@ -0,0 +1,25 @@ +//! This test used to ICE: rust-lang/rust#125914 +//! Instead of actually analyzing the erroneous patterns, +//! we instead stop after typeck where errors are already +//! reported. + +enum AstKind<'ast> { + //~^ ERROR: `'ast` is never used + ExprInt, +} + +enum Foo { + Bar(isize), + Baz, +} + +enum Other { + Other1(Foo), + Other2(AstKind), //~ ERROR: missing lifetime specifier +} + +fn main() { + match Other::Other1(Foo::Baz) { + ::Other::Other2(::Foo::Bar(..)) => {} + } +} diff --git a/tests/ui/pattern/missing_lifetime.stderr b/tests/ui/pattern/missing_lifetime.stderr new file mode 100644 index 0000000000000..ec4063fd289ad --- /dev/null +++ b/tests/ui/pattern/missing_lifetime.stderr @@ -0,0 +1,25 @@ +error[E0106]: missing lifetime specifier + --> $DIR/missing_lifetime.rs:18:12 + | +LL | Other2(AstKind), + | ^^^^^^^ expected named lifetime parameter + | +help: consider introducing a named lifetime parameter + | +LL ~ enum Other<'a> { +LL | Other1(Foo), +LL ~ Other2(AstKind<'a>), + | + +error[E0392]: lifetime parameter `'ast` is never used + --> $DIR/missing_lifetime.rs:6:14 + | +LL | enum AstKind<'ast> { + | ^^^^ unused lifetime parameter + | + = help: consider removing `'ast`, referring to it in a field, or using a marker such as `PhantomData` + +error: aborting due to 2 previous errors + +Some errors have detailed explanations: E0106, E0392. +For more information about an error, try `rustc --explain E0106`. diff --git a/tests/ui/pattern/type_mismatch.rs b/tests/ui/pattern/type_mismatch.rs new file mode 100644 index 0000000000000..408ff75884712 --- /dev/null +++ b/tests/ui/pattern/type_mismatch.rs @@ -0,0 +1,30 @@ +//! This test used to ICE: rust-lang/rust#109812 +//! Instead of actually analyzing the erroneous patterns, +//! we instead stop after typeck where errors are already +//! reported. + +#![warn(rust_2021_incompatible_closure_captures)] + +enum Either { + One(X), + Two(X), +} + +struct X(Y); + +struct Y; + +fn consume_fnmut(_: impl FnMut()) {} + +fn move_into_fnmut() { + let x = X(Y); + + consume_fnmut(|| { + let Either::Two(ref mut _t) = x; + //~^ ERROR: mismatched types + + let X(mut _t) = x; + }); +} + +fn main() {} diff --git a/tests/ui/pattern/type_mismatch.stderr b/tests/ui/pattern/type_mismatch.stderr new file mode 100644 index 0000000000000..b0441b1fadcfe --- /dev/null +++ b/tests/ui/pattern/type_mismatch.stderr @@ -0,0 +1,11 @@ +error[E0308]: mismatched types + --> $DIR/type_mismatch.rs:23:13 + | +LL | let Either::Two(ref mut _t) = x; + | ^^^^^^^^^^^^^^^^^^^^^^^ - this expression has type `X` + | | + | expected `X`, found `Either` + +error: aborting due to 1 previous error + +For more information about this error, try `rustc --explain E0308`. diff --git a/tests/ui/proc-macro/auxiliary/api/literal.rs b/tests/ui/proc-macro/auxiliary/api/literal.rs new file mode 100644 index 0000000000000..7109340bb645b --- /dev/null +++ b/tests/ui/proc-macro/auxiliary/api/literal.rs @@ -0,0 +1,83 @@ +// ignore-tidy-linelength + +use proc_macro::Literal; + +pub fn test() { + test_display_literal(); + test_parse_literal(); +} + +fn test_display_literal() { + assert_eq!(Literal::isize_unsuffixed(-10).to_string(), "-10"); + assert_eq!(Literal::isize_suffixed(-10).to_string(), "-10isize"); + assert_eq!(Literal::f32_unsuffixed(-10.0).to_string(), "-10.0"); + assert_eq!(Literal::f32_suffixed(-10.0).to_string(), "-10f32"); + assert_eq!(Literal::f64_unsuffixed(-10.0).to_string(), "-10.0"); + assert_eq!(Literal::f64_suffixed(-10.0).to_string(), "-10f64"); + assert_eq!( + Literal::f64_unsuffixed(1e100).to_string(), + "10000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000.0", + ); + + assert_eq!(Literal::string("aA").to_string(), r#" "aA" "#.trim()); + assert_eq!(Literal::string("\t").to_string(), r#" "\t" "#.trim()); + assert_eq!(Literal::string("❤").to_string(), r#" "❤" "#.trim()); + assert_eq!(Literal::string("'").to_string(), r#" "'" "#.trim()); + assert_eq!(Literal::string("\"").to_string(), r#" "\"" "#.trim()); + assert_eq!(Literal::string("\0").to_string(), r#" "\0" "#.trim()); + assert_eq!(Literal::string("\u{1}").to_string(), r#" "\u{1}" "#.trim()); + + assert_eq!(Literal::byte_string(b"aA").to_string(), r#" b"aA" "#.trim()); + assert_eq!(Literal::byte_string(b"\t").to_string(), r#" b"\t" "#.trim()); + assert_eq!(Literal::byte_string(b"'").to_string(), r#" b"'" "#.trim()); + assert_eq!(Literal::byte_string(b"\"").to_string(), r#" b"\"" "#.trim()); + assert_eq!(Literal::byte_string(b"\0").to_string(), r#" b"\0" "#.trim()); + assert_eq!(Literal::byte_string(b"\x01").to_string(), r#" b"\x01" "#.trim()); + + assert_eq!(Literal::c_string(c"aA").to_string(), r#" c"aA" "#.trim()); + assert_eq!(Literal::c_string(c"\t").to_string(), r#" c"\t" "#.trim()); + assert_eq!(Literal::c_string(c"❤").to_string(), r#" c"❤" "#.trim()); + assert_eq!(Literal::c_string(c"\'").to_string(), r#" c"'" "#.trim()); + assert_eq!(Literal::c_string(c"\"").to_string(), r#" c"\"" "#.trim()); + assert_eq!(Literal::c_string(c"\x7f\xff\xfe\u{333}").to_string(), r#" c"\u{7f}\xff\xfe\u{333}" "#.trim()); + + assert_eq!(Literal::character('a').to_string(), r#" 'a' "#.trim()); + assert_eq!(Literal::character('\t').to_string(), r#" '\t' "#.trim()); + assert_eq!(Literal::character('❤').to_string(), r#" '❤' "#.trim()); + assert_eq!(Literal::character('\'').to_string(), r#" '\'' "#.trim()); + assert_eq!(Literal::character('"').to_string(), r#" '"' "#.trim()); + assert_eq!(Literal::character('\0').to_string(), r#" '\0' "#.trim()); + assert_eq!(Literal::character('\u{1}').to_string(), r#" '\u{1}' "#.trim()); + + assert_eq!(Literal::byte_character(b'a').to_string(), r#" b'a' "#.trim()); + assert_eq!(Literal::byte_character(b'\t').to_string(), r#" b'\t' "#.trim()); + assert_eq!(Literal::byte_character(b'\'').to_string(), r#" b'\'' "#.trim()); + assert_eq!(Literal::byte_character(b'"').to_string(), r#" b'"' "#.trim()); + assert_eq!(Literal::byte_character(0).to_string(), r#" b'\0' "#.trim()); + assert_eq!(Literal::byte_character(1).to_string(), r#" b'\x01' "#.trim()); +} + +fn test_parse_literal() { + assert_eq!("1".parse::().unwrap().to_string(), "1"); + assert_eq!("1.0".parse::().unwrap().to_string(), "1.0"); + assert_eq!("'a'".parse::().unwrap().to_string(), "'a'"); + assert_eq!("b'a'".parse::().unwrap().to_string(), "b'a'"); + assert_eq!("\"\n\"".parse::().unwrap().to_string(), "\"\n\""); + assert_eq!("b\"\"".parse::().unwrap().to_string(), "b\"\""); + assert_eq!("c\"\"".parse::().unwrap().to_string(), "c\"\""); + assert_eq!("r##\"\"##".parse::().unwrap().to_string(), "r##\"\"##"); + assert_eq!("10ulong".parse::().unwrap().to_string(), "10ulong"); + assert_eq!("-10ulong".parse::().unwrap().to_string(), "-10ulong"); + + assert!("true".parse::().is_err()); + assert!(".8".parse::().is_err()); + assert!("0 1".parse::().is_err()); + assert!("'a".parse::().is_err()); + assert!(" 0".parse::().is_err()); + assert!("0 ".parse::().is_err()); + assert!("/* comment */0".parse::().is_err()); + assert!("0/* comment */".parse::().is_err()); + assert!("0// comment".parse::().is_err()); + assert!("- 10".parse::().is_err()); + assert!("-'x'".parse::().is_err()); +} diff --git a/tests/ui/proc-macro/auxiliary/api/mod.rs b/tests/ui/proc-macro/auxiliary/api/mod.rs index 45ef6922d2834..e0a381cb6c1a7 100644 --- a/tests/ui/proc-macro/auxiliary/api/mod.rs +++ b/tests/ui/proc-macro/auxiliary/api/mod.rs @@ -10,7 +10,7 @@ extern crate proc_macro; mod cmp; -mod parse; +mod literal; use proc_macro::TokenStream; @@ -19,7 +19,7 @@ pub fn run(input: TokenStream) -> TokenStream { assert!(input.is_empty()); cmp::test(); - parse::test(); + literal::test(); TokenStream::new() } diff --git a/tests/ui/proc-macro/auxiliary/api/parse.rs b/tests/ui/proc-macro/auxiliary/api/parse.rs deleted file mode 100644 index 801c616c80404..0000000000000 --- a/tests/ui/proc-macro/auxiliary/api/parse.rs +++ /dev/null @@ -1,58 +0,0 @@ -// ignore-tidy-linelength - -use proc_macro::Literal; - -pub fn test() { - test_display_literal(); - test_parse_literal(); -} - -fn test_display_literal() { - assert_eq!(Literal::isize_unsuffixed(-10).to_string(), "-10"); - assert_eq!(Literal::isize_suffixed(-10).to_string(), "-10isize"); - assert_eq!(Literal::f32_unsuffixed(-10.0).to_string(), "-10.0"); - assert_eq!(Literal::f32_suffixed(-10.0).to_string(), "-10f32"); - assert_eq!(Literal::f64_unsuffixed(-10.0).to_string(), "-10.0"); - assert_eq!(Literal::f64_suffixed(-10.0).to_string(), "-10f64"); - assert_eq!( - Literal::f64_unsuffixed(1e100).to_string(), - "10000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000.0", - ); - - assert_eq!(Literal::string("a \t ❤ ' \" \u{1}").to_string(), "\"a \\t ❤ ' \\\" \\u{1}\"",); - assert_eq!(Literal::c_string(c"\'\"\x7f\u{7fff}").to_string(), r#"c"\'\"\x7f\xe7\xbf\xbf""#); - assert_eq!(Literal::character('a').to_string(), "'a'"); - assert_eq!(Literal::character('\t').to_string(), "'\\t'"); - assert_eq!(Literal::character('❤').to_string(), "'❤'"); - assert_eq!(Literal::character('\'').to_string(), "'\\''"); - assert_eq!(Literal::character('"').to_string(), "'\"'"); - assert_eq!(Literal::character('\u{1}').to_string(), "'\\u{1}'"); - - assert_eq!(Literal::byte_character(b'a').to_string(), "b'a'"); - assert_eq!(Literal::byte_character(0).to_string(), "b'\\x00'"); -} - -fn test_parse_literal() { - assert_eq!("1".parse::().unwrap().to_string(), "1"); - assert_eq!("1.0".parse::().unwrap().to_string(), "1.0"); - assert_eq!("'a'".parse::().unwrap().to_string(), "'a'"); - assert_eq!("b'a'".parse::().unwrap().to_string(), "b'a'"); - assert_eq!("\"\n\"".parse::().unwrap().to_string(), "\"\n\""); - assert_eq!("b\"\"".parse::().unwrap().to_string(), "b\"\""); - assert_eq!("c\"\"".parse::().unwrap().to_string(), "c\"\""); - assert_eq!("r##\"\"##".parse::().unwrap().to_string(), "r##\"\"##"); - assert_eq!("10ulong".parse::().unwrap().to_string(), "10ulong"); - assert_eq!("-10ulong".parse::().unwrap().to_string(), "-10ulong"); - - assert!("true".parse::().is_err()); - assert!(".8".parse::().is_err()); - assert!("0 1".parse::().is_err()); - assert!("'a".parse::().is_err()); - assert!(" 0".parse::().is_err()); - assert!("0 ".parse::().is_err()); - assert!("/* comment */0".parse::().is_err()); - assert!("0/* comment */".parse::().is_err()); - assert!("0// comment".parse::().is_err()); - assert!("- 10".parse::().is_err()); - assert!("-'x'".parse::().is_err()); -} diff --git a/tests/ui/resolve/issue-16058.stderr b/tests/ui/resolve/issue-16058.stderr index 914990c35ff76..12b1ac8a5fb44 100644 --- a/tests/ui/resolve/issue-16058.stderr +++ b/tests/ui/resolve/issue-16058.stderr @@ -4,7 +4,7 @@ error[E0574]: expected struct, variant or union type, found enum `Result` LL | Result { | ^^^^^^ not a struct, variant or union type | -help: consider importing one of these items instead +help: consider importing one of these type aliases instead | LL + use std::fmt::Result; | diff --git a/tests/ui/resolve/issue-21221-1.stderr b/tests/ui/resolve/issue-21221-1.stderr index a38116cd7287a..ccf03afaa19fe 100644 --- a/tests/ui/resolve/issue-21221-1.stderr +++ b/tests/ui/resolve/issue-21221-1.stderr @@ -4,14 +4,14 @@ error[E0405]: cannot find trait `Mul` in this scope LL | impl Mul for Foo { | ^^^ not found in this scope | -help: consider importing one of these items +help: consider importing one of these traits + | +LL + use std::ops::Mul; | LL + use mul1::Mul; | LL + use mul2::Mul; | -LL + use std::ops::Mul; - | error[E0412]: cannot find type `Mul` in this scope --> $DIR/issue-21221-1.rs:58:16 @@ -19,14 +19,14 @@ error[E0412]: cannot find type `Mul` in this scope LL | fn getMul() -> Mul { | ^^^ not found in this scope | -help: consider importing one of these items +help: consider importing one of these traits + | +LL + use std::ops::Mul; | LL + use mul1::Mul; | LL + use mul2::Mul; | -LL + use std::ops::Mul; - | error[E0405]: cannot find trait `ThisTraitReallyDoesntExistInAnyModuleReally` in this scope --> $DIR/issue-21221-1.rs:63:6 diff --git a/tests/ui/resolve/issue-21221-2.stderr b/tests/ui/resolve/issue-21221-2.stderr index 3bd4c1a5d1315..5db327955eb10 100644 --- a/tests/ui/resolve/issue-21221-2.stderr +++ b/tests/ui/resolve/issue-21221-2.stderr @@ -4,7 +4,7 @@ error[E0405]: cannot find trait `T` in this scope LL | impl T for Foo { } | ^ not found in this scope | -help: consider importing one of these items +help: consider importing one of these traits | LL + use baz::T; | diff --git a/tests/ui/resolve/issue-50599.stderr b/tests/ui/resolve/issue-50599.stderr index e5eacd741fbe2..24fb3d580b8fa 100644 --- a/tests/ui/resolve/issue-50599.stderr +++ b/tests/ui/resolve/issue-50599.stderr @@ -4,7 +4,7 @@ error[E0425]: cannot find value `LOG10_2` in module `std::f64` LL | const M: usize = (f64::from(N) * std::f64::LOG10_2) as usize; | ^^^^^^^ not found in `std::f64` | -help: consider importing one of these items +help: consider importing one of these constants | LL + use std::f128::consts::LOG10_2; | diff --git a/tests/ui/resolve/issue-73427.stderr b/tests/ui/resolve/issue-73427.stderr index c5e245d884b7b..0a9a504f79caa 100644 --- a/tests/ui/resolve/issue-73427.stderr +++ b/tests/ui/resolve/issue-73427.stderr @@ -105,7 +105,7 @@ help: the following enum variant is available | LL | (E::TupleWithFields(/* fields */)).foo(); | ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ -help: consider importing one of these items instead +help: consider importing one of these constants instead | LL + use std::f128::consts::E; | diff --git a/tests/ui/resolve/privacy-enum-ctor.stderr b/tests/ui/resolve/privacy-enum-ctor.stderr index 01c8a38d2a48a..ee3aecddcc342 100644 --- a/tests/ui/resolve/privacy-enum-ctor.stderr +++ b/tests/ui/resolve/privacy-enum-ctor.stderr @@ -82,7 +82,7 @@ help: a function with a similar name exists | LL | let _: E = m::f; | ~ -help: consider importing one of these items instead +help: consider importing one of these constants instead | LL + use std::f128::consts::E; | @@ -123,7 +123,7 @@ help: alternatively, the following enum variant is available | LL | let _: E = (E::Fn(/* fields */)); | ~~~~~~~~~~~~~~~~~~~~~ -help: consider importing one of these items instead +help: consider importing one of these constants instead | LL + use std::f128::consts::E; | diff --git a/tests/ui/rfcs/rfc-2126-extern-absolute-paths/not-allowed.stderr b/tests/ui/rfcs/rfc-2126-extern-absolute-paths/not-allowed.stderr index 7f989c15f1c05..d0c084f7bd5d0 100644 --- a/tests/ui/rfcs/rfc-2126-extern-absolute-paths/not-allowed.stderr +++ b/tests/ui/rfcs/rfc-2126-extern-absolute-paths/not-allowed.stderr @@ -4,10 +4,8 @@ error[E0432]: unresolved import `alloc` LL | use alloc; | ^^^^^ no external crate `alloc` | -help: consider importing one of these items instead +help: consider importing this module instead | -LL | use core::alloc; - | ~~~~~~~~~~~ LL | use std::alloc; | ~~~~~~~~~~ diff --git a/tests/ui/rust-2018/issue-52202-use-suggestions.stderr b/tests/ui/rust-2018/issue-52202-use-suggestions.stderr index 49736205f204b..ee1a336ea98f6 100644 --- a/tests/ui/rust-2018/issue-52202-use-suggestions.stderr +++ b/tests/ui/rust-2018/issue-52202-use-suggestions.stderr @@ -4,7 +4,7 @@ error[E0422]: cannot find struct, variant or union type `Drain` in this scope LL | let _d = Drain {}; | ^^^^^ not found in this scope | -help: consider importing one of these items +help: consider importing one of these structs | LL + use crate::plumbing::Drain; | diff --git a/tests/ui/span/multiline-span-simple.stderr b/tests/ui/span/multiline-span-simple.stderr index 2de792b03d722..2454769863b9c 100644 --- a/tests/ui/span/multiline-span-simple.stderr +++ b/tests/ui/span/multiline-span-simple.stderr @@ -6,10 +6,10 @@ LL | foo(1 as u32 + | = help: the trait `Add<()>` is not implemented for `u32` = help: the following other types implement trait `Add`: - <&'a u32 as Add> - <&u32 as Add<&u32>> - > - + `&'a u32` implements `Add` + `&u32` implements `Add<&u32>` + `u32` implements `Add<&u32>` + `u32` implements `Add` error: aborting due to 1 previous error diff --git a/tests/ui/suggestions/core-std-import-order-issue-83564.no_std.fixed b/tests/ui/suggestions/core-std-import-order-issue-83564.no_std.fixed new file mode 100644 index 0000000000000..02d667d984421 --- /dev/null +++ b/tests/ui/suggestions/core-std-import-order-issue-83564.no_std.fixed @@ -0,0 +1,22 @@ +//@ edition:2018 +// +// This is a regression test for #83564. +// For some reason, Rust 2018 or higher is required to reproduce the bug. +//@ run-rustfix +//@ revisions: no_std std +//@ [no_std]compile-flags: --cfg=no_std -C panic=abort +#![cfg_attr(no_std, no_std)] + +use core::num::NonZero; + +fn main() { + //~^ HELP consider importing this struct + let _x = NonZero::new(5u32).unwrap(); + //~^ ERROR failed to resolve: use of undeclared type `NonZero` +} + +#[allow(dead_code)] +#[cfg_attr(no_std, panic_handler)] +fn panic(_info: &core::panic::PanicInfo) -> ! { + loop {} +} diff --git a/tests/ui/suggestions/core-std-import-order-issue-83564.stderr b/tests/ui/suggestions/core-std-import-order-issue-83564.no_std.stderr similarity index 71% rename from tests/ui/suggestions/core-std-import-order-issue-83564.stderr rename to tests/ui/suggestions/core-std-import-order-issue-83564.no_std.stderr index 8665cc6d87cf5..d73f613bf9c8a 100644 --- a/tests/ui/suggestions/core-std-import-order-issue-83564.stderr +++ b/tests/ui/suggestions/core-std-import-order-issue-83564.no_std.stderr @@ -1,15 +1,13 @@ error[E0433]: failed to resolve: use of undeclared type `NonZero` - --> $DIR/core-std-import-order-issue-83564.rs:8:14 + --> $DIR/core-std-import-order-issue-83564.rs:12:14 | LL | let _x = NonZero::new(5u32).unwrap(); | ^^^^^^^ use of undeclared type `NonZero` | -help: consider importing one of these items +help: consider importing this struct | LL + use core::num::NonZero; | -LL + use std::num::NonZero; - | error: aborting due to 1 previous error diff --git a/tests/ui/suggestions/core-std-import-order-issue-83564.rs b/tests/ui/suggestions/core-std-import-order-issue-83564.rs index 6f2bdd7a38af5..5bb5bfe176ba8 100644 --- a/tests/ui/suggestions/core-std-import-order-issue-83564.rs +++ b/tests/ui/suggestions/core-std-import-order-issue-83564.rs @@ -2,9 +2,19 @@ // // This is a regression test for #83564. // For some reason, Rust 2018 or higher is required to reproduce the bug. +//@ run-rustfix +//@ revisions: no_std std +//@ [no_std]compile-flags: --cfg=no_std -C panic=abort +#![cfg_attr(no_std, no_std)] fn main() { - //~^ HELP consider importing one of these items + //~^ HELP consider importing this struct let _x = NonZero::new(5u32).unwrap(); //~^ ERROR failed to resolve: use of undeclared type `NonZero` } + +#[allow(dead_code)] +#[cfg_attr(no_std, panic_handler)] +fn panic(_info: &core::panic::PanicInfo) -> ! { + loop {} +} diff --git a/tests/ui/suggestions/core-std-import-order-issue-83564.std.fixed b/tests/ui/suggestions/core-std-import-order-issue-83564.std.fixed new file mode 100644 index 0000000000000..3492b42c685f9 --- /dev/null +++ b/tests/ui/suggestions/core-std-import-order-issue-83564.std.fixed @@ -0,0 +1,22 @@ +//@ edition:2018 +// +// This is a regression test for #83564. +// For some reason, Rust 2018 or higher is required to reproduce the bug. +//@ run-rustfix +//@ revisions: no_std std +//@ [no_std]compile-flags: --cfg=no_std -C panic=abort +#![cfg_attr(no_std, no_std)] + +use std::num::NonZero; + +fn main() { + //~^ HELP consider importing this struct + let _x = NonZero::new(5u32).unwrap(); + //~^ ERROR failed to resolve: use of undeclared type `NonZero` +} + +#[allow(dead_code)] +#[cfg_attr(no_std, panic_handler)] +fn panic(_info: &core::panic::PanicInfo) -> ! { + loop {} +} diff --git a/tests/ui/suggestions/core-std-import-order-issue-83564.std.stderr b/tests/ui/suggestions/core-std-import-order-issue-83564.std.stderr new file mode 100644 index 0000000000000..ebfe197b45d69 --- /dev/null +++ b/tests/ui/suggestions/core-std-import-order-issue-83564.std.stderr @@ -0,0 +1,14 @@ +error[E0433]: failed to resolve: use of undeclared type `NonZero` + --> $DIR/core-std-import-order-issue-83564.rs:12:14 + | +LL | let _x = NonZero::new(5u32).unwrap(); + | ^^^^^^^ use of undeclared type `NonZero` + | +help: consider importing this struct + | +LL + use std::num::NonZero; + | + +error: aborting due to 1 previous error + +For more information about this error, try `rustc --explain E0433`. diff --git a/tests/ui/suggestions/crate-or-module-typo.stderr b/tests/ui/suggestions/crate-or-module-typo.stderr index 457d779064682..084d0408a8e7d 100644 --- a/tests/ui/suggestions/crate-or-module-typo.stderr +++ b/tests/ui/suggestions/crate-or-module-typo.stderr @@ -30,9 +30,7 @@ help: there is a crate or module with a similar name | LL | bar: std::cell::Cell | ~~~ -help: consider importing one of these items - | -LL + use core::cell; +help: consider importing this module | LL + use std::cell; | diff --git a/tests/ui/suggestions/into-str.stderr b/tests/ui/suggestions/into-str.stderr index 2fdfab8bdc544..6c1e1ec428fe7 100644 --- a/tests/ui/suggestions/into-str.stderr +++ b/tests/ui/suggestions/into-str.stderr @@ -8,12 +8,12 @@ LL | foo(String::new()); | = note: to coerce a `String` into a `&str`, use `&*` as a prefix = help: the following other types implement trait `From`: - > - > - > - >> - >> - > + `String` implements `From<&String>` + `String` implements `From<&mut str>` + `String` implements `From<&str>` + `String` implements `From>` + `String` implements `From>` + `String` implements `From` = note: required for `String` to implement `Into<&str>` note: required by a bound in `foo` --> $DIR/into-str.rs:1:31 diff --git a/tests/ui/suggestions/issue-71394-no-from-impl.stderr b/tests/ui/suggestions/issue-71394-no-from-impl.stderr index e626b5b0eb7cd..79f5dcf4b7305 100644 --- a/tests/ui/suggestions/issue-71394-no-from-impl.stderr +++ b/tests/ui/suggestions/issue-71394-no-from-impl.stderr @@ -5,14 +5,14 @@ LL | let _: &[i8] = data.into(); | ^^^^ the trait `From<&[u8]>` is not implemented for `&[i8]`, which is required by `&[u8]: Into<_>` | = help: the following other types implement trait `From`: - <[T; 10] as From<(T, T, T, T, T, T, T, T, T, T)>> - <[T; 11] as From<(T, T, T, T, T, T, T, T, T, T, T)>> - <[T; 12] as From<(T, T, T, T, T, T, T, T, T, T, T, T)>> - <[T; 1] as From<(T,)>> - <[T; 2] as From<(T, T)>> - <[T; 3] as From<(T, T, T)>> - <[T; 4] as From<(T, T, T, T)>> - <[T; 5] as From<(T, T, T, T, T)>> + `[T; 10]` implements `From<(T, T, T, T, T, T, T, T, T, T)>` + `[T; 11]` implements `From<(T, T, T, T, T, T, T, T, T, T, T)>` + `[T; 12]` implements `From<(T, T, T, T, T, T, T, T, T, T, T, T)>` + `[T; 1]` implements `From<(T,)>` + `[T; 2]` implements `From<(T, T)>` + `[T; 3]` implements `From<(T, T, T)>` + `[T; 4]` implements `From<(T, T, T, T)>` + `[T; 5]` implements `From<(T, T, T, T, T)>` and 6 others = note: required for `&[u8]` to implement `Into<&[i8]>` diff --git a/tests/ui/suggestions/suggest-remove-refs-5.stderr b/tests/ui/suggestions/suggest-remove-refs-5.stderr index 3b6994b45d109..b132c56473eed 100644 --- a/tests/ui/suggestions/suggest-remove-refs-5.stderr +++ b/tests/ui/suggestions/suggest-remove-refs-5.stderr @@ -4,7 +4,7 @@ error[E0277]: `&mut &mut &mut &mut Vec` is not an iterator LL | for _ in &mut &mut v {} | ^^^^^^^^^^^ `&mut &mut &mut &mut Vec` is not an iterator | - = help: the trait `Iterator` is not implemented for `&mut &mut &mut &mut Vec`, which is required by `&mut &mut &mut &mut Vec: IntoIterator` + = help: the trait `Iterator` is not implemented for `Vec`, which is required by `&mut &mut &mut &mut Vec: IntoIterator` = note: required for `&mut Vec` to implement `Iterator` = note: 3 redundant requirements hidden = note: required for `&mut &mut &mut &mut Vec` to implement `Iterator` @@ -21,7 +21,7 @@ error[E0277]: `&mut &mut &mut [u8; 1]` is not an iterator LL | for _ in &mut v {} | ^^^^^^ `&mut &mut &mut [u8; 1]` is not an iterator | - = help: the trait `Iterator` is not implemented for `&mut &mut &mut [u8; 1]`, which is required by `&mut &mut &mut [u8; 1]: IntoIterator` + = help: the trait `Iterator` is not implemented for `[u8; 1]`, which is required by `&mut &mut &mut [u8; 1]: IntoIterator` = note: required for `&mut [u8; 1]` to implement `Iterator` = note: 2 redundant requirements hidden = note: required for `&mut &mut &mut [u8; 1]` to implement `Iterator` diff --git a/tests/ui/suggestions/suggest-tryinto-edition-change.rs b/tests/ui/suggestions/suggest-tryinto-edition-change.rs index 3732177487450..f45670ae7c1e2 100644 --- a/tests/ui/suggestions/suggest-tryinto-edition-change.rs +++ b/tests/ui/suggestions/suggest-tryinto-edition-change.rs @@ -1,5 +1,5 @@ // Make sure that trying to access `TryInto`, `TryFrom`, `FromIterator` in pre-2021 mentions -// Edition 2021 change +// Edition 2021 change. //@ edition:2018 fn test() { @@ -11,19 +11,16 @@ fn test() { //~^ ERROR failed to resolve: use of undeclared type //~| NOTE use of undeclared type //~| NOTE 'std::convert::TryFrom' is included in the prelude starting in Edition 2021 - //~| NOTE 'core::convert::TryFrom' is included in the prelude starting in Edition 2021 let _i: i16 = TryInto::try_into(0_i32).unwrap(); //~^ ERROR failed to resolve: use of undeclared type //~| NOTE use of undeclared type //~| NOTE 'std::convert::TryInto' is included in the prelude starting in Edition 2021 - //~| NOTE 'core::convert::TryInto' is included in the prelude starting in Edition 2021 let _v: Vec<_> = FromIterator::from_iter(&[1]); //~^ ERROR failed to resolve: use of undeclared type //~| NOTE use of undeclared type //~| NOTE 'std::iter::FromIterator' is included in the prelude starting in Edition 2021 - //~| NOTE 'core::iter::FromIterator' is included in the prelude starting in Edition 2021 } fn main() { diff --git a/tests/ui/suggestions/suggest-tryinto-edition-change.stderr b/tests/ui/suggestions/suggest-tryinto-edition-change.stderr index db7c40101cdc2..5be55f75cd15d 100644 --- a/tests/ui/suggestions/suggest-tryinto-edition-change.stderr +++ b/tests/ui/suggestions/suggest-tryinto-edition-change.stderr @@ -4,45 +4,36 @@ error[E0433]: failed to resolve: use of undeclared type `TryFrom` LL | let _i: i16 = TryFrom::try_from(0_i32).unwrap(); | ^^^^^^^ use of undeclared type `TryFrom` | - = note: 'core::convert::TryFrom' is included in the prelude starting in Edition 2021 = note: 'std::convert::TryFrom' is included in the prelude starting in Edition 2021 -help: consider importing one of these items - | -LL + use core::convert::TryFrom; +help: consider importing this trait | LL + use std::convert::TryFrom; | error[E0433]: failed to resolve: use of undeclared type `TryInto` - --> $DIR/suggest-tryinto-edition-change.rs:16:19 + --> $DIR/suggest-tryinto-edition-change.rs:15:19 | LL | let _i: i16 = TryInto::try_into(0_i32).unwrap(); | ^^^^^^^ use of undeclared type `TryInto` | - = note: 'core::convert::TryInto' is included in the prelude starting in Edition 2021 = note: 'std::convert::TryInto' is included in the prelude starting in Edition 2021 -help: consider importing one of these items - | -LL + use core::convert::TryInto; +help: consider importing this trait | LL + use std::convert::TryInto; | error[E0433]: failed to resolve: use of undeclared type `FromIterator` - --> $DIR/suggest-tryinto-edition-change.rs:22:22 + --> $DIR/suggest-tryinto-edition-change.rs:20:22 | LL | let _v: Vec<_> = FromIterator::from_iter(&[1]); | ^^^^^^^^^^^^ use of undeclared type `FromIterator` | - = note: 'core::iter::FromIterator' is included in the prelude starting in Edition 2021 = note: 'std::iter::FromIterator' is included in the prelude starting in Edition 2021 help: a trait with a similar name exists | LL | let _v: Vec<_> = IntoIterator::from_iter(&[1]); | ~~~~~~~~~~~~ -help: consider importing one of these items - | -LL + use core::iter::FromIterator; +help: consider importing this trait | LL + use std::iter::FromIterator; | diff --git a/tests/ui/traits/inheritance/repeated-supertrait-ambig.stderr b/tests/ui/traits/inheritance/repeated-supertrait-ambig.stderr index 7027fa69e033e..6f7c9fa11d4b3 100644 --- a/tests/ui/traits/inheritance/repeated-supertrait-ambig.stderr +++ b/tests/ui/traits/inheritance/repeated-supertrait-ambig.stderr @@ -7,8 +7,8 @@ LL | c.same_as(22) | required by a bound introduced by this call | = help: the following other types implement trait `CompareTo`: - > - > + `i64` implements `CompareTo` + `i64` implements `CompareTo` error[E0277]: the trait bound `C: CompareTo` is not satisfied --> $DIR/repeated-supertrait-ambig.rs:30:15 @@ -30,8 +30,8 @@ LL | ::same_as(c, 22) | ^^^^^^^^^^^^^^^^^ the trait `CompareTo` is not implemented for `dyn CompareToInts` | = help: the following other types implement trait `CompareTo`: - > - > + `i64` implements `CompareTo` + `i64` implements `CompareTo` error[E0277]: the trait bound `C: CompareTo` is not satisfied --> $DIR/repeated-supertrait-ambig.rs:38:27 @@ -55,8 +55,8 @@ LL | assert_eq!(22_i64.same_as(22), true); | required by a bound introduced by this call | = help: the following other types implement trait `CompareTo`: - > - > + `i64` implements `CompareTo` + `i64` implements `CompareTo` error: aborting due to 5 previous errors diff --git a/tests/ui/traits/negative-bounds/opaque-type-unsatisfied-bound.rs b/tests/ui/traits/negative-bounds/opaque-type-unsatisfied-bound.rs index 2607f047024dd..35757f2339dbf 100644 --- a/tests/ui/traits/negative-bounds/opaque-type-unsatisfied-bound.rs +++ b/tests/ui/traits/negative-bounds/opaque-type-unsatisfied-bound.rs @@ -18,3 +18,4 @@ fn weird1() -> impl !Sized + Sized {} //~^ ERROR type mismatch resolving `impl !Sized + Sized == ()` fn weird2() -> impl !Sized {} //~^ ERROR type mismatch resolving `impl !Sized == ()` +//~| ERROR the size for values of type `impl !Sized` cannot be known at compilation time diff --git a/tests/ui/traits/negative-bounds/opaque-type-unsatisfied-bound.stderr b/tests/ui/traits/negative-bounds/opaque-type-unsatisfied-bound.stderr index ceaf42431fec2..3dd2b27b55b67 100644 --- a/tests/ui/traits/negative-bounds/opaque-type-unsatisfied-bound.stderr +++ b/tests/ui/traits/negative-bounds/opaque-type-unsatisfied-bound.stderr @@ -16,6 +16,15 @@ error[E0271]: type mismatch resolving `impl !Sized == ()` LL | fn weird2() -> impl !Sized {} | ^^^^^^^^^^^ types differ +error[E0277]: the size for values of type `impl !Sized` cannot be known at compilation time + --> $DIR/opaque-type-unsatisfied-bound.rs:19:16 + | +LL | fn weird2() -> impl !Sized {} + | ^^^^^^^^^^^ doesn't have a size known at compile-time + | + = help: the trait `Sized` is not implemented for `impl !Sized` + = note: the return type of a function must have a statically known size + error[E0277]: the trait bound `impl !Trait: Trait` is not satisfied --> $DIR/opaque-type-unsatisfied-bound.rs:12:13 | @@ -30,7 +39,7 @@ note: required by a bound in `consume` LL | fn consume(_: impl Trait) {} | ^^^^^ required by this bound in `consume` -error: aborting due to 4 previous errors +error: aborting due to 5 previous errors Some errors have detailed explanations: E0271, E0277. For more information about an error, try `rustc --explain E0271`. diff --git a/tests/ui/traits/next-solver/auto-with-drop_tracking_mir.fail.stderr b/tests/ui/traits/next-solver/auto-with-drop_tracking_mir.fail.stderr index 562d7ccf9fec0..e0b23bd8110a3 100644 --- a/tests/ui/traits/next-solver/auto-with-drop_tracking_mir.fail.stderr +++ b/tests/ui/traits/next-solver/auto-with-drop_tracking_mir.fail.stderr @@ -4,7 +4,7 @@ error: future cannot be sent between threads safely LL | is_send(foo()); | ^^^^^ future returned by `foo` is not `Send` | - = help: the trait `Sync` is not implemented for `impl Future`, which is required by `impl Future: Send` + = help: the trait `Sync` is not implemented for `NotSync`, which is required by `impl Future: Send` note: future is not `Send` as this value is used across an await --> $DIR/auto-with-drop_tracking_mir.rs:16:11 | diff --git a/tests/ui/traits/next-solver/canonical/const-region-infer-to-static-in-binder.stderr b/tests/ui/traits/next-solver/canonical/const-region-infer-to-static-in-binder.stderr index 9dde1963bd49d..e0cbee88aa100 100644 --- a/tests/ui/traits/next-solver/canonical/const-region-infer-to-static-in-binder.stderr +++ b/tests/ui/traits/next-solver/canonical/const-region-infer-to-static-in-binder.stderr @@ -1,8 +1,8 @@ -error[E0284]: type annotations needed: cannot satisfy `{ || {} } == _` +error[E0284]: type annotations needed: cannot normalize `X::{constant#0}` --> $DIR/const-region-infer-to-static-in-binder.rs:4:10 | LL | struct X; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^ cannot satisfy `{ || {} } == _` + | ^^^^^^^^^^^^^^^^^^^^^^^^^^ cannot normalize `X::{constant#0}` error: using function pointers as const generic parameters is forbidden --> $DIR/const-region-infer-to-static-in-binder.rs:4:20 diff --git a/tests/ui/traits/next-solver/coroutine.fail.stderr b/tests/ui/traits/next-solver/coroutine.fail.stderr index e880d05a4dd34..8c263e8644bd0 100644 --- a/tests/ui/traits/next-solver/coroutine.fail.stderr +++ b/tests/ui/traits/next-solver/coroutine.fail.stderr @@ -6,8 +6,6 @@ LL | needs_coroutine( LL | #[coroutine] LL | / || { LL | | -LL | | -LL | | LL | | yield (); LL | | }, | |_________^ the trait `Coroutine` is not implemented for `{coroutine@$DIR/coroutine.rs:20:9: 20:11}` @@ -18,47 +16,6 @@ note: required by a bound in `needs_coroutine` LL | fn needs_coroutine(_: impl Coroutine) {} | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `needs_coroutine` -error[E0271]: type mismatch resolving `<{coroutine@$DIR/coroutine.rs:20:9: 20:11} as Coroutine>::Yield == B` - --> $DIR/coroutine.rs:20:9 - | -LL | needs_coroutine( - | --------------- required by a bound introduced by this call -LL | #[coroutine] -LL | / || { -LL | | -LL | | -LL | | -LL | | yield (); -LL | | }, - | |_________^ types differ - | -note: required by a bound in `needs_coroutine` - --> $DIR/coroutine.rs:14:41 - | -LL | fn needs_coroutine(_: impl Coroutine) {} - | ^^^^^^^^^ required by this bound in `needs_coroutine` - -error[E0271]: type mismatch resolving `<{coroutine@$DIR/coroutine.rs:20:9: 20:11} as Coroutine>::Return == C` - --> $DIR/coroutine.rs:20:9 - | -LL | needs_coroutine( - | --------------- required by a bound introduced by this call -LL | #[coroutine] -LL | / || { -LL | | -LL | | -LL | | -LL | | yield (); -LL | | }, - | |_________^ types differ - | -note: required by a bound in `needs_coroutine` - --> $DIR/coroutine.rs:14:52 - | -LL | fn needs_coroutine(_: impl Coroutine) {} - | ^^^^^^^^^^ required by this bound in `needs_coroutine` - -error: aborting due to 3 previous errors +error: aborting due to 1 previous error -Some errors have detailed explanations: E0271, E0277. -For more information about an error, try `rustc --explain E0271`. +For more information about this error, try `rustc --explain E0277`. diff --git a/tests/ui/traits/next-solver/coroutine.rs b/tests/ui/traits/next-solver/coroutine.rs index 1882a62cf29cc..bdc34842f6d5e 100644 --- a/tests/ui/traits/next-solver/coroutine.rs +++ b/tests/ui/traits/next-solver/coroutine.rs @@ -19,8 +19,6 @@ fn main() { #[coroutine] || { //[fail]~^ ERROR Coroutine` is not satisfied - //[fail]~| ERROR as Coroutine>::Yield == B` - //[fail]~| ERROR as Coroutine>::Return == C` yield (); }, ); diff --git a/tests/ui/traits/next-solver/diagnostics/point-at-failing-nested.stderr b/tests/ui/traits/next-solver/diagnostics/point-at-failing-nested.stderr index 6bf4e3cb53493..9a18a58debd2f 100644 --- a/tests/ui/traits/next-solver/diagnostics/point-at-failing-nested.stderr +++ b/tests/ui/traits/next-solver/diagnostics/point-at-failing-nested.stderr @@ -4,6 +4,11 @@ error[E0277]: the trait bound `(): Foo` is not satisfied LL | needs_foo::<()>(); | ^^ the trait `Bar` is not implemented for `()`, which is required by `(): Foo` | +help: this trait has no implementations, consider adding one + --> $DIR/point-at-failing-nested.rs:4:1 + | +LL | trait Bar {} + | ^^^^^^^^^ note: required for `()` to implement `Foo` --> $DIR/point-at-failing-nested.rs:9:12 | diff --git a/tests/ui/traits/next-solver/diagnostics/projection-trait-ref.rs b/tests/ui/traits/next-solver/diagnostics/projection-trait-ref.rs new file mode 100644 index 0000000000000..a3ab7bf03e55a --- /dev/null +++ b/tests/ui/traits/next-solver/diagnostics/projection-trait-ref.rs @@ -0,0 +1,17 @@ +//@ compile-flags: -Znext-solver + +trait Trait { + type Assoc; +} + +fn test_poly() { + let x: ::Assoc = (); + //~^ ERROR the trait bound `T: Trait` is not satisfied +} + +fn test() { + let x: ::Assoc = (); + //~^ ERROR the trait bound `i32: Trait` is not satisfied +} + +fn main() {} diff --git a/tests/ui/traits/next-solver/diagnostics/projection-trait-ref.stderr b/tests/ui/traits/next-solver/diagnostics/projection-trait-ref.stderr new file mode 100644 index 0000000000000..cd8d8b3ffcd38 --- /dev/null +++ b/tests/ui/traits/next-solver/diagnostics/projection-trait-ref.stderr @@ -0,0 +1,26 @@ +error[E0277]: the trait bound `T: Trait` is not satisfied + --> $DIR/projection-trait-ref.rs:8:12 + | +LL | let x: ::Assoc = (); + | ^^^^^^^^^^^^^^^^^^^ the trait `Trait` is not implemented for `T` + | +help: consider restricting type parameter `T` + | +LL | fn test_poly() { + | +++++++ + +error[E0277]: the trait bound `i32: Trait` is not satisfied + --> $DIR/projection-trait-ref.rs:13:12 + | +LL | let x: ::Assoc = (); + | ^^^^^^^^^^^^^^^^^^^^^ the trait `Trait` is not implemented for `i32` + | +help: this trait has no implementations, consider adding one + --> $DIR/projection-trait-ref.rs:3:1 + | +LL | trait Trait { + | ^^^^^^^^^^^ + +error: aborting due to 2 previous errors + +For more information about this error, try `rustc --explain E0277`. diff --git a/tests/ui/traits/next-solver/diagnostics/where-clause-doesnt-apply.stderr b/tests/ui/traits/next-solver/diagnostics/where-clause-doesnt-apply.stderr index 77a0cc4975412..ab1d4a56c0234 100644 --- a/tests/ui/traits/next-solver/diagnostics/where-clause-doesnt-apply.stderr +++ b/tests/ui/traits/next-solver/diagnostics/where-clause-doesnt-apply.stderr @@ -6,6 +6,11 @@ LL | needs_foo(()); | | | required by a bound introduced by this call | +help: this trait has no implementations, consider adding one + --> $DIR/where-clause-doesnt-apply.rs:2:1 + | +LL | trait Bar {} + | ^^^^^^^^^ note: required for `()` to implement `Foo` --> $DIR/where-clause-doesnt-apply.rs:4:9 | diff --git a/tests/ui/traits/next-solver/env-shadows-impls/param-candidate-shadows-project.stderr b/tests/ui/traits/next-solver/env-shadows-impls/param-candidate-shadows-project.stderr index 3ef0afa38bff4..0c72fc25dca7a 100644 --- a/tests/ui/traits/next-solver/env-shadows-impls/param-candidate-shadows-project.stderr +++ b/tests/ui/traits/next-solver/env-shadows-impls/param-candidate-shadows-project.stderr @@ -2,13 +2,8 @@ error[E0271]: type mismatch resolving `::Assoc == i32` --> $DIR/param-candidate-shadows-project.rs:27:19 | LL | require_bar::(); - | ^ type mismatch resolving `::Assoc == i32` + | ^ types differ | -note: types differ - --> $DIR/param-candidate-shadows-project.rs:10:18 - | -LL | type Assoc = i32; - | ^^^ note: required for `T` to implement `Bar` --> $DIR/param-candidate-shadows-project.rs:13:9 | diff --git a/tests/ui/traits/next-solver/fn-trait.rs b/tests/ui/traits/next-solver/fn-trait.rs index 6d6ae9260b0f3..7994dd3052c40 100644 --- a/tests/ui/traits/next-solver/fn-trait.rs +++ b/tests/ui/traits/next-solver/fn-trait.rs @@ -19,14 +19,10 @@ fn main() { require_fn(f as fn() -> i32); require_fn(f as unsafe fn() -> i32); //~^ ERROR: expected a `Fn()` closure, found `unsafe fn() -> i32` - //~| ERROR: type mismatch resolving ` i32 as FnOnce<()>>::Output == i32` require_fn(g); //~^ ERROR: expected a `Fn()` closure, found `extern "C" fn() -> i32 {g}` - //~| ERROR: type mismatch resolving ` i32 {g} as FnOnce<()>>::Output == i32` require_fn(g as extern "C" fn() -> i32); //~^ ERROR: expected a `Fn()` closure, found `extern "C" fn() -> i32` - //~| ERROR: type mismatch resolving ` i32 as FnOnce<()>>::Output == i32` require_fn(h); //~^ ERROR: expected a `Fn()` closure, found `unsafe fn() -> i32 {h}` - //~| ERROR: type mismatch resolving ` i32 {h} as FnOnce<()>>::Output == i32` } diff --git a/tests/ui/traits/next-solver/fn-trait.stderr b/tests/ui/traits/next-solver/fn-trait.stderr index 86d97cb16b320..00243fd905950 100644 --- a/tests/ui/traits/next-solver/fn-trait.stderr +++ b/tests/ui/traits/next-solver/fn-trait.stderr @@ -15,22 +15,8 @@ note: required by a bound in `require_fn` LL | fn require_fn(_: impl Fn() -> i32) {} | ^^^^^^^^^^^ required by this bound in `require_fn` -error[E0271]: type mismatch resolving ` i32 as FnOnce<()>>::Output == i32` - --> $DIR/fn-trait.rs:20:16 - | -LL | require_fn(f as unsafe fn() -> i32); - | ---------- ^^^^^^^^^^^^^^^^^^^^^^^ types differ - | | - | required by a bound introduced by this call - | -note: required by a bound in `require_fn` - --> $DIR/fn-trait.rs:3:31 - | -LL | fn require_fn(_: impl Fn() -> i32) {} - | ^^^ required by this bound in `require_fn` - error[E0277]: expected a `Fn()` closure, found `extern "C" fn() -> i32 {g}` - --> $DIR/fn-trait.rs:23:16 + --> $DIR/fn-trait.rs:22:16 | LL | require_fn(g); | ---------- ^ expected an `Fn()` closure, found `extern "C" fn() -> i32 {g}` @@ -45,22 +31,8 @@ note: required by a bound in `require_fn` LL | fn require_fn(_: impl Fn() -> i32) {} | ^^^^^^^^^^^ required by this bound in `require_fn` -error[E0271]: type mismatch resolving ` i32 {g} as FnOnce<()>>::Output == i32` - --> $DIR/fn-trait.rs:23:16 - | -LL | require_fn(g); - | ---------- ^ types differ - | | - | required by a bound introduced by this call - | -note: required by a bound in `require_fn` - --> $DIR/fn-trait.rs:3:31 - | -LL | fn require_fn(_: impl Fn() -> i32) {} - | ^^^ required by this bound in `require_fn` - error[E0277]: expected a `Fn()` closure, found `extern "C" fn() -> i32` - --> $DIR/fn-trait.rs:26:16 + --> $DIR/fn-trait.rs:24:16 | LL | require_fn(g as extern "C" fn() -> i32); | ---------- ^^^^^^^^^^^^^^^^^^^^^^^^^^^ expected an `Fn()` closure, found `extern "C" fn() -> i32` @@ -75,22 +47,8 @@ note: required by a bound in `require_fn` LL | fn require_fn(_: impl Fn() -> i32) {} | ^^^^^^^^^^^ required by this bound in `require_fn` -error[E0271]: type mismatch resolving ` i32 as FnOnce<()>>::Output == i32` - --> $DIR/fn-trait.rs:26:16 - | -LL | require_fn(g as extern "C" fn() -> i32); - | ---------- ^^^^^^^^^^^^^^^^^^^^^^^^^^^ types differ - | | - | required by a bound introduced by this call - | -note: required by a bound in `require_fn` - --> $DIR/fn-trait.rs:3:31 - | -LL | fn require_fn(_: impl Fn() -> i32) {} - | ^^^ required by this bound in `require_fn` - error[E0277]: expected a `Fn()` closure, found `unsafe fn() -> i32 {h}` - --> $DIR/fn-trait.rs:29:16 + --> $DIR/fn-trait.rs:26:16 | LL | require_fn(h); | ---------- ^ call the function in a closure: `|| unsafe { /* code */ }` @@ -106,21 +64,6 @@ note: required by a bound in `require_fn` LL | fn require_fn(_: impl Fn() -> i32) {} | ^^^^^^^^^^^ required by this bound in `require_fn` -error[E0271]: type mismatch resolving ` i32 {h} as FnOnce<()>>::Output == i32` - --> $DIR/fn-trait.rs:29:16 - | -LL | require_fn(h); - | ---------- ^ types differ - | | - | required by a bound introduced by this call - | -note: required by a bound in `require_fn` - --> $DIR/fn-trait.rs:3:31 - | -LL | fn require_fn(_: impl Fn() -> i32) {} - | ^^^ required by this bound in `require_fn` - -error: aborting due to 8 previous errors +error: aborting due to 4 previous errors -Some errors have detailed explanations: E0271, E0277. -For more information about an error, try `rustc --explain E0271`. +For more information about this error, try `rustc --explain E0277`. diff --git a/tests/ui/traits/next-solver/normalize/two-projection-param-candidates-are-ambiguous.rs b/tests/ui/traits/next-solver/normalize/two-projection-param-candidates-are-ambiguous.rs index 12ea1bf142ab8..5239474ff44b2 100644 --- a/tests/ui/traits/next-solver/normalize/two-projection-param-candidates-are-ambiguous.rs +++ b/tests/ui/traits/next-solver/normalize/two-projection-param-candidates-are-ambiguous.rs @@ -24,7 +24,7 @@ fn needs_bar() {} fn foo + Foo>() { needs_bar::(); - //~^ ERROR type annotations needed: cannot satisfy `::Assoc == i32` + //~^ ERROR type annotations needed: cannot normalize } fn main() {} diff --git a/tests/ui/traits/next-solver/normalize/two-projection-param-candidates-are-ambiguous.stderr b/tests/ui/traits/next-solver/normalize/two-projection-param-candidates-are-ambiguous.stderr index 21f3fbfeb872e..270ad85171779 100644 --- a/tests/ui/traits/next-solver/normalize/two-projection-param-candidates-are-ambiguous.stderr +++ b/tests/ui/traits/next-solver/normalize/two-projection-param-candidates-are-ambiguous.stderr @@ -1,8 +1,8 @@ -error[E0284]: type annotations needed: cannot satisfy `::Assoc == i32` +error[E0284]: type annotations needed: cannot normalize `::Assoc` --> $DIR/two-projection-param-candidates-are-ambiguous.rs:26:17 | LL | needs_bar::(); - | ^ cannot satisfy `::Assoc == i32` + | ^ cannot normalize `::Assoc` | note: required for `T` to implement `Bar` --> $DIR/two-projection-param-candidates-are-ambiguous.rs:21:9 diff --git a/tests/ui/traits/next-solver/specialization-transmute.stderr b/tests/ui/traits/next-solver/specialization-transmute.stderr index 524522bef098c..b96bfab927d2d 100644 --- a/tests/ui/traits/next-solver/specialization-transmute.stderr +++ b/tests/ui/traits/next-solver/specialization-transmute.stderr @@ -10,23 +10,23 @@ LL | #![feature(specialization)] error: cannot normalize `::Id: '_` -error[E0284]: type annotations needed: cannot satisfy `::Id == _` +error[E0284]: type annotations needed: cannot normalize `::Id` --> $DIR/specialization-transmute.rs:15:23 | LL | fn intu(&self) -> &Self::Id { - | ^^^^^^^^^ cannot satisfy `::Id == _` + | ^^^^^^^^^ cannot normalize `::Id` -error[E0284]: type annotations needed: cannot satisfy `T <: ::Id` +error[E0284]: type annotations needed: cannot satisfy `::Id normalizes-to T` --> $DIR/specialization-transmute.rs:17:9 | LL | self - | ^^^^ cannot satisfy `T <: ::Id` + | ^^^^ cannot satisfy `::Id normalizes-to T` -error[E0284]: type annotations needed: cannot satisfy `::Id == Option>` +error[E0284]: type annotations needed: cannot satisfy `::Id normalizes-to Option>` --> $DIR/specialization-transmute.rs:28:13 | LL | let s = transmute::>>(0); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ cannot satisfy `::Id == Option>` + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ cannot satisfy `::Id normalizes-to Option>` | note: required by a bound in `transmute` --> $DIR/specialization-transmute.rs:21:25 diff --git a/tests/ui/traits/next-solver/specialization-unconstrained.rs b/tests/ui/traits/next-solver/specialization-unconstrained.rs index e44246a1262ad..2bbe784011071 100644 --- a/tests/ui/traits/next-solver/specialization-unconstrained.rs +++ b/tests/ui/traits/next-solver/specialization-unconstrained.rs @@ -18,5 +18,5 @@ fn test, U>() {} fn main() { test::(); - //~^ ERROR cannot satisfy `::Id == ()` + //~^ ERROR cannot satisfy `::Id normalizes-to ()` } diff --git a/tests/ui/traits/next-solver/specialization-unconstrained.stderr b/tests/ui/traits/next-solver/specialization-unconstrained.stderr index a6f6a4f260d41..e1d785b554bd3 100644 --- a/tests/ui/traits/next-solver/specialization-unconstrained.stderr +++ b/tests/ui/traits/next-solver/specialization-unconstrained.stderr @@ -8,11 +8,11 @@ LL | #![feature(specialization)] = help: consider using `min_specialization` instead, which is more stable and complete = note: `#[warn(incomplete_features)]` on by default -error[E0284]: type annotations needed: cannot satisfy `::Id == ()` +error[E0284]: type annotations needed: cannot satisfy `::Id normalizes-to ()` --> $DIR/specialization-unconstrained.rs:20:5 | LL | test::(); - | ^^^^^^^^^^^^^^^^^ cannot satisfy `::Id == ()` + | ^^^^^^^^^^^^^^^^^ cannot satisfy `::Id normalizes-to ()` | note: required by a bound in `test` --> $DIR/specialization-unconstrained.rs:17:20 diff --git a/tests/ui/traits/next-solver/unevaluated-const-impl-trait-ref.fails.stderr b/tests/ui/traits/next-solver/unevaluated-const-impl-trait-ref.fails.stderr index 4be90c702a035..efdc9f8fc9f71 100644 --- a/tests/ui/traits/next-solver/unevaluated-const-impl-trait-ref.fails.stderr +++ b/tests/ui/traits/next-solver/unevaluated-const-impl-trait-ref.fails.stderr @@ -5,8 +5,8 @@ LL | needs::<1>(); | ^ the trait `Trait<1>` is not implemented for `()` | = help: the following other types implement trait `Trait`: - <() as Trait<0>> - <() as Trait<2>> + `()` implements `Trait<0>` + `()` implements `Trait<2>` note: required by a bound in `needs` --> $DIR/unevaluated-const-impl-trait-ref.rs:10:38 | diff --git a/tests/ui/traits/question-mark-result-err-mismatch.stderr b/tests/ui/traits/question-mark-result-err-mismatch.stderr index 8a6c5fc10c5fd..66276bcbe3bb0 100644 --- a/tests/ui/traits/question-mark-result-err-mismatch.stderr +++ b/tests/ui/traits/question-mark-result-err-mismatch.stderr @@ -31,12 +31,12 @@ LL | .map_err(|_| ())?; | = note: the question mark operation (`?`) implicitly performs a conversion on the error value using the `From` trait = help: the following other types implement trait `From`: - > - > - > - >> - >> - > + `String` implements `From<&String>` + `String` implements `From<&mut str>` + `String` implements `From<&str>` + `String` implements `From>` + `String` implements `From>` + `String` implements `From` = note: required for `Result<(), String>` to implement `FromResidual>` error[E0277]: `?` couldn't convert the error to `String` diff --git a/tests/ui/traits/suggest-dereferences/root-obligation.stderr b/tests/ui/traits/suggest-dereferences/root-obligation.stderr index 14b2ecbb9f2d7..bbfbb98fba774 100644 --- a/tests/ui/traits/suggest-dereferences/root-obligation.stderr +++ b/tests/ui/traits/suggest-dereferences/root-obligation.stderr @@ -2,7 +2,7 @@ error[E0277]: the trait bound `&char: Pattern<'_>` is not satisfied --> $DIR/root-obligation.rs:6:38 | LL | .filter(|c| "aeiou".contains(c)) - | -------- ^ the trait `Fn(char)` is not implemented for `&char`, which is required by `&char: Pattern<'_>` + | -------- ^ the trait `Fn(char)` is not implemented for `char`, which is required by `&char: Pattern<'_>` | | | required by a bound introduced by this call | diff --git a/tests/ui/transmutability/enums/uninhabited_optimization.rs b/tests/ui/transmutability/enums/uninhabited_optimization.rs new file mode 100644 index 0000000000000..04a8eb40c8b8d --- /dev/null +++ b/tests/ui/transmutability/enums/uninhabited_optimization.rs @@ -0,0 +1,26 @@ +//@ check-pass +//! Tests that we do not regress rust-lang/rust#125811 +#![feature(transmutability)] + +fn assert_transmutable() +where + (): std::mem::BikeshedIntrinsicFrom +{} + +enum Uninhabited {} + +enum SingleInhabited { + X, + Y(Uninhabited) +} + +enum SingleUninhabited { + X(Uninhabited), + Y(Uninhabited), +} + +fn main() { + assert_transmutable::(); + assert_transmutable::(); + assert_transmutable::(); +} diff --git a/tests/ui/transmutability/references/unsafecell.stderr b/tests/ui/transmutability/references/unsafecell.stderr index 651eb8ceb2676..8bb323593554a 100644 --- a/tests/ui/transmutability/references/unsafecell.stderr +++ b/tests/ui/transmutability/references/unsafecell.stderr @@ -2,7 +2,7 @@ error[E0277]: `&u8` cannot be safely transmuted into `&UnsafeCell` --> $DIR/unsafecell.rs:27:50 | LL | assert::is_maybe_transmutable::<&'static u8, &'static UnsafeCell>(); - | ^^^^^^^^^^^^^^^^^^^^^^^ the trait `Freeze` is not implemented for `&'static UnsafeCell` + | ^^^^^^^^^^^^^^^^^^^^^^^ the trait `Freeze` is not implemented for `UnsafeCell` | note: required by a bound in `is_maybe_transmutable` --> $DIR/unsafecell.rs:12:14 @@ -17,7 +17,7 @@ error[E0277]: `&UnsafeCell` cannot be safely transmuted into `&UnsafeCell $DIR/unsafecell.rs:29:62 | LL | assert::is_maybe_transmutable::<&'static UnsafeCell, &'static UnsafeCell>(); - | ^^^^^^^^^^^^^^^^^^^^^^^ the trait `Freeze` is not implemented for `&'static UnsafeCell` + | ^^^^^^^^^^^^^^^^^^^^^^^ the trait `Freeze` is not implemented for `UnsafeCell` | note: required by a bound in `is_maybe_transmutable` --> $DIR/unsafecell.rs:12:14 diff --git a/tests/ui/try-trait/bad-interconversion.stderr b/tests/ui/try-trait/bad-interconversion.stderr index e3edec6a4c76b..c30b6334fed6e 100644 --- a/tests/ui/try-trait/bad-interconversion.stderr +++ b/tests/ui/try-trait/bad-interconversion.stderr @@ -10,8 +10,8 @@ LL | Ok(Err(123_i32)?) | = note: the question mark operation (`?`) implicitly performs a conversion on the error value using the `From` trait = help: the following other types implement trait `From`: - > - > + `u8` implements `From` + `u8` implements `From` = note: required for `Result` to implement `FromResidual>` error[E0277]: the `?` operator can only be used on `Result`s, not `Option`s, in a function that returns `Result` @@ -24,8 +24,8 @@ LL | Some(3)?; | = help: the trait `FromResidual>` is not implemented for `Result` = help: the following other types implement trait `FromResidual`: - as FromResidual>> - as FromResidual>> + `Result` implements `FromResidual>` + `Result` implements `FromResidual>` error[E0277]: the `?` operator can only be used on `Result`s in a function that returns `Result` --> $DIR/bad-interconversion.rs:17:31 @@ -37,8 +37,8 @@ LL | Ok(ControlFlow::Break(123)?) | = help: the trait `FromResidual>` is not implemented for `Result` = help: the following other types implement trait `FromResidual`: - as FromResidual>> - as FromResidual>> + `Result` implements `FromResidual>` + `Result` implements `FromResidual>` error[E0277]: the `?` operator can only be used on `Option`s, not `Result`s, in a function that returns `Option` --> $DIR/bad-interconversion.rs:22:22 @@ -50,8 +50,8 @@ LL | Some(Err("hello")?) | = help: the trait `FromResidual>` is not implemented for `Option` = help: the following other types implement trait `FromResidual`: - as FromResidual>> - as FromResidual> + `Option` implements `FromResidual>` + `Option` implements `FromResidual` error[E0277]: the `?` operator can only be used on `Option`s in a function that returns `Option` --> $DIR/bad-interconversion.rs:27:33 @@ -63,8 +63,8 @@ LL | Some(ControlFlow::Break(123)?) | = help: the trait `FromResidual>` is not implemented for `Option` = help: the following other types implement trait `FromResidual`: - as FromResidual>> - as FromResidual> + `Option` implements `FromResidual>` + `Option` implements `FromResidual` error[E0277]: the `?` operator can only be used on `ControlFlow`s in a function that returns `ControlFlow` --> $DIR/bad-interconversion.rs:32:39 diff --git a/tests/ui/try-trait/issue-32709.stderr b/tests/ui/try-trait/issue-32709.stderr index a0dd18fa039c9..9b77f578437c9 100644 --- a/tests/ui/try-trait/issue-32709.stderr +++ b/tests/ui/try-trait/issue-32709.stderr @@ -10,14 +10,14 @@ LL | Err(5)?; | = note: the question mark operation (`?`) implicitly performs a conversion on the error value using the `From` trait = help: the following other types implement trait `From`: - <(T, T) as From<[T; 2]>> - <(T, T, T) as From<[T; 3]>> - <(T, T, T, T) as From<[T; 4]>> - <(T, T, T, T, T) as From<[T; 5]>> - <(T, T, T, T, T, T) as From<[T; 6]>> - <(T, T, T, T, T, T, T) as From<[T; 7]>> - <(T, T, T, T, T, T, T, T) as From<[T; 8]>> - <(T, T, T, T, T, T, T, T, T) as From<[T; 9]>> + `(T, T)` implements `From<[T; 2]>` + `(T, T, T)` implements `From<[T; 3]>` + `(T, T, T, T)` implements `From<[T; 4]>` + `(T, T, T, T, T)` implements `From<[T; 5]>` + `(T, T, T, T, T, T)` implements `From<[T; 6]>` + `(T, T, T, T, T, T, T)` implements `From<[T; 7]>` + `(T, T, T, T, T, T, T, T)` implements `From<[T; 8]>` + `(T, T, T, T, T, T, T, T, T)` implements `From<[T; 9]>` and 4 others = note: required for `Result` to implement `FromResidual>` diff --git a/tests/ui/try-trait/option-to-result.stderr b/tests/ui/try-trait/option-to-result.stderr index fabc1ff2c762e..2d97226275d26 100644 --- a/tests/ui/try-trait/option-to-result.stderr +++ b/tests/ui/try-trait/option-to-result.stderr @@ -9,8 +9,8 @@ LL | a?; | = help: the trait `FromResidual>` is not implemented for `Result<(), ()>` = help: the following other types implement trait `FromResidual`: - as FromResidual>> - as FromResidual>> + `Result` implements `FromResidual>` + `Result` implements `FromResidual>` error[E0277]: the `?` operator can only be used on `Option`s, not `Result`s, in a function that returns `Option` --> $DIR/option-to-result.rs:11:6 @@ -23,8 +23,8 @@ LL | a?; | = help: the trait `FromResidual>` is not implemented for `Option` = help: the following other types implement trait `FromResidual`: - as FromResidual>> - as FromResidual> + `Option` implements `FromResidual>` + `Option` implements `FromResidual` error: aborting due to 2 previous errors diff --git a/tests/ui/try-trait/try-on-option.stderr b/tests/ui/try-trait/try-on-option.stderr index fad6a1fe8237b..84a51a078af1c 100644 --- a/tests/ui/try-trait/try-on-option.stderr +++ b/tests/ui/try-trait/try-on-option.stderr @@ -9,8 +9,8 @@ LL | x?; | = help: the trait `FromResidual>` is not implemented for `Result` = help: the following other types implement trait `FromResidual`: - as FromResidual>> - as FromResidual>> + `Result` implements `FromResidual>` + `Result` implements `FromResidual>` error[E0277]: the `?` operator can only be used in a function that returns `Result` or `Option` (or another type that implements `FromResidual`) --> $DIR/try-on-option.rs:11:6 diff --git a/tests/ui/type-alias-impl-trait/constrain_in_projection2.current.stderr b/tests/ui/type-alias-impl-trait/constrain_in_projection2.current.stderr index 69df5c77f9de9..909f1f6d61cbe 100644 --- a/tests/ui/type-alias-impl-trait/constrain_in_projection2.current.stderr +++ b/tests/ui/type-alias-impl-trait/constrain_in_projection2.current.stderr @@ -5,8 +5,8 @@ LL | let x = >::Assoc::default(); | ^^^ the trait `Trait` is not implemented for `Foo` | = help: the following other types implement trait `Trait`: - > - > + `Foo` implements `Trait<()>` + `Foo` implements `Trait` error: aborting due to 1 previous error diff --git a/tests/ui/type-alias-impl-trait/issue-84660-unsoundness.next.stderr b/tests/ui/type-alias-impl-trait/issue-84660-unsoundness.next.stderr index 4c8a25edfedbe..5a728a00138c8 100644 --- a/tests/ui/type-alias-impl-trait/issue-84660-unsoundness.next.stderr +++ b/tests/ui/type-alias-impl-trait/issue-84660-unsoundness.next.stderr @@ -1,4 +1,4 @@ -error[E0284]: type annotations needed: cannot satisfy `>::Out == ()` +error[E0284]: type annotations needed: cannot satisfy `Bar == _` --> $DIR/issue-84660-unsoundness.rs:22:37 | LL | fn convert(_i: In) -> Self::Out { @@ -7,7 +7,7 @@ LL | | LL | | LL | | unreachable!(); LL | | } - | |_____^ cannot satisfy `>::Out == ()` + | |_____^ cannot satisfy `Bar == _` error[E0119]: conflicting implementations of trait `Trait` --> $DIR/issue-84660-unsoundness.rs:29:1 diff --git a/tests/ui/type-alias-impl-trait/issue-84660-unsoundness.rs b/tests/ui/type-alias-impl-trait/issue-84660-unsoundness.rs index 73c8deb3a4d97..f3234bafd1153 100644 --- a/tests/ui/type-alias-impl-trait/issue-84660-unsoundness.rs +++ b/tests/ui/type-alias-impl-trait/issue-84660-unsoundness.rs @@ -20,7 +20,7 @@ trait Trait { impl Trait for Out { type Out = Out; fn convert(_i: In) -> Self::Out { - //[next]~^ ERROR: cannot satisfy `>::Out == ()` + //[next]~^ ERROR: cannot satisfy `Bar == _` //[current]~^^ ERROR: item does not constrain `Bar::{opaque#0}`, but has it in its signature unreachable!(); } diff --git a/tests/ui/type-alias-impl-trait/method_resolution.current.stderr b/tests/ui/type-alias-impl-trait/method_resolution.current.stderr new file mode 100644 index 0000000000000..a9c05ad33424d --- /dev/null +++ b/tests/ui/type-alias-impl-trait/method_resolution.current.stderr @@ -0,0 +1,15 @@ +error[E0599]: no method named `bar` found for struct `Bar` in the current scope + --> $DIR/method_resolution.rs:21:14 + | +LL | struct Bar(T); + | ------------- method `bar` not found for this struct +... +LL | self.bar() + | ^^^ method not found in `Bar` + | + = note: the method was found for + - `Bar` + +error: aborting due to 1 previous error + +For more information about this error, try `rustc --explain E0599`. diff --git a/tests/ui/type-alias-impl-trait/method_resolution.next.stderr b/tests/ui/type-alias-impl-trait/method_resolution.next.stderr new file mode 100644 index 0000000000000..6b34358a56ea3 --- /dev/null +++ b/tests/ui/type-alias-impl-trait/method_resolution.next.stderr @@ -0,0 +1,12 @@ +error[E0599]: no method named `bar` found for struct `Bar` in the current scope + --> $DIR/method_resolution.rs:21:14 + | +LL | struct Bar(T); + | ------------- method `bar` not found for this struct +... +LL | self.bar() + | ^^^ method cannot be called on `Bar` due to unsatisfied trait bounds + +error: aborting due to 1 previous error + +For more information about this error, try `rustc --explain E0599`. diff --git a/tests/ui/type-alias-impl-trait/method_resolution.rs b/tests/ui/type-alias-impl-trait/method_resolution.rs new file mode 100644 index 0000000000000..f636aba15c0c4 --- /dev/null +++ b/tests/ui/type-alias-impl-trait/method_resolution.rs @@ -0,0 +1,30 @@ +//! `Bar::foo` is not defining `Foo`, so it cannot rely on the fact that +//! `u32` is the hidden type of `Foo` to call `bar` + +//@ revisions: current next +//@[next] compile-flags: -Znext-solver + +#![feature(type_alias_impl_trait)] + +type Foo = impl Sized; + +struct Bar(T); + +impl Bar { + fn bar(mut self) { + self.0 = 42_u32; + } +} + +impl Bar { + fn foo(self) { + self.bar() + //~^ ERROR: no method named `bar` + } +} + +fn foo() -> Foo { + 42_u32 +} + +fn main() {} diff --git a/tests/ui/type-alias-impl-trait/method_resolution2.rs b/tests/ui/type-alias-impl-trait/method_resolution2.rs new file mode 100644 index 0000000000000..f69661db79922 --- /dev/null +++ b/tests/ui/type-alias-impl-trait/method_resolution2.rs @@ -0,0 +1,28 @@ +//! Check that we do unify `Bar` with `Bar`, as the +//! `foo` method call can be resolved unambiguously by doing so. + +//@ revisions: current next +//@[next] compile-flags: -Znext-solver +//@ check-pass + +#![feature(type_alias_impl_trait)] + +type Foo = impl Sized; + +struct Bar(T); + +impl Bar { + fn bar(self) { + self.foo() + } +} + +impl Bar { + fn foo(self) {} +} + +fn foo() -> Foo { + 42_u32 +} + +fn main() {} diff --git a/tests/ui/type-alias-impl-trait/method_resolution3.current.stderr b/tests/ui/type-alias-impl-trait/method_resolution3.current.stderr new file mode 100644 index 0000000000000..e992d059daf7d --- /dev/null +++ b/tests/ui/type-alias-impl-trait/method_resolution3.current.stderr @@ -0,0 +1,21 @@ +error[E0307]: invalid `self` parameter type: `Bar` + --> $DIR/method_resolution3.rs:16:18 + | +LL | fn bar(self: Bar) { + | ^^^^^^^^ + | + = note: type of `self` must be `Self` or a type that dereferences to it + = help: consider changing to `self`, `&self`, `&mut self`, `self: Box`, `self: Rc`, `self: Arc`, or `self: Pin

` (where P is one of the previous types except `Self`) + +error[E0307]: invalid `self` parameter type: `&Bar` + --> $DIR/method_resolution3.rs:21:18 + | +LL | fn baz(self: &Bar) { + | ^^^^^^^^^ + | + = note: type of `self` must be `Self` or a type that dereferences to it + = help: consider changing to `self`, `&self`, `&mut self`, `self: Box`, `self: Rc`, `self: Arc`, or `self: Pin

` (where P is one of the previous types except `Self`) + +error: aborting due to 2 previous errors + +For more information about this error, try `rustc --explain E0307`. diff --git a/tests/ui/type-alias-impl-trait/method_resolution3.next.stderr b/tests/ui/type-alias-impl-trait/method_resolution3.next.stderr new file mode 100644 index 0000000000000..9272017cdf5d1 --- /dev/null +++ b/tests/ui/type-alias-impl-trait/method_resolution3.next.stderr @@ -0,0 +1,15 @@ +error[E0271]: type mismatch resolving `Foo == u32` + --> $DIR/method_resolution3.rs:16:18 + | +LL | fn bar(self: Bar) { + | ^^^^^^^^ types differ + +error[E0271]: type mismatch resolving `Foo == u32` + --> $DIR/method_resolution3.rs:21:18 + | +LL | fn baz(self: &Bar) { + | ^^^^^^^^^ types differ + +error: aborting due to 2 previous errors + +For more information about this error, try `rustc --explain E0271`. diff --git a/tests/ui/type-alias-impl-trait/method_resolution3.rs b/tests/ui/type-alias-impl-trait/method_resolution3.rs new file mode 100644 index 0000000000000..447f3144b822c --- /dev/null +++ b/tests/ui/type-alias-impl-trait/method_resolution3.rs @@ -0,0 +1,36 @@ +//! Check that one cannot use arbitrary self types where a generic parameter +//! mismatches with an opaque type. In theory this could unify with the opaque +//! type, registering the generic parameter as the hidden type of the opaque type. + +//@ revisions: current next +//@[next] compile-flags: -Znext-solver + +#![feature(type_alias_impl_trait, arbitrary_self_types)] + +type Foo = impl Copy; + +#[derive(Copy, Clone)] +struct Bar(T); + +impl Bar { + fn bar(self: Bar) { + //[current]~^ ERROR: invalid `self` parameter + //[next]~^^ ERROR: type mismatch resolving `Foo == u32` + self.foo() + } + fn baz(self: &Bar) { + //[current]~^ ERROR: invalid `self` parameter + //[next]~^^ ERROR: type mismatch resolving `Foo == u32` + self.foo() + } +} + +impl Bar { + fn foo(self) {} +} + +fn foo() -> Foo { + 42_u32 +} + +fn main() {} diff --git a/tests/ui/type-alias-impl-trait/method_resolution4.current.stderr b/tests/ui/type-alias-impl-trait/method_resolution4.current.stderr new file mode 100644 index 0000000000000..3a2ca18f89097 --- /dev/null +++ b/tests/ui/type-alias-impl-trait/method_resolution4.current.stderr @@ -0,0 +1,21 @@ +error[E0307]: invalid `self` parameter type: `Bar` + --> $DIR/method_resolution4.rs:27:18 + | +LL | fn foo(self: Bar) { + | ^^^^^^^^ + | + = note: type of `self` must be `Self` or a type that dereferences to it + = help: consider changing to `self`, `&self`, `&mut self`, `self: Box`, `self: Rc`, `self: Arc`, or `self: Pin

` (where P is one of the previous types except `Self`) + +error[E0307]: invalid `self` parameter type: `&Bar` + --> $DIR/method_resolution4.rs:32:20 + | +LL | fn foomp(self: &Bar) { + | ^^^^^^^^^ + | + = note: type of `self` must be `Self` or a type that dereferences to it + = help: consider changing to `self`, `&self`, `&mut self`, `self: Box`, `self: Rc`, `self: Arc`, or `self: Pin

` (where P is one of the previous types except `Self`) + +error: aborting due to 2 previous errors + +For more information about this error, try `rustc --explain E0307`. diff --git a/tests/ui/type-alias-impl-trait/method_resolution4.next.stderr b/tests/ui/type-alias-impl-trait/method_resolution4.next.stderr new file mode 100644 index 0000000000000..33ed2800ebe0c --- /dev/null +++ b/tests/ui/type-alias-impl-trait/method_resolution4.next.stderr @@ -0,0 +1,15 @@ +error[E0271]: type mismatch resolving `u32 == Foo` + --> $DIR/method_resolution4.rs:27:18 + | +LL | fn foo(self: Bar) { + | ^^^^^^^^ types differ + +error[E0271]: type mismatch resolving `u32 == Foo` + --> $DIR/method_resolution4.rs:32:20 + | +LL | fn foomp(self: &Bar) { + | ^^^^^^^^^ types differ + +error: aborting due to 2 previous errors + +For more information about this error, try `rustc --explain E0271`. diff --git a/tests/ui/type-alias-impl-trait/method_resolution4.rs b/tests/ui/type-alias-impl-trait/method_resolution4.rs new file mode 100644 index 0000000000000..42ed04b3c30f6 --- /dev/null +++ b/tests/ui/type-alias-impl-trait/method_resolution4.rs @@ -0,0 +1,39 @@ +//! Check that one cannot use arbitrary self types where a generic parameter +//! mismatches with an opaque type. In theory this could unify with the opaque +//! type, registering the generic parameter as the hidden type of the opaque type. + +//@ revisions: current next +//@[next] compile-flags: -Znext-solver + +#![feature(type_alias_impl_trait, arbitrary_self_types)] + +mod foo { + pub type Foo = impl Copy; + + fn foo() -> Foo { + 42_u32 + } +} +use foo::Foo; + +#[derive(Copy, Clone)] +struct Bar(T); + +impl Bar { + fn bar(self) {} +} + +impl Bar { + fn foo(self: Bar) { + //[current]~^ ERROR: invalid `self` parameter + //[next]~^^ ERROR: type mismatch resolving `u32 == Foo` + self.bar() + } + fn foomp(self: &Bar) { + //[current]~^ ERROR: invalid `self` parameter + //[next]~^^ ERROR: type mismatch resolving `u32 == Foo` + self.bar() + } +} + +fn main() {} diff --git a/tests/ui/type-alias-impl-trait/method_resolution5.rs b/tests/ui/type-alias-impl-trait/method_resolution5.rs new file mode 100644 index 0000000000000..64355e4560de2 --- /dev/null +++ b/tests/ui/type-alias-impl-trait/method_resolution5.rs @@ -0,0 +1,33 @@ +//! Even though `Bar::foo` is defining `Foo`, the old solver does +//! not figure out that `u32` is the hidden type of `Foo` to call `bar`. + +//@ revisions: current next +//@[next] compile-flags: -Znext-solver +//@ check-pass + +#![feature(type_alias_impl_trait)] + +type Foo = impl Sized; + +struct Bar(T); + +impl Bar { + fn bar(mut self) { + self.0 = 42_u32; + } +} + +impl Bar { + fn foo(self) + where + Foo:, + { + self.bar() + } +} + +fn foo() -> Foo { + 42_u32 +} + +fn main() {} diff --git a/tests/ui/type-alias-impl-trait/method_resolution_trait_method_from_opaque.current.stderr b/tests/ui/type-alias-impl-trait/method_resolution_trait_method_from_opaque.current.stderr new file mode 100644 index 0000000000000..f331da1af8793 --- /dev/null +++ b/tests/ui/type-alias-impl-trait/method_resolution_trait_method_from_opaque.current.stderr @@ -0,0 +1,15 @@ +error: item does not constrain `Tait::{opaque#0}`, but has it in its signature + --> $DIR/method_resolution_trait_method_from_opaque.rs:24:8 + | +LL | fn foo(&mut self) { + | ^^^ + | + = note: consider moving the opaque type's declaration and defining uses into a separate module +note: this opaque type is in the signature + --> $DIR/method_resolution_trait_method_from_opaque.rs:17:13 + | +LL | type Tait = impl Iterator; + | ^^^^^^^^^^^^^^^^^^^^^^^^ + +error: aborting due to 1 previous error + diff --git a/tests/ui/type-alias-impl-trait/method_resolution_trait_method_from_opaque.next.stderr b/tests/ui/type-alias-impl-trait/method_resolution_trait_method_from_opaque.next.stderr new file mode 100644 index 0000000000000..2617ce124c105 --- /dev/null +++ b/tests/ui/type-alias-impl-trait/method_resolution_trait_method_from_opaque.next.stderr @@ -0,0 +1,9 @@ +error[E0282]: type annotations needed + --> $DIR/method_resolution_trait_method_from_opaque.rs:26:9 + | +LL | self.bar.next().unwrap(); + | ^^^^^^^^ cannot infer type + +error: aborting due to 1 previous error + +For more information about this error, try `rustc --explain E0282`. diff --git a/tests/ui/type-alias-impl-trait/method_resolution_trait_method_from_opaque.rs b/tests/ui/type-alias-impl-trait/method_resolution_trait_method_from_opaque.rs new file mode 100644 index 0000000000000..b6adf08853f2f --- /dev/null +++ b/tests/ui/type-alias-impl-trait/method_resolution_trait_method_from_opaque.rs @@ -0,0 +1,31 @@ +//! This test demonstrates how method calls will attempt to unify an opaque type with a reference +//! if the method takes `&self` as its argument. This is almost never what is desired, as the user +//! would like to have method resolution happen on the opaque type instead of inferring the hidden +//! type. Once type-alias-impl-trait requires annotating which functions should constrain the hidden +//! type, this won't be as much of a problem, as most functions that do method calls on opaque types +//! won't also be the ones defining the hidden type. + +//@ revisions: current next +//@[next] compile-flags: -Znext-solver + +#![feature(type_alias_impl_trait)] + +pub struct Foo { + bar: Tait, +} + +type Tait = impl Iterator; + +impl Foo { + pub fn new() -> Foo { + Foo { bar: std::iter::empty() } + } + + fn foo(&mut self) { + //[current]~^ ERROR: item does not constrain + self.bar.next().unwrap(); + //[next]~^ ERROR: type annotations needed + } +} + +fn main() {} diff --git a/tests/ui/type-alias-impl-trait/nested-tait-inference2.current.stderr b/tests/ui/type-alias-impl-trait/nested-tait-inference2.current.stderr index 614bc09872f82..9da3926ac7081 100644 --- a/tests/ui/type-alias-impl-trait/nested-tait-inference2.current.stderr +++ b/tests/ui/type-alias-impl-trait/nested-tait-inference2.current.stderr @@ -8,8 +8,8 @@ LL | () | -- return type was inferred to be `()` here | = help: the following other types implement trait `Foo`: - <() as Foo<()>> - <() as Foo> + `()` implements `Foo<()>` + `()` implements `Foo` error: aborting due to 1 previous error diff --git a/tests/ui/type/type-check-defaults.stderr b/tests/ui/type/type-check-defaults.stderr index 9ba63ffe9c93f..499e8142cc8f4 100644 --- a/tests/ui/type/type-check-defaults.stderr +++ b/tests/ui/type/type-check-defaults.stderr @@ -66,10 +66,10 @@ LL | trait ProjectionPred> where T::Item : Add {} | = help: the trait `Add` is not implemented for `i32` = help: the following other types implement trait `Add`: - <&'a i32 as Add> - <&i32 as Add<&i32>> - > - + `&'a i32` implements `Add` + `&i32` implements `Add<&i32>` + `i32` implements `Add<&i32>` + `i32` implements `Add` error: aborting due to 7 previous errors diff --git a/tests/ui/typeck/issue-81293.stderr b/tests/ui/typeck/issue-81293.stderr index 6976be71135c2..3c48db335b5f0 100644 --- a/tests/ui/typeck/issue-81293.stderr +++ b/tests/ui/typeck/issue-81293.stderr @@ -21,10 +21,10 @@ LL | a = c + b * 5; | = help: the trait `Add` is not implemented for `usize` = help: the following other types implement trait `Add`: - <&'a usize as Add> - <&usize as Add<&usize>> - > - + `&'a usize` implements `Add` + `&usize` implements `Add<&usize>` + `usize` implements `Add<&usize>` + `usize` implements `Add` error: aborting due to 3 previous errors diff --git a/tests/ui/typeck/issue-90101.stderr b/tests/ui/typeck/issue-90101.stderr index 800d7e9594a25..d6832d1b34ffc 100644 --- a/tests/ui/typeck/issue-90101.stderr +++ b/tests/ui/typeck/issue-90101.stderr @@ -7,11 +7,11 @@ LL | func(Path::new("hello").to_path_buf().to_string_lossy(), "world") | required by a bound introduced by this call | = help: the following other types implement trait `From`: - > - >> - >> - > - > + `PathBuf` implements `From<&T>` + `PathBuf` implements `From>` + `PathBuf` implements `From>` + `PathBuf` implements `From` + `PathBuf` implements `From` = note: required for `Cow<'_, str>` to implement `Into` note: required by a bound in `func` --> $DIR/issue-90101.rs:3:20 diff --git a/tests/ui/typeck/suggest-similar-impls-for-root-obligation.rs b/tests/ui/typeck/suggest-similar-impls-for-root-obligation.rs new file mode 100644 index 0000000000000..d00b4f3313258 --- /dev/null +++ b/tests/ui/typeck/suggest-similar-impls-for-root-obligation.rs @@ -0,0 +1,16 @@ +trait Foo<'s> {} + +impl<'s> Foo<'s> for () {} + +struct Bar; + +impl<'s, T: Foo<'s>> From for Bar { + fn from(_: T) -> Self { + Bar + } +} + +fn main() { + let _: Bar = ((),).into(); + //~^ ERROR he trait bound `((),): Into` is not satisfied +} diff --git a/tests/ui/typeck/suggest-similar-impls-for-root-obligation.stderr b/tests/ui/typeck/suggest-similar-impls-for-root-obligation.stderr new file mode 100644 index 0000000000000..8410574e31129 --- /dev/null +++ b/tests/ui/typeck/suggest-similar-impls-for-root-obligation.stderr @@ -0,0 +1,20 @@ +error[E0277]: the trait bound `((),): Into` is not satisfied + --> $DIR/suggest-similar-impls-for-root-obligation.rs:14:24 + | +LL | let _: Bar = ((),).into(); + | ^^^^ the trait `Foo<'_>` is not implemented for `((),)`, which is required by `((),): Into<_>` + | + = help: the trait `Foo<'_>` is implemented for `()` + = help: for that trait implementation, expected `()`, found `((),)` +note: required for `Bar` to implement `From<((),)>` + --> $DIR/suggest-similar-impls-for-root-obligation.rs:7:22 + | +LL | impl<'s, T: Foo<'s>> From for Bar { + | ------- ^^^^^^^ ^^^ + | | + | unsatisfied trait bound introduced here + = note: required for `((),)` to implement `Into` + +error: aborting due to 1 previous error + +For more information about this error, try `rustc --explain E0277`. diff --git a/tests/ui/ufcs/ufcs-qpath-self-mismatch.stderr b/tests/ui/ufcs/ufcs-qpath-self-mismatch.stderr index 964fd4af0092f..5b8a49d22c739 100644 --- a/tests/ui/ufcs/ufcs-qpath-self-mismatch.stderr +++ b/tests/ui/ufcs/ufcs-qpath-self-mismatch.stderr @@ -6,10 +6,10 @@ LL | >::add(1, 2); | = help: the trait `Add` is not implemented for `i32` = help: the following other types implement trait `Add`: - <&'a i32 as Add> - <&i32 as Add<&i32>> - > - + `&'a i32` implements `Add` + `&i32` implements `Add<&i32>` + `i32` implements `Add<&i32>` + `i32` implements `Add` error[E0277]: cannot add `u32` to `i32` --> $DIR/ufcs-qpath-self-mismatch.rs:4:5 @@ -19,10 +19,10 @@ LL | >::add(1, 2); | = help: the trait `Add` is not implemented for `i32` = help: the following other types implement trait `Add`: - <&'a i32 as Add> - <&i32 as Add<&i32>> - > - + `&'a i32` implements `Add` + `&i32` implements `Add<&i32>` + `i32` implements `Add<&i32>` + `i32` implements `Add` error[E0308]: mismatched types --> $DIR/ufcs-qpath-self-mismatch.rs:7:28