diff options
616 files changed, 11860 insertions, 6772 deletions
diff --git a/.gitignore b/.gitignore index 485968d9c56..87d02563ed0 100644 --- a/.gitignore +++ b/.gitignore @@ -52,6 +52,7 @@ build/ /src/tools/x/target # Created by default with `src/ci/docker/run.sh` /obj/ +/rustc-ice* ## Temporary files *~ diff --git a/Cargo.lock b/Cargo.lock index 138e00adc49..da99ac9b8af 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", @@ -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", @@ -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]] @@ -1740,27 +1740,13 @@ dependencies = [ [[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" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "c13771afe0e6e846f1e67d038d4cb29998a6779f93c809212e4e9c32efd244d4" dependencies = [ "log", "mac", - "markup5ever 0.12.1", + "markup5ever", "proc-macro2", "quote", "syn 2.0.66", @@ -1805,6 +1791,18 @@ dependencies = [ ] [[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" source = "registry+https://github.com/rust-lang/crates.io-index" @@ -1858,6 +1856,51 @@ 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" source = "registry+https://github.com/rust-lang/crates.io-index" @@ -1906,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]] @@ -2181,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]] @@ -2231,7 +2276,7 @@ dependencies = [ name = "linkchecker" version = "0.1.0" dependencies = [ - "html5ever 0.26.0", + "html5ever", "regex", ] @@ -2318,27 +2363,13 @@ 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" 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", @@ -2393,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", @@ -2871,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", ] @@ -2953,15 +2984,6 @@ dependencies = [ [[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" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ade2d8b8f33c7333b51bcf0428d37e217e9f32192ae4772156f65063b8ce03dc" @@ -2971,16 +2993,6 @@ dependencies = [ [[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" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e8d39688d359e6b34654d328e262234662d16cc0f60ec8dcbe5e718709342a5a" @@ -3350,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", ] @@ -3411,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" @@ -3429,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" @@ -3468,14 +3480,6 @@ dependencies = [ ] [[package]] -name = "rust-demangler" -version = "0.0.1" -dependencies = [ - "regex", - "rustc-demangle", -] - -[[package]] name = "rustbook" version = "0.1.0" dependencies = [ @@ -4508,7 +4512,16 @@ dependencies = [ name = "rustc_next_trait_solver" version = "0.0.0" dependencies = [ + "bitflags 2.5.0", + "derivative", + "rustc_ast_ir", + "rustc_data_structures", + "rustc_index", + "rustc_macros", + "rustc_serialize", "rustc_type_ir", + "rustc_type_ir_macros", + "tracing", ] [[package]] @@ -5484,7 +5497,7 @@ dependencies = [ "once_cell", "onig", "plist", - "regex-syntax 0.8.3", + "regex-syntax 0.8.4", "serde", "serde_derive", "serde_json", @@ -5997,7 +6010,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", @@ -6079,12 +6092,6 @@ dependencies = [ ] [[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" source = "registry+https://github.com/rust-lang/crates.io-index" @@ -6185,9 +6192,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", @@ -6201,12 +6208,24 @@ 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" source = "registry+https://github.com/rust-lang/crates.io-index" @@ -6570,6 +6589,12 @@ dependencies = [ ] [[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" source = "registry+https://github.com/rust-lang/crates.io-index" diff --git a/Cargo.toml b/Cargo.toml index a601ebf4369..c17ea99d037 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -23,7 +23,6 @@ members = [ "src/tools/remote-test-client", "src/tools/remote-test-server", "src/tools/rust-installer", - "src/tools/rust-demangler", "src/tools/rustdoc", "src/tools/rls", "src/tools/rustfmt", diff --git a/RELEASES.md b/RELEASES.md index 2297924c7f3..305da6a3550 100644 --- a/RELEASES.md +++ b/RELEASES.md @@ -97,7 +97,6 @@ Cargo - [Prevent dashes in `lib.name`, always normalizing to `_`.](https://github.com/rust-lang/cargo/pull/12783/) - [Stabilize MSRV-aware version requirement selection in `cargo add`.](https://github.com/rust-lang/cargo/pull/13608/) - [Switch to using `gitoxide` by default for listing files.](https://github.com/rust-lang/cargo/pull/13696/) -- [Error on `[project]` in Edition 2024; `cargo fix --edition` will change it to `[package]`.](https://github.com/rust-lang/cargo/pull/13747/) <a id="1.79.0-Rustdoc"></a> diff --git a/compiler/rustc_ast/src/ast.rs b/compiler/rustc_ast/src/ast.rs index ca7f0363fa7..71932f02017 100644 --- a/compiler/rustc_ast/src/ast.rs +++ b/compiler/rustc_ast/src/ast.rs @@ -307,6 +307,8 @@ impl TraitBoundModifiers { pub enum GenericBound { Trait(PolyTraitRef, TraitBoundModifiers), Outlives(Lifetime), + /// Precise capturing syntax: `impl Sized + use<'a>` + Use(ThinVec<PreciseCapturingArg>, Span), } impl GenericBound { @@ -314,6 +316,7 @@ impl GenericBound { match self { GenericBound::Trait(t, ..) => t.span, GenericBound::Outlives(l) => l.ident.span, + GenericBound::Use(_, span) => *span, } } } @@ -2164,7 +2167,7 @@ pub enum TyKind { /// The `NodeId` exists to prevent lowering from having to /// generate `NodeId`s on the fly, which would complicate /// the generation of opaque `type Foo = impl Trait` items significantly. - ImplTrait(NodeId, GenericBounds, Option<P<(ThinVec<PreciseCapturingArg>, Span)>>), + ImplTrait(NodeId, GenericBounds), /// No-op; kept solely so that we can pretty-print faithfully. Paren(P<Ty>), /// Unused for now. @@ -3160,13 +3163,16 @@ pub struct Delegation { pub path: Path, pub rename: Option<Ident>, pub body: Option<P<Block>>, + /// The item was expanded from a glob delegation item. + pub from_glob: bool, } #[derive(Clone, Encodable, Decodable, Debug)] pub struct DelegationMac { pub qself: Option<P<QSelf>>, pub prefix: Path, - pub suffixes: ThinVec<(Ident, Option<Ident>)>, + // Some for list delegation, and None for glob delegation. + pub suffixes: Option<ThinVec<(Ident, Option<Ident>)>>, pub body: Option<P<Block>>, } @@ -3293,7 +3299,7 @@ pub enum ItemKind { /// /// E.g. `reuse <Type as Trait>::name { target_expr_template }`. Delegation(Box<Delegation>), - /// A list delegation item (`reuse prefix::{a, b, c}`). + /// A list or glob delegation item (`reuse prefix::{a, b, c}`, `reuse prefix::*`). /// Treated similarly to a macro call and expanded early. DelegationMac(Box<DelegationMac>), } @@ -3374,7 +3380,7 @@ pub enum AssocItemKind { MacCall(P<MacCall>), /// An associated delegation item. Delegation(Box<Delegation>), - /// An associated delegation item list. + /// An associated list or glob delegation item. DelegationMac(Box<DelegationMac>), } diff --git a/compiler/rustc_ast/src/mut_visit.rs b/compiler/rustc_ast/src/mut_visit.rs index cc33ce2cb56..35aa53e978c 100644 --- a/compiler/rustc_ast/src/mut_visit.rs +++ b/compiler/rustc_ast/src/mut_visit.rs @@ -523,14 +523,9 @@ pub fn noop_visit_ty<T: MutVisitor>(ty: &mut P<Ty>, vis: &mut T) { TyKind::TraitObject(bounds, _syntax) => { visit_vec(bounds, |bound| vis.visit_param_bound(bound)) } - TyKind::ImplTrait(id, bounds, precise_capturing) => { + TyKind::ImplTrait(id, bounds) => { vis.visit_id(id); visit_vec(bounds, |bound| vis.visit_param_bound(bound)); - if let Some((precise_capturing, _span)) = precise_capturing.as_deref_mut() { - for arg in precise_capturing { - vis.visit_precise_capturing_arg(arg); - } - } } TyKind::MacCall(mac) => vis.visit_mac_call(mac), TyKind::AnonStruct(id, fields) | TyKind::AnonUnion(id, fields) => { @@ -923,6 +918,11 @@ fn noop_visit_param_bound<T: MutVisitor>(pb: &mut GenericBound, vis: &mut T) { match pb { GenericBound::Trait(ty, _modifier) => vis.visit_poly_trait_ref(ty), GenericBound::Outlives(lifetime) => noop_visit_lifetime(lifetime, vis), + GenericBound::Use(args, _) => { + for arg in args { + vis.visit_precise_capturing_arg(arg); + } + } } } @@ -1162,7 +1162,14 @@ impl NoopVisitItemKind for ItemKind { } ItemKind::MacCall(m) => vis.visit_mac_call(m), ItemKind::MacroDef(def) => vis.visit_macro_def(def), - ItemKind::Delegation(box Delegation { id, qself, path, rename, body }) => { + ItemKind::Delegation(box Delegation { + id, + qself, + path, + rename, + body, + from_glob: _, + }) => { vis.visit_id(id); vis.visit_qself(qself); vis.visit_path(path); @@ -1176,10 +1183,12 @@ impl NoopVisitItemKind for ItemKind { ItemKind::DelegationMac(box DelegationMac { qself, prefix, suffixes, body }) => { vis.visit_qself(qself); vis.visit_path(prefix); - for (ident, rename) in suffixes { - vis.visit_ident(ident); - if let Some(rename) = rename { - vis.visit_ident(rename); + if let Some(suffixes) = suffixes { + for (ident, rename) in suffixes { + vis.visit_ident(ident); + if let Some(rename) = rename { + vis.visit_ident(rename); + } } } if let Some(body) = body { @@ -1218,7 +1227,14 @@ impl NoopVisitItemKind for AssocItemKind { visit_opt(ty, |ty| visitor.visit_ty(ty)); } AssocItemKind::MacCall(mac) => visitor.visit_mac_call(mac), - AssocItemKind::Delegation(box Delegation { id, qself, path, rename, body }) => { + AssocItemKind::Delegation(box Delegation { + id, + qself, + path, + rename, + body, + from_glob: _, + }) => { visitor.visit_id(id); visitor.visit_qself(qself); visitor.visit_path(path); @@ -1232,10 +1248,12 @@ impl NoopVisitItemKind for AssocItemKind { AssocItemKind::DelegationMac(box DelegationMac { qself, prefix, suffixes, body }) => { visitor.visit_qself(qself); visitor.visit_path(prefix); - for (ident, rename) in suffixes { - visitor.visit_ident(ident); - if let Some(rename) = rename { - visitor.visit_ident(rename); + if let Some(suffixes) = suffixes { + for (ident, rename) in suffixes { + visitor.visit_ident(ident); + if let Some(rename) = rename { + visitor.visit_ident(rename); + } } } if let Some(body) = body { diff --git a/compiler/rustc_ast/src/util/classify.rs b/compiler/rustc_ast/src/util/classify.rs index 382c903625f..4b2544ac47e 100644 --- a/compiler/rustc_ast/src/util/classify.rs +++ b/compiler/rustc_ast/src/util/classify.rs @@ -184,7 +184,7 @@ fn type_trailing_braced_mac_call(mut ty: &ast::Ty) -> Option<&ast::MacCall> { None => break None, }, - ast::TyKind::TraitObject(bounds, _) | ast::TyKind::ImplTrait(_, bounds, _) => { + ast::TyKind::TraitObject(bounds, _) | ast::TyKind::ImplTrait(_, bounds) => { match bounds.last() { Some(ast::GenericBound::Trait(bound, _)) => { match path_return_type(&bound.trait_ref.path) { @@ -192,7 +192,9 @@ fn type_trailing_braced_mac_call(mut ty: &ast::Ty) -> Option<&ast::MacCall> { None => break None, } } - Some(ast::GenericBound::Outlives(_)) | None => break None, + Some(ast::GenericBound::Outlives(_) | ast::GenericBound::Use(..)) | None => { + break None; + } } } diff --git a/compiler/rustc_ast/src/visit.rs b/compiler/rustc_ast/src/visit.rs index fa97c8db326..ed34a44db67 100644 --- a/compiler/rustc_ast/src/visit.rs +++ b/compiler/rustc_ast/src/visit.rs @@ -52,6 +52,16 @@ pub enum BoundKind { /// E.g., `trait A: B` SuperTraits, } +impl BoundKind { + pub fn descr(self) -> &'static str { + match self { + BoundKind::Bound => "bounds", + BoundKind::Impl => "`impl Trait`", + BoundKind::TraitObject => "`dyn` trait object bounds", + BoundKind::SuperTraits => "supertrait bounds", + } + } +} #[derive(Copy, Clone, Debug)] pub enum FnKind<'a> { @@ -398,7 +408,14 @@ impl WalkItemKind for ItemKind { } ItemKind::MacCall(mac) => try_visit!(visitor.visit_mac_call(mac)), ItemKind::MacroDef(ts) => try_visit!(visitor.visit_mac_def(ts, item.id)), - ItemKind::Delegation(box Delegation { id, qself, path, rename, body }) => { + ItemKind::Delegation(box Delegation { + id, + qself, + path, + rename, + body, + from_glob: _, + }) => { if let Some(qself) = qself { try_visit!(visitor.visit_ty(&qself.ty)); } @@ -411,10 +428,12 @@ impl WalkItemKind for ItemKind { try_visit!(visitor.visit_ty(&qself.ty)); } try_visit!(visitor.visit_path(prefix, item.id)); - for (ident, rename) in suffixes { - visitor.visit_ident(*ident); - if let Some(rename) = rename { - visitor.visit_ident(*rename); + if let Some(suffixes) = suffixes { + for (ident, rename) in suffixes { + visitor.visit_ident(*ident); + if let Some(rename) = rename { + visitor.visit_ident(*rename); + } } } visit_opt!(visitor, visit_block, body); @@ -497,13 +516,8 @@ pub fn walk_ty<'a, V: Visitor<'a>>(visitor: &mut V, typ: &'a Ty) -> V::Result { TyKind::TraitObject(bounds, ..) => { walk_list!(visitor, visit_param_bound, bounds, BoundKind::TraitObject); } - TyKind::ImplTrait(_, bounds, precise_capturing) => { + TyKind::ImplTrait(_, bounds) => { walk_list!(visitor, visit_param_bound, bounds, BoundKind::Impl); - if let Some((precise_capturing, _span)) = precise_capturing.as_deref() { - for arg in precise_capturing { - try_visit!(visitor.visit_precise_capturing_arg(arg)); - } - } } TyKind::Typeof(expression) => try_visit!(visitor.visit_anon_const(expression)), TyKind::Infer | TyKind::ImplicitSelf | TyKind::Dummy | TyKind::Err(_) => {} @@ -688,6 +702,10 @@ pub fn walk_param_bound<'a, V: Visitor<'a>>(visitor: &mut V, bound: &'a GenericB match bound { GenericBound::Trait(typ, _modifier) => visitor.visit_poly_trait_ref(typ), GenericBound::Outlives(lifetime) => visitor.visit_lifetime(lifetime, LifetimeCtxt::Bound), + GenericBound::Use(args, _) => { + walk_list!(visitor, visit_precise_capturing_arg, args); + V::Result::output() + } } } @@ -828,7 +846,14 @@ impl WalkItemKind for AssocItemKind { AssocItemKind::MacCall(mac) => { try_visit!(visitor.visit_mac_call(mac)); } - AssocItemKind::Delegation(box Delegation { id, qself, path, rename, body }) => { + AssocItemKind::Delegation(box Delegation { + id, + qself, + path, + rename, + body, + from_glob: _, + }) => { if let Some(qself) = qself { try_visit!(visitor.visit_ty(&qself.ty)); } @@ -841,10 +866,12 @@ impl WalkItemKind for AssocItemKind { try_visit!(visitor.visit_ty(&qself.ty)); } try_visit!(visitor.visit_path(prefix, item.id)); - for (ident, rename) in suffixes { - visitor.visit_ident(*ident); - if let Some(rename) = rename { - visitor.visit_ident(*rename); + if let Some(suffixes) = suffixes { + for (ident, rename) in suffixes { + visitor.visit_ident(*ident); + if let Some(rename) = rename { + visitor.visit_ident(*rename); + } } } visit_opt!(visitor, visit_block, body); diff --git a/compiler/rustc_ast_lowering/messages.ftl b/compiler/rustc_ast_lowering/messages.ftl index 10efe6fba65..7d81e45d314 100644 --- a/compiler/rustc_ast_lowering/messages.ftl +++ b/compiler/rustc_ast_lowering/messages.ftl @@ -128,7 +128,7 @@ ast_lowering_never_pattern_with_guard = a guard on a never pattern will never be run .suggestion = remove this guard -ast_lowering_no_precise_captures_on_apit = `use<...>` precise capturing syntax not allowed on argument-position `impl Trait` +ast_lowering_no_precise_captures_on_apit = `use<...>` precise capturing syntax not allowed in argument-position `impl Trait` ast_lowering_previously_used_here = previously used here diff --git a/compiler/rustc_ast_lowering/src/expr.rs b/compiler/rustc_ast_lowering/src/expr.rs index 77f95869e9d..79cff0fbcd2 100644 --- a/compiler/rustc_ast_lowering/src/expr.rs +++ b/compiler/rustc_ast_lowering/src/expr.rs @@ -1716,24 +1716,28 @@ impl<'hir> LoweringContext<'_, 'hir> { // `mut iter => { ... }` let iter_arm = self.arm(iter_pat, loop_expr); - let into_iter_expr = match loop_kind { + let match_expr = match loop_kind { ForLoopKind::For => { // `::std::iter::IntoIterator::into_iter(<head>)` - self.expr_call_lang_item_fn( + let into_iter_expr = self.expr_call_lang_item_fn( head_span, hir::LangItem::IntoIterIntoIter, arena_vec![self; head], - ) + ); + + self.arena.alloc(self.expr_match( + for_span, + into_iter_expr, + arena_vec![self; iter_arm], + hir::MatchSource::ForLoopDesugar, + )) } - // ` unsafe { Pin::new_unchecked(&mut into_async_iter(<head>)) }` + // `match into_async_iter(<head>) { ref mut iter => match unsafe { Pin::new_unchecked(iter) } { ... } }` ForLoopKind::ForAwait => { - // `::core::async_iter::IntoAsyncIterator::into_async_iter(<head>)` - let iter = self.expr_call_lang_item_fn( - head_span, - hir::LangItem::IntoAsyncIterIntoIter, - arena_vec![self; head], - ); - let iter = self.expr_mut_addr_of(head_span, iter); + let iter_ident = iter; + let (async_iter_pat, async_iter_pat_id) = + self.pat_ident_binding_mode(head_span, iter_ident, hir::BindingMode::REF_MUT); + let iter = self.expr_ident_mut(head_span, iter_ident, async_iter_pat_id); // `Pin::new_unchecked(...)` let iter = self.arena.alloc(self.expr_call_lang_item_fn_mut( head_span, @@ -1742,17 +1746,29 @@ impl<'hir> LoweringContext<'_, 'hir> { )); // `unsafe { ... }` let iter = self.arena.alloc(self.expr_unsafe(iter)); - iter + let inner_match_expr = self.arena.alloc(self.expr_match( + for_span, + iter, + arena_vec![self; iter_arm], + hir::MatchSource::ForLoopDesugar, + )); + + // `::core::async_iter::IntoAsyncIterator::into_async_iter(<head>)` + let iter = self.expr_call_lang_item_fn( + head_span, + hir::LangItem::IntoAsyncIterIntoIter, + arena_vec![self; head], + ); + let iter_arm = self.arm(async_iter_pat, inner_match_expr); + self.arena.alloc(self.expr_match( + for_span, + iter, + arena_vec![self; iter_arm], + hir::MatchSource::ForLoopDesugar, + )) } }; - let match_expr = self.arena.alloc(self.expr_match( - for_span, - into_iter_expr, - arena_vec![self; iter_arm], - hir::MatchSource::ForLoopDesugar, - )); - // This is effectively `{ let _result = ...; _result }`. // The construct was introduced in #21984 and is necessary to make sure that // temporaries in the `head` expression are dropped and do not leak to the diff --git a/compiler/rustc_ast_lowering/src/item.rs b/compiler/rustc_ast_lowering/src/item.rs index 8c963e9f890..c6c0d9a2e60 100644 --- a/compiler/rustc_ast_lowering/src/item.rs +++ b/compiler/rustc_ast_lowering/src/item.rs @@ -1319,6 +1319,14 @@ impl<'hir> LoweringContext<'_, 'hir> { CoroutineKind::AsyncGen { .. } => hir::CoroutineDesugaring::AsyncGen, }; let closure_id = coroutine_kind.closure_id(); + + let span = if let FnRetTy::Default(span) = decl.output + && matches!(coroutine_source, rustc_hir::CoroutineSource::Closure) + { + body_span.with_lo(span.lo()) + } else { + body_span + }; let coroutine_expr = self.make_desugared_coroutine_expr( // The default capture mode here is by-ref. Later on during upvar analysis, // we will force the captured arguments to by-move, but for async closures, @@ -1327,7 +1335,7 @@ impl<'hir> LoweringContext<'_, 'hir> { CaptureBy::Ref, closure_id, None, - body_span, + span, desugaring_kind, coroutine_source, mkbody, diff --git a/compiler/rustc_ast_lowering/src/lib.rs b/compiler/rustc_ast_lowering/src/lib.rs index 88f6e6c3b78..da8682d3d09 100644 --- a/compiler/rustc_ast_lowering/src/lib.rs +++ b/compiler/rustc_ast_lowering/src/lib.rs @@ -50,10 +50,10 @@ use rustc_data_structures::fx::FxIndexSet; use rustc_data_structures::sorted_map::SortedMap; use rustc_data_structures::stable_hasher::{HashStable, StableHasher}; use rustc_data_structures::sync::Lrc; -use rustc_errors::{DiagArgFromDisplay, DiagCtxt, StashKey}; -use rustc_hir as hir; +use rustc_errors::{DiagArgFromDisplay, DiagCtxtHandle, StashKey}; use rustc_hir::def::{DefKind, LifetimeRes, Namespace, PartialRes, PerNS, Res}; use rustc_hir::def_id::{LocalDefId, LocalDefIdMap, CRATE_DEF_ID, LOCAL_CRATE}; +use rustc_hir::{self as hir}; use rustc_hir::{ ConstArg, GenericArg, HirId, ItemLocalMap, MissingLifetimeKind, ParamName, TraitCandidate, }; @@ -188,7 +188,7 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> { } } - pub(crate) fn dcx(&self) -> &'hir DiagCtxt { + pub(crate) fn dcx(&self) -> DiagCtxtHandle<'hir> { self.tcx.dcx() } } @@ -1384,6 +1384,12 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> { } None } + // Ignore `use` syntax since that is not valid in objects. + GenericBound::Use(_, span) => { + this.dcx() + .span_delayed_bug(*span, "use<> not allowed in dyn types"); + None + } })); let lifetime_bound = lifetime_bound.unwrap_or_else(|| this.elided_dyn_bound(t.span)); @@ -1391,7 +1397,7 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> { }); hir::TyKind::TraitObject(bounds, lifetime_bound, *kind) } - TyKind::ImplTrait(def_node_id, bounds, precise_capturing) => { + TyKind::ImplTrait(def_node_id, bounds) => { let span = t.span; match itctx { ImplTraitContext::OpaqueTy { origin, fn_kind } => self.lower_opaque_impl_trait( @@ -1401,12 +1407,15 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> { bounds, fn_kind, itctx, - precise_capturing.as_deref().map(|(args, span)| (args.as_slice(), *span)), ), ImplTraitContext::Universal => { - if let Some(&(_, span)) = precise_capturing.as_deref() { + if let Some(span) = bounds.iter().find_map(|bound| match *bound { + ast::GenericBound::Use(_, span) => Some(span), + _ => None, + }) { self.tcx.dcx().emit_err(errors::NoPreciseCapturesOnApit { span }); - }; + } + let span = t.span; // HACK: pprust breaks strings with newlines when the type @@ -1517,7 +1526,6 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> { bounds: &GenericBounds, fn_kind: Option<FnDeclKind>, itctx: ImplTraitContext, - precise_capturing_args: Option<(&[PreciseCapturingArg], Span)>, ) -> hir::TyKind<'hir> { // Make sure we know that some funky desugaring has been going on here. // This is a first: there is code in other places like for loop @@ -1526,59 +1534,64 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> { // frequently opened issues show. let opaque_ty_span = self.mark_span_with_reason(DesugaringKind::OpaqueTy, span, None); - let captured_lifetimes_to_duplicate = - if let Some((precise_capturing, _)) = precise_capturing_args { - // We'll actually validate these later on; all we need is the list of - // lifetimes to duplicate during this portion of lowering. - precise_capturing - .iter() - .filter_map(|arg| match arg { - PreciseCapturingArg::Lifetime(lt) => Some(*lt), - PreciseCapturingArg::Arg(..) => None, - }) - // Add in all the lifetimes mentioned in the bounds. We will error - // them out later, but capturing them here is important to make sure - // they actually get resolved in resolve_bound_vars. - .chain(lifetime_collector::lifetimes_in_bounds(self.resolver, bounds)) - .collect() - } else { - match origin { - hir::OpaqueTyOrigin::TyAlias { .. } => { - // type alias impl trait and associated type position impl trait were - // decided to capture all in-scope lifetimes, which we collect for - // all opaques during resolution. + let captured_lifetimes_to_duplicate = if let Some(args) = + // We only look for one `use<...>` syntax since we syntactially reject more than one. + bounds.iter().find_map( + |bound| match bound { + ast::GenericBound::Use(a, _) => Some(a), + _ => None, + }, + ) { + // We'll actually validate these later on; all we need is the list of + // lifetimes to duplicate during this portion of lowering. + args.iter() + .filter_map(|arg| match arg { + PreciseCapturingArg::Lifetime(lt) => Some(*lt), + PreciseCapturingArg::Arg(..) => None, + }) + // Add in all the lifetimes mentioned in the bounds. We will error + // them out later, but capturing them here is important to make sure + // they actually get resolved in resolve_bound_vars. + .chain(lifetime_collector::lifetimes_in_bounds(self.resolver, bounds)) + .collect() + } else { + match origin { + hir::OpaqueTyOrigin::TyAlias { .. } => { + // type alias impl trait and associated type position impl trait were + // decided to capture all in-scope lifetimes, which we collect for + // all opaques during resolution. + self.resolver + .take_extra_lifetime_params(opaque_ty_node_id) + .into_iter() + .map(|(ident, id, _)| Lifetime { id, ident }) + .collect() + } + hir::OpaqueTyOrigin::FnReturn(..) => { + if matches!( + fn_kind.expect("expected RPITs to be lowered with a FnKind"), + FnDeclKind::Impl | FnDeclKind::Trait + ) || self.tcx.features().lifetime_capture_rules_2024 + || span.at_least_rust_2024() + { + // return-position impl trait in trait was decided to capture all + // in-scope lifetimes, which we collect for all opaques during resolution. self.resolver .take_extra_lifetime_params(opaque_ty_node_id) .into_iter() .map(|(ident, id, _)| Lifetime { id, ident }) .collect() - } - hir::OpaqueTyOrigin::FnReturn(..) => { - if matches!( - fn_kind.expect("expected RPITs to be lowered with a FnKind"), - FnDeclKind::Impl | FnDeclKind::Trait - ) || self.tcx.features().lifetime_capture_rules_2024 - || span.at_least_rust_2024() - { - // return-position impl trait in trait was decided to capture all - // in-scope lifetimes, which we collect for all opaques during resolution. - self.resolver - .take_extra_lifetime_params(opaque_ty_node_id) - .into_iter() - .map(|(ident, id, _)| Lifetime { id, ident }) - .collect() - } else { - // in fn return position, like the `fn test<'a>() -> impl Debug + 'a` - // example, we only need to duplicate lifetimes that appear in the - // bounds, since those are the only ones that are captured by the opaque. - lifetime_collector::lifetimes_in_bounds(self.resolver, bounds) - } - } - hir::OpaqueTyOrigin::AsyncFn(..) => { - unreachable!("should be using `lower_async_fn_ret_ty`") + } else { + // in fn return position, like the `fn test<'a>() -> impl Debug + 'a` + // example, we only need to duplicate lifetimes that appear in the + // bounds, since those are the only ones that are captured by the opaque. + lifetime_collector::lifetimes_in_bounds(self.resolver, bounds) } } - }; + hir::OpaqueTyOrigin::AsyncFn(..) => { + unreachable!("should be using `lower_async_fn_ret_ty`") + } + } + }; debug!(?captured_lifetimes_to_duplicate); self.lower_opaque_inner( @@ -1588,7 +1601,6 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> { captured_lifetimes_to_duplicate, span, opaque_ty_span, - precise_capturing_args, |this| this.lower_param_bounds(bounds, itctx), ) } @@ -1601,7 +1613,6 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> { captured_lifetimes_to_duplicate: FxIndexSet<Lifetime>, span: Span, opaque_ty_span: Span, - precise_capturing_args: Option<(&[PreciseCapturingArg], Span)>, lower_item_bounds: impl FnOnce(&mut Self) -> &'hir [hir::GenericBound<'hir>], ) -> hir::TyKind<'hir> { let opaque_ty_def_id = self.create_def( @@ -1688,18 +1699,8 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> { // Install the remapping from old to new (if any). This makes sure that // any lifetimes that would have resolved to the def-id of captured // lifetimes are remapped to the new *synthetic* lifetimes of the opaque. - let (bounds, precise_capturing_args) = - this.with_remapping(captured_to_synthesized_mapping, |this| { - ( - lower_item_bounds(this), - precise_capturing_args.map(|(precise_capturing, span)| { - ( - this.lower_precise_capturing_args(precise_capturing), - this.lower_span(span), - ) - }), - ) - }); + let bounds = this + .with_remapping(captured_to_synthesized_mapping, |this| lower_item_bounds(this)); let generic_params = this.arena.alloc_from_iter(synthesized_lifetime_definitions.iter().map( @@ -1744,7 +1745,6 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> { origin, lifetime_mapping, in_trait, - precise_capturing_args, }; // Generate an `type Foo = impl Trait;` declaration. @@ -1955,7 +1955,6 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> { captured_lifetimes, span, opaque_ty_span, - None, |this| { let bound = this.lower_coroutine_fn_output_type_to_bound( output, @@ -2038,6 +2037,10 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> { GenericBound::Outlives(lifetime) => { hir::GenericBound::Outlives(self.lower_lifetime(lifetime)) } + GenericBound::Use(args, span) => hir::GenericBound::Use( + self.lower_precise_capturing_args(args), + self.lower_span(*span), + ), } } diff --git a/compiler/rustc_ast_passes/messages.ftl b/compiler/rustc_ast_passes/messages.ftl index 9a8689e27c0..2626631d800 100644 --- a/compiler/rustc_ast_passes/messages.ftl +++ b/compiler/rustc_ast_passes/messages.ftl @@ -215,6 +215,11 @@ ast_passes_pattern_in_fn_pointer = patterns aren't allowed in function pointer t ast_passes_pattern_in_foreign = patterns aren't allowed in foreign function declarations .label = pattern not allowed in foreign function +ast_passes_precise_capturing_duplicated = duplicate `use<...>` precise capturing syntax + .label = second `use<...>` here + +ast_passes_precise_capturing_not_allowed_here = `use<...>` precise capturing syntax not allowed in {$loc} + ast_passes_show_span = {$msg} ast_passes_stability_outside_std = stability attributes may not be used outside of the standard library diff --git a/compiler/rustc_ast_passes/src/ast_validation.rs b/compiler/rustc_ast_passes/src/ast_validation.rs index 0fbb288cc96..b274a9b9114 100644 --- a/compiler/rustc_ast_passes/src/ast_validation.rs +++ b/compiler/rustc_ast_passes/src/ast_validation.rs @@ -12,6 +12,7 @@ use rustc_ast::visit::{walk_list, AssocCtxt, BoundKind, FnCtxt, FnKind, Visitor} use rustc_ast::*; use rustc_ast_pretty::pprust::{self, State}; use rustc_data_structures::fx::FxIndexMap; +use rustc_errors::DiagCtxtHandle; use rustc_feature::Features; use rustc_parse::validate_attr; use rustc_session::lint::builtin::{ @@ -193,8 +194,24 @@ impl<'a> AstValidator<'a> { // Mirrors `visit::walk_ty`, but tracks relevant state. fn walk_ty(&mut self, t: &'a Ty) { match &t.kind { - TyKind::ImplTrait(..) => { - self.with_impl_trait(Some(t.span), |this| visit::walk_ty(this, t)) + TyKind::ImplTrait(_, bounds) => { + self.with_impl_trait(Some(t.span), |this| visit::walk_ty(this, t)); + + // FIXME(precise_capturing): If we were to allow `use` in other positions + // (e.g. GATs), then we must validate those as well. However, we don't have + // a good way of doing this with the current `Visitor` structure. + let mut use_bounds = bounds + .iter() + .filter_map(|bound| match bound { + GenericBound::Use(_, span) => Some(span), + _ => None, + }) + .copied(); + if let Some(bound1) = use_bounds.next() + && let Some(bound2) = use_bounds.next() + { + self.dcx().emit_err(errors::DuplicatePreciseCapturing { bound1, bound2 }); + } } TyKind::TraitObject(..) => self .with_tilde_const(Some(DisallowTildeConstContext::TraitObject), |this| { @@ -253,7 +270,7 @@ impl<'a> AstValidator<'a> { } } - fn dcx(&self) -> &rustc_errors::DiagCtxt { + fn dcx(&self) -> DiagCtxtHandle<'a> { self.session.dcx() } @@ -751,7 +768,7 @@ impl<'a> AstValidator<'a> { } } } - TyKind::ImplTrait(_, bounds, _) => { + TyKind::ImplTrait(_, bounds) => { if self.is_impl_trait_banned { self.dcx().emit_err(errors::ImplTraitPath { span: ty.span }); } @@ -793,11 +810,7 @@ impl<'a> AstValidator<'a> { /// Checks that generic parameters are in the correct order, /// which is lifetimes, then types and then consts. (`<'a, T, const N: usize>`) -fn validate_generic_param_order( - dcx: &rustc_errors::DiagCtxt, - generics: &[GenericParam], - span: Span, -) { +fn validate_generic_param_order(dcx: DiagCtxtHandle<'_>, generics: &[GenericParam], span: Span) { let mut max_param: Option<ParamKindOrd> = None; let mut out_of_order = FxIndexMap::default(); let mut param_idents = Vec::with_capacity(generics.len()); @@ -1304,6 +1317,7 @@ impl<'a> Visitor<'a> for AstValidator<'a> { } } GenericBound::Outlives(_) => {} + GenericBound::Use(..) => {} } } } @@ -1322,95 +1336,110 @@ impl<'a> Visitor<'a> for AstValidator<'a> { } fn visit_param_bound(&mut self, bound: &'a GenericBound, ctxt: BoundKind) { - if let GenericBound::Trait(poly, modifiers) = bound { - match (ctxt, modifiers.constness, modifiers.polarity) { - (BoundKind::SuperTraits, BoundConstness::Never, BoundPolarity::Maybe(_)) => { - self.dcx().emit_err(errors::OptionalTraitSupertrait { - span: poly.span, - path_str: pprust::path_to_string(&poly.trait_ref.path), - }); - } - (BoundKind::TraitObject, BoundConstness::Never, BoundPolarity::Maybe(_)) => { - self.dcx().emit_err(errors::OptionalTraitObject { span: poly.span }); - } - (BoundKind::TraitObject, BoundConstness::Always(_), BoundPolarity::Positive) => { - self.dcx().emit_err(errors::ConstBoundTraitObject { span: poly.span }); + match bound { + GenericBound::Trait(trait_ref, modifiers) => { + match (ctxt, modifiers.constness, modifiers.polarity) { + (BoundKind::SuperTraits, BoundConstness::Never, BoundPolarity::Maybe(_)) => { + self.dcx().emit_err(errors::OptionalTraitSupertrait { + span: trait_ref.span, + path_str: pprust::path_to_string(&trait_ref.trait_ref.path), + }); + } + (BoundKind::TraitObject, BoundConstness::Never, BoundPolarity::Maybe(_)) => { + self.dcx().emit_err(errors::OptionalTraitObject { span: trait_ref.span }); + } + ( + BoundKind::TraitObject, + BoundConstness::Always(_), + BoundPolarity::Positive, + ) => { + self.dcx().emit_err(errors::ConstBoundTraitObject { span: trait_ref.span }); + } + (_, BoundConstness::Maybe(span), BoundPolarity::Positive) + if let Some(reason) = &self.disallow_tilde_const => + { + let reason = match reason { + DisallowTildeConstContext::Fn(FnKind::Closure(..)) => { + errors::TildeConstReason::Closure + } + DisallowTildeConstContext::Fn(FnKind::Fn(_, ident, ..)) => { + errors::TildeConstReason::Function { ident: ident.span } + } + &DisallowTildeConstContext::Trait(span) => { + errors::TildeConstReason::Trait { span } + } + &DisallowTildeConstContext::TraitImpl(span) => { + errors::TildeConstReason::TraitImpl { span } + } + &DisallowTildeConstContext::Impl(span) => { + // FIXME(effects): Consider providing a help message or even a structured + // suggestion for moving such bounds to the assoc const fns if available. + errors::TildeConstReason::Impl { span } + } + &DisallowTildeConstContext::TraitAssocTy(span) => { + errors::TildeConstReason::TraitAssocTy { span } + } + &DisallowTildeConstContext::TraitImplAssocTy(span) => { + errors::TildeConstReason::TraitImplAssocTy { span } + } + &DisallowTildeConstContext::InherentAssocTy(span) => { + errors::TildeConstReason::InherentAssocTy { span } + } + DisallowTildeConstContext::TraitObject => { + errors::TildeConstReason::TraitObject + } + DisallowTildeConstContext::Item => errors::TildeConstReason::Item, + }; + self.dcx().emit_err(errors::TildeConstDisallowed { span, reason }); + } + ( + _, + BoundConstness::Always(_) | BoundConstness::Maybe(_), + BoundPolarity::Negative(_) | BoundPolarity::Maybe(_), + ) => { + self.dcx().emit_err(errors::IncompatibleTraitBoundModifiers { + span: bound.span(), + left: modifiers.constness.as_str(), + right: modifiers.polarity.as_str(), + }); + } + _ => {} } - (_, BoundConstness::Maybe(span), BoundPolarity::Positive) - if let Some(reason) = &self.disallow_tilde_const => + + // Negative trait bounds are not allowed to have associated constraints + if let BoundPolarity::Negative(_) = modifiers.polarity + && let Some(segment) = trait_ref.trait_ref.path.segments.last() { - let reason = match reason { - DisallowTildeConstContext::Fn(FnKind::Closure(..)) => { - errors::TildeConstReason::Closure - } - DisallowTildeConstContext::Fn(FnKind::Fn(_, ident, ..)) => { - errors::TildeConstReason::Function { ident: ident.span } - } - &DisallowTildeConstContext::Trait(span) => { - errors::TildeConstReason::Trait { span } - } - &DisallowTildeConstContext::TraitImpl(span) => { - errors::TildeConstReason::TraitImpl { span } - } - &DisallowTildeConstContext::Impl(span) => { - // FIXME(effects): Consider providing a help message or even a structured - // suggestion for moving such bounds to the assoc const fns if available. - errors::TildeConstReason::Impl { span } - } - &DisallowTildeConstContext::TraitAssocTy(span) => { - errors::TildeConstReason::TraitAssocTy { span } - } - &DisallowTildeConstContext::TraitImplAssocTy(span) => { - errors::TildeConstReason::TraitImplAssocTy { span } - } - &DisallowTildeConstContext::InherentAssocTy(span) => { - errors::TildeConstReason::InherentAssocTy { span } - } - DisallowTildeConstContext::TraitObject => { - errors::TildeConstReason::TraitObject + match segment.args.as_deref() { + Some(ast::GenericArgs::AngleBracketed(args)) => { + for arg in &args.args { + if let ast::AngleBracketedArg::Constraint(constraint) = arg { + self.dcx().emit_err(errors::ConstraintOnNegativeBound { + span: constraint.span, + }); + } + } } - DisallowTildeConstContext::Item => errors::TildeConstReason::Item, - }; - self.dcx().emit_err(errors::TildeConstDisallowed { span, reason }); - } - ( - _, - BoundConstness::Always(_) | BoundConstness::Maybe(_), - BoundPolarity::Negative(_) | BoundPolarity::Maybe(_), - ) => { - self.dcx().emit_err(errors::IncompatibleTraitBoundModifiers { - span: bound.span(), - left: modifiers.constness.as_str(), - right: modifiers.polarity.as_str(), - }); - } - _ => {} - } - } - - // Negative trait bounds are not allowed to have associated constraints - if let GenericBound::Trait(trait_ref, modifiers) = bound - && let BoundPolarity::Negative(_) = modifiers.polarity - && let Some(segment) = trait_ref.trait_ref.path.segments.last() - { - match segment.args.as_deref() { - Some(ast::GenericArgs::AngleBracketed(args)) => { - for arg in &args.args { - if let ast::AngleBracketedArg::Constraint(constraint) = arg { - self.dcx().emit_err(errors::ConstraintOnNegativeBound { - span: constraint.span, + // The lowered form of parenthesized generic args contains an associated type binding. + Some(ast::GenericArgs::Parenthesized(args)) => { + self.dcx().emit_err(errors::NegativeBoundWithParentheticalNotation { + span: args.span, }); } + None => {} } } - // The lowered form of parenthesized generic args contains an associated type binding. - Some(ast::GenericArgs::Parenthesized(args)) => { - self.dcx().emit_err(errors::NegativeBoundWithParentheticalNotation { - span: args.span, + } + GenericBound::Outlives(_) => {} + GenericBound::Use(_, span) => match ctxt { + BoundKind::Impl => {} + BoundKind::Bound | BoundKind::TraitObject | BoundKind::SuperTraits => { + self.dcx().emit_err(errors::PreciseCapturingNotAllowedHere { + loc: ctxt.descr(), + span: *span, }); } - None => {} - } + }, } visit::walk_param_bound(self, bound) diff --git a/compiler/rustc_ast_passes/src/errors.rs b/compiler/rustc_ast_passes/src/errors.rs index 260c182bd9e..601910ded20 100644 --- a/compiler/rustc_ast_passes/src/errors.rs +++ b/compiler/rustc_ast_passes/src/errors.rs @@ -844,3 +844,20 @@ pub struct MatchArmWithNoBody { #[suggestion(code = " => todo!(),", applicability = "has-placeholders")] pub suggestion: Span, } + +#[derive(Diagnostic)] +#[diag(ast_passes_precise_capturing_not_allowed_here)] +pub struct PreciseCapturingNotAllowedHere { + #[primary_span] + pub span: Span, + pub loc: &'static str, +} + +#[derive(Diagnostic)] +#[diag(ast_passes_precise_capturing_duplicated)] +pub struct DuplicatePreciseCapturing { + #[primary_span] + pub bound1: Span, + #[label] + pub bound2: Span, +} diff --git a/compiler/rustc_ast_passes/src/show_span.rs b/compiler/rustc_ast_passes/src/show_span.rs index 10590074282..e7ba2e7fc30 100644 --- a/compiler/rustc_ast_passes/src/show_span.rs +++ b/compiler/rustc_ast_passes/src/show_span.rs @@ -8,6 +8,7 @@ use std::str::FromStr; use rustc_ast as ast; use rustc_ast::visit; use rustc_ast::visit::Visitor; +use rustc_errors::DiagCtxtHandle; use crate::errors; @@ -31,7 +32,7 @@ impl FromStr for Mode { } struct ShowSpanVisitor<'a> { - dcx: &'a rustc_errors::DiagCtxt, + dcx: DiagCtxtHandle<'a>, mode: Mode, } @@ -58,7 +59,7 @@ impl<'a> Visitor<'a> for ShowSpanVisitor<'a> { } } -pub fn run(dcx: &rustc_errors::DiagCtxt, mode: &str, krate: &ast::Crate) { +pub fn run(dcx: DiagCtxtHandle<'_>, mode: &str, krate: &ast::Crate) { let Ok(mode) = mode.parse() else { return; }; diff --git a/compiler/rustc_ast_pretty/src/pprust/state.rs b/compiler/rustc_ast_pretty/src/pprust/state.rs index 4eb2a103fd8..0225c95dca8 100644 --- a/compiler/rustc_ast_pretty/src/pprust/state.rs +++ b/compiler/rustc_ast_pretty/src/pprust/state.rs @@ -1187,17 +1187,8 @@ impl<'a> State<'a> { } self.print_type_bounds(bounds); } - ast::TyKind::ImplTrait(_, bounds, precise_capturing_args) => { + ast::TyKind::ImplTrait(_, bounds) => { self.word_nbsp("impl"); - if let Some((precise_capturing_args, ..)) = precise_capturing_args.as_deref() { - self.word("use"); - self.word("<"); - self.commasep(Inconsistent, precise_capturing_args, |s, arg| match arg { - ast::PreciseCapturingArg::Arg(p, _) => s.print_path(p, false, 0), - ast::PreciseCapturingArg::Lifetime(lt) => s.print_lifetime(*lt), - }); - self.word(">") - } self.print_type_bounds(bounds); } ast::TyKind::Array(ty, length) => { @@ -1800,6 +1791,15 @@ impl<'a> State<'a> { self.print_poly_trait_ref(tref); } GenericBound::Outlives(lt) => self.print_lifetime(*lt), + GenericBound::Use(args, _) => { + self.word("use"); + self.word("<"); + self.commasep(Inconsistent, args, |s, arg| match arg { + ast::PreciseCapturingArg::Arg(p, _) => s.print_path(p, false, 0), + ast::PreciseCapturingArg::Lifetime(lt) => s.print_lifetime(*lt), + }); + self.word(">") + } } } } diff --git a/compiler/rustc_ast_pretty/src/pprust/state/item.rs b/compiler/rustc_ast_pretty/src/pprust/state/item.rs index 474741fb067..49ac5ece337 100644 --- a/compiler/rustc_ast_pretty/src/pprust/state/item.rs +++ b/compiler/rustc_ast_pretty/src/pprust/state/item.rs @@ -9,6 +9,12 @@ use rustc_ast::ptr::P; use rustc_ast::ModKind; use rustc_span::symbol::Ident; +enum DelegationKind<'a> { + Single, + List(&'a [(Ident, Option<Ident>)]), + Glob, +} + fn visibility_qualified(vis: &ast::Visibility, s: &str) -> String { format!("{}{}", State::to_string(|s| s.print_visibility(vis)), s) } @@ -387,7 +393,7 @@ impl<'a> State<'a> { &item.vis, &deleg.qself, &deleg.path, - None, + DelegationKind::Single, &deleg.body, ), ast::ItemKind::DelegationMac(deleg) => self.print_delegation( @@ -395,7 +401,7 @@ impl<'a> State<'a> { &item.vis, &deleg.qself, &deleg.prefix, - Some(&deleg.suffixes), + deleg.suffixes.as_ref().map_or(DelegationKind::Glob, |s| DelegationKind::List(s)), &deleg.body, ), } @@ -579,7 +585,7 @@ impl<'a> State<'a> { vis, &deleg.qself, &deleg.path, - None, + DelegationKind::Single, &deleg.body, ), ast::AssocItemKind::DelegationMac(deleg) => self.print_delegation( @@ -587,20 +593,20 @@ impl<'a> State<'a> { vis, &deleg.qself, &deleg.prefix, - Some(&deleg.suffixes), + deleg.suffixes.as_ref().map_or(DelegationKind::Glob, |s| DelegationKind::List(s)), &deleg.body, ), } self.ann.post(self, AnnNode::SubItem(id)) } - pub(crate) fn print_delegation( + fn print_delegation( &mut self, attrs: &[ast::Attribute], vis: &ast::Visibility, qself: &Option<P<ast::QSelf>>, path: &ast::Path, - suffixes: Option<&[(Ident, Option<Ident>)]>, + kind: DelegationKind<'_>, body: &Option<P<ast::Block>>, ) { if body.is_some() { @@ -614,21 +620,28 @@ impl<'a> State<'a> { } else { self.print_path(path, false, 0); } - if let Some(suffixes) = suffixes { - self.word("::"); - self.word("{"); - for (i, (ident, rename)) in suffixes.iter().enumerate() { - self.print_ident(*ident); - if let Some(rename) = rename { - self.nbsp(); - self.word_nbsp("as"); - self.print_ident(*rename); - } - if i != suffixes.len() - 1 { - self.word_space(","); + match kind { + DelegationKind::Single => {} + DelegationKind::List(suffixes) => { + self.word("::"); + self.word("{"); + for (i, (ident, rename)) in suffixes.iter().enumerate() { + self.print_ident(*ident); + if let Some(rename) = rename { + self.nbsp(); + self.word_nbsp("as"); + self.print_ident(*rename); + } + if i != suffixes.len() - 1 { + self.word_space(","); + } } + self.word("}"); + } + DelegationKind::Glob => { + self.word("::"); + self.word("*"); } - self.word("}"); } if let Some(body) = body { self.nbsp(); diff --git a/compiler/rustc_attr/src/builtin.rs b/compiler/rustc_attr/src/builtin.rs index 5113c5adc8f..34c24a26f7b 100644 --- a/compiler/rustc_attr/src/builtin.rs +++ b/compiler/rustc_attr/src/builtin.rs @@ -596,7 +596,7 @@ pub fn eval_condition( features: Option<&Features>, eval: &mut impl FnMut(Condition) -> bool, ) -> bool { - let dcx = &sess.psess.dcx; + let dcx = sess.dcx(); match &cfg.kind { ast::MetaItemKind::List(mis) if cfg.name_or_empty() == sym::version => { try_gate_cfg(sym::version, cfg.span, sess, features); diff --git a/compiler/rustc_attr/src/session_diagnostics.rs b/compiler/rustc_attr/src/session_diagnostics.rs index 303909de343..0cffeed0a75 100644 --- a/compiler/rustc_attr/src/session_diagnostics.rs +++ b/compiler/rustc_attr/src/session_diagnostics.rs @@ -1,7 +1,8 @@ use std::num::IntErrorKind; use rustc_ast as ast; -use rustc_errors::{codes::*, Applicability, Diag, DiagCtxt, Diagnostic, EmissionGuarantee, Level}; +use rustc_errors::DiagCtxtHandle; +use rustc_errors::{codes::*, Applicability, Diag, Diagnostic, EmissionGuarantee, Level}; use rustc_macros::{Diagnostic, Subdiagnostic}; use rustc_span::{Span, Symbol}; @@ -49,7 +50,7 @@ pub(crate) struct UnknownMetaItem<'a> { // Manual implementation to be able to format `expected` items correctly. impl<'a, G: EmissionGuarantee> Diagnostic<'a, G> for UnknownMetaItem<'_> { - fn into_diag(self, dcx: &'a DiagCtxt, level: Level) -> Diag<'a, G> { + fn into_diag(self, dcx: DiagCtxtHandle<'a>, level: Level) -> Diag<'a, G> { let expected = self.expected.iter().map(|name| format!("`{name}`")).collect::<Vec<_>>(); Diag::new(dcx, level, fluent::attr_unknown_meta_item) .with_span(self.span) @@ -202,7 +203,7 @@ pub(crate) struct UnsupportedLiteral { } impl<'a, G: EmissionGuarantee> Diagnostic<'a, G> for UnsupportedLiteral { - fn into_diag(self, dcx: &'a DiagCtxt, level: Level) -> Diag<'a, G> { + fn into_diag(self, dcx: DiagCtxtHandle<'a>, level: Level) -> Diag<'a, G> { let mut diag = Diag::new( dcx, level, diff --git a/compiler/rustc_borrowck/src/borrowck_errors.rs b/compiler/rustc_borrowck/src/borrowck_errors.rs index 622feb4e4c7..c1f75328272 100644 --- a/compiler/rustc_borrowck/src/borrowck_errors.rs +++ b/compiler/rustc_borrowck/src/borrowck_errors.rs @@ -1,13 +1,13 @@ #![allow(rustc::diagnostic_outside_of_impl)] #![allow(rustc::untranslatable_diagnostic)] -use rustc_errors::{codes::*, struct_span_code_err, Diag, DiagCtxt}; +use rustc_errors::{codes::*, struct_span_code_err, Diag, DiagCtxtHandle}; use rustc_middle::span_bug; use rustc_middle::ty::{self, Ty, TyCtxt}; use rustc_span::Span; impl<'cx, 'tcx> crate::MirBorrowckCtxt<'cx, 'tcx> { - pub fn dcx(&self) -> &'tcx DiagCtxt { + pub fn dcx(&self) -> DiagCtxtHandle<'tcx> { self.infcx.dcx() } diff --git a/compiler/rustc_borrowck/src/diagnostics/conflict_errors.rs b/compiler/rustc_borrowck/src/diagnostics/conflict_errors.rs index 6bc340e44f5..197da3eb641 100644 --- a/compiler/rustc_borrowck/src/diagnostics/conflict_errors.rs +++ b/compiler/rustc_borrowck/src/diagnostics/conflict_errors.rs @@ -228,7 +228,7 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> { seen_spans.insert(move_span); } - use_spans.var_path_only_subdiag(self.dcx(), &mut err, desired_action); + use_spans.var_path_only_subdiag(&mut err, desired_action); if !is_loop_move { err.span_label( @@ -303,24 +303,18 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> { if needs_note { if let Some(local) = place.as_local() { let span = self.body.local_decls[local].source_info.span; - err.subdiagnostic( - self.dcx(), - crate::session_diagnostics::TypeNoCopy::Label { - is_partial_move, - ty, - place: ¬e_msg, - span, - }, - ); + err.subdiagnostic(crate::session_diagnostics::TypeNoCopy::Label { + is_partial_move, + ty, + place: ¬e_msg, + span, + }); } else { - err.subdiagnostic( - self.dcx(), - crate::session_diagnostics::TypeNoCopy::Note { - is_partial_move, - ty, - place: ¬e_msg, - }, - ); + err.subdiagnostic(crate::session_diagnostics::TypeNoCopy::Note { + is_partial_move, + ty, + place: ¬e_msg, + }); }; } @@ -597,7 +591,7 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> { E0381, "{used} binding {desc}{isnt_initialized}" ); - use_spans.var_path_only_subdiag(self.dcx(), &mut err, desired_action); + use_spans.var_path_only_subdiag(&mut err, desired_action); if let InitializationRequiringAction::PartialAssignment | InitializationRequiringAction::Assignment = desired_action @@ -996,7 +990,7 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> { &self, err: &mut Diag<'_>, ty: Ty<'tcx>, - expr: &'cx hir::Expr<'cx>, + expr: &hir::Expr<'_>, ) { let typeck_results = self.infcx.tcx.typeck(self.mir_def_id()); let hir::ExprKind::Struct(struct_qpath, fields, Some(base)) = expr.kind else { return }; @@ -1084,8 +1078,8 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> { &self, err: &mut Diag<'_>, ty: Ty<'tcx>, - mut expr: &'cx hir::Expr<'cx>, - mut other_expr: Option<&'cx hir::Expr<'cx>>, + mut expr: &'tcx hir::Expr<'tcx>, + mut other_expr: Option<&'tcx hir::Expr<'tcx>>, use_spans: Option<UseSpans<'tcx>>, ) { if let hir::ExprKind::Struct(_, _, Some(_)) = expr.kind { @@ -1410,13 +1404,9 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> { &value_msg, ); - borrow_spans.var_path_only_subdiag( - self.dcx(), - &mut err, - crate::InitializationRequiringAction::Borrow, - ); + borrow_spans.var_path_only_subdiag(&mut err, crate::InitializationRequiringAction::Borrow); - move_spans.var_subdiag(self.dcx(), &mut err, None, |kind, var_span| { + move_spans.var_subdiag(&mut err, None, |kind, var_span| { use crate::session_diagnostics::CaptureVarCause::*; match kind { hir::ClosureKind::Coroutine(_) => MoveUseInCoroutine { var_span }, @@ -1468,7 +1458,7 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> { borrow_span, &self.describe_any_place(borrow.borrowed_place.as_ref()), ); - borrow_spans.var_subdiag(self.dcx(), &mut err, Some(borrow.kind), |kind, var_span| { + borrow_spans.var_subdiag(&mut err, Some(borrow.kind), |kind, var_span| { use crate::session_diagnostics::CaptureVarCause::*; let place = &borrow.borrowed_place; let desc_place = self.describe_any_place(place.as_ref()); @@ -1633,7 +1623,6 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> { "mutably borrow", ); borrow_spans.var_subdiag( - self.dcx(), &mut err, Some(BorrowKind::Mut { kind: MutBorrowKind::ClosureCapture }), |kind, var_span| { @@ -1730,64 +1719,45 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> { }; if issued_spans == borrow_spans { - borrow_spans.var_subdiag( - self.dcx(), - &mut err, - Some(gen_borrow_kind), - |kind, var_span| { - use crate::session_diagnostics::CaptureVarCause::*; - match kind { - hir::ClosureKind::Coroutine(_) => BorrowUsePlaceCoroutine { - place: desc_place, - var_span, - is_single_var: false, - }, - hir::ClosureKind::Closure | hir::ClosureKind::CoroutineClosure(_) => { - BorrowUsePlaceClosure { - place: desc_place, - var_span, - is_single_var: false, - } - } + borrow_spans.var_subdiag(&mut err, Some(gen_borrow_kind), |kind, var_span| { + use crate::session_diagnostics::CaptureVarCause::*; + match kind { + hir::ClosureKind::Coroutine(_) => BorrowUsePlaceCoroutine { + place: desc_place, + var_span, + is_single_var: false, + }, + hir::ClosureKind::Closure | hir::ClosureKind::CoroutineClosure(_) => { + BorrowUsePlaceClosure { place: desc_place, var_span, is_single_var: false } } - }, - ); + } + }); } else { - issued_spans.var_subdiag( - self.dcx(), - &mut err, - Some(issued_borrow.kind), - |kind, var_span| { - use crate::session_diagnostics::CaptureVarCause::*; - let borrow_place = &issued_borrow.borrowed_place; - let borrow_place_desc = self.describe_any_place(borrow_place.as_ref()); - match kind { - hir::ClosureKind::Coroutine(_) => { - FirstBorrowUsePlaceCoroutine { place: borrow_place_desc, var_span } - } - hir::ClosureKind::Closure | hir::ClosureKind::CoroutineClosure(_) => { - FirstBorrowUsePlaceClosure { place: borrow_place_desc, var_span } - } + issued_spans.var_subdiag(&mut err, Some(issued_borrow.kind), |kind, var_span| { + use crate::session_diagnostics::CaptureVarCause::*; + let borrow_place = &issued_borrow.borrowed_place; + let borrow_place_desc = self.describe_any_place(borrow_place.as_ref()); + match kind { + hir::ClosureKind::Coroutine(_) => { + FirstBorrowUsePlaceCoroutine { place: borrow_place_desc, var_span } } - }, - ); + hir::ClosureKind::Closure | hir::ClosureKind::CoroutineClosure(_) => { + FirstBorrowUsePlaceClosure { place: borrow_place_desc, var_span } + } + } + }); - borrow_spans.var_subdiag( - self.dcx(), - &mut err, - Some(gen_borrow_kind), - |kind, var_span| { - use crate::session_diagnostics::CaptureVarCause::*; - match kind { - hir::ClosureKind::Coroutine(_) => { - SecondBorrowUsePlaceCoroutine { place: desc_place, var_span } - } - hir::ClosureKind::Closure | hir::ClosureKind::CoroutineClosure(_) => { - SecondBorrowUsePlaceClosure { place: desc_place, var_span } - } + borrow_spans.var_subdiag(&mut err, Some(gen_borrow_kind), |kind, var_span| { + use crate::session_diagnostics::CaptureVarCause::*; + match kind { + hir::ClosureKind::Coroutine(_) => { + SecondBorrowUsePlaceCoroutine { place: desc_place, var_span } } - }, - ); + hir::ClosureKind::Closure | hir::ClosureKind::CoroutineClosure(_) => { + SecondBorrowUsePlaceClosure { place: desc_place, var_span } + } + } + }); } if union_type_name != "" { @@ -2016,7 +1986,7 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> { ); } - pub(crate) fn find_expr(&self, span: Span) -> Option<&hir::Expr<'_>> { + pub(crate) fn find_expr(&self, span: Span) -> Option<&'tcx hir::Expr<'tcx>> { let tcx = self.infcx.tcx; let body_id = tcx.hir_node(self.mir_hir_id()).body_id()?; let mut expr_finder = FindExprBySpan::new(span, tcx); @@ -2961,7 +2931,7 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> { err.span_label(borrow_span, "borrowed value does not live long enough"); err.span_label(drop_span, format!("`{name}` dropped here while still borrowed")); - borrow_spans.args_subdiag(self.dcx(), &mut err, |args_span| { + borrow_spans.args_subdiag(&mut err, |args_span| { crate::session_diagnostics::CaptureArgLabel::Capture { is_within: borrow_spans.for_coroutine(), args_span, @@ -3219,7 +3189,7 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> { None, ); - borrow_spans.args_subdiag(self.dcx(), &mut err, |args_span| { + borrow_spans.args_subdiag(&mut err, |args_span| { crate::session_diagnostics::CaptureArgLabel::Capture { is_within: borrow_spans.for_coroutine(), args_span, @@ -3680,7 +3650,7 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> { "assign", ); - loan_spans.var_subdiag(self.dcx(), &mut err, Some(loan.kind), |kind, var_span| { + loan_spans.var_subdiag(&mut err, Some(loan.kind), |kind, var_span| { use crate::session_diagnostics::CaptureVarCause::*; match kind { hir::ClosureKind::Coroutine(_) => BorrowUseInCoroutine { var_span }, @@ -3698,7 +3668,7 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> { let mut err = self.cannot_assign_to_borrowed(span, loan_span, &descr_place); - loan_spans.var_subdiag(self.dcx(), &mut err, Some(loan.kind), |kind, var_span| { + loan_spans.var_subdiag(&mut err, Some(loan.kind), |kind, var_span| { use crate::session_diagnostics::CaptureVarCause::*; match kind { hir::ClosureKind::Coroutine(_) => BorrowUseInCoroutine { var_span }, diff --git a/compiler/rustc_borrowck/src/diagnostics/mod.rs b/compiler/rustc_borrowck/src/diagnostics/mod.rs index abb0b5afbd8..5b4269caccb 100644 --- a/compiler/rustc_borrowck/src/diagnostics/mod.rs +++ b/compiler/rustc_borrowck/src/diagnostics/mod.rs @@ -4,8 +4,8 @@ use crate::session_diagnostics::{ CaptureArgLabel, CaptureReasonLabel, CaptureReasonNote, CaptureReasonSuggest, CaptureVarCause, CaptureVarKind, CaptureVarPathUseCause, OnClosureNote, }; +use rustc_errors::MultiSpan; use rustc_errors::{Applicability, Diag}; -use rustc_errors::{DiagCtxt, MultiSpan}; use rustc_hir::def::{CtorKind, Namespace}; use rustc_hir::CoroutineKind; use rustc_hir::{self as hir, LangItem}; @@ -130,16 +130,13 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> { if let ty::Closure(did, _) = self.body.local_decls[closure].ty.kind() { let did = did.expect_local(); if let Some((span, hir_place)) = self.infcx.tcx.closure_kind_origin(did) { - diag.subdiagnostic( - self.dcx(), - OnClosureNote::InvokedTwice { - place_name: &ty::place_to_string_for_capture( - self.infcx.tcx, - hir_place, - ), - span: *span, - }, - ); + diag.subdiagnostic(OnClosureNote::InvokedTwice { + place_name: &ty::place_to_string_for_capture( + self.infcx.tcx, + hir_place, + ), + span: *span, + }); return true; } } @@ -152,13 +149,10 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> { if let ty::Closure(did, _) = self.body.local_decls[target].ty.kind() { let did = did.expect_local(); if let Some((span, hir_place)) = self.infcx.tcx.closure_kind_origin(did) { - diag.subdiagnostic( - self.dcx(), - OnClosureNote::MovedTwice { - place_name: &ty::place_to_string_for_capture(self.infcx.tcx, hir_place), - span: *span, - }, - ); + diag.subdiagnostic(OnClosureNote::MovedTwice { + place_name: &ty::place_to_string_for_capture(self.infcx.tcx, hir_place), + span: *span, + }); return true; } } @@ -591,14 +585,9 @@ impl UseSpans<'_> { /// Add a span label to the arguments of the closure, if it exists. #[allow(rustc::diagnostic_outside_of_impl)] - pub(super) fn args_subdiag( - self, - dcx: &DiagCtxt, - err: &mut Diag<'_>, - f: impl FnOnce(Span) -> CaptureArgLabel, - ) { + pub(super) fn args_subdiag(self, err: &mut Diag<'_>, f: impl FnOnce(Span) -> CaptureArgLabel) { if let UseSpans::ClosureUse { args_span, .. } = self { - err.subdiagnostic(dcx, f(args_span)); + err.subdiagnostic(f(args_span)); } } @@ -607,7 +596,6 @@ impl UseSpans<'_> { #[allow(rustc::diagnostic_outside_of_impl)] pub(super) fn var_path_only_subdiag( self, - dcx: &DiagCtxt, err: &mut Diag<'_>, action: crate::InitializationRequiringAction, ) { @@ -616,26 +604,20 @@ impl UseSpans<'_> { if let UseSpans::ClosureUse { closure_kind, path_span, .. } = self { match closure_kind { hir::ClosureKind::Coroutine(_) => { - err.subdiagnostic( - dcx, - match action { - Borrow => BorrowInCoroutine { path_span }, - MatchOn | Use => UseInCoroutine { path_span }, - Assignment => AssignInCoroutine { path_span }, - PartialAssignment => AssignPartInCoroutine { path_span }, - }, - ); + err.subdiagnostic(match action { + Borrow => BorrowInCoroutine { path_span }, + MatchOn | Use => UseInCoroutine { path_span }, + Assignment => AssignInCoroutine { path_span }, + PartialAssignment => AssignPartInCoroutine { path_span }, + }); } hir::ClosureKind::Closure | hir::ClosureKind::CoroutineClosure(_) => { - err.subdiagnostic( - dcx, - match action { - Borrow => BorrowInClosure { path_span }, - MatchOn | Use => UseInClosure { path_span }, - Assignment => AssignInClosure { path_span }, - PartialAssignment => AssignPartInClosure { path_span }, - }, - ); + err.subdiagnostic(match action { + Borrow => BorrowInClosure { path_span }, + MatchOn | Use => UseInClosure { path_span }, + Assignment => AssignInClosure { path_span }, + PartialAssignment => AssignPartInClosure { path_span }, + }); } } } @@ -645,32 +627,28 @@ impl UseSpans<'_> { #[allow(rustc::diagnostic_outside_of_impl)] pub(super) fn var_subdiag( self, - dcx: &DiagCtxt, err: &mut Diag<'_>, kind: Option<rustc_middle::mir::BorrowKind>, f: impl FnOnce(hir::ClosureKind, Span) -> CaptureVarCause, ) { if let UseSpans::ClosureUse { closure_kind, capture_kind_span, path_span, .. } = self { if capture_kind_span != path_span { - err.subdiagnostic( - dcx, - match kind { - Some(kd) => match kd { - rustc_middle::mir::BorrowKind::Shared - | rustc_middle::mir::BorrowKind::Fake(_) => { - CaptureVarKind::Immut { kind_span: capture_kind_span } - } + err.subdiagnostic(match kind { + Some(kd) => match kd { + rustc_middle::mir::BorrowKind::Shared + | rustc_middle::mir::BorrowKind::Fake(_) => { + CaptureVarKind::Immut { kind_span: capture_kind_span } + } - rustc_middle::mir::BorrowKind::Mut { .. } => { - CaptureVarKind::Mut { kind_span: capture_kind_span } - } - }, - None => CaptureVarKind::Move { kind_span: capture_kind_span }, + rustc_middle::mir::BorrowKind::Mut { .. } => { + CaptureVarKind::Mut { kind_span: capture_kind_span } + } }, - ); + None => CaptureVarKind::Move { kind_span: capture_kind_span }, + }); }; let diag = f(closure_kind, path_span); - err.subdiagnostic(dcx, diag); + err.subdiagnostic(diag); } } @@ -1042,15 +1020,12 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> { CallKind::FnCall { fn_trait_id, self_ty } if self.infcx.tcx.is_lang_item(fn_trait_id, LangItem::FnOnce) => { - err.subdiagnostic( - self.dcx(), - CaptureReasonLabel::Call { - fn_call_span, - place_name: &place_name, - is_partial, - is_loop_message, - }, - ); + err.subdiagnostic(CaptureReasonLabel::Call { + fn_call_span, + place_name: &place_name, + is_partial, + is_loop_message, + }); // Check if the move occurs on a value because of a call on a closure that comes // from a type parameter `F: FnOnce()`. If so, we provide a targeted `note`: // ``` @@ -1119,27 +1094,20 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> { ); err.span_note(span, fluent::borrowck_moved_a_fn_once_in_call_call); } else { - err.subdiagnostic( - self.dcx(), - CaptureReasonNote::FnOnceMoveInCall { var_span }, - ); + err.subdiagnostic(CaptureReasonNote::FnOnceMoveInCall { var_span }); } } CallKind::Operator { self_arg, trait_id, .. } => { let self_arg = self_arg.unwrap(); - err.subdiagnostic( - self.dcx(), - CaptureReasonLabel::OperatorUse { - fn_call_span, - place_name: &place_name, - is_partial, - is_loop_message, - }, - ); + err.subdiagnostic(CaptureReasonLabel::OperatorUse { + fn_call_span, + place_name: &place_name, + is_partial, + is_loop_message, + }); if self.fn_self_span_reported.insert(fn_span) { let lang = self.infcx.tcx.lang_items(); err.subdiagnostic( - self.dcx(), if [lang.not_trait(), lang.deref_trait(), lang.neg_trait()] .contains(&Some(trait_id)) { @@ -1164,14 +1132,11 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> { ); let func = tcx.def_path_str(method_did); - err.subdiagnostic( - self.dcx(), - CaptureReasonNote::FuncTakeSelf { - func, - place_name: place_name.clone(), - span: self_arg.span, - }, - ); + err.subdiagnostic(CaptureReasonNote::FuncTakeSelf { + func, + place_name: place_name.clone(), + span: self_arg.span, + }); } let parent_did = tcx.parent(method_did); let parent_self_ty = @@ -1185,10 +1150,7 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> { matches!(tcx.get_diagnostic_name(def_id), Some(sym::Option | sym::Result)) }); if is_option_or_result && maybe_reinitialized_locations_is_empty { - err.subdiagnostic( - self.dcx(), - CaptureReasonLabel::BorrowContent { var_span }, - ); + err.subdiagnostic(CaptureReasonLabel::BorrowContent { var_span }); } if let Some((CallDesugaringKind::ForLoopIntoIter, _)) = desugaring { let ty = moved_place.ty(self.body, tcx).ty; @@ -1202,24 +1164,18 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> { _ => false, }; if suggest { - err.subdiagnostic( - self.dcx(), - CaptureReasonSuggest::IterateSlice { - ty, - span: move_span.shrink_to_lo(), - }, - ); + err.subdiagnostic(CaptureReasonSuggest::IterateSlice { + ty, + span: move_span.shrink_to_lo(), + }); } - err.subdiagnostic( - self.dcx(), - CaptureReasonLabel::ImplicitCall { - fn_call_span, - place_name: &place_name, - is_partial, - is_loop_message, - }, - ); + err.subdiagnostic(CaptureReasonLabel::ImplicitCall { + fn_call_span, + place_name: &place_name, + is_partial, + is_loop_message, + }); // If the moved place was a `&mut` ref, then we can // suggest to reborrow it where it was moved, so it // will still be valid by the time we get to the usage. @@ -1243,25 +1199,19 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> { } } else { if let Some((CallDesugaringKind::Await, _)) = desugaring { - err.subdiagnostic( - self.dcx(), - CaptureReasonLabel::Await { - fn_call_span, - place_name: &place_name, - is_partial, - is_loop_message, - }, - ); + err.subdiagnostic(CaptureReasonLabel::Await { + fn_call_span, + place_name: &place_name, + is_partial, + is_loop_message, + }); } else { - err.subdiagnostic( - self.dcx(), - CaptureReasonLabel::MethodCall { - fn_call_span, - place_name: &place_name, - is_partial, - is_loop_message, - }, - ); + err.subdiagnostic(CaptureReasonLabel::MethodCall { + fn_call_span, + place_name: &place_name, + is_partial, + is_loop_message, + }); } // Erase and shadow everything that could be passed to the new infcx. let ty = moved_place.ty(self.body, tcx).ty; @@ -1276,12 +1226,9 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> { ) && self.infcx.can_eq(self.param_env, ty, self_ty) { - err.subdiagnostic( - self.dcx(), - CaptureReasonSuggest::FreshReborrow { - span: move_span.shrink_to_hi(), - }, - ); + err.subdiagnostic(CaptureReasonSuggest::FreshReborrow { + span: move_span.shrink_to_hi(), + }); has_sugg = true; } if let Some(clone_trait) = tcx.lang_items().clone_trait() { @@ -1368,20 +1315,17 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> { } } else { if move_span != span || is_loop_message { - err.subdiagnostic( - self.dcx(), - CaptureReasonLabel::MovedHere { - move_span, - is_partial, - is_move_msg, - is_loop_message, - }, - ); + err.subdiagnostic(CaptureReasonLabel::MovedHere { + move_span, + is_partial, + is_move_msg, + is_loop_message, + }); } // If the move error occurs due to a loop, don't show // another message for the same span if !is_loop_message { - move_spans.var_subdiag(self.dcx(), err, None, |kind, var_span| match kind { + move_spans.var_subdiag(err, None, |kind, var_span| match kind { hir::ClosureKind::Coroutine(_) => { CaptureVarCause::PartialMoveUseInCoroutine { var_span, is_partial } } diff --git a/compiler/rustc_borrowck/src/diagnostics/move_errors.rs b/compiler/rustc_borrowck/src/diagnostics/move_errors.rs index 1d844c3d6a2..5a7bca9ab03 100644 --- a/compiler/rustc_borrowck/src/diagnostics/move_errors.rs +++ b/compiler/rustc_borrowck/src/diagnostics/move_errors.rs @@ -579,15 +579,12 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, 'tcx> { self.suggest_cloning(err, place_ty, expr, self.find_expr(other_span), None); } - err.subdiagnostic( - self.dcx(), - crate::session_diagnostics::TypeNoCopy::Label { - is_partial_move: false, - ty: place_ty, - place: &place_desc, - span, - }, - ); + err.subdiagnostic(crate::session_diagnostics::TypeNoCopy::Label { + is_partial_move: false, + ty: place_ty, + place: &place_desc, + span, + }); } else { binds_to.sort(); binds_to.dedup(); @@ -620,17 +617,14 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, 'tcx> { ); } - err.subdiagnostic( - self.dcx(), - crate::session_diagnostics::TypeNoCopy::Label { - is_partial_move: false, - ty: place_ty, - place: &place_desc, - span: use_span, - }, - ); + err.subdiagnostic(crate::session_diagnostics::TypeNoCopy::Label { + is_partial_move: false, + ty: place_ty, + place: &place_desc, + span: use_span, + }); - use_spans.args_subdiag(self.dcx(), err, |args_span| { + use_spans.args_subdiag(err, |args_span| { crate::session_diagnostics::CaptureArgLabel::MoveOutPlace { place: place_desc, args_span, @@ -733,15 +727,12 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, 'tcx> { self.suggest_cloning(err, bind_to.ty, expr, None, None); } - err.subdiagnostic( - self.dcx(), - crate::session_diagnostics::TypeNoCopy::Label { - is_partial_move: false, - ty: bind_to.ty, - place: place_desc, - span: binding_span, - }, - ); + err.subdiagnostic(crate::session_diagnostics::TypeNoCopy::Label { + is_partial_move: false, + ty: bind_to.ty, + place: place_desc, + span: binding_span, + }); } } diff --git a/compiler/rustc_borrowck/src/diagnostics/mutability_errors.rs b/compiler/rustc_borrowck/src/diagnostics/mutability_errors.rs index df1a1411cf5..e0b18536dd5 100644 --- a/compiler/rustc_borrowck/src/diagnostics/mutability_errors.rs +++ b/compiler/rustc_borrowck/src/diagnostics/mutability_errors.rs @@ -8,7 +8,7 @@ use rustc_hir::intravisit::Visitor; use rustc_hir::{self as hir, BindingMode, ByRef, Node}; use rustc_middle::bug; use rustc_middle::mir::{Mutability, Place, PlaceRef, ProjectionElem}; -use rustc_middle::ty::{self, InstanceDef, Ty, TyCtxt, Upcast}; +use rustc_middle::ty::{self, InstanceKind, Ty, TyCtxt, Upcast}; use rustc_middle::{ hir::place::PlaceBase, mir::{self, BindingForm, Local, LocalDecl, LocalInfo, LocalKind, Location}, @@ -230,7 +230,6 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, 'tcx> { } if suggest { borrow_spans.var_subdiag( - self.dcx(), &mut err, Some(mir::BorrowKind::Mut { kind: mir::MutBorrowKind::Default }), |_kind, var_span| { @@ -937,56 +936,81 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, 'tcx> { let node = self.infcx.tcx.hir_node(fn_call_id); let def_id = hir.enclosing_body_owner(fn_call_id); let mut look_at_return = true; - // If we can detect the expression to be an `fn` call where the closure was an argument, - // we point at the `fn` definition argument... - if let hir::Node::Expr(hir::Expr { kind: hir::ExprKind::Call(func, args), .. }) = node { - let arg_pos = args + + // If the HIR node is a function or method call gets the def ID + // of the called function or method and the span and args of the call expr + let get_call_details = || { + let hir::Node::Expr(hir::Expr { hir_id, kind, .. }) = node else { + return None; + }; + + let typeck_results = self.infcx.tcx.typeck(def_id); + + match kind { + hir::ExprKind::Call(expr, args) => { + if let Some(ty::FnDef(def_id, _)) = + typeck_results.node_type_opt(expr.hir_id).as_ref().map(|ty| ty.kind()) + { + Some((*def_id, expr.span, *args)) + } else { + None + } + } + hir::ExprKind::MethodCall(_, _, args, span) => { + if let Some(def_id) = typeck_results.type_dependent_def_id(*hir_id) { + Some((def_id, *span, *args)) + } else { + None + } + } + _ => None, + } + }; + + // If we can detect the expression to be an function or method call where the closure was an argument, + // we point at the function or method definition argument... + if let Some((callee_def_id, call_span, call_args)) = get_call_details() { + let arg_pos = call_args .iter() .enumerate() .filter(|(_, arg)| arg.hir_id == closure_id) .map(|(pos, _)| pos) .next(); - let tables = self.infcx.tcx.typeck(def_id); - if let Some(ty::FnDef(def_id, _)) = - tables.node_type_opt(func.hir_id).as_ref().map(|ty| ty.kind()) - { - let arg = match hir.get_if_local(*def_id) { - Some( - hir::Node::Item(hir::Item { - ident, kind: hir::ItemKind::Fn(sig, ..), .. - }) - | hir::Node::TraitItem(hir::TraitItem { - ident, - kind: hir::TraitItemKind::Fn(sig, _), - .. + + let arg = match hir.get_if_local(callee_def_id) { + Some( + hir::Node::Item(hir::Item { ident, kind: hir::ItemKind::Fn(sig, ..), .. }) + | hir::Node::TraitItem(hir::TraitItem { + ident, + kind: hir::TraitItemKind::Fn(sig, _), + .. + }) + | hir::Node::ImplItem(hir::ImplItem { + ident, + kind: hir::ImplItemKind::Fn(sig, _), + .. + }), + ) => Some( + arg_pos + .and_then(|pos| { + sig.decl.inputs.get( + pos + if sig.decl.implicit_self.has_implicit_self() { + 1 + } else { + 0 + }, + ) }) - | hir::Node::ImplItem(hir::ImplItem { - ident, - kind: hir::ImplItemKind::Fn(sig, _), - .. - }), - ) => Some( - arg_pos - .and_then(|pos| { - sig.decl.inputs.get( - pos + if sig.decl.implicit_self.has_implicit_self() { - 1 - } else { - 0 - }, - ) - }) - .map(|arg| arg.span) - .unwrap_or(ident.span), - ), - _ => None, - }; - if let Some(span) = arg { - err.span_label(span, "change this to accept `FnMut` instead of `Fn`"); - err.span_label(func.span, "expects `Fn` instead of `FnMut`"); - err.span_label(closure_span, "in this closure"); - look_at_return = false; - } + .map(|arg| arg.span) + .unwrap_or(ident.span), + ), + _ => None, + }; + if let Some(span) = arg { + err.span_label(span, "change this to accept `FnMut` instead of `Fn`"); + err.span_label(call_span, "expects `Fn` instead of `FnMut`"); + err.span_label(closure_span, "in this closure"); + look_at_return = false; } } @@ -1020,7 +1044,7 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, 'tcx> { fn suggest_using_iter_mut(&self, err: &mut Diag<'_>) { let source = self.body.source; let hir = self.infcx.tcx.hir(); - if let InstanceDef::Item(def_id) = source.instance + if let InstanceKind::Item(def_id) = source.instance && let Some(Node::Expr(hir::Expr { hir_id, kind, .. })) = hir.get_if_local(def_id) && let ExprKind::Closure(hir::Closure { kind: hir::ClosureKind::Closure, .. }) = kind && let Node::Expr(expr) = self.infcx.tcx.parent_hir_node(*hir_id) diff --git a/compiler/rustc_borrowck/src/diagnostics/region_errors.rs b/compiler/rustc_borrowck/src/diagnostics/region_errors.rs index 15a8764aab3..67c11ff4a5b 100644 --- a/compiler/rustc_borrowck/src/diagnostics/region_errors.rs +++ b/compiler/rustc_borrowck/src/diagnostics/region_errors.rs @@ -631,13 +631,13 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, 'tcx> { let upvars_map = self.infcx.tcx.upvars_mentioned(def_id).unwrap(); let upvar_def_span = self.infcx.tcx.hir().span(def_hir); let upvar_span = upvars_map.get(&def_hir).unwrap().span; - diag.subdiagnostic(self.dcx(), VarHereDenote::Defined { span: upvar_def_span }); - diag.subdiagnostic(self.dcx(), VarHereDenote::Captured { span: upvar_span }); + diag.subdiagnostic(VarHereDenote::Defined { span: upvar_def_span }); + diag.subdiagnostic(VarHereDenote::Captured { span: upvar_span }); } } if let Some(fr_span) = self.give_region_a_name(*outlived_fr).unwrap().span() { - diag.subdiagnostic(self.dcx(), VarHereDenote::FnMutInferred { span: fr_span }); + diag.subdiagnostic(VarHereDenote::FnMutInferred { span: fr_span }); } self.suggest_move_on_borrowing_closure(&mut diag); @@ -810,7 +810,7 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, 'tcx> { }, }; - diag.subdiagnostic(self.dcx(), err_category); + diag.subdiagnostic(err_category); self.add_static_impl_trait_suggestion(&mut diag, *fr, fr_name, *outlived_fr); self.suggest_adding_lifetime_params(&mut diag, *fr, *outlived_fr); @@ -1008,7 +1008,7 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, 'tcx> { ident.span, "calling this method introduces the `impl`'s `'static` requirement", ); - err.subdiagnostic(self.dcx(), RequireStaticErr::UsedImpl { multi_span }); + err.subdiagnostic(RequireStaticErr::UsedImpl { multi_span }); err.span_suggestion_verbose( span.shrink_to_hi(), "consider relaxing the implicit `'static` requirement", diff --git a/compiler/rustc_borrowck/src/diagnostics/region_name.rs b/compiler/rustc_borrowck/src/diagnostics/region_name.rs index 2cf548e28b1..77fb9fb4315 100644 --- a/compiler/rustc_borrowck/src/diagnostics/region_name.rs +++ b/compiler/rustc_borrowck/src/diagnostics/region_name.rs @@ -628,9 +628,7 @@ impl<'tcx> MirBorrowckCtxt<'_, 'tcx> { | GenericArgKind::Const(_), _, ) => { - // This was previously a `span_delayed_bug` and could be - // reached by the test for #82126, but no longer. - self.dcx().span_bug( + self.dcx().span_delayed_bug( hir_arg.span(), format!("unmatched arg and hir arg: found {kind:?} vs {hir_arg:?}"), ); diff --git a/compiler/rustc_builtin_macros/src/asm.rs b/compiler/rustc_builtin_macros/src/asm.rs index 1a7961bf70c..64238e81b26 100644 --- a/compiler/rustc_builtin_macros/src/asm.rs +++ b/compiler/rustc_builtin_macros/src/asm.rs @@ -46,7 +46,7 @@ pub fn parse_asm_args<'a>( sp: Span, is_global_asm: bool, ) -> PResult<'a, AsmArgs> { - let dcx = &p.psess.dcx; + let dcx = p.dcx(); if p.token == token::Eof { return Err(dcx.create_err(errors::AsmRequiresTemplate { span: sp })); @@ -307,7 +307,7 @@ pub fn parse_asm_args<'a>( fn err_duplicate_option(p: &Parser<'_>, symbol: Symbol, span: Span) { // Tool-only output let full_span = if p.token.kind == token::Comma { span.to(p.token.span) } else { span }; - p.psess.dcx.emit_err(errors::AsmOptAlreadyprovided { span, symbol, full_span }); + p.dcx().emit_err(errors::AsmOptAlreadyprovided { span, symbol, full_span }); } /// Try to set the provided option in the provided `AsmArgs`. @@ -379,7 +379,7 @@ fn parse_clobber_abi<'a>(p: &mut Parser<'a>, args: &mut AsmArgs) -> PResult<'a, p.expect(&token::OpenDelim(Delimiter::Parenthesis))?; if p.eat(&token::CloseDelim(Delimiter::Parenthesis)) { - return Err(p.psess.dcx.create_err(errors::NonABI { span: p.token.span })); + return Err(p.dcx().create_err(errors::NonABI { span: p.token.span })); } let mut new_abis = Vec::new(); @@ -390,7 +390,7 @@ fn parse_clobber_abi<'a>(p: &mut Parser<'a>, args: &mut AsmArgs) -> PResult<'a, } Err(opt_lit) => { let span = opt_lit.map_or(p.token.span, |lit| lit.span); - let mut err = p.psess.dcx.struct_span_err(span, "expected string literal"); + let mut err = p.dcx().struct_span_err(span, "expected string literal"); err.span_label(span, "not a string literal"); return Err(err); } diff --git a/compiler/rustc_builtin_macros/src/cmdline_attrs.rs b/compiler/rustc_builtin_macros/src/cmdline_attrs.rs index 16184ec7511..58928815e89 100644 --- a/compiler/rustc_builtin_macros/src/cmdline_attrs.rs +++ b/compiler/rustc_builtin_macros/src/cmdline_attrs.rs @@ -26,7 +26,7 @@ pub fn inject(krate: &mut ast::Crate, psess: &ParseSess, attrs: &[String]) { }; let end_span = parser.token.span; if parser.token != token::Eof { - psess.dcx.emit_err(errors::InvalidCrateAttr { span: start_span.to(end_span) }); + psess.dcx().emit_err(errors::InvalidCrateAttr { span: start_span.to(end_span) }); continue; } diff --git a/compiler/rustc_builtin_macros/src/errors.rs b/compiler/rustc_builtin_macros/src/errors.rs index b14eb2b5ee6..ed2f98f2a39 100644 --- a/compiler/rustc_builtin_macros/src/errors.rs +++ b/compiler/rustc_builtin_macros/src/errors.rs @@ -1,5 +1,5 @@ use rustc_errors::{ - codes::*, Diag, DiagCtxt, Diagnostic, EmissionGuarantee, Level, MultiSpan, + codes::*, Diag, DiagCtxtHandle, Diagnostic, EmissionGuarantee, Level, MultiSpan, SingleLabelManySpans, SubdiagMessageOp, Subdiagnostic, }; use rustc_macros::{Diagnostic, Subdiagnostic}; @@ -434,7 +434,7 @@ pub(crate) struct EnvNotDefinedWithUserMessage { // Hand-written implementation to support custom user messages. impl<'a, G: EmissionGuarantee> Diagnostic<'a, G> for EnvNotDefinedWithUserMessage { #[track_caller] - fn into_diag(self, dcx: &'a DiagCtxt, level: Level) -> Diag<'a, G> { + fn into_diag(self, dcx: DiagCtxtHandle<'a>, level: Level) -> Diag<'a, G> { #[expect( rustc::untranslatable_diagnostic, reason = "cannot translate user-provided messages" @@ -801,7 +801,7 @@ pub(crate) struct AsmClobberNoReg { } impl<'a, G: EmissionGuarantee> Diagnostic<'a, G> for AsmClobberNoReg { - fn into_diag(self, dcx: &'a DiagCtxt, level: Level) -> Diag<'a, G> { + fn into_diag(self, dcx: DiagCtxtHandle<'a>, level: Level) -> Diag<'a, G> { // eager translation as `span_labels` takes `AsRef<str>` let lbl1 = dcx.eagerly_translate_to_string( crate::fluent_generated::builtin_macros_asm_clobber_abi, diff --git a/compiler/rustc_builtin_macros/src/proc_macro_harness.rs b/compiler/rustc_builtin_macros/src/proc_macro_harness.rs index 477e5c8bec5..99d0191958d 100644 --- a/compiler/rustc_builtin_macros/src/proc_macro_harness.rs +++ b/compiler/rustc_builtin_macros/src/proc_macro_harness.rs @@ -3,6 +3,7 @@ use rustc_ast::ptr::P; use rustc_ast::visit::{self, Visitor}; use rustc_ast::{self as ast, attr, NodeId}; use rustc_ast_pretty::pprust; +use rustc_errors::DiagCtxtHandle; use rustc_expand::base::{parse_macro_name_and_helper_attrs, ExtCtxt, ResolverExpand}; use rustc_expand::expand::{AstFragment, ExpansionConfig}; use rustc_feature::Features; @@ -38,7 +39,7 @@ enum ProcMacro { struct CollectProcMacros<'a> { macros: Vec<ProcMacro>, in_root: bool, - dcx: &'a rustc_errors::DiagCtxt, + dcx: DiagCtxtHandle<'a>, source_map: &'a SourceMap, is_proc_macro_crate: bool, is_test_crate: bool, @@ -52,7 +53,7 @@ pub fn inject( is_proc_macro_crate: bool, has_proc_macro_decls: bool, is_test_crate: bool, - dcx: &rustc_errors::DiagCtxt, + dcx: DiagCtxtHandle<'_>, ) { let ecfg = ExpansionConfig::default("proc_macro".to_string(), features); let mut cx = ExtCtxt::new(sess, ecfg, resolver, None); diff --git a/compiler/rustc_builtin_macros/src/test_harness.rs b/compiler/rustc_builtin_macros/src/test_harness.rs index ba4e5cfd130..9d032eb190a 100644 --- a/compiler/rustc_builtin_macros/src/test_harness.rs +++ b/compiler/rustc_builtin_macros/src/test_harness.rs @@ -6,6 +6,7 @@ use rustc_ast::mut_visit::*; use rustc_ast::ptr::P; use rustc_ast::visit::{walk_item, Visitor}; use rustc_ast::{attr, ModKind}; +use rustc_errors::DiagCtxtHandle; use rustc_expand::base::{ExtCtxt, ResolverExpand}; use rustc_expand::expand::{AstFragment, ExpansionConfig}; use rustc_feature::Features; @@ -391,7 +392,7 @@ fn get_test_name(i: &ast::Item) -> Option<Symbol> { attr::first_attr_value_str_by_name(&i.attrs, sym::rustc_test_marker) } -fn get_test_runner(dcx: &rustc_errors::DiagCtxt, krate: &ast::Crate) -> Option<ast::Path> { +fn get_test_runner(dcx: DiagCtxtHandle<'_>, krate: &ast::Crate) -> Option<ast::Path> { let test_attr = attr::find_by_name(&krate.attrs, sym::test_runner)?; let meta_list = test_attr.meta_item_list()?; let span = test_attr.span; diff --git a/compiler/rustc_codegen_cranelift/src/abi/mod.rs b/compiler/rustc_codegen_cranelift/src/abi/mod.rs index bd5a8876905..695dbaf2804 100644 --- a/compiler/rustc_codegen_cranelift/src/abi/mod.rs +++ b/compiler/rustc_codegen_cranelift/src/abi/mod.rs @@ -399,7 +399,7 @@ pub(crate) fn codegen_terminator_call<'tcx>( } match instance.def { - InstanceDef::Intrinsic(_) => { + InstanceKind::Intrinsic(_) => { match crate::intrinsics::codegen_intrinsic_call( fx, instance, @@ -412,7 +412,7 @@ pub(crate) fn codegen_terminator_call<'tcx>( Err(instance) => Some(instance), } } - InstanceDef::DropGlue(_, None) | ty::InstanceDef::AsyncDropGlueCtorShim(_, None) => { + InstanceKind::DropGlue(_, None) | ty::InstanceKind::AsyncDropGlueCtorShim(_, None) => { // empty drop glue - a nop. let dest = target.expect("Non terminating drop_in_place_real???"); let ret_block = fx.get_block(dest); @@ -494,7 +494,7 @@ pub(crate) fn codegen_terminator_call<'tcx>( let (func_ref, first_arg_override) = match instance { // Trait object call - Some(Instance { def: InstanceDef::Virtual(_, idx), .. }) => { + Some(Instance { def: InstanceKind::Virtual(_, idx), .. }) => { if fx.clif_comments.enabled() { let nop_inst = fx.bcx.ins().nop(); fx.add_comment( @@ -598,7 +598,7 @@ pub(crate) fn codegen_drop<'tcx>( let ty = drop_place.layout().ty; let drop_instance = Instance::resolve_drop_in_place(fx.tcx, ty).polymorphize(fx.tcx); - if let ty::InstanceDef::DropGlue(_, None) | ty::InstanceDef::AsyncDropGlueCtorShim(_, None) = + if let ty::InstanceKind::DropGlue(_, None) | ty::InstanceKind::AsyncDropGlueCtorShim(_, None) = drop_instance.def { // we don't actually need to drop anything @@ -630,7 +630,7 @@ pub(crate) fn codegen_drop<'tcx>( // FIXME(eddyb) perhaps move some of this logic into // `Instance::resolve_drop_in_place`? let virtual_drop = Instance { - def: ty::InstanceDef::Virtual(drop_instance.def_id(), 0), + def: ty::InstanceKind::Virtual(drop_instance.def_id(), 0), args: drop_instance.args, }; let fn_abi = @@ -673,7 +673,7 @@ pub(crate) fn codegen_drop<'tcx>( fx.bcx.switch_to_block(continued); let virtual_drop = Instance { - def: ty::InstanceDef::Virtual(drop_instance.def_id(), 0), + def: ty::InstanceKind::Virtual(drop_instance.def_id(), 0), args: drop_instance.args, }; let fn_abi = @@ -684,7 +684,7 @@ pub(crate) fn codegen_drop<'tcx>( fx.bcx.ins().call_indirect(sig, drop_fn, &[data]); } _ => { - assert!(!matches!(drop_instance.def, InstanceDef::Virtual(_, _))); + assert!(!matches!(drop_instance.def, InstanceKind::Virtual(_, _))); let fn_abi = RevealAllLayoutCx(fx.tcx).fn_abi_of_instance(drop_instance, ty::List::empty()); diff --git a/compiler/rustc_codegen_cranelift/src/concurrency_limiter.rs b/compiler/rustc_codegen_cranelift/src/concurrency_limiter.rs index a73860cf18b..2093b49ff31 100644 --- a/compiler/rustc_codegen_cranelift/src/concurrency_limiter.rs +++ b/compiler/rustc_codegen_cranelift/src/concurrency_limiter.rs @@ -1,6 +1,7 @@ use std::sync::{Arc, Condvar, Mutex}; use jobserver::HelperThread; +use rustc_errors::DiagCtxtHandle; use rustc_session::Session; // FIXME don't panic when a worker thread panics @@ -46,7 +47,7 @@ impl ConcurrencyLimiter { } } - pub(super) fn acquire(&self, dcx: &rustc_errors::DiagCtxt) -> ConcurrencyLimiterToken { + pub(super) fn acquire(&self, dcx: DiagCtxtHandle<'_>) -> ConcurrencyLimiterToken { let mut state = self.state.lock().unwrap(); loop { state.assert_invariants(); diff --git a/compiler/rustc_codegen_cranelift/src/constant.rs b/compiler/rustc_codegen_cranelift/src/constant.rs index a53598018f4..87c5da3b7c3 100644 --- a/compiler/rustc_codegen_cranelift/src/constant.rs +++ b/compiler/rustc_codegen_cranelift/src/constant.rs @@ -50,7 +50,7 @@ pub(crate) fn codegen_tls_ref<'tcx>( ) -> CValue<'tcx> { let tls_ptr = if !def_id.is_local() && fx.tcx.needs_thread_local_shim(def_id) { let instance = ty::Instance { - def: ty::InstanceDef::ThreadLocalShim(def_id), + def: ty::InstanceKind::ThreadLocalShim(def_id), args: ty::GenericArgs::empty(), }; let func_ref = fx.get_function_ref(instance); diff --git a/compiler/rustc_codegen_cranelift/src/intrinsics/mod.rs b/compiler/rustc_codegen_cranelift/src/intrinsics/mod.rs index cafdc051db5..b21c559e668 100644 --- a/compiler/rustc_codegen_cranelift/src/intrinsics/mod.rs +++ b/compiler/rustc_codegen_cranelift/src/intrinsics/mod.rs @@ -1261,7 +1261,7 @@ fn codegen_regular_intrinsic_call<'tcx>( } // Unimplemented intrinsics must have a fallback body. The fallback body is obtained - // by converting the `InstanceDef::Intrinsic` to an `InstanceDef::Item`. + // by converting the `InstanceKind::Intrinsic` to an `InstanceKind::Item`. _ => { let intrinsic = fx.tcx.intrinsic(instance.def_id()).unwrap(); if intrinsic.must_be_overridden { diff --git a/compiler/rustc_codegen_cranelift/src/lib.rs b/compiler/rustc_codegen_cranelift/src/lib.rs index 0fea3fd4253..2edb34e7c20 100644 --- a/compiler/rustc_codegen_cranelift/src/lib.rs +++ b/compiler/rustc_codegen_cranelift/src/lib.rs @@ -98,7 +98,7 @@ mod prelude { pub(crate) use rustc_middle::mir::{self, *}; pub(crate) use rustc_middle::ty::layout::{LayoutOf, TyAndLayout}; pub(crate) use rustc_middle::ty::{ - self, FloatTy, Instance, InstanceDef, IntTy, ParamEnv, Ty, TyCtxt, UintTy, + self, FloatTy, Instance, InstanceKind, IntTy, ParamEnv, Ty, TyCtxt, UintTy, }; pub(crate) use rustc_span::Span; pub(crate) use rustc_target::abi::{Abi, FieldIdx, Scalar, Size, VariantIdx, FIRST_VARIANT}; diff --git a/compiler/rustc_codegen_gcc/src/back/lto.rs b/compiler/rustc_codegen_gcc/src/back/lto.rs index 61e0f203ee0..ec70fbdddb0 100644 --- a/compiler/rustc_codegen_gcc/src/back/lto.rs +++ b/compiler/rustc_codegen_gcc/src/back/lto.rs @@ -28,7 +28,7 @@ use rustc_codegen_ssa::back::write::{CodegenContext, FatLtoInput}; use rustc_codegen_ssa::traits::*; use rustc_codegen_ssa::{looks_like_rust_object_file, ModuleCodegen, ModuleKind}; use rustc_data_structures::memmap::Mmap; -use rustc_errors::{DiagCtxt, FatalError}; +use rustc_errors::{DiagCtxtHandle, FatalError}; use rustc_hir::def_id::LOCAL_CRATE; use rustc_middle::dep_graph::WorkProduct; use rustc_middle::middle::exported_symbols::{SymbolExportInfo, SymbolExportLevel}; @@ -59,7 +59,7 @@ struct LtoData { fn prepare_lto( cgcx: &CodegenContext<GccCodegenBackend>, - dcx: &DiagCtxt, + dcx: DiagCtxtHandle<'_>, ) -> Result<LtoData, FatalError> { let export_threshold = match cgcx.lto { // We're just doing LTO for our one crate @@ -179,12 +179,13 @@ pub(crate) fn run_fat( cached_modules: Vec<(SerializedModule<ModuleBuffer>, WorkProduct)>, ) -> Result<LtoModuleCodegen<GccCodegenBackend>, FatalError> { let dcx = cgcx.create_dcx(); - let lto_data = prepare_lto(cgcx, &dcx)?; + let dcx = dcx.handle(); + let lto_data = prepare_lto(cgcx, dcx)?; /*let symbols_below_threshold = lto_data.symbols_below_threshold.iter().map(|c| c.as_ptr()).collect::<Vec<_>>();*/ fat_lto( cgcx, - &dcx, + dcx, modules, cached_modules, lto_data.upstream_modules, @@ -195,7 +196,7 @@ pub(crate) fn run_fat( fn fat_lto( cgcx: &CodegenContext<GccCodegenBackend>, - _dcx: &DiagCtxt, + _dcx: DiagCtxtHandle<'_>, modules: Vec<FatLtoInput<GccCodegenBackend>>, cached_modules: Vec<(SerializedModule<ModuleBuffer>, WorkProduct)>, mut serialized_modules: Vec<(SerializedModule<ModuleBuffer>, CString)>, diff --git a/compiler/rustc_codegen_gcc/src/back/write.rs b/compiler/rustc_codegen_gcc/src/back/write.rs index 3ea5be1ee56..b9c7f72d0b7 100644 --- a/compiler/rustc_codegen_gcc/src/back/write.rs +++ b/compiler/rustc_codegen_gcc/src/back/write.rs @@ -4,7 +4,7 @@ use gccjit::OutputKind; use rustc_codegen_ssa::back::link::ensure_removed; use rustc_codegen_ssa::back::write::{BitcodeSection, CodegenContext, EmitObj, ModuleConfig}; use rustc_codegen_ssa::{CompiledModule, ModuleCodegen}; -use rustc_errors::DiagCtxt; +use rustc_errors::DiagCtxtHandle; use rustc_fs_util::link_or_copy; use rustc_session::config::OutputType; use rustc_span::fatal_error::FatalError; @@ -15,7 +15,7 @@ use crate::{GccCodegenBackend, GccContext}; pub(crate) unsafe fn codegen( cgcx: &CodegenContext<GccCodegenBackend>, - dcx: &DiagCtxt, + dcx: DiagCtxtHandle<'_>, module: ModuleCodegen<GccContext>, config: &ModuleConfig, ) -> Result<CompiledModule, FatalError> { @@ -166,7 +166,7 @@ pub(crate) unsafe fn codegen( pub(crate) fn link( _cgcx: &CodegenContext<GccCodegenBackend>, - _dcx: &DiagCtxt, + _dcx: DiagCtxtHandle<'_>, mut _modules: Vec<ModuleCodegen<GccContext>>, ) -> Result<ModuleCodegen<GccContext>, FatalError> { unimplemented!(); diff --git a/compiler/rustc_codegen_gcc/src/errors.rs b/compiler/rustc_codegen_gcc/src/errors.rs index aee2b077dba..6bada3d334c 100644 --- a/compiler/rustc_codegen_gcc/src/errors.rs +++ b/compiler/rustc_codegen_gcc/src/errors.rs @@ -1,4 +1,4 @@ -use rustc_errors::{Diag, DiagCtxt, Diagnostic, EmissionGuarantee, Level}; +use rustc_errors::{Diag, DiagCtxtHandle, Diagnostic, EmissionGuarantee, Level}; use rustc_macros::{Diagnostic, Subdiagnostic}; use rustc_span::Span; @@ -90,13 +90,13 @@ pub(crate) struct TargetFeatureDisableOrEnable<'a> { pub(crate) struct MissingFeatures; impl<G: EmissionGuarantee> Diagnostic<'_, G> for TargetFeatureDisableOrEnable<'_> { - fn into_diag(self, dcx: &'_ DiagCtxt, level: Level) -> Diag<'_, G> { + fn into_diag(self, dcx: DiagCtxtHandle<'_>, level: Level) -> Diag<'_, G> { let mut diag = Diag::new(dcx, level, fluent::codegen_gcc_target_feature_disable_or_enable); if let Some(span) = self.span { diag.span(span); }; if let Some(missing_features) = self.missing_features { - diag.subdiagnostic(dcx, missing_features); + diag.subdiagnostic(missing_features); } diag.arg("features", self.features.join(", ")); diag diff --git a/compiler/rustc_codegen_gcc/src/lib.rs b/compiler/rustc_codegen_gcc/src/lib.rs index b1785e150ad..24856506c46 100644 --- a/compiler/rustc_codegen_gcc/src/lib.rs +++ b/compiler/rustc_codegen_gcc/src/lib.rs @@ -16,13 +16,7 @@ #![allow(internal_features)] #![doc(rust_logo)] #![feature(rustdoc_internals)] -#![feature( - rustc_private, - decl_macro, - never_type, - trusted_len, - hash_raw_entry -)] +#![feature(rustc_private, decl_macro, never_type, trusted_len, hash_raw_entry)] #![allow(broken_intra_doc_links)] #![recursion_limit = "256"] #![warn(rust_2018_idioms)] @@ -104,7 +98,7 @@ use rustc_codegen_ssa::traits::{ use rustc_codegen_ssa::{CodegenResults, CompiledModule, ModuleCodegen}; use rustc_data_structures::fx::FxIndexMap; use rustc_data_structures::sync::IntoDynSyncSend; -use rustc_errors::{DiagCtxt, ErrorGuaranteed}; +use rustc_errors::{DiagCtxtHandle, ErrorGuaranteed}; use rustc_metadata::EncodedMetadata; use rustc_middle::dep_graph::{WorkProduct, WorkProductId}; use rustc_middle::ty::TyCtxt; @@ -386,7 +380,7 @@ impl WriteBackendMethods for GccCodegenBackend { unsafe fn optimize( _cgcx: &CodegenContext<Self>, - _dcx: &DiagCtxt, + _dcx: DiagCtxtHandle<'_>, module: &ModuleCodegen<Self::Module>, config: &ModuleConfig, ) -> Result<(), FatalError> { @@ -411,14 +405,17 @@ impl WriteBackendMethods for GccCodegenBackend { unsafe fn codegen( cgcx: &CodegenContext<Self>, - dcx: &DiagCtxt, + dcx: DiagCtxtHandle<'_>, module: ModuleCodegen<Self::Module>, config: &ModuleConfig, ) -> Result<CompiledModule, FatalError> { back::write::codegen(cgcx, dcx, module, config) } - fn prepare_thin(_module: ModuleCodegen<Self::Module>, _emit_summary: bool) -> (String, Self::ThinBuffer) { + fn prepare_thin( + _module: ModuleCodegen<Self::Module>, + _emit_summary: bool, + ) -> (String, Self::ThinBuffer) { unimplemented!(); } @@ -428,7 +425,7 @@ impl WriteBackendMethods for GccCodegenBackend { fn run_link( cgcx: &CodegenContext<Self>, - dcx: &DiagCtxt, + dcx: DiagCtxtHandle<'_>, modules: Vec<ModuleCodegen<Self::Module>>, ) -> Result<ModuleCodegen<Self::Module>, FatalError> { back::write::link(cgcx, dcx, modules) diff --git a/compiler/rustc_codegen_llvm/src/back/lto.rs b/compiler/rustc_codegen_llvm/src/back/lto.rs index bb7c8fe2ea7..aff3e3d7076 100644 --- a/compiler/rustc_codegen_llvm/src/back/lto.rs +++ b/compiler/rustc_codegen_llvm/src/back/lto.rs @@ -14,7 +14,7 @@ use rustc_codegen_ssa::traits::*; use rustc_codegen_ssa::{looks_like_rust_object_file, ModuleCodegen, ModuleKind}; use rustc_data_structures::fx::FxHashMap; use rustc_data_structures::memmap::Mmap; -use rustc_errors::{DiagCtxt, FatalError}; +use rustc_errors::{DiagCtxtHandle, FatalError}; use rustc_hir::def_id::LOCAL_CRATE; use rustc_middle::bug; use rustc_middle::dep_graph::WorkProduct; @@ -49,7 +49,7 @@ pub fn crate_type_allows_lto(crate_type: CrateType) -> bool { fn prepare_lto( cgcx: &CodegenContext<LlvmCodegenBackend>, - dcx: &DiagCtxt, + dcx: DiagCtxtHandle<'_>, ) -> Result<(Vec<CString>, Vec<(SerializedModule<ModuleBuffer>, CString)>), FatalError> { let export_threshold = match cgcx.lto { // We're just doing LTO for our one crate @@ -203,10 +203,11 @@ pub(crate) fn run_fat( cached_modules: Vec<(SerializedModule<ModuleBuffer>, WorkProduct)>, ) -> Result<LtoModuleCodegen<LlvmCodegenBackend>, FatalError> { let dcx = cgcx.create_dcx(); - let (symbols_below_threshold, upstream_modules) = prepare_lto(cgcx, &dcx)?; + let dcx = dcx.handle(); + let (symbols_below_threshold, upstream_modules) = prepare_lto(cgcx, dcx)?; let symbols_below_threshold = symbols_below_threshold.iter().map(|c| c.as_ptr()).collect::<Vec<_>>(); - fat_lto(cgcx, &dcx, modules, cached_modules, upstream_modules, &symbols_below_threshold) + fat_lto(cgcx, dcx, modules, cached_modules, upstream_modules, &symbols_below_threshold) } /// Performs thin LTO by performing necessary global analysis and returning two @@ -218,7 +219,8 @@ pub(crate) fn run_thin( cached_modules: Vec<(SerializedModule<ModuleBuffer>, WorkProduct)>, ) -> Result<(Vec<LtoModuleCodegen<LlvmCodegenBackend>>, Vec<WorkProduct>), FatalError> { let dcx = cgcx.create_dcx(); - let (symbols_below_threshold, upstream_modules) = prepare_lto(cgcx, &dcx)?; + let dcx = dcx.handle(); + let (symbols_below_threshold, upstream_modules) = prepare_lto(cgcx, dcx)?; let symbols_below_threshold = symbols_below_threshold.iter().map(|c| c.as_ptr()).collect::<Vec<_>>(); if cgcx.opts.cg.linker_plugin_lto.enabled() { @@ -227,7 +229,7 @@ pub(crate) fn run_thin( is deferred to the linker" ); } - thin_lto(cgcx, &dcx, modules, upstream_modules, cached_modules, &symbols_below_threshold) + thin_lto(cgcx, dcx, modules, upstream_modules, cached_modules, &symbols_below_threshold) } pub(crate) fn prepare_thin( @@ -241,7 +243,7 @@ pub(crate) fn prepare_thin( fn fat_lto( cgcx: &CodegenContext<LlvmCodegenBackend>, - dcx: &DiagCtxt, + dcx: DiagCtxtHandle<'_>, modules: Vec<FatLtoInput<LlvmCodegenBackend>>, cached_modules: Vec<(SerializedModule<ModuleBuffer>, WorkProduct)>, mut serialized_modules: Vec<(SerializedModule<ModuleBuffer>, CString)>, @@ -436,7 +438,7 @@ impl Drop for Linker<'_> { /// they all go out of scope. fn thin_lto( cgcx: &CodegenContext<LlvmCodegenBackend>, - dcx: &DiagCtxt, + dcx: DiagCtxtHandle<'_>, modules: Vec<(String, ThinBuffer)>, serialized_modules: Vec<(SerializedModule<ModuleBuffer>, CString)>, cached_modules: Vec<(SerializedModule<ModuleBuffer>, WorkProduct)>, @@ -593,7 +595,7 @@ fn thin_lto( pub(crate) fn run_pass_manager( cgcx: &CodegenContext<LlvmCodegenBackend>, - dcx: &DiagCtxt, + dcx: DiagCtxtHandle<'_>, module: &mut ModuleCodegen<ModuleLlvm>, thin: bool, ) -> Result<(), FatalError> { @@ -714,10 +716,11 @@ pub unsafe fn optimize_thin_module( cgcx: &CodegenContext<LlvmCodegenBackend>, ) -> Result<ModuleCodegen<ModuleLlvm>, FatalError> { let dcx = cgcx.create_dcx(); + let dcx = dcx.handle(); let module_name = &thin_module.shared.module_names[thin_module.idx]; let tm_factory_config = TargetMachineFactoryConfig::new(cgcx, module_name.to_str().unwrap()); - let tm = (cgcx.tm_factory)(tm_factory_config).map_err(|e| write::llvm_err(&dcx, e))?; + let tm = (cgcx.tm_factory)(tm_factory_config).map_err(|e| write::llvm_err(dcx, e))?; // Right now the implementation we've got only works over serialized // modules, so we create a fresh new LLVM context and parse the module @@ -725,7 +728,7 @@ pub unsafe fn optimize_thin_module( // crates but for locally codegened modules we may be able to reuse // that LLVM Context and Module. let llcx = llvm::LLVMRustContextCreate(cgcx.fewer_names); - let llmod_raw = parse_module(llcx, module_name, thin_module.data(), &dcx)? as *const _; + let llmod_raw = parse_module(llcx, module_name, thin_module.data(), dcx)? as *const _; let mut module = ModuleCodegen { module_llvm: ModuleLlvm { llmod_raw, llcx, tm: ManuallyDrop::new(tm) }, name: thin_module.name().to_string(), @@ -748,7 +751,7 @@ pub unsafe fn optimize_thin_module( let _timer = cgcx.prof.generic_activity_with_arg("LLVM_thin_lto_rename", thin_module.name()); if !llvm::LLVMRustPrepareThinLTORename(thin_module.shared.data.0, llmod, target) { - return Err(write::llvm_err(&dcx, LlvmError::PrepareThinLtoModule)); + return Err(write::llvm_err(dcx, LlvmError::PrepareThinLtoModule)); } save_temp_bitcode(cgcx, &module, "thin-lto-after-rename"); } @@ -758,7 +761,7 @@ pub unsafe fn optimize_thin_module( .prof .generic_activity_with_arg("LLVM_thin_lto_resolve_weak", thin_module.name()); if !llvm::LLVMRustPrepareThinLTOResolveWeak(thin_module.shared.data.0, llmod) { - return Err(write::llvm_err(&dcx, LlvmError::PrepareThinLtoModule)); + return Err(write::llvm_err(dcx, LlvmError::PrepareThinLtoModule)); } save_temp_bitcode(cgcx, &module, "thin-lto-after-resolve"); } @@ -768,7 +771,7 @@ pub unsafe fn optimize_thin_module( .prof .generic_activity_with_arg("LLVM_thin_lto_internalize", thin_module.name()); if !llvm::LLVMRustPrepareThinLTOInternalize(thin_module.shared.data.0, llmod) { - return Err(write::llvm_err(&dcx, LlvmError::PrepareThinLtoModule)); + return Err(write::llvm_err(dcx, LlvmError::PrepareThinLtoModule)); } save_temp_bitcode(cgcx, &module, "thin-lto-after-internalize"); } @@ -777,7 +780,7 @@ pub unsafe fn optimize_thin_module( let _timer = cgcx.prof.generic_activity_with_arg("LLVM_thin_lto_import", thin_module.name()); if !llvm::LLVMRustPrepareThinLTOImport(thin_module.shared.data.0, llmod, target) { - return Err(write::llvm_err(&dcx, LlvmError::PrepareThinLtoModule)); + return Err(write::llvm_err(dcx, LlvmError::PrepareThinLtoModule)); } save_temp_bitcode(cgcx, &module, "thin-lto-after-import"); } @@ -789,7 +792,7 @@ pub unsafe fn optimize_thin_module( // little differently. { info!("running thin lto passes over {}", module.name); - run_pass_manager(cgcx, &dcx, &mut module, true)?; + run_pass_manager(cgcx, dcx, &mut module, true)?; save_temp_bitcode(cgcx, &module, "thin-lto-after-pm"); } } @@ -859,7 +862,7 @@ pub fn parse_module<'a>( cx: &'a llvm::Context, name: &CStr, data: &[u8], - dcx: &DiagCtxt, + dcx: DiagCtxtHandle<'_>, ) -> Result<&'a llvm::Module, FatalError> { unsafe { llvm::LLVMRustParseBitcodeForLTO(cx, data.as_ptr(), data.len(), name.as_ptr()) diff --git a/compiler/rustc_codegen_llvm/src/back/write.rs b/compiler/rustc_codegen_llvm/src/back/write.rs index 02e3bb06dda..bbfc697407b 100644 --- a/compiler/rustc_codegen_llvm/src/back/write.rs +++ b/compiler/rustc_codegen_llvm/src/back/write.rs @@ -26,7 +26,7 @@ use rustc_codegen_ssa::traits::*; use rustc_codegen_ssa::{CompiledModule, ModuleCodegen}; use rustc_data_structures::profiling::SelfProfilerRef; use rustc_data_structures::small_c_str::SmallCStr; -use rustc_errors::{DiagCtxt, FatalError, Level}; +use rustc_errors::{DiagCtxtHandle, FatalError, Level}; use rustc_fs_util::{link_or_copy, path_to_c_string}; use rustc_middle::ty::TyCtxt; use rustc_session::config::{self, Lto, OutputType, Passes}; @@ -47,7 +47,7 @@ use std::slice; use std::str; use std::sync::Arc; -pub fn llvm_err<'a>(dcx: &rustc_errors::DiagCtxt, err: LlvmError<'a>) -> FatalError { +pub fn llvm_err<'a>(dcx: DiagCtxtHandle<'_>, err: LlvmError<'a>) -> FatalError { match llvm::last_error() { Some(llvm_err) => dcx.emit_almost_fatal(WithLlvmError(err, llvm_err)), None => dcx.emit_almost_fatal(err), @@ -55,7 +55,7 @@ pub fn llvm_err<'a>(dcx: &rustc_errors::DiagCtxt, err: LlvmError<'a>) -> FatalEr } pub fn write_output_file<'ll>( - dcx: &rustc_errors::DiagCtxt, + dcx: DiagCtxtHandle<'_>, target: &'ll llvm::TargetMachine, pm: &llvm::PassManager<'ll>, m: &'ll llvm::Module, @@ -331,7 +331,7 @@ pub enum CodegenDiagnosticsStage { } pub struct DiagnosticHandlers<'a> { - data: *mut (&'a CodegenContext<LlvmCodegenBackend>, &'a DiagCtxt), + data: *mut (&'a CodegenContext<LlvmCodegenBackend>, DiagCtxtHandle<'a>), llcx: &'a llvm::Context, old_handler: Option<&'a llvm::DiagnosticHandler>, } @@ -339,7 +339,7 @@ pub struct DiagnosticHandlers<'a> { impl<'a> DiagnosticHandlers<'a> { pub fn new( cgcx: &'a CodegenContext<LlvmCodegenBackend>, - dcx: &'a DiagCtxt, + dcx: DiagCtxtHandle<'a>, llcx: &'a llvm::Context, module: &ModuleCodegen<ModuleLlvm>, stage: CodegenDiagnosticsStage, @@ -428,7 +428,7 @@ unsafe extern "C" fn diagnostic_handler(info: &DiagnosticInfo, user: *mut c_void if user.is_null() { return; } - let (cgcx, dcx) = *(user as *const (&CodegenContext<LlvmCodegenBackend>, &DiagCtxt)); + let (cgcx, dcx) = *(user as *const (&CodegenContext<LlvmCodegenBackend>, DiagCtxtHandle<'_>)); match llvm::diagnostic::Diagnostic::unpack(info) { llvm::diagnostic::InlineAsm(inline) => { @@ -506,7 +506,7 @@ fn get_instr_profile_output_path(config: &ModuleConfig) -> Option<CString> { pub(crate) unsafe fn llvm_optimize( cgcx: &CodegenContext<LlvmCodegenBackend>, - dcx: &DiagCtxt, + dcx: DiagCtxtHandle<'_>, module: &ModuleCodegen<ModuleLlvm>, config: &ModuleConfig, opt_level: config::OptLevel, @@ -604,7 +604,7 @@ pub(crate) unsafe fn llvm_optimize( // Unsafe due to LLVM calls. pub(crate) unsafe fn optimize( cgcx: &CodegenContext<LlvmCodegenBackend>, - dcx: &DiagCtxt, + dcx: DiagCtxtHandle<'_>, module: &ModuleCodegen<ModuleLlvm>, config: &ModuleConfig, ) -> Result<(), FatalError> { @@ -637,7 +637,7 @@ pub(crate) unsafe fn optimize( pub(crate) fn link( cgcx: &CodegenContext<LlvmCodegenBackend>, - dcx: &DiagCtxt, + dcx: DiagCtxtHandle<'_>, mut modules: Vec<ModuleCodegen<ModuleLlvm>>, ) -> Result<ModuleCodegen<ModuleLlvm>, FatalError> { use super::lto::{Linker, ModuleBuffer}; @@ -660,7 +660,7 @@ pub(crate) fn link( pub(crate) unsafe fn codegen( cgcx: &CodegenContext<LlvmCodegenBackend>, - dcx: &DiagCtxt, + dcx: DiagCtxtHandle<'_>, module: ModuleCodegen<ModuleLlvm>, config: &ModuleConfig, ) -> Result<CompiledModule, FatalError> { diff --git a/compiler/rustc_codegen_llvm/src/debuginfo/metadata.rs b/compiler/rustc_codegen_llvm/src/debuginfo/metadata.rs index a543ccbde0e..8de4e0effad 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/errors.rs b/compiler/rustc_codegen_llvm/src/errors.rs index 9d83dc81163..40ac2f9c8ba 100644 --- a/compiler/rustc_codegen_llvm/src/errors.rs +++ b/compiler/rustc_codegen_llvm/src/errors.rs @@ -4,7 +4,7 @@ use std::path::Path; use crate::fluent_generated as fluent; use rustc_data_structures::small_c_str::SmallCStr; -use rustc_errors::{Diag, DiagCtxt, Diagnostic, EmissionGuarantee, Level}; +use rustc_errors::{Diag, DiagCtxtHandle, Diagnostic, EmissionGuarantee, Level}; use rustc_macros::{Diagnostic, Subdiagnostic}; use rustc_span::Span; @@ -100,7 +100,7 @@ pub(crate) struct DynamicLinkingWithLTO; pub(crate) struct ParseTargetMachineConfig<'a>(pub LlvmError<'a>); impl<G: EmissionGuarantee> Diagnostic<'_, G> for ParseTargetMachineConfig<'_> { - fn into_diag(self, dcx: &'_ DiagCtxt, level: Level) -> Diag<'_, G> { + fn into_diag(self, dcx: DiagCtxtHandle<'_>, level: Level) -> Diag<'_, G> { let diag: Diag<'_, G> = self.0.into_diag(dcx, level); let (message, _) = diag.messages.first().expect("`LlvmError` with no message"); let message = dcx.eagerly_translate_to_string(message.clone(), diag.args.iter()); @@ -120,13 +120,13 @@ pub(crate) struct TargetFeatureDisableOrEnable<'a> { pub(crate) struct MissingFeatures; impl<G: EmissionGuarantee> Diagnostic<'_, G> for TargetFeatureDisableOrEnable<'_> { - fn into_diag(self, dcx: &'_ DiagCtxt, level: Level) -> Diag<'_, G> { + fn into_diag(self, dcx: DiagCtxtHandle<'_>, level: Level) -> Diag<'_, G> { let mut diag = Diag::new(dcx, level, fluent::codegen_llvm_target_feature_disable_or_enable); if let Some(span) = self.span { diag.span(span); }; if let Some(missing_features) = self.missing_features { - diag.subdiagnostic(dcx, missing_features); + diag.subdiagnostic(missing_features); } diag.arg("features", self.features.join(", ")); diag @@ -180,7 +180,7 @@ pub enum LlvmError<'a> { pub(crate) struct WithLlvmError<'a>(pub LlvmError<'a>, pub String); impl<G: EmissionGuarantee> Diagnostic<'_, G> for WithLlvmError<'_> { - fn into_diag(self, dcx: &'_ DiagCtxt, level: Level) -> Diag<'_, G> { + fn into_diag(self, dcx: DiagCtxtHandle<'_>, level: Level) -> Diag<'_, G> { use LlvmError::*; let msg_with_llvm_err = match &self.0 { WriteOutput { .. } => fluent::codegen_llvm_write_output_with_llvm_err, diff --git a/compiler/rustc_codegen_llvm/src/lib.rs b/compiler/rustc_codegen_llvm/src/lib.rs index bb76d388393..4b7a2643007 100644 --- a/compiler/rustc_codegen_llvm/src/lib.rs +++ b/compiler/rustc_codegen_llvm/src/lib.rs @@ -31,7 +31,7 @@ use rustc_codegen_ssa::traits::*; use rustc_codegen_ssa::ModuleCodegen; use rustc_codegen_ssa::{CodegenResults, CompiledModule}; use rustc_data_structures::fx::FxIndexMap; -use rustc_errors::{DiagCtxt, ErrorGuaranteed, FatalError}; +use rustc_errors::{DiagCtxtHandle, ErrorGuaranteed, FatalError}; use rustc_metadata::EncodedMetadata; use rustc_middle::dep_graph::{WorkProduct, WorkProductId}; use rustc_middle::ty::TyCtxt; @@ -191,7 +191,7 @@ impl WriteBackendMethods for LlvmCodegenBackend { } fn run_link( cgcx: &CodegenContext<Self>, - dcx: &DiagCtxt, + dcx: DiagCtxtHandle<'_>, modules: Vec<ModuleCodegen<Self::Module>>, ) -> Result<ModuleCodegen<Self::Module>, FatalError> { back::write::link(cgcx, dcx, modules) @@ -212,7 +212,7 @@ impl WriteBackendMethods for LlvmCodegenBackend { } unsafe fn optimize( cgcx: &CodegenContext<Self>, - dcx: &DiagCtxt, + dcx: DiagCtxtHandle<'_>, module: &ModuleCodegen<Self::Module>, config: &ModuleConfig, ) -> Result<(), FatalError> { @@ -223,7 +223,8 @@ impl WriteBackendMethods for LlvmCodegenBackend { module: &mut ModuleCodegen<Self::Module>, ) -> Result<(), FatalError> { let dcx = cgcx.create_dcx(); - back::lto::run_pass_manager(cgcx, &dcx, module, false) + let dcx = dcx.handle(); + back::lto::run_pass_manager(cgcx, dcx, module, false) } unsafe fn optimize_thin( cgcx: &CodegenContext<Self>, @@ -233,7 +234,7 @@ impl WriteBackendMethods for LlvmCodegenBackend { } unsafe fn codegen( cgcx: &CodegenContext<Self>, - dcx: &DiagCtxt, + dcx: DiagCtxtHandle<'_>, module: ModuleCodegen<Self::Module>, config: &ModuleConfig, ) -> Result<CompiledModule, FatalError> { @@ -441,7 +442,7 @@ impl ModuleLlvm { cgcx: &CodegenContext<LlvmCodegenBackend>, name: &CStr, buffer: &[u8], - dcx: &DiagCtxt, + dcx: DiagCtxtHandle<'_>, ) -> Result<Self, FatalError> { unsafe { let llcx = llvm::LLVMRustContextCreate(cgcx.fewer_names); diff --git a/compiler/rustc_codegen_ssa/src/back/link.rs b/compiler/rustc_codegen_ssa/src/back/link.rs index bdb808b1d4f..c352100b01b 100644 --- a/compiler/rustc_codegen_ssa/src/back/link.rs +++ b/compiler/rustc_codegen_ssa/src/back/link.rs @@ -3,7 +3,7 @@ use rustc_ast::CRATE_NODE_ID; use rustc_data_structures::fx::{FxIndexMap, FxIndexSet}; use rustc_data_structures::memmap::Mmap; use rustc_data_structures::temp_dir::MaybeTempDir; -use rustc_errors::{DiagCtxt, ErrorGuaranteed, FatalError}; +use rustc_errors::{DiagCtxtHandle, ErrorGuaranteed, FatalError}; use rustc_fs_util::{fix_windows_verbatim_for_gcc, try_canonicalize}; use rustc_hir::def_id::{CrateNum, LOCAL_CRATE}; use rustc_metadata::find_native_static_library; @@ -54,7 +54,7 @@ use std::process::{ExitStatus, Output, Stdio}; use std::{env, fmt, fs, io, mem, str}; use tracing::{debug, info, warn}; -pub fn ensure_removed(dcx: &DiagCtxt, path: &Path) { +pub fn ensure_removed(dcx: DiagCtxtHandle<'_>, path: &Path) { if let Err(e) = fs::remove_file(path) { if e.kind() != io::ErrorKind::NotFound { dcx.err(format!("failed to remove {}: {}", path.display(), e)); diff --git a/compiler/rustc_codegen_ssa/src/back/symbol_export.rs b/compiler/rustc_codegen_ssa/src/back/symbol_export.rs index a6df8950b35..6abe4fa1c38 100644 --- a/compiler/rustc_codegen_ssa/src/back/symbol_export.rs +++ b/compiler/rustc_codegen_ssa/src/back/symbol_export.rs @@ -310,7 +310,7 @@ fn exported_symbols_provider_local( if tcx.sess.opts.share_generics() && tcx.local_crate_exports_generics() { use rustc_middle::mir::mono::{Linkage, MonoItem, Visibility}; - use rustc_middle::ty::InstanceDef; + use rustc_middle::ty::InstanceKind; // Normally, we require that shared monomorphizations are not hidden, // because if we want to re-use a monomorphization from a Rust dylib, it @@ -337,7 +337,7 @@ fn exported_symbols_provider_local( } match *mono_item { - MonoItem::Fn(Instance { def: InstanceDef::Item(def), args }) => { + MonoItem::Fn(Instance { def: InstanceKind::Item(def), args }) => { if args.non_erasable_generics(tcx, def).next().is_some() { let symbol = ExportedSymbol::Generic(def, args); symbols.push(( @@ -350,7 +350,7 @@ fn exported_symbols_provider_local( )); } } - MonoItem::Fn(Instance { def: InstanceDef::DropGlue(def_id, Some(ty)), args }) => { + MonoItem::Fn(Instance { def: InstanceKind::DropGlue(def_id, Some(ty)), args }) => { // A little sanity-check debug_assert_eq!( args.non_erasable_generics(tcx, def_id).next(), @@ -366,12 +366,12 @@ fn exported_symbols_provider_local( )); } MonoItem::Fn(Instance { - def: InstanceDef::AsyncDropGlueCtorShim(def_id, Some(ty)), + def: InstanceKind::AsyncDropGlueCtorShim(def_id, Some(ty)), args, }) => { // A little sanity-check debug_assert_eq!( - args.non_erasable_generics(tcx, def_id).skip(1).next(), + args.non_erasable_generics(tcx, def_id).next(), Some(GenericArgKind::Type(ty)) ); symbols.push(( @@ -422,10 +422,7 @@ fn upstream_monomorphizations_provider( } ExportedSymbol::AsyncDropGlueCtorShim(ty) => { if let Some(async_drop_in_place_fn_def_id) = async_drop_in_place_fn_def_id { - ( - async_drop_in_place_fn_def_id, - tcx.mk_args(&[tcx.lifetimes.re_erased.into(), ty.into()]), - ) + (async_drop_in_place_fn_def_id, tcx.mk_args(&[ty.into()])) } else { // `drop_in_place` in place does not exist, don't try // to use it. @@ -473,11 +470,16 @@ fn upstream_drop_glue_for_provider<'tcx>( tcx: TyCtxt<'tcx>, args: GenericArgsRef<'tcx>, ) -> Option<CrateNum> { - if let Some(def_id) = tcx.lang_items().drop_in_place_fn() { - tcx.upstream_monomorphizations_for(def_id).and_then(|monos| monos.get(&args).cloned()) - } else { - None - } + let def_id = tcx.lang_items().drop_in_place_fn()?; + tcx.upstream_monomorphizations_for(def_id)?.get(&args).cloned() +} + +fn upstream_async_drop_glue_for_provider<'tcx>( + tcx: TyCtxt<'tcx>, + args: GenericArgsRef<'tcx>, +) -> Option<CrateNum> { + let def_id = tcx.lang_items().async_drop_in_place_fn()?; + tcx.upstream_monomorphizations_for(def_id)?.get(&args).cloned() } fn is_unreachable_local_definition_provider(tcx: TyCtxt<'_>, def_id: LocalDefId) -> bool { @@ -491,6 +493,7 @@ pub fn provide(providers: &mut Providers) { providers.upstream_monomorphizations = upstream_monomorphizations_provider; providers.is_unreachable_local_definition = is_unreachable_local_definition_provider; providers.upstream_drop_glue_for = upstream_drop_glue_for_provider; + providers.upstream_async_drop_glue_for = upstream_async_drop_glue_for_provider; providers.wasm_import_module_map = wasm_import_module_map; providers.extern_queries.is_reachable_non_generic = is_reachable_non_generic_provider_extern; providers.extern_queries.upstream_monomorphizations_for = @@ -556,7 +559,7 @@ pub fn symbol_name_for_instance_in_crate<'tcx>( rustc_symbol_mangling::symbol_name_for_instance_in_crate( tcx, ty::Instance { - def: ty::InstanceDef::ThreadLocalShim(def_id), + def: ty::InstanceKind::ThreadLocalShim(def_id), args: ty::GenericArgs::empty(), }, instantiating_crate, diff --git a/compiler/rustc_codegen_ssa/src/back/write.rs b/compiler/rustc_codegen_ssa/src/back/write.rs index dec87db0fc5..064be4988bd 100644 --- a/compiler/rustc_codegen_ssa/src/back/write.rs +++ b/compiler/rustc_codegen_ssa/src/back/write.rs @@ -891,9 +891,10 @@ fn execute_optimize_work_item<B: ExtraBackendMethods>( module_config: &ModuleConfig, ) -> Result<WorkItemResult<B>, FatalError> { let dcx = cgcx.create_dcx(); + let dcx = dcx.handle(); unsafe { - B::optimize(cgcx, &dcx, &module, module_config)?; + B::optimize(cgcx, dcx, &module, module_config)?; } // After we've done the initial round of optimizations we need to @@ -954,7 +955,11 @@ fn execute_copy_from_cache_work_item<B: ExtraBackendMethods>( match link_or_copy(&source_file, &output_path) { Ok(_) => Some(output_path), Err(error) => { - cgcx.create_dcx().emit_err(errors::CopyPathBuf { source_file, output_path, error }); + cgcx.create_dcx().handle().emit_err(errors::CopyPathBuf { + source_file, + output_path, + error, + }); None } } @@ -987,7 +992,7 @@ fn execute_copy_from_cache_work_item<B: ExtraBackendMethods>( let bytecode = load_from_incr_cache(module_config.emit_bc, OutputType::Bitcode); let object = load_from_incr_cache(should_emit_obj, OutputType::Object); if should_emit_obj && object.is_none() { - cgcx.create_dcx().emit_fatal(errors::NoSavedObjectFile { cgu_name: &module.name }) + cgcx.create_dcx().handle().emit_fatal(errors::NoSavedObjectFile { cgu_name: &module.name }) } WorkItemResult::Finished(CompiledModule { @@ -1016,12 +1021,13 @@ fn finish_intra_module_work<B: ExtraBackendMethods>( module_config: &ModuleConfig, ) -> Result<WorkItemResult<B>, FatalError> { let dcx = cgcx.create_dcx(); + let dcx = dcx.handle(); if !cgcx.opts.unstable_opts.combine_cgu || module.kind == ModuleKind::Metadata || module.kind == ModuleKind::Allocator { - let module = unsafe { B::codegen(cgcx, &dcx, module, module_config)? }; + let module = unsafe { B::codegen(cgcx, dcx, module, module_config)? }; Ok(WorkItemResult::Finished(module)) } else { Ok(WorkItemResult::NeedsLink(module)) @@ -1692,9 +1698,10 @@ fn start_executing_work<B: ExtraBackendMethods>( if !needs_link.is_empty() { assert!(compiled_modules.is_empty()); let dcx = cgcx.create_dcx(); - let module = B::run_link(&cgcx, &dcx, needs_link).map_err(|_| ())?; + let dcx = dcx.handle(); + let module = B::run_link(&cgcx, dcx, needs_link).map_err(|_| ())?; let module = unsafe { - B::codegen(&cgcx, &dcx, module, cgcx.config(ModuleKind::Regular)).map_err(|_| ())? + B::codegen(&cgcx, dcx, module, cgcx.config(ModuleKind::Regular)).map_err(|_| ())? }; compiled_modules.push(module); } diff --git a/compiler/rustc_codegen_ssa/src/errors.rs b/compiler/rustc_codegen_ssa/src/errors.rs index 3641e7842cf..e6ba31c5165 100644 --- a/compiler/rustc_codegen_ssa/src/errors.rs +++ b/compiler/rustc_codegen_ssa/src/errors.rs @@ -4,7 +4,7 @@ use crate::assert_module_sources::CguReuse; use crate::back::command::Command; use crate::fluent_generated as fluent; use rustc_errors::{ - codes::*, Diag, DiagArgValue, DiagCtxt, Diagnostic, EmissionGuarantee, IntoDiagArg, Level, + codes::*, Diag, DiagArgValue, DiagCtxtHandle, Diagnostic, EmissionGuarantee, IntoDiagArg, Level, }; use rustc_macros::Diagnostic; use rustc_middle::ty::layout::LayoutError; @@ -215,7 +215,7 @@ pub enum LinkRlibError { pub struct ThorinErrorWrapper(pub thorin::Error); impl<G: EmissionGuarantee> Diagnostic<'_, G> for ThorinErrorWrapper { - fn into_diag(self, dcx: &DiagCtxt, level: Level) -> Diag<'_, G> { + fn into_diag(self, dcx: DiagCtxtHandle<'_>, level: Level) -> Diag<'_, G> { let build = |msg| Diag::new(dcx, level, msg); match self.0 { thorin::Error::ReadInput(_) => build(fluent::codegen_ssa_thorin_read_input_failure), @@ -348,7 +348,7 @@ pub struct LinkingFailed<'a> { } impl<G: EmissionGuarantee> Diagnostic<'_, G> for LinkingFailed<'_> { - fn into_diag(self, dcx: &DiagCtxt, level: Level) -> Diag<'_, G> { + fn into_diag(self, dcx: DiagCtxtHandle<'_>, level: Level) -> Diag<'_, G> { let mut diag = Diag::new(dcx, level, fluent::codegen_ssa_linking_failed); diag.arg("linker_path", format!("{}", self.linker_path.display())); diag.arg("exit_status", format!("{}", self.exit_status)); diff --git a/compiler/rustc_codegen_ssa/src/mir/block.rs b/compiler/rustc_codegen_ssa/src/mir/block.rs index bd9704b37ae..57138d3b9db 100644 --- a/compiler/rustc_codegen_ssa/src/mir/block.rs +++ b/compiler/rustc_codegen_ssa/src/mir/block.rs @@ -510,7 +510,7 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> { let ty = self.monomorphize(ty); let drop_fn = Instance::resolve_drop_in_place(bx.tcx(), ty); - if let ty::InstanceDef::DropGlue(_, None) = drop_fn.def { + if let ty::InstanceKind::DropGlue(_, None) = drop_fn.def { // we don't actually need to drop anything. return helper.funclet_br(self, bx, target, mergeable_succ); } @@ -541,7 +541,7 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> { // \-------/ // let virtual_drop = Instance { - def: ty::InstanceDef::Virtual(drop_fn.def_id(), 0), // idx 0: the drop function + def: ty::InstanceKind::Virtual(drop_fn.def_id(), 0), // idx 0: the drop function args: drop_fn.args, }; debug!("ty = {:?}", ty); @@ -583,7 +583,7 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> { // // SO THEN WE CAN USE THE ABOVE CODE. let virtual_drop = Instance { - def: ty::InstanceDef::Virtual(drop_fn.def_id(), 0), // idx 0: the drop function + def: ty::InstanceKind::Virtual(drop_fn.def_id(), 0), // idx 0: the drop function args: drop_fn.args, }; debug!("ty = {:?}", ty); @@ -855,7 +855,7 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> { let def = instance.map(|i| i.def); if let Some( - ty::InstanceDef::DropGlue(_, None) | ty::InstanceDef::AsyncDropGlueCtorShim(_, None), + ty::InstanceKind::DropGlue(_, None) | ty::InstanceKind::AsyncDropGlueCtorShim(_, None), ) = def { // Empty drop glue; a no-op. @@ -871,7 +871,7 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> { // Handle intrinsics old codegen wants Expr's for, ourselves. let intrinsic = match def { - Some(ty::InstanceDef::Intrinsic(def_id)) => Some(bx.tcx().intrinsic(def_id).unwrap()), + Some(ty::InstanceKind::Intrinsic(def_id)) => Some(bx.tcx().intrinsic(def_id).unwrap()), _ => None, }; @@ -1026,7 +1026,7 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> { 'make_args: for (i, arg) in first_args.iter().enumerate() { let mut op = self.codegen_operand(bx, &arg.node); - if let (0, Some(ty::InstanceDef::Virtual(_, idx))) = (i, def) { + if let (0, Some(ty::InstanceKind::Virtual(_, idx))) = (i, def) { match op.val { Pair(data_ptr, meta) => { // In the case of Rc<Self>, we need to explicitly pass a diff --git a/compiler/rustc_codegen_ssa/src/mir/rvalue.rs b/compiler/rustc_codegen_ssa/src/mir/rvalue.rs index ad6b3f1159d..3dc7dc35511 100644 --- a/compiler/rustc_codegen_ssa/src/mir/rvalue.rs +++ b/compiler/rustc_codegen_ssa/src/mir/rvalue.rs @@ -704,7 +704,7 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> { let static_ = if !def_id.is_local() && bx.cx().tcx().needs_thread_local_shim(def_id) { let instance = ty::Instance { - def: ty::InstanceDef::ThreadLocalShim(def_id), + def: ty::InstanceKind::ThreadLocalShim(def_id), args: ty::GenericArgs::empty(), }; let fn_ptr = bx.get_fn_addr(instance); diff --git a/compiler/rustc_codegen_ssa/src/traits/write.rs b/compiler/rustc_codegen_ssa/src/traits/write.rs index f83e34ab01b..f4b1421a532 100644 --- a/compiler/rustc_codegen_ssa/src/traits/write.rs +++ b/compiler/rustc_codegen_ssa/src/traits/write.rs @@ -2,7 +2,7 @@ use crate::back::lto::{LtoModuleCodegen, SerializedModule, ThinModule}; use crate::back::write::{CodegenContext, FatLtoInput, ModuleConfig}; use crate::{CompiledModule, ModuleCodegen}; -use rustc_errors::{DiagCtxt, FatalError}; +use rustc_errors::{DiagCtxtHandle, FatalError}; use rustc_middle::dep_graph::WorkProduct; pub trait WriteBackendMethods: 'static + Sized + Clone { @@ -16,7 +16,7 @@ pub trait WriteBackendMethods: 'static + Sized + Clone { /// Merge all modules into main_module and returning it fn run_link( cgcx: &CodegenContext<Self>, - dcx: &DiagCtxt, + dcx: DiagCtxtHandle<'_>, modules: Vec<ModuleCodegen<Self::Module>>, ) -> Result<ModuleCodegen<Self::Module>, FatalError>; /// Performs fat LTO by merging all modules into a single one and returning it @@ -38,7 +38,7 @@ pub trait WriteBackendMethods: 'static + Sized + Clone { fn print_statistics(&self); unsafe fn optimize( cgcx: &CodegenContext<Self>, - dcx: &DiagCtxt, + dcx: DiagCtxtHandle<'_>, module: &ModuleCodegen<Self::Module>, config: &ModuleConfig, ) -> Result<(), FatalError>; @@ -52,7 +52,7 @@ pub trait WriteBackendMethods: 'static + Sized + Clone { ) -> Result<ModuleCodegen<Self::Module>, FatalError>; unsafe fn codegen( cgcx: &CodegenContext<Self>, - dcx: &DiagCtxt, + dcx: DiagCtxtHandle<'_>, module: ModuleCodegen<Self::Module>, config: &ModuleConfig, ) -> Result<CompiledModule, FatalError>; diff --git a/compiler/rustc_const_eval/messages.ftl b/compiler/rustc_const_eval/messages.ftl index 2dbeb7d5e0c..1a7e5bd7092 100644 --- a/compiler/rustc_const_eval/messages.ftl +++ b/compiler/rustc_const_eval/messages.ftl @@ -73,8 +73,6 @@ const_eval_division_by_zero = dividing by zero const_eval_division_overflow = overflow in signed division (dividing MIN by -1) -const_eval_double_storage_live = - StorageLive on a local that was already live const_eval_dyn_call_not_a_method = `dyn` call trying to call something that is not a method @@ -399,7 +397,6 @@ const_eval_unwind_past_top = ## The `front_matter`s here refer to either `const_eval_front_matter_invalid_value` or `const_eval_front_matter_invalid_value_with_path`. ## (We'd love to sort this differently to make that more clear but tidy won't let us...) -const_eval_validation_box_to_static = {$front_matter}: encountered a box pointing to a static variable in a constant const_eval_validation_box_to_uninhabited = {$front_matter}: encountered a box pointing to uninhabited type {$ty} const_eval_validation_const_ref_to_extern = {$front_matter}: encountered reference to `extern` static in `const` @@ -454,7 +451,6 @@ const_eval_validation_out_of_range = {$front_matter}: encountered {$value}, but const_eval_validation_partial_pointer = {$front_matter}: encountered a partial pointer or a mix of pointers const_eval_validation_pointer_as_int = {$front_matter}: encountered a pointer, but {$expected} const_eval_validation_ptr_out_of_range = {$front_matter}: encountered a pointer, but expected something that cannot possibly fail to be {$in_range} -const_eval_validation_ref_to_static = {$front_matter}: encountered a reference pointing to a static variable in a constant const_eval_validation_ref_to_uninhabited = {$front_matter}: encountered a reference pointing to uninhabited type {$ty} const_eval_validation_unaligned_box = {$front_matter}: encountered an unaligned box (required {$required_bytes} byte alignment but found {$found_bytes}) const_eval_validation_unaligned_ref = {$front_matter}: encountered an unaligned reference (required {$required_bytes} byte alignment but found {$found_bytes}) diff --git a/compiler/rustc_const_eval/src/check_consts/check.rs b/compiler/rustc_const_eval/src/check_consts/check.rs index 0818d9425e2..ab60cc37920 100644 --- a/compiler/rustc_const_eval/src/check_consts/check.rs +++ b/compiler/rustc_const_eval/src/check_consts/check.rs @@ -10,7 +10,7 @@ use rustc_middle::mir::visit::{MutatingUseContext, NonMutatingUseContext, PlaceC use rustc_middle::mir::*; use rustc_middle::span_bug; use rustc_middle::ty::{self, adjustment::PointerCoercion, Ty, TyCtxt}; -use rustc_middle::ty::{Instance, InstanceDef, TypeVisitableExt}; +use rustc_middle::ty::{Instance, InstanceKind, TypeVisitableExt}; use rustc_mir_dataflow::Analysis; use rustc_span::{sym, Span, Symbol, DUMMY_SP}; use rustc_trait_selection::traits::error_reporting::TypeErrCtxtExt as _; @@ -769,7 +769,7 @@ impl<'tcx> Visitor<'tcx> for Checker<'_, 'tcx> { if let Ok(Some(instance)) = Instance::resolve(tcx, param_env, callee, fn_args) - && let InstanceDef::Item(def) = instance.def + && let InstanceKind::Item(def) = instance.def { // Resolve a trait method call to its concrete implementation, which may be in a // `const` trait impl. This is only used for the const stability check below, since diff --git a/compiler/rustc_const_eval/src/check_consts/mod.rs b/compiler/rustc_const_eval/src/check_consts/mod.rs index 308b90cd470..ac8f0d842ee 100644 --- a/compiler/rustc_const_eval/src/check_consts/mod.rs +++ b/compiler/rustc_const_eval/src/check_consts/mod.rs @@ -5,7 +5,7 @@ //! it finds operations that are invalid in a certain context. use rustc_attr as attr; -use rustc_errors::DiagCtxt; +use rustc_errors::DiagCtxtHandle; use rustc_hir as hir; use rustc_hir::def_id::{DefId, LocalDefId}; use rustc_middle::bug; @@ -46,7 +46,7 @@ impl<'mir, 'tcx> ConstCx<'mir, 'tcx> { ConstCx { body, tcx, param_env, const_kind } } - pub(crate) fn dcx(&self) -> &'tcx DiagCtxt { + pub(crate) fn dcx(&self) -> DiagCtxtHandle<'tcx> { self.tcx.dcx() } diff --git a/compiler/rustc_const_eval/src/check_consts/ops.rs b/compiler/rustc_const_eval/src/check_consts/ops.rs index eb9a83fb9cf..55432e63ef9 100644 --- a/compiler/rustc_const_eval/src/check_consts/ops.rs +++ b/compiler/rustc_const_eval/src/check_consts/ops.rs @@ -138,7 +138,7 @@ impl<'tcx> NonConstOp<'tcx> for FnCallNonConst<'tcx> { // FIXME(effects) revisit this if !tcx.is_const_trait_impl_raw(data.impl_def_id) { let span = tcx.def_span(data.impl_def_id); - err.subdiagnostic(tcx.dcx(), errors::NonConstImplNote { span }); + err.subdiagnostic(errors::NonConstImplNote { span }); } } } 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 4b8145eb485..c60df06bb0e 100644 --- a/compiler/rustc_const_eval/src/const_eval/eval_queries.rs +++ b/compiler/rustc_const_eval/src/const_eval/eval_queries.rs @@ -289,7 +289,7 @@ pub fn eval_to_const_value_raw_provider<'tcx>( // We call `const_eval` for zero arg intrinsics, too, in order to cache their value. // Catch such calls and evaluate them instead of trying to load a constant's MIR. - if let ty::InstanceDef::Intrinsic(def_id) = key.value.instance.def { + if let ty::InstanceKind::Intrinsic(def_id) = key.value.instance.def { let ty = key.value.instance.ty(tcx, key.param_env); let ty::FnDef(_, args) = ty.kind() else { bug!("intrinsic with type {:?}", ty); diff --git a/compiler/rustc_const_eval/src/const_eval/machine.rs b/compiler/rustc_const_eval/src/const_eval/machine.rs index d3631e0d723..99276bac035 100644 --- a/compiler/rustc_const_eval/src/const_eval/machine.rs +++ b/compiler/rustc_const_eval/src/const_eval/machine.rs @@ -398,10 +398,10 @@ impl<'tcx> interpret::Machine<'tcx> for CompileTimeMachine<'tcx> { fn load_mir( ecx: &InterpCx<'tcx, Self>, - instance: ty::InstanceDef<'tcx>, + instance: ty::InstanceKind<'tcx>, ) -> InterpResult<'tcx, &'tcx mir::Body<'tcx>> { match instance { - ty::InstanceDef::Item(def) => Ok(ecx.tcx.mir_for_ctfe(def)), + ty::InstanceKind::Item(def) => Ok(ecx.tcx.mir_for_ctfe(def)), _ => Ok(ecx.tcx.instance_mir(instance)), } } @@ -424,7 +424,7 @@ impl<'tcx> interpret::Machine<'tcx> for CompileTimeMachine<'tcx> { }; // Only check non-glue functions - if let ty::InstanceDef::Item(def) = instance.def { + if let ty::InstanceKind::Item(def) = instance.def { // Execution might have wandered off into other crates, so we cannot do a stability- // sensitive check here. But we can at least rule out functions that are not const at // all. That said, we have to allow calling functions inside a trait marked with @@ -540,7 +540,7 @@ impl<'tcx> interpret::Machine<'tcx> for CompileTimeMachine<'tcx> { ); } return Ok(Some(ty::Instance { - def: ty::InstanceDef::Item(instance.def_id()), + def: ty::InstanceKind::Item(instance.def_id()), args: instance.args, })); } diff --git a/compiler/rustc_const_eval/src/errors.rs b/compiler/rustc_const_eval/src/errors.rs index e5ea4c3442e..5fa48a59794 100644 --- a/compiler/rustc_const_eval/src/errors.rs +++ b/compiler/rustc_const_eval/src/errors.rs @@ -2,7 +2,7 @@ use std::borrow::Cow; use either::Either; use rustc_errors::{ - codes::*, Diag, DiagArgValue, DiagCtxt, DiagMessage, Diagnostic, EmissionGuarantee, Level, + codes::*, Diag, DiagArgValue, DiagCtxtHandle, DiagMessage, Diagnostic, EmissionGuarantee, Level, }; use rustc_hir::ConstContext; use rustc_macros::{Diagnostic, LintDiagnostic, Subdiagnostic}; @@ -453,7 +453,7 @@ pub trait ReportErrorExt { } } -fn bad_pointer_message(msg: CheckInAllocMsg, dcx: &DiagCtxt) -> String { +fn bad_pointer_message(msg: CheckInAllocMsg, dcx: DiagCtxtHandle<'_>) -> String { use crate::fluent_generated::*; let msg = match msg { @@ -640,9 +640,6 @@ impl<'tcx> ReportErrorExt for ValidationErrorInfo<'tcx> { const_eval_validation_ref_to_uninhabited } - PtrToStatic { ptr_kind: PointerKind::Box } => const_eval_validation_box_to_static, - PtrToStatic { ptr_kind: PointerKind::Ref(_) } => const_eval_validation_ref_to_static, - PointerAsInt { .. } => const_eval_validation_pointer_as_int, PartialPointer => const_eval_validation_partial_pointer, ConstRefToMutable => const_eval_validation_const_ref_to_mutable, @@ -807,7 +804,6 @@ impl<'tcx> ReportErrorExt for ValidationErrorInfo<'tcx> { ); } NullPtr { .. } - | PtrToStatic { .. } | ConstRefToMutable | ConstRefToExtern | MutableRefToImmutable diff --git a/compiler/rustc_const_eval/src/interpret/discriminant.rs b/compiler/rustc_const_eval/src/interpret/discriminant.rs index a50b50d231d..b3a139d553a 100644 --- a/compiler/rustc_const_eval/src/interpret/discriminant.rs +++ b/compiler/rustc_const_eval/src/interpret/discriminant.rs @@ -241,7 +241,16 @@ 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 { .. } => Ok(None), + abi::Variants::Single { .. } => { + // The tag of a `Single` enum is like the tag of the niched + // variant: there's no tag as the discriminant is encoded + // entirely implicitly. If `write_discriminant` ever hits this + // case, we do a "validation read" to ensure the the right + // discriminant is encoded implicitly, so any attempt to write + // the wrong discriminant for a `Single` enum will reliably + // result in UB. + 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 4d93038a81e..67eeb1b3b87 100644 --- a/compiler/rustc_const_eval/src/interpret/eval_context.rs +++ b/compiler/rustc_const_eval/src/interpret/eval_context.rs @@ -4,7 +4,7 @@ use std::{fmt, mem}; use either::{Either, Left, Right}; use tracing::{debug, info, info_span, instrument, trace}; -use rustc_errors::DiagCtxt; +use rustc_errors::DiagCtxtHandle; use rustc_hir::{self as hir, def_id::DefId, definitions::DefPathData}; use rustc_index::IndexVec; use rustc_middle::mir; @@ -474,7 +474,7 @@ pub(super) fn from_known_layout<'tcx>( /// /// This is NOT the preferred way to render an error; use `report` from `const_eval` instead. /// However, this is useful when error messages appear in ICEs. -pub fn format_interp_error<'tcx>(dcx: &DiagCtxt, e: InterpErrorInfo<'tcx>) -> String { +pub fn format_interp_error<'tcx>(dcx: DiagCtxtHandle<'_>, e: InterpErrorInfo<'tcx>) -> String { let (e, backtrace) = e.into_parts(); backtrace.print_backtrace(); // FIXME(fee1-dead), HACK: we want to use the error as title therefore we can just extract the @@ -562,7 +562,7 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> { pub fn load_mir( &self, - instance: ty::InstanceDef<'tcx>, + instance: ty::InstanceKind<'tcx>, promoted: Option<mir::Promoted>, ) -> InterpResult<'tcx, &'tcx mir::Body<'tcx>> { trace!("load mir(instance={:?}, promoted={:?})", instance, promoted); @@ -1100,11 +1100,9 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> { Operand::Immediate(Immediate::Uninit) }); - // StorageLive expects the local to be dead, and marks it live. + // If the local is already live, deallocate its old memory. let old = mem::replace(&mut self.frame_mut().locals[local].value, local_val); - if !matches!(old, LocalValue::Dead) { - throw_ub_custom!(fluent::const_eval_double_storage_live); - } + self.deallocate_local(old)?; Ok(()) } @@ -1118,7 +1116,7 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> { assert!(local != mir::RETURN_PLACE, "Cannot make return place dead"); trace!("{:?} is now dead", local); - // It is entirely okay for this local to be already dead (at least that's how we currently generate MIR) + // If the local is already dead, this is a NOP. let old = mem::replace(&mut self.frame_mut().locals[local].value, LocalValue::Dead); self.deallocate_local(old)?; Ok(()) diff --git a/compiler/rustc_const_eval/src/interpret/machine.rs b/compiler/rustc_const_eval/src/interpret/machine.rs index 4ae0aca5a0c..e91ab7c1791 100644 --- a/compiler/rustc_const_eval/src/interpret/machine.rs +++ b/compiler/rustc_const_eval/src/interpret/machine.rs @@ -177,7 +177,7 @@ pub trait Machine<'tcx>: Sized { /// constants, ... fn load_mir( ecx: &InterpCx<'tcx, Self>, - instance: ty::InstanceDef<'tcx>, + instance: ty::InstanceKind<'tcx>, ) -> InterpResult<'tcx, &'tcx mir::Body<'tcx>> { Ok(ecx.tcx.instance_mir(instance)) } diff --git a/compiler/rustc_const_eval/src/interpret/terminator.rs b/compiler/rustc_const_eval/src/interpret/terminator.rs index 8f76a148679..74521d0f493 100644 --- a/compiler/rustc_const_eval/src/interpret/terminator.rs +++ b/compiler/rustc_const_eval/src/interpret/terminator.rs @@ -175,7 +175,7 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> { Drop { place, target, unwind, replace: _ } => { let place = self.eval_place(place)?; let instance = Instance::resolve_drop_in_place(*self.tcx, place.layout.ty); - if let ty::InstanceDef::DropGlue(_, None) = instance.def { + if let ty::InstanceKind::DropGlue(_, None) = instance.def { // This is the branch we enter if and only if the dropped type has no drop glue // whatsoever. This can happen as a result of monomorphizing a drop of a // generic. In order to make sure that generic and non-generic code behaves @@ -550,7 +550,7 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> { }; match instance.def { - ty::InstanceDef::Intrinsic(def_id) => { + ty::InstanceKind::Intrinsic(def_id) => { assert!(self.tcx.intrinsic(def_id).is_some()); // FIXME: Should `InPlace` arguments be reset to uninit? if let Some(fallback) = M::call_intrinsic( @@ -562,7 +562,7 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> { unwind, )? { assert!(!self.tcx.intrinsic(fallback.def_id()).unwrap().must_be_overridden); - assert!(matches!(fallback.def, ty::InstanceDef::Item(_))); + assert!(matches!(fallback.def, ty::InstanceKind::Item(_))); return self.eval_fn_call( FnVal::Instance(fallback), (caller_abi, caller_fn_abi), @@ -576,18 +576,18 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> { Ok(()) } } - ty::InstanceDef::VTableShim(..) - | ty::InstanceDef::ReifyShim(..) - | ty::InstanceDef::ClosureOnceShim { .. } - | ty::InstanceDef::ConstructCoroutineInClosureShim { .. } - | ty::InstanceDef::CoroutineKindShim { .. } - | ty::InstanceDef::FnPtrShim(..) - | ty::InstanceDef::DropGlue(..) - | ty::InstanceDef::CloneShim(..) - | ty::InstanceDef::FnPtrAddrShim(..) - | ty::InstanceDef::ThreadLocalShim(..) - | ty::InstanceDef::AsyncDropGlueCtorShim(..) - | ty::InstanceDef::Item(_) => { + ty::InstanceKind::VTableShim(..) + | ty::InstanceKind::ReifyShim(..) + | ty::InstanceKind::ClosureOnceShim { .. } + | ty::InstanceKind::ConstructCoroutineInClosureShim { .. } + | ty::InstanceKind::CoroutineKindShim { .. } + | ty::InstanceKind::FnPtrShim(..) + | ty::InstanceKind::DropGlue(..) + | ty::InstanceKind::CloneShim(..) + | ty::InstanceKind::FnPtrAddrShim(..) + | ty::InstanceKind::ThreadLocalShim(..) + | ty::InstanceKind::AsyncDropGlueCtorShim(..) + | ty::InstanceKind::Item(_) => { // We need MIR for this fn let Some((body, instance)) = M::find_mir_or_eval_fn( self, @@ -786,9 +786,9 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> { Ok(()) => Ok(()), } } - // `InstanceDef::Virtual` does not have callable MIR. Calls to `Virtual` instances must be + // `InstanceKind::Virtual` does not have callable MIR. Calls to `Virtual` instances must be // codegen'd / interpreted as virtual calls through the vtable. - ty::InstanceDef::Virtual(def_id, idx) => { + ty::InstanceKind::Virtual(def_id, idx) => { let mut args = args.to_vec(); // We have to implement all "object safe receivers". So we have to go search for a // pointer or `dyn Trait` type, but it could be wrapped in newtypes. So recursively @@ -965,7 +965,7 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> { let place = self.force_allocation(place)?; // We behave a bit different from codegen here. - // Codegen creates an `InstanceDef::Virtual` with index 0 (the slot of the drop method) and + // Codegen creates an `InstanceKind::Virtual` with index 0 (the slot of the drop method) and // then dispatches that to the normal call machinery. However, our call machinery currently // only supports calling `VtblEntry::Method`; it would choke on a `MetadataDropInPlace`. So // instead we do the virtual call stuff ourselves. It's easier here than in `eval_fn_call` diff --git a/compiler/rustc_const_eval/src/interpret/util.rs b/compiler/rustc_const_eval/src/interpret/util.rs index f6537ed6ea9..bbe5e5fe3ed 100644 --- a/compiler/rustc_const_eval/src/interpret/util.rs +++ b/compiler/rustc_const_eval/src/interpret/util.rs @@ -44,7 +44,7 @@ where | ty::CoroutineClosure(def_id, args, ..) | ty::Coroutine(def_id, args, ..) | ty::FnDef(def_id, args) => { - let instance = ty::InstanceDef::Item(def_id); + let instance = ty::InstanceKind::Item(def_id); let unused_params = self.tcx.unused_generic_params(instance); for (index, arg) in args.into_iter().enumerate() { let index = index diff --git a/compiler/rustc_data_structures/src/flock.rs b/compiler/rustc_data_structures/src/flock.rs index 008565e4c7b..e03962a54ec 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_driver_impl/src/lib.rs b/compiler/rustc_driver_impl/src/lib.rs index 9acff4a0a26..5ffa3a6099c 100644 --- a/compiler/rustc_driver_impl/src/lib.rs +++ b/compiler/rustc_driver_impl/src/lib.rs @@ -1444,6 +1444,7 @@ fn report_ice( fallback_bundle, )); let dcx = rustc_errors::DiagCtxt::new(emitter); + let dcx = dcx.handle(); // a .span_bug or .bug call has already printed what // it wants to print. @@ -1509,7 +1510,7 @@ fn report_ice( let num_frames = if backtrace { None } else { Some(2) }; - interface::try_print_query_stack(&dcx, num_frames, file); + interface::try_print_query_stack(dcx, num_frames, file); // We don't trust this callback not to panic itself, so run it at the end after we're sure we've // printed all the relevant info. diff --git a/compiler/rustc_errors/src/diagnostic.rs b/compiler/rustc_errors/src/diagnostic.rs index 34b569c4206..e580910af77 100644 --- a/compiler/rustc_errors/src/diagnostic.rs +++ b/compiler/rustc_errors/src/diagnostic.rs @@ -1,7 +1,7 @@ use crate::snippet::Style; use crate::{ - CodeSuggestion, DiagCtxt, DiagMessage, ErrCode, ErrorGuaranteed, ExplicitBug, Level, MultiSpan, - StashKey, SubdiagMessage, Substitution, SubstitutionPart, SuggestionStyle, + CodeSuggestion, DiagCtxtHandle, DiagMessage, ErrCode, ErrorGuaranteed, ExplicitBug, Level, + MultiSpan, StashKey, SubdiagMessage, Substitution, SubstitutionPart, SuggestionStyle, }; use rustc_data_structures::fx::FxIndexMap; use rustc_error_messages::fluent_value_from_str_list_sep_by_and; @@ -133,7 +133,7 @@ impl EmissionGuarantee for rustc_span::fatal_error::FatalError { pub trait Diagnostic<'a, G: EmissionGuarantee = ErrorGuaranteed> { /// Write out as a diagnostic out of `DiagCtxt`. #[must_use] - fn into_diag(self, dcx: &'a DiagCtxt, level: Level) -> Diag<'a, G>; + fn into_diag(self, dcx: DiagCtxtHandle<'a>, level: Level) -> Diag<'a, G>; } impl<'a, T, G> Diagnostic<'a, G> for Spanned<T> @@ -141,7 +141,7 @@ where T: Diagnostic<'a, G>, G: EmissionGuarantee, { - fn into_diag(self, dcx: &'a DiagCtxt, level: Level) -> Diag<'a, G> { + fn into_diag(self, dcx: DiagCtxtHandle<'a>, level: Level) -> Diag<'a, G> { self.node.into_diag(dcx, level).with_span(self.span) } } @@ -490,7 +490,7 @@ pub struct Subdiag { /// the methods of `Diag` here, consider extending `DiagCtxtFlags`. #[must_use] pub struct Diag<'a, G: EmissionGuarantee = ErrorGuaranteed> { - pub dcx: &'a DiagCtxt, + pub dcx: DiagCtxtHandle<'a>, /// Why the `Option`? It is always `Some` until the `Diag` is consumed via /// `emit`, `cancel`, etc. At that point it is consumed and replaced with @@ -578,13 +578,13 @@ macro_rules! with_fn { impl<'a, G: EmissionGuarantee> Diag<'a, G> { #[rustc_lint_diagnostics] #[track_caller] - pub fn new(dcx: &'a DiagCtxt, level: Level, message: impl Into<DiagMessage>) -> Self { + pub fn new(dcx: DiagCtxtHandle<'a>, level: Level, message: impl Into<DiagMessage>) -> Self { Self::new_diagnostic(dcx, DiagInner::new(level, message)) } /// Creates a new `Diag` with an already constructed diagnostic. #[track_caller] - pub(crate) fn new_diagnostic(dcx: &'a DiagCtxt, diag: DiagInner) -> Self { + pub(crate) fn new_diagnostic(dcx: DiagCtxtHandle<'a>, diag: DiagInner) -> Self { debug!("Created new diagnostic"); Self { dcx, diag: Some(Box::new(diag)), _marker: PhantomData } } @@ -1192,11 +1192,8 @@ impl<'a, G: EmissionGuarantee> Diag<'a, G> { /// used in the subdiagnostic, so suitable for use with repeated messages (i.e. re-use of /// interpolated variables). #[rustc_lint_diagnostics] - pub fn subdiagnostic( - &mut self, - dcx: &crate::DiagCtxt, - subdiagnostic: impl Subdiagnostic, - ) -> &mut Self { + pub fn subdiagnostic(&mut self, subdiagnostic: impl Subdiagnostic) -> &mut Self { + let dcx = self.dcx; subdiagnostic.add_to_diag_with(self, &|diag, msg| { let args = diag.args.iter(); let msg = diag.subdiagnostic_message_to_diagnostic_message(msg); @@ -1341,7 +1338,8 @@ impl<'a, G: EmissionGuarantee> Diag<'a, G> { /// See `DiagCtxt::stash_diagnostic` for details. pub fn stash(mut self, span: Span, key: StashKey) -> Option<ErrorGuaranteed> { - self.dcx.stash_diagnostic(span, key, self.take_diag()) + let diag = self.take_diag(); + self.dcx.stash_diagnostic(span, key, diag) } /// Delay emission of this diagnostic as a bug. diff --git a/compiler/rustc_errors/src/diagnostic_impls.rs b/compiler/rustc_errors/src/diagnostic_impls.rs index ee6df8e15db..0af80bc5c67 100644 --- a/compiler/rustc_errors/src/diagnostic_impls.rs +++ b/compiler/rustc_errors/src/diagnostic_impls.rs @@ -1,7 +1,7 @@ use crate::diagnostic::DiagLocation; -use crate::{fluent_generated as fluent, Subdiagnostic}; +use crate::{fluent_generated as fluent, DiagCtxtHandle, Subdiagnostic}; use crate::{ - Diag, DiagArgValue, DiagCtxt, Diagnostic, EmissionGuarantee, ErrCode, IntoDiagArg, Level, + Diag, DiagArgValue, Diagnostic, EmissionGuarantee, ErrCode, IntoDiagArg, Level, SubdiagMessageOp, }; use rustc_ast as ast; @@ -315,7 +315,7 @@ impl IntoDiagArg for DiagSymbolList { } impl<G: EmissionGuarantee> Diagnostic<'_, G> for TargetDataLayoutErrors<'_> { - fn into_diag(self, dcx: &DiagCtxt, level: Level) -> Diag<'_, G> { + fn into_diag(self, dcx: DiagCtxtHandle<'_>, level: Level) -> Diag<'_, G> { match self { TargetDataLayoutErrors::InvalidAddressSpace { addr_space, err, cause } => { Diag::new(dcx, level, fluent::errors_target_invalid_address_space) diff --git a/compiler/rustc_errors/src/emitter.rs b/compiler/rustc_errors/src/emitter.rs index 5d4d2555100..245deda50d5 100644 --- a/compiler/rustc_errors/src/emitter.rs +++ b/compiler/rustc_errors/src/emitter.rs @@ -567,7 +567,7 @@ impl Emitter for SilentEmitter { if let Some(fatal_note) = &self.fatal_note { diag.sub(Level::Note, fatal_note.clone(), MultiSpan::new()); } - self.fatal_dcx.emit_diagnostic(diag); + self.fatal_dcx.handle().emit_diagnostic(diag); } } } diff --git a/compiler/rustc_errors/src/json/tests.rs b/compiler/rustc_errors/src/json/tests.rs index 80b4d2bf75c..e4b29fc9103 100644 --- a/compiler/rustc_errors/src/json/tests.rs +++ b/compiler/rustc_errors/src/json/tests.rs @@ -55,8 +55,7 @@ fn test_positions(code: &str, span: (u32, u32), expected_output: SpanTestData) { ); let span = Span::with_root_ctxt(BytePos(span.0), BytePos(span.1)); - let dcx = DiagCtxt::new(Box::new(je)); - dcx.span_err(span, "foo"); + DiagCtxt::new(Box::new(je)).handle().span_err(span, "foo"); let bytes = output.lock().unwrap(); let actual_output = str::from_utf8(&bytes).unwrap(); diff --git a/compiler/rustc_errors/src/lib.rs b/compiler/rustc_errors/src/lib.rs index 4dc5d84b318..83d5bbff0b0 100644 --- a/compiler/rustc_errors/src/lib.rs +++ b/compiler/rustc_errors/src/lib.rs @@ -414,6 +414,19 @@ pub struct DiagCtxt { inner: Lock<DiagCtxtInner>, } +#[derive(Copy, Clone)] +pub struct DiagCtxtHandle<'a> { + dcx: &'a DiagCtxt, +} + +impl<'a> std::ops::Deref for DiagCtxtHandle<'a> { + type Target = &'a DiagCtxt; + + fn deref(&self) -> &Self::Target { + &self.dcx + } +} + /// This inner struct exists to keep it all behind a single lock; /// this is done to prevent possible deadlocks in a multi-threaded compiler, /// as well as inconsistent state observation. @@ -608,7 +621,7 @@ impl DiagCtxt { } pub fn make_silent( - &mut self, + &self, fallback_bundle: LazyFallbackBundle, fatal_note: Option<String>, emit_fatal_diagnostic: bool, @@ -623,7 +636,7 @@ impl DiagCtxt { }); } - fn wrap_emitter<F>(&mut self, f: F) + fn wrap_emitter<F>(&self, f: F) where F: FnOnce(DiagCtxtInner) -> Box<DynEmitter>, { @@ -738,6 +751,12 @@ impl DiagCtxt { *fulfilled_expectations = Default::default(); } + pub fn handle<'a>(&'a self) -> DiagCtxtHandle<'a> { + DiagCtxtHandle { dcx: self } + } +} + +impl<'a> DiagCtxtHandle<'a> { /// Stashes a diagnostic for possible later improvement in a different, /// later stage of the compiler. Possible actions depend on the diagnostic /// level: @@ -745,8 +764,8 @@ impl DiagCtxt { /// - Level::Error: immediately counted as an error that has occurred, because it /// is guaranteed to be emitted eventually. Can be later accessed with the /// provided `span` and `key` through - /// [`DiagCtxt::try_steal_modify_and_emit_err`] or - /// [`DiagCtxt::try_steal_replace_and_emit_err`]. These do not allow + /// [`DiagCtxtHandle::try_steal_modify_and_emit_err`] or + /// [`DiagCtxtHandle::try_steal_replace_and_emit_err`]. These do not allow /// cancellation or downgrading of the error. Returns /// `Some(ErrorGuaranteed)`. /// - Level::DelayedBug: this does happen occasionally with errors that are @@ -757,7 +776,7 @@ impl DiagCtxt { /// user-facing error. Returns `Some(ErrorGuaranteed)` as is normal for /// delayed bugs. /// - Level::Warning and lower (i.e. !is_error()): can be accessed with the - /// provided `span` and `key` through [`DiagCtxt::steal_non_err()`]. This + /// provided `span` and `key` through [`DiagCtxtHandle::steal_non_err()`]. This /// allows cancelling and downgrading of the diagnostic. Returns `None`. pub fn stash_diagnostic( &self, @@ -793,7 +812,7 @@ impl DiagCtxt { /// Steal a previously stashed non-error diagnostic with the given `Span` /// and [`StashKey`] as the key. Panics if the found diagnostic is an /// error. - pub fn steal_non_err(&self, span: Span, key: StashKey) -> Option<Diag<'_, ()>> { + pub fn steal_non_err(self, span: Span, key: StashKey) -> Option<Diag<'a, ()>> { let key = (span.with_parent(None), key); // FIXME(#120456) - is `swap_remove` correct? let (diag, guar) = self.inner.borrow_mut().stashed_diagnostics.swap_remove(&key)?; @@ -807,7 +826,7 @@ impl DiagCtxt { /// no matching diagnostic is found. Panics if the found diagnostic's level /// isn't `Level::Error`. pub fn try_steal_modify_and_emit_err<F>( - &self, + self, span: Span, key: StashKey, mut modify_err: F, @@ -833,7 +852,7 @@ impl DiagCtxt { /// [`StashKey`] as the key, cancels it if found, and emits `new_err`. /// Panics if the found diagnostic's level isn't `Level::Error`. pub fn try_steal_replace_and_emit_err( - &self, + self, span: Span, key: StashKey, new_err: Diag<'_>, @@ -1106,18 +1125,18 @@ impl DiagCtxt { // // Functions beginning with `struct_`/`create_` create a diagnostic. Other // functions create and emit a diagnostic all in one go. -impl DiagCtxt { +impl<'a> DiagCtxtHandle<'a> { // No `#[rustc_lint_diagnostics]` and no `impl Into<DiagMessage>` because bug messages aren't // user-facing. #[track_caller] - pub fn struct_bug(&self, msg: impl Into<Cow<'static, str>>) -> Diag<'_, BugAbort> { + pub fn struct_bug(self, msg: impl Into<Cow<'static, str>>) -> Diag<'a, BugAbort> { Diag::new(self, Bug, msg.into()) } // No `#[rustc_lint_diagnostics]` and no `impl Into<DiagMessage>` because bug messages aren't // user-facing. #[track_caller] - pub fn bug(&self, msg: impl Into<Cow<'static, str>>) -> ! { + pub fn bug(self, msg: impl Into<Cow<'static, str>>) -> ! { self.struct_bug(msg).emit() } @@ -1125,111 +1144,108 @@ impl DiagCtxt { // user-facing. #[track_caller] pub fn struct_span_bug( - &self, + self, span: impl Into<MultiSpan>, msg: impl Into<Cow<'static, str>>, - ) -> Diag<'_, BugAbort> { + ) -> Diag<'a, BugAbort> { self.struct_bug(msg).with_span(span) } // No `#[rustc_lint_diagnostics]` and no `impl Into<DiagMessage>` because bug messages aren't // user-facing. #[track_caller] - pub fn span_bug(&self, span: impl Into<MultiSpan>, msg: impl Into<Cow<'static, str>>) -> ! { + pub fn span_bug(self, span: impl Into<MultiSpan>, msg: impl Into<Cow<'static, str>>) -> ! { self.struct_span_bug(span, msg.into()).emit() } #[track_caller] - pub fn create_bug<'a>(&'a self, bug: impl Diagnostic<'a, BugAbort>) -> Diag<'a, BugAbort> { + pub fn create_bug(self, bug: impl Diagnostic<'a, BugAbort>) -> Diag<'a, BugAbort> { bug.into_diag(self, Bug) } #[track_caller] - pub fn emit_bug<'a>(&'a self, bug: impl Diagnostic<'a, BugAbort>) -> ! { + pub fn emit_bug(self, bug: impl Diagnostic<'a, BugAbort>) -> ! { self.create_bug(bug).emit() } #[rustc_lint_diagnostics] #[track_caller] - pub fn struct_fatal(&self, msg: impl Into<DiagMessage>) -> Diag<'_, FatalAbort> { + pub fn struct_fatal(self, msg: impl Into<DiagMessage>) -> Diag<'a, FatalAbort> { Diag::new(self, Fatal, msg) } #[rustc_lint_diagnostics] #[track_caller] - pub fn fatal(&self, msg: impl Into<DiagMessage>) -> ! { + pub fn fatal(self, msg: impl Into<DiagMessage>) -> ! { self.struct_fatal(msg).emit() } #[rustc_lint_diagnostics] #[track_caller] pub fn struct_span_fatal( - &self, + self, span: impl Into<MultiSpan>, msg: impl Into<DiagMessage>, - ) -> Diag<'_, FatalAbort> { + ) -> Diag<'a, FatalAbort> { self.struct_fatal(msg).with_span(span) } #[rustc_lint_diagnostics] #[track_caller] - pub fn span_fatal(&self, span: impl Into<MultiSpan>, msg: impl Into<DiagMessage>) -> ! { + pub fn span_fatal(self, span: impl Into<MultiSpan>, msg: impl Into<DiagMessage>) -> ! { self.struct_span_fatal(span, msg).emit() } #[track_caller] - pub fn create_fatal<'a>( - &'a self, - fatal: impl Diagnostic<'a, FatalAbort>, - ) -> Diag<'a, FatalAbort> { + pub fn create_fatal(self, fatal: impl Diagnostic<'a, FatalAbort>) -> Diag<'a, FatalAbort> { fatal.into_diag(self, Fatal) } #[track_caller] - pub fn emit_fatal<'a>(&'a self, fatal: impl Diagnostic<'a, FatalAbort>) -> ! { + pub fn emit_fatal(self, fatal: impl Diagnostic<'a, FatalAbort>) -> ! { self.create_fatal(fatal).emit() } #[track_caller] - pub fn create_almost_fatal<'a>( - &'a self, + pub fn create_almost_fatal( + self, fatal: impl Diagnostic<'a, FatalError>, ) -> Diag<'a, FatalError> { fatal.into_diag(self, Fatal) } #[track_caller] - pub fn emit_almost_fatal<'a>(&'a self, fatal: impl Diagnostic<'a, FatalError>) -> FatalError { + pub fn emit_almost_fatal(self, fatal: impl Diagnostic<'a, FatalError>) -> FatalError { self.create_almost_fatal(fatal).emit() } // FIXME: This method should be removed (every error should have an associated error code). #[rustc_lint_diagnostics] #[track_caller] - pub fn struct_err(&self, msg: impl Into<DiagMessage>) -> Diag<'_> { + pub fn struct_err(self, msg: impl Into<DiagMessage>) -> Diag<'a> { Diag::new(self, Error, msg) } #[rustc_lint_diagnostics] #[track_caller] - pub fn err(&self, msg: impl Into<DiagMessage>) -> ErrorGuaranteed { + pub fn err(self, msg: impl Into<DiagMessage>) -> ErrorGuaranteed { self.struct_err(msg).emit() } #[rustc_lint_diagnostics] #[track_caller] pub fn struct_span_err( - &self, + self, span: impl Into<MultiSpan>, msg: impl Into<DiagMessage>, - ) -> Diag<'_> { + ) -> Diag<'a> { self.struct_err(msg).with_span(span) } #[rustc_lint_diagnostics] #[track_caller] pub fn span_err( - &self, + self, span: impl Into<MultiSpan>, msg: impl Into<DiagMessage>, ) -> ErrorGuaranteed { @@ -1237,12 +1253,12 @@ impl DiagCtxt { } #[track_caller] - pub fn create_err<'a>(&'a self, err: impl Diagnostic<'a>) -> Diag<'a> { + pub fn create_err(self, err: impl Diagnostic<'a>) -> Diag<'a> { err.into_diag(self, Error) } #[track_caller] - pub fn emit_err<'a>(&'a self, err: impl Diagnostic<'a>) -> ErrorGuaranteed { + pub fn emit_err(self, err: impl Diagnostic<'a>) -> ErrorGuaranteed { self.create_err(err).emit() } @@ -1251,7 +1267,7 @@ impl DiagCtxt { // No `#[rustc_lint_diagnostics]` and no `impl Into<DiagMessage>` because bug messages aren't // user-facing. #[track_caller] - pub fn delayed_bug(&self, msg: impl Into<Cow<'static, str>>) -> ErrorGuaranteed { + pub fn delayed_bug(self, msg: impl Into<Cow<'static, str>>) -> ErrorGuaranteed { Diag::<ErrorGuaranteed>::new(self, DelayedBug, msg.into()).emit() } @@ -1264,7 +1280,7 @@ impl DiagCtxt { // user-facing. #[track_caller] pub fn span_delayed_bug( - &self, + self, sp: impl Into<MultiSpan>, msg: impl Into<Cow<'static, str>>, ) -> ErrorGuaranteed { @@ -1273,45 +1289,45 @@ impl DiagCtxt { #[rustc_lint_diagnostics] #[track_caller] - pub fn struct_warn(&self, msg: impl Into<DiagMessage>) -> Diag<'_, ()> { + pub fn struct_warn(self, msg: impl Into<DiagMessage>) -> Diag<'a, ()> { Diag::new(self, Warning, msg) } #[rustc_lint_diagnostics] #[track_caller] - pub fn warn(&self, msg: impl Into<DiagMessage>) { + pub fn warn(self, msg: impl Into<DiagMessage>) { self.struct_warn(msg).emit() } #[rustc_lint_diagnostics] #[track_caller] pub fn struct_span_warn( - &self, + self, span: impl Into<MultiSpan>, msg: impl Into<DiagMessage>, - ) -> Diag<'_, ()> { + ) -> Diag<'a, ()> { self.struct_warn(msg).with_span(span) } #[rustc_lint_diagnostics] #[track_caller] - pub fn span_warn(&self, span: impl Into<MultiSpan>, msg: impl Into<DiagMessage>) { + pub fn span_warn(self, span: impl Into<MultiSpan>, msg: impl Into<DiagMessage>) { self.struct_span_warn(span, msg).emit() } #[track_caller] - pub fn create_warn<'a>(&'a self, warning: impl Diagnostic<'a, ()>) -> Diag<'a, ()> { + pub fn create_warn(self, warning: impl Diagnostic<'a, ()>) -> Diag<'a, ()> { warning.into_diag(self, Warning) } #[track_caller] - pub fn emit_warn<'a>(&'a self, warning: impl Diagnostic<'a, ()>) { + pub fn emit_warn(self, warning: impl Diagnostic<'a, ()>) { self.create_warn(warning).emit() } #[rustc_lint_diagnostics] #[track_caller] - pub fn struct_note(&self, msg: impl Into<DiagMessage>) -> Diag<'_, ()> { + pub fn struct_note(self, msg: impl Into<DiagMessage>) -> Diag<'a, ()> { Diag::new(self, Note, msg) } @@ -1324,54 +1340,50 @@ impl DiagCtxt { #[rustc_lint_diagnostics] #[track_caller] pub fn struct_span_note( - &self, + self, span: impl Into<MultiSpan>, msg: impl Into<DiagMessage>, - ) -> Diag<'_, ()> { + ) -> Diag<'a, ()> { self.struct_note(msg).with_span(span) } #[rustc_lint_diagnostics] #[track_caller] - pub fn span_note(&self, span: impl Into<MultiSpan>, msg: impl Into<DiagMessage>) { + pub fn span_note(self, span: impl Into<MultiSpan>, msg: impl Into<DiagMessage>) { self.struct_span_note(span, msg).emit() } #[track_caller] - pub fn create_note<'a>(&'a self, note: impl Diagnostic<'a, ()>) -> Diag<'a, ()> { + pub fn create_note(self, note: impl Diagnostic<'a, ()>) -> Diag<'a, ()> { note.into_diag(self, Note) } #[track_caller] - pub fn emit_note<'a>(&'a self, note: impl Diagnostic<'a, ()>) { + pub fn emit_note(self, note: impl Diagnostic<'a, ()>) { self.create_note(note).emit() } #[rustc_lint_diagnostics] #[track_caller] - pub fn struct_help(&self, msg: impl Into<DiagMessage>) -> Diag<'_, ()> { + pub fn struct_help(self, msg: impl Into<DiagMessage>) -> Diag<'a, ()> { Diag::new(self, Help, msg) } #[rustc_lint_diagnostics] #[track_caller] - pub fn struct_failure_note(&self, msg: impl Into<DiagMessage>) -> Diag<'_, ()> { + pub fn struct_failure_note(self, msg: impl Into<DiagMessage>) -> Diag<'a, ()> { Diag::new(self, FailureNote, msg) } #[rustc_lint_diagnostics] #[track_caller] - pub fn struct_allow(&self, msg: impl Into<DiagMessage>) -> Diag<'_, ()> { + pub fn struct_allow(self, msg: impl Into<DiagMessage>) -> Diag<'a, ()> { Diag::new(self, Allow, msg) } #[rustc_lint_diagnostics] #[track_caller] - pub fn struct_expect( - &self, - msg: impl Into<DiagMessage>, - id: LintExpectationId, - ) -> Diag<'_, ()> { + pub fn struct_expect(self, msg: impl Into<DiagMessage>, id: LintExpectationId) -> Diag<'a, ()> { Diag::new(self, Expect(id), msg) } } diff --git a/compiler/rustc_expand/messages.ftl b/compiler/rustc_expand/messages.ftl index 2e150f7bb27..6113580491e 100644 --- a/compiler/rustc_expand/messages.ftl +++ b/compiler/rustc_expand/messages.ftl @@ -35,8 +35,8 @@ expand_duplicate_matcher_binding = duplicate matcher binding .label = duplicate binding .label2 = previous binding -expand_empty_delegation_list = - empty list delegation is not supported +expand_empty_delegation_mac = + empty {$kind} delegation is not supported expand_expected_paren_or_brace = expected `(` or `{"{"}`, found `{$token}` @@ -58,6 +58,9 @@ expand_feature_removed = .label = feature has been removed .reason = {$reason} +expand_glob_delegation_outside_impls = + glob delegation is only supported in impls + expand_helper_attribute_name_invalid = `{$name}` cannot be a name of derive helper attribute diff --git a/compiler/rustc_expand/src/base.rs b/compiler/rustc_expand/src/base.rs index b3f6a35f3a4..d8e6d3525da 100644 --- a/compiler/rustc_expand/src/base.rs +++ b/compiler/rustc_expand/src/base.rs @@ -12,7 +12,7 @@ use rustc_ast::{self as ast, AttrVec, Attribute, HasAttrs, Item, NodeId, PatKind use rustc_attr::{self as attr, Deprecation, Stability}; use rustc_data_structures::fx::FxIndexMap; use rustc_data_structures::sync::{self, Lrc}; -use rustc_errors::{DiagCtxt, ErrorGuaranteed, PResult}; +use rustc_errors::{DiagCtxtHandle, ErrorGuaranteed, PResult}; use rustc_feature::Features; use rustc_lint_defs::{BufferedEarlyLint, RegisteredTools}; use rustc_parse::{parser::Parser, MACRO_ARGUMENTS}; @@ -357,6 +357,10 @@ where } } +pub trait GlobDelegationExpander { + fn expand(&self, ecx: &mut ExtCtxt<'_>) -> ExpandResult<Vec<(Ident, Option<Ident>)>, ()>; +} + // Use a macro because forwarding to a simple function has type system issues macro_rules! make_stmts_default { ($me:expr) => { @@ -714,6 +718,9 @@ pub enum SyntaxExtensionKind { /// The produced AST fragment is appended to the input AST fragment. Box<dyn MultiItemModifier + sync::DynSync + sync::DynSend>, ), + + /// A glob delegation. + GlobDelegation(Box<dyn GlobDelegationExpander + sync::DynSync + sync::DynSend>), } /// A struct representing a macro definition in "lowered" form ready for expansion. @@ -748,7 +755,9 @@ impl SyntaxExtension { /// Returns which kind of macro calls this syntax extension. pub fn macro_kind(&self) -> MacroKind { match self.kind { - SyntaxExtensionKind::Bang(..) | SyntaxExtensionKind::LegacyBang(..) => MacroKind::Bang, + SyntaxExtensionKind::Bang(..) + | SyntaxExtensionKind::LegacyBang(..) + | SyntaxExtensionKind::GlobDelegation(..) => MacroKind::Bang, SyntaxExtensionKind::Attr(..) | SyntaxExtensionKind::LegacyAttr(..) | SyntaxExtensionKind::NonMacroAttr => MacroKind::Attr, @@ -922,6 +931,32 @@ impl SyntaxExtension { SyntaxExtension::default(SyntaxExtensionKind::NonMacroAttr, edition) } + pub fn glob_delegation( + trait_def_id: DefId, + impl_def_id: LocalDefId, + edition: Edition, + ) -> SyntaxExtension { + struct GlobDelegationExpanderImpl { + trait_def_id: DefId, + impl_def_id: LocalDefId, + } + impl GlobDelegationExpander for GlobDelegationExpanderImpl { + fn expand( + &self, + ecx: &mut ExtCtxt<'_>, + ) -> ExpandResult<Vec<(Ident, Option<Ident>)>, ()> { + match ecx.resolver.glob_delegation_suffixes(self.trait_def_id, self.impl_def_id) { + Ok(suffixes) => ExpandResult::Ready(suffixes), + Err(Indeterminate) if ecx.force_mode => ExpandResult::Ready(Vec::new()), + Err(Indeterminate) => ExpandResult::Retry(()), + } + } + } + + let expander = GlobDelegationExpanderImpl { trait_def_id, impl_def_id }; + SyntaxExtension::default(SyntaxExtensionKind::GlobDelegation(Box::new(expander)), edition) + } + pub fn expn_data( &self, parent: LocalExpnId, @@ -1030,6 +1065,16 @@ pub trait ResolverExpand { /// Tools registered with `#![register_tool]` and used by tool attributes and lints. fn registered_tools(&self) -> &RegisteredTools; + + /// Mark this invocation id as a glob delegation. + fn register_glob_delegation(&mut self, invoc_id: LocalExpnId); + + /// Names of specific methods to which glob delegation expands. + fn glob_delegation_suffixes( + &mut self, + trait_def_id: DefId, + impl_def_id: LocalDefId, + ) -> Result<Vec<(Ident, Option<Ident>)>, Indeterminate>; } pub trait LintStoreExpand { @@ -1135,7 +1180,7 @@ impl<'a> ExtCtxt<'a> { } } - pub fn dcx(&self) -> &'a DiagCtxt { + pub fn dcx(&self) -> DiagCtxtHandle<'a> { self.sess.dcx() } @@ -1256,7 +1301,7 @@ pub fn resolve_path(sess: &Session, path: impl Into<PathBuf>, span: Span) -> PRe } pub fn parse_macro_name_and_helper_attrs( - dcx: &rustc_errors::DiagCtxt, + dcx: DiagCtxtHandle<'_>, attr: &Attribute, macro_type: &str, ) -> Option<(Symbol, Vec<Symbol>)> { @@ -1358,7 +1403,7 @@ fn pretty_printing_compatibility_hack(item: &Item, sess: &Session) { if crate_matches { // FIXME: make this translatable #[allow(rustc::untranslatable_diagnostic)] - sess.psess.dcx.emit_fatal(errors::ProcMacroBackCompat { + sess.dcx().emit_fatal(errors::ProcMacroBackCompat { crate_name: "rental".to_string(), fixed_version: "0.5.6".to_string(), }); diff --git a/compiler/rustc_expand/src/errors.rs b/compiler/rustc_expand/src/errors.rs index 3f8b4661e5f..c883121fb40 100644 --- a/compiler/rustc_expand/src/errors.rs +++ b/compiler/rustc_expand/src/errors.rs @@ -435,8 +435,16 @@ pub struct ExpectedParenOrBrace<'a> { } #[derive(Diagnostic)] -#[diag(expand_empty_delegation_list)] -pub(crate) struct EmptyDelegationList { +#[diag(expand_empty_delegation_mac)] +pub(crate) struct EmptyDelegationMac { + #[primary_span] + pub span: Span, + pub kind: String, +} + +#[derive(Diagnostic)] +#[diag(expand_glob_delegation_outside_impls)] +pub(crate) struct GlobDelegationOutsideImpls { #[primary_span] pub span: Span, } diff --git a/compiler/rustc_expand/src/expand.rs b/compiler/rustc_expand/src/expand.rs index c28a09eb57c..716bfc8c26b 100644 --- a/compiler/rustc_expand/src/expand.rs +++ b/compiler/rustc_expand/src/expand.rs @@ -1,8 +1,8 @@ use crate::base::*; use crate::config::StripUnconfigured; use crate::errors::{ - EmptyDelegationList, IncompleteParse, RecursionLimitReached, RemoveExprNotSupported, - RemoveNodeNotSupported, UnsupportedKeyValue, WrongFragmentKind, + EmptyDelegationMac, GlobDelegationOutsideImpls, IncompleteParse, RecursionLimitReached, + RemoveExprNotSupported, RemoveNodeNotSupported, UnsupportedKeyValue, WrongFragmentKind, }; use crate::mbe::diagnostics::annotate_err_with_kind; use crate::module::{mod_dir_path, parse_external_mod, DirOwnership, ParsedExternalMod}; @@ -343,6 +343,9 @@ pub enum InvocationKind { is_const: bool, item: Annotatable, }, + GlobDelegation { + item: P<ast::AssocItem>, + }, } impl InvocationKind { @@ -370,6 +373,7 @@ impl Invocation { InvocationKind::Bang { span, .. } => *span, InvocationKind::Attr { attr, .. } => attr.span, InvocationKind::Derive { path, .. } => path.span, + InvocationKind::GlobDelegation { item } => item.span, } } @@ -378,6 +382,7 @@ impl Invocation { InvocationKind::Bang { span, .. } => span, InvocationKind::Attr { attr, .. } => &mut attr.span, InvocationKind::Derive { path, .. } => &mut path.span, + InvocationKind::GlobDelegation { item } => &mut item.span, } } } @@ -800,6 +805,36 @@ impl<'a, 'b> MacroExpander<'a, 'b> { } _ => unreachable!(), }, + InvocationKind::GlobDelegation { item } => { + let AssocItemKind::DelegationMac(deleg) = &item.kind else { unreachable!() }; + let suffixes = match ext { + SyntaxExtensionKind::GlobDelegation(expander) => match expander.expand(self.cx) + { + ExpandResult::Ready(suffixes) => suffixes, + ExpandResult::Retry(()) => { + // Reassemble the original invocation for retrying. + return ExpandResult::Retry(Invocation { + kind: InvocationKind::GlobDelegation { item }, + ..invoc + }); + } + }, + SyntaxExtensionKind::LegacyBang(..) => { + let msg = "expanded a dummy glob delegation"; + let guar = self.cx.dcx().span_delayed_bug(span, msg); + return ExpandResult::Ready(fragment_kind.dummy(span, guar)); + } + _ => unreachable!(), + }; + + type Node = AstNodeWrapper<P<ast::AssocItem>, ImplItemTag>; + let single_delegations = build_single_delegations::<Node>( + self.cx, deleg, &item, &suffixes, item.span, true, + ); + fragment_kind.expect_from_annotatables( + single_delegations.map(|item| Annotatable::ImplItem(P(item))), + ) + } }) } @@ -1067,7 +1102,7 @@ trait InvocationCollectorNode: HasAttrs + HasNodeId + Sized { fn take_mac_call(self) -> (P<ast::MacCall>, Self::AttrsTy, AddSemicolon) { unreachable!() } - fn delegation_list(&self) -> Option<(&ast::DelegationMac, &ast::Item<Self::ItemKind>)> { + fn delegation(&self) -> Option<(&ast::DelegationMac, &ast::Item<Self::ItemKind>)> { None } fn delegation_item_kind(_deleg: Box<ast::Delegation>) -> Self::ItemKind { @@ -1126,7 +1161,7 @@ impl InvocationCollectorNode for P<ast::Item> { _ => unreachable!(), } } - fn delegation_list(&self) -> Option<(&ast::DelegationMac, &ast::Item<Self::ItemKind>)> { + fn delegation(&self) -> Option<(&ast::DelegationMac, &ast::Item<Self::ItemKind>)> { match &self.kind { ItemKind::DelegationMac(deleg) => Some((deleg, self)), _ => None, @@ -1270,7 +1305,7 @@ impl InvocationCollectorNode for AstNodeWrapper<P<ast::AssocItem>, TraitItemTag> _ => unreachable!(), } } - fn delegation_list(&self) -> Option<(&ast::DelegationMac, &ast::Item<Self::ItemKind>)> { + fn delegation(&self) -> Option<(&ast::DelegationMac, &ast::Item<Self::ItemKind>)> { match &self.wrapped.kind { AssocItemKind::DelegationMac(deleg) => Some((deleg, &self.wrapped)), _ => None, @@ -1311,7 +1346,7 @@ impl InvocationCollectorNode for AstNodeWrapper<P<ast::AssocItem>, ImplItemTag> _ => unreachable!(), } } - fn delegation_list(&self) -> Option<(&ast::DelegationMac, &ast::Item<Self::ItemKind>)> { + fn delegation(&self) -> Option<(&ast::DelegationMac, &ast::Item<Self::ItemKind>)> { match &self.wrapped.kind { AssocItemKind::DelegationMac(deleg) => Some((deleg, &self.wrapped)), _ => None, @@ -1487,7 +1522,7 @@ impl InvocationCollectorNode for ast::Stmt { }; (mac, attrs, if add_semicolon { AddSemicolon::Yes } else { AddSemicolon::No }) } - fn delegation_list(&self) -> Option<(&ast::DelegationMac, &ast::Item<Self::ItemKind>)> { + fn delegation(&self) -> Option<(&ast::DelegationMac, &ast::Item<Self::ItemKind>)> { match &self.kind { StmtKind::Item(item) => match &item.kind { ItemKind::DelegationMac(deleg) => Some((deleg, item)), @@ -1684,6 +1719,44 @@ impl InvocationCollectorNode for AstNodeWrapper<P<ast::Expr>, MethodReceiverTag> } } +fn build_single_delegations<'a, Node: InvocationCollectorNode>( + ecx: &ExtCtxt<'_>, + deleg: &'a ast::DelegationMac, + item: &'a ast::Item<Node::ItemKind>, + suffixes: &'a [(Ident, Option<Ident>)], + item_span: Span, + from_glob: bool, +) -> impl Iterator<Item = ast::Item<Node::ItemKind>> + 'a { + if suffixes.is_empty() { + // Report an error for now, to avoid keeping stem for resolution and + // stability checks. + let kind = String::from(if from_glob { "glob" } else { "list" }); + ecx.dcx().emit_err(EmptyDelegationMac { span: item.span, kind }); + } + + suffixes.iter().map(move |&(ident, rename)| { + let mut path = deleg.prefix.clone(); + path.segments.push(ast::PathSegment { ident, id: ast::DUMMY_NODE_ID, args: None }); + + ast::Item { + attrs: item.attrs.clone(), + id: ast::DUMMY_NODE_ID, + span: if from_glob { item_span } else { ident.span }, + vis: item.vis.clone(), + ident: rename.unwrap_or(ident), + kind: Node::delegation_item_kind(Box::new(ast::Delegation { + id: ast::DUMMY_NODE_ID, + qself: deleg.qself.clone(), + path, + rename, + body: deleg.body.clone(), + from_glob, + })), + tokens: None, + } + }) +} + struct InvocationCollector<'a, 'b> { cx: &'a mut ExtCtxt<'b>, invocations: Vec<(Invocation, Option<Lrc<SyntaxExtension>>)>, @@ -1702,6 +1775,11 @@ impl<'a, 'b> InvocationCollector<'a, 'b> { fn collect(&mut self, fragment_kind: AstFragmentKind, kind: InvocationKind) -> AstFragment { let expn_id = LocalExpnId::fresh_empty(); + if matches!(kind, InvocationKind::GlobDelegation { .. }) { + // In resolver we need to know which invocation ids are delegations early, + // before their `ExpnData` is filled. + self.cx.resolver.register_glob_delegation(expn_id); + } let vis = kind.placeholder_visibility(); self.invocations.push(( Invocation { @@ -1734,6 +1812,14 @@ impl<'a, 'b> InvocationCollector<'a, 'b> { self.collect(kind, InvocationKind::Attr { attr, pos, item, derives }) } + fn collect_glob_delegation( + &mut self, + item: P<ast::AssocItem>, + kind: AstFragmentKind, + ) -> AstFragment { + self.collect(kind, InvocationKind::GlobDelegation { item }) + } + /// If `item` is an attribute invocation, remove the attribute and return it together with /// its position and derives following it. We have to collect the derives in order to resolve /// legacy derive helpers (helpers written before derives that introduce them). @@ -1901,37 +1987,27 @@ impl<'a, 'b> InvocationCollector<'a, 'b> { Node::post_flat_map_node_collect_bang(&mut res, add_semicolon); res } - None if let Some((deleg, item)) = node.delegation_list() => { - if deleg.suffixes.is_empty() { - // Report an error for now, to avoid keeping stem for resolution and - // stability checks. - self.cx.dcx().emit_err(EmptyDelegationList { span: item.span }); - } - - Node::flatten_outputs(deleg.suffixes.iter().map(|&(ident, rename)| { - let mut path = deleg.prefix.clone(); - path.segments.push(ast::PathSegment { - ident, - id: ast::DUMMY_NODE_ID, - args: None, - }); - - let mut item = Node::from_item(ast::Item { - attrs: item.attrs.clone(), - id: ast::DUMMY_NODE_ID, - span: ident.span, - vis: item.vis.clone(), - ident: rename.unwrap_or(ident), - kind: Node::delegation_item_kind(Box::new(ast::Delegation { - id: ast::DUMMY_NODE_ID, - qself: deleg.qself.clone(), - path, - rename, - body: deleg.body.clone(), - })), - tokens: None, - }); + None if let Some((deleg, item)) = node.delegation() => { + let Some(suffixes) = &deleg.suffixes else { + let item = match node.to_annotatable() { + Annotatable::ImplItem(item) => item, + ann @ (Annotatable::Item(_) + | Annotatable::TraitItem(_) + | Annotatable::Stmt(_)) => { + let span = ann.span(); + self.cx.dcx().emit_err(GlobDelegationOutsideImpls { span }); + return Default::default(); + } + _ => unreachable!(), + }; + return self.collect_glob_delegation(item, Node::KIND).make_ast::<Node>(); + }; + let single_delegations = build_single_delegations::<Node>( + self.cx, deleg, item, suffixes, item.span, false, + ); + Node::flatten_outputs(single_delegations.map(|item| { + let mut item = Node::from_item(item); assign_id!(self, item.node_id_mut(), || item.noop_flat_map(self)) })) } @@ -1983,7 +2059,7 @@ impl<'a, 'b> InvocationCollector<'a, 'b> { self.collect_bang(mac, Node::KIND).make_ast::<Node>() }) } - None if node.delegation_list().is_some() => unreachable!(), + None if node.delegation().is_some() => unreachable!(), None => { assign_id!(self, node.node_id_mut(), || node.noop_visit(self)) } diff --git a/compiler/rustc_expand/src/mbe/diagnostics.rs b/compiler/rustc_expand/src/mbe/diagnostics.rs index 442fd654b6a..bf475c1dc96 100644 --- a/compiler/rustc_expand/src/mbe/diagnostics.rs +++ b/compiler/rustc_expand/src/mbe/diagnostics.rs @@ -7,7 +7,7 @@ use crate::mbe::{ use rustc_ast::token::{self, Token, TokenKind}; use rustc_ast::tokenstream::TokenStream; use rustc_ast_pretty::pprust; -use rustc_errors::{Applicability, Diag, DiagCtxt, DiagMessage}; +use rustc_errors::{Applicability, Diag, DiagMessage}; use rustc_macros::Subdiagnostic; use rustc_parse::parser::{Parser, Recovery}; use rustc_span::source_map::SourceMap; @@ -61,7 +61,7 @@ pub(super) fn failed_to_match_macro<'cx>( err.span_label(cx.source_map().guess_head_span(def_span), "when calling this macro"); } - annotate_doc_comment(cx.sess.dcx(), &mut err, psess.source_map(), span); + annotate_doc_comment(&mut err, psess.source_map(), span); if let Some(span) = remaining_matcher.span() { err.span_note(span, format!("while trying to match {remaining_matcher}")); @@ -324,12 +324,12 @@ enum ExplainDocComment { }, } -pub(super) fn annotate_doc_comment(dcx: &DiagCtxt, err: &mut Diag<'_>, sm: &SourceMap, span: Span) { +pub(super) fn annotate_doc_comment(err: &mut Diag<'_>, sm: &SourceMap, span: Span) { if let Ok(src) = sm.span_to_snippet(span) { if src.starts_with("///") || src.starts_with("/**") { - err.subdiagnostic(dcx, ExplainDocComment::Outer { span }); + err.subdiagnostic(ExplainDocComment::Outer { span }); } else if src.starts_with("//!") || src.starts_with("/*!") { - err.subdiagnostic(dcx, ExplainDocComment::Inner { span }); + err.subdiagnostic(ExplainDocComment::Inner { span }); } } } diff --git a/compiler/rustc_expand/src/mbe/macro_check.rs b/compiler/rustc_expand/src/mbe/macro_check.rs index 72dbbde54b3..d9a945a3215 100644 --- a/compiler/rustc_expand/src/mbe/macro_check.rs +++ b/compiler/rustc_expand/src/mbe/macro_check.rs @@ -206,7 +206,7 @@ pub(super) fn check_meta_variables( rhses: &[TokenTree], ) -> Result<(), ErrorGuaranteed> { if lhses.len() != rhses.len() { - psess.dcx.span_bug(span, "length mismatch between LHSes and RHSes") + psess.dcx().span_bug(span, "length mismatch between LHSes and RHSes") } let mut guar = None; for (lhs, rhs) in iter::zip(lhses, rhses) { @@ -245,7 +245,7 @@ fn check_binders( // MetaVar(fragment) and not as MetaVarDecl(y, fragment). TokenTree::MetaVar(span, name) => { if macros.is_empty() { - psess.dcx.span_bug(span, "unexpected MetaVar in lhs"); + psess.dcx().span_bug(span, "unexpected MetaVar in lhs"); } let name = MacroRulesNormalizedIdent::new(name); // There are 3 possibilities: @@ -276,7 +276,7 @@ fn check_binders( ); } if !macros.is_empty() { - psess.dcx.span_bug(span, "unexpected MetaVarDecl in nested lhs"); + psess.dcx().span_bug(span, "unexpected MetaVarDecl in nested lhs"); } let name = MacroRulesNormalizedIdent::new(name); if let Some(prev_info) = get_binder_info(macros, binders, name) { @@ -284,7 +284,7 @@ fn check_binders( // for nested macro definitions. *guar = Some( psess - .dcx + .dcx() .emit_err(errors::DuplicateMatcherBinding { span, prev: prev_info.span }), ); } else { @@ -344,7 +344,7 @@ fn check_occurrences( match *rhs { TokenTree::Token(..) => {} TokenTree::MetaVarDecl(span, _name, _kind) => { - psess.dcx.span_bug(span, "unexpected MetaVarDecl in rhs") + psess.dcx().span_bug(span, "unexpected MetaVarDecl in rhs") } TokenTree::MetaVar(span, name) => { let name = MacroRulesNormalizedIdent::new(name); diff --git a/compiler/rustc_expand/src/mbe/macro_rules.rs b/compiler/rustc_expand/src/mbe/macro_rules.rs index 5d3ba5d3223..49b1f5ce0e3 100644 --- a/compiler/rustc_expand/src/mbe/macro_rules.rs +++ b/compiler/rustc_expand/src/mbe/macro_rules.rs @@ -383,7 +383,7 @@ pub fn compile_declarative_macro( }; let dummy_syn_ext = |guar| (mk_syn_ext(Box::new(DummyExpander(guar))), Vec::new()); - let dcx = &sess.psess.dcx; + let dcx = sess.dcx(); let lhs_nm = Ident::new(sym::lhs, def.span); let rhs_nm = Ident::new(sym::rhs, def.span); let tt_spec = Some(NonterminalKind::TT); @@ -463,7 +463,7 @@ pub fn compile_declarative_macro( let sp = token.span.substitute_dummy(def.span); let mut err = sess.dcx().struct_span_err(sp, s); err.span_label(sp, msg); - annotate_doc_comment(sess.dcx(), &mut err, sess.source_map(), sp); + annotate_doc_comment(&mut err, sess.source_map(), sp); let guar = err.emit(); return dummy_syn_ext(guar); } diff --git a/compiler/rustc_expand/src/mbe/metavar_expr.rs b/compiler/rustc_expand/src/mbe/metavar_expr.rs index 3295a91029e..25958e03028 100644 --- a/compiler/rustc_expand/src/mbe/metavar_expr.rs +++ b/compiler/rustc_expand/src/mbe/metavar_expr.rs @@ -42,7 +42,7 @@ impl MetaVarExpr { let ident = parse_ident(&mut tts, psess, outer_span)?; let Some(TokenTree::Delimited(.., Delimiter::Parenthesis, args)) = tts.next() else { let msg = "meta-variable expression parameter must be wrapped in parentheses"; - return Err(psess.dcx.struct_span_err(ident.span, msg)); + return Err(psess.dcx().struct_span_err(ident.span, msg)); }; check_trailing_token(&mut tts, psess)?; let mut iter = args.trees(); @@ -62,12 +62,12 @@ impl MetaVarExpr { break; } if !try_eat_comma(&mut iter) { - return Err(psess.dcx.struct_span_err(outer_span, "expected comma")); + return Err(psess.dcx().struct_span_err(outer_span, "expected comma")); } } if result.len() < 2 { return Err(psess - .dcx + .dcx() .struct_span_err(ident.span, "`concat` must have at least two elements")); } MetaVarExpr::Concat(result.into()) @@ -81,7 +81,7 @@ impl MetaVarExpr { "len" => MetaVarExpr::Len(parse_depth(&mut iter, psess, ident.span)?), _ => { let err_msg = "unrecognized meta-variable expression"; - let mut err = psess.dcx.struct_span_err(ident.span, err_msg); + let mut err = psess.dcx().struct_span_err(ident.span, err_msg); err.span_suggestion( ident.span, "supported expressions are count, ignore, index and len", @@ -120,7 +120,7 @@ fn check_trailing_token<'psess>( ) -> PResult<'psess, ()> { if let Some(tt) = iter.next() { let mut diag = psess - .dcx + .dcx() .struct_span_err(tt.span(), format!("unexpected token: {}", pprust::tt_to_string(tt))); diag.span_note(tt.span(), "meta-variable expression must not have trailing tokens"); Err(diag) @@ -139,7 +139,7 @@ fn parse_count<'psess>( let ident = parse_ident(iter, psess, span)?; let depth = if try_eat_comma(iter) { if iter.look_ahead(0).is_none() { - return Err(psess.dcx.struct_span_err( + return Err(psess.dcx().struct_span_err( span, "`count` followed by a comma must have an associated index indicating its depth", )); @@ -160,7 +160,7 @@ fn parse_depth<'psess>( let Some(tt) = iter.next() else { return Ok(0) }; let TokenTree::Token(token::Token { kind: token::TokenKind::Literal(lit), .. }, _) = tt else { return Err(psess - .dcx + .dcx() .struct_span_err(span, "meta-variable expression depth must be a literal")); }; if let Ok(lit_kind) = LitKind::from_token_lit(*lit) @@ -170,7 +170,7 @@ fn parse_depth<'psess>( Ok(n_usize) } else { let msg = "only unsuffixes integer literals are supported in meta-variable expressions"; - Err(psess.dcx.struct_span_err(span, msg)) + Err(psess.dcx().struct_span_err(span, msg)) } } @@ -181,20 +181,21 @@ fn parse_ident<'psess>( fallback_span: Span, ) -> PResult<'psess, Ident> { let Some(tt) = iter.next() else { - return Err(psess.dcx.struct_span_err(fallback_span, "expected identifier")); + 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")); + 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)); + return Err(psess.dcx().struct_span_err(elem.span, RAW_IDENT_ERR)); } return Ok(elem); } let token_str = pprust::token_to_string(token); - let mut err = - psess.dcx.struct_span_err(token.span, format!("expected identifier, found `{token_str}`")); + 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}`"), @@ -236,7 +237,7 @@ fn eat_dollar<'psess>( let _ = iter.next(); return Ok(()); } - Err(psess.dcx.struct_span_err( + Err(psess.dcx().struct_span_err( span, "meta-variables within meta-variable expressions must be referenced using a dollar sign", )) diff --git a/compiler/rustc_expand/src/mbe/transcribe.rs b/compiler/rustc_expand/src/mbe/transcribe.rs index 914bd03675a..f935f1b77e0 100644 --- a/compiler/rustc_expand/src/mbe/transcribe.rs +++ b/compiler/rustc_expand/src/mbe/transcribe.rs @@ -10,7 +10,7 @@ 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_errors::{pluralize, Diag, DiagCtxtHandle, PResult}; use rustc_parse::parser::ParseNtResult; use rustc_session::parse::ParseSess; use rustc_span::hygiene::{LocalExpnId, Transparency}; @@ -141,7 +141,7 @@ pub(super) fn transcribe<'a>( let mut result_stack = Vec::new(); let mut marker = Marker(expand_id, transparency, Default::default()); - let dcx = &psess.dcx; + let dcx = psess.dcx(); loop { // Look at the last frame on the stack. // If it still has a TokenTree we have not looked at yet, use that tree. @@ -571,7 +571,7 @@ fn lockstep_iter_size( /// * `[ $( ${count(foo, 1)} ),* ]` will return an error because `${count(foo, 1)}` is /// declared inside a single repetition and the index `1` implies two nested repetitions. fn count_repetitions<'a>( - dcx: &'a DiagCtxt, + dcx: DiagCtxtHandle<'a>, depth_user: usize, mut matched: &NamedMatch, repeats: &[(usize, usize)], @@ -632,7 +632,7 @@ fn count_repetitions<'a>( /// Returns a `NamedMatch` item declared on the LHS given an arbitrary [Ident] fn matched_from_ident<'ctx, 'interp, 'rslt>( - dcx: &'ctx DiagCtxt, + dcx: DiagCtxtHandle<'ctx>, ident: Ident, interp: &'interp FxHashMap<MacroRulesNormalizedIdent, NamedMatch>, ) -> PResult<'ctx, &'rslt NamedMatch> @@ -646,7 +646,7 @@ where /// Used by meta-variable expressions when an user input is out of the actual declared bounds. For /// example, index(999999) in an repetition of only three elements. -fn out_of_bounds_err<'a>(dcx: &'a DiagCtxt, max: usize, span: Span, ty: &str) -> Diag<'a> { +fn out_of_bounds_err<'a>(dcx: DiagCtxtHandle<'a>, max: usize, span: Span, ty: &str) -> Diag<'a> { let msg = if max == 0 { format!( "meta-variable expression `{ty}` with depth parameter \ @@ -662,7 +662,7 @@ fn out_of_bounds_err<'a>(dcx: &'a DiagCtxt, max: usize, span: Span, ty: &str) -> } fn transcribe_metavar_expr<'a>( - dcx: &'a DiagCtxt, + dcx: DiagCtxtHandle<'a>, expr: &MetaVarExpr, interp: &FxHashMap<MacroRulesNormalizedIdent, NamedMatch>, marker: &mut Marker, @@ -730,7 +730,7 @@ fn transcribe_metavar_expr<'a>( /// Extracts an identifier that can be originated from a `$var:ident` variable or from a token tree. fn extract_ident<'a>( - dcx: &'a DiagCtxt, + dcx: DiagCtxtHandle<'a>, ident: Ident, interp: &FxHashMap<MacroRulesNormalizedIdent, NamedMatch>, ) -> PResult<'a, String> { diff --git a/compiler/rustc_expand/src/proc_macro_server.rs b/compiler/rustc_expand/src/proc_macro_server.rs index 93f8682090d..5508358f53b 100644 --- a/compiler/rustc_expand/src/proc_macro_server.rs +++ b/compiler/rustc_expand/src/proc_macro_server.rs @@ -522,7 +522,7 @@ impl server::FreeFunctions for Rustc<'_, '_> { fn emit_diagnostic(&mut self, diagnostic: Diagnostic<Self::Span>) { let message = rustc_errors::DiagMessage::from(diagnostic.message); let mut diag: Diag<'_, ()> = - Diag::new(&self.psess().dcx, diagnostic.level.to_internal(), message); + Diag::new(self.psess().dcx(), diagnostic.level.to_internal(), message); diag.span(MultiSpan::from_spans(diagnostic.spans)); for child in diagnostic.children { // This message comes from another diagnostic, and we are just reconstructing the diff --git a/compiler/rustc_feature/src/unstable.rs b/compiler/rustc_feature/src/unstable.rs index 58832cb1087..5cfbcdcbbbe 100644 --- a/compiler/rustc_feature/src/unstable.rs +++ b/compiler/rustc_feature/src/unstable.rs @@ -567,8 +567,8 @@ declare_features! ( (unstable, optimize_attribute, "1.34.0", Some(54882)), /// Allows postfix match `expr.match { ... }` (unstable, postfix_match, "1.79.0", Some(121618)), - /// Allows `use<'a, 'b, A, B>` in `impl use<...> Trait` for precise capture of generic args. - (incomplete, precise_capturing, "1.79.0", Some(123432)), + /// Allows `use<'a, 'b, A, B>` in `impl Trait + use<...>` for precise capture of generic args. + (unstable, precise_capturing, "1.79.0", Some(123432)), /// Allows macro attributes on expressions, statements and non-inline modules. (unstable, proc_macro_hygiene, "1.30.0", Some(54727)), /// Allows `&raw const $place_expr` and `&raw mut $place_expr` expressions. @@ -588,6 +588,8 @@ declare_features! ( (incomplete, return_type_notation, "1.70.0", Some(109417)), /// Allows `extern "rust-cold"`. (unstable, rust_cold_cc, "1.63.0", Some(97544)), + /// Shortern the tail expression lifetime + (unstable, shorter_tail_lifetimes, "1.79.0", Some(123739)), /// Allows the use of SIMD types in functions declared in `extern` blocks. (unstable, simd_ffi, "1.0.0", Some(27731)), /// Allows specialization of implementations (RFC 1210). diff --git a/compiler/rustc_hir/src/hir.rs b/compiler/rustc_hir/src/hir.rs index d4a22c4c31f..22a6c06bba3 100644 --- a/compiler/rustc_hir/src/hir.rs +++ b/compiler/rustc_hir/src/hir.rs @@ -463,6 +463,7 @@ pub enum TraitBoundModifier { pub enum GenericBound<'hir> { Trait(PolyTraitRef<'hir>, TraitBoundModifier), Outlives(&'hir Lifetime), + Use(&'hir [PreciseCapturingArg<'hir>], Span), } impl GenericBound<'_> { @@ -477,6 +478,7 @@ impl GenericBound<'_> { match self { GenericBound::Trait(t, ..) => t.span, GenericBound::Outlives(l) => l.ident.span, + GenericBound::Use(_, span) => *span, } } } @@ -2689,8 +2691,6 @@ pub struct OpaqueTy<'hir> { /// originating from a trait method. This makes it so that the opaque is /// lowered as an associated type. pub in_trait: bool, - /// List of arguments captured via `impl use<'a, P, ...> Trait` syntax. - pub precise_capturing_args: Option<(&'hir [PreciseCapturingArg<'hir>], Span)>, } #[derive(Debug, Clone, Copy, HashStable_Generic)] diff --git a/compiler/rustc_hir/src/intravisit.rs b/compiler/rustc_hir/src/intravisit.rs index 5a16f266dab..065ecc5d7b7 100644 --- a/compiler/rustc_hir/src/intravisit.rs +++ b/compiler/rustc_hir/src/intravisit.rs @@ -532,15 +532,10 @@ pub fn walk_item<'v, V: Visitor<'v>>(visitor: &mut V, item: &'v Item<'v>) -> V:: try_visit!(visitor.visit_ty(ty)); try_visit!(visitor.visit_generics(generics)); } - ItemKind::OpaqueTy(&OpaqueTy { generics, bounds, precise_capturing_args, .. }) => { + ItemKind::OpaqueTy(&OpaqueTy { generics, bounds, .. }) => { try_visit!(visitor.visit_id(item.hir_id())); try_visit!(walk_generics(visitor, generics)); walk_list!(visitor, visit_param_bound, bounds); - if let Some((precise_capturing_args, _)) = precise_capturing_args { - for arg in precise_capturing_args { - try_visit!(visitor.visit_precise_capturing_arg(arg)); - } - } } ItemKind::Enum(ref enum_definition, ref generics) => { try_visit!(visitor.visit_generics(generics)); @@ -1147,6 +1142,10 @@ pub fn walk_param_bound<'v, V: Visitor<'v>>( match *bound { GenericBound::Trait(ref typ, _modifier) => visitor.visit_poly_trait_ref(typ), GenericBound::Outlives(ref lifetime) => visitor.visit_lifetime(lifetime), + GenericBound::Use(args, _) => { + walk_list!(visitor, visit_precise_capturing_arg, args); + V::Result::output() + } } } diff --git a/compiler/rustc_hir_analysis/src/check/check.rs b/compiler/rustc_hir_analysis/src/check/check.rs index 72e5995e892..3b53c253195 100644 --- a/compiler/rustc_hir_analysis/src/check/check.rs +++ b/compiler/rustc_hir_analysis/src/check/check.rs @@ -481,9 +481,12 @@ fn sanity_check_found_hidden_type<'tcx>( /// 2. Checking that all lifetimes that are implicitly captured are mentioned. /// 3. Asserting that all parameters mentioned in the captures list are invariant. fn check_opaque_precise_captures<'tcx>(tcx: TyCtxt<'tcx>, opaque_def_id: LocalDefId) { - let hir::OpaqueTy { precise_capturing_args, .. } = + let hir::OpaqueTy { bounds, .. } = *tcx.hir_node_by_def_id(opaque_def_id).expect_item().expect_opaque_ty(); - let Some((precise_capturing_args, _)) = precise_capturing_args else { + let Some(precise_capturing_args) = bounds.iter().find_map(|bound| match *bound { + hir::GenericBound::Use(bounds, ..) => Some(bounds), + _ => None, + }) else { // No precise capturing args; nothing to validate return; }; diff --git a/compiler/rustc_hir_analysis/src/check/errs.rs b/compiler/rustc_hir_analysis/src/check/errs.rs index 2cdcc06f53c..17cb20df754 100644 --- a/compiler/rustc_hir_analysis/src/check/errs.rs +++ b/compiler/rustc_hir_analysis/src/check/errs.rs @@ -63,7 +63,7 @@ fn handle_static_mut_ref( } else { (errors::StaticMutRefSugg::Shared { span, var }, "shared") }; - tcx.sess.psess.dcx.emit_err(errors::StaticMutRef { span, sugg, shared }); + tcx.dcx().emit_err(errors::StaticMutRef { span, sugg, shared }); } else { let (sugg, shared) = if mutable == Mutability::Mut { (errors::RefOfMutStaticSugg::Mut { span, var }, "mutable") diff --git a/compiler/rustc_hir_analysis/src/check/region.rs b/compiler/rustc_hir_analysis/src/check/region.rs index 72e431926ca..2b5efd3b2f6 100644 --- a/compiler/rustc_hir_analysis/src/check/region.rs +++ b/compiler/rustc_hir_analysis/src/check/region.rs @@ -6,7 +6,6 @@ //! //! [rustc dev guide]: https://rustc-dev-guide.rust-lang.org/borrow_check.html -use rustc_ast::visit::visit_opt; use rustc_data_structures::fx::FxHashSet; use rustc_hir as hir; use rustc_hir::def_id::DefId; @@ -168,7 +167,14 @@ fn resolve_block<'tcx>(visitor: &mut RegionResolutionVisitor<'tcx>, blk: &'tcx h hir::StmtKind::Expr(..) | hir::StmtKind::Semi(..) => visitor.visit_stmt(statement), } } - visit_opt!(visitor, visit_expr, &blk.expr); + if let Some(tail_expr) = blk.expr { + if visitor.tcx.features().shorter_tail_lifetimes + && blk.span.edition().at_least_rust_2024() + { + visitor.terminating_scopes.insert(tail_expr.hir_id.local_id); + } + visitor.visit_expr(tail_expr); + } } visitor.cx = prev_cx; diff --git a/compiler/rustc_hir_analysis/src/coherence/orphan.rs b/compiler/rustc_hir_analysis/src/coherence/orphan.rs index 61ac4af0151..9421269e51e 100644 --- a/compiler/rustc_hir_analysis/src/coherence/orphan.rs +++ b/compiler/rustc_hir_analysis/src/coherence/orphan.rs @@ -403,74 +403,56 @@ fn emit_orphan_check_error<'tcx>( match *ty.kind() { ty::Slice(_) => { if is_foreign { - diag.subdiagnostic( - tcx.dcx(), - errors::OnlyCurrentTraitsForeign { span }, - ); + diag.subdiagnostic(errors::OnlyCurrentTraitsForeign { span }); } else { - diag.subdiagnostic( - tcx.dcx(), - errors::OnlyCurrentTraitsName { span, name: "slices" }, - ); + diag.subdiagnostic(errors::OnlyCurrentTraitsName { + span, + name: "slices", + }); } } ty::Array(..) => { if is_foreign { - diag.subdiagnostic( - tcx.dcx(), - errors::OnlyCurrentTraitsForeign { span }, - ); + diag.subdiagnostic(errors::OnlyCurrentTraitsForeign { span }); } else { - diag.subdiagnostic( - tcx.dcx(), - errors::OnlyCurrentTraitsName { span, name: "arrays" }, - ); + diag.subdiagnostic(errors::OnlyCurrentTraitsName { + span, + name: "arrays", + }); } } ty::Tuple(..) => { if is_foreign { - diag.subdiagnostic( - tcx.dcx(), - errors::OnlyCurrentTraitsForeign { span }, - ); + diag.subdiagnostic(errors::OnlyCurrentTraitsForeign { span }); } else { - diag.subdiagnostic( - tcx.dcx(), - errors::OnlyCurrentTraitsName { span, name: "tuples" }, - ); + diag.subdiagnostic(errors::OnlyCurrentTraitsName { + span, + name: "tuples", + }); } } ty::Alias(ty::Opaque, ..) => { - diag.subdiagnostic(tcx.dcx(), errors::OnlyCurrentTraitsOpaque { span }); + diag.subdiagnostic(errors::OnlyCurrentTraitsOpaque { span }); } ty::RawPtr(ptr_ty, mutbl) => { if !trait_ref.self_ty().has_param() { - diag.subdiagnostic( - tcx.dcx(), - errors::OnlyCurrentTraitsPointerSugg { - wrapper_span: impl_.self_ty.span, - struct_span: item.span.shrink_to_lo(), - mut_key: mutbl.prefix_str(), - ptr_ty, - }, - ); + diag.subdiagnostic(errors::OnlyCurrentTraitsPointerSugg { + wrapper_span: impl_.self_ty.span, + struct_span: item.span.shrink_to_lo(), + mut_key: mutbl.prefix_str(), + ptr_ty, + }); } - diag.subdiagnostic( - tcx.dcx(), - errors::OnlyCurrentTraitsPointer { span, pointer: ty }, - ); + diag.subdiagnostic(errors::OnlyCurrentTraitsPointer { span, pointer: ty }); } ty::Adt(adt_def, _) => { - diag.subdiagnostic( - tcx.dcx(), - errors::OnlyCurrentTraitsAdt { - span, - name: tcx.def_path_str(adt_def.did()), - }, - ); + diag.subdiagnostic(errors::OnlyCurrentTraitsAdt { + span, + name: tcx.def_path_str(adt_def.did()), + }); } _ => { - diag.subdiagnostic(tcx.dcx(), errors::OnlyCurrentTraitsTy { span, ty }); + diag.subdiagnostic(errors::OnlyCurrentTraitsTy { span, ty }); } } } diff --git a/compiler/rustc_hir_analysis/src/errors.rs b/compiler/rustc_hir_analysis/src/errors.rs index 41dceea2e32..cff8d5a5ea5 100644 --- a/compiler/rustc_hir_analysis/src/errors.rs +++ b/compiler/rustc_hir_analysis/src/errors.rs @@ -2,7 +2,7 @@ use crate::fluent_generated as fluent; use rustc_errors::{ - codes::*, Applicability, Diag, DiagCtxt, Diagnostic, EmissionGuarantee, Level, MultiSpan, + codes::*, Applicability, Diag, DiagCtxtHandle, Diagnostic, EmissionGuarantee, Level, MultiSpan, }; use rustc_macros::{Diagnostic, LintDiagnostic, Subdiagnostic}; use rustc_middle::ty::Ty; @@ -424,7 +424,7 @@ pub struct MissingTypeParams { // Manual implementation of `Diagnostic` to be able to call `span_to_snippet`. impl<'a, G: EmissionGuarantee> Diagnostic<'a, G> for MissingTypeParams { #[track_caller] - fn into_diag(self, dcx: &'a DiagCtxt, level: Level) -> Diag<'a, G> { + fn into_diag(self, dcx: DiagCtxtHandle<'a>, level: Level) -> Diag<'a, G> { let mut err = Diag::new(dcx, level, fluent::hir_analysis_missing_type_params); err.span(self.span); err.code(E0393); diff --git a/compiler/rustc_hir_analysis/src/hir_ty_lowering/bounds.rs b/compiler/rustc_hir_analysis/src/hir_ty_lowering/bounds.rs index 9a6bc8a7b72..c7699b0b310 100644 --- a/compiler/rustc_hir_analysis/src/hir_ty_lowering/bounds.rs +++ b/compiler/rustc_hir_analysis/src/hir_ty_lowering/bounds.rs @@ -178,6 +178,9 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ { lifetime.ident.span, ); } + hir::GenericBound::Use(..) => { + // We don't actually lower `use` into the type layer. + } } } } diff --git a/compiler/rustc_hir_pretty/src/lib.rs b/compiler/rustc_hir_pretty/src/lib.rs index d32d0183c4e..b21f1eadfb7 100644 --- a/compiler/rustc_hir_pretty/src/lib.rs +++ b/compiler/rustc_hir_pretty/src/lib.rs @@ -13,7 +13,7 @@ use rustc_ast_pretty::pprust::{Comments, PrintState}; use rustc_hir as hir; use rustc_hir::{ BindingMode, ByRef, GenericArg, GenericBound, GenericParam, GenericParamKind, HirId, - LifetimeParamKind, Node, PatKind, RangeEnd, Term, TraitBoundModifier, + LifetimeParamKind, Node, PatKind, PreciseCapturingArg, RangeEnd, Term, TraitBoundModifier, }; use rustc_span::source_map::SourceMap; use rustc_span::symbol::{kw, Ident, Symbol}; @@ -2100,10 +2100,24 @@ impl<'a> State<'a> { GenericBound::Outlives(lt) => { self.print_lifetime(lt); } + GenericBound::Use(args, _) => { + self.word("use <"); + + self.commasep(Inconsistent, args, |s, arg| s.print_precise_capturing_arg(*arg)); + + self.word(">"); + } } } } + fn print_precise_capturing_arg(&mut self, arg: PreciseCapturingArg<'_>) { + match arg { + PreciseCapturingArg::Lifetime(lt) => self.print_lifetime(lt), + PreciseCapturingArg::Param(arg) => self.print_ident(arg.ident), + } + } + fn print_generic_params(&mut self, generic_params: &[GenericParam<'_>]) { if !generic_params.is_empty() { self.word("<"); diff --git a/compiler/rustc_hir_typeck/src/_match.rs b/compiler/rustc_hir_typeck/src/_match.rs index 281af80bff5..4e2104ff561 100644 --- a/compiler/rustc_hir_typeck/src/_match.rs +++ b/compiler/rustc_hir_typeck/src/_match.rs @@ -246,7 +246,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { let semi = expr.span.shrink_to_hi().with_hi(semi_span.hi()); let sugg = crate::errors::RemoveSemiForCoerce { expr: expr.span, ret, semi }; - diag.subdiagnostic(self.dcx(), sugg); + diag.subdiagnostic(sugg); } /// When the previously checked expression (the scrutinee) diverges, diff --git a/compiler/rustc_hir_typeck/src/cast.rs b/compiler/rustc_hir_typeck/src/cast.rs index 9e9a1f678ed..58708510282 100644 --- a/compiler/rustc_hir_typeck/src/cast.rs +++ b/compiler/rustc_hir_typeck/src/cast.rs @@ -1005,25 +1005,19 @@ impl<'a, 'tcx> CastCheck<'tcx> { if let Some((deref_ty, _)) = derefed { // Give a note about what the expr derefs to. if deref_ty != self.expr_ty.peel_refs() { - err.subdiagnostic( - fcx.dcx(), - errors::DerefImplsIsEmpty { - span: self.expr_span, - deref_ty: fcx.ty_to_string(deref_ty), - }, - ); + err.subdiagnostic(errors::DerefImplsIsEmpty { + span: self.expr_span, + deref_ty: fcx.ty_to_string(deref_ty), + }); } // Create a multipart suggestion: add `!` and `.is_empty()` in // place of the cast. - err.subdiagnostic( - fcx.dcx(), - errors::UseIsEmpty { - lo: self.expr_span.shrink_to_lo(), - hi: self.span.with_lo(self.expr_span.hi()), - expr_ty: fcx.ty_to_string(self.expr_ty), - }, - ); + err.subdiagnostic(errors::UseIsEmpty { + lo: self.expr_span.shrink_to_lo(), + hi: self.span.with_lo(self.expr_span.hi()), + expr_ty: fcx.ty_to_string(self.expr_ty), + }); } } } diff --git a/compiler/rustc_hir_typeck/src/coercion.rs b/compiler/rustc_hir_typeck/src/coercion.rs index fcd22b74676..31f85e21d71 100644 --- a/compiler/rustc_hir_typeck/src/coercion.rs +++ b/compiler/rustc_hir_typeck/src/coercion.rs @@ -1782,20 +1782,14 @@ impl<'tcx, 'exprs, E: AsCoercionSite> CoerceMany<'tcx, 'exprs, E> { } let rpid_def_span = fcx.tcx.def_span(rpit_def_id); - err.subdiagnostic( - fcx.tcx.dcx(), - SuggestBoxingForReturnImplTrait::ChangeReturnType { - start_sp: rpid_def_span.with_hi(rpid_def_span.lo() + BytePos(4)), - end_sp: rpid_def_span.shrink_to_hi(), - }, - ); + err.subdiagnostic(SuggestBoxingForReturnImplTrait::ChangeReturnType { + start_sp: rpid_def_span.with_hi(rpid_def_span.lo() + BytePos(4)), + end_sp: rpid_def_span.shrink_to_hi(), + }); let (starts, ends) = arm_spans.map(|span| (span.shrink_to_lo(), span.shrink_to_hi())).unzip(); - err.subdiagnostic( - fcx.tcx.dcx(), - SuggestBoxingForReturnImplTrait::BoxReturnExpr { starts, ends }, - ); + err.subdiagnostic(SuggestBoxingForReturnImplTrait::BoxReturnExpr { starts, ends }); } fn report_return_mismatched_types<'a>( diff --git a/compiler/rustc_hir_typeck/src/expr.rs b/compiler/rustc_hir_typeck/src/expr.rs index fe497498c4b..233dc2afa9b 100644 --- a/compiler/rustc_hir_typeck/src/expr.rs +++ b/compiler/rustc_hir_typeck/src/expr.rs @@ -384,7 +384,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { if let Some(sp) = tcx.sess.psess.ambiguous_block_expr_parse.borrow().get(&sp) { - err.subdiagnostic(self.dcx(), ExprParenthesesNeeded::surrounding(*sp)); + err.subdiagnostic(ExprParenthesesNeeded::surrounding(*sp)); } oprnd_t = Ty::new_error(tcx, err.emit()); } @@ -2018,10 +2018,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { .shrink_to_hi() .to(range_end.span); - err.subdiagnostic( - self.dcx(), - TypeMismatchFruTypo { expr_span: range_start.span, fru_span, expr }, - ); + err.subdiagnostic(TypeMismatchFruTypo { expr_span: range_start.span, fru_span, expr }); // Suppress any range expr type mismatches self.dcx().try_steal_replace_and_emit_err( diff --git a/compiler/rustc_hir_typeck/src/fn_ctxt/_impl.rs b/compiler/rustc_hir_typeck/src/fn_ctxt/_impl.rs index 9531c002829..061afd03062 100644 --- a/compiler/rustc_hir_typeck/src/fn_ctxt/_impl.rs +++ b/compiler/rustc_hir_typeck/src/fn_ctxt/_impl.rs @@ -750,16 +750,13 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { /// Resolves an associated value path into a base type and associated constant, or method /// resolution. The newly resolved definition is written into `type_dependent_defs`. + #[instrument(level = "trace", skip(self), ret)] pub fn resolve_ty_and_res_fully_qualified_call( &self, qpath: &'tcx QPath<'tcx>, hir_id: HirId, span: Span, ) -> (Res, Option<LoweredTy<'tcx>>, &'tcx [hir::PathSegment<'tcx>]) { - debug!( - "resolve_ty_and_res_fully_qualified_call: qpath={:?} hir_id={:?} span={:?}", - qpath, hir_id, span - ); let (ty, qself, item_segment) = match *qpath { QPath::Resolved(ref opt_qself, path) => { return ( @@ -1417,10 +1414,10 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { // This also occurs for an enum variant on a type alias. 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( + match self.at(&self.misc(span), self.param_env).sub( DefineOpaqueTypes::Yes, - impl_ty, self_ty, + impl_ty, ) { Ok(ok) => self.register_infer_ok_obligations(ok), Err(_) => { diff --git a/compiler/rustc_hir_typeck/src/fn_ctxt/checks.rs b/compiler/rustc_hir_typeck/src/fn_ctxt/checks.rs index 10d9e07db6f..1138642c56d 100644 --- a/compiler/rustc_hir_typeck/src/fn_ctxt/checks.rs +++ b/compiler/rustc_hir_typeck/src/fn_ctxt/checks.rs @@ -1435,7 +1435,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { { // The user provided `ptr::null()`, but the function expects // `ptr::null_mut()`. - err.subdiagnostic(self.dcx(), SuggestPtrNullMut { span: arg.span }); + err.subdiagnostic(SuggestPtrNullMut { span: arg.span }); } } diff --git a/compiler/rustc_hir_typeck/src/fn_ctxt/mod.rs b/compiler/rustc_hir_typeck/src/fn_ctxt/mod.rs index 2ef27e6a0ba..1713d75092e 100644 --- a/compiler/rustc_hir_typeck/src/fn_ctxt/mod.rs +++ b/compiler/rustc_hir_typeck/src/fn_ctxt/mod.rs @@ -5,14 +5,13 @@ mod checks; mod inspect_obligations; mod suggestions; -use rustc_errors::ErrorGuaranteed; +use rustc_errors::{DiagCtxtHandle, ErrorGuaranteed}; use crate::coercion::DynamicCoerceMany; use crate::fallback::DivergingFallbackBehavior; use crate::fn_ctxt::checks::DivergingBlockBehavior; use crate::{CoroutineTypes, Diverges, EnclosingBreakables, TypeckRootCtxt}; use hir::def_id::CRATE_DEF_ID; -use rustc_errors::DiagCtxt; use rustc_hir as hir; use rustc_hir::def_id::{DefId, LocalDefId}; use rustc_hir_analysis::hir_ty_lowering::{HirTyLowerer, RegionInferReason}; @@ -145,8 +144,8 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { } } - pub(crate) fn dcx(&self) -> &'tcx DiagCtxt { - self.tcx.dcx() + pub(crate) fn dcx(&self) -> DiagCtxtHandle<'tcx> { + self.infcx.dcx() } pub fn cause(&self, span: Span, code: ObligationCauseCode<'tcx>) -> ObligationCause<'tcx> { diff --git a/compiler/rustc_hir_typeck/src/fn_ctxt/suggestions.rs b/compiler/rustc_hir_typeck/src/fn_ctxt/suggestions.rs index 9743dc7c69f..9dd82868adc 100644 --- a/compiler/rustc_hir_typeck/src/fn_ctxt/suggestions.rs +++ b/compiler/rustc_hir_typeck/src/fn_ctxt/suggestions.rs @@ -460,16 +460,13 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { // but those checks need to be a bit more delicate and the benefit is diminishing. if self.can_eq(self.param_env, found_ty_inner, peeled) && error_tys_equate_as_ref { let sugg = prefix_wrap(".as_ref()"); - err.subdiagnostic( - self.dcx(), - errors::SuggestConvertViaMethod { - span: expr.span.shrink_to_hi(), - sugg, - expected, - found, - borrow_removal_span, - }, - ); + err.subdiagnostic(errors::SuggestConvertViaMethod { + span: expr.span.shrink_to_hi(), + sugg, + expected, + found, + borrow_removal_span, + }); return true; } else if let Some((deref_ty, _)) = self.autoderef(expr.span, found_ty_inner).silence_errors().nth(1) @@ -477,16 +474,13 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { && error_tys_equate_as_ref { let sugg = prefix_wrap(".as_deref()"); - err.subdiagnostic( - self.dcx(), - errors::SuggestConvertViaMethod { - span: expr.span.shrink_to_hi(), - sugg, - expected, - found, - borrow_removal_span, - }, - ); + err.subdiagnostic(errors::SuggestConvertViaMethod { + span: expr.span.shrink_to_hi(), + sugg, + expected, + found, + borrow_removal_span, + }); return true; } else if let ty::Adt(adt, _) = found_ty_inner.peel_refs().kind() && self.tcx.is_lang_item(adt.did(), LangItem::String) @@ -573,7 +567,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { end: span.shrink_to_hi(), }, }; - err.subdiagnostic(self.dcx(), suggest_boxing); + err.subdiagnostic(suggest_boxing); true } else { @@ -814,28 +808,22 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { match &fn_decl.output { &hir::FnRetTy::DefaultReturn(span) if expected.is_unit() && !can_suggest => { // `fn main()` must return `()`, do not suggest changing return type - err.subdiagnostic(self.dcx(), errors::ExpectedReturnTypeLabel::Unit { span }); + err.subdiagnostic(errors::ExpectedReturnTypeLabel::Unit { span }); return true; } &hir::FnRetTy::DefaultReturn(span) if expected.is_unit() => { if let Some(found) = found.make_suggestable(self.tcx, false, None) { - err.subdiagnostic( - self.dcx(), - errors::AddReturnTypeSuggestion::Add { span, found: found.to_string() }, - ); + err.subdiagnostic(errors::AddReturnTypeSuggestion::Add { + span, + found: found.to_string(), + }); return true; } else if let Some(sugg) = suggest_impl_trait(self, self.param_env, found) { - err.subdiagnostic( - self.dcx(), - errors::AddReturnTypeSuggestion::Add { span, found: sugg }, - ); + err.subdiagnostic(errors::AddReturnTypeSuggestion::Add { span, found: sugg }); return true; } else { // FIXME: if `found` could be `impl Iterator` we should suggest that. - err.subdiagnostic( - self.dcx(), - errors::AddReturnTypeSuggestion::MissingHere { span }, - ); + err.subdiagnostic(errors::AddReturnTypeSuggestion::MissingHere { span }); return true; } } @@ -856,39 +844,36 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { debug!(?found); if found.is_suggestable(self.tcx, false) { if ty.span.is_empty() { - err.subdiagnostic( - self.dcx(), - errors::AddReturnTypeSuggestion::Add { - span: ty.span, - found: found.to_string(), - }, - ); + err.subdiagnostic(errors::AddReturnTypeSuggestion::Add { + span: ty.span, + found: found.to_string(), + }); return true; } else { - err.subdiagnostic( - self.dcx(), - errors::ExpectedReturnTypeLabel::Other { span: ty.span, expected }, - ); + err.subdiagnostic(errors::ExpectedReturnTypeLabel::Other { + span: ty.span, + expected, + }); } } } else { // Only point to return type if the expected type is the return type, as if they // are not, the expectation must have been caused by something else. - debug!("return type {:?}", hir_ty); + debug!(?hir_ty, "return type"); let ty = self.lowerer().lower_ty(hir_ty); - debug!("return type {:?}", ty); - debug!("expected type {:?}", expected); + debug!(?ty, "return type (lowered)"); + debug!(?expected, "expected type"); let bound_vars = self.tcx.late_bound_vars(hir_ty.hir_id.owner.into()); let ty = Binder::bind_with_vars(ty, bound_vars); let ty = self.normalize(hir_ty.span, ty); let ty = self.tcx.instantiate_bound_regions_with_erased(ty); if self.can_coerce(expected, ty) { - err.subdiagnostic( - self.dcx(), - errors::ExpectedReturnTypeLabel::Other { span: hir_ty.span, expected }, - ); + err.subdiagnostic(errors::ExpectedReturnTypeLabel::Other { + span: hir_ty.span, + expected, + }); self.try_suggest_return_impl_trait(err, expected, found, fn_id); - self.note_caller_chooses_ty_for_ty_param(err, expected, found); + self.try_note_caller_chooses_ty_for_ty_param(err, expected, found); return true; } } @@ -898,21 +883,30 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { false } - fn note_caller_chooses_ty_for_ty_param( + fn try_note_caller_chooses_ty_for_ty_param( &self, diag: &mut Diag<'_>, expected: Ty<'tcx>, found: Ty<'tcx>, ) { - if let ty::Param(expected_ty_as_param) = expected.kind() { - diag.subdiagnostic( - self.dcx(), - errors::NoteCallerChoosesTyForTyParam { - ty_param_name: expected_ty_as_param.name, - found_ty: found, - }, - ); + // Only show the note if: + // 1. `expected` ty is a type parameter; + // 2. The `expected` type parameter does *not* occur in the return expression type. This can + // happen for e.g. `fn foo<T>(t: &T) -> T { t }`, where `expected` is `T` but `found` is + // `&T`. Saying "the caller chooses a type for `T` which can be different from `&T`" is + // "well duh" and is only confusing and not helpful. + let ty::Param(expected_ty_as_param) = expected.kind() else { + return; + }; + + if found.contains(expected) { + return; } + + diag.subdiagnostic(errors::NoteCallerChoosesTyForTyParam { + ty_param_name: expected_ty_as_param.name, + found_ty: found, + }); } /// check whether the return type is a generic type with a trait bound @@ -1136,7 +1130,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { let sp = self.tcx.sess.source_map().start_point(expr.span).with_parent(None); if let Some(sp) = self.tcx.sess.psess.ambiguous_block_expr_parse.borrow().get(&sp) { // `{ 42 } &&x` (#61475) or `{ 42 } && if x { 1 } else { 0 }` - err.subdiagnostic(self.dcx(), ExprParenthesesNeeded::surrounding(*sp)); + err.subdiagnostic(ExprParenthesesNeeded::surrounding(*sp)); true } else { false @@ -1250,7 +1244,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { } else { return false; }; - diag.subdiagnostic(self.dcx(), subdiag); + diag.subdiagnostic(subdiag); return true; } } diff --git a/compiler/rustc_hir_typeck/src/method/suggest.rs b/compiler/rustc_hir_typeck/src/method/suggest.rs index abbfe452f5f..a5e955a986b 100644 --- a/compiler/rustc_hir_typeck/src/method/suggest.rs +++ b/compiler/rustc_hir_typeck/src/method/suggest.rs @@ -303,14 +303,57 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { } if !candidates.is_empty() { let help = format!( - "{an}other candidate{s} {were} found in the following trait{s}, perhaps \ - add a `use` for {one_of_them}:", + "{an}other candidate{s} {were} found in the following trait{s}", an = if candidates.len() == 1 { "an" } else { "" }, s = pluralize!(candidates.len()), were = pluralize!("was", candidates.len()), - one_of_them = if candidates.len() == 1 { "it" } else { "one_of_them" }, ); - self.suggest_use_candidates(&mut err, help, candidates); + self.suggest_use_candidates( + candidates, + |accessible_sugg, inaccessible_sugg, span| { + let suggest_for_access = + |err: &mut Diag<'_>, mut msg: String, sugg: Vec<_>| { + msg += &format!( + ", perhaps add a `use` for {one_of_them}:", + one_of_them = + if sugg.len() == 1 { "it" } else { "one_of_them" }, + ); + err.span_suggestions( + span, + msg, + sugg, + Applicability::MaybeIncorrect, + ); + }; + let suggest_for_privacy = + |err: &mut Diag<'_>, mut msg: String, sugg: Vec<String>| { + if sugg.len() == 1 { + let msg = format!("\ + trait `{}` provides `{item_name}` is implemented but not reachable", + sugg[0].trim() + ); + err.help(msg); + } else { + msg += &format!(" but {} not reachable", pluralize!("is", sugg.len())); + err.span_suggestions( + span, + msg, + sugg, + Applicability::MaybeIncorrect, + ); + } + }; + if accessible_sugg.is_empty() { + // `inaccessible_sugg` must not be empty + suggest_for_privacy(&mut err, help, inaccessible_sugg); + } else if inaccessible_sugg.is_empty() { + suggest_for_access(&mut err, help, accessible_sugg); + } else { + suggest_for_access(&mut err, help.clone(), accessible_sugg); + suggest_for_privacy(&mut err, help, inaccessible_sugg); + } + }, + ); } if let ty::Ref(region, t_type, mutability) = rcvr_ty.kind() { if needs_mut { @@ -3089,49 +3132,69 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { } } - fn suggest_use_candidates(&self, err: &mut Diag<'_>, msg: String, candidates: Vec<DefId>) { + fn suggest_use_candidates<F>(&self, candidates: Vec<DefId>, handle_candidates: F) + where + F: FnOnce(Vec<String>, Vec<String>, Span), + { let parent_map = self.tcx.visible_parent_map(()); - // Separate out candidates that must be imported with a glob, because they are named `_` - // and cannot be referred with their identifier. - let (candidates, globs): (Vec<_>, Vec<_>) = candidates.into_iter().partition(|trait_did| { - if let Some(parent_did) = parent_map.get(trait_did) { - // If the item is re-exported as `_`, we should suggest a glob-import instead. - if *parent_did != self.tcx.parent(*trait_did) - && self - .tcx - .module_children(*parent_did) - .iter() - .filter(|child| child.res.opt_def_id() == Some(*trait_did)) - .all(|child| child.ident.name == kw::Underscore) - { - return false; - } - } + let scope = self.tcx.parent_module_from_def_id(self.body_id); + let (accessible_candidates, inaccessible_candidates): (Vec<_>, Vec<_>) = + candidates.into_iter().partition(|id| { + let vis = self.tcx.visibility(*id); + vis.is_accessible_from(scope, self.tcx) + }); - true - }); + let sugg = |candidates: Vec<_>, visible| { + // Separate out candidates that must be imported with a glob, because they are named `_` + // and cannot be referred with their identifier. + let (candidates, globs): (Vec<_>, Vec<_>) = + candidates.into_iter().partition(|trait_did| { + if let Some(parent_did) = parent_map.get(trait_did) { + // If the item is re-exported as `_`, we should suggest a glob-import instead. + if *parent_did != self.tcx.parent(*trait_did) + && self + .tcx + .module_children(*parent_did) + .iter() + .filter(|child| child.res.opt_def_id() == Some(*trait_did)) + .all(|child| child.ident.name == kw::Underscore) + { + return false; + } + } - let module_did = self.tcx.parent_module_from_def_id(self.body_id); - let (module, _, _) = self.tcx.hir().get_module(module_did); - let span = module.spans.inject_use_span; + true + }); - let path_strings = candidates.iter().map(|trait_did| { - format!("use {};\n", with_crate_prefix!(self.tcx.def_path_str(*trait_did)),) - }); + let prefix = if visible { "use " } else { "" }; + let postfix = if visible { ";" } else { "" }; + let path_strings = candidates.iter().map(|trait_did| { + format!( + "{prefix}{}{postfix}\n", + with_crate_prefix!(self.tcx.def_path_str(*trait_did)), + ) + }); - let glob_path_strings = globs.iter().map(|trait_did| { - let parent_did = parent_map.get(trait_did).unwrap(); - format!( - "use {}::*; // trait {}\n", - with_crate_prefix!(self.tcx.def_path_str(*parent_did)), - self.tcx.item_name(*trait_did), - ) - }); - let mut sugg: Vec<_> = path_strings.chain(glob_path_strings).collect(); - sugg.sort(); + let glob_path_strings = globs.iter().map(|trait_did| { + let parent_did = parent_map.get(trait_did).unwrap(); + format!( + "{prefix}{}::*{postfix} // trait {}\n", + with_crate_prefix!(self.tcx.def_path_str(*parent_did)), + self.tcx.item_name(*trait_did), + ) + }); + let mut sugg: Vec<_> = path_strings.chain(glob_path_strings).collect(); + sugg.sort(); + sugg + }; + + let accessible_sugg = sugg(accessible_candidates, true); + let inaccessible_sugg = sugg(inaccessible_candidates, false); - err.span_suggestions(span, msg, sugg, Applicability::MaybeIncorrect); + let (module, _, _) = self.tcx.hir().get_module(scope); + let span = module.spans.inject_use_span; + handle_candidates(accessible_sugg, inaccessible_sugg, span); } fn suggest_valid_traits( @@ -3155,9 +3218,9 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { if explain { err.help("items from traits can only be used if the trait is in scope"); } + let msg = format!( - "{this_trait_is} implemented but not in scope; perhaps you want to import \ - {one_of_them}", + "{this_trait_is} implemented but not in scope", this_trait_is = if candidates.len() == 1 { format!( "trait `{}` which provides `{item_name}` is", @@ -3165,11 +3228,43 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { ) } else { format!("the following traits which provide `{item_name}` are") - }, - one_of_them = if candidates.len() == 1 { "it" } else { "one of them" }, + } ); - self.suggest_use_candidates(err, msg, candidates); + self.suggest_use_candidates(candidates, |accessible_sugg, inaccessible_sugg, span| { + let suggest_for_access = |err: &mut Diag<'_>, mut msg: String, sugg: Vec<_>| { + msg += &format!( + "; perhaps you want to import {one_of}", + one_of = if sugg.len() == 1 { "it" } else { "one of them" }, + ); + err.span_suggestions(span, msg, sugg, Applicability::MaybeIncorrect); + }; + let suggest_for_privacy = |err: &mut Diag<'_>, sugg: Vec<String>| { + let msg = format!( + "{this_trait_is} implemented but not reachable", + this_trait_is = if sugg.len() == 1 { + format!("trait `{}` which provides `{item_name}` is", sugg[0].trim()) + } else { + format!("the following traits which provide `{item_name}` are") + } + ); + if sugg.len() == 1 { + err.help(msg); + } else { + err.span_suggestions(span, msg, sugg, Applicability::MaybeIncorrect); + } + }; + if accessible_sugg.is_empty() { + // `inaccessible_sugg` must not be empty + suggest_for_privacy(err, inaccessible_sugg); + } else if inaccessible_sugg.is_empty() { + suggest_for_access(err, msg, accessible_sugg); + } else { + suggest_for_access(err, msg, accessible_sugg); + suggest_for_privacy(err, inaccessible_sugg); + } + }); + if let Some(did) = edition_fix { err.note(format!( "'{}' is included in the prelude starting in Edition 2021", @@ -3729,22 +3824,19 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { if impls_trait(trait_info.def_id) { self.suggest_valid_traits(err, item_name, vec![trait_info.def_id], false); } else { - err.subdiagnostic( - self.dcx(), - CandidateTraitNote { - span: self.tcx.def_span(trait_info.def_id), - trait_name: self.tcx.def_path_str(trait_info.def_id), - item_name, - action_or_ty: if trait_missing_method { - "NONE".to_string() - } else { - param_type.map_or_else( - || "implement".to_string(), // FIXME: it might only need to be imported into scope, not implemented. - |p| p.to_string(), - ) - }, + err.subdiagnostic(CandidateTraitNote { + span: self.tcx.def_span(trait_info.def_id), + trait_name: self.tcx.def_path_str(trait_info.def_id), + item_name, + action_or_ty: if trait_missing_method { + "NONE".to_string() + } else { + param_type.map_or_else( + || "implement".to_string(), // FIXME: it might only need to be imported into scope, not implemented. + |p| p.to_string(), + ) }, - ); + }); } } trait_infos => { diff --git a/compiler/rustc_hir_typeck/src/op.rs b/compiler/rustc_hir_typeck/src/op.rs index d774ae2146a..5a11cb7096f 100644 --- a/compiler/rustc_hir_typeck/src/op.rs +++ b/compiler/rustc_hir_typeck/src/op.rs @@ -820,7 +820,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { // If the previous expression was a block expression, suggest parentheses // (turning this into a binary subtraction operation instead.) // for example, `{2} - 2` -> `({2}) - 2` (see src\test\ui\parser\expr-as-stmt.rs) - err.subdiagnostic(self.dcx(), ExprParenthesesNeeded::surrounding(*sp)); + err.subdiagnostic(ExprParenthesesNeeded::surrounding(*sp)); } else { match actual.kind() { Uint(_) if op == hir::UnOp::Neg => { diff --git a/compiler/rustc_hir_typeck/src/typeck_root_ctxt.rs b/compiler/rustc_hir_typeck/src/typeck_root_ctxt.rs index 28745af3a53..b6e9000ef95 100644 --- a/compiler/rustc_hir_typeck/src/typeck_root_ctxt.rs +++ b/compiler/rustc_hir_typeck/src/typeck_root_ctxt.rs @@ -22,7 +22,7 @@ use std::ops::Deref; /// e.g. closures defined within the function. For example: /// ```ignore (illustrative) /// fn foo() { -/// bar(move|| { ... }) +/// bar(move || { ... }) /// } /// ``` /// Here, the function `foo()` and the closure passed to diff --git a/compiler/rustc_infer/src/infer/error_reporting/mod.rs b/compiler/rustc_infer/src/infer/error_reporting/mod.rs index e15866f3f0f..227691d0994 100644 --- a/compiler/rustc_infer/src/infer/error_reporting/mod.rs +++ b/compiler/rustc_infer/src/infer/error_reporting/mod.rs @@ -61,8 +61,8 @@ use crate::traits::{ use crate::infer::relate::{self, RelateResult, TypeRelation}; use rustc_data_structures::fx::{FxIndexMap, FxIndexSet}; use rustc_errors::{ - codes::*, pluralize, struct_span_code_err, Applicability, Diag, DiagCtxt, DiagStyledString, - ErrorGuaranteed, IntoDiagArg, StringPart, + codes::*, pluralize, struct_span_code_err, Applicability, Diag, DiagCtxtHandle, + DiagStyledString, ErrorGuaranteed, IntoDiagArg, StringPart, }; use rustc_hir::def::DefKind; use rustc_hir::def_id::{DefId, LocalDefId}; @@ -139,8 +139,8 @@ pub struct TypeErrCtxt<'a, 'tcx> { } impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> { - pub fn dcx(&self) -> &'tcx DiagCtxt { - self.infcx.tcx.dcx() + pub fn dcx(&self) -> DiagCtxtHandle<'tcx> { + self.infcx.dcx() } /// This is just to avoid a potential footgun of accidentally @@ -892,7 +892,7 @@ impl<'tcx> TypeErrCtxt<'_, 'tcx> { arm_ty, arm_span, ) { - err.subdiagnostic(self.dcx(), subdiag); + err.subdiagnostic(subdiag); } } }, @@ -918,7 +918,7 @@ impl<'tcx> TypeErrCtxt<'_, 'tcx> { else_ty, else_span, ) { - err.subdiagnostic(self.dcx(), subdiag); + err.subdiagnostic(subdiag); } } ObligationCauseCode::LetElse => { diff --git a/compiler/rustc_infer/src/infer/error_reporting/note.rs b/compiler/rustc_infer/src/infer/error_reporting/note.rs index acb74f8a82c..8fd19563c30 100644 --- a/compiler/rustc_infer/src/infer/error_reporting/note.rs +++ b/compiler/rustc_infer/src/infer/error_reporting/note.rs @@ -369,7 +369,7 @@ impl<'tcx> TypeErrCtxt<'_, 'tcx> { trait_predicates: trait_predicates.join(", "), } }; - err.subdiagnostic(self.dcx(), suggestion); + err.subdiagnostic(suggestion); } pub(super) fn report_placeholder_failure( diff --git a/compiler/rustc_infer/src/infer/error_reporting/suggest.rs b/compiler/rustc_infer/src/infer/error_reporting/suggest.rs index 17fb760295a..74c65e93616 100644 --- a/compiler/rustc_infer/src/infer/error_reporting/suggest.rs +++ b/compiler/rustc_infer/src/infer/error_reporting/suggest.rs @@ -121,7 +121,7 @@ impl<'tcx> TypeErrCtxt<'_, 'tcx> { span_low: cause.span.shrink_to_lo(), span_high: cause.span.shrink_to_hi(), }; - diag.subdiagnostic(self.dcx(), sugg); + diag.subdiagnostic(sugg); } _ => { // More than one matching variant. @@ -130,7 +130,7 @@ impl<'tcx> TypeErrCtxt<'_, 'tcx> { cause_span: cause.span, compatible_variants, }; - diag.subdiagnostic(self.dcx(), sugg); + diag.subdiagnostic(sugg); } } } @@ -202,10 +202,9 @@ impl<'tcx> TypeErrCtxt<'_, 'tcx> { }, (_, Some(ty)) if self.same_type_modulo_infer(exp_found.expected, ty) => { // FIXME: Seems like we can't have a suggestion and a note with different spans in a single subdiagnostic - diag.subdiagnostic( - self.dcx(), - ConsiderAddingAwait::FutureSugg { span: exp_span.shrink_to_hi() }, - ); + diag.subdiagnostic(ConsiderAddingAwait::FutureSugg { + span: exp_span.shrink_to_hi(), + }); Some(ConsiderAddingAwait::FutureSuggNote { span: exp_span }) } (Some(ty), _) if self.same_type_modulo_infer(ty, exp_found.found) => match cause.code() @@ -233,7 +232,7 @@ impl<'tcx> TypeErrCtxt<'_, 'tcx> { _ => None, }; if let Some(subdiag) = subdiag { - diag.subdiagnostic(self.dcx(), subdiag); + diag.subdiagnostic(subdiag); } } @@ -269,7 +268,7 @@ impl<'tcx> TypeErrCtxt<'_, 'tcx> { } else { return; }; - diag.subdiagnostic(self.dcx(), suggestion); + diag.subdiagnostic(suggestion); } } } @@ -401,15 +400,15 @@ impl<'tcx> TypeErrCtxt<'_, 'tcx> { (true, false) => FunctionPointerSuggestion::UseRef { span, fn_name }, (false, true) => FunctionPointerSuggestion::RemoveRef { span, fn_name }, (true, true) => { - diag.subdiagnostic(self.dcx(), FnItemsAreDistinct); + diag.subdiagnostic(FnItemsAreDistinct); FunctionPointerSuggestion::CastRef { span, fn_name, sig: *sig } } (false, false) => { - diag.subdiagnostic(self.dcx(), FnItemsAreDistinct); + diag.subdiagnostic(FnItemsAreDistinct); FunctionPointerSuggestion::Cast { span, fn_name, sig: *sig } } }; - diag.subdiagnostic(self.dcx(), sugg); + diag.subdiagnostic(sugg); } (ty::FnDef(did1, args1), ty::FnDef(did2, args2)) => { let expected_sig = @@ -418,7 +417,7 @@ impl<'tcx> TypeErrCtxt<'_, 'tcx> { &(self.normalize_fn_sig)(self.tcx.fn_sig(*did2).instantiate(self.tcx, args2)); if self.same_type_modulo_infer(*expected_sig, *found_sig) { - diag.subdiagnostic(self.dcx(), FnUniqTypes); + diag.subdiagnostic(FnUniqTypes); } if !self.same_type_modulo_infer(*found_sig, *expected_sig) @@ -447,7 +446,7 @@ impl<'tcx> TypeErrCtxt<'_, 'tcx> { } }; - diag.subdiagnostic(self.dcx(), sug); + diag.subdiagnostic(sug); } (ty::FnDef(did, args), ty::FnPtr(sig)) => { let expected_sig = @@ -466,7 +465,7 @@ impl<'tcx> TypeErrCtxt<'_, 'tcx> { format!("{fn_name} as {found_sig}") }; - diag.subdiagnostic(self.dcx(), FnConsiderCasting { casting }); + diag.subdiagnostic(FnConsiderCasting { casting }); } _ => { return; @@ -889,7 +888,7 @@ impl<'tcx> TypeErrCtxt<'_, 'tcx> { let diag = self.consider_returning_binding_diag(blk, expected_ty); match diag { Some(diag) => { - err.subdiagnostic(self.dcx(), diag); + err.subdiagnostic(diag); true } None => false, diff --git a/compiler/rustc_infer/src/infer/mod.rs b/compiler/rustc_infer/src/infer/mod.rs index 8412912b9f3..4d6ddd7ba66 100644 --- a/compiler/rustc_infer/src/infer/mod.rs +++ b/compiler/rustc_infer/src/infer/mod.rs @@ -4,13 +4,14 @@ pub use lexical_region_resolve::RegionResolutionError; pub use relate::combine::CombineFields; pub use relate::combine::PredicateEmittingRelation; pub use relate::StructurallyRelateAliases; +use rustc_errors::DiagCtxtHandle; pub use rustc_macros::{TypeFoldable, TypeVisitable}; pub use rustc_middle::ty::IntVarValue; pub use BoundRegionConversionTime::*; pub use RegionVariableOrigin::*; pub use SubregionOrigin::*; -use crate::infer::relate::{Relate, RelateResult}; +use crate::infer::relate::RelateResult; use crate::traits::{self, ObligationCause, ObligationInspector, PredicateObligation, TraitEngine}; use error_reporting::TypeErrCtxt; use free_regions::RegionRelations; @@ -23,7 +24,7 @@ use rustc_data_structures::fx::{FxHashMap, FxHashSet, FxIndexMap}; use rustc_data_structures::sync::Lrc; use rustc_data_structures::undo_log::Rollback; use rustc_data_structures::unify as ut; -use rustc_errors::{Diag, DiagCtxt, ErrorGuaranteed}; +use rustc_errors::{Diag, ErrorGuaranteed}; use rustc_hir::def_id::{DefId, LocalDefId}; use rustc_macros::extension; use rustc_middle::infer::canonical::{Canonical, CanonicalVarValues}; @@ -44,7 +45,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, DUMMY_SP}; +use rustc_span::Span; use snapshot::undo_log::InferCtxtUndoLogs; use std::cell::{Cell, RefCell}; use std::fmt; @@ -334,149 +335,6 @@ pub struct InferCtxt<'tcx> { pub obligation_inspector: Cell<Option<ObligationInspector<'tcx>>>, } -impl<'tcx> ty::InferCtxtLike for InferCtxt<'tcx> { - type Interner = TyCtxt<'tcx>; - - fn interner(&self) -> TyCtxt<'tcx> { - self.tcx - } - - fn universe_of_ty(&self, vid: TyVid) -> Option<ty::UniverseIndex> { - // FIXME(BoxyUwU): this is kind of jank and means that printing unresolved - // ty infers will give you the universe of the var it resolved to not the universe - // it actually had. It also means that if you have a `?0.1` and infer it to `u8` then - // try to print out `?0.1` it will just print `?0`. - match self.probe_ty_var(vid) { - Err(universe) => Some(universe), - Ok(_) => None, - } - } - - fn universe_of_lt(&self, lt: ty::RegionVid) -> Option<ty::UniverseIndex> { - match self.inner.borrow_mut().unwrap_region_constraints().probe_value(lt) { - Err(universe) => Some(universe), - Ok(_) => None, - } - } - - fn universe_of_ct(&self, ct: ConstVid) -> Option<ty::UniverseIndex> { - // Same issue as with `universe_of_ty` - match self.probe_const_var(ct) { - Err(universe) => Some(universe), - Ok(_) => None, - } - } - - fn root_ty_var(&self, var: TyVid) -> TyVid { - self.root_var(var) - } - - fn root_const_var(&self, var: ConstVid) -> ConstVid { - self.root_const_var(var) - } - - fn opportunistic_resolve_ty_var(&self, vid: TyVid) -> Ty<'tcx> { - match self.probe_ty_var(vid) { - Ok(ty) => ty, - Err(_) => Ty::new_var(self.tcx, self.root_var(vid)), - } - } - - fn opportunistic_resolve_int_var(&self, vid: IntVid) -> Ty<'tcx> { - self.opportunistic_resolve_int_var(vid) - } - - fn opportunistic_resolve_float_var(&self, vid: FloatVid) -> Ty<'tcx> { - self.opportunistic_resolve_float_var(vid) - } - - fn opportunistic_resolve_ct_var(&self, vid: ConstVid) -> ty::Const<'tcx> { - match self.probe_const_var(vid) { - Ok(ct) => ct, - Err(_) => ty::Const::new_var(self.tcx, self.root_const_var(vid)), - } - } - - fn opportunistic_resolve_effect_var(&self, vid: EffectVid) -> ty::Const<'tcx> { - match self.probe_effect_var(vid) { - Some(ct) => ct, - None => { - ty::Const::new_infer(self.tcx, InferConst::EffectVar(self.root_effect_var(vid))) - } - } - } - - 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<LocalDefId> { - 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<T: TypeFoldable<Self::Interner> + Copy>( - &self, - value: ty::Binder<'tcx, T>, - ) -> T { - self.instantiate_binder_with_fresh_vars( - DUMMY_SP, - BoundRegionConversionTime::HigherRankedType, - value, - ) - } - - fn enter_forall<T: TypeFoldable<TyCtxt<'tcx>> + Copy, U>( - &self, - value: ty::Binder<'tcx, T>, - f: impl FnOnce(T) -> U, - ) -> U { - self.enter_forall(value, f) - } - - fn relate<T: Relate<TyCtxt<'tcx>>>( - &self, - param_env: ty::ParamEnv<'tcx>, - lhs: T, - variance: ty::Variance, - rhs: T, - ) -> Result<Vec<Goal<'tcx, ty::Predicate<'tcx>>>, NoSolution> { - self.at(&ObligationCause::dummy(), param_env).relate_no_trace(lhs, variance, rhs) - } - - fn eq_structurally_relating_aliases<T: Relate<TyCtxt<'tcx>>>( - &self, - param_env: ty::ParamEnv<'tcx>, - lhs: T, - rhs: T, - ) -> Result<Vec<Goal<'tcx, ty::Predicate<'tcx>>>, NoSolution> { - self.at(&ObligationCause::dummy(), param_env) - .eq_structurally_relating_aliases_no_trace(lhs, rhs) - } - - fn resolve_vars_if_possible<T>(&self, value: T) -> T - where - T: TypeFoldable<TyCtxt<'tcx>>, - { - self.resolve_vars_if_possible(value) - } - - fn probe<T>(&self, probe: impl FnOnce() -> T) -> T { - self.probe(|_| probe()) - } -} - /// See the `error_reporting` module for more details. #[derive(Clone, Copy, Debug, PartialEq, Eq, TypeFoldable, TypeVisitable)] pub enum ValuePairs<'tcx> { @@ -826,10 +684,14 @@ impl<'tcx> InferOk<'tcx, ()> { } impl<'tcx> InferCtxt<'tcx> { - pub fn dcx(&self) -> &'tcx DiagCtxt { + pub fn dcx(&self) -> DiagCtxtHandle<'tcx> { self.tcx.dcx() } + pub fn defining_opaque_types(&self) -> &'tcx ty::List<LocalDefId> { + self.defining_opaque_types + } + pub fn next_trait_solver(&self) -> bool { self.next_trait_solver } @@ -1016,9 +878,9 @@ impl<'tcx> InferCtxt<'tcx> { self.enter_forall(predicate, |ty::SubtypePredicate { a_is_expected, a, b }| { if a_is_expected { - Ok(self.at(cause, param_env).sub(DefineOpaqueTypes::No, a, b)) + Ok(self.at(cause, param_env).sub(DefineOpaqueTypes::Yes, a, b)) } else { - Ok(self.at(cause, param_env).sup(DefineOpaqueTypes::No, b, a)) + Ok(self.at(cause, param_env).sup(DefineOpaqueTypes::Yes, b, a)) } }) } diff --git a/compiler/rustc_interface/src/interface.rs b/compiler/rustc_interface/src/interface.rs index c95a10f4e8d..41c8b941717 100644 --- a/compiler/rustc_interface/src/interface.rs +++ b/compiler/rustc_interface/src/interface.rs @@ -9,7 +9,7 @@ use rustc_data_structures::jobserver; use rustc_data_structures::stable_hasher::StableHasher; use rustc_data_structures::sync::Lrc; use rustc_errors::registry::Registry; -use rustc_errors::{DiagCtxt, ErrorGuaranteed}; +use rustc_errors::{DiagCtxtHandle, ErrorGuaranteed}; use rustc_lint::LintStore; use rustc_middle::ty; use rustc_middle::ty::CurrentGcx; @@ -46,7 +46,7 @@ pub struct Compiler { } /// Converts strings provided as `--cfg [cfgspec]` into a `Cfg`. -pub(crate) fn parse_cfg(dcx: &DiagCtxt, cfgs: Vec<String>) -> Cfg { +pub(crate) fn parse_cfg(dcx: DiagCtxtHandle<'_>, cfgs: Vec<String>) -> Cfg { cfgs.into_iter() .map(|s| { let psess = ParseSess::with_silent_emitter( @@ -105,7 +105,7 @@ pub(crate) fn parse_cfg(dcx: &DiagCtxt, cfgs: Vec<String>) -> Cfg { } /// Converts strings provided as `--check-cfg [specs]` into a `CheckCfg`. -pub(crate) fn parse_check_cfg(dcx: &DiagCtxt, specs: Vec<String>) -> CheckCfg { +pub(crate) fn parse_check_cfg(dcx: DiagCtxtHandle<'_>, specs: Vec<String>) -> CheckCfg { // If any --check-cfg is passed then exhaustive_values and exhaustive_names // are enabled by default. let exhaustive_names = !specs.is_empty(); @@ -451,12 +451,12 @@ pub fn run_compiler<R: Send>(config: Config, f: impl FnOnce(&Compiler) -> R + Se codegen_backend.init(&sess); - let cfg = parse_cfg(&sess.dcx(), config.crate_cfg); + let cfg = parse_cfg(sess.dcx(), config.crate_cfg); let mut cfg = config::build_configuration(&sess, cfg); util::add_configuration(&mut cfg, &mut sess, &*codegen_backend); sess.psess.config = cfg; - let mut check_cfg = parse_check_cfg(&sess.dcx(), config.crate_check_cfg); + let mut check_cfg = parse_check_cfg(sess.dcx(), config.crate_check_cfg); check_cfg.fill_well_known(&sess.target); sess.psess.check_config = check_cfg; @@ -529,7 +529,7 @@ pub fn run_compiler<R: Send>(config: Config, f: impl FnOnce(&Compiler) -> R + Se } pub fn try_print_query_stack( - dcx: &DiagCtxt, + dcx: DiagCtxtHandle<'_>, num_frames: Option<usize>, file: Option<std::fs::File>, ) { diff --git a/compiler/rustc_interface/src/passes.rs b/compiler/rustc_interface/src/passes.rs index d52286d5887..f881d53858a 100644 --- a/compiler/rustc_interface/src/passes.rs +++ b/compiler/rustc_interface/src/passes.rs @@ -756,7 +756,7 @@ fn run_required_analyses(tcx: TyCtxt<'_>) { || tcx.hir().body_const_context(def_id).is_some() { tcx.ensure().mir_drops_elaborated_and_const_checked(def_id); - tcx.ensure().unused_generic_params(ty::InstanceDef::Item(def_id.to_def_id())); + tcx.ensure().unused_generic_params(ty::InstanceKind::Item(def_id.to_def_id())); } } }); diff --git a/compiler/rustc_interface/src/tests.rs b/compiler/rustc_interface/src/tests.rs index 6538995926a..2909f8adfb0 100644 --- a/compiler/rustc_interface/src/tests.rs +++ b/compiler/rustc_interface/src/tests.rs @@ -70,7 +70,7 @@ where Arc::default(), Default::default(), ); - let cfg = parse_cfg(&sess.dcx(), matches.opt_strs("cfg")); + let cfg = parse_cfg(sess.dcx(), matches.opt_strs("cfg")); let cfg = build_configuration(&sess, cfg); f(sess, cfg) }); @@ -761,7 +761,7 @@ fn test_unstable_options_tracking_hash() { }) ); tracked!(codegen_backend, Some("abc".to_string())); - tracked!(coverage_options, CoverageOptions { level: CoverageLevel::Mcdc }); + tracked!(coverage_options, CoverageOptions { level: CoverageLevel::Mcdc, no_mir_spans: true }); tracked!(crate_attr, vec!["abc".to_string()]); tracked!(cross_crate_inline_threshold, InliningThreshold::Always); tracked!(debug_info_for_profiling, true); diff --git a/compiler/rustc_lint/messages.ftl b/compiler/rustc_lint/messages.ftl index 043042a492b..007709e32d8 100644 --- a/compiler/rustc_lint/messages.ftl +++ b/compiler/rustc_lint/messages.ftl @@ -14,6 +14,7 @@ lint_associated_const_elided_lifetime = {$elided -> *[false] `'_` cannot be used here } .suggestion = use the `'static` lifetime + .note = cannot automatically infer `'static` because of other lifetimes in scope lint_async_fn_in_trait = use of `async fn` in public traits is discouraged as auto trait bounds cannot be specified .note = you can suppress this lint if you plan to use the trait only in your own code, or do not care about auto traits like `Send` on the `Future` @@ -548,6 +549,7 @@ lint_non_local_definitions_impl = non-local `impl` definition, `impl` blocks sho .without_trait = methods and associated constants are still usable outside the current expression, only `impl Local` and `impl dyn Local` can ever be private, and only if the type is nested in the same item as the `impl` .with_trait = 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` .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 + .doctest = make this doc-test a standalone test with its own `fn main() {"{"} ... {"}"}` .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 diff --git a/compiler/rustc_lint/src/context/diagnostics.rs b/compiler/rustc_lint/src/context/diagnostics.rs index 83640d7210f..290bb5173db 100644 --- a/compiler/rustc_lint/src/context/diagnostics.rs +++ b/compiler/rustc_lint/src/context/diagnostics.rs @@ -319,11 +319,20 @@ pub(super) fn decorate_lint(sess: &Session, diagnostic: BuiltinLintDiag, diag: & BuiltinLintDiag::UnusedQualifications { removal_span } => { lints::UnusedQualifications { removal_span }.decorate_lint(diag); } - BuiltinLintDiag::AssociatedConstElidedLifetime { elided, span: lt_span } => { + BuiltinLintDiag::AssociatedConstElidedLifetime { + elided, + span: lt_span, + lifetimes_in_scope, + } => { let lt_span = if elided { lt_span.shrink_to_hi() } else { lt_span }; let code = if elided { "'static " } else { "'static" }; - lints::AssociatedConstElidedLifetime { span: lt_span, code, elided } - .decorate_lint(diag); + lints::AssociatedConstElidedLifetime { + span: lt_span, + code, + elided, + lifetimes_in_scope, + } + .decorate_lint(diag); } BuiltinLintDiag::RedundantImportVisibility { max_vis, span: vis_span, import_vis } => { lints::RedundantImportVisibility { span: vis_span, help: (), max_vis, import_vis } diff --git a/compiler/rustc_lint/src/impl_trait_overcaptures.rs b/compiler/rustc_lint/src/impl_trait_overcaptures.rs index a311c274a6b..d4f6d388d9f 100644 --- a/compiler/rustc_lint/src/impl_trait_overcaptures.rs +++ b/compiler/rustc_lint/src/impl_trait_overcaptures.rs @@ -11,7 +11,7 @@ use rustc_middle::ty::{ self, Ty, TyCtxt, TypeSuperVisitable, TypeVisitable, TypeVisitableExt, TypeVisitor, }; use rustc_session::{declare_lint, declare_lint_pass}; -use rustc_span::{sym, BytePos, Span}; +use rustc_span::{sym, Span}; use crate::fluent_generated as fluent; use crate::{LateContext, LateLintPass}; @@ -53,7 +53,7 @@ declare_lint! { /// while the `impl Display` is live. /// /// To fix this, we can explicitly state that the `impl Display` doesn't - /// capture any lifetimes, using `impl use<> Display`. + /// capture any lifetimes, using `impl Display + use<>`. pub IMPL_TRAIT_OVERCAPTURES, Allow, "`impl Trait` will capture more lifetimes than possibly intended in edition 2024", @@ -79,7 +79,7 @@ declare_lint! { /// # #![feature(precise_capturing, lifetime_capture_rules_2024)] /// # #![allow(incomplete_features)] /// # #![deny(impl_trait_redundant_captures)] - /// fn test<'a>(x: &'a i32) -> impl use<'a> Sized { x } + /// fn test<'a>(x: &'a i32) -> impl Sized + use<'a> { x } /// ``` /// /// {{produces}} @@ -249,7 +249,7 @@ impl<'tcx> TypeVisitor<TyCtxt<'tcx>> for VisitOpaqueTypes<'tcx> { // If we have uncaptured args, and if the opaque doesn't already have // `use<>` syntax on it, and we're < edition 2024, then warn the user. if !new_capture_rules - && opaque.precise_capturing_args.is_none() + && !opaque.bounds.iter().any(|bound| matches!(bound, hir::GenericBound::Use(..))) && !uncaptured_spans.is_empty() { let suggestion = if let Ok(snippet) = @@ -268,8 +268,8 @@ impl<'tcx> TypeVisitor<TyCtxt<'tcx>> for VisitOpaqueTypes<'tcx> { // Make sure that we're not trying to name any APITs if generics.iter().all(|name| !name.starts_with("impl ")) { Some(( - format!(" use<{}>", generics.join(", ")), - opaque_span.with_lo(opaque_span.lo() + BytePos(4)).shrink_to_lo(), + format!(" + use<{}>", generics.join(", ")), + opaque_span.shrink_to_hi(), )) } else { None @@ -294,7 +294,11 @@ impl<'tcx> TypeVisitor<TyCtxt<'tcx>> for VisitOpaqueTypes<'tcx> { // have no uncaptured args, then we should warn to the user that // it's redundant to capture all args explicitly. else if new_capture_rules - && let Some((captured_args, capturing_span)) = opaque.precise_capturing_args + && let Some((captured_args, capturing_span)) = + opaque.bounds.iter().find_map(|bound| match *bound { + hir::GenericBound::Use(a, s) => Some((a, s)), + _ => None, + }) { let mut explicitly_captured = UnordSet::default(); for arg in captured_args { diff --git a/compiler/rustc_lint/src/lints.rs b/compiler/rustc_lint/src/lints.rs index 8059f5c1a2e..b26d04d0618 100644 --- a/compiler/rustc_lint/src/lints.rs +++ b/compiler/rustc_lint/src/lints.rs @@ -1358,6 +1358,7 @@ pub enum NonLocalDefinitionsDiag { cargo_update: Option<NonLocalDefinitionsCargoUpdateNote>, const_anon: Option<Option<Span>>, move_to: Option<(Span, Vec<Span>)>, + doctest: bool, may_remove: Option<(Span, String)>, has_trait: bool, self_ty_str: String, @@ -1368,8 +1369,7 @@ pub enum NonLocalDefinitionsDiag { depth: u32, body_kind_descr: &'static str, body_name: String, - help: Option<()>, - doctest_help: Option<()>, + doctest: bool, cargo_update: Option<NonLocalDefinitionsCargoUpdateNote>, }, } @@ -1384,6 +1384,7 @@ impl<'a> LintDiagnostic<'a, ()> for NonLocalDefinitionsDiag { cargo_update, const_anon, move_to, + doctest, may_remove, has_trait, self_ty_str, @@ -1405,7 +1406,7 @@ impl<'a> LintDiagnostic<'a, ()> for NonLocalDefinitionsDiag { diag.note(fluent::lint_macro_to_change); } if let Some(cargo_update) = cargo_update { - diag.subdiagnostic(&diag.dcx, cargo_update); + diag.subdiagnostic(cargo_update); } if has_trait { @@ -1422,6 +1423,9 @@ impl<'a> LintDiagnostic<'a, ()> for NonLocalDefinitionsDiag { } diag.span_help(ms, fluent::lint_non_local_definitions_impl_move_help); } + if doctest { + diag.help(fluent::lint_doctest); + } if let Some((span, part)) = may_remove { diag.arg("may_remove_part", part); @@ -1451,8 +1455,7 @@ impl<'a> LintDiagnostic<'a, ()> for NonLocalDefinitionsDiag { depth, body_kind_descr, body_name, - help, - doctest_help, + doctest, cargo_update, } => { diag.primary_message(fluent::lint_non_local_definitions_macro_rules); @@ -1460,18 +1463,17 @@ impl<'a> LintDiagnostic<'a, ()> for NonLocalDefinitionsDiag { diag.arg("body_kind_descr", body_kind_descr); diag.arg("body_name", body_name); - if let Some(()) = help { - diag.help(fluent::lint_help); - } - if let Some(()) = doctest_help { + if doctest { diag.help(fluent::lint_help_doctest); + } else { + diag.help(fluent::lint_help); } diag.note(fluent::lint_non_local); diag.note(fluent::lint_non_local_definitions_deprecation); if let Some(cargo_update) = cargo_update { - diag.subdiagnostic(&diag.dcx, cargo_update); + diag.subdiagnostic(cargo_update); } } } @@ -1957,7 +1959,7 @@ impl<'a> LintDiagnostic<'a, ()> for UnusedDef<'_, '_> { diag.note(note.to_string()); } if let Some(sugg) = self.suggestion { - diag.subdiagnostic(diag.dcx, sugg); + diag.subdiagnostic(sugg); } } } @@ -2873,6 +2875,8 @@ pub struct AssociatedConstElidedLifetime { pub code: &'static str, pub elided: bool, + #[note] + pub lifetimes_in_scope: MultiSpan, } #[derive(LintDiagnostic)] diff --git a/compiler/rustc_lint/src/non_local_def.rs b/compiler/rustc_lint/src/non_local_def.rs index b0ec6e06658..24dd337e699 100644 --- a/compiler/rustc_lint/src/non_local_def.rs +++ b/compiler/rustc_lint/src/non_local_def.rs @@ -111,6 +111,12 @@ impl<'tcx> LateLintPass<'tcx> for NonLocalDefinitions { } }; + // determining if we are in a doctest context can't currently be determined + // by the code itself (there are no specific attributes), but fortunately rustdoc + // sets a perma-unstable env var for libtest so we just reuse that for now + let is_at_toplevel_doctest = + || self.body_depth == 2 && std::env::var("UNSTABLE_RUSTDOC_TEST_PATH").is_ok(); + match item.kind { ItemKind::Impl(impl_) => { // The RFC states: @@ -191,29 +197,6 @@ impl<'tcx> LateLintPass<'tcx> for NonLocalDefinitions { None }; - let mut collector = PathCollector { paths: Vec::new() }; - collector.visit_ty(&impl_.self_ty); - if let Some(of_trait) = &impl_.of_trait { - collector.visit_trait_ref(of_trait); - } - collector.visit_generics(&impl_.generics); - - let mut may_move: Vec<Span> = collector - .paths - .into_iter() - .filter_map(|path| { - if let Some(did) = path.res.opt_def_id() - && did_has_local_parent(did, cx.tcx, parent, parent_parent) - { - Some(cx.tcx.def_span(did)) - } else { - None - } - }) - .collect(); - may_move.sort(); - may_move.dedup(); - let const_anon = matches!(parent_def_kind, DefKind::Const | DefKind::Static { .. }) .then_some(span_for_const_anon_suggestion); @@ -248,14 +231,44 @@ impl<'tcx> LateLintPass<'tcx> for NonLocalDefinitions { } else { None }; - let move_to = if may_move.is_empty() { - ms.push_span_label( - cx.tcx.def_span(parent), - fluent::lint_non_local_definitions_impl_move_help, - ); - None + + let (doctest, move_to) = if is_at_toplevel_doctest() { + (true, None) } else { - Some((cx.tcx.def_span(parent), may_move)) + let mut collector = PathCollector { paths: Vec::new() }; + collector.visit_ty(&impl_.self_ty); + if let Some(of_trait) = &impl_.of_trait { + collector.visit_trait_ref(of_trait); + } + collector.visit_generics(&impl_.generics); + + let mut may_move: Vec<Span> = collector + .paths + .into_iter() + .filter_map(|path| { + if let Some(did) = path.res.opt_def_id() + && did_has_local_parent(did, cx.tcx, parent, parent_parent) + { + Some(cx.tcx.def_span(did)) + } else { + None + } + }) + .collect(); + may_move.sort(); + may_move.dedup(); + + let move_to = if may_move.is_empty() { + ms.push_span_label( + cx.tcx.def_span(parent), + fluent::lint_non_local_definitions_impl_move_help, + ); + None + } else { + Some((cx.tcx.def_span(parent), may_move)) + }; + + (false, move_to) }; let macro_to_change = @@ -279,6 +292,7 @@ impl<'tcx> LateLintPass<'tcx> for NonLocalDefinitions { self_ty_str, of_trait_str, move_to, + doctest, may_remove, has_trait: impl_.of_trait.is_some(), macro_to_change, @@ -288,12 +302,6 @@ impl<'tcx> LateLintPass<'tcx> for NonLocalDefinitions { ItemKind::Macro(_macro, MacroKind::Bang) if cx.tcx.has_attr(item.owner_id.def_id, sym::macro_export) => { - // determining we if are in a doctest context can't currently be determined - // by the code it-self (no specific attrs), but fortunatly rustdoc sets a - // perma-unstable env for libtest so we just re-use that env for now - let is_at_toplevel_doctest = - self.body_depth == 2 && std::env::var("UNSTABLE_RUSTDOC_TEST_PATH").is_ok(); - cx.emit_span_lint( NON_LOCAL_DEFINITIONS, item.span, @@ -304,8 +312,7 @@ impl<'tcx> LateLintPass<'tcx> for NonLocalDefinitions { .map(|s| s.to_ident_string()) .unwrap_or_else(|| "<unnameable>".to_string()), cargo_update: cargo_update(), - help: (!is_at_toplevel_doctest).then_some(()), - doctest_help: is_at_toplevel_doctest.then_some(()), + doctest: is_at_toplevel_doctest(), }, ) } diff --git a/compiler/rustc_lint/src/shadowed_into_iter.rs b/compiler/rustc_lint/src/shadowed_into_iter.rs index 85006421fdd..da2b5878b19 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/unused.rs b/compiler/rustc_lint/src/unused.rs index 7a1aa4043be..195a0f72475 100644 --- a/compiler/rustc_lint/src/unused.rs +++ b/compiler/rustc_lint/src/unused.rs @@ -1268,7 +1268,7 @@ impl EarlyLintPass for UnusedParens { ast::TyKind::TraitObject(..) => {} ast::TyKind::BareFn(b) if self.with_self_ty_parens && b.generic_params.len() > 0 => {} - ast::TyKind::ImplTrait(_, bounds, _) if bounds.len() > 1 => {} + ast::TyKind::ImplTrait(_, bounds) if bounds.len() > 1 => {} _ => { let spans = if !ty.span.from_expansion() { r.span diff --git a/compiler/rustc_lint_defs/src/builtin.rs b/compiler/rustc_lint_defs/src/builtin.rs index a12c76037e7..1913b9d6a1c 100644 --- a/compiler/rustc_lint_defs/src/builtin.rs +++ b/compiler/rustc_lint_defs/src/builtin.rs @@ -4593,16 +4593,18 @@ declare_lint! { declare_lint! { /// The `elided_lifetimes_in_associated_constant` lint detects elided lifetimes - /// that were erroneously allowed in associated constants. + /// in associated constants when there are other lifetimes in scope. This was + /// accidentally supported, and this lint was later relaxed to allow eliding + /// lifetimes to `'static` when there are no lifetimes in scope. /// /// ### Example /// /// ```rust,compile_fail /// #![deny(elided_lifetimes_in_associated_constant)] /// - /// struct Foo; + /// struct Foo<'a>(&'a ()); /// - /// impl Foo { + /// impl<'a> Foo<'a> { /// const STR: &str = "hello, world"; /// } /// ``` diff --git a/compiler/rustc_lint_defs/src/lib.rs b/compiler/rustc_lint_defs/src/lib.rs index 1ce95df3404..70330c44577 100644 --- a/compiler/rustc_lint_defs/src/lib.rs +++ b/compiler/rustc_lint_defs/src/lib.rs @@ -696,6 +696,7 @@ pub enum BuiltinLintDiag { AssociatedConstElidedLifetime { elided: bool, span: Span, + lifetimes_in_scope: MultiSpan, }, RedundantImportVisibility { span: Span, diff --git a/compiler/rustc_macros/src/diagnostics/diagnostic.rs b/compiler/rustc_macros/src/diagnostics/diagnostic.rs index ef6005283d6..a3abbdcf18c 100644 --- a/compiler/rustc_macros/src/diagnostics/diagnostic.rs +++ b/compiler/rustc_macros/src/diagnostics/diagnostic.rs @@ -78,7 +78,7 @@ impl<'a> DiagnosticDerive<'a> { #[track_caller] fn into_diag( self, - dcx: &'_sess rustc_errors::DiagCtxt, + dcx: rustc_errors::DiagCtxtHandle<'_sess>, level: rustc_errors::Level ) -> rustc_errors::Diag<'_sess, G> { #implementation diff --git a/compiler/rustc_macros/src/diagnostics/diagnostic_builder.rs b/compiler/rustc_macros/src/diagnostics/diagnostic_builder.rs index 38d4a5ee61c..46bd80c2df6 100644 --- a/compiler/rustc_macros/src/diagnostics/diagnostic_builder.rs +++ b/compiler/rustc_macros/src/diagnostics/diagnostic_builder.rs @@ -335,7 +335,7 @@ impl DiagnosticDeriveVariantBuilder { } } (Meta::Path(_), "subdiagnostic") => { - return Ok(quote! { diag.subdiagnostic(diag.dcx, #binding); }); + return Ok(quote! { diag.subdiagnostic(#binding); }); } _ => (), } diff --git a/compiler/rustc_metadata/src/creader.rs b/compiler/rustc_metadata/src/creader.rs index ad283117d7e..749495bc2ef 100644 --- a/compiler/rustc_metadata/src/creader.rs +++ b/compiler/rustc_metadata/src/creader.rs @@ -10,7 +10,7 @@ use rustc_data_structures::fx::FxHashSet; use rustc_data_structures::owned_slice::OwnedSlice; use rustc_data_structures::svh::Svh; use rustc_data_structures::sync::{self, FreezeReadGuard, FreezeWriteGuard}; -use rustc_errors::DiagCtxt; +use rustc_errors::DiagCtxtHandle; use rustc_expand::base::SyntaxExtension; use rustc_fs_util::try_canonicalize; use rustc_hir::def_id::{CrateNum, LocalDefId, StableCrateId, LOCAL_CRATE}; @@ -91,8 +91,8 @@ impl<'a, 'tcx> std::ops::Deref for CrateLoader<'a, 'tcx> { } impl<'a, 'tcx> CrateLoader<'a, 'tcx> { - fn dcx(&self) -> &'tcx DiagCtxt { - &self.tcx.dcx() + fn dcx(&self) -> DiagCtxtHandle<'tcx> { + self.tcx.dcx() } } diff --git a/compiler/rustc_metadata/src/errors.rs b/compiler/rustc_metadata/src/errors.rs index 47d183a0440..b0d82a0e3b7 100644 --- a/compiler/rustc_metadata/src/errors.rs +++ b/compiler/rustc_metadata/src/errors.rs @@ -3,7 +3,7 @@ use std::{ path::{Path, PathBuf}, }; -use rustc_errors::{codes::*, Diag, DiagCtxt, Diagnostic, EmissionGuarantee, Level}; +use rustc_errors::{codes::*, Diag, DiagCtxtHandle, Diagnostic, EmissionGuarantee, Level}; use rustc_macros::{Diagnostic, Subdiagnostic}; use rustc_span::{sym, Span, Symbol}; use rustc_target::spec::{PanicStrategy, TargetTriple}; @@ -503,7 +503,7 @@ pub(crate) struct MultipleCandidates { } impl<G: EmissionGuarantee> Diagnostic<'_, G> for MultipleCandidates { - fn into_diag(self, dcx: &'_ DiagCtxt, level: Level) -> Diag<'_, G> { + fn into_diag(self, dcx: DiagCtxtHandle<'_>, level: Level) -> Diag<'_, G> { let mut diag = Diag::new(dcx, level, fluent::metadata_multiple_candidates); diag.arg("crate_name", self.crate_name); diag.arg("flavor", self.flavor); @@ -602,7 +602,7 @@ pub struct InvalidMetadataFiles { impl<G: EmissionGuarantee> Diagnostic<'_, G> for InvalidMetadataFiles { #[track_caller] - fn into_diag(self, dcx: &'_ DiagCtxt, level: Level) -> Diag<'_, G> { + fn into_diag(self, dcx: DiagCtxtHandle<'_>, level: Level) -> Diag<'_, G> { let mut diag = Diag::new(dcx, level, fluent::metadata_invalid_meta_files); diag.arg("crate_name", self.crate_name); diag.arg("add_info", self.add_info); @@ -631,7 +631,7 @@ pub struct CannotFindCrate { impl<G: EmissionGuarantee> Diagnostic<'_, G> for CannotFindCrate { #[track_caller] - fn into_diag(self, dcx: &'_ DiagCtxt, level: Level) -> Diag<'_, G> { + fn into_diag(self, dcx: DiagCtxtHandle<'_>, level: Level) -> Diag<'_, G> { let mut diag = Diag::new(dcx, level, fluent::metadata_cannot_find_crate); diag.arg("crate_name", self.crate_name); diag.arg("current_crate", self.current_crate); diff --git a/compiler/rustc_metadata/src/rmeta/decoder/cstore_impl.rs b/compiler/rustc_metadata/src/rmeta/decoder/cstore_impl.rs index 1cef35f082b..c9450142cd3 100644 --- a/compiler/rustc_metadata/src/rmeta/decoder/cstore_impl.rs +++ b/compiler/rustc_metadata/src/rmeta/decoder/cstore_impl.rs @@ -191,7 +191,7 @@ impl IntoArgs for (CrateNum, DefId) { } } -impl<'tcx> IntoArgs for ty::InstanceDef<'tcx> { +impl<'tcx> IntoArgs for ty::InstanceKind<'tcx> { type Other = (); fn into_args(self) -> (DefId, ()) { (self.def_id(), ()) diff --git a/compiler/rustc_metadata/src/rmeta/encoder.rs b/compiler/rustc_metadata/src/rmeta/encoder.rs index d7840a2d516..4bd2ec09a6e 100644 --- a/compiler/rustc_metadata/src/rmeta/encoder.rs +++ b/compiler/rustc_metadata/src/rmeta/encoder.rs @@ -1693,7 +1693,7 @@ impl<'a, 'tcx> EncodeContext<'a, 'tcx> { record!(self.tables.mir_coroutine_witnesses[def_id.to_def_id()] <- witnesses); } - let instance = ty::InstanceDef::Item(def_id.to_def_id()); + let instance = ty::InstanceKind::Item(def_id.to_def_id()); let unused = tcx.unused_generic_params(instance); self.tables.unused_generic_params.set(def_id.local_def_index, unused); } diff --git a/compiler/rustc_middle/src/arena.rs b/compiler/rustc_middle/src/arena.rs index de786c38326..e3d7dff3c66 100644 --- a/compiler/rustc_middle/src/arena.rs +++ b/compiler/rustc_middle/src/arena.rs @@ -110,8 +110,8 @@ macro_rules! arena_types { rustc_hir::def_id::DefId, rustc_middle::ty::EarlyBinder<'tcx, rustc_middle::ty::Ty<'tcx>> >, - [] external_constraints: rustc_middle::traits::solve::ExternalConstraintsData<'tcx>, - [] predefined_opaques_in_body: rustc_middle::traits::solve::PredefinedOpaquesData<'tcx>, + [] external_constraints: rustc_middle::traits::solve::ExternalConstraintsData<rustc_middle::ty::TyCtxt<'tcx>>, + [] predefined_opaques_in_body: rustc_middle::traits::solve::PredefinedOpaquesData<rustc_middle::ty::TyCtxt<'tcx>>, [decode] doc_link_resolutions: rustc_hir::def::DocLinkResMap, [] stripped_cfg_items: rustc_ast::expand::StrippedCfgItem, [] mod_child: rustc_middle::metadata::ModChild, diff --git a/compiler/rustc_middle/src/macros.rs b/compiler/rustc_middle/src/macros.rs index 817ac594627..fcea1ea81a7 100644 --- a/compiler/rustc_middle/src/macros.rs +++ b/compiler/rustc_middle/src/macros.rs @@ -4,10 +4,10 @@ /// /// If you have a span available, you should use [`span_bug`] instead. /// -/// If the bug should only be emitted when compilation didn't fail, [`DiagCtxt::span_delayed_bug`] +/// If the bug should only be emitted when compilation didn't fail, [`DiagCtxtHandle::span_delayed_bug`] /// may be useful. /// -/// [`DiagCtxt::span_delayed_bug`]: rustc_errors::DiagCtxt::span_delayed_bug +/// [`DiagCtxtHandle::span_delayed_bug`]: rustc_errors::DiagCtxtHandle::span_delayed_bug /// [`span_bug`]: crate::span_bug #[macro_export] macro_rules! bug { @@ -30,10 +30,10 @@ macro_rules! bug { /// at the code the compiler was compiling when it ICEd. This is the preferred way to trigger /// ICEs. /// -/// If the bug should only be emitted when compilation didn't fail, [`DiagCtxt::span_delayed_bug`] +/// If the bug should only be emitted when compilation didn't fail, [`DiagCtxtHandle::span_delayed_bug`] /// may be useful. /// -/// [`DiagCtxt::span_delayed_bug`]: rustc_errors::DiagCtxt::span_delayed_bug +/// [`DiagCtxtHandle::span_delayed_bug`]: rustc_errors::DiagCtxtHandle::span_delayed_bug #[macro_export] macro_rules! span_bug { ($span:expr, $msg:expr) => ( diff --git a/compiler/rustc_middle/src/middle/exported_symbols.rs b/compiler/rustc_middle/src/middle/exported_symbols.rs index 3b6eecb7fa0..b35cc83cb8e 100644 --- a/compiler/rustc_middle/src/middle/exported_symbols.rs +++ b/compiler/rustc_middle/src/middle/exported_symbols.rs @@ -64,7 +64,7 @@ impl<'tcx> ExportedSymbol<'tcx> { tcx.symbol_name(ty::Instance::resolve_async_drop_in_place(tcx, ty)) } ExportedSymbol::ThreadLocalShim(def_id) => tcx.symbol_name(ty::Instance { - def: ty::InstanceDef::ThreadLocalShim(def_id), + def: ty::InstanceKind::ThreadLocalShim(def_id), args: ty::GenericArgs::empty(), }), ExportedSymbol::NoDefId(symbol_name) => symbol_name, diff --git a/compiler/rustc_middle/src/middle/stability.rs b/compiler/rustc_middle/src/middle/stability.rs index 8cf1bedf0da..d1ccd158cf9 100644 --- a/compiler/rustc_middle/src/middle/stability.rs +++ b/compiler/rustc_middle/src/middle/stability.rs @@ -176,7 +176,7 @@ impl<'a, G: EmissionGuarantee> rustc_errors::LintDiagnostic<'a, G> for Deprecate diag.arg("has_note", false); } if let Some(sub) = self.sub { - diag.subdiagnostic(diag.dcx, sub); + diag.subdiagnostic(sub); } } } diff --git a/compiler/rustc_middle/src/mir/graphviz.rs b/compiler/rustc_middle/src/mir/graphviz.rs index 96bef40dac5..2eadc4d553c 100644 --- a/compiler/rustc_middle/src/mir/graphviz.rs +++ b/compiler/rustc_middle/src/mir/graphviz.rs @@ -19,7 +19,7 @@ where if tcx.is_const_fn_raw(*def_id) { vec![tcx.optimized_mir(*def_id), tcx.mir_for_ctfe(*def_id)] } else { - vec![tcx.instance_mir(ty::InstanceDef::Item(*def_id))] + vec![tcx.instance_mir(ty::InstanceKind::Item(*def_id))] } }) .collect::<Vec<_>>(); diff --git a/compiler/rustc_middle/src/mir/interpret/allocation.rs b/compiler/rustc_middle/src/mir/interpret/allocation.rs index b0f8a047b82..2fc466c0e7e 100644 --- a/compiler/rustc_middle/src/mir/interpret/allocation.rs +++ b/compiler/rustc_middle/src/mir/interpret/allocation.rs @@ -52,7 +52,7 @@ impl AllocBytes for Box<[u8]> { } fn zeroed(size: Size, _align: Align) -> Option<Self> { - let bytes = Box::<[u8]>::try_new_zeroed_slice(size.bytes_usize()).ok()?; + let bytes = Box::<[u8]>::try_new_zeroed_slice(size.bytes().try_into().ok()?).ok()?; // SAFETY: the box was zero-allocated, which is a valid initial value for Box<[u8]> let bytes = unsafe { bytes.assume_init() }; Some(bytes) @@ -323,7 +323,10 @@ impl<Prov: Provenance, Bytes: AllocBytes> Allocation<Prov, (), Bytes> { /// first call this function and then call write_scalar to fill in the right data. pub fn uninit(size: Size, align: Align) -> Self { match Self::uninit_inner(size, align, || { - panic!("Allocation::uninit called with panic_on_fail had allocation failure"); + panic!( + "interpreter ran out of memory: cannot create allocation of {} bytes", + size.bytes() + ); }) { Ok(x) => x, Err(x) => x, diff --git a/compiler/rustc_middle/src/mir/interpret/error.rs b/compiler/rustc_middle/src/mir/interpret/error.rs index eabbcc2033f..23680f14397 100644 --- a/compiler/rustc_middle/src/mir/interpret/error.rs +++ b/compiler/rustc_middle/src/mir/interpret/error.rs @@ -438,9 +438,6 @@ pub enum ValidationErrorKind<'tcx> { ptr_kind: PointerKind, ty: Ty<'tcx>, }, - PtrToStatic { - ptr_kind: PointerKind, - }, ConstRefToMutable, ConstRefToExtern, MutableRefToImmutable, diff --git a/compiler/rustc_middle/src/mir/mod.rs b/compiler/rustc_middle/src/mir/mod.rs index 02e5174a715..01cefc75194 100644 --- a/compiler/rustc_middle/src/mir/mod.rs +++ b/compiler/rustc_middle/src/mir/mod.rs @@ -10,7 +10,7 @@ use crate::ty::print::{pretty_print_const, with_no_trimmed_paths}; use crate::ty::print::{FmtPrinter, Printer}; use crate::ty::visit::TypeVisitableExt; use crate::ty::{self, List, Ty, TyCtxt}; -use crate::ty::{AdtDef, Instance, InstanceDef, UserTypeAnnotationIndex}; +use crate::ty::{AdtDef, Instance, InstanceKind, UserTypeAnnotationIndex}; use crate::ty::{GenericArg, GenericArgsRef}; use rustc_data_structures::captures::Captures; @@ -233,7 +233,7 @@ impl RuntimePhase { #[derive(Copy, Clone, Debug, PartialEq, Eq)] #[derive(HashStable, TyEncodable, TyDecodable, TypeFoldable, TypeVisitable)] pub struct MirSource<'tcx> { - pub instance: InstanceDef<'tcx>, + pub instance: InstanceKind<'tcx>, /// If `Some`, this is a promoted rvalue within the parent function. pub promoted: Option<Promoted>, @@ -241,10 +241,10 @@ pub struct MirSource<'tcx> { impl<'tcx> MirSource<'tcx> { pub fn item(def_id: DefId) -> Self { - MirSource { instance: InstanceDef::Item(def_id), promoted: None } + MirSource { instance: InstanceKind::Item(def_id), promoted: None } } - pub fn from_instance(instance: InstanceDef<'tcx>) -> Self { + pub fn from_instance(instance: InstanceKind<'tcx>) -> Self { MirSource { instance, promoted: None } } diff --git a/compiler/rustc_middle/src/mir/mono.rs b/compiler/rustc_middle/src/mir/mono.rs index 3d79ec0092f..146cd6dfbeb 100644 --- a/compiler/rustc_middle/src/mir/mono.rs +++ b/compiler/rustc_middle/src/mir/mono.rs @@ -1,5 +1,5 @@ use crate::dep_graph::{DepNode, WorkProduct, WorkProductId}; -use crate::ty::{GenericArgs, Instance, InstanceDef, SymbolName, TyCtxt}; +use crate::ty::{GenericArgs, Instance, InstanceKind, SymbolName, TyCtxt}; use rustc_attr::InlineAttr; use rustc_data_structures::base_n::BaseNString; use rustc_data_structures::base_n::ToBaseN; @@ -56,7 +56,7 @@ impl<'tcx> MonoItem<'tcx> { /// Returns `true` if the mono item is user-defined (i.e. not compiler-generated, like shims). pub fn is_user_defined(&self) -> bool { match *self { - MonoItem::Fn(instance) => matches!(instance.def, InstanceDef::Item(..)), + MonoItem::Fn(instance) => matches!(instance.def, InstanceKind::Item(..)), MonoItem::Static(..) | MonoItem::GlobalAsm(..) => true, } } @@ -69,9 +69,9 @@ impl<'tcx> MonoItem<'tcx> { match instance.def { // "Normal" functions size estimate: the number of // statements, plus one for the terminator. - InstanceDef::Item(..) - | InstanceDef::DropGlue(..) - | InstanceDef::AsyncDropGlueCtorShim(..) => { + InstanceKind::Item(..) + | InstanceKind::DropGlue(..) + | InstanceKind::AsyncDropGlueCtorShim(..) => { let mir = tcx.instance_mir(instance.def); mir.basic_blocks.iter().map(|bb| bb.statements.len() + 1).sum() } @@ -407,20 +407,20 @@ impl<'tcx> CodegenUnit<'tcx> { // instances into account. The others don't matter for // the codegen tests and can even make item order // unstable. - InstanceDef::Item(def) => def.as_local().map(Idx::index), - InstanceDef::VTableShim(..) - | InstanceDef::ReifyShim(..) - | InstanceDef::Intrinsic(..) - | InstanceDef::FnPtrShim(..) - | InstanceDef::Virtual(..) - | InstanceDef::ClosureOnceShim { .. } - | InstanceDef::ConstructCoroutineInClosureShim { .. } - | InstanceDef::CoroutineKindShim { .. } - | InstanceDef::DropGlue(..) - | InstanceDef::CloneShim(..) - | InstanceDef::ThreadLocalShim(..) - | InstanceDef::FnPtrAddrShim(..) - | InstanceDef::AsyncDropGlueCtorShim(..) => None, + InstanceKind::Item(def) => def.as_local().map(Idx::index), + InstanceKind::VTableShim(..) + | InstanceKind::ReifyShim(..) + | InstanceKind::Intrinsic(..) + | InstanceKind::FnPtrShim(..) + | InstanceKind::Virtual(..) + | InstanceKind::ClosureOnceShim { .. } + | InstanceKind::ConstructCoroutineInClosureShim { .. } + | InstanceKind::CoroutineKindShim { .. } + | InstanceKind::DropGlue(..) + | InstanceKind::CloneShim(..) + | InstanceKind::ThreadLocalShim(..) + | InstanceKind::FnPtrAddrShim(..) + | InstanceKind::AsyncDropGlueCtorShim(..) => None, } } MonoItem::Static(def_id) => def_id.as_local().map(Idx::index), diff --git a/compiler/rustc_middle/src/mir/pretty.rs b/compiler/rustc_middle/src/mir/pretty.rs index f1c3cb69896..4657f4dcf81 100644 --- a/compiler/rustc_middle/src/mir/pretty.rs +++ b/compiler/rustc_middle/src/mir/pretty.rs @@ -177,7 +177,7 @@ fn dump_path<'tcx>( // All drop shims have the same DefId, so we have to add the type // to get unique file names. let shim_disambiguator = match source.instance { - ty::InstanceDef::DropGlue(_, Some(ty)) => { + ty::InstanceKind::DropGlue(_, Some(ty)) => { // Unfortunately, pretty-printed typed are not very filename-friendly. // We dome some filtering. let mut s = ".".to_owned(); @@ -188,7 +188,7 @@ fn dump_path<'tcx>( })); s } - ty::InstanceDef::AsyncDropGlueCtorShim(_, Some(ty)) => { + ty::InstanceKind::AsyncDropGlueCtorShim(_, Some(ty)) => { // Unfortunately, pretty-printed typed are not very filename-friendly. // We dome some filtering. let mut s = ".".to_owned(); @@ -280,7 +280,7 @@ pub fn write_mir_pretty<'tcx>( // are shared between mir_for_ctfe and optimized_mir write_mir_fn(tcx, tcx.mir_for_ctfe(def_id), &mut |_, _| Ok(()), w)?; } else { - let instance_mir = tcx.instance_mir(ty::InstanceDef::Item(def_id)); + let instance_mir = tcx.instance_mir(ty::InstanceKind::Item(def_id)); render_body(w, instance_mir)?; } } diff --git a/compiler/rustc_middle/src/mir/syntax.rs b/compiler/rustc_middle/src/mir/syntax.rs index 3edc5fe36cd..736cef3cdb8 100644 --- a/compiler/rustc_middle/src/mir/syntax.rs +++ b/compiler/rustc_middle/src/mir/syntax.rs @@ -361,16 +361,19 @@ pub enum StatementKind<'tcx> { /// At any point during the execution of a function, each local is either allocated or /// unallocated. Except as noted below, all locals except function parameters are initially /// unallocated. `StorageLive` statements cause memory to be allocated for the local while - /// `StorageDead` statements cause the memory to be freed. Using a local in any way (not only - /// reading/writing from it) while it is unallocated is UB. + /// `StorageDead` statements cause the memory to be freed. In other words, + /// `StorageLive`/`StorageDead` act like the heap operations `allocate`/`deallocate`, but for + /// stack-allocated local variables. Using a local in any way (not only reading/writing from it) + /// while it is unallocated is UB. /// /// Some locals have no `StorageLive` or `StorageDead` statements within the entire MIR body. /// These locals are implicitly allocated for the full duration of the function. There is a /// convenience method at `rustc_mir_dataflow::storage::always_storage_live_locals` for /// computing these locals. /// - /// If the local is already allocated, calling `StorageLive` again is UB. However, for an - /// unallocated local an additional `StorageDead` all is simply a nop. + /// If the local is already allocated, calling `StorageLive` again will implicitly free the + /// local and then allocate fresh uninitilized memory. If a local is already deallocated, + /// calling `StorageDead` again is a NOP. StorageLive(Local), /// See `StorageLive` above. diff --git a/compiler/rustc_middle/src/mir/visit.rs b/compiler/rustc_middle/src/mir/visit.rs index 10609e56f2c..7628a1ed2fe 100644 --- a/compiler/rustc_middle/src/mir/visit.rs +++ b/compiler/rustc_middle/src/mir/visit.rs @@ -337,27 +337,27 @@ macro_rules! make_mir_visitor { let ty::Instance { def: callee_def, args: callee_args } = callee; match callee_def { - ty::InstanceDef::Item(_def_id) => {} - - ty::InstanceDef::Intrinsic(_def_id) | - ty::InstanceDef::VTableShim(_def_id) | - ty::InstanceDef::ReifyShim(_def_id, _) | - ty::InstanceDef::Virtual(_def_id, _) | - ty::InstanceDef::ThreadLocalShim(_def_id) | - ty::InstanceDef::ClosureOnceShim { call_once: _def_id, track_caller: _ } | - ty::InstanceDef::ConstructCoroutineInClosureShim { + ty::InstanceKind::Item(_def_id) => {} + + ty::InstanceKind::Intrinsic(_def_id) | + ty::InstanceKind::VTableShim(_def_id) | + ty::InstanceKind::ReifyShim(_def_id, _) | + ty::InstanceKind::Virtual(_def_id, _) | + ty::InstanceKind::ThreadLocalShim(_def_id) | + ty::InstanceKind::ClosureOnceShim { call_once: _def_id, track_caller: _ } | + ty::InstanceKind::ConstructCoroutineInClosureShim { coroutine_closure_def_id: _def_id, receiver_by_ref: _, } | - ty::InstanceDef::CoroutineKindShim { coroutine_def_id: _def_id } | - ty::InstanceDef::AsyncDropGlueCtorShim(_def_id, None) | - ty::InstanceDef::DropGlue(_def_id, None) => {} - - ty::InstanceDef::FnPtrShim(_def_id, ty) | - ty::InstanceDef::DropGlue(_def_id, Some(ty)) | - ty::InstanceDef::CloneShim(_def_id, ty) | - ty::InstanceDef::FnPtrAddrShim(_def_id, ty) | - ty::InstanceDef::AsyncDropGlueCtorShim(_def_id, Some(ty)) => { + ty::InstanceKind::CoroutineKindShim { coroutine_def_id: _def_id } | + ty::InstanceKind::AsyncDropGlueCtorShim(_def_id, None) | + ty::InstanceKind::DropGlue(_def_id, None) => {} + + ty::InstanceKind::FnPtrShim(_def_id, ty) | + ty::InstanceKind::DropGlue(_def_id, Some(ty)) | + ty::InstanceKind::CloneShim(_def_id, ty) | + ty::InstanceKind::FnPtrAddrShim(_def_id, ty) | + ty::InstanceKind::AsyncDropGlueCtorShim(_def_id, Some(ty)) => { // FIXME(eddyb) use a better `TyContext` here. self.visit_ty($(& $mutability)? *ty, TyContext::Location(location)); } diff --git a/compiler/rustc_middle/src/query/erase.rs b/compiler/rustc_middle/src/query/erase.rs index b29a86d58ed..301c9911b44 100644 --- a/compiler/rustc_middle/src/query/erase.rs +++ b/compiler/rustc_middle/src/query/erase.rs @@ -365,7 +365,7 @@ tcx_lifetime! { rustc_middle::ty::GenericPredicates, rustc_middle::ty::inhabitedness::InhabitedPredicate, rustc_middle::ty::Instance, - rustc_middle::ty::InstanceDef, + rustc_middle::ty::InstanceKind, rustc_middle::ty::layout::FnAbiError, rustc_middle::ty::layout::LayoutError, rustc_middle::ty::ParamEnv, diff --git a/compiler/rustc_middle/src/query/keys.rs b/compiler/rustc_middle/src/query/keys.rs index 5452e1dff3e..add88491f84 100644 --- a/compiler/rustc_middle/src/query/keys.rs +++ b/compiler/rustc_middle/src/query/keys.rs @@ -62,7 +62,7 @@ impl Key for () { } } -impl<'tcx> Key for ty::InstanceDef<'tcx> { +impl<'tcx> Key for ty::InstanceKind<'tcx> { type Cache<V> = DefaultCache<Self, V>; fn default_span(&self, tcx: TyCtxt<'_>) -> Span { @@ -70,7 +70,7 @@ impl<'tcx> Key for ty::InstanceDef<'tcx> { } } -impl<'tcx> AsLocalKey for ty::InstanceDef<'tcx> { +impl<'tcx> AsLocalKey for ty::InstanceKind<'tcx> { type LocalKey = Self; #[inline(always)] diff --git a/compiler/rustc_middle/src/query/mod.rs b/compiler/rustc_middle/src/query/mod.rs index 8ba930f493e..c5afecffb07 100644 --- a/compiler/rustc_middle/src/query/mod.rs +++ b/compiler/rustc_middle/src/query/mod.rs @@ -575,7 +575,7 @@ rustc_queries! { /// Summarizes coverage IDs inserted by the `InstrumentCoverage` MIR pass /// (for compiler option `-Cinstrument-coverage`), after MIR optimizations /// have had a chance to potentially remove some of them. - query coverage_ids_info(key: ty::InstanceDef<'tcx>) -> &'tcx mir::CoverageIdsInfo { + query coverage_ids_info(key: ty::InstanceKind<'tcx>) -> &'tcx mir::CoverageIdsInfo { desc { |tcx| "retrieving coverage IDs info from MIR for `{}`", tcx.def_path_str(key.def_id()) } arena_cache } @@ -1033,7 +1033,7 @@ rustc_queries! { } /// Obtain all the calls into other local functions - query mir_inliner_callees(key: ty::InstanceDef<'tcx>) -> &'tcx [(DefId, GenericArgsRef<'tcx>)] { + query mir_inliner_callees(key: ty::InstanceKind<'tcx>) -> &'tcx [(DefId, GenericArgsRef<'tcx>)] { fatal_cycle desc { |tcx| "computing all local function calls in `{}`", @@ -1140,7 +1140,7 @@ rustc_queries! { } /// Generates a MIR body for the shim. - query mir_shims(key: ty::InstanceDef<'tcx>) -> &'tcx mir::Body<'tcx> { + query mir_shims(key: ty::InstanceKind<'tcx>) -> &'tcx mir::Body<'tcx> { arena_cache desc { |tcx| "generating MIR shim for `{}`", tcx.def_path_str(key.def_id()) } } @@ -1410,7 +1410,7 @@ rustc_queries! { /// Compute a `FnAbi` suitable for indirect calls, i.e. to `fn` pointers. /// /// NB: this doesn't handle virtual calls - those should use `fn_abi_of_instance` - /// instead, where the instance is an `InstanceDef::Virtual`. + /// instead, where the instance is an `InstanceKind::Virtual`. query fn_abi_of_fn_ptr( key: ty::ParamEnvAnd<'tcx, (ty::PolyFnSig<'tcx>, &'tcx ty::List<Ty<'tcx>>)> ) -> Result<&'tcx abi::call::FnAbi<'tcx, Ty<'tcx>>, &'tcx ty::layout::FnAbiError<'tcx>> { @@ -1421,7 +1421,7 @@ rustc_queries! { /// direct calls to an `fn`. /// /// NB: that includes virtual calls, which are represented by "direct calls" - /// to an `InstanceDef::Virtual` instance (of `<dyn Trait as Trait>::fn`). + /// to an `InstanceKind::Virtual` instance (of `<dyn Trait as Trait>::fn`). query fn_abi_of_instance( key: ty::ParamEnvAnd<'tcx, (ty::Instance<'tcx>, &'tcx ty::List<Ty<'tcx>>)> ) -> Result<&'tcx abi::call::FnAbi<'tcx, Ty<'tcx>>, &'tcx ty::layout::FnAbiError<'tcx>> { @@ -1554,12 +1554,13 @@ rustc_queries! { } } - /// The entire set of monomorphizations the local crate can safely link - /// to because they are exported from upstream crates. Do not depend on - /// this directly, as its value changes anytime a monomorphization gets - /// added or removed in any upstream crate. Instead use the narrower - /// `upstream_monomorphizations_for`, `upstream_drop_glue_for`, or, even - /// better, `Instance::upstream_monomorphization()`. + /// The entire set of monomorphizations the local crate can safely + /// link to because they are exported from upstream crates. Do + /// not depend on this directly, as its value changes anytime + /// a monomorphization gets added or removed in any upstream + /// crate. Instead use the narrower `upstream_monomorphizations_for`, + /// `upstream_drop_glue_for`, `upstream_async_drop_glue_for`, or, + /// even better, `Instance::upstream_monomorphization()`. query upstream_monomorphizations(_: ()) -> &'tcx DefIdMap<UnordMap<GenericArgsRef<'tcx>, CrateNum>> { arena_cache desc { "collecting available upstream monomorphizations" } @@ -1601,6 +1602,26 @@ rustc_queries! { desc { "available upstream drop-glue for `{:?}`", args } } + /// Returns the upstream crate that exports async-drop-glue for + /// the given type (`args` is expected to be a single-item list + /// containing the type one wants async-drop-glue for). + /// + /// This is a subset of `upstream_monomorphizations_for` in order + /// to increase dep-tracking granularity. Otherwise adding or + /// removing any type with async-drop-glue in any upstream crate + /// would invalidate all functions calling async-drop-glue of an + /// upstream type. + /// + /// You likely want to call `Instance::upstream_monomorphization()` + /// instead of invoking this query directly. + /// + /// NOTE: This query could easily be extended to also support other + /// common functions that have are large set of monomorphizations + /// (like `Clone::clone` for example). + query upstream_async_drop_glue_for(args: GenericArgsRef<'tcx>) -> Option<CrateNum> { + desc { "available upstream async-drop-glue for `{:?}`", args } + } + /// Returns a list of all `extern` blocks of a crate. query foreign_modules(_: CrateNum) -> &'tcx FxIndexMap<DefId, ForeignModule> { arena_cache @@ -1918,7 +1939,7 @@ rustc_queries! { desc { "getting codegen unit `{sym}`" } } - query unused_generic_params(key: ty::InstanceDef<'tcx>) -> UnusedGenericParams { + query unused_generic_params(key: ty::InstanceKind<'tcx>) -> UnusedGenericParams { cache_on_disk_if { key.def_id().is_local() } desc { |tcx| "determining which generic parameters are unused by `{}`", diff --git a/compiler/rustc_middle/src/traits/mod.rs b/compiler/rustc_middle/src/traits/mod.rs index 202d587f0ad..b4e3fae1b43 100644 --- a/compiler/rustc_middle/src/traits/mod.rs +++ b/compiler/rustc_middle/src/traits/mod.rs @@ -32,54 +32,7 @@ use std::hash::{Hash, Hasher}; pub use self::select::{EvaluationCache, EvaluationResult, OverflowError, SelectionCache}; // FIXME: Remove this import and import via `solve::` -pub use rustc_type_ir::solve::BuiltinImplSource; - -/// Depending on the stage of compilation, we want projection to be -/// more or less conservative. -#[derive(Debug, Copy, Clone, PartialEq, Eq, Hash, HashStable, Encodable, Decodable)] -pub enum Reveal { - /// At type-checking time, we refuse to project any associated - /// type that is marked `default`. Non-`default` ("final") types - /// are always projected. This is necessary in general for - /// soundness of specialization. However, we *could* allow - /// projections in fully-monomorphic cases. We choose not to, - /// because we prefer for `default type` to force the type - /// definition to be treated abstractly by any consumers of the - /// impl. Concretely, that means that the following example will - /// fail to compile: - /// - /// ```compile_fail,E0308 - /// #![feature(specialization)] - /// trait Assoc { - /// type Output; - /// } - /// - /// impl<T> Assoc for T { - /// default type Output = bool; - /// } - /// - /// fn main() { - /// let x: <() as Assoc>::Output = true; - /// } - /// ``` - /// - /// We also do not reveal the hidden type of opaque types during - /// type-checking. - UserFacing, - - /// At codegen time, all monomorphic projections will succeed. - /// Also, `impl Trait` is normalized to the concrete type, - /// which has to be already collected by type-checking. - /// - /// NOTE: as `impl Trait`'s concrete type should *never* - /// be observable directly by the user, `Reveal::All` - /// should not be used by checks which may expose - /// type equality or type contents to the user. - /// There are some exceptions, e.g., around auto traits and - /// transmute-checking, which expose some details, but - /// not the whole concrete type of the `impl Trait`. - All, -} +pub use rustc_type_ir::solve::{BuiltinImplSource, Reveal}; /// The reason why we incurred this obligation; used for error reporting. /// diff --git a/compiler/rustc_middle/src/traits/solve.rs b/compiler/rustc_middle/src/traits/solve.rs index 0d9ce402c64..90f80f90767 100644 --- a/compiler/rustc_middle/src/traits/solve.rs +++ b/compiler/rustc_middle/src/traits/solve.rs @@ -1,17 +1,16 @@ use rustc_ast_ir::try_visit; use rustc_data_structures::intern::Interned; -use rustc_macros::{HashStable, TypeFoldable, TypeVisitable}; +use rustc_macros::HashStable; use rustc_type_ir as ir; pub use rustc_type_ir::solve::*; -use crate::infer::canonical::QueryRegionConstraints; use crate::ty::{ - self, FallibleTypeFolder, Ty, TyCtxt, TypeFoldable, TypeFolder, TypeVisitable, TypeVisitor, + self, FallibleTypeFolder, TyCtxt, TypeFoldable, TypeFolder, TypeVisitable, TypeVisitor, }; mod cache; -pub use cache::{CacheData, EvaluationCache}; +pub use cache::EvaluationCache; pub type Goal<'tcx, P> = ir::solve::Goal<TyCtxt<'tcx>, P>; pub type QueryInput<'tcx, P> = ir::solve::QueryInput<TyCtxt<'tcx>, P>; @@ -20,17 +19,11 @@ pub type CandidateSource<'tcx> = ir::solve::CandidateSource<TyCtxt<'tcx>>; pub type CanonicalInput<'tcx, P = ty::Predicate<'tcx>> = ir::solve::CanonicalInput<TyCtxt<'tcx>, P>; pub type CanonicalResponse<'tcx> = ir::solve::CanonicalResponse<TyCtxt<'tcx>>; -/// Additional constraints returned on success. -#[derive(Debug, PartialEq, Eq, Clone, Hash, HashStable, Default)] -pub struct PredefinedOpaquesData<'tcx> { - pub opaque_types: Vec<(ty::OpaqueTypeKey<'tcx>, Ty<'tcx>)>, -} - #[derive(Debug, PartialEq, Eq, Copy, Clone, Hash, HashStable)] -pub struct PredefinedOpaques<'tcx>(pub(crate) Interned<'tcx, PredefinedOpaquesData<'tcx>>); +pub struct PredefinedOpaques<'tcx>(pub(crate) Interned<'tcx, PredefinedOpaquesData<TyCtxt<'tcx>>>); impl<'tcx> std::ops::Deref for PredefinedOpaques<'tcx> { - type Target = PredefinedOpaquesData<'tcx>; + type Target = PredefinedOpaquesData<TyCtxt<'tcx>>; fn deref(&self) -> &Self::Target { &self.0 @@ -38,37 +31,18 @@ impl<'tcx> std::ops::Deref for PredefinedOpaques<'tcx> { } #[derive(Debug, PartialEq, Eq, Copy, Clone, Hash, HashStable)] -pub struct ExternalConstraints<'tcx>(pub(crate) Interned<'tcx, ExternalConstraintsData<'tcx>>); +pub struct ExternalConstraints<'tcx>( + pub(crate) Interned<'tcx, ExternalConstraintsData<TyCtxt<'tcx>>>, +); impl<'tcx> std::ops::Deref for ExternalConstraints<'tcx> { - type Target = ExternalConstraintsData<'tcx>; + type Target = ExternalConstraintsData<TyCtxt<'tcx>>; fn deref(&self) -> &Self::Target { &self.0 } } -/// Additional constraints returned on success. -#[derive(Debug, PartialEq, Eq, Clone, Hash, HashStable, Default, TypeVisitable, TypeFoldable)] -pub struct ExternalConstraintsData<'tcx> { - // FIXME: implement this. - pub region_constraints: QueryRegionConstraints<'tcx>, - pub opaque_types: Vec<(ty::OpaqueTypeKey<'tcx>, Ty<'tcx>)>, - pub normalization_nested_goals: NestedNormalizationGoals<'tcx>, -} - -#[derive(Debug, PartialEq, Eq, Clone, Hash, HashStable, Default, TypeVisitable, TypeFoldable)] -pub struct NestedNormalizationGoals<'tcx>(pub Vec<(GoalSource, Goal<'tcx, ty::Predicate<'tcx>>)>); -impl<'tcx> NestedNormalizationGoals<'tcx> { - pub fn empty() -> Self { - NestedNormalizationGoals(vec![]) - } - - pub fn is_empty(&self) -> bool { - self.0.is_empty() - } -} - // FIXME: Having to clone `region_constraints` for folding feels bad and // probably isn't great wrt performance. // diff --git a/compiler/rustc_middle/src/traits/solve/cache.rs b/compiler/rustc_middle/src/traits/solve/cache.rs index dc31114b2c4..72a8d4eb405 100644 --- a/compiler/rustc_middle/src/traits/solve/cache.rs +++ b/compiler/rustc_middle/src/traits/solve/cache.rs @@ -5,6 +5,8 @@ use rustc_data_structures::sync::Lock; use rustc_query_system::cache::WithDepNode; use rustc_query_system::dep_graph::DepNodeIndex; use rustc_session::Limit; +use rustc_type_ir::solve::CacheData; + /// The trait solver cache used by `-Znext-solver`. /// /// FIXME(@lcnr): link to some official documentation of how @@ -14,17 +16,9 @@ pub struct EvaluationCache<'tcx> { map: Lock<FxHashMap<CanonicalInput<'tcx>, CacheEntry<'tcx>>>, } -#[derive(Debug, PartialEq, Eq)] -pub struct CacheData<'tcx> { - pub result: QueryResult<'tcx>, - pub proof_tree: Option<&'tcx inspect::CanonicalGoalEvaluationStep<TyCtxt<'tcx>>>, - pub additional_depth: usize, - pub encountered_overflow: bool, -} - -impl<'tcx> EvaluationCache<'tcx> { +impl<'tcx> rustc_type_ir::inherent::EvaluationCache<TyCtxt<'tcx>> for &'tcx EvaluationCache<'tcx> { /// Insert a final result into the global cache. - pub fn insert( + fn insert( &self, tcx: TyCtxt<'tcx>, key: CanonicalInput<'tcx>, @@ -48,7 +42,7 @@ impl<'tcx> EvaluationCache<'tcx> { if cfg!(debug_assertions) { drop(map); let expected = CacheData { result, proof_tree, additional_depth, encountered_overflow }; - let actual = self.get(tcx, key, [], Limit(additional_depth)); + let actual = self.get(tcx, key, [], additional_depth); if !actual.as_ref().is_some_and(|actual| expected == *actual) { bug!("failed to lookup inserted element for {key:?}: {expected:?} != {actual:?}"); } @@ -59,13 +53,13 @@ impl<'tcx> EvaluationCache<'tcx> { /// and handling root goals of coinductive cycles. /// /// If this returns `Some` the cache result can be used. - pub fn get( + fn get( &self, tcx: TyCtxt<'tcx>, key: CanonicalInput<'tcx>, stack_entries: impl IntoIterator<Item = CanonicalInput<'tcx>>, - available_depth: Limit, - ) -> Option<CacheData<'tcx>> { + available_depth: usize, + ) -> Option<CacheData<TyCtxt<'tcx>>> { let map = self.map.borrow(); let entry = map.get(&key)?; @@ -76,7 +70,7 @@ impl<'tcx> EvaluationCache<'tcx> { } if let Some(ref success) = entry.success { - if available_depth.value_within_limit(success.additional_depth) { + if Limit(available_depth).value_within_limit(success.additional_depth) { let QueryData { result, proof_tree } = success.data.get(tcx); return Some(CacheData { result, @@ -87,12 +81,12 @@ impl<'tcx> EvaluationCache<'tcx> { } } - entry.with_overflow.get(&available_depth.0).map(|e| { + entry.with_overflow.get(&available_depth).map(|e| { let QueryData { result, proof_tree } = e.get(tcx); CacheData { result, proof_tree, - additional_depth: available_depth.0, + additional_depth: available_depth, encountered_overflow: true, } }) diff --git a/compiler/rustc_middle/src/ty/adt.rs b/compiler/rustc_middle/src/ty/adt.rs index 684b3233cfd..8e221cdc603 100644 --- a/compiler/rustc_middle/src/ty/adt.rs +++ b/compiler/rustc_middle/src/ty/adt.rs @@ -205,6 +205,14 @@ impl<'tcx> rustc_type_ir::inherent::AdtDef<TyCtxt<'tcx>> for AdtDef<'tcx> { self.did() } + fn is_struct(self) -> bool { + self.is_struct() + } + + fn struct_tail_ty(self, interner: TyCtxt<'tcx>) -> Option<ty::EarlyBinder<'tcx, Ty<'tcx>>> { + Some(interner.type_of(self.non_enum_variant().tail_opt()?.did)) + } + fn is_phantom_data(self) -> bool { self.is_phantom_data() } @@ -212,7 +220,7 @@ impl<'tcx> rustc_type_ir::inherent::AdtDef<TyCtxt<'tcx>> for AdtDef<'tcx> { fn all_field_tys( self, tcx: TyCtxt<'tcx>, - ) -> ty::EarlyBinder<'tcx, impl Iterator<Item = Ty<'tcx>>> { + ) -> ty::EarlyBinder<'tcx, impl IntoIterator<Item = Ty<'tcx>>> { ty::EarlyBinder::bind( self.all_fields().map(move |field| tcx.type_of(field.did).skip_binder()), ) diff --git a/compiler/rustc_middle/src/ty/consts.rs b/compiler/rustc_middle/src/ty/consts.rs index 12f0c38b054..32d01d07c17 100644 --- a/compiler/rustc_middle/src/ty/consts.rs +++ b/compiler/rustc_middle/src/ty/consts.rs @@ -16,8 +16,8 @@ mod valtree; pub use int::*; pub use kind::*; -use rustc_span::Span; use rustc_span::DUMMY_SP; +use rustc_span::{ErrorGuaranteed, Span}; pub use valtree::*; pub type ConstKind<'tcx> = ir::ConstKind<TyCtxt<'tcx>>; @@ -176,6 +176,10 @@ impl<'tcx> rustc_type_ir::inherent::Const<TyCtxt<'tcx>> for Const<'tcx> { fn new_expr(interner: TyCtxt<'tcx>, expr: ty::Expr<'tcx>) -> Self { Const::new_expr(interner, expr) } + + fn new_error(interner: TyCtxt<'tcx>, guar: ErrorGuaranteed) -> Self { + Const::new_error(interner, guar) + } } impl<'tcx> Const<'tcx> { diff --git a/compiler/rustc_middle/src/ty/context.rs b/compiler/rustc_middle/src/ty/context.rs index 3651c990c97..6d64c1d50ae 100644 --- a/compiler/rustc_middle/src/ty/context.rs +++ b/compiler/rustc_middle/src/ty/context.rs @@ -47,7 +47,9 @@ use rustc_data_structures::sync::{self, FreezeReadGuard, Lock, Lrc, RwLock, Work #[cfg(parallel_compiler)] use rustc_data_structures::sync::{DynSend, DynSync}; use rustc_data_structures::unord::UnordSet; -use rustc_errors::{Applicability, Diag, DiagCtxt, ErrorGuaranteed, LintDiagnostic, MultiSpan}; +use rustc_errors::{ + Applicability, Diag, DiagCtxtHandle, ErrorGuaranteed, LintDiagnostic, MultiSpan, +}; use rustc_hir as hir; use rustc_hir::def::DefKind; use rustc_hir::def_id::{CrateNum, DefId, LocalDefId, LOCAL_CRATE}; @@ -71,6 +73,7 @@ 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::solve::SolverMode; use rustc_type_ir::TyKind::*; use rustc_type_ir::{CollectAndApply, Interner, TypeFlags, WithCachedTypeInfo}; use tracing::{debug, instrument}; @@ -88,46 +91,66 @@ use std::ops::{Bound, Deref}; #[allow(rustc::usage_of_ty_tykind)] impl<'tcx> Interner for TyCtxt<'tcx> { type DefId = DefId; - type AdtDef = ty::AdtDef<'tcx>; - + type LocalDefId = LocalDefId; type GenericArgs = ty::GenericArgsRef<'tcx>; + type GenericArgsSlice = &'tcx [ty::GenericArg<'tcx>]; type GenericArg = ty::GenericArg<'tcx>; type Term = ty::Term<'tcx>; - type BoundVarKinds = &'tcx List<ty::BoundVariableKind>; - type BoundVarKind = ty::BoundVariableKind; - type CanonicalVars = CanonicalVarInfos<'tcx>; + type BoundVarKind = ty::BoundVariableKind; type PredefinedOpaques = solve::PredefinedOpaques<'tcx>; + + fn mk_predefined_opaques_in_body( + self, + data: PredefinedOpaquesData<Self>, + ) -> Self::PredefinedOpaques { + self.mk_predefined_opaques_in_body(data) + } type DefiningOpaqueTypes = &'tcx ty::List<LocalDefId>; - type ExternalConstraints = ExternalConstraints<'tcx>; type CanonicalGoalEvaluationStepRef = &'tcx solve::inspect::CanonicalGoalEvaluationStep<TyCtxt<'tcx>>; + type CanonicalVars = CanonicalVarInfos<'tcx>; + fn mk_canonical_var_infos(self, infos: &[ty::CanonicalVarInfo<Self>]) -> Self::CanonicalVars { + self.mk_canonical_var_infos(infos) + } + type ExternalConstraints = ExternalConstraints<'tcx>; + fn mk_external_constraints( + self, + data: ExternalConstraintsData<Self>, + ) -> ExternalConstraints<'tcx> { + self.mk_external_constraints(data) + } + type DepNodeIndex = DepNodeIndex; + fn with_cached_task<T>(self, task: impl FnOnce() -> T) -> (T, DepNodeIndex) { + self.dep_graph.with_anon_task(self, crate::dep_graph::dep_kinds::TraitSelect, task) + } type Ty = Ty<'tcx>; type Tys = &'tcx List<Ty<'tcx>>; + type FnInputTys = &'tcx [Ty<'tcx>]; type ParamTy = ParamTy; type BoundTy = ty::BoundTy; - type PlaceholderTy = ty::PlaceholderType; + type PlaceholderTy = ty::PlaceholderType; type ErrorGuaranteed = ErrorGuaranteed; type BoundExistentialPredicates = &'tcx List<PolyExistentialPredicate<'tcx>>; - type AllocId = crate::mir::interpret::AllocId; + type AllocId = crate::mir::interpret::AllocId; type Pat = Pattern<'tcx>; type Safety = hir::Safety; type Abi = abi::Abi; - type Const = ty::Const<'tcx>; type PlaceholderConst = ty::PlaceholderConst; + type ParamConst = ty::ParamConst; type BoundConst = ty::BoundVar; type ValueConst = ty::ValTree<'tcx>; type ExprConst = ty::Expr<'tcx>; - type Region = Region<'tcx>; + type EarlyParamRegion = ty::EarlyParamRegion; type LateParamRegion = ty::LateParamRegion; type BoundRegion = ty::BoundRegion; @@ -135,15 +158,21 @@ impl<'tcx> Interner for TyCtxt<'tcx> { type ParamEnv = ty::ParamEnv<'tcx>; type Predicate = Predicate<'tcx>; + type Clause = Clause<'tcx>; type Clauses = ty::Clauses<'tcx>; - fn expand_abstract_consts<T: TypeFoldable<TyCtxt<'tcx>>>(self, t: T) -> T { - self.expand_abstract_consts(t) + type EvaluationCache = &'tcx solve::EvaluationCache<'tcx>; + + fn evaluation_cache(self, mode: SolverMode) -> &'tcx solve::EvaluationCache<'tcx> { + match mode { + SolverMode::Normal => &self.new_solver_evaluation_cache, + SolverMode::Coherence => &self.new_solver_coherence_evaluation_cache, + } } - fn mk_canonical_var_infos(self, infos: &[ty::CanonicalVarInfo<Self>]) -> Self::CanonicalVars { - self.mk_canonical_var_infos(infos) + fn expand_abstract_consts<T: TypeFoldable<TyCtxt<'tcx>>>(self, t: T) -> T { + self.expand_abstract_consts(t) } type GenericsOf = &'tcx ty::Generics; @@ -162,6 +191,11 @@ impl<'tcx> Interner for TyCtxt<'tcx> { self.type_of(def_id) } + type AdtDef = ty::AdtDef<'tcx>; + fn adt_def(self, adt_def_id: DefId) -> Self::AdtDef { + self.adt_def(adt_def_id) + } + fn alias_ty_kind(self, alias: ty::AliasTy<'tcx>) -> ty::AliasTyKind { match self.def_kind(alias.def_id) { DefKind::AssocTy => { @@ -199,8 +233,8 @@ impl<'tcx> Interner for TyCtxt<'tcx> { fn trait_ref_and_own_args_for_alias( self, def_id: DefId, - args: Self::GenericArgs, - ) -> (rustc_type_ir::TraitRef<Self>, Self::GenericArgsSlice) { + args: ty::GenericArgsRef<'tcx>, + ) -> (ty::TraitRef<'tcx>, &'tcx [ty::GenericArg<'tcx>]) { assert_matches!(self.def_kind(def_id), DefKind::AssocTy | DefKind::AssocConst); let trait_def_id = self.parent(def_id); assert_matches!(self.def_kind(trait_def_id), DefKind::Trait); @@ -211,18 +245,22 @@ impl<'tcx> Interner for TyCtxt<'tcx> { ) } - fn mk_args(self, args: &[Self::GenericArg]) -> Self::GenericArgs { + fn mk_args(self, args: &[Self::GenericArg]) -> ty::GenericArgsRef<'tcx> { self.mk_args(args) } fn mk_args_from_iter<I, T>(self, args: I) -> T::Output where I: Iterator<Item = T>, - T: CollectAndApply<Self::GenericArg, Self::GenericArgs>, + T: CollectAndApply<Self::GenericArg, ty::GenericArgsRef<'tcx>>, { self.mk_args_from_iter(args) } + fn check_args_compatible(self, def_id: DefId, args: ty::GenericArgsRef<'tcx>) -> bool { + self.check_args_compatible(def_id, args) + } + fn check_and_mk_args( self, def_id: DefId, @@ -241,7 +279,7 @@ impl<'tcx> Interner for TyCtxt<'tcx> { fn mk_type_list_from_iter<I, T>(self, args: I) -> T::Output where I: Iterator<Item = T>, - T: CollectAndApply<Self::Ty, Self::Tys>, + T: CollectAndApply<Ty<'tcx>, &'tcx List<Ty<'tcx>>>, { self.mk_type_list_from_iter(args) } @@ -290,6 +328,24 @@ impl<'tcx> Interner for TyCtxt<'tcx> { self.item_bounds(def_id).map_bound(IntoIterator::into_iter) } + fn predicates_of( + self, + def_id: DefId, + ) -> ty::EarlyBinder<'tcx, impl IntoIterator<Item = ty::Clause<'tcx>>> { + ty::EarlyBinder::bind( + self.predicates_of(def_id).instantiate_identity(self).predicates.into_iter(), + ) + } + + fn own_predicates_of( + self, + def_id: DefId, + ) -> ty::EarlyBinder<'tcx, impl IntoIterator<Item = ty::Clause<'tcx>>> { + ty::EarlyBinder::bind( + self.predicates_of(def_id).instantiate_own_identity().map(|(clause, _)| clause), + ) + } + fn super_predicates_of( self, def_id: DefId, @@ -304,15 +360,11 @@ impl<'tcx> Interner for TyCtxt<'tcx> { } 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, - ) + self.require_lang_item(trait_lang_item_to_lang_item(lang_item), None) + } + + fn is_lang_item(self, def_id: DefId, lang_item: TraitSolverLangItem) -> bool { + self.is_lang_item(def_id, trait_lang_item_to_lang_item(lang_item)) } fn associated_type_def_ids(self, def_id: DefId) -> impl IntoIterator<Item = DefId> { @@ -321,6 +373,257 @@ impl<'tcx> Interner for TyCtxt<'tcx> { .filter(|assoc_item| matches!(assoc_item.kind, ty::AssocKind::Type)) .map(|assoc_item| assoc_item.def_id) } + + fn args_may_unify_deep( + self, + obligation_args: ty::GenericArgsRef<'tcx>, + impl_args: ty::GenericArgsRef<'tcx>, + ) -> bool { + ty::fast_reject::DeepRejectCtxt { + treat_obligation_params: ty::fast_reject::TreatParams::ForLookup, + } + .args_may_unify(obligation_args, impl_args) + } + + // This implementation is a bit different from `TyCtxt::for_each_relevant_impl`, + // since we want to skip over blanket impls for non-rigid aliases, and also we + // only want to consider types that *actually* unify with float/int vars. + fn for_each_relevant_impl( + self, + trait_def_id: DefId, + self_ty: Ty<'tcx>, + mut f: impl FnMut(DefId), + ) { + let tcx = self; + let trait_impls = tcx.trait_impls_of(trait_def_id); + let mut consider_impls_for_simplified_type = |simp| { + if let Some(impls_for_type) = trait_impls.non_blanket_impls().get(&simp) { + for &impl_def_id in impls_for_type { + f(impl_def_id); + } + } + }; + + match self_ty.kind() { + ty::Bool + | ty::Char + | ty::Int(_) + | ty::Uint(_) + | ty::Float(_) + | ty::Adt(_, _) + | ty::Foreign(_) + | ty::Str + | ty::Array(_, _) + | ty::Pat(_, _) + | ty::Slice(_) + | ty::RawPtr(_, _) + | ty::Ref(_, _, _) + | ty::FnDef(_, _) + | ty::FnPtr(_) + | ty::Dynamic(_, _, _) + | ty::Closure(..) + | ty::CoroutineClosure(..) + | ty::Coroutine(_, _) + | ty::Never + | ty::Tuple(_) => { + let simp = ty::fast_reject::simplify_type( + tcx, + self_ty, + ty::fast_reject::TreatParams::ForLookup, + ) + .unwrap(); + consider_impls_for_simplified_type(simp); + } + + // HACK: For integer and float variables we have to manually look at all impls + // which have some integer or float as a self type. + ty::Infer(ty::IntVar(_)) => { + use ty::IntTy::*; + use ty::UintTy::*; + // This causes a compiler error if any new integer kinds are added. + let (I8 | I16 | I32 | I64 | I128 | Isize): ty::IntTy; + let (U8 | U16 | U32 | U64 | U128 | Usize): ty::UintTy; + let possible_integers = [ + // signed integers + ty::SimplifiedType::Int(I8), + ty::SimplifiedType::Int(I16), + ty::SimplifiedType::Int(I32), + ty::SimplifiedType::Int(I64), + ty::SimplifiedType::Int(I128), + ty::SimplifiedType::Int(Isize), + // unsigned integers + ty::SimplifiedType::Uint(U8), + ty::SimplifiedType::Uint(U16), + ty::SimplifiedType::Uint(U32), + ty::SimplifiedType::Uint(U64), + ty::SimplifiedType::Uint(U128), + ty::SimplifiedType::Uint(Usize), + ]; + for simp in possible_integers { + consider_impls_for_simplified_type(simp); + } + } + + ty::Infer(ty::FloatVar(_)) => { + // This causes a compiler error if any new float kinds are added. + let (ty::FloatTy::F16 | ty::FloatTy::F32 | ty::FloatTy::F64 | ty::FloatTy::F128); + let possible_floats = [ + ty::SimplifiedType::Float(ty::FloatTy::F16), + ty::SimplifiedType::Float(ty::FloatTy::F32), + ty::SimplifiedType::Float(ty::FloatTy::F64), + ty::SimplifiedType::Float(ty::FloatTy::F128), + ]; + + for simp in possible_floats { + consider_impls_for_simplified_type(simp); + } + } + + // The only traits applying to aliases and placeholders are blanket impls. + // + // Impls which apply to an alias after normalization are handled by + // `assemble_candidates_after_normalizing_self_ty`. + ty::Alias(_, _) | ty::Placeholder(..) | ty::Error(_) => (), + + // FIXME: These should ideally not exist as a self type. It would be nice for + // the builtin auto trait impls of coroutines to instead directly recurse + // into the witness. + ty::CoroutineWitness(..) => (), + + // These variants should not exist as a self type. + ty::Infer(ty::TyVar(_) | ty::FreshTy(_) | ty::FreshIntTy(_) | ty::FreshFloatTy(_)) + | ty::Param(_) + | ty::Bound(_, _) => bug!("unexpected self type: {self_ty}"), + } + + let trait_impls = tcx.trait_impls_of(trait_def_id); + for &impl_def_id in trait_impls.blanket_impls() { + f(impl_def_id); + } + } + + fn has_item_definition(self, def_id: DefId) -> bool { + self.defaultness(def_id).has_value() + } + + fn impl_is_default(self, impl_def_id: DefId) -> bool { + self.defaultness(impl_def_id).is_default() + } + + fn impl_trait_ref(self, impl_def_id: DefId) -> ty::EarlyBinder<'tcx, ty::TraitRef<'tcx>> { + self.impl_trait_ref(impl_def_id).unwrap() + } + + fn impl_polarity(self, impl_def_id: DefId) -> ty::ImplPolarity { + self.impl_polarity(impl_def_id) + } + + fn trait_is_auto(self, trait_def_id: DefId) -> bool { + self.trait_is_auto(trait_def_id) + } + + fn trait_is_alias(self, trait_def_id: DefId) -> bool { + self.trait_is_alias(trait_def_id) + } + + fn trait_is_object_safe(self, trait_def_id: DefId) -> bool { + self.is_object_safe(trait_def_id) + } + + fn trait_may_be_implemented_via_object(self, trait_def_id: DefId) -> bool { + self.trait_def(trait_def_id).implement_via_object + } + + fn fn_trait_kind_from_def_id(self, trait_def_id: DefId) -> Option<ty::ClosureKind> { + self.fn_trait_kind_from_def_id(trait_def_id) + } + + fn async_fn_trait_kind_from_def_id(self, trait_def_id: DefId) -> Option<ty::ClosureKind> { + self.async_fn_trait_kind_from_def_id(trait_def_id) + } + + fn supertrait_def_ids(self, trait_def_id: DefId) -> impl IntoIterator<Item = DefId> { + self.supertrait_def_ids(trait_def_id) + } + + fn delay_bug(self, msg: impl ToString) -> ErrorGuaranteed { + self.dcx().span_delayed_bug(DUMMY_SP, msg.to_string()) + } + + fn is_general_coroutine(self, coroutine_def_id: DefId) -> bool { + self.is_general_coroutine(coroutine_def_id) + } + + fn coroutine_is_async(self, coroutine_def_id: DefId) -> bool { + self.coroutine_is_async(coroutine_def_id) + } + + fn coroutine_is_gen(self, coroutine_def_id: DefId) -> bool { + self.coroutine_is_gen(coroutine_def_id) + } + + fn coroutine_is_async_gen(self, coroutine_def_id: DefId) -> bool { + self.coroutine_is_async_gen(coroutine_def_id) + } + + fn layout_is_pointer_like(self, param_env: ty::ParamEnv<'tcx>, ty: Ty<'tcx>) -> bool { + self.layout_of(self.erase_regions(param_env.and(ty))) + .is_ok_and(|layout| layout.layout.is_pointer_like(&self.data_layout)) + } + + type UnsizingParams = &'tcx rustc_index::bit_set::BitSet<u32>; + fn unsizing_params_for_adt(self, adt_def_id: DefId) -> Self::UnsizingParams { + self.unsizing_params_for_adt(adt_def_id) + } + + fn find_const_ty_from_env( + self, + param_env: ty::ParamEnv<'tcx>, + placeholder: Self::PlaceholderConst, + ) -> Ty<'tcx> { + placeholder.find_const_ty_from_env(param_env) + } +} + +fn trait_lang_item_to_lang_item(lang_item: TraitSolverLangItem) -> LangItem { + match lang_item { + TraitSolverLangItem::AsyncDestruct => LangItem::AsyncDestruct, + TraitSolverLangItem::AsyncFnKindHelper => LangItem::AsyncFnKindHelper, + TraitSolverLangItem::AsyncFnKindUpvars => LangItem::AsyncFnKindUpvars, + TraitSolverLangItem::AsyncFnOnceOutput => LangItem::AsyncFnOnceOutput, + TraitSolverLangItem::AsyncIterator => LangItem::AsyncIterator, + TraitSolverLangItem::CallOnceFuture => LangItem::CallOnceFuture, + TraitSolverLangItem::CallRefFuture => LangItem::CallRefFuture, + TraitSolverLangItem::Clone => LangItem::Clone, + TraitSolverLangItem::Copy => LangItem::Copy, + TraitSolverLangItem::Coroutine => LangItem::Coroutine, + TraitSolverLangItem::CoroutineReturn => LangItem::CoroutineReturn, + TraitSolverLangItem::CoroutineYield => LangItem::CoroutineYield, + TraitSolverLangItem::Destruct => LangItem::Destruct, + TraitSolverLangItem::DiscriminantKind => LangItem::DiscriminantKind, + TraitSolverLangItem::DynMetadata => LangItem::DynMetadata, + TraitSolverLangItem::FnPtrTrait => LangItem::FnPtrTrait, + TraitSolverLangItem::FusedIterator => LangItem::FusedIterator, + TraitSolverLangItem::Future => LangItem::Future, + TraitSolverLangItem::FutureOutput => LangItem::FutureOutput, + TraitSolverLangItem::Iterator => LangItem::Iterator, + TraitSolverLangItem::Metadata => LangItem::Metadata, + TraitSolverLangItem::Option => LangItem::Option, + TraitSolverLangItem::PointeeTrait => LangItem::PointeeTrait, + TraitSolverLangItem::PointerLike => LangItem::PointerLike, + TraitSolverLangItem::Poll => LangItem::Poll, + TraitSolverLangItem::Sized => LangItem::Sized, + TraitSolverLangItem::TransmuteTrait => LangItem::TransmuteTrait, + TraitSolverLangItem::Tuple => LangItem::Tuple, + TraitSolverLangItem::Unpin => LangItem::Unpin, + TraitSolverLangItem::Unsize => LangItem::Unsize, + } +} + +impl<'tcx> rustc_type_ir::inherent::DefId<TyCtxt<'tcx>> for DefId { + fn as_local(self) -> Option<LocalDefId> { + self.as_local() + } } impl<'tcx> rustc_type_ir::inherent::Abi<TyCtxt<'tcx>> for abi::Abi { @@ -355,6 +658,10 @@ impl<'tcx> rustc_type_ir::inherent::Features<TyCtxt<'tcx>> for &'tcx rustc_featu fn coroutine_clone(self) -> bool { self.coroutine_clone } + + fn associated_const_equality(self) -> bool { + self.associated_const_equality + } } type InternedSet<'tcx, T> = ShardedHashMap<InternedInSet<'tcx, T>, ()>; @@ -382,8 +689,8 @@ pub struct CtxtInterners<'tcx> { bound_variable_kinds: InternedSet<'tcx, List<ty::BoundVariableKind>>, layout: InternedSet<'tcx, LayoutS<FieldIdx, VariantIdx>>, adt_def: InternedSet<'tcx, AdtDefData>, - external_constraints: InternedSet<'tcx, ExternalConstraintsData<'tcx>>, - predefined_opaques_in_body: InternedSet<'tcx, PredefinedOpaquesData<'tcx>>, + external_constraints: InternedSet<'tcx, ExternalConstraintsData<TyCtxt<'tcx>>>, + predefined_opaques_in_body: InternedSet<'tcx, PredefinedOpaquesData<TyCtxt<'tcx>>>, fields: InternedSet<'tcx, List<FieldIdx>>, local_def_ids: InternedSet<'tcx, List<LocalDefId>>, captures: InternedSet<'tcx, List<&'tcx ty::CapturedPlace<'tcx>>>, @@ -1414,7 +1721,7 @@ impl<'tcx> TyCtxt<'tcx> { ) } - pub fn dcx(self) -> &'tcx DiagCtxt { + pub fn dcx(self) -> DiagCtxtHandle<'tcx> { self.sess.dcx() } } @@ -2093,9 +2400,9 @@ direct_interners! { const_allocation: pub mk_const_alloc(Allocation): ConstAllocation -> ConstAllocation<'tcx>, layout: pub mk_layout(LayoutS<FieldIdx, VariantIdx>): Layout -> Layout<'tcx>, adt_def: pub mk_adt_def_from_data(AdtDefData): AdtDef -> AdtDef<'tcx>, - external_constraints: pub mk_external_constraints(ExternalConstraintsData<'tcx>): + external_constraints: pub mk_external_constraints(ExternalConstraintsData<TyCtxt<'tcx>>): ExternalConstraints -> ExternalConstraints<'tcx>, - predefined_opaques_in_body: pub mk_predefined_opaques_in_body(PredefinedOpaquesData<'tcx>): + predefined_opaques_in_body: pub mk_predefined_opaques_in_body(PredefinedOpaquesData<TyCtxt<'tcx>>): PredefinedOpaques -> PredefinedOpaques<'tcx>, } diff --git a/compiler/rustc_middle/src/ty/generic_args.rs b/compiler/rustc_middle/src/ty/generic_args.rs index 54c88e48614..83d45ca78d9 100644 --- a/compiler/rustc_middle/src/ty/generic_args.rs +++ b/compiler/rustc_middle/src/ty/generic_args.rs @@ -44,10 +44,27 @@ pub struct GenericArg<'tcx> { impl<'tcx> rustc_type_ir::inherent::GenericArg<TyCtxt<'tcx>> for GenericArg<'tcx> {} impl<'tcx> rustc_type_ir::inherent::GenericArgs<TyCtxt<'tcx>> for ty::GenericArgsRef<'tcx> { + fn rebase_onto( + self, + tcx: TyCtxt<'tcx>, + source_ancestor: DefId, + target_args: GenericArgsRef<'tcx>, + ) -> GenericArgsRef<'tcx> { + self.rebase_onto(tcx, source_ancestor, target_args) + } + fn type_at(self, i: usize) -> Ty<'tcx> { self.type_at(i) } + fn region_at(self, i: usize) -> ty::Region<'tcx> { + self.region_at(i) + } + + fn const_at(self, i: usize) -> ty::Const<'tcx> { + self.const_at(i) + } + fn identity_for_item(tcx: TyCtxt<'tcx>, def_id: DefId) -> ty::GenericArgsRef<'tcx> { GenericArgs::identity_for_item(tcx, def_id) } @@ -281,6 +298,7 @@ impl<'tcx> GenericArg<'tcx> { pub fn is_non_region_infer(self) -> bool { match self.unpack() { GenericArgKind::Lifetime(_) => false, + // FIXME: This shouldn't return numerical/float. GenericArgKind::Type(ty) => ty.is_ty_or_numeric_infer(), GenericArgKind::Const(ct) => ct.is_ct_infer(), } diff --git a/compiler/rustc_middle/src/ty/generics.rs b/compiler/rustc_middle/src/ty/generics.rs index 185dbe44735..6467689a8aa 100644 --- a/compiler/rustc_middle/src/ty/generics.rs +++ b/compiler/rustc_middle/src/ty/generics.rs @@ -392,6 +392,10 @@ impl<'tcx> GenericPredicates<'tcx> { EarlyBinder::bind(self.predicates).iter_instantiated_copied(tcx, args) } + pub fn instantiate_own_identity(&self) -> impl Iterator<Item = (Clause<'tcx>, Span)> { + EarlyBinder::bind(self.predicates).instantiate_identity_iter_copied() + } + #[instrument(level = "debug", skip(self, tcx))] fn instantiate_into( &self, diff --git a/compiler/rustc_middle/src/ty/instance.rs b/compiler/rustc_middle/src/ty/instance.rs index bdf90cbb25b..efaf9c7231b 100644 --- a/compiler/rustc_middle/src/ty/instance.rs +++ b/compiler/rustc_middle/src/ty/instance.rs @@ -19,10 +19,10 @@ use tracing::{debug, instrument}; use std::assert_matches::assert_matches; use std::fmt; -/// A monomorphized `InstanceDef`. +/// An `InstanceKind` along with the args that are needed to substitute the instance. /// /// Monomorphization happens on-the-fly and no monomorphized MIR is ever created. Instead, this type -/// simply couples a potentially generic `InstanceDef` with some args, and codegen and const eval +/// simply couples a potentially generic `InstanceKind` with some args, and codegen and const eval /// will do all required instantiations as they run. /// /// Note: the `Lift` impl is currently not used by rustc, but is used by @@ -30,7 +30,7 @@ use std::fmt; #[derive(Copy, Clone, PartialEq, Eq, Hash, Debug, TyEncodable, TyDecodable)] #[derive(HashStable, Lift, TypeFoldable, TypeVisitable)] pub struct Instance<'tcx> { - pub def: InstanceDef<'tcx>, + pub def: InstanceKind<'tcx>, pub args: GenericArgsRef<'tcx>, } @@ -58,7 +58,7 @@ pub enum ReifyReason { #[derive(Copy, Clone, PartialEq, Eq, Hash, Debug)] #[derive(TyEncodable, TyDecodable, HashStable, TypeFoldable, TypeVisitable, Lift)] -pub enum InstanceDef<'tcx> { +pub enum InstanceKind<'tcx> { /// A user-defined callable item. /// /// This includes: @@ -69,7 +69,7 @@ pub enum InstanceDef<'tcx> { /// An intrinsic `fn` item (with `"rust-intrinsic"` or `"platform-intrinsic"` ABI). /// - /// Alongside `Virtual`, this is the only `InstanceDef` that does not have its own callable MIR. + /// Alongside `Virtual`, this is the only `InstanceKind` that does not have its own callable MIR. /// Instead, codegen and const eval "magically" evaluate calls to intrinsics purely in the /// caller. Intrinsic(DefId), @@ -85,7 +85,7 @@ pub enum InstanceDef<'tcx> { /// /// One example is `<dyn Trait as Trait>::fn`, where the shim contains /// a virtual call, which codegen supports only via a direct call to the - /// `<dyn Trait as Trait>::fn` instance (an `InstanceDef::Virtual`). + /// `<dyn Trait as Trait>::fn` instance (an `InstanceKind::Virtual`). /// /// Another example is functions annotated with `#[track_caller]`, which /// must have their implicit caller location argument populated for a call. @@ -107,7 +107,7 @@ pub enum InstanceDef<'tcx> { /// Dynamic dispatch to `<dyn Trait as Trait>::fn`. /// - /// This `InstanceDef` does not have callable MIR. Calls to `Virtual` instances must be + /// This `InstanceKind` does not have callable MIR. Calls to `Virtual` instances must be /// codegen'd as virtual calls through the vtable. /// /// If this is reified to a `fn` pointer, a `ReifyShim` is used (see `ReifyShim` above for more @@ -216,59 +216,61 @@ impl<'tcx> Instance<'tcx> { } match self.def { - InstanceDef::Item(def) => tcx + InstanceKind::Item(def) => tcx .upstream_monomorphizations_for(def) .and_then(|monos| monos.get(&self.args).cloned()), - InstanceDef::DropGlue(_, Some(_)) | InstanceDef::AsyncDropGlueCtorShim(_, _) => { - tcx.upstream_drop_glue_for(self.args) + InstanceKind::DropGlue(_, Some(_)) => tcx.upstream_drop_glue_for(self.args), + InstanceKind::AsyncDropGlueCtorShim(_, Some(_)) => { + tcx.upstream_async_drop_glue_for(self.args) } _ => None, } } } -impl<'tcx> InstanceDef<'tcx> { +impl<'tcx> InstanceKind<'tcx> { #[inline] pub fn def_id(self) -> DefId { match self { - InstanceDef::Item(def_id) - | InstanceDef::VTableShim(def_id) - | InstanceDef::ReifyShim(def_id, _) - | InstanceDef::FnPtrShim(def_id, _) - | InstanceDef::Virtual(def_id, _) - | InstanceDef::Intrinsic(def_id) - | InstanceDef::ThreadLocalShim(def_id) - | InstanceDef::ClosureOnceShim { call_once: def_id, track_caller: _ } - | ty::InstanceDef::ConstructCoroutineInClosureShim { + InstanceKind::Item(def_id) + | InstanceKind::VTableShim(def_id) + | InstanceKind::ReifyShim(def_id, _) + | InstanceKind::FnPtrShim(def_id, _) + | InstanceKind::Virtual(def_id, _) + | InstanceKind::Intrinsic(def_id) + | InstanceKind::ThreadLocalShim(def_id) + | InstanceKind::ClosureOnceShim { call_once: def_id, track_caller: _ } + | ty::InstanceKind::ConstructCoroutineInClosureShim { coroutine_closure_def_id: def_id, receiver_by_ref: _, } - | ty::InstanceDef::CoroutineKindShim { coroutine_def_id: def_id } - | InstanceDef::DropGlue(def_id, _) - | InstanceDef::CloneShim(def_id, _) - | InstanceDef::FnPtrAddrShim(def_id, _) - | InstanceDef::AsyncDropGlueCtorShim(def_id, _) => def_id, + | ty::InstanceKind::CoroutineKindShim { coroutine_def_id: def_id } + | InstanceKind::DropGlue(def_id, _) + | InstanceKind::CloneShim(def_id, _) + | InstanceKind::FnPtrAddrShim(def_id, _) + | InstanceKind::AsyncDropGlueCtorShim(def_id, _) => def_id, } } /// Returns the `DefId` of instances which might not require codegen locally. pub fn def_id_if_not_guaranteed_local_codegen(self) -> Option<DefId> { match self { - ty::InstanceDef::Item(def) => Some(def), - ty::InstanceDef::DropGlue(def_id, Some(_)) - | InstanceDef::AsyncDropGlueCtorShim(def_id, _) - | InstanceDef::ThreadLocalShim(def_id) => Some(def_id), - InstanceDef::VTableShim(..) - | InstanceDef::ReifyShim(..) - | InstanceDef::FnPtrShim(..) - | InstanceDef::Virtual(..) - | InstanceDef::Intrinsic(..) - | InstanceDef::ClosureOnceShim { .. } - | ty::InstanceDef::ConstructCoroutineInClosureShim { .. } - | ty::InstanceDef::CoroutineKindShim { .. } - | InstanceDef::DropGlue(..) - | InstanceDef::CloneShim(..) - | InstanceDef::FnPtrAddrShim(..) => None, + ty::InstanceKind::Item(def) => Some(def), + ty::InstanceKind::DropGlue(def_id, Some(_)) + | InstanceKind::AsyncDropGlueCtorShim(def_id, Some(_)) + | InstanceKind::ThreadLocalShim(def_id) => Some(def_id), + InstanceKind::VTableShim(..) + | InstanceKind::ReifyShim(..) + | InstanceKind::FnPtrShim(..) + | InstanceKind::Virtual(..) + | InstanceKind::Intrinsic(..) + | InstanceKind::ClosureOnceShim { .. } + | ty::InstanceKind::ConstructCoroutineInClosureShim { .. } + | ty::InstanceKind::CoroutineKindShim { .. } + | InstanceKind::DropGlue(..) + | InstanceKind::AsyncDropGlueCtorShim(..) + | InstanceKind::CloneShim(..) + | InstanceKind::FnPtrAddrShim(..) => None, } } @@ -289,10 +291,10 @@ impl<'tcx> InstanceDef<'tcx> { pub fn requires_inline(&self, tcx: TyCtxt<'tcx>) -> bool { use rustc_hir::definitions::DefPathData; let def_id = match *self { - ty::InstanceDef::Item(def) => def, - ty::InstanceDef::DropGlue(_, Some(_)) => return false, - ty::InstanceDef::AsyncDropGlueCtorShim(_, Some(_)) => return false, - ty::InstanceDef::ThreadLocalShim(_) => return false, + ty::InstanceKind::Item(def) => def, + ty::InstanceKind::DropGlue(_, Some(_)) => return false, + ty::InstanceKind::AsyncDropGlueCtorShim(_, Some(_)) => return false, + ty::InstanceKind::ThreadLocalShim(_) => return false, _ => return true, }; matches!( @@ -312,7 +314,9 @@ impl<'tcx> InstanceDef<'tcx> { if self.requires_inline(tcx) { return true; } - if let ty::InstanceDef::DropGlue(.., Some(ty)) = *self { + if let ty::InstanceKind::DropGlue(.., Some(ty)) + | ty::InstanceKind::AsyncDropGlueCtorShim(.., Some(ty)) = *self + { // Drop glue generally wants to be instantiated at every codegen // unit, but without an #[inline] hint. We should make this // available to normal end-users. @@ -327,12 +331,17 @@ impl<'tcx> InstanceDef<'tcx> { // drops of `Option::None` before LTO. We also respect the intent of // `#[inline]` on `Drop::drop` implementations. return ty.ty_adt_def().map_or(true, |adt_def| { - adt_def - .destructor(tcx) - .map_or_else(|| adt_def.is_enum(), |dtor| tcx.cross_crate_inlinable(dtor.did)) + match *self { + ty::InstanceKind::DropGlue(..) => adt_def.destructor(tcx).map(|dtor| dtor.did), + ty::InstanceKind::AsyncDropGlueCtorShim(..) => { + adt_def.async_destructor(tcx).map(|dtor| dtor.ctor) + } + _ => unreachable!(), + } + .map_or_else(|| adt_def.is_enum(), |did| tcx.cross_crate_inlinable(did)) }); } - if let ty::InstanceDef::ThreadLocalShim(..) = *self { + if let ty::InstanceKind::ThreadLocalShim(..) = *self { return false; } tcx.cross_crate_inlinable(self.def_id()) @@ -340,10 +349,10 @@ impl<'tcx> InstanceDef<'tcx> { pub fn requires_caller_location(&self, tcx: TyCtxt<'_>) -> bool { match *self { - InstanceDef::Item(def_id) | InstanceDef::Virtual(def_id, _) => { + InstanceKind::Item(def_id) | InstanceKind::Virtual(def_id, _) => { tcx.body_codegen_attrs(def_id).flags.contains(CodegenFnAttrFlags::TRACK_CALLER) } - InstanceDef::ClosureOnceShim { call_once: _, track_caller } => track_caller, + InstanceKind::ClosureOnceShim { call_once: _, track_caller } => track_caller, _ => false, } } @@ -356,22 +365,22 @@ impl<'tcx> InstanceDef<'tcx> { /// body should perform necessary instantiations. pub fn has_polymorphic_mir_body(&self) -> bool { match *self { - InstanceDef::CloneShim(..) - | InstanceDef::ThreadLocalShim(..) - | InstanceDef::FnPtrAddrShim(..) - | InstanceDef::FnPtrShim(..) - | InstanceDef::DropGlue(_, Some(_)) - | InstanceDef::AsyncDropGlueCtorShim(_, Some(_)) => false, - InstanceDef::ClosureOnceShim { .. } - | InstanceDef::ConstructCoroutineInClosureShim { .. } - | InstanceDef::CoroutineKindShim { .. } - | InstanceDef::DropGlue(..) - | InstanceDef::AsyncDropGlueCtorShim(..) - | InstanceDef::Item(_) - | InstanceDef::Intrinsic(..) - | InstanceDef::ReifyShim(..) - | InstanceDef::Virtual(..) - | InstanceDef::VTableShim(..) => true, + InstanceKind::CloneShim(..) + | InstanceKind::ThreadLocalShim(..) + | InstanceKind::FnPtrAddrShim(..) + | InstanceKind::FnPtrShim(..) + | InstanceKind::DropGlue(_, Some(_)) + | InstanceKind::AsyncDropGlueCtorShim(_, Some(_)) => false, + InstanceKind::ClosureOnceShim { .. } + | InstanceKind::ConstructCoroutineInClosureShim { .. } + | InstanceKind::CoroutineKindShim { .. } + | InstanceKind::DropGlue(..) + | InstanceKind::AsyncDropGlueCtorShim(..) + | InstanceKind::Item(_) + | InstanceKind::Intrinsic(..) + | InstanceKind::ReifyShim(..) + | InstanceKind::Virtual(..) + | InstanceKind::VTableShim(..) => true, } } } @@ -395,24 +404,24 @@ fn fmt_instance( })?; match instance.def { - InstanceDef::Item(_) => Ok(()), - InstanceDef::VTableShim(_) => write!(f, " - shim(vtable)"), - InstanceDef::ReifyShim(_, None) => write!(f, " - shim(reify)"), - InstanceDef::ReifyShim(_, Some(ReifyReason::FnPtr)) => write!(f, " - shim(reify-fnptr)"), - InstanceDef::ReifyShim(_, Some(ReifyReason::Vtable)) => write!(f, " - shim(reify-vtable)"), - InstanceDef::ThreadLocalShim(_) => write!(f, " - shim(tls)"), - InstanceDef::Intrinsic(_) => write!(f, " - intrinsic"), - InstanceDef::Virtual(_, num) => write!(f, " - virtual#{num}"), - InstanceDef::FnPtrShim(_, ty) => write!(f, " - shim({ty})"), - InstanceDef::ClosureOnceShim { .. } => write!(f, " - shim"), - InstanceDef::ConstructCoroutineInClosureShim { .. } => write!(f, " - shim"), - InstanceDef::CoroutineKindShim { .. } => write!(f, " - shim"), - InstanceDef::DropGlue(_, None) => write!(f, " - shim(None)"), - InstanceDef::DropGlue(_, Some(ty)) => write!(f, " - shim(Some({ty}))"), - InstanceDef::CloneShim(_, ty) => write!(f, " - shim({ty})"), - InstanceDef::FnPtrAddrShim(_, ty) => write!(f, " - shim({ty})"), - InstanceDef::AsyncDropGlueCtorShim(_, None) => write!(f, " - shim(None)"), - InstanceDef::AsyncDropGlueCtorShim(_, Some(ty)) => write!(f, " - shim(Some({ty}))"), + InstanceKind::Item(_) => Ok(()), + InstanceKind::VTableShim(_) => write!(f, " - shim(vtable)"), + InstanceKind::ReifyShim(_, None) => write!(f, " - shim(reify)"), + InstanceKind::ReifyShim(_, Some(ReifyReason::FnPtr)) => write!(f, " - shim(reify-fnptr)"), + InstanceKind::ReifyShim(_, Some(ReifyReason::Vtable)) => write!(f, " - shim(reify-vtable)"), + InstanceKind::ThreadLocalShim(_) => write!(f, " - shim(tls)"), + InstanceKind::Intrinsic(_) => write!(f, " - intrinsic"), + InstanceKind::Virtual(_, num) => write!(f, " - virtual#{num}"), + InstanceKind::FnPtrShim(_, ty) => write!(f, " - shim({ty})"), + InstanceKind::ClosureOnceShim { .. } => write!(f, " - shim"), + InstanceKind::ConstructCoroutineInClosureShim { .. } => write!(f, " - shim"), + InstanceKind::CoroutineKindShim { .. } => write!(f, " - shim"), + InstanceKind::DropGlue(_, None) => write!(f, " - shim(None)"), + InstanceKind::DropGlue(_, Some(ty)) => write!(f, " - shim(Some({ty}))"), + InstanceKind::CloneShim(_, ty) => write!(f, " - shim({ty})"), + InstanceKind::FnPtrAddrShim(_, ty) => write!(f, " - shim({ty})"), + InstanceKind::AsyncDropGlueCtorShim(_, None) => write!(f, " - shim(None)"), + InstanceKind::AsyncDropGlueCtorShim(_, Some(ty)) => write!(f, " - shim(Some({ty}))"), } } @@ -434,9 +443,9 @@ impl<'tcx> Instance<'tcx> { pub fn new(def_id: DefId, args: GenericArgsRef<'tcx>) -> Instance<'tcx> { assert!( !args.has_escaping_bound_vars(), - "args of instance {def_id:?} not normalized for codegen: {args:?}" + "args of instance {def_id:?} has escaping bound vars: {args:?}" ); - Instance { def: InstanceDef::Item(def_id), args } + Instance { def: InstanceKind::Item(def_id), args } } pub fn mono(tcx: TyCtxt<'tcx>, def_id: DefId) -> Instance<'tcx> { @@ -526,13 +535,13 @@ impl<'tcx> Instance<'tcx> { let reason = tcx.sess.is_sanitizer_kcfi_enabled().then_some(ReifyReason::FnPtr); Instance::resolve(tcx, param_env, def_id, args).ok().flatten().map(|mut resolved| { match resolved.def { - InstanceDef::Item(def) if resolved.def.requires_caller_location(tcx) => { + InstanceKind::Item(def) if resolved.def.requires_caller_location(tcx) => { debug!(" => fn pointer created for function with #[track_caller]"); - resolved.def = InstanceDef::ReifyShim(def, reason); + resolved.def = InstanceKind::ReifyShim(def, reason); } - InstanceDef::Virtual(def_id, _) => { + InstanceKind::Virtual(def_id, _) => { debug!(" => fn pointer created for virtual call"); - resolved.def = InstanceDef::ReifyShim(def_id, reason); + resolved.def = InstanceKind::ReifyShim(def_id, reason); } // Reify `Trait::method` implementations if KCFI is enabled // FIXME(maurer) only reify it if it is a vtable-safe function @@ -544,7 +553,7 @@ impl<'tcx> Instance<'tcx> { { // If this function could also go in a vtable, we need to `ReifyShim` it with // KCFI because it can only attach one type per function. - resolved.def = InstanceDef::ReifyShim(resolved.def_id(), reason) + resolved.def = InstanceKind::ReifyShim(resolved.def_id(), reason) } // Reify `::call`-like method implementations if KCFI is enabled _ if tcx.sess.is_sanitizer_kcfi_enabled() @@ -553,7 +562,7 @@ impl<'tcx> Instance<'tcx> { // Reroute through a reify via the *unresolved* instance. The resolved one can't // be directly reified because it's closure-like. The reify can handle the // unresolved instance. - resolved = Instance { def: InstanceDef::ReifyShim(def_id, reason), args } + resolved = Instance { def: InstanceKind::ReifyShim(def_id, reason), args } } _ => {} } @@ -575,12 +584,12 @@ impl<'tcx> Instance<'tcx> { && tcx.generics_of(def_id).has_self; if is_vtable_shim { debug!(" => associated item with unsizeable self: Self"); - Some(Instance { def: InstanceDef::VTableShim(def_id), args }) + Some(Instance { def: InstanceKind::VTableShim(def_id), args }) } else { let reason = tcx.sess.is_sanitizer_kcfi_enabled().then_some(ReifyReason::Vtable); Instance::resolve(tcx, param_env, def_id, args).ok().flatten().map(|mut resolved| { match resolved.def { - InstanceDef::Item(def) => { + InstanceKind::Item(def) => { // We need to generate a shim when we cannot guarantee that // the caller of a trait object method will be aware of // `#[track_caller]` - this ensures that the caller @@ -614,18 +623,18 @@ impl<'tcx> Instance<'tcx> { // Create a shim for the `FnOnce/FnMut/Fn` method we are calling // - unlike functions, invoking a closure always goes through a // trait. - resolved = Instance { def: InstanceDef::ReifyShim(def_id, reason), args }; + resolved = Instance { def: InstanceKind::ReifyShim(def_id, reason), args }; } else { debug!( " => vtable fn pointer created for function with #[track_caller]: {:?}", def ); - resolved.def = InstanceDef::ReifyShim(def, reason); + resolved.def = InstanceKind::ReifyShim(def, reason); } } } - InstanceDef::Virtual(def_id, _) => { + InstanceKind::Virtual(def_id, _) => { debug!(" => vtable fn pointer created for virtual call"); - resolved.def = InstanceDef::ReifyShim(def_id, reason) + resolved.def = InstanceKind::ReifyShim(def_id, reason) } _ => {} } @@ -676,7 +685,7 @@ impl<'tcx> Instance<'tcx> { .def_id; let track_caller = tcx.codegen_fn_attrs(closure_did).flags.contains(CodegenFnAttrFlags::TRACK_CALLER); - let def = ty::InstanceDef::ClosureOnceShim { call_once, track_caller }; + let def = ty::InstanceKind::ClosureOnceShim { call_once, track_caller }; let self_ty = Ty::new_closure(tcx, closure_did, args); @@ -733,10 +742,10 @@ impl<'tcx> Instance<'tcx> { // If the closure's kind ty disagrees with the identity closure's kind ty, // then this must be a coroutine generated by one of the `ConstructCoroutineInClosureShim`s. if args.as_coroutine().kind_ty() == id_args.as_coroutine().kind_ty() { - Some(Instance { def: ty::InstanceDef::Item(coroutine_def_id), args }) + Some(Instance { def: ty::InstanceKind::Item(coroutine_def_id), args }) } else { Some(Instance { - def: ty::InstanceDef::CoroutineKindShim { coroutine_def_id }, + def: ty::InstanceKind::CoroutineKindShim { coroutine_def_id }, args, }) } @@ -749,7 +758,7 @@ impl<'tcx> Instance<'tcx> { } } - /// Depending on the kind of `InstanceDef`, the MIR body associated with an + /// Depending on the kind of `InstanceKind`, the MIR body associated with an /// instance is expressed in terms of the generic parameters of `self.def_id()`, and in other /// cases the MIR body is expressed in terms of the types found in the generic parameter array. /// In the former case, we want to instantiate those generic types and replace them with the @@ -832,7 +841,7 @@ impl<'tcx> Instance<'tcx> { fn polymorphize<'tcx>( tcx: TyCtxt<'tcx>, - instance: ty::InstanceDef<'tcx>, + instance: ty::InstanceKind<'tcx>, args: GenericArgsRef<'tcx>, ) -> GenericArgsRef<'tcx> { debug!("polymorphize({:?}, {:?})", instance, args); @@ -873,7 +882,7 @@ fn polymorphize<'tcx>( match *ty.kind() { ty::Closure(def_id, args) => { let polymorphized_args = - polymorphize(self.tcx, ty::InstanceDef::Item(def_id), args); + polymorphize(self.tcx, ty::InstanceKind::Item(def_id), args); if args == polymorphized_args { ty } else { @@ -882,7 +891,7 @@ fn polymorphize<'tcx>( } ty::Coroutine(def_id, args) => { let polymorphized_args = - polymorphize(self.tcx, ty::InstanceDef::Item(def_id), args); + polymorphize(self.tcx, ty::InstanceKind::Item(def_id), args); if args == polymorphized_args { ty } else { diff --git a/compiler/rustc_middle/src/ty/layout.rs b/compiler/rustc_middle/src/ty/layout.rs index 02c0d41f619..3d397b6b37e 100644 --- a/compiler/rustc_middle/src/ty/layout.rs +++ b/compiler/rustc_middle/src/ty/layout.rs @@ -5,7 +5,7 @@ use crate::ty::normalize_erasing_regions::NormalizationError; use crate::ty::{self, CoroutineArgsExt, Ty, TyCtxt, TypeVisitableExt}; use rustc_error_messages::DiagMessage; use rustc_errors::{ - Diag, DiagArgValue, DiagCtxt, Diagnostic, EmissionGuarantee, IntoDiagArg, Level, + Diag, DiagArgValue, DiagCtxtHandle, Diagnostic, EmissionGuarantee, IntoDiagArg, Level, }; use rustc_hir as hir; use rustc_hir::def_id::DefId; @@ -1256,7 +1256,7 @@ pub enum FnAbiError<'tcx> { } impl<'a, 'b, G: EmissionGuarantee> Diagnostic<'a, G> for FnAbiError<'b> { - fn into_diag(self, dcx: &'a DiagCtxt, level: Level) -> Diag<'a, G> { + fn into_diag(self, dcx: DiagCtxtHandle<'a>, level: Level) -> Diag<'a, G> { match self { Self::Layout(e) => e.into_diagnostic().into_diag(dcx, level), Self::AdjustForForeignAbi(call::AdjustForForeignAbiError::Unsupported { @@ -1302,7 +1302,7 @@ pub trait FnAbiOf<'tcx>: FnAbiOfHelpers<'tcx> { /// Compute a `FnAbi` suitable for indirect calls, i.e. to `fn` pointers. /// /// NB: this doesn't handle virtual calls - those should use `fn_abi_of_instance` - /// instead, where the instance is an `InstanceDef::Virtual`. + /// instead, where the instance is an `InstanceKind::Virtual`. #[inline] fn fn_abi_of_fn_ptr( &self, @@ -1322,7 +1322,7 @@ pub trait FnAbiOf<'tcx>: FnAbiOfHelpers<'tcx> { /// direct calls to an `fn`. /// /// NB: that includes virtual calls, which are represented by "direct calls" - /// to an `InstanceDef::Virtual` instance (of `<dyn Trait as Trait>::fn`). + /// to an `InstanceKind::Virtual` instance (of `<dyn Trait as Trait>::fn`). #[inline] #[tracing::instrument(level = "debug", skip(self))] fn fn_abi_of_instance( diff --git a/compiler/rustc_middle/src/ty/mod.rs b/compiler/rustc_middle/src/ty/mod.rs index 5a94a53e175..9c2bfc12a18 100644 --- a/compiler/rustc_middle/src/ty/mod.rs +++ b/compiler/rustc_middle/src/ty/mod.rs @@ -92,8 +92,9 @@ pub use self::context::{ tls, CtxtInterners, CurrentGcx, DeducedParamAttrs, Feed, FreeRegionInfo, GlobalCtxt, Lift, TyCtxt, TyCtxtFeed, }; -pub use self::instance::{Instance, InstanceDef, ReifyReason, ShortInstance, UnusedGenericParams}; +pub use self::instance::{Instance, InstanceKind, ReifyReason, ShortInstance, UnusedGenericParams}; pub use self::list::{List, ListWithCachedTypeInfo}; +pub use self::opaque_types::OpaqueTypeKey; pub use self::parameterized::ParameterizedOverTcx; pub use self::pattern::{Pattern, PatternKind}; pub use self::predicate::{ @@ -758,45 +759,6 @@ impl<'a, 'tcx> IntoIterator for &'a InstantiatedPredicates<'tcx> { } } -#[derive(Copy, Clone, Debug, PartialEq, Eq, Hash, HashStable, TyEncodable, TyDecodable)] -#[derive(TypeFoldable, TypeVisitable)] -pub struct OpaqueTypeKey<'tcx> { - pub def_id: LocalDefId, - pub args: GenericArgsRef<'tcx>, -} - -impl<'tcx> OpaqueTypeKey<'tcx> { - pub fn iter_captured_args( - self, - tcx: TyCtxt<'tcx>, - ) -> impl Iterator<Item = (usize, GenericArg<'tcx>)> { - std::iter::zip(self.args, tcx.variances_of(self.def_id)).enumerate().filter_map( - |(i, (arg, v))| match (arg.unpack(), v) { - (_, ty::Invariant) => Some((i, arg)), - (ty::GenericArgKind::Lifetime(_), ty::Bivariant) => None, - _ => bug!("unexpected opaque type arg variance"), - }, - ) - } - - pub fn fold_captured_lifetime_args( - self, - tcx: TyCtxt<'tcx>, - mut f: impl FnMut(Region<'tcx>) -> Region<'tcx>, - ) -> Self { - let Self { def_id, args } = self; - let args = std::iter::zip(args, tcx.variances_of(def_id)).map(|(arg, v)| { - match (arg.unpack(), v) { - (ty::GenericArgKind::Lifetime(_), ty::Bivariant) => arg, - (ty::GenericArgKind::Lifetime(lt), _) => f(lt).into(), - _ => arg, - } - }); - let args = tcx.mk_args_from_iter(args); - Self { def_id, args } - } -} - #[derive(Copy, Clone, Debug, TypeFoldable, TypeVisitable, HashStable, TyEncodable, TyDecodable)] pub struct OpaqueHiddenType<'tcx> { /// The span of this particular definition of the opaque type. So @@ -1028,6 +990,16 @@ pub struct ParamEnv<'tcx> { packed: CopyTaggedPtr<Clauses<'tcx>, ParamTag, true>, } +impl<'tcx> rustc_type_ir::inherent::ParamEnv<TyCtxt<'tcx>> for ParamEnv<'tcx> { + fn reveal(self) -> Reveal { + self.reveal() + } + + fn caller_bounds(self) -> impl IntoIterator<Item = ty::Clause<'tcx>> { + self.caller_bounds() + } +} + #[derive(Copy, Clone)] struct ParamTag { reveal: traits::Reveal, @@ -1731,11 +1703,11 @@ impl<'tcx> TyCtxt<'tcx> { } } - /// Returns the possibly-auto-generated MIR of a [`ty::InstanceDef`]. + /// Returns the possibly-auto-generated MIR of a [`ty::InstanceKind`]. #[instrument(skip(self), level = "debug")] - pub fn instance_mir(self, instance: ty::InstanceDef<'tcx>) -> &'tcx Body<'tcx> { + pub fn instance_mir(self, instance: ty::InstanceKind<'tcx>) -> &'tcx Body<'tcx> { match instance { - ty::InstanceDef::Item(def) => { + ty::InstanceKind::Item(def) => { debug!("calling def_kind on def: {:?}", def); let def_kind = self.def_kind(def); debug!("returned from def_kind: {:?}", def_kind); @@ -1751,19 +1723,19 @@ impl<'tcx> TyCtxt<'tcx> { _ => self.optimized_mir(def), } } - ty::InstanceDef::VTableShim(..) - | ty::InstanceDef::ReifyShim(..) - | ty::InstanceDef::Intrinsic(..) - | ty::InstanceDef::FnPtrShim(..) - | ty::InstanceDef::Virtual(..) - | ty::InstanceDef::ClosureOnceShim { .. } - | ty::InstanceDef::ConstructCoroutineInClosureShim { .. } - | ty::InstanceDef::CoroutineKindShim { .. } - | ty::InstanceDef::DropGlue(..) - | ty::InstanceDef::CloneShim(..) - | ty::InstanceDef::ThreadLocalShim(..) - | ty::InstanceDef::FnPtrAddrShim(..) - | ty::InstanceDef::AsyncDropGlueCtorShim(..) => self.mir_shims(instance), + ty::InstanceKind::VTableShim(..) + | ty::InstanceKind::ReifyShim(..) + | ty::InstanceKind::Intrinsic(..) + | ty::InstanceKind::FnPtrShim(..) + | ty::InstanceKind::Virtual(..) + | ty::InstanceKind::ClosureOnceShim { .. } + | ty::InstanceKind::ConstructCoroutineInClosureShim { .. } + | ty::InstanceKind::CoroutineKindShim { .. } + | ty::InstanceKind::DropGlue(..) + | ty::InstanceKind::CloneShim(..) + | ty::InstanceKind::ThreadLocalShim(..) + | ty::InstanceKind::FnPtrAddrShim(..) + | ty::InstanceKind::AsyncDropGlueCtorShim(..) => self.mir_shims(instance), } } diff --git a/compiler/rustc_middle/src/ty/opaque_types.rs b/compiler/rustc_middle/src/ty/opaque_types.rs index 52902aadd7c..08b2f9e8920 100644 --- a/compiler/rustc_middle/src/ty/opaque_types.rs +++ b/compiler/rustc_middle/src/ty/opaque_types.rs @@ -7,6 +7,8 @@ use rustc_span::def_id::DefId; use rustc_span::Span; use tracing::{debug, instrument, trace}; +pub type OpaqueTypeKey<'tcx> = rustc_type_ir::OpaqueTypeKey<TyCtxt<'tcx>>; + /// Converts generic params of a TypeFoldable from one /// item's generics to another. Usually from a function's generics /// list to the opaque type's own generics. diff --git a/compiler/rustc_middle/src/ty/predicate.rs b/compiler/rustc_middle/src/ty/predicate.rs index ae36f2624ca..e9b37503bb3 100644 --- a/compiler/rustc_middle/src/ty/predicate.rs +++ b/compiler/rustc_middle/src/ty/predicate.rs @@ -175,6 +175,14 @@ pub struct Clause<'tcx>( impl<'tcx> rustc_type_ir::inherent::Clause<TyCtxt<'tcx>> for Clause<'tcx> {} +impl<'tcx> rustc_type_ir::inherent::IntoKind for Clause<'tcx> { + type Kind = ty::Binder<'tcx, ClauseKind<'tcx>>; + + fn kind(self) -> Self::Kind { + self.kind() + } +} + impl<'tcx> Clause<'tcx> { pub fn as_predicate(self) -> Predicate<'tcx> { Predicate(self.0) @@ -251,6 +259,28 @@ impl<'tcx> ExistentialPredicate<'tcx> { pub type PolyExistentialPredicate<'tcx> = ty::Binder<'tcx, ExistentialPredicate<'tcx>>; +impl<'tcx> rustc_type_ir::inherent::BoundExistentialPredicates<TyCtxt<'tcx>> + for &'tcx ty::List<ty::PolyExistentialPredicate<'tcx>> +{ + fn principal_def_id(self) -> Option<DefId> { + self.principal_def_id() + } + + fn principal(self) -> Option<ty::PolyExistentialTraitRef<'tcx>> { + self.principal() + } + + fn auto_traits(self) -> impl IntoIterator<Item = DefId> { + self.auto_traits() + } + + fn projection_bounds( + self, + ) -> impl IntoIterator<Item = ty::Binder<'tcx, ExistentialProjection<'tcx>>> { + self.projection_bounds() + } +} + impl<'tcx> ty::List<ty::PolyExistentialPredicate<'tcx>> { /// Returns the "principal `DefId`" of this set of existential predicates. /// @@ -481,12 +511,6 @@ impl<'tcx> UpcastFrom<TyCtxt<'tcx>, TraitRef<'tcx>> for Predicate<'tcx> { } } -impl<'tcx> UpcastFrom<TyCtxt<'tcx>, TraitRef<'tcx>> for TraitPredicate<'tcx> { - fn upcast_from(from: TraitRef<'tcx>, _tcx: TyCtxt<'tcx>) -> Self { - TraitPredicate { trait_ref: from, polarity: PredicatePolarity::Positive } - } -} - impl<'tcx> UpcastFrom<TyCtxt<'tcx>, TraitRef<'tcx>> for Clause<'tcx> { fn upcast_from(from: TraitRef<'tcx>, tcx: TyCtxt<'tcx>) -> Self { let p: Predicate<'tcx> = from.upcast(tcx); @@ -543,6 +567,12 @@ impl<'tcx> UpcastFrom<TyCtxt<'tcx>, PolyTraitPredicate<'tcx>> for Clause<'tcx> { } } +impl<'tcx> UpcastFrom<TyCtxt<'tcx>, RegionOutlivesPredicate<'tcx>> for Predicate<'tcx> { + fn upcast_from(from: RegionOutlivesPredicate<'tcx>, tcx: TyCtxt<'tcx>) -> Self { + ty::Binder::dummy(PredicateKind::Clause(ClauseKind::RegionOutlives(from))).upcast(tcx) + } +} + impl<'tcx> UpcastFrom<TyCtxt<'tcx>, PolyRegionOutlivesPredicate<'tcx>> for Predicate<'tcx> { fn upcast_from(from: PolyRegionOutlivesPredicate<'tcx>, tcx: TyCtxt<'tcx>) -> Self { from.map_bound(|p| PredicateKind::Clause(ClauseKind::RegionOutlives(p))).upcast(tcx) diff --git a/compiler/rustc_middle/src/ty/print/pretty.rs b/compiler/rustc_middle/src/ty/print/pretty.rs index de1796d4800..72cb3e13402 100644 --- a/compiler/rustc_middle/src/ty/print/pretty.rs +++ b/compiler/rustc_middle/src/ty/print/pretty.rs @@ -7,7 +7,7 @@ use crate::ty::{ ConstInt, Expr, ParamConst, ScalarInt, Term, TermKind, TypeFoldable, TypeSuperFoldable, TypeSuperVisitable, TypeVisitable, TypeVisitableExt, }; -use rustc_apfloat::ieee::{Double, Single}; +use rustc_apfloat::ieee::{Double, Half, Quad, Single}; use rustc_apfloat::Float; use rustc_data_structures::fx::{FxHashMap, FxIndexMap}; use rustc_data_structures::unord::UnordMap; @@ -1710,6 +1710,10 @@ pub trait PrettyPrinter<'tcx>: Printer<'tcx> + fmt::Write { ty::Bool if int == ScalarInt::FALSE => p!("false"), ty::Bool if int == ScalarInt::TRUE => p!("true"), // Float + ty::Float(ty::FloatTy::F16) => { + let val = Half::try_from(int).unwrap(); + p!(write("{}{}f16", val, if val.is_finite() { "" } else { "_" })) + } ty::Float(ty::FloatTy::F32) => { let val = Single::try_from(int).unwrap(); p!(write("{}{}f32", val, if val.is_finite() { "" } else { "_" })) @@ -1718,6 +1722,10 @@ pub trait PrettyPrinter<'tcx>: Printer<'tcx> + fmt::Write { let val = Double::try_from(int).unwrap(); p!(write("{}{}f64", val, if val.is_finite() { "" } else { "_" })) } + ty::Float(ty::FloatTy::F128) => { + let val = Quad::try_from(int).unwrap(); + p!(write("{}{}f128", val, if val.is_finite() { "" } else { "_" })) + } // Int ty::Uint(_) | ty::Int(_) => { let int = diff --git a/compiler/rustc_middle/src/ty/sty.rs b/compiler/rustc_middle/src/ty/sty.rs index 8308e537e5e..9c8a3484aa5 100644 --- a/compiler/rustc_middle/src/ty/sty.rs +++ b/compiler/rustc_middle/src/ty/sty.rs @@ -930,6 +930,22 @@ impl<'tcx> rustc_type_ir::inherent::Ty<TyCtxt<'tcx>> for Ty<'tcx> { fn new_pat(interner: TyCtxt<'tcx>, ty: Self, pat: ty::Pattern<'tcx>) -> Self { Ty::new_pat(interner, ty, pat) } + + fn new_unit(interner: TyCtxt<'tcx>) -> Self { + interner.types.unit + } + + fn new_usize(interner: TyCtxt<'tcx>) -> Self { + interner.types.usize + } + + fn discriminant_ty(self, interner: TyCtxt<'tcx>) -> Ty<'tcx> { + self.discriminant_ty(interner) + } + + fn async_destructor_ty(self, interner: TyCtxt<'tcx>) -> Ty<'tcx> { + self.async_destructor_ty(interner) + } } /// Type utilities diff --git a/compiler/rustc_middle/src/ty/util.rs b/compiler/rustc_middle/src/ty/util.rs index 52a0e72e17e..b079ed521d3 100644 --- a/compiler/rustc_middle/src/ty/util.rs +++ b/compiler/rustc_middle/src/ty/util.rs @@ -565,42 +565,6 @@ impl<'tcx> TyCtxt<'tcx> { Ok(()) } - /// Checks whether each generic argument is simply a unique generic placeholder. - /// - /// This is used in the new solver, which canonicalizes params to placeholders - /// for better caching. - pub fn uses_unique_placeholders_ignoring_regions( - self, - args: GenericArgsRef<'tcx>, - ) -> Result<(), NotUniqueParam<'tcx>> { - let mut seen = GrowableBitSet::default(); - for arg in args { - match arg.unpack() { - // Ignore regions, since we can't resolve those in a canonicalized - // query in the trait solver. - GenericArgKind::Lifetime(_) => {} - GenericArgKind::Type(t) => match t.kind() { - ty::Placeholder(p) => { - if !seen.insert(p.bound.var) { - return Err(NotUniqueParam::DuplicateParam(t.into())); - } - } - _ => return Err(NotUniqueParam::NotParam(t.into())), - }, - GenericArgKind::Const(c) => match c.kind() { - ty::ConstKind::Placeholder(p) => { - if !seen.insert(p.bound) { - return Err(NotUniqueParam::DuplicateParam(c.into())); - } - } - _ => return Err(NotUniqueParam::NotParam(c.into())), - }, - } - } - - Ok(()) - } - /// Returns `true` if `def_id` refers to a closure, coroutine, or coroutine-closure /// (i.e. an async closure). These are all represented by `hir::Closure`, and all /// have the same `DefKind`. diff --git a/compiler/rustc_mir_build/src/build/coverageinfo.rs b/compiler/rustc_mir_build/src/build/coverageinfo.rs index 855dcbbcb34..876faca5172 100644 --- a/compiler/rustc_mir_build/src/build/coverageinfo.rs +++ b/compiler/rustc_mir_build/src/build/coverageinfo.rs @@ -118,17 +118,35 @@ impl BranchInfoBuilder { } } - fn add_two_way_branch<'tcx>( + fn register_two_way_branch<'tcx>( &mut self, + tcx: TyCtxt<'tcx>, cfg: &mut CFG<'tcx>, source_info: SourceInfo, true_block: BasicBlock, false_block: BasicBlock, ) { - let true_marker = self.markers.inject_block_marker(cfg, source_info, true_block); - let false_marker = self.markers.inject_block_marker(cfg, source_info, false_block); - - self.branch_spans.push(BranchSpan { span: source_info.span, true_marker, false_marker }); + // Separate path for handling branches when MC/DC is enabled. + if let Some(mcdc_info) = self.mcdc_info.as_mut() { + let inject_block_marker = + |source_info, block| self.markers.inject_block_marker(cfg, source_info, block); + mcdc_info.visit_evaluated_condition( + tcx, + source_info, + true_block, + false_block, + inject_block_marker, + ); + } else { + let true_marker = self.markers.inject_block_marker(cfg, source_info, true_block); + let false_marker = self.markers.inject_block_marker(cfg, source_info, false_block); + + self.branch_spans.push(BranchSpan { + span: source_info.span, + true_marker, + false_marker, + }); + } } pub(crate) fn into_done(self) -> Option<Box<mir::coverage::BranchInfo>> { @@ -205,7 +223,14 @@ impl<'tcx> Builder<'_, 'tcx> { mir::TerminatorKind::if_(mir::Operand::Copy(place), true_block, false_block), ); - branch_info.add_two_way_branch(&mut self.cfg, source_info, true_block, false_block); + // Separate path for handling branches when MC/DC is enabled. + branch_info.register_two_way_branch( + self.tcx, + &mut self.cfg, + source_info, + true_block, + false_block, + ); let join_block = self.cfg.start_new_block(); self.cfg.goto(true_block, source_info, join_block); @@ -236,22 +261,13 @@ impl<'tcx> Builder<'_, 'tcx> { let source_info = SourceInfo { span: self.thir[expr_id].span, scope: self.source_scope }; - // Separate path for handling branches when MC/DC is enabled. - if let Some(mcdc_info) = branch_info.mcdc_info.as_mut() { - let inject_block_marker = |source_info, block| { - branch_info.markers.inject_block_marker(&mut self.cfg, source_info, block) - }; - mcdc_info.visit_evaluated_condition( - self.tcx, - source_info, - then_block, - else_block, - inject_block_marker, - ); - return; - } - - branch_info.add_two_way_branch(&mut self.cfg, source_info, then_block, else_block); + branch_info.register_two_way_branch( + self.tcx, + &mut self.cfg, + source_info, + then_block, + else_block, + ); } /// If branch coverage is enabled, inject marker statements into `true_block` @@ -270,6 +286,12 @@ impl<'tcx> Builder<'_, 'tcx> { // FIXME(#124144) This may need special handling when MC/DC is enabled. let source_info = SourceInfo { span: pattern.span, scope: self.source_scope }; - branch_info.add_two_way_branch(&mut self.cfg, source_info, true_block, false_block); + branch_info.register_two_way_branch( + self.tcx, + &mut self.cfg, + source_info, + true_block, + false_block, + ); } } diff --git a/compiler/rustc_mir_build/src/build/expr/into.rs b/compiler/rustc_mir_build/src/build/expr/into.rs index c08a3b6691a..6b4dd8b64a4 100644 --- a/compiler/rustc_mir_build/src/build/expr/into.rs +++ b/compiler/rustc_mir_build/src/build/expr/into.rs @@ -150,6 +150,9 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { ExprKind::LogicalOp { op, lhs, rhs } => { let condition_scope = this.local_scope(); let source_info = this.source_info(expr.span); + + this.visit_coverage_branch_operation(op, expr.span); + // We first evaluate the left-hand side of the predicate ... let (then_block, else_block) = this.in_if_then_scope(condition_scope, expr.span, |this| { diff --git a/compiler/rustc_mir_build/src/build/matches/mod.rs b/compiler/rustc_mir_build/src/build/matches/mod.rs index 544f27b84e9..68244136d1a 100644 --- a/compiler/rustc_mir_build/src/build/matches/mod.rs +++ b/compiler/rustc_mir_build/src/build/matches/mod.rs @@ -1074,12 +1074,9 @@ struct Candidate<'pat, 'tcx> { // because that would break binding consistency. subcandidates: Vec<Candidate<'pat, 'tcx>>, - /// ...and the guard must be evaluated if there is one. + /// ...and if there is a guard it must be evaluated; if it's `false` then branch to `otherwise_block`. has_guard: bool, - /// If the guard is `false` then branch to `otherwise_block`. - otherwise_block: Option<BasicBlock>, - /// If the candidate matches, bindings and ascriptions must be established. extra_data: PatternExtraData<'tcx>, @@ -1090,6 +1087,9 @@ struct Candidate<'pat, 'tcx> { /// The block before the `bindings` have been established. pre_binding_block: Option<BasicBlock>, + /// The block to branch to if the guard or a nested candidate fails to match. + otherwise_block: Option<BasicBlock>, + /// The earliest block that has only candidates >= this one as descendents. Used for false /// edges, see the doc for [`Builder::match_expr`]. false_edge_start_block: Option<BasicBlock>, @@ -1364,56 +1364,105 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { otherwise_block: BasicBlock, candidates: &mut [&mut Candidate<'pat, 'tcx>], ) { - let mut split_or_candidate = false; - for candidate in &mut *candidates { - if let [MatchPair { test_case: TestCase::Or { .. }, .. }] = &*candidate.match_pairs { - // Split a candidate in which the only match-pair is an or-pattern into multiple - // candidates. This is so that - // - // match x { - // 0 | 1 => { ... }, - // 2 | 3 => { ... }, - // } - // - // only generates a single switch. - let match_pair = candidate.match_pairs.pop().unwrap(); - self.create_or_subcandidates(candidate, match_pair); - split_or_candidate = true; + // We process or-patterns here. If any candidate starts with an or-pattern, we have to + // expand the or-pattern before we can proceed further. + // + // We can't expand them freely however. The rule is: if the candidate has an or-pattern as + // its only remaining match pair, we can expand it freely. If it has other match pairs, we + // can expand it but we can't process more candidates after it. + // + // If we didn't stop, the `otherwise` cases could get mixed up. E.g. in the following, + // or-pattern simplification (in `merge_trivial_subcandidates`) makes it so the `1` and `2` + // cases branch to a same block (which then tests `false`). If we took `(2, _)` in the same + // set of candidates, when we reach the block that tests `false` we don't know whether we + // came from `1` or `2`, hence we can't know where to branch on failure. + // ```ignore(illustrative) + // match (1, true) { + // (1 | 2, false) => {}, + // (2, _) => {}, + // _ => {} + // } + // ``` + // + // We therefore split the `candidates` slice in two, expand or-patterns in the first half, + // and process both halves separately. + let mut expand_until = 0; + for (i, candidate) in candidates.iter().enumerate() { + if matches!( + &*candidate.match_pairs, + [MatchPair { test_case: TestCase::Or { .. }, .. }, ..] + ) { + expand_until = i + 1; + if candidate.match_pairs.len() > 1 { + break; + } } } + let (candidates_to_expand, remaining_candidates) = candidates.split_at_mut(expand_until); ensure_sufficient_stack(|| { - if split_or_candidate { - // At least one of the candidates has been split into subcandidates. - // We need to change the candidate list to include those. - let mut new_candidates = Vec::new(); - for candidate in candidates.iter_mut() { - candidate.visit_leaves(|leaf_candidate| new_candidates.push(leaf_candidate)); + if candidates_to_expand.is_empty() { + // No candidates start with an or-pattern, we can continue. + self.match_expanded_candidates( + span, + scrutinee_span, + start_block, + otherwise_block, + remaining_candidates, + ); + } else { + // Expand one level of or-patterns for each candidate in `candidates_to_expand`. + let mut expanded_candidates = Vec::new(); + for candidate in candidates_to_expand.iter_mut() { + if let [MatchPair { test_case: TestCase::Or { .. }, .. }, ..] = + &*candidate.match_pairs + { + let or_match_pair = candidate.match_pairs.remove(0); + // Expand the or-pattern into subcandidates. + self.create_or_subcandidates(candidate, or_match_pair); + // Collect the newly created subcandidates. + for subcandidate in candidate.subcandidates.iter_mut() { + expanded_candidates.push(subcandidate); + } + } else { + expanded_candidates.push(candidate); + } } + + // Process the expanded candidates. + let remainder_start = self.cfg.start_new_block(); + // There might be new or-patterns obtained from expanding the old ones, so we call + // `match_candidates` again. self.match_candidates( span, scrutinee_span, start_block, - otherwise_block, - &mut *new_candidates, + remainder_start, + expanded_candidates.as_mut_slice(), ); - for candidate in candidates { - self.merge_trivial_subcandidates(candidate); + // Simplify subcandidates and process any leftover match pairs. + for candidate in candidates_to_expand { + if !candidate.subcandidates.is_empty() { + self.finalize_or_candidate(span, scrutinee_span, candidate); + } } - } else { - self.match_simplified_candidates( + + // Process the remaining candidates. + self.match_candidates( span, scrutinee_span, - start_block, + remainder_start, otherwise_block, - candidates, + remaining_candidates, ); } }); } - fn match_simplified_candidates( + /// Construct the decision tree for `candidates`. Caller must ensure that no candidate in + /// `candidates` starts with an or-pattern. + fn match_expanded_candidates( &mut self, span: Span, scrutinee_span: Span, @@ -1438,7 +1487,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { // The first candidate has satisfied all its match pairs; we link it up and continue // with the remaining candidates. start_block = self.select_matched_candidate(first, start_block); - self.match_simplified_candidates( + self.match_expanded_candidates( span, scrutinee_span, start_block, @@ -1448,7 +1497,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { } candidates => { // The first candidate has some unsatisfied match pairs; we proceed to do more tests. - self.test_candidates_with_or( + self.test_candidates( span, scrutinee_span, candidates, @@ -1495,16 +1544,14 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { candidate.pre_binding_block = Some(start_block); let otherwise_block = self.cfg.start_new_block(); - if candidate.has_guard { - // Create the otherwise block for this candidate, which is the - // pre-binding block for the next candidate. - candidate.otherwise_block = Some(otherwise_block); - } + // Create the otherwise block for this candidate, which is the + // pre-binding block for the next candidate. + candidate.otherwise_block = Some(otherwise_block); otherwise_block } - /// Tests a candidate where there are only or-patterns left to test, or - /// forwards to [Builder::test_candidates]. + /// Simplify subcandidates and process any leftover match pairs. The candidate should have been + /// expanded with `create_or_subcandidates`. /// /// Given a pattern `(P | Q, R | S)` we (in principle) generate a CFG like /// so: @@ -1556,84 +1603,56 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { /// | /// ... /// ``` - fn test_candidates_with_or( + fn finalize_or_candidate( &mut self, span: Span, scrutinee_span: Span, - candidates: &mut [&mut Candidate<'_, 'tcx>], - start_block: BasicBlock, - otherwise_block: BasicBlock, + candidate: &mut Candidate<'_, 'tcx>, ) { - let (first_candidate, remaining_candidates) = candidates.split_first_mut().unwrap(); - assert!(first_candidate.subcandidates.is_empty()); - if !matches!(first_candidate.match_pairs[0].test_case, TestCase::Or { .. }) { - self.test_candidates(span, scrutinee_span, candidates, start_block, otherwise_block); + if candidate.subcandidates.is_empty() { return; } - let first_match_pair = first_candidate.match_pairs.remove(0); - let remaining_match_pairs = mem::take(&mut first_candidate.match_pairs); - let remainder_start = self.cfg.start_new_block(); - // Test the alternatives of this or-pattern. - self.test_or_pattern(first_candidate, start_block, remainder_start, first_match_pair); + self.merge_trivial_subcandidates(candidate); - if !remaining_match_pairs.is_empty() { + if !candidate.match_pairs.is_empty() { // If more match pairs remain, test them after each subcandidate. // We could add them to the or-candidates before the call to `test_or_pattern` but this // would make it impossible to detect simplifiable or-patterns. That would guarantee // exponentially large CFGs for cases like `(1 | 2, 3 | 4, ...)`. - first_candidate.visit_leaves(|leaf_candidate| { + let mut last_otherwise = None; + candidate.visit_leaves(|leaf_candidate| { + last_otherwise = leaf_candidate.otherwise_block; + }); + let remaining_match_pairs = mem::take(&mut candidate.match_pairs); + candidate.visit_leaves(|leaf_candidate| { assert!(leaf_candidate.match_pairs.is_empty()); leaf_candidate.match_pairs.extend(remaining_match_pairs.iter().cloned()); let or_start = leaf_candidate.pre_binding_block.unwrap(); - // In a case like `(a | b, c | d)`, if `a` succeeds and `c | d` fails, we know `(b, - // c | d)` will fail too. If there is no guard, we skip testing of `b` by branching - // directly to `remainder_start`. If there is a guard, we have to try `(b, c | d)`. - let or_otherwise = leaf_candidate.otherwise_block.unwrap_or(remainder_start); - self.test_candidates_with_or( + // In a case like `(P | Q, R | S)`, if `P` succeeds and `R | S` fails, we know `(Q, + // R | S)` will fail too. If there is no guard, we skip testing of `Q` by branching + // directly to `last_otherwise`. If there is a guard, + // `leaf_candidate.otherwise_block` can be reached by guard failure as well, so we + // can't skip `Q`. + let or_otherwise = if leaf_candidate.has_guard { + leaf_candidate.otherwise_block.unwrap() + } else { + last_otherwise.unwrap() + }; + self.match_candidates( span, scrutinee_span, - &mut [leaf_candidate], or_start, or_otherwise, + &mut [leaf_candidate], ); }); } - - // Test the remaining candidates. - self.match_candidates( - span, - scrutinee_span, - remainder_start, - otherwise_block, - remaining_candidates, - ); - } - - #[instrument(skip(self, start_block, otherwise_block, candidate, match_pair), level = "debug")] - fn test_or_pattern<'pat>( - &mut self, - candidate: &mut Candidate<'pat, 'tcx>, - start_block: BasicBlock, - otherwise_block: BasicBlock, - match_pair: MatchPair<'pat, 'tcx>, - ) { - let or_span = match_pair.pattern.span; - self.create_or_subcandidates(candidate, match_pair); - let mut or_candidate_refs: Vec<_> = candidate.subcandidates.iter_mut().collect(); - self.match_candidates( - or_span, - or_span, - start_block, - otherwise_block, - &mut or_candidate_refs, - ); - self.merge_trivial_subcandidates(candidate); } /// Given a match-pair that corresponds to an or-pattern, expand each subpattern into a new /// subcandidate. Any candidate that has been expanded that way should be passed to - /// `merge_trivial_subcandidates` after its subcandidates have been processed. + /// `finalize_or_candidate` after its subcandidates have been processed. fn create_or_subcandidates<'pat>( &mut self, candidate: &mut Candidate<'pat, 'tcx>, @@ -1651,8 +1670,8 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { } /// Try to merge all of the subcandidates of the given candidate into one. This avoids - /// exponentially large CFGs in cases like `(1 | 2, 3 | 4, ...)`. The or-pattern should have - /// been expanded with `create_or_subcandidates`. + /// exponentially large CFGs in cases like `(1 | 2, 3 | 4, ...)`. The candidate should have been + /// expanded with `create_or_subcandidates`. fn merge_trivial_subcandidates(&mut self, candidate: &mut Candidate<'_, 'tcx>) { if candidate.subcandidates.is_empty() || candidate.has_guard { // FIXME(or_patterns; matthewjasper) Don't give up if we have a guard. @@ -1664,6 +1683,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { subcandidate.subcandidates.is_empty() && subcandidate.extra_data.is_empty() }); if can_merge { + let mut last_otherwise = None; let any_matches = self.cfg.start_new_block(); let or_span = candidate.or_span.take().unwrap(); let source_info = self.source_info(or_span); @@ -1674,8 +1694,11 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { for subcandidate in mem::take(&mut candidate.subcandidates) { let or_block = subcandidate.pre_binding_block.unwrap(); self.cfg.goto(or_block, source_info, any_matches); + last_otherwise = subcandidate.otherwise_block; } candidate.pre_binding_block = Some(any_matches); + assert!(last_otherwise.is_some()); + candidate.otherwise_block = last_otherwise; } else { // Never subcandidates may have a set of bindings inconsistent with their siblings, // which would break later code. So we filter them out. Note that we can't filter out diff --git a/compiler/rustc_mir_build/src/errors.rs b/compiler/rustc_mir_build/src/errors.rs index 3bd2e47976b..7c73d8a6d47 100644 --- a/compiler/rustc_mir_build/src/errors.rs +++ b/compiler/rustc_mir_build/src/errors.rs @@ -1,9 +1,9 @@ use crate::fluent_generated as fluent; -use rustc_errors::DiagArgValue; use rustc_errors::{ - codes::*, Applicability, Diag, DiagCtxt, Diagnostic, EmissionGuarantee, Level, MultiSpan, + codes::*, Applicability, Diag, Diagnostic, EmissionGuarantee, Level, MultiSpan, SubdiagMessageOp, Subdiagnostic, }; +use rustc_errors::{DiagArgValue, DiagCtxtHandle}; use rustc_macros::{Diagnostic, LintDiagnostic, Subdiagnostic}; use rustc_middle::ty::{self, Ty}; use rustc_pattern_analysis::{errors::Uncovered, rustc::RustcPatCtxt}; @@ -492,7 +492,7 @@ pub(crate) struct NonExhaustivePatternsTypeNotEmpty<'p, 'tcx, 'm> { } impl<'a, G: EmissionGuarantee> Diagnostic<'a, G> for NonExhaustivePatternsTypeNotEmpty<'_, '_, '_> { - fn into_diag(self, dcx: &'a DiagCtxt, level: Level) -> Diag<'_, G> { + fn into_diag(self, dcx: DiagCtxtHandle<'a>, level: Level) -> Diag<'_, G> { let mut diag = Diag::new(dcx, level, fluent::mir_build_non_exhaustive_patterns_type_not_empty); diag.span(self.scrut_span); diff --git a/compiler/rustc_mir_build/src/thir/pattern/check_match.rs b/compiler/rustc_mir_build/src/thir/pattern/check_match.rs index 30f57c8c622..70065b5a2c3 100644 --- a/compiler/rustc_mir_build/src/thir/pattern/check_match.rs +++ b/compiler/rustc_mir_build/src/thir/pattern/check_match.rs @@ -1137,7 +1137,7 @@ fn report_non_exhaustive_match<'p, 'tcx>( let all_arms_have_guards = arms.iter().all(|arm_id| thir[*arm_id].guard.is_some()); if !is_empty_match && all_arms_have_guards { - err.subdiagnostic(cx.tcx.dcx(), NonExhaustiveMatchAllArmsGuarded); + err.subdiagnostic(NonExhaustiveMatchAllArmsGuarded); } if let Some((span, sugg)) = suggestion { err.span_suggestion_verbose(span, msg, sugg, Applicability::HasPlaceholders); diff --git a/compiler/rustc_mir_transform/src/coroutine.rs b/compiler/rustc_mir_transform/src/coroutine.rs index 84512e81637..bf79b4e133a 100644 --- a/compiler/rustc_mir_transform/src/coroutine.rs +++ b/compiler/rustc_mir_transform/src/coroutine.rs @@ -68,7 +68,7 @@ use rustc_index::{Idx, IndexVec}; use rustc_middle::mir::visit::{MutVisitor, PlaceContext, Visitor}; use rustc_middle::mir::*; use rustc_middle::ty::CoroutineArgs; -use rustc_middle::ty::InstanceDef; +use rustc_middle::ty::InstanceKind; use rustc_middle::ty::{self, CoroutineArgsExt, Ty, TyCtxt}; use rustc_middle::{bug, span_bug}; use rustc_mir_dataflow::impls::{ @@ -1276,7 +1276,7 @@ fn create_coroutine_drop_shim<'tcx>( // Update the body's def to become the drop glue. let coroutine_instance = body.source.instance; let drop_in_place = tcx.require_lang_item(LangItem::DropInPlace, None); - let drop_instance = InstanceDef::DropGlue(drop_in_place, Some(coroutine_ty)); + let drop_instance = InstanceKind::DropGlue(drop_in_place, Some(coroutine_ty)); // Temporary change MirSource to coroutine's instance so that dump_mir produces more sensible // filename. diff --git a/compiler/rustc_mir_transform/src/coroutine/by_move_body.rs b/compiler/rustc_mir_transform/src/coroutine/by_move_body.rs index 10c0567eb4b..69d21a63f55 100644 --- a/compiler/rustc_mir_transform/src/coroutine/by_move_body.rs +++ b/compiler/rustc_mir_transform/src/coroutine/by_move_body.rs @@ -75,7 +75,7 @@ use rustc_middle::bug; use rustc_middle::hir::place::{Projection, ProjectionKind}; use rustc_middle::mir::visit::MutVisitor; use rustc_middle::mir::{self, dump_mir, MirPass}; -use rustc_middle::ty::{self, InstanceDef, Ty, TyCtxt, TypeVisitableExt}; +use rustc_middle::ty::{self, InstanceKind, Ty, TyCtxt, TypeVisitableExt}; use rustc_target::abi::{FieldIdx, VariantIdx}; pub struct ByMoveBody; @@ -102,7 +102,7 @@ impl<'tcx> MirPass<'tcx> for ByMoveBody { // We don't need to generate a by-move coroutine if the coroutine body was // produced by the `CoroutineKindShim`, since it's already by-move. - if matches!(body.source.instance, ty::InstanceDef::CoroutineKindShim { .. }) { + if matches!(body.source.instance, ty::InstanceKind::CoroutineKindShim { .. }) { return; } @@ -193,7 +193,7 @@ impl<'tcx> MirPass<'tcx> for ByMoveBody { MakeByMoveBody { tcx, field_remapping, by_move_coroutine_ty }.visit_body(&mut by_move_body); dump_mir(tcx, false, "coroutine_by_move", &0, &by_move_body, |_, _| Ok(())); // FIXME: use query feeding to generate the body right here and then only store the `DefId` of the new body. - by_move_body.source = mir::MirSource::from_instance(InstanceDef::CoroutineKindShim { + by_move_body.source = mir::MirSource::from_instance(InstanceKind::CoroutineKindShim { coroutine_def_id: coroutine_def_id.to_def_id(), }); body.coroutine.as_mut().unwrap().by_move_body = Some(by_move_body); diff --git a/compiler/rustc_mir_transform/src/coverage/counters.rs b/compiler/rustc_mir_transform/src/coverage/counters.rs index b5968517d77..a8b0f4a8d6d 100644 --- a/compiler/rustc_mir_transform/src/coverage/counters.rs +++ b/compiler/rustc_mir_transform/src/coverage/counters.rs @@ -168,11 +168,6 @@ impl CoverageCounters { self.counter_increment_sites.len() } - #[cfg(test)] - pub(super) fn num_expressions(&self) -> usize { - self.expressions.len() - } - fn set_bcb_counter(&mut self, bcb: BasicCoverageBlock, counter_kind: BcbCounter) -> BcbCounter { if let Some(replaced) = self.bcb_counters[bcb].replace(counter_kind) { bug!( diff --git a/compiler/rustc_mir_transform/src/coverage/graph.rs b/compiler/rustc_mir_transform/src/coverage/graph.rs index fd74a2a97e2..360dccb240d 100644 --- a/compiler/rustc_mir_transform/src/coverage/graph.rs +++ b/compiler/rustc_mir_transform/src/coverage/graph.rs @@ -14,16 +14,16 @@ use std::ops::{Index, IndexMut}; /// A coverage-specific simplification of the MIR control flow graph (CFG). The `CoverageGraph`s /// nodes are `BasicCoverageBlock`s, which encompass one or more MIR `BasicBlock`s. #[derive(Debug)] -pub(super) struct CoverageGraph { +pub(crate) struct CoverageGraph { bcbs: IndexVec<BasicCoverageBlock, BasicCoverageBlockData>, bb_to_bcb: IndexVec<BasicBlock, Option<BasicCoverageBlock>>, - pub successors: IndexVec<BasicCoverageBlock, Vec<BasicCoverageBlock>>, - pub predecessors: IndexVec<BasicCoverageBlock, Vec<BasicCoverageBlock>>, + pub(crate) successors: IndexVec<BasicCoverageBlock, Vec<BasicCoverageBlock>>, + pub(crate) predecessors: IndexVec<BasicCoverageBlock, Vec<BasicCoverageBlock>>, dominators: Option<Dominators<BasicCoverageBlock>>, } impl CoverageGraph { - pub fn from_mir(mir_body: &mir::Body<'_>) -> Self { + pub(crate) fn from_mir(mir_body: &mir::Body<'_>) -> Self { let (bcbs, bb_to_bcb) = Self::compute_basic_coverage_blocks(mir_body); // Pre-transform MIR `BasicBlock` successors and predecessors into the BasicCoverageBlock @@ -135,24 +135,28 @@ impl CoverageGraph { } #[inline(always)] - pub fn iter_enumerated( + pub(crate) fn iter_enumerated( &self, ) -> impl Iterator<Item = (BasicCoverageBlock, &BasicCoverageBlockData)> { self.bcbs.iter_enumerated() } #[inline(always)] - pub fn bcb_from_bb(&self, bb: BasicBlock) -> Option<BasicCoverageBlock> { + pub(crate) fn bcb_from_bb(&self, bb: BasicBlock) -> Option<BasicCoverageBlock> { if bb.index() < self.bb_to_bcb.len() { self.bb_to_bcb[bb] } else { None } } #[inline(always)] - pub fn dominates(&self, dom: BasicCoverageBlock, node: BasicCoverageBlock) -> bool { + pub(crate) fn dominates(&self, dom: BasicCoverageBlock, node: BasicCoverageBlock) -> bool { self.dominators.as_ref().unwrap().dominates(dom, node) } #[inline(always)] - pub fn cmp_in_dominator_order(&self, a: BasicCoverageBlock, b: BasicCoverageBlock) -> Ordering { + pub(crate) fn cmp_in_dominator_order( + &self, + a: BasicCoverageBlock, + b: BasicCoverageBlock, + ) -> Ordering { self.dominators.as_ref().unwrap().cmp_in_dominator_order(a, b) } @@ -166,7 +170,7 @@ impl CoverageGraph { /// /// FIXME: That assumption might not be true for [`TerminatorKind::Yield`]? #[inline(always)] - pub(super) fn bcb_has_multiple_in_edges(&self, bcb: BasicCoverageBlock) -> bool { + pub(crate) fn bcb_has_multiple_in_edges(&self, bcb: BasicCoverageBlock) -> bool { // Even though bcb0 conceptually has an extra virtual in-edge due to // being the entry point, we've already asserted that it has no _other_ // in-edges, so there's no possibility of it having _multiple_ in-edges. @@ -212,7 +216,7 @@ impl graph::StartNode for CoverageGraph { impl graph::Successors for CoverageGraph { #[inline] fn successors(&self, node: Self::Node) -> impl Iterator<Item = Self::Node> { - self.successors[node].iter().cloned() + self.successors[node].iter().copied() } } @@ -227,7 +231,7 @@ rustc_index::newtype_index! { /// A node in the control-flow graph of CoverageGraph. #[orderable] #[debug_format = "bcb{}"] - pub(super) struct BasicCoverageBlock { + pub(crate) struct BasicCoverageBlock { const START_BCB = 0; } } @@ -259,23 +263,23 @@ rustc_index::newtype_index! { /// queries (`dominates()`, `predecessors`, `successors`, etc.) have branch (control flow) /// significance. #[derive(Debug, Clone)] -pub(super) struct BasicCoverageBlockData { - pub basic_blocks: Vec<BasicBlock>, +pub(crate) struct BasicCoverageBlockData { + pub(crate) basic_blocks: Vec<BasicBlock>, } impl BasicCoverageBlockData { - pub fn from(basic_blocks: Vec<BasicBlock>) -> Self { + fn from(basic_blocks: Vec<BasicBlock>) -> Self { assert!(basic_blocks.len() > 0); Self { basic_blocks } } #[inline(always)] - pub fn leader_bb(&self) -> BasicBlock { + pub(crate) fn leader_bb(&self) -> BasicBlock { self.basic_blocks[0] } #[inline(always)] - pub fn last_bb(&self) -> BasicBlock { + pub(crate) fn last_bb(&self) -> BasicBlock { *self.basic_blocks.last().unwrap() } } @@ -364,7 +368,7 @@ fn bcb_filtered_successors<'a, 'tcx>(terminator: &'a Terminator<'tcx>) -> Covera /// CoverageGraph outside all loops. This supports traversing the BCB CFG in a way that /// ensures a loop is completely traversed before processing Blocks after the end of the loop. #[derive(Debug)] -pub(super) struct TraversalContext { +struct TraversalContext { /// BCB with one or more incoming loop backedges, indicating which loop /// this context is for. /// @@ -375,7 +379,7 @@ pub(super) struct TraversalContext { worklist: VecDeque<BasicCoverageBlock>, } -pub(super) struct TraverseCoverageGraphWithLoops<'a> { +pub(crate) struct TraverseCoverageGraphWithLoops<'a> { basic_coverage_blocks: &'a CoverageGraph, backedges: IndexVec<BasicCoverageBlock, Vec<BasicCoverageBlock>>, @@ -384,7 +388,7 @@ pub(super) struct TraverseCoverageGraphWithLoops<'a> { } impl<'a> TraverseCoverageGraphWithLoops<'a> { - pub(super) fn new(basic_coverage_blocks: &'a CoverageGraph) -> Self { + pub(crate) fn new(basic_coverage_blocks: &'a CoverageGraph) -> Self { let backedges = find_loop_backedges(basic_coverage_blocks); let worklist = VecDeque::from([basic_coverage_blocks.start_node()]); @@ -400,7 +404,7 @@ impl<'a> TraverseCoverageGraphWithLoops<'a> { /// For each loop on the loop context stack (top-down), yields a list of BCBs /// within that loop that have an outgoing edge back to the loop header. - pub(super) fn reloop_bcbs_per_loop(&self) -> impl Iterator<Item = &[BasicCoverageBlock]> { + pub(crate) fn reloop_bcbs_per_loop(&self) -> impl Iterator<Item = &[BasicCoverageBlock]> { self.context_stack .iter() .rev() @@ -408,39 +412,38 @@ impl<'a> TraverseCoverageGraphWithLoops<'a> { .map(|header_bcb| self.backedges[header_bcb].as_slice()) } - pub(super) fn next(&mut self) -> Option<BasicCoverageBlock> { + pub(crate) fn next(&mut self) -> Option<BasicCoverageBlock> { debug!( "TraverseCoverageGraphWithLoops::next - context_stack: {:?}", self.context_stack.iter().rev().collect::<Vec<_>>() ); while let Some(context) = self.context_stack.last_mut() { - if let Some(bcb) = context.worklist.pop_front() { - if !self.visited.insert(bcb) { - debug!("Already visited: {bcb:?}"); - continue; - } - debug!("Visiting {bcb:?}"); - - if self.backedges[bcb].len() > 0 { - debug!("{bcb:?} is a loop header! Start a new TraversalContext..."); - self.context_stack.push(TraversalContext { - loop_header: Some(bcb), - worklist: VecDeque::new(), - }); - } - self.add_successors_to_worklists(bcb); - return Some(bcb); - } else { - // Strip contexts with empty worklists from the top of the stack + let Some(bcb) = context.worklist.pop_front() else { + // This stack level is exhausted; pop it and try the next one. self.context_stack.pop(); + continue; + }; + + if !self.visited.insert(bcb) { + debug!("Already visited: {bcb:?}"); + continue; + } + debug!("Visiting {bcb:?}"); + + if self.backedges[bcb].len() > 0 { + debug!("{bcb:?} is a loop header! Start a new TraversalContext..."); + self.context_stack + .push(TraversalContext { loop_header: Some(bcb), worklist: VecDeque::new() }); } + self.add_successors_to_worklists(bcb); + return Some(bcb); } None } - pub fn add_successors_to_worklists(&mut self, bcb: BasicCoverageBlock) { + fn add_successors_to_worklists(&mut self, bcb: BasicCoverageBlock) { let successors = &self.basic_coverage_blocks.successors[bcb]; debug!("{:?} has {} successors:", bcb, successors.len()); @@ -494,11 +497,11 @@ impl<'a> TraverseCoverageGraphWithLoops<'a> { } } - pub fn is_complete(&self) -> bool { + pub(crate) fn is_complete(&self) -> bool { self.visited.count() == self.visited.domain_size() } - pub fn unvisited(&self) -> Vec<BasicCoverageBlock> { + pub(crate) fn unvisited(&self) -> Vec<BasicCoverageBlock> { let mut unvisited_set: BitSet<BasicCoverageBlock> = BitSet::new_filled(self.visited.domain_size()); unvisited_set.subtract(&self.visited); @@ -506,7 +509,7 @@ impl<'a> TraverseCoverageGraphWithLoops<'a> { } } -pub(super) fn find_loop_backedges( +fn find_loop_backedges( basic_coverage_blocks: &CoverageGraph, ) -> IndexVec<BasicCoverageBlock, Vec<BasicCoverageBlock>> { let num_bcbs = basic_coverage_blocks.num_nodes(); diff --git a/compiler/rustc_mir_transform/src/coverage/mappings.rs b/compiler/rustc_mir_transform/src/coverage/mappings.rs index 0e209757100..759bb7c1f9d 100644 --- a/compiler/rustc_mir_transform/src/coverage/mappings.rs +++ b/compiler/rustc_mir_transform/src/coverage/mappings.rs @@ -5,6 +5,7 @@ use rustc_index::bit_set::BitSet; use rustc_index::IndexVec; use rustc_middle::mir::coverage::{BlockMarkerId, BranchSpan, ConditionInfo, CoverageKind}; use rustc_middle::mir::{self, BasicBlock, StatementKind}; +use rustc_middle::ty::TyCtxt; use rustc_span::Span; use crate::coverage::graph::{BasicCoverageBlock, CoverageGraph, START_BCB}; @@ -63,31 +64,35 @@ pub(super) struct ExtractedMappings { /// Extracts coverage-relevant spans from MIR, and associates them with /// their corresponding BCBs. -pub(super) fn extract_all_mapping_info_from_mir( - mir_body: &mir::Body<'_>, +pub(super) fn extract_all_mapping_info_from_mir<'tcx>( + tcx: TyCtxt<'tcx>, + mir_body: &mir::Body<'tcx>, hir_info: &ExtractedHirInfo, basic_coverage_blocks: &CoverageGraph, ) -> ExtractedMappings { - if hir_info.is_async_fn { + let mut code_mappings = vec![]; + let mut branch_pairs = vec![]; + let mut mcdc_bitmap_bytes = 0; + let mut mcdc_branches = vec![]; + let mut mcdc_decisions = vec![]; + + if hir_info.is_async_fn || tcx.sess.coverage_no_mir_spans() { // An async function desugars into a function that returns a future, // with the user code wrapped in a closure. Any spans in the desugared // outer function will be unhelpful, so just keep the signature span // and ignore all of the spans in the MIR body. - let mut mappings = ExtractedMappings::default(); + // + // When debugging flag `-Zcoverage-options=no-mir-spans` is set, we need + // to give the same treatment to _all_ functions, because `llvm-cov` + // seems to ignore functions that don't have any ordinary code spans. if let Some(span) = hir_info.fn_sig_span_extended { - mappings.code_mappings.push(CodeMapping { span, bcb: START_BCB }); + code_mappings.push(CodeMapping { span, bcb: START_BCB }); } - return mappings; + } else { + // Extract coverage spans from MIR statements/terminators as normal. + extract_refined_covspans(mir_body, hir_info, basic_coverage_blocks, &mut code_mappings); } - let mut code_mappings = vec![]; - let mut branch_pairs = vec![]; - let mut mcdc_bitmap_bytes = 0; - let mut mcdc_branches = vec![]; - let mut mcdc_decisions = vec![]; - - extract_refined_covspans(mir_body, hir_info, basic_coverage_blocks, &mut code_mappings); - branch_pairs.extend(extract_branch_pairs(mir_body, hir_info, basic_coverage_blocks)); extract_mcdc_mappings( diff --git a/compiler/rustc_mir_transform/src/coverage/mod.rs b/compiler/rustc_mir_transform/src/coverage/mod.rs index 419e39bc386..4a64d21f3d1 100644 --- a/compiler/rustc_mir_transform/src/coverage/mod.rs +++ b/compiler/rustc_mir_transform/src/coverage/mod.rs @@ -71,8 +71,12 @@ fn instrument_function_for_coverage<'tcx>(tcx: TyCtxt<'tcx>, mir_body: &mut mir: //////////////////////////////////////////////////// // Extract coverage spans and other mapping info from MIR. - let extracted_mappings = - mappings::extract_all_mapping_info_from_mir(mir_body, &hir_info, &basic_coverage_blocks); + let extracted_mappings = mappings::extract_all_mapping_info_from_mir( + tcx, + mir_body, + &hir_info, + &basic_coverage_blocks, + ); //////////////////////////////////////////////////// // Create an optimized mix of `Counter`s and `Expression`s for the `CoverageGraph`. Ensure diff --git a/compiler/rustc_mir_transform/src/coverage/query.rs b/compiler/rustc_mir_transform/src/coverage/query.rs index 65715253647..25744009be8 100644 --- a/compiler/rustc_mir_transform/src/coverage/query.rs +++ b/compiler/rustc_mir_transform/src/coverage/query.rs @@ -49,7 +49,7 @@ fn is_eligible_for_coverage(tcx: TyCtxt<'_>, def_id: LocalDefId) -> bool { /// Query implementation for `coverage_ids_info`. fn coverage_ids_info<'tcx>( tcx: TyCtxt<'tcx>, - instance_def: ty::InstanceDef<'tcx>, + instance_def: ty::InstanceKind<'tcx>, ) -> CoverageIdsInfo { let mir_body = tcx.instance_mir(instance_def); diff --git a/compiler/rustc_mir_transform/src/coverage/spans.rs b/compiler/rustc_mir_transform/src/coverage/spans.rs index bb6a666ff73..84a70d1f02d 100644 --- a/compiler/rustc_mir_transform/src/coverage/spans.rs +++ b/compiler/rustc_mir_transform/src/coverage/spans.rs @@ -1,9 +1,15 @@ +use std::collections::VecDeque; + +use rustc_data_structures::captures::Captures; +use rustc_data_structures::fx::FxHashSet; use rustc_middle::mir; use rustc_span::Span; use crate::coverage::graph::{BasicCoverageBlock, CoverageGraph}; use crate::coverage::mappings; -use crate::coverage::spans::from_mir::SpanFromMir; +use crate::coverage::spans::from_mir::{ + extract_covspans_and_holes_from_mir, ExtractedCovspans, Hole, SpanFromMir, +}; use crate::coverage::ExtractedHirInfo; mod from_mir; @@ -19,50 +25,181 @@ pub(super) fn extract_refined_covspans( basic_coverage_blocks: &CoverageGraph, code_mappings: &mut impl Extend<mappings::CodeMapping>, ) { - let sorted_span_buckets = - from_mir::mir_to_initial_sorted_coverage_spans(mir_body, hir_info, basic_coverage_blocks); - for bucket in sorted_span_buckets { - let refined_spans = refine_sorted_spans(bucket); - code_mappings.extend(refined_spans.into_iter().map(|RefinedCovspan { span, bcb }| { + let ExtractedCovspans { mut covspans, mut holes } = + extract_covspans_and_holes_from_mir(mir_body, hir_info, basic_coverage_blocks); + + // First, perform the passes that need macro information. + covspans.sort_by(|a, b| basic_coverage_blocks.cmp_in_dominator_order(a.bcb, b.bcb)); + remove_unwanted_macro_spans(&mut covspans); + split_visible_macro_spans(&mut covspans); + + // We no longer need the extra information in `SpanFromMir`, so convert to `Covspan`. + let mut covspans = covspans.into_iter().map(SpanFromMir::into_covspan).collect::<Vec<_>>(); + + let compare_covspans = |a: &Covspan, b: &Covspan| { + compare_spans(a.span, b.span) + // After deduplication, we want to keep only the most-dominated BCB. + .then_with(|| basic_coverage_blocks.cmp_in_dominator_order(a.bcb, b.bcb).reverse()) + }; + covspans.sort_by(compare_covspans); + + // Among covspans with the same span, keep only one, + // preferring the one with the most-dominated BCB. + // (Ideally we should try to preserve _all_ non-dominating BCBs, but that + // requires a lot more complexity in the span refiner, for little benefit.) + covspans.dedup_by(|b, a| a.span.source_equal(b.span)); + + // Sort the holes, and merge overlapping/adjacent holes. + holes.sort_by(|a, b| compare_spans(a.span, b.span)); + holes.dedup_by(|b, a| a.merge_if_overlapping_or_adjacent(b)); + + // Split the covspans into separate buckets that don't overlap any holes. + let buckets = divide_spans_into_buckets(covspans, &holes); + + for mut covspans in buckets { + // Make sure each individual bucket is internally sorted. + covspans.sort_by(compare_covspans); + let _span = debug_span!("processing bucket", ?covspans).entered(); + + let mut covspans = remove_unwanted_overlapping_spans(covspans); + debug!(?covspans, "after removing overlaps"); + + // Do one last merge pass, to simplify the output. + covspans.dedup_by(|b, a| a.merge_if_eligible(b)); + debug!(?covspans, "after merge"); + + code_mappings.extend(covspans.into_iter().map(|Covspan { span, bcb }| { // Each span produced by the refiner represents an ordinary code region. mappings::CodeMapping { span, bcb } })); } } -#[derive(Debug)] -struct RefinedCovspan { - span: Span, - bcb: BasicCoverageBlock, +/// Macros that expand into branches (e.g. `assert!`, `trace!`) tend to generate +/// multiple condition/consequent blocks that have the span of the whole macro +/// invocation, which is unhelpful. Keeping only the first such span seems to +/// give better mappings, so remove the others. +/// +/// (The input spans should be sorted in BCB dominator order, so that the +/// retained "first" span is likely to dominate the others.) +fn remove_unwanted_macro_spans(covspans: &mut Vec<SpanFromMir>) { + let mut seen_macro_spans = FxHashSet::default(); + covspans.retain(|covspan| { + // Ignore (retain) non-macro-expansion spans. + if covspan.visible_macro.is_none() { + return true; + } + + // Retain only the first macro-expanded covspan with this span. + seen_macro_spans.insert(covspan.span) + }); } -impl RefinedCovspan { - fn is_mergeable(&self, other: &Self) -> bool { - self.bcb == other.bcb - } +/// When a span corresponds to a macro invocation that is visible from the +/// function body, split it into two parts. The first part covers just the +/// macro name plus `!`, and the second part covers the rest of the macro +/// invocation. This seems to give better results for code that uses macros. +fn split_visible_macro_spans(covspans: &mut Vec<SpanFromMir>) { + let mut extra_spans = vec![]; - fn merge_from(&mut self, other: &Self) { - debug_assert!(self.is_mergeable(other)); - self.span = self.span.to(other.span); + covspans.retain(|covspan| { + let Some(visible_macro) = covspan.visible_macro else { return true }; + + let split_len = visible_macro.as_str().len() as u32 + 1; + let (before, after) = covspan.span.split_at(split_len); + if !covspan.span.contains(before) || !covspan.span.contains(after) { + // Something is unexpectedly wrong with the split point. + // The debug assertion in `split_at` will have already caught this, + // but in release builds it's safer to do nothing and maybe get a + // bug report for unexpected coverage, rather than risk an ICE. + return true; + } + + extra_spans.push(SpanFromMir::new(before, covspan.visible_macro, covspan.bcb)); + extra_spans.push(SpanFromMir::new(after, covspan.visible_macro, covspan.bcb)); + false // Discard the original covspan that we just split. + }); + + // The newly-split spans are added at the end, so any previous sorting + // is not preserved. + covspans.extend(extra_spans); +} + +/// Uses the holes to divide the given covspans into buckets, such that: +/// - No span in any hole overlaps a bucket (truncating the spans if necessary). +/// - The spans in each bucket are strictly after all spans in previous buckets, +/// and strictly before all spans in subsequent buckets. +/// +/// The resulting buckets are sorted relative to each other, but might not be +/// internally sorted. +#[instrument(level = "debug")] +fn divide_spans_into_buckets(input_covspans: Vec<Covspan>, holes: &[Hole]) -> Vec<Vec<Covspan>> { + debug_assert!(input_covspans.is_sorted_by(|a, b| compare_spans(a.span, b.span).is_le())); + debug_assert!(holes.is_sorted_by(|a, b| compare_spans(a.span, b.span).is_le())); + + // Now we're ready to start carving holes out of the initial coverage spans, + // and grouping them in buckets separated by the holes. + + let mut input_covspans = VecDeque::from(input_covspans); + let mut fragments = vec![]; + + // For each hole: + // - Identify the spans that are entirely or partly before the hole. + // - Put those spans in a corresponding bucket, truncated to the start of the hole. + // - If one of those spans also extends after the hole, put the rest of it + // in a "fragments" vector that is processed by the next hole. + let mut buckets = (0..holes.len()).map(|_| vec![]).collect::<Vec<_>>(); + for (hole, bucket) in holes.iter().zip(&mut buckets) { + let fragments_from_prev = std::mem::take(&mut fragments); + + // Only inspect spans that precede or overlap this hole, + // leaving the rest to be inspected by later holes. + // (This relies on the spans and holes both being sorted.) + let relevant_input_covspans = + drain_front_while(&mut input_covspans, |c| c.span.lo() < hole.span.hi()); + + for covspan in fragments_from_prev.into_iter().chain(relevant_input_covspans) { + let (before, after) = covspan.split_around_hole_span(hole.span); + bucket.extend(before); + fragments.extend(after); + } } + + // After finding the spans before each hole, any remaining fragments/spans + // form their own final bucket, after the final hole. + // (If there were no holes, this will just be all of the initial spans.) + fragments.extend(input_covspans); + buckets.push(fragments); + + buckets +} + +/// Similar to `.drain(..)`, but stops just before it would remove an item not +/// satisfying the predicate. +fn drain_front_while<'a, T>( + queue: &'a mut VecDeque<T>, + mut pred_fn: impl FnMut(&T) -> bool, +) -> impl Iterator<Item = T> + Captures<'a> { + std::iter::from_fn(move || if pred_fn(queue.front()?) { queue.pop_front() } else { None }) } /// Takes one of the buckets of (sorted) spans extracted from MIR, and "refines" -/// those spans by removing spans that overlap in unwanted ways, and by merging -/// compatible adjacent spans. +/// those spans by removing spans that overlap in unwanted ways. #[instrument(level = "debug")] -fn refine_sorted_spans(sorted_spans: Vec<SpanFromMir>) -> Vec<RefinedCovspan> { +fn remove_unwanted_overlapping_spans(sorted_spans: Vec<Covspan>) -> Vec<Covspan> { + debug_assert!(sorted_spans.is_sorted_by(|a, b| compare_spans(a.span, b.span).is_le())); + // Holds spans that have been read from the input vector, but haven't yet // been committed to the output vector. let mut pending = vec![]; let mut refined = vec![]; for curr in sorted_spans { - pending.retain(|prev: &SpanFromMir| { + pending.retain(|prev: &Covspan| { if prev.span.hi() <= curr.span.lo() { // There's no overlap between the previous/current covspans, // so move the previous one into the refined list. - refined.push(RefinedCovspan { span: prev.span, bcb: prev.bcb }); + refined.push(prev.clone()); false } else { // Otherwise, retain the previous covspan only if it has the @@ -75,22 +212,57 @@ fn refine_sorted_spans(sorted_spans: Vec<SpanFromMir>) -> Vec<RefinedCovspan> { } // Drain the rest of the pending list into the refined list. - for prev in pending { - refined.push(RefinedCovspan { span: prev.span, bcb: prev.bcb }); + refined.extend(pending); + refined +} + +#[derive(Clone, Debug)] +struct Covspan { + span: Span, + bcb: BasicCoverageBlock, +} + +impl Covspan { + /// Splits this covspan into 0-2 parts: + /// - The part that is strictly before the hole span, if any. + /// - The part that is strictly after the hole span, if any. + fn split_around_hole_span(&self, hole_span: Span) -> (Option<Self>, Option<Self>) { + let before = try { + let span = self.span.trim_end(hole_span)?; + Self { span, ..*self } + }; + let after = try { + let span = self.span.trim_start(hole_span)?; + Self { span, ..*self } + }; + + (before, after) } - // Do one last merge pass, to simplify the output. - debug!(?refined, "before merge"); - refined.dedup_by(|b, a| { - if a.is_mergeable(b) { - debug!(?a, ?b, "merging list-adjacent refined spans"); - a.merge_from(b); - true - } else { - false + /// If `self` and `other` can be merged (i.e. they have the same BCB), + /// mutates `self.span` to also include `other.span` and returns true. + /// + /// Note that compatible covspans can be merged even if their underlying + /// spans are not overlapping/adjacent; any space between them will also be + /// part of the merged covspan. + fn merge_if_eligible(&mut self, other: &Self) -> bool { + if self.bcb != other.bcb { + return false; } - }); - debug!(?refined, "after merge"); - refined + self.span = self.span.to(other.span); + true + } +} + +/// Compares two spans in (lo ascending, hi descending) order. +fn compare_spans(a: Span, b: Span) -> std::cmp::Ordering { + // First sort by span start. + Ord::cmp(&a.lo(), &b.lo()) + // If span starts are the same, sort by span end in reverse order. + // This ensures that if spans A and B are adjacent in the list, + // and they overlap but are not equal, then either: + // - Span A extends further left, or + // - Both have the same start and span A extends further right + .then_with(|| Ord::cmp(&a.hi(), &b.hi()).reverse()) } diff --git a/compiler/rustc_mir_transform/src/coverage/spans/from_mir.rs b/compiler/rustc_mir_transform/src/coverage/spans/from_mir.rs index b1f71035dde..09deb7534bf 100644 --- a/compiler/rustc_mir_transform/src/coverage/spans/from_mir.rs +++ b/compiler/rustc_mir_transform/src/coverage/spans/from_mir.rs @@ -1,7 +1,3 @@ -use std::collections::VecDeque; - -use rustc_data_structures::captures::Captures; -use rustc_data_structures::fx::FxHashSet; use rustc_middle::bug; use rustc_middle::mir::coverage::CoverageKind; use rustc_middle::mir::{ @@ -13,25 +9,25 @@ use rustc_span::{ExpnKind, MacroKind, Span, Symbol}; use crate::coverage::graph::{ BasicCoverageBlock, BasicCoverageBlockData, CoverageGraph, START_BCB, }; +use crate::coverage::spans::Covspan; use crate::coverage::ExtractedHirInfo; +pub(crate) struct ExtractedCovspans { + pub(crate) covspans: Vec<SpanFromMir>, + pub(crate) holes: Vec<Hole>, +} + /// Traverses the MIR body to produce an initial collection of coverage-relevant /// spans, each associated with a node in the coverage graph (BCB) and possibly /// other metadata. -/// -/// The returned spans are divided into one or more buckets, such that: -/// - The spans in each bucket are strictly after all spans in previous buckets, -/// and strictly before all spans in subsequent buckets. -/// - The contents of each bucket are also sorted, in a specific order that is -/// expected by the subsequent span-refinement step. -pub(super) fn mir_to_initial_sorted_coverage_spans( +pub(crate) fn extract_covspans_and_holes_from_mir( mir_body: &mir::Body<'_>, hir_info: &ExtractedHirInfo, basic_coverage_blocks: &CoverageGraph, -) -> Vec<Vec<SpanFromMir>> { +) -> ExtractedCovspans { let &ExtractedHirInfo { body_span, .. } = hir_info; - let mut initial_spans = vec![]; + let mut covspans = vec![]; let mut holes = vec![]; for (bcb, bcb_data) in basic_coverage_blocks.iter_enumerated() { @@ -40,150 +36,21 @@ pub(super) fn mir_to_initial_sorted_coverage_spans( body_span, bcb, bcb_data, - &mut initial_spans, + &mut covspans, &mut holes, ); } // Only add the signature span if we found at least one span in the body. - if !initial_spans.is_empty() || !holes.is_empty() { + if !covspans.is_empty() || !holes.is_empty() { // If there is no usable signature span, add a fake one (before refinement) // to avoid an ugly gap between the body start and the first real span. // FIXME: Find a more principled way to solve this problem. let fn_sig_span = hir_info.fn_sig_span_extended.unwrap_or_else(|| body_span.shrink_to_lo()); - initial_spans.push(SpanFromMir::for_fn_sig(fn_sig_span)); - } - - initial_spans.sort_by(|a, b| basic_coverage_blocks.cmp_in_dominator_order(a.bcb, b.bcb)); - remove_unwanted_macro_spans(&mut initial_spans); - split_visible_macro_spans(&mut initial_spans); - - let compare_covspans = |a: &SpanFromMir, b: &SpanFromMir| { - compare_spans(a.span, b.span) - // After deduplication, we want to keep only the most-dominated BCB. - .then_with(|| basic_coverage_blocks.cmp_in_dominator_order(a.bcb, b.bcb).reverse()) - }; - initial_spans.sort_by(compare_covspans); - - // Among covspans with the same span, keep only one, - // preferring the one with the most-dominated BCB. - // (Ideally we should try to preserve _all_ non-dominating BCBs, but that - // requires a lot more complexity in the span refiner, for little benefit.) - initial_spans.dedup_by(|b, a| a.span.source_equal(b.span)); - - // Sort the holes, and merge overlapping/adjacent holes. - holes.sort_by(|a, b| compare_spans(a.span, b.span)); - holes.dedup_by(|b, a| a.merge_if_overlapping_or_adjacent(b)); - - // Now we're ready to start carving holes out of the initial coverage spans, - // and grouping them in buckets separated by the holes. - - let mut initial_spans = VecDeque::from(initial_spans); - let mut fragments: Vec<SpanFromMir> = vec![]; - - // For each hole: - // - Identify the spans that are entirely or partly before the hole. - // - Put those spans in a corresponding bucket, truncated to the start of the hole. - // - If one of those spans also extends after the hole, put the rest of it - // in a "fragments" vector that is processed by the next hole. - let mut buckets = (0..holes.len()).map(|_| vec![]).collect::<Vec<_>>(); - for (hole, bucket) in holes.iter().zip(&mut buckets) { - let fragments_from_prev = std::mem::take(&mut fragments); - - // Only inspect spans that precede or overlap this hole, - // leaving the rest to be inspected by later holes. - // (This relies on the spans and holes both being sorted.) - let relevant_initial_spans = - drain_front_while(&mut initial_spans, |c| c.span.lo() < hole.span.hi()); - - for covspan in fragments_from_prev.into_iter().chain(relevant_initial_spans) { - let (before, after) = covspan.split_around_hole_span(hole.span); - bucket.extend(before); - fragments.extend(after); - } + covspans.push(SpanFromMir::for_fn_sig(fn_sig_span)); } - // After finding the spans before each hole, any remaining fragments/spans - // form their own final bucket, after the final hole. - // (If there were no holes, this will just be all of the initial spans.) - fragments.extend(initial_spans); - buckets.push(fragments); - - // Make sure each individual bucket is still internally sorted. - for bucket in &mut buckets { - bucket.sort_by(compare_covspans); - } - buckets -} - -fn compare_spans(a: Span, b: Span) -> std::cmp::Ordering { - // First sort by span start. - Ord::cmp(&a.lo(), &b.lo()) - // If span starts are the same, sort by span end in reverse order. - // This ensures that if spans A and B are adjacent in the list, - // and they overlap but are not equal, then either: - // - Span A extends further left, or - // - Both have the same start and span A extends further right - .then_with(|| Ord::cmp(&a.hi(), &b.hi()).reverse()) -} - -/// Similar to `.drain(..)`, but stops just before it would remove an item not -/// satisfying the predicate. -fn drain_front_while<'a, T>( - queue: &'a mut VecDeque<T>, - mut pred_fn: impl FnMut(&T) -> bool, -) -> impl Iterator<Item = T> + Captures<'a> { - std::iter::from_fn(move || if pred_fn(queue.front()?) { queue.pop_front() } else { None }) -} - -/// Macros that expand into branches (e.g. `assert!`, `trace!`) tend to generate -/// multiple condition/consequent blocks that have the span of the whole macro -/// invocation, which is unhelpful. Keeping only the first such span seems to -/// give better mappings, so remove the others. -/// -/// (The input spans should be sorted in BCB dominator order, so that the -/// retained "first" span is likely to dominate the others.) -fn remove_unwanted_macro_spans(initial_spans: &mut Vec<SpanFromMir>) { - let mut seen_macro_spans = FxHashSet::default(); - initial_spans.retain(|covspan| { - // Ignore (retain) non-macro-expansion spans. - if covspan.visible_macro.is_none() { - return true; - } - - // Retain only the first macro-expanded covspan with this span. - seen_macro_spans.insert(covspan.span) - }); -} - -/// When a span corresponds to a macro invocation that is visible from the -/// function body, split it into two parts. The first part covers just the -/// macro name plus `!`, and the second part covers the rest of the macro -/// invocation. This seems to give better results for code that uses macros. -fn split_visible_macro_spans(initial_spans: &mut Vec<SpanFromMir>) { - let mut extra_spans = vec![]; - - initial_spans.retain(|covspan| { - let Some(visible_macro) = covspan.visible_macro else { return true }; - - let split_len = visible_macro.as_str().len() as u32 + 1; - let (before, after) = covspan.span.split_at(split_len); - if !covspan.span.contains(before) || !covspan.span.contains(after) { - // Something is unexpectedly wrong with the split point. - // The debug assertion in `split_at` will have already caught this, - // but in release builds it's safer to do nothing and maybe get a - // bug report for unexpected coverage, rather than risk an ICE. - return true; - } - - extra_spans.push(SpanFromMir::new(before, covspan.visible_macro, covspan.bcb)); - extra_spans.push(SpanFromMir::new(after, covspan.visible_macro, covspan.bcb)); - false // Discard the original covspan that we just split. - }); - - // The newly-split spans are added at the end, so any previous sorting - // is not preserved. - initial_spans.extend(extra_spans); + ExtractedCovspans { covspans, holes } } // Generate a set of coverage spans from the filtered set of `Statement`s and `Terminator`s of @@ -402,12 +269,12 @@ fn unexpand_into_body_span_with_prev( } #[derive(Debug)] -struct Hole { - span: Span, +pub(crate) struct Hole { + pub(crate) span: Span, } impl Hole { - fn merge_if_overlapping_or_adjacent(&mut self, other: &mut Self) -> bool { + pub(crate) fn merge_if_overlapping_or_adjacent(&mut self, other: &mut Self) -> bool { if !self.span.overlaps_or_adjacent(other.span) { return false; } @@ -418,7 +285,7 @@ impl Hole { } #[derive(Debug)] -pub(super) struct SpanFromMir { +pub(crate) struct SpanFromMir { /// A span that has been extracted from MIR and then "un-expanded" back to /// within the current function's `body_span`. After various intermediate /// processing steps, this span is emitted as part of the final coverage @@ -426,9 +293,9 @@ pub(super) struct SpanFromMir { /// /// With the exception of `fn_sig_span`, this should always be contained /// within `body_span`. - pub(super) span: Span, - visible_macro: Option<Symbol>, - pub(super) bcb: BasicCoverageBlock, + pub(crate) span: Span, + pub(crate) visible_macro: Option<Symbol>, + pub(crate) bcb: BasicCoverageBlock, } impl SpanFromMir { @@ -436,23 +303,12 @@ impl SpanFromMir { Self::new(fn_sig_span, None, START_BCB) } - fn new(span: Span, visible_macro: Option<Symbol>, bcb: BasicCoverageBlock) -> Self { + pub(crate) fn new(span: Span, visible_macro: Option<Symbol>, bcb: BasicCoverageBlock) -> Self { Self { span, visible_macro, bcb } } - /// Splits this span into 0-2 parts: - /// - The part that is strictly before the hole span, if any. - /// - The part that is strictly after the hole span, if any. - fn split_around_hole_span(&self, hole_span: Span) -> (Option<Self>, Option<Self>) { - let before = try { - let span = self.span.trim_end(hole_span)?; - Self { span, ..*self } - }; - let after = try { - let span = self.span.trim_start(hole_span)?; - Self { span, ..*self } - }; - - (before, after) + pub(crate) fn into_covspan(self) -> Covspan { + let Self { span, visible_macro: _, bcb } = self; + Covspan { span, bcb } } } diff --git a/compiler/rustc_mir_transform/src/coverage/tests.rs b/compiler/rustc_mir_transform/src/coverage/tests.rs index ca64688e6b8..048547dc9f5 100644 --- a/compiler/rustc_mir_transform/src/coverage/tests.rs +++ b/compiler/rustc_mir_transform/src/coverage/tests.rs @@ -24,7 +24,6 @@ //! globals is comparatively simpler. The easiest way is to wrap the test in a closure argument //! to: `rustc_span::create_default_session_globals_then(|| { test_here(); })`. -use super::counters; use super::graph::{self, BasicCoverageBlock}; use itertools::Itertools; @@ -551,108 +550,3 @@ fn test_covgraph_switchint_loop_then_inner_loop_else_break() { assert_successors(&basic_coverage_blocks, bcb(5), &[bcb(1)]); assert_successors(&basic_coverage_blocks, bcb(6), &[bcb(4)]); } - -#[test] -fn test_find_loop_backedges_none() { - let mir_body = goto_switchint(); - let basic_coverage_blocks = graph::CoverageGraph::from_mir(&mir_body); - if false { - eprintln!( - "basic_coverage_blocks = {:?}", - basic_coverage_blocks.iter_enumerated().collect::<Vec<_>>() - ); - eprintln!("successors = {:?}", basic_coverage_blocks.successors); - } - let backedges = graph::find_loop_backedges(&basic_coverage_blocks); - assert_eq!( - backedges.iter_enumerated().map(|(_bcb, backedges)| backedges.len()).sum::<usize>(), - 0, - "backedges: {:?}", - backedges - ); -} - -#[test] -fn test_find_loop_backedges_one() { - let mir_body = switchint_then_loop_else_return(); - let basic_coverage_blocks = graph::CoverageGraph::from_mir(&mir_body); - let backedges = graph::find_loop_backedges(&basic_coverage_blocks); - assert_eq!( - backedges.iter_enumerated().map(|(_bcb, backedges)| backedges.len()).sum::<usize>(), - 1, - "backedges: {:?}", - backedges - ); - - assert_eq!(backedges[bcb(1)], &[bcb(3)]); -} - -#[test] -fn test_find_loop_backedges_two() { - let mir_body = switchint_loop_then_inner_loop_else_break(); - let basic_coverage_blocks = graph::CoverageGraph::from_mir(&mir_body); - let backedges = graph::find_loop_backedges(&basic_coverage_blocks); - assert_eq!( - backedges.iter_enumerated().map(|(_bcb, backedges)| backedges.len()).sum::<usize>(), - 2, - "backedges: {:?}", - backedges - ); - - assert_eq!(backedges[bcb(1)], &[bcb(5)]); - assert_eq!(backedges[bcb(4)], &[bcb(6)]); -} - -#[test] -fn test_traverse_coverage_with_loops() { - let mir_body = switchint_loop_then_inner_loop_else_break(); - let basic_coverage_blocks = graph::CoverageGraph::from_mir(&mir_body); - let mut traversed_in_order = Vec::new(); - let mut traversal = graph::TraverseCoverageGraphWithLoops::new(&basic_coverage_blocks); - while let Some(bcb) = traversal.next() { - traversed_in_order.push(bcb); - } - - // bcb0 is visited first. Then bcb1 starts the first loop, and all remaining nodes, *except* - // bcb6 are inside the first loop. - assert_eq!( - *traversed_in_order.last().expect("should have elements"), - bcb(6), - "bcb6 should not be visited until all nodes inside the first loop have been visited" - ); -} - -#[test] -fn test_make_bcb_counters() { - rustc_span::create_default_session_globals_then(|| { - let mir_body = goto_switchint(); - let basic_coverage_blocks = graph::CoverageGraph::from_mir(&mir_body); - // Historically this test would use `spans` internals to set up fake - // coverage spans for BCBs 1 and 2. Now we skip that step and just tell - // BCB counter construction that those BCBs have spans. - let bcb_has_coverage_spans = |bcb: BasicCoverageBlock| (1..=2).contains(&bcb.as_usize()); - let coverage_counters = counters::CoverageCounters::make_bcb_counters( - &basic_coverage_blocks, - bcb_has_coverage_spans, - ); - assert_eq!(coverage_counters.num_expressions(), 0); - - assert_eq!( - 0, // bcb1 has a `Counter` with id = 0 - match coverage_counters.bcb_counter(bcb(1)).expect("should have a counter") { - counters::BcbCounter::Counter { id, .. } => id, - _ => panic!("expected a Counter"), - } - .as_u32() - ); - - assert_eq!( - 1, // bcb2 has a `Counter` with id = 1 - match coverage_counters.bcb_counter(bcb(2)).expect("should have a counter") { - counters::BcbCounter::Counter { id, .. } => id, - _ => panic!("expected a Counter"), - } - .as_u32() - ); - }); -} diff --git a/compiler/rustc_mir_transform/src/errors.rs b/compiler/rustc_mir_transform/src/errors.rs index b28dcb38cb6..dc7648d27b5 100644 --- a/compiler/rustc_mir_transform/src/errors.rs +++ b/compiler/rustc_mir_transform/src/errors.rs @@ -104,7 +104,7 @@ impl<'a> LintDiagnostic<'a, ()> for MustNotSupend<'_, '_> { diag.primary_message(fluent::mir_transform_must_not_suspend); diag.span_label(self.yield_sp, fluent::_subdiag::label); if let Some(reason) = self.reason { - diag.subdiagnostic(diag.dcx, reason); + diag.subdiagnostic(reason); } diag.span_help(self.src_sp, fluent::_subdiag::help); diag.arg("pre", self.pre); diff --git a/compiler/rustc_mir_transform/src/inline.rs b/compiler/rustc_mir_transform/src/inline.rs index 2cbe0a01e9e..d04bb8d302e 100644 --- a/compiler/rustc_mir_transform/src/inline.rs +++ b/compiler/rustc_mir_transform/src/inline.rs @@ -10,7 +10,7 @@ use rustc_middle::middle::codegen_fn_attrs::{CodegenFnAttrFlags, CodegenFnAttrs} use rustc_middle::mir::visit::*; use rustc_middle::mir::*; use rustc_middle::ty::TypeVisitableExt; -use rustc_middle::ty::{self, Instance, InstanceDef, ParamEnv, Ty, TyCtxt}; +use rustc_middle::ty::{self, Instance, InstanceKind, ParamEnv, Ty, TyCtxt}; use rustc_session::config::{DebugInfo, OptLevel}; use rustc_span::source_map::Spanned; use rustc_span::sym; @@ -293,7 +293,7 @@ impl<'tcx> Inliner<'tcx> { } match callee.def { - InstanceDef::Item(_) => { + InstanceKind::Item(_) => { // If there is no MIR available (either because it was not in metadata or // because it has no MIR because it's an extern function), then the inliner // won't cause cycles on this. @@ -302,24 +302,24 @@ impl<'tcx> Inliner<'tcx> { } } // These have no own callable MIR. - InstanceDef::Intrinsic(_) | InstanceDef::Virtual(..) => { + InstanceKind::Intrinsic(_) | InstanceKind::Virtual(..) => { return Err("instance without MIR (intrinsic / virtual)"); } // This cannot result in an immediate cycle since the callee MIR is a shim, which does // not get any optimizations run on it. Any subsequent inlining may cause cycles, but we // do not need to catch this here, we can wait until the inliner decides to continue // inlining a second time. - InstanceDef::VTableShim(_) - | InstanceDef::ReifyShim(..) - | InstanceDef::FnPtrShim(..) - | InstanceDef::ClosureOnceShim { .. } - | InstanceDef::ConstructCoroutineInClosureShim { .. } - | InstanceDef::CoroutineKindShim { .. } - | InstanceDef::DropGlue(..) - | InstanceDef::CloneShim(..) - | InstanceDef::ThreadLocalShim(..) - | InstanceDef::FnPtrAddrShim(..) - | InstanceDef::AsyncDropGlueCtorShim(..) => return Ok(()), + InstanceKind::VTableShim(_) + | InstanceKind::ReifyShim(..) + | InstanceKind::FnPtrShim(..) + | InstanceKind::ClosureOnceShim { .. } + | InstanceKind::ConstructCoroutineInClosureShim { .. } + | InstanceKind::CoroutineKindShim { .. } + | InstanceKind::DropGlue(..) + | InstanceKind::CloneShim(..) + | InstanceKind::ThreadLocalShim(..) + | InstanceKind::FnPtrAddrShim(..) + | InstanceKind::AsyncDropGlueCtorShim(..) => return Ok(()), } if self.tcx.is_constructor(callee_def_id) { @@ -372,7 +372,7 @@ impl<'tcx> Inliner<'tcx> { let callee = Instance::resolve(self.tcx, self.param_env, def_id, args).ok().flatten()?; - if let InstanceDef::Virtual(..) | InstanceDef::Intrinsic(_) = callee.def { + if let InstanceKind::Virtual(..) | InstanceKind::Intrinsic(_) = callee.def { return None; } @@ -384,7 +384,7 @@ impl<'tcx> Inliner<'tcx> { // Additionally, check that the body that we're inlining actually agrees // with the ABI of the trait that the item comes from. - if let InstanceDef::Item(instance_def_id) = callee.def + if let InstanceKind::Item(instance_def_id) = callee.def && self.tcx.def_kind(instance_def_id) == DefKind::AssocFn && let instance_fn_sig = self.tcx.fn_sig(instance_def_id).skip_binder() && instance_fn_sig.abi() != fn_sig.abi() @@ -1063,10 +1063,10 @@ impl<'tcx> MutVisitor<'tcx> for Integrator<'_, 'tcx> { #[instrument(skip(tcx), level = "debug")] fn try_instance_mir<'tcx>( tcx: TyCtxt<'tcx>, - instance: InstanceDef<'tcx>, + instance: InstanceKind<'tcx>, ) -> Result<&'tcx Body<'tcx>, &'static str> { - if let ty::InstanceDef::DropGlue(_, Some(ty)) - | ty::InstanceDef::AsyncDropGlueCtorShim(_, Some(ty)) = instance + if let ty::InstanceKind::DropGlue(_, Some(ty)) + | ty::InstanceKind::AsyncDropGlueCtorShim(_, Some(ty)) = instance && let ty::Adt(def, args) = ty.kind() { let fields = def.all_fields(); diff --git a/compiler/rustc_mir_transform/src/inline/cycle.rs b/compiler/rustc_mir_transform/src/inline/cycle.rs index 8c5f965108b..35bcd24ce95 100644 --- a/compiler/rustc_mir_transform/src/inline/cycle.rs +++ b/compiler/rustc_mir_transform/src/inline/cycle.rs @@ -3,7 +3,7 @@ use rustc_data_structures::stack::ensure_sufficient_stack; use rustc_hir::def_id::{DefId, LocalDefId}; use rustc_middle::mir::TerminatorKind; use rustc_middle::ty::TypeVisitableExt; -use rustc_middle::ty::{self, GenericArgsRef, InstanceDef, TyCtxt}; +use rustc_middle::ty::{self, GenericArgsRef, InstanceKind, TyCtxt}; use rustc_session::Limit; use rustc_span::sym; @@ -22,7 +22,7 @@ pub(crate) fn mir_callgraph_reachable<'tcx>( "you should not call `mir_callgraph_reachable` on immediate self recursion" ); assert!( - matches!(root.def, InstanceDef::Item(_)), + matches!(root.def, InstanceKind::Item(_)), "you should not call `mir_callgraph_reachable` on shims" ); assert!( @@ -70,7 +70,7 @@ pub(crate) fn mir_callgraph_reachable<'tcx>( } match callee.def { - InstanceDef::Item(_) => { + InstanceKind::Item(_) => { // If there is no MIR available (either because it was not in metadata or // because it has no MIR because it's an extern function), then the inliner // won't cause cycles on this. @@ -80,24 +80,24 @@ pub(crate) fn mir_callgraph_reachable<'tcx>( } } // These have no own callable MIR. - InstanceDef::Intrinsic(_) | InstanceDef::Virtual(..) => continue, + InstanceKind::Intrinsic(_) | InstanceKind::Virtual(..) => continue, // These have MIR and if that MIR is inlined, instantiated and then inlining is run // again, a function item can end up getting inlined. Thus we'll be able to cause // a cycle that way - InstanceDef::VTableShim(_) - | InstanceDef::ReifyShim(..) - | InstanceDef::FnPtrShim(..) - | InstanceDef::ClosureOnceShim { .. } - | InstanceDef::ConstructCoroutineInClosureShim { .. } - | InstanceDef::CoroutineKindShim { .. } - | InstanceDef::ThreadLocalShim { .. } - | InstanceDef::CloneShim(..) => {} + InstanceKind::VTableShim(_) + | InstanceKind::ReifyShim(..) + | InstanceKind::FnPtrShim(..) + | InstanceKind::ClosureOnceShim { .. } + | InstanceKind::ConstructCoroutineInClosureShim { .. } + | InstanceKind::CoroutineKindShim { .. } + | InstanceKind::ThreadLocalShim { .. } + | InstanceKind::CloneShim(..) => {} // This shim does not call any other functions, thus there can be no recursion. - InstanceDef::FnPtrAddrShim(..) => { + InstanceKind::FnPtrAddrShim(..) => { continue; } - InstanceDef::DropGlue(..) | InstanceDef::AsyncDropGlueCtorShim(..) => { + InstanceKind::DropGlue(..) | InstanceKind::AsyncDropGlueCtorShim(..) => { // FIXME: A not fully instantiated drop shim can cause ICEs if one attempts to // have its MIR built. Likely oli-obk just screwed up the `ParamEnv`s, so this // needs some more analysis. @@ -151,12 +151,12 @@ pub(crate) fn mir_callgraph_reachable<'tcx>( pub(crate) fn mir_inliner_callees<'tcx>( tcx: TyCtxt<'tcx>, - instance: ty::InstanceDef<'tcx>, + instance: ty::InstanceKind<'tcx>, ) -> &'tcx [(DefId, GenericArgsRef<'tcx>)] { let steal; let guard; let body = match (instance, instance.def_id().as_local()) { - (InstanceDef::Item(_), Some(def_id)) => { + (InstanceKind::Item(_), Some(def_id)) => { steal = tcx.mir_promoted(def_id).0; guard = steal.borrow(); &*guard diff --git a/compiler/rustc_mir_transform/src/lib.rs b/compiler/rustc_mir_transform/src/lib.rs index 3c0f4e9142b..afba6781a70 100644 --- a/compiler/rustc_mir_transform/src/lib.rs +++ b/compiler/rustc_mir_transform/src/lib.rs @@ -398,7 +398,7 @@ fn mir_drops_elaborated_and_const_checked(tcx: TyCtxt<'_>, def: LocalDefId) -> & if is_fn_like { // Do not compute the mir call graph without said call graph actually being used. if pm::should_run_pass(tcx, &inline::Inline) { - tcx.ensure_with_value().mir_inliner_callees(ty::InstanceDef::Item(def.to_def_id())); + tcx.ensure_with_value().mir_inliner_callees(ty::InstanceKind::Item(def.to_def_id())); } } diff --git a/compiler/rustc_mir_transform/src/shim.rs b/compiler/rustc_mir_transform/src/shim.rs index d03c2d18c0c..825f8957187 100644 --- a/compiler/rustc_mir_transform/src/shim.rs +++ b/compiler/rustc_mir_transform/src/shim.rs @@ -29,16 +29,16 @@ pub fn provide(providers: &mut Providers) { providers.mir_shims = make_shim; } -fn make_shim<'tcx>(tcx: TyCtxt<'tcx>, instance: ty::InstanceDef<'tcx>) -> Body<'tcx> { +fn make_shim<'tcx>(tcx: TyCtxt<'tcx>, instance: ty::InstanceKind<'tcx>) -> Body<'tcx> { debug!("make_shim({:?})", instance); let mut result = match instance { - ty::InstanceDef::Item(..) => bug!("item {:?} passed to make_shim", instance), - ty::InstanceDef::VTableShim(def_id) => { + ty::InstanceKind::Item(..) => bug!("item {:?} passed to make_shim", instance), + ty::InstanceKind::VTableShim(def_id) => { let adjustment = Adjustment::Deref { source: DerefSource::MutPtr }; build_call_shim(tcx, instance, Some(adjustment), CallKind::Direct(def_id)) } - ty::InstanceDef::FnPtrShim(def_id, ty) => { + ty::InstanceKind::FnPtrShim(def_id, ty) => { let trait_ = tcx.trait_of_item(def_id).unwrap(); // Supports `Fn` or `async Fn` traits. let adjustment = match tcx @@ -58,10 +58,10 @@ fn make_shim<'tcx>(tcx: TyCtxt<'tcx>, instance: ty::InstanceDef<'tcx>) -> Body<' // a virtual call, or a direct call to a function for which // indirect calls must be codegen'd differently than direct ones // (such as `#[track_caller]`). - ty::InstanceDef::ReifyShim(def_id, _) => { + ty::InstanceKind::ReifyShim(def_id, _) => { build_call_shim(tcx, instance, None, CallKind::Direct(def_id)) } - ty::InstanceDef::ClosureOnceShim { call_once: _, track_caller: _ } => { + ty::InstanceKind::ClosureOnceShim { call_once: _, track_caller: _ } => { let fn_mut = tcx.require_lang_item(LangItem::FnMut, None); let call_mut = tcx .associated_items(fn_mut) @@ -73,16 +73,16 @@ fn make_shim<'tcx>(tcx: TyCtxt<'tcx>, instance: ty::InstanceDef<'tcx>) -> Body<' build_call_shim(tcx, instance, Some(Adjustment::RefMut), CallKind::Direct(call_mut)) } - ty::InstanceDef::ConstructCoroutineInClosureShim { + ty::InstanceKind::ConstructCoroutineInClosureShim { coroutine_closure_def_id, receiver_by_ref, } => build_construct_coroutine_by_move_shim(tcx, coroutine_closure_def_id, receiver_by_ref), - ty::InstanceDef::CoroutineKindShim { coroutine_def_id } => { + ty::InstanceKind::CoroutineKindShim { coroutine_def_id } => { return tcx.optimized_mir(coroutine_def_id).coroutine_by_move_body().unwrap().clone(); } - ty::InstanceDef::DropGlue(def_id, ty) => { + ty::InstanceKind::DropGlue(def_id, ty) => { // FIXME(#91576): Drop shims for coroutines aren't subject to the MIR passes at the end // of this function. Is this intentional? if let Some(ty::Coroutine(coroutine_def_id, args)) = ty.map(Ty::kind) { @@ -127,16 +127,16 @@ fn make_shim<'tcx>(tcx: TyCtxt<'tcx>, instance: ty::InstanceDef<'tcx>) -> Body<' build_drop_shim(tcx, def_id, ty) } - ty::InstanceDef::ThreadLocalShim(..) => build_thread_local_shim(tcx, instance), - ty::InstanceDef::CloneShim(def_id, ty) => build_clone_shim(tcx, def_id, ty), - ty::InstanceDef::FnPtrAddrShim(def_id, ty) => build_fn_ptr_addr_shim(tcx, def_id, ty), - ty::InstanceDef::AsyncDropGlueCtorShim(def_id, ty) => { + ty::InstanceKind::ThreadLocalShim(..) => build_thread_local_shim(tcx, instance), + ty::InstanceKind::CloneShim(def_id, ty) => build_clone_shim(tcx, def_id, ty), + ty::InstanceKind::FnPtrAddrShim(def_id, ty) => build_fn_ptr_addr_shim(tcx, def_id, ty), + ty::InstanceKind::AsyncDropGlueCtorShim(def_id, ty) => { async_destructor_ctor::build_async_destructor_ctor_shim(tcx, def_id, ty) } - ty::InstanceDef::Virtual(..) => { - bug!("InstanceDef::Virtual ({:?}) is for direct calls only", instance) + ty::InstanceKind::Virtual(..) => { + bug!("InstanceKind::Virtual ({:?}) is for direct calls only", instance) } - ty::InstanceDef::Intrinsic(_) => { + ty::InstanceKind::Intrinsic(_) => { bug!("creating shims from intrinsics ({:?}) is unsupported", instance) } }; @@ -240,7 +240,7 @@ fn build_drop_shim<'tcx>(tcx: TyCtxt<'tcx>, def_id: DefId, ty: Option<Ty<'tcx>>) block(&mut blocks, TerminatorKind::Goto { target: return_block }); block(&mut blocks, TerminatorKind::Return); - let source = MirSource::from_instance(ty::InstanceDef::DropGlue(def_id, ty)); + let source = MirSource::from_instance(ty::InstanceKind::DropGlue(def_id, ty)); let mut body = new_body(source, blocks, local_decls_for_sig(&sig, span), sig.inputs().len(), span); @@ -392,7 +392,10 @@ impl<'a, 'tcx> DropElaborator<'a, 'tcx> for DropShimElaborator<'a, 'tcx> { } } -fn build_thread_local_shim<'tcx>(tcx: TyCtxt<'tcx>, instance: ty::InstanceDef<'tcx>) -> Body<'tcx> { +fn build_thread_local_shim<'tcx>( + tcx: TyCtxt<'tcx>, + instance: ty::InstanceKind<'tcx>, +) -> Body<'tcx> { let def_id = instance.def_id(); let span = tcx.def_span(def_id); @@ -472,7 +475,7 @@ impl<'tcx> CloneShimBuilder<'tcx> { } fn into_mir(self) -> Body<'tcx> { - let source = MirSource::from_instance(ty::InstanceDef::CloneShim( + let source = MirSource::from_instance(ty::InstanceKind::CloneShim( self.def_id, self.sig.inputs_and_output[0], )); @@ -682,14 +685,14 @@ impl<'tcx> CloneShimBuilder<'tcx> { #[instrument(level = "debug", skip(tcx), ret)] fn build_call_shim<'tcx>( tcx: TyCtxt<'tcx>, - instance: ty::InstanceDef<'tcx>, + instance: ty::InstanceKind<'tcx>, rcvr_adjustment: Option<Adjustment>, call_kind: CallKind<'tcx>, ) -> Body<'tcx> { // `FnPtrShim` contains the fn pointer type that a call shim is being built for - this is used // to instantiate into the signature of the shim. It is not necessary for users of this - // MIR body to perform further instantiations (see `InstanceDef::has_polymorphic_mir_body`). - let (sig_args, untuple_args) = if let ty::InstanceDef::FnPtrShim(_, ty) = instance { + // MIR body to perform further instantiations (see `InstanceKind::has_polymorphic_mir_body`). + let (sig_args, untuple_args) = if let ty::InstanceKind::FnPtrShim(_, ty) = instance { let sig = tcx.instantiate_bound_regions_with_erased(ty.fn_sig(tcx)); let untuple_args = sig.inputs(); @@ -741,8 +744,8 @@ fn build_call_shim<'tcx>( } // FIXME(eddyb) avoid having this snippet both here and in - // `Instance::fn_sig` (introduce `InstanceDef::fn_sig`?). - if let ty::InstanceDef::VTableShim(..) = instance { + // `Instance::fn_sig` (introduce `InstanceKind::fn_sig`?). + if let ty::InstanceKind::VTableShim(..) = instance { // Modify fn(self, ...) to fn(self: *mut Self, ...) let mut inputs_and_output = sig.inputs_and_output.to_vec(); let self_arg = &mut inputs_and_output[0]; @@ -1007,7 +1010,7 @@ fn build_fn_ptr_addr_shim<'tcx>(tcx: TyCtxt<'tcx>, def_id: DefId, self_ty: Ty<'t terminator: Some(Terminator { source_info, kind: TerminatorKind::Return }), is_cleanup: false, }; - let source = MirSource::from_instance(ty::InstanceDef::FnPtrAddrShim(def_id, self_ty)); + let source = MirSource::from_instance(ty::InstanceKind::FnPtrAddrShim(def_id, self_ty)); new_body(source, IndexVec::from_elem_n(start_block, 1), locals, sig.inputs().len(), span) } @@ -1087,7 +1090,7 @@ fn build_construct_coroutine_by_move_shim<'tcx>( is_cleanup: false, }; - let source = MirSource::from_instance(ty::InstanceDef::ConstructCoroutineInClosureShim { + let source = MirSource::from_instance(ty::InstanceKind::ConstructCoroutineInClosureShim { coroutine_closure_def_id, receiver_by_ref, }); 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 41643f20285..ea4f5fca59e 100644 --- a/compiler/rustc_mir_transform/src/shim/async_destructor_ctor.rs +++ b/compiler/rustc_mir_transform/src/shim/async_destructor_ctor.rs @@ -529,7 +529,7 @@ impl<'tcx> AsyncDestructorCtorShimBuilder<'tcx> { last_bb.terminator = Some(Terminator { source_info, kind: TerminatorKind::Return }); - let source = MirSource::from_instance(ty::InstanceDef::AsyncDropGlueCtorShim( + let source = MirSource::from_instance(ty::InstanceKind::AsyncDropGlueCtorShim( self.def_id, self.self_ty, )); diff --git a/compiler/rustc_mir_transform/src/validate.rs b/compiler/rustc_mir_transform/src/validate.rs index ea23bbc2a38..2cca1a6f507 100644 --- a/compiler/rustc_mir_transform/src/validate.rs +++ b/compiler/rustc_mir_transform/src/validate.rs @@ -10,7 +10,7 @@ use rustc_middle::mir::visit::{NonUseContext, PlaceContext, Visitor}; use rustc_middle::mir::*; use rustc_middle::ty::adjustment::PointerCoercion; use rustc_middle::ty::{ - self, CoroutineArgsExt, InstanceDef, ParamEnv, ScalarInt, Ty, TyCtxt, TypeVisitableExt, + self, CoroutineArgsExt, InstanceKind, ParamEnv, ScalarInt, Ty, TyCtxt, TypeVisitableExt, Variance, }; use rustc_middle::{bug, span_bug}; @@ -44,7 +44,7 @@ impl<'tcx> MirPass<'tcx> for Validator { // terribly important that they pass the validator. However, I think other passes might // still see them, in which case they might be surprised. It would probably be better if we // didn't put this through the MIR pipeline at all. - if matches!(body.source.instance, InstanceDef::Intrinsic(..) | InstanceDef::Virtual(..)) { + if matches!(body.source.instance, InstanceKind::Intrinsic(..) | InstanceKind::Virtual(..)) { return; } let def_id = body.source.def_id(); @@ -95,7 +95,7 @@ impl<'tcx> MirPass<'tcx> for Validator { } if let MirPhase::Runtime(_) = body.phase { - if let ty::InstanceDef::Item(_) = body.source.instance { + if let ty::InstanceKind::Item(_) = body.source.instance { if body.has_free_regions() { cfg_checker.fail( Location::START, diff --git a/compiler/rustc_monomorphize/src/collector.rs b/compiler/rustc_monomorphize/src/collector.rs index 04de1654c1a..235743fccc8 100644 --- a/compiler/rustc_monomorphize/src/collector.rs +++ b/compiler/rustc_monomorphize/src/collector.rs @@ -224,7 +224,7 @@ use rustc_middle::ty::adjustment::{CustomCoerceUnsized, PointerCoercion}; use rustc_middle::ty::layout::ValidityRequirement; use rustc_middle::ty::print::with_no_trimmed_paths; use rustc_middle::ty::{ - self, AssocKind, GenericParamDefKind, Instance, InstanceDef, Ty, TyCtxt, TypeFoldable, + self, AssocKind, GenericParamDefKind, Instance, InstanceKind, Ty, TyCtxt, TypeFoldable, TypeVisitableExt, VtblEntry, }; use rustc_middle::ty::{GenericArgKind, GenericArgs}; @@ -420,7 +420,7 @@ fn collect_items_rec<'tcx>( used_items.push(respan( starting_item.span, MonoItem::Fn(Instance { - def: InstanceDef::ThreadLocalShim(def_id), + def: InstanceKind::ThreadLocalShim(def_id), args: GenericArgs::empty(), }), )); @@ -938,7 +938,7 @@ fn visit_instance_use<'tcx>( if !should_codegen_locally(tcx, instance) { return; } - if let ty::InstanceDef::Intrinsic(def_id) = instance.def { + if let ty::InstanceKind::Intrinsic(def_id) = instance.def { let name = tcx.item_name(def_id); if let Some(_requirement) = ValidityRequirement::from_intrinsic(name) { // The intrinsics assert_inhabited, assert_zero_valid, and assert_mem_uninitialized_valid will @@ -960,31 +960,31 @@ fn visit_instance_use<'tcx>( } match instance.def { - ty::InstanceDef::Virtual(..) | ty::InstanceDef::Intrinsic(_) => { + ty::InstanceKind::Virtual(..) | ty::InstanceKind::Intrinsic(_) => { if !is_direct_call { bug!("{:?} being reified", instance); } } - ty::InstanceDef::ThreadLocalShim(..) => { + ty::InstanceKind::ThreadLocalShim(..) => { bug!("{:?} being reified", instance); } - ty::InstanceDef::DropGlue(_, None) | ty::InstanceDef::AsyncDropGlueCtorShim(_, None) => { + ty::InstanceKind::DropGlue(_, None) | ty::InstanceKind::AsyncDropGlueCtorShim(_, None) => { // Don't need to emit noop drop glue if we are calling directly. if !is_direct_call { output.push(create_fn_mono_item(tcx, instance, source)); } } - ty::InstanceDef::DropGlue(_, Some(_)) - | ty::InstanceDef::AsyncDropGlueCtorShim(_, Some(_)) - | ty::InstanceDef::VTableShim(..) - | ty::InstanceDef::ReifyShim(..) - | ty::InstanceDef::ClosureOnceShim { .. } - | ty::InstanceDef::ConstructCoroutineInClosureShim { .. } - | ty::InstanceDef::CoroutineKindShim { .. } - | ty::InstanceDef::Item(..) - | ty::InstanceDef::FnPtrShim(..) - | ty::InstanceDef::CloneShim(..) - | ty::InstanceDef::FnPtrAddrShim(..) => { + ty::InstanceKind::DropGlue(_, Some(_)) + | ty::InstanceKind::AsyncDropGlueCtorShim(_, Some(_)) + | ty::InstanceKind::VTableShim(..) + | ty::InstanceKind::ReifyShim(..) + | ty::InstanceKind::ClosureOnceShim { .. } + | ty::InstanceKind::ConstructCoroutineInClosureShim { .. } + | ty::InstanceKind::CoroutineKindShim { .. } + | ty::InstanceKind::Item(..) + | ty::InstanceKind::FnPtrShim(..) + | ty::InstanceKind::CloneShim(..) + | ty::InstanceKind::FnPtrAddrShim(..) => { output.push(create_fn_mono_item(tcx, instance, source)); } } diff --git a/compiler/rustc_monomorphize/src/errors.rs b/compiler/rustc_monomorphize/src/errors.rs index 35fc78f2045..c0d1efd96c5 100644 --- a/compiler/rustc_monomorphize/src/errors.rs +++ b/compiler/rustc_monomorphize/src/errors.rs @@ -1,7 +1,7 @@ use std::path::PathBuf; use crate::fluent_generated as fluent; -use rustc_errors::{Diag, DiagCtxt, Diagnostic, EmissionGuarantee, Level}; +use rustc_errors::{Diag, DiagCtxtHandle, Diagnostic, EmissionGuarantee, Level}; use rustc_macros::{Diagnostic, LintDiagnostic}; use rustc_span::{Span, Symbol}; @@ -48,7 +48,7 @@ pub struct UnusedGenericParamsHint { impl<G: EmissionGuarantee> Diagnostic<'_, G> for UnusedGenericParamsHint { #[track_caller] - fn into_diag(self, dcx: &'_ DiagCtxt, level: Level) -> Diag<'_, G> { + fn into_diag(self, dcx: DiagCtxtHandle<'_>, level: Level) -> Diag<'_, G> { let mut diag = Diag::new(dcx, level, fluent::monomorphize_unused_generic_params); diag.span(self.span); for (span, name) in self.param_spans.into_iter().zip(self.param_names) { diff --git a/compiler/rustc_monomorphize/src/partitioning.rs b/compiler/rustc_monomorphize/src/partitioning.rs index 14b5b22dc64..9a7c488833a 100644 --- a/compiler/rustc_monomorphize/src/partitioning.rs +++ b/compiler/rustc_monomorphize/src/partitioning.rs @@ -114,7 +114,7 @@ use rustc_middle::mir::mono::{ }; use rustc_middle::query::Providers; use rustc_middle::ty::print::{characteristic_def_id_of_type, with_no_trimmed_paths}; -use rustc_middle::ty::{self, visit::TypeVisitableExt, InstanceDef, TyCtxt}; +use rustc_middle::ty::{self, visit::TypeVisitableExt, InstanceKind, TyCtxt}; use rustc_session::config::{DumpMonoStatsFormat, SwitchWithOptPath}; use rustc_session::CodegenUnits; use rustc_span::symbol::Symbol; @@ -620,20 +620,20 @@ fn characteristic_def_id_of_mono_item<'tcx>( match mono_item { MonoItem::Fn(instance) => { let def_id = match instance.def { - ty::InstanceDef::Item(def) => def, - ty::InstanceDef::VTableShim(..) - | ty::InstanceDef::ReifyShim(..) - | ty::InstanceDef::FnPtrShim(..) - | ty::InstanceDef::ClosureOnceShim { .. } - | ty::InstanceDef::ConstructCoroutineInClosureShim { .. } - | ty::InstanceDef::CoroutineKindShim { .. } - | ty::InstanceDef::Intrinsic(..) - | ty::InstanceDef::DropGlue(..) - | ty::InstanceDef::Virtual(..) - | ty::InstanceDef::CloneShim(..) - | ty::InstanceDef::ThreadLocalShim(..) - | ty::InstanceDef::FnPtrAddrShim(..) - | ty::InstanceDef::AsyncDropGlueCtorShim(..) => return None, + ty::InstanceKind::Item(def) => def, + ty::InstanceKind::VTableShim(..) + | ty::InstanceKind::ReifyShim(..) + | ty::InstanceKind::FnPtrShim(..) + | ty::InstanceKind::ClosureOnceShim { .. } + | ty::InstanceKind::ConstructCoroutineInClosureShim { .. } + | ty::InstanceKind::CoroutineKindShim { .. } + | ty::InstanceKind::Intrinsic(..) + | ty::InstanceKind::DropGlue(..) + | ty::InstanceKind::Virtual(..) + | ty::InstanceKind::CloneShim(..) + | ty::InstanceKind::ThreadLocalShim(..) + | ty::InstanceKind::FnPtrAddrShim(..) + | ty::InstanceKind::AsyncDropGlueCtorShim(..) => return None, }; // If this is a method, we want to put it into the same module as @@ -777,28 +777,28 @@ fn mono_item_visibility<'tcx>( }; let def_id = match instance.def { - InstanceDef::Item(def_id) - | InstanceDef::DropGlue(def_id, Some(_)) - | InstanceDef::AsyncDropGlueCtorShim(def_id, Some(_)) => def_id, + InstanceKind::Item(def_id) + | InstanceKind::DropGlue(def_id, Some(_)) + | InstanceKind::AsyncDropGlueCtorShim(def_id, Some(_)) => def_id, // We match the visibility of statics here - InstanceDef::ThreadLocalShim(def_id) => { + InstanceKind::ThreadLocalShim(def_id) => { return static_visibility(tcx, can_be_internalized, def_id); } // These are all compiler glue and such, never exported, always hidden. - InstanceDef::VTableShim(..) - | InstanceDef::ReifyShim(..) - | InstanceDef::FnPtrShim(..) - | InstanceDef::Virtual(..) - | InstanceDef::Intrinsic(..) - | InstanceDef::ClosureOnceShim { .. } - | InstanceDef::ConstructCoroutineInClosureShim { .. } - | InstanceDef::CoroutineKindShim { .. } - | InstanceDef::DropGlue(..) - | InstanceDef::AsyncDropGlueCtorShim(..) - | InstanceDef::CloneShim(..) - | InstanceDef::FnPtrAddrShim(..) => return Visibility::Hidden, + InstanceKind::VTableShim(..) + | InstanceKind::ReifyShim(..) + | InstanceKind::FnPtrShim(..) + | InstanceKind::Virtual(..) + | InstanceKind::Intrinsic(..) + | InstanceKind::ClosureOnceShim { .. } + | InstanceKind::ConstructCoroutineInClosureShim { .. } + | InstanceKind::CoroutineKindShim { .. } + | InstanceKind::DropGlue(..) + | InstanceKind::AsyncDropGlueCtorShim(..) + | InstanceKind::CloneShim(..) + | InstanceKind::FnPtrAddrShim(..) => return Visibility::Hidden, }; // The `start_fn` lang item is actually a monomorphized instance of a @@ -813,7 +813,7 @@ fn mono_item_visibility<'tcx>( // internalization, but we have to understand that it's referenced // from the `main` symbol we'll generate later. // - // This may be fixable with a new `InstanceDef` perhaps? Unsure! + // This may be fixable with a new `InstanceKind` perhaps? Unsure! 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 c187cb63ee1..2d69bfa4da8 100644 --- a/compiler/rustc_monomorphize/src/polymorphize.rs +++ b/compiler/rustc_monomorphize/src/polymorphize.rs @@ -33,7 +33,7 @@ pub fn provide(providers: &mut Providers) { /// parameters are used). fn unused_generic_params<'tcx>( tcx: TyCtxt<'tcx>, - instance: ty::InstanceDef<'tcx>, + instance: ty::InstanceKind<'tcx>, ) -> UnusedGenericParams { assert!(instance.def_id().is_local()); @@ -88,7 +88,7 @@ fn unused_generic_params<'tcx>( fn should_polymorphize<'tcx>( tcx: TyCtxt<'tcx>, def_id: DefId, - instance: ty::InstanceDef<'tcx>, + instance: ty::InstanceKind<'tcx>, ) -> bool { // If an instance's MIR body is not polymorphic then the modified generic parameters that are // derived from polymorphization's result won't make any difference. @@ -97,7 +97,7 @@ fn should_polymorphize<'tcx>( } // Don't polymorphize intrinsics or virtual calls - calling `instance_mir` will panic. - if matches!(instance, ty::InstanceDef::Intrinsic(..) | ty::InstanceDef::Virtual(..)) { + if matches!(instance, ty::InstanceKind::Intrinsic(..) | ty::InstanceKind::Virtual(..)) { return false; } @@ -230,7 +230,7 @@ impl<'a, 'tcx> MarkUsedGenericParams<'a, 'tcx> { /// a closure, coroutine or constant). #[instrument(level = "debug", skip(self, def_id, args))] fn visit_child_body(&mut self, def_id: DefId, args: GenericArgsRef<'tcx>) { - let instance = ty::InstanceDef::Item(def_id); + let instance = ty::InstanceKind::Item(def_id); let unused = self.tcx.unused_generic_params(instance); debug!(?self.unused_parameters, ?unused); for (i, arg) in args.iter().enumerate() { diff --git a/compiler/rustc_next_trait_solver/Cargo.toml b/compiler/rustc_next_trait_solver/Cargo.toml index 50dbc991f8f..3a5f438b432 100644 --- a/compiler/rustc_next_trait_solver/Cargo.toml +++ b/compiler/rustc_next_trait_solver/Cargo.toml @@ -5,9 +5,25 @@ edition = "2021" [dependencies] # tidy-alphabetical-start +bitflags = "2.4.1" +derivative = "2.2.0" +rustc_ast_ir = { path = "../rustc_ast_ir" } +rustc_data_structures = { path = "../rustc_data_structures", optional = true } +rustc_index = { path = "../rustc_index", default-features = false } +rustc_macros = { path = "../rustc_macros", optional = true } +rustc_serialize = { path = "../rustc_serialize", optional = true } rustc_type_ir = { path = "../rustc_type_ir", default-features = false } +rustc_type_ir_macros = { path = "../rustc_type_ir_macros" } +tracing = "0.1" # tidy-alphabetical-end [features] default = ["nightly"] -nightly = ["rustc_type_ir/nightly"] +nightly = [ + "rustc_ast_ir/nightly", + "rustc_data_structures", + "rustc_index/nightly", + "rustc_macros", + "rustc_serialize", + "rustc_type_ir/nightly", +] diff --git a/compiler/rustc_next_trait_solver/src/canonicalizer.rs b/compiler/rustc_next_trait_solver/src/canonicalizer.rs index f22e24ef654..a81fd03d034 100644 --- a/compiler/rustc_next_trait_solver/src/canonicalizer.rs +++ b/compiler/rustc_next_trait_solver/src/canonicalizer.rs @@ -4,10 +4,11 @@ use rustc_type_ir::fold::{TypeFoldable, TypeFolder, TypeSuperFoldable}; use rustc_type_ir::inherent::*; use rustc_type_ir::visit::TypeVisitableExt; use rustc_type_ir::{ - self as ty, Canonical, CanonicalTyVarKind, CanonicalVarInfo, CanonicalVarKind, InferCtxtLike, - Interner, + self as ty, Canonical, CanonicalTyVarKind, CanonicalVarInfo, CanonicalVarKind, Interner, }; +use crate::infcx::SolverDelegate; + /// Whether we're canonicalizing a query input or the query response. /// /// When canonicalizing an input we're in the context of the caller @@ -37,7 +38,7 @@ pub enum CanonicalizeMode { }, } -pub struct Canonicalizer<'a, Infcx: InferCtxtLike<Interner = I>, I: Interner> { +pub struct Canonicalizer<'a, Infcx: SolverDelegate<Interner = I>, I: Interner> { infcx: &'a Infcx, canonicalize_mode: CanonicalizeMode, @@ -46,7 +47,7 @@ pub struct Canonicalizer<'a, Infcx: InferCtxtLike<Interner = I>, I: Interner> { binder_index: ty::DebruijnIndex, } -impl<'a, Infcx: InferCtxtLike<Interner = I>, I: Interner> Canonicalizer<'a, Infcx, I> { +impl<'a, Infcx: SolverDelegate<Interner = I>, I: Interner> Canonicalizer<'a, Infcx, I> { pub fn canonicalize<T: TypeFoldable<I>>( infcx: &'a Infcx, canonicalize_mode: CanonicalizeMode, @@ -210,7 +211,7 @@ impl<'a, Infcx: InferCtxtLike<Interner = I>, I: Interner> Canonicalizer<'a, Infc } } -impl<Infcx: InferCtxtLike<Interner = I>, I: Interner> TypeFolder<I> +impl<Infcx: SolverDelegate<Interner = I>, I: Interner> TypeFolder<I> for Canonicalizer<'_, Infcx, I> { fn interner(&self) -> I { diff --git a/compiler/rustc_next_trait_solver/src/infcx.rs b/compiler/rustc_next_trait_solver/src/infcx.rs new file mode 100644 index 00000000000..c249eb94cf6 --- /dev/null +++ b/compiler/rustc_next_trait_solver/src/infcx.rs @@ -0,0 +1,205 @@ +use std::fmt::Debug; + +use rustc_type_ir::fold::TypeFoldable; +use rustc_type_ir::relate::Relate; +use rustc_type_ir::solve::{Certainty, Goal, NoSolution, SolverMode}; +use rustc_type_ir::{self as ty, Interner}; + +pub trait SolverDelegate: Sized { + type Interner: Interner; + fn interner(&self) -> Self::Interner; + + type Span: Copy; + + fn solver_mode(&self) -> SolverMode; + + fn build_with_canonical<V>( + interner: Self::Interner, + solver_mode: SolverMode, + canonical: &ty::Canonical<Self::Interner, V>, + ) -> (Self, V, ty::CanonicalVarValues<Self::Interner>) + where + V: TypeFoldable<Self::Interner>; + + fn universe(&self) -> ty::UniverseIndex; + fn create_next_universe(&self) -> ty::UniverseIndex; + + fn universe_of_ty(&self, ty: ty::TyVid) -> Option<ty::UniverseIndex>; + fn universe_of_lt(&self, lt: ty::RegionVid) -> Option<ty::UniverseIndex>; + fn universe_of_ct(&self, ct: ty::ConstVid) -> Option<ty::UniverseIndex>; + + 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) -> <Self::Interner as Interner>::Ty; + fn opportunistic_resolve_int_var(&self, vid: ty::IntVid) -> <Self::Interner as Interner>::Ty; + fn opportunistic_resolve_float_var( + &self, + vid: ty::FloatVid, + ) -> <Self::Interner as Interner>::Ty; + fn opportunistic_resolve_ct_var( + &self, + vid: ty::ConstVid, + ) -> <Self::Interner as Interner>::Const; + fn opportunistic_resolve_effect_var( + &self, + vid: ty::EffectVid, + ) -> <Self::Interner as Interner>::Const; + fn opportunistic_resolve_lt_var( + &self, + vid: ty::RegionVid, + ) -> <Self::Interner as Interner>::Region; + + fn defining_opaque_types(&self) -> <Self::Interner as Interner>::DefiningOpaqueTypes; + + fn next_ty_infer(&self) -> <Self::Interner as Interner>::Ty; + fn next_const_infer(&self) -> <Self::Interner as Interner>::Const; + fn fresh_args_for_item( + &self, + def_id: <Self::Interner as Interner>::DefId, + ) -> <Self::Interner as Interner>::GenericArgs; + + fn fresh_var_for_kind_with_span( + &self, + arg: <Self::Interner as Interner>::GenericArg, + span: Self::Span, + ) -> <Self::Interner as Interner>::GenericArg; + + fn instantiate_binder_with_infer<T: TypeFoldable<Self::Interner> + Copy>( + &self, + value: ty::Binder<Self::Interner, T>, + ) -> T; + + fn enter_forall<T: TypeFoldable<Self::Interner> + Copy, U>( + &self, + value: ty::Binder<Self::Interner, T>, + f: impl FnOnce(T) -> U, + ) -> U; + + fn relate<T: Relate<Self::Interner>>( + &self, + param_env: <Self::Interner as Interner>::ParamEnv, + lhs: T, + variance: ty::Variance, + rhs: T, + ) -> Result<Vec<Goal<Self::Interner, <Self::Interner as Interner>::Predicate>>, NoSolution>; + + fn eq_structurally_relating_aliases<T: Relate<Self::Interner>>( + &self, + param_env: <Self::Interner as Interner>::ParamEnv, + lhs: T, + rhs: T, + ) -> Result<Vec<Goal<Self::Interner, <Self::Interner as Interner>::Predicate>>, NoSolution>; + + fn resolve_vars_if_possible<T>(&self, value: T) -> T + where + T: TypeFoldable<Self::Interner>; + + fn probe<T>(&self, probe: impl FnOnce() -> T) -> T; + + // FIXME: Uplift the leak check into this crate. + fn leak_check(&self, max_input_universe: ty::UniverseIndex) -> Result<(), NoSolution>; + + // FIXME: This is only here because elaboration lives in `rustc_infer`! + fn elaborate_supertraits( + interner: Self::Interner, + trait_ref: ty::Binder<Self::Interner, ty::TraitRef<Self::Interner>>, + ) -> impl Iterator<Item = ty::Binder<Self::Interner, ty::TraitRef<Self::Interner>>>; + + fn try_const_eval_resolve( + &self, + param_env: <Self::Interner as Interner>::ParamEnv, + unevaluated: ty::UnevaluatedConst<Self::Interner>, + ) -> Option<<Self::Interner as Interner>::Const>; + + fn sub_regions( + &self, + sub: <Self::Interner as Interner>::Region, + sup: <Self::Interner as Interner>::Region, + ); + + fn register_ty_outlives( + &self, + ty: <Self::Interner as Interner>::Ty, + r: <Self::Interner as Interner>::Region, + ); + + // FIXME: This only is here because `wf::obligations` is in `rustc_trait_selection`! + fn well_formed_goals( + &self, + param_env: <Self::Interner as Interner>::ParamEnv, + arg: <Self::Interner as Interner>::GenericArg, + ) -> Option<Vec<Goal<Self::Interner, <Self::Interner as Interner>::Predicate>>>; + + fn clone_opaque_types_for_query_response( + &self, + ) -> Vec<(ty::OpaqueTypeKey<Self::Interner>, <Self::Interner as Interner>::Ty)>; + + fn make_deduplicated_outlives_constraints( + &self, + ) -> Vec<ty::OutlivesPredicate<Self::Interner, <Self::Interner as Interner>::GenericArg>>; + + fn instantiate_canonical<V>( + &self, + canonical: ty::Canonical<Self::Interner, V>, + values: ty::CanonicalVarValues<Self::Interner>, + ) -> V + where + V: TypeFoldable<Self::Interner>; + + fn instantiate_canonical_var_with_infer( + &self, + cv_info: ty::CanonicalVarInfo<Self::Interner>, + universe_map: impl Fn(ty::UniverseIndex) -> ty::UniverseIndex, + ) -> <Self::Interner as Interner>::GenericArg; + + // FIXME: Can we implement this in terms of `add` and `inject`? + fn insert_hidden_type( + &self, + opaque_type_key: ty::OpaqueTypeKey<Self::Interner>, + param_env: <Self::Interner as Interner>::ParamEnv, + hidden_ty: <Self::Interner as Interner>::Ty, + goals: &mut Vec<Goal<Self::Interner, <Self::Interner as Interner>::Predicate>>, + ) -> Result<(), NoSolution>; + + fn add_item_bounds_for_hidden_type( + &self, + def_id: <Self::Interner as Interner>::DefId, + args: <Self::Interner as Interner>::GenericArgs, + param_env: <Self::Interner as Interner>::ParamEnv, + hidden_ty: <Self::Interner as Interner>::Ty, + goals: &mut Vec<Goal<Self::Interner, <Self::Interner as Interner>::Predicate>>, + ); + + fn inject_new_hidden_type_unchecked( + &self, + key: ty::OpaqueTypeKey<Self::Interner>, + hidden_ty: <Self::Interner as Interner>::Ty, + ); + + fn reset_opaque_types(&self); + + fn trait_ref_is_knowable<E: Debug>( + &self, + trait_ref: ty::TraitRef<Self::Interner>, + lazily_normalize_ty: impl FnMut( + <Self::Interner as Interner>::Ty, + ) -> Result<<Self::Interner as Interner>::Ty, E>, + ) -> Result<bool, E>; + + fn fetch_eligible_assoc_item( + &self, + param_env: <Self::Interner as Interner>::ParamEnv, + goal_trait_ref: ty::TraitRef<Self::Interner>, + trait_assoc_def_id: <Self::Interner as Interner>::DefId, + impl_def_id: <Self::Interner as Interner>::DefId, + ) -> Result<Option<<Self::Interner as Interner>::DefId>, NoSolution>; + + fn is_transmutable( + &self, + param_env: <Self::Interner as Interner>::ParamEnv, + dst: <Self::Interner as Interner>::Ty, + src: <Self::Interner as Interner>::Ty, + assume: <Self::Interner as Interner>::Const, + ) -> Result<Certainty, NoSolution>; +} diff --git a/compiler/rustc_next_trait_solver/src/lib.rs b/compiler/rustc_next_trait_solver/src/lib.rs index b913a05095c..79c6925221e 100644 --- a/compiler/rustc_next_trait_solver/src/lib.rs +++ b/compiler/rustc_next_trait_solver/src/lib.rs @@ -1,3 +1,12 @@ +//! Crate containing the implementation of the next-generation trait solver. +//! +//! This crate may also contain things that are used by the old trait solver, +//! but were uplifted in the process of making the new trait solver generic. +//! So if you got to this crate from the old solver, it's totally normal. + +#![feature(let_chains)] + pub mod canonicalizer; +pub mod infcx; pub mod resolve; pub mod solve; diff --git a/compiler/rustc_next_trait_solver/src/resolve.rs b/compiler/rustc_next_trait_solver/src/resolve.rs index 5c00b6978d6..3d8d957eaae 100644 --- a/compiler/rustc_next_trait_solver/src/resolve.rs +++ b/compiler/rustc_next_trait_solver/src/resolve.rs @@ -1,27 +1,28 @@ +use crate::infcx::SolverDelegate; use rustc_type_ir::fold::{TypeFoldable, TypeFolder, TypeSuperFoldable}; use rustc_type_ir::inherent::*; use rustc_type_ir::visit::TypeVisitableExt; -use rustc_type_ir::{self as ty, InferCtxtLike, Interner}; +use rustc_type_ir::{self as ty, Interner}; /////////////////////////////////////////////////////////////////////////// // EAGER RESOLUTION /// Resolves ty, region, and const vars to their inferred values or their root vars. -pub struct EagerResolver<'a, Infcx, I = <Infcx as InferCtxtLike>::Interner> +pub struct EagerResolver<'a, Infcx, I = <Infcx as SolverDelegate>::Interner> where - Infcx: InferCtxtLike<Interner = I>, + Infcx: SolverDelegate<Interner = I>, I: Interner, { infcx: &'a Infcx, } -impl<'a, Infcx: InferCtxtLike> EagerResolver<'a, Infcx> { +impl<'a, Infcx: SolverDelegate> EagerResolver<'a, Infcx> { pub fn new(infcx: &'a Infcx) -> Self { EagerResolver { infcx } } } -impl<Infcx: InferCtxtLike<Interner = I>, I: Interner> TypeFolder<I> for EagerResolver<'_, Infcx> { +impl<Infcx: SolverDelegate<Interner = I>, I: Interner> TypeFolder<I> for EagerResolver<'_, Infcx> { fn interner(&self) -> I { self.infcx.interner() } diff --git a/compiler/rustc_next_trait_solver/src/solve.rs b/compiler/rustc_next_trait_solver/src/solve.rs deleted file mode 100644 index eba96facabc..00000000000 --- a/compiler/rustc_next_trait_solver/src/solve.rs +++ /dev/null @@ -1 +0,0 @@ -pub use rustc_type_ir::solve::*; diff --git a/compiler/rustc_trait_selection/src/solve/alias_relate.rs b/compiler/rustc_next_trait_solver/src/solve/alias_relate.rs index 4e52caa5a5b..fbc8ac1d5d5 100644 --- a/compiler/rustc_trait_selection/src/solve/alias_relate.rs +++ b/compiler/rustc_next_trait_solver/src/solve/alias_relate.rs @@ -15,17 +15,23 @@ //! (3.) Otherwise, if we end with two rigid (non-projection) or infer types, //! relate them structurally. -use super::EvalCtxt; -use rustc_infer::infer::InferCtxt; -use rustc_middle::traits::solve::{Certainty, Goal, QueryResult}; -use rustc_middle::ty; +use rustc_type_ir::inherent::*; +use rustc_type_ir::{self as ty, Interner}; +use tracing::{instrument, trace}; -impl<'tcx> EvalCtxt<'_, InferCtxt<'tcx>> { +use crate::infcx::SolverDelegate; +use crate::solve::{Certainty, EvalCtxt, Goal, QueryResult}; + +impl<Infcx, I> EvalCtxt<'_, Infcx> +where + Infcx: SolverDelegate<Interner = I>, + I: Interner, +{ #[instrument(level = "trace", skip(self), ret)] pub(super) fn compute_alias_relate_goal( &mut self, - goal: Goal<'tcx, (ty::Term<'tcx>, ty::Term<'tcx>, ty::AliasRelationDirection)>, - ) -> QueryResult<'tcx> { + goal: Goal<I, (I::Term, I::Term, ty::AliasRelationDirection)>, + ) -> QueryResult<I> { let tcx = self.interner(); let Goal { param_env, predicate: (lhs, rhs, direction) } = goal; debug_assert!(lhs.to_alias_term().is_some() || rhs.to_alias_term().is_some()); diff --git a/compiler/rustc_trait_selection/src/solve/assembly/mod.rs b/compiler/rustc_next_trait_solver/src/solve/assembly/mod.rs index 1cdbf082078..9a1537d2606 100644 --- a/compiler/rustc_trait_selection/src/solve/assembly/mod.rs +++ b/compiler/rustc_next_trait_solver/src/solve/assembly/mod.rs @@ -1,33 +1,26 @@ //! 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::{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 rustc_type_ir::solve::{CandidateSource, CanonicalResponse}; -use rustc_type_ir::Interner; - -use crate::solve::GoalSource; -use crate::solve::{EvalCtxt, SolverMode}; - pub(super) mod structural_traits; +use rustc_type_ir::fold::TypeFoldable; +use rustc_type_ir::inherent::*; +use rustc_type_ir::lang_items::TraitSolverLangItem; +use rustc_type_ir::visit::TypeVisitableExt as _; +use rustc_type_ir::{self as ty, Interner, Upcast as _}; +use tracing::{debug, instrument}; + +use crate::infcx::SolverDelegate; +use crate::solve::inspect::ProbeKind; +use crate::solve::{ + BuiltinImplSource, CandidateSource, CanonicalResponse, Certainty, EvalCtxt, Goal, GoalSource, + MaybeCause, NoSolution, QueryResult, SolverMode, +}; + /// A candidate is a possible way to prove a goal. /// /// It consists of both the `source`, which describes how that goal would be proven, /// and the `result` when using the given `source`. -#[derive(Derivative)] +#[derive(derivative::Derivative)] #[derivative(Debug(bound = ""), Clone(bound = ""))] pub(super) struct Candidate<I: Interner> { pub(super) source: CandidateSource<I>, @@ -35,39 +28,42 @@ pub(super) struct Candidate<I: Interner> { } /// Methods used to assemble candidates for either trait or projection goals. -pub(super) trait GoalKind<'tcx>: - TypeFoldable<TyCtxt<'tcx>> + Copy + Eq + std::fmt::Display +pub(super) trait GoalKind<Infcx, I = <Infcx as SolverDelegate>::Interner>: + TypeFoldable<I> + Copy + Eq + std::fmt::Display +where + Infcx: SolverDelegate<Interner = I>, + I: Interner, { - fn self_ty(self) -> Ty<'tcx>; + fn self_ty(self) -> I::Ty; - fn trait_ref(self, tcx: TyCtxt<'tcx>) -> ty::TraitRef<'tcx>; + fn trait_ref(self, tcx: I) -> ty::TraitRef<I>; - fn with_self_ty(self, tcx: TyCtxt<'tcx>, self_ty: Ty<'tcx>) -> Self; + fn with_self_ty(self, tcx: I, self_ty: I::Ty) -> Self; - fn trait_def_id(self, tcx: TyCtxt<'tcx>) -> DefId; + fn trait_def_id(self, tcx: I) -> I::DefId; /// Try equating an assumption predicate against a goal's predicate. If it /// holds, then execute the `then` callback, which should do any additional /// work, then produce a response (typically by executing /// [`EvalCtxt::evaluate_added_goals_and_make_canonical_response`]). fn probe_and_match_goal_against_assumption( - ecx: &mut EvalCtxt<'_, InferCtxt<'tcx>>, - source: CandidateSource<TyCtxt<'tcx>>, - goal: Goal<'tcx, Self>, - assumption: ty::Clause<'tcx>, - then: impl FnOnce(&mut EvalCtxt<'_, InferCtxt<'tcx>>) -> QueryResult<'tcx>, - ) -> Result<Candidate<TyCtxt<'tcx>>, NoSolution>; + ecx: &mut EvalCtxt<'_, Infcx>, + source: CandidateSource<I>, + goal: Goal<I, Self>, + assumption: I::Clause, + then: impl FnOnce(&mut EvalCtxt<'_, Infcx>) -> QueryResult<I>, + ) -> Result<Candidate<I>, 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<TyCtxt<'tcx>>, - goal: Goal<'tcx, Self>, - assumption: ty::Clause<'tcx>, - requirements: impl IntoIterator<Item = (GoalSource, Goal<'tcx, ty::Predicate<'tcx>>)>, - ) -> Result<Candidate<TyCtxt<'tcx>>, NoSolution> { + ecx: &mut EvalCtxt<'_, Infcx>, + parent_source: CandidateSource<I>, + goal: Goal<I, Self>, + assumption: I::Clause, + requirements: impl IntoIterator<Item = (GoalSource, Goal<I, I::Predicate>)>, + ) -> Result<Candidate<I>, 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); @@ -80,15 +76,15 @@ pub(super) trait GoalKind<'tcx>: /// additionally checking all of the supertraits and object bounds to hold, /// 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<TyCtxt<'tcx>>, - goal: Goal<'tcx, Self>, - assumption: ty::Clause<'tcx>, - ) -> Result<Candidate<TyCtxt<'tcx>>, NoSolution> { + ecx: &mut EvalCtxt<'_, Infcx>, + source: CandidateSource<I>, + goal: Goal<I, Self>, + assumption: I::Clause, + ) -> Result<Candidate<I>, 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 { - bug!("expected object type in `probe_and_consider_object_bound_candidate`"); + let ty::Dynamic(bounds, _, _) = goal.predicate.self_ty().kind() else { + panic!("expected object type in `probe_and_consider_object_bound_candidate`"); }; ecx.add_goals( GoalSource::ImplWhereBound, @@ -104,10 +100,10 @@ pub(super) trait GoalKind<'tcx>: } fn consider_impl_candidate( - ecx: &mut EvalCtxt<'_, InferCtxt<'tcx>>, - goal: Goal<'tcx, Self>, - impl_def_id: DefId, - ) -> Result<Candidate<TyCtxt<'tcx>>, NoSolution>; + ecx: &mut EvalCtxt<'_, Infcx>, + goal: Goal<I, Self>, + impl_def_id: I::DefId, + ) -> Result<Candidate<I>, 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 @@ -116,85 +112,85 @@ pub(super) trait GoalKind<'tcx>: /// Trait goals always hold while projection goals never do. This is a bit arbitrary /// but prevents incorrect normalization while hiding any trait errors. fn consider_error_guaranteed_candidate( - ecx: &mut EvalCtxt<'_, InferCtxt<'tcx>>, - guar: ErrorGuaranteed, - ) -> Result<Candidate<TyCtxt<'tcx>>, NoSolution>; + ecx: &mut EvalCtxt<'_, Infcx>, + guar: I::ErrorGuaranteed, + ) -> Result<Candidate<I>, NoSolution>; /// A type implements an `auto trait` if its components do as well. /// /// These components are given by built-in rules from /// [`structural_traits::instantiate_constituent_tys_for_auto_trait`]. fn consider_auto_trait_candidate( - ecx: &mut EvalCtxt<'_, InferCtxt<'tcx>>, - goal: Goal<'tcx, Self>, - ) -> Result<Candidate<TyCtxt<'tcx>>, NoSolution>; + ecx: &mut EvalCtxt<'_, Infcx>, + goal: Goal<I, Self>, + ) -> Result<Candidate<I>, 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<Candidate<TyCtxt<'tcx>>, NoSolution>; + ecx: &mut EvalCtxt<'_, Infcx>, + goal: Goal<I, Self>, + ) -> Result<Candidate<I>, NoSolution>; /// A type is `Sized` if its tail component is `Sized`. /// /// These components are given by built-in rules from /// [`structural_traits::instantiate_constituent_tys_for_sized_trait`]. fn consider_builtin_sized_candidate( - ecx: &mut EvalCtxt<'_, InferCtxt<'tcx>>, - goal: Goal<'tcx, Self>, - ) -> Result<Candidate<TyCtxt<'tcx>>, NoSolution>; + ecx: &mut EvalCtxt<'_, Infcx>, + goal: Goal<I, Self>, + ) -> Result<Candidate<I>, NoSolution>; /// A type is `Copy` or `Clone` if its components are `Copy` or `Clone`. /// /// These components are given by built-in rules from /// [`structural_traits::instantiate_constituent_tys_for_copy_clone_trait`]. fn consider_builtin_copy_clone_candidate( - ecx: &mut EvalCtxt<'_, InferCtxt<'tcx>>, - goal: Goal<'tcx, Self>, - ) -> Result<Candidate<TyCtxt<'tcx>>, NoSolution>; + ecx: &mut EvalCtxt<'_, Infcx>, + goal: Goal<I, Self>, + ) -> Result<Candidate<I>, 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<Candidate<TyCtxt<'tcx>>, NoSolution>; + ecx: &mut EvalCtxt<'_, Infcx>, + goal: Goal<I, Self>, + ) -> Result<Candidate<I>, 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<Candidate<TyCtxt<'tcx>>, NoSolution>; + ecx: &mut EvalCtxt<'_, Infcx>, + goal: Goal<I, Self>, + ) -> Result<Candidate<I>, NoSolution>; /// A callable type (a closure, fn def, or fn ptr) is known to implement the `Fn<A>` /// family of traits where `A` is given by the signature of the type. fn consider_builtin_fn_trait_candidates( - ecx: &mut EvalCtxt<'_, InferCtxt<'tcx>>, - goal: Goal<'tcx, Self>, + ecx: &mut EvalCtxt<'_, Infcx>, + goal: Goal<I, Self>, kind: ty::ClosureKind, - ) -> Result<Candidate<TyCtxt<'tcx>>, NoSolution>; + ) -> Result<Candidate<I>, NoSolution>; /// An async closure is known to implement the `AsyncFn<A>` family of traits /// where `A` is given by the signature of the type. fn consider_builtin_async_fn_trait_candidates( - ecx: &mut EvalCtxt<'_, InferCtxt<'tcx>>, - goal: Goal<'tcx, Self>, + ecx: &mut EvalCtxt<'_, Infcx>, + goal: Goal<I, Self>, kind: ty::ClosureKind, - ) -> Result<Candidate<TyCtxt<'tcx>>, NoSolution>; + ) -> Result<Candidate<I>, NoSolution>; /// Compute the built-in logic of the `AsyncFnKindHelper` helper trait, which /// is used internally to delay computation for async closures until after /// upvar analysis is performed in HIR typeck. fn consider_builtin_async_fn_kind_helper_candidate( - ecx: &mut EvalCtxt<'_, InferCtxt<'tcx>>, - goal: Goal<'tcx, Self>, - ) -> Result<Candidate<TyCtxt<'tcx>>, NoSolution>; + ecx: &mut EvalCtxt<'_, Infcx>, + goal: Goal<I, Self>, + ) -> Result<Candidate<I>, 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<Candidate<TyCtxt<'tcx>>, NoSolution>; + ecx: &mut EvalCtxt<'_, Infcx>, + goal: Goal<I, Self>, + ) -> Result<Candidate<I>, NoSolution>; /// `Pointee` is always implemented. /// @@ -202,65 +198,65 @@ pub(super) trait GoalKind<'tcx>: /// the built-in types. For structs, the metadata type is given by the struct /// tail. fn consider_builtin_pointee_candidate( - ecx: &mut EvalCtxt<'_, InferCtxt<'tcx>>, - goal: Goal<'tcx, Self>, - ) -> Result<Candidate<TyCtxt<'tcx>>, NoSolution>; + ecx: &mut EvalCtxt<'_, Infcx>, + goal: Goal<I, Self>, + ) -> Result<Candidate<I>, NoSolution>; /// A coroutine (that comes from an `async` desugaring) is known to implement /// `Future<Output = O>`, where `O` is given by the coroutine's return type /// that was computed during type-checking. fn consider_builtin_future_candidate( - ecx: &mut EvalCtxt<'_, InferCtxt<'tcx>>, - goal: Goal<'tcx, Self>, - ) -> Result<Candidate<TyCtxt<'tcx>>, NoSolution>; + ecx: &mut EvalCtxt<'_, Infcx>, + goal: Goal<I, Self>, + ) -> Result<Candidate<I>, NoSolution>; /// A coroutine (that comes from a `gen` desugaring) is known to implement /// `Iterator<Item = O>`, where `O` is given by the generator's yield type /// that was computed during type-checking. fn consider_builtin_iterator_candidate( - ecx: &mut EvalCtxt<'_, InferCtxt<'tcx>>, - goal: Goal<'tcx, Self>, - ) -> Result<Candidate<TyCtxt<'tcx>>, NoSolution>; + ecx: &mut EvalCtxt<'_, Infcx>, + goal: Goal<I, Self>, + ) -> Result<Candidate<I>, 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<Candidate<TyCtxt<'tcx>>, NoSolution>; + ecx: &mut EvalCtxt<'_, Infcx>, + goal: Goal<I, Self>, + ) -> Result<Candidate<I>, NoSolution>; fn consider_builtin_async_iterator_candidate( - ecx: &mut EvalCtxt<'_, InferCtxt<'tcx>>, - goal: Goal<'tcx, Self>, - ) -> Result<Candidate<TyCtxt<'tcx>>, NoSolution>; + ecx: &mut EvalCtxt<'_, Infcx>, + goal: Goal<I, Self>, + ) -> Result<Candidate<I>, NoSolution>; /// A coroutine (that doesn't come from an `async` or `gen` desugaring) is known to /// implement `Coroutine<R, Yield = Y, Return = O>`, given the resume, yield, /// and return types of the coroutine computed during type-checking. fn consider_builtin_coroutine_candidate( - ecx: &mut EvalCtxt<'_, InferCtxt<'tcx>>, - goal: Goal<'tcx, Self>, - ) -> Result<Candidate<TyCtxt<'tcx>>, NoSolution>; + ecx: &mut EvalCtxt<'_, Infcx>, + goal: Goal<I, Self>, + ) -> Result<Candidate<I>, NoSolution>; fn consider_builtin_discriminant_kind_candidate( - ecx: &mut EvalCtxt<'_, InferCtxt<'tcx>>, - goal: Goal<'tcx, Self>, - ) -> Result<Candidate<TyCtxt<'tcx>>, NoSolution>; + ecx: &mut EvalCtxt<'_, Infcx>, + goal: Goal<I, Self>, + ) -> Result<Candidate<I>, NoSolution>; fn consider_builtin_async_destruct_candidate( - ecx: &mut EvalCtxt<'_, InferCtxt<'tcx>>, - goal: Goal<'tcx, Self>, - ) -> Result<Candidate<TyCtxt<'tcx>>, NoSolution>; + ecx: &mut EvalCtxt<'_, Infcx>, + goal: Goal<I, Self>, + ) -> Result<Candidate<I>, NoSolution>; fn consider_builtin_destruct_candidate( - ecx: &mut EvalCtxt<'_, InferCtxt<'tcx>>, - goal: Goal<'tcx, Self>, - ) -> Result<Candidate<TyCtxt<'tcx>>, NoSolution>; + ecx: &mut EvalCtxt<'_, Infcx>, + goal: Goal<I, Self>, + ) -> Result<Candidate<I>, NoSolution>; fn consider_builtin_transmute_candidate( - ecx: &mut EvalCtxt<'_, InferCtxt<'tcx>>, - goal: Goal<'tcx, Self>, - ) -> Result<Candidate<TyCtxt<'tcx>>, NoSolution>; + ecx: &mut EvalCtxt<'_, Infcx>, + goal: Goal<I, Self>, + ) -> Result<Candidate<I>, 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`. @@ -270,16 +266,20 @@ pub(super) trait GoalKind<'tcx>: /// otherwise recompute this for codegen. This is a bit of a mess but the /// easiest way to maintain the existing behavior for now. fn consider_structural_builtin_unsize_candidates( - ecx: &mut EvalCtxt<'_, InferCtxt<'tcx>>, - goal: Goal<'tcx, Self>, - ) -> Vec<Candidate<TyCtxt<'tcx>>>; + ecx: &mut EvalCtxt<'_, Infcx>, + goal: Goal<I, Self>, + ) -> Vec<Candidate<I>>; } -impl<'tcx> EvalCtxt<'_, InferCtxt<'tcx>> { - pub(super) fn assemble_and_evaluate_candidates<G: GoalKind<'tcx>>( +impl<Infcx, I> EvalCtxt<'_, Infcx> +where + Infcx: SolverDelegate<Interner = I>, + I: Interner, +{ + pub(super) fn assemble_and_evaluate_candidates<G: GoalKind<Infcx>>( &mut self, - goal: Goal<'tcx, G>, - ) -> Vec<Candidate<TyCtxt<'tcx>>> { + goal: Goal<I, G>, + ) -> Vec<Candidate<I>> { let Ok(normalized_self_ty) = self.structurally_normalize_ty(goal.param_env, goal.predicate.self_ty()) else { @@ -291,7 +291,7 @@ impl<'tcx> EvalCtxt<'_, InferCtxt<'tcx>> { return self.forced_ambiguity(MaybeCause::Ambiguity).into_iter().collect(); } - let goal: Goal<'tcx, G> = goal.with( + let goal: Goal<I, G> = goal.with( self.interner(), goal.predicate.with_self_ty(self.interner(), normalized_self_ty), ); @@ -301,7 +301,7 @@ impl<'tcx> EvalCtxt<'_, InferCtxt<'tcx>> { let mut candidates = vec![]; - self.assemble_non_blanket_impl_candidates(goal, &mut candidates); + self.assemble_impl_candidates(goal, &mut candidates); self.assemble_builtin_impl_candidates(goal, &mut candidates); @@ -309,8 +309,6 @@ impl<'tcx> EvalCtxt<'_, InferCtxt<'tcx>> { self.assemble_object_bound_candidates(goal, &mut candidates); - self.assemble_blanket_impl_candidates(goal, &mut candidates); - self.assemble_param_env_candidates(goal, &mut candidates); match self.solver_mode() { @@ -326,7 +324,7 @@ impl<'tcx> EvalCtxt<'_, InferCtxt<'tcx>> { pub(super) fn forced_ambiguity( &mut self, cause: MaybeCause, - ) -> Result<Candidate<TyCtxt<'tcx>>, NoSolution> { + ) -> Result<Candidate<I>, 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,149 +337,36 @@ impl<'tcx> EvalCtxt<'_, InferCtxt<'tcx>> { } #[instrument(level = "trace", skip_all)] - fn assemble_non_blanket_impl_candidates<G: GoalKind<'tcx>>( + fn assemble_impl_candidates<G: GoalKind<Infcx>>( &mut self, - goal: Goal<'tcx, G>, - candidates: &mut Vec<Candidate<TyCtxt<'tcx>>>, + goal: Goal<I, G>, + candidates: &mut Vec<Candidate<I>>, ) { let tcx = self.interner(); - let self_ty = goal.predicate.self_ty(); - let trait_impls = tcx.trait_impls_of(goal.predicate.trait_def_id(tcx)); - let mut consider_impls_for_simplified_type = |simp| { - if let Some(impls_for_type) = trait_impls.non_blanket_impls().get(&simp) { - for &impl_def_id in impls_for_type { - // For every `default impl`, there's always a non-default `impl` - // that will *also* apply. There's no reason to register a candidate - // for this impl, since it is *not* proof that the trait goal holds. - if tcx.defaultness(impl_def_id).is_default() { - return; - } - - match G::consider_impl_candidate(self, goal, impl_def_id) { - Ok(candidate) => candidates.push(candidate), - Err(NoSolution) => (), - } - } - } - }; - - match self_ty.kind() { - ty::Bool - | ty::Char - | ty::Int(_) - | ty::Uint(_) - | ty::Float(_) - | ty::Adt(_, _) - | ty::Foreign(_) - | ty::Str - | ty::Array(_, _) - | ty::Pat(_, _) - | ty::Slice(_) - | ty::RawPtr(_, _) - | ty::Ref(_, _, _) - | ty::FnDef(_, _) - | ty::FnPtr(_) - | ty::Dynamic(_, _, _) - | ty::Closure(..) - | ty::CoroutineClosure(..) - | ty::Coroutine(_, _) - | ty::Never - | ty::Tuple(_) => { - let simp = - fast_reject::simplify_type(tcx, self_ty, TreatParams::ForLookup).unwrap(); - consider_impls_for_simplified_type(simp); - } - - // HACK: For integer and float variables we have to manually look at all impls - // which have some integer or float as a self type. - ty::Infer(ty::IntVar(_)) => { - use ty::IntTy::*; - use ty::UintTy::*; - // This causes a compiler error if any new integer kinds are added. - let (I8 | I16 | I32 | I64 | I128 | Isize): ty::IntTy; - let (U8 | U16 | U32 | U64 | U128 | Usize): ty::UintTy; - let possible_integers = [ - // signed integers - SimplifiedType::Int(I8), - SimplifiedType::Int(I16), - SimplifiedType::Int(I32), - SimplifiedType::Int(I64), - SimplifiedType::Int(I128), - SimplifiedType::Int(Isize), - // unsigned integers - SimplifiedType::Uint(U8), - SimplifiedType::Uint(U16), - SimplifiedType::Uint(U32), - SimplifiedType::Uint(U64), - SimplifiedType::Uint(U128), - SimplifiedType::Uint(Usize), - ]; - for simp in possible_integers { - consider_impls_for_simplified_type(simp); + tcx.for_each_relevant_impl( + goal.predicate.trait_def_id(tcx), + goal.predicate.self_ty(), + |impl_def_id| { + // For every `default impl`, there's always a non-default `impl` + // that will *also* apply. There's no reason to register a candidate + // for this impl, since it is *not* proof that the trait goal holds. + if tcx.impl_is_default(impl_def_id) { + return; } - } - ty::Infer(ty::FloatVar(_)) => { - // This causes a compiler error if any new float kinds are added. - let (ty::FloatTy::F16 | ty::FloatTy::F32 | ty::FloatTy::F64 | ty::FloatTy::F128); - let possible_floats = [ - SimplifiedType::Float(ty::FloatTy::F16), - SimplifiedType::Float(ty::FloatTy::F32), - SimplifiedType::Float(ty::FloatTy::F64), - SimplifiedType::Float(ty::FloatTy::F128), - ]; - - for simp in possible_floats { - consider_impls_for_simplified_type(simp); + match G::consider_impl_candidate(self, goal, impl_def_id) { + Ok(candidate) => candidates.push(candidate), + Err(NoSolution) => (), } - } - - // The only traits applying to aliases and placeholders are blanket impls. - // - // Impls which apply to an alias after normalization are handled by - // `assemble_candidates_after_normalizing_self_ty`. - ty::Alias(_, _) | ty::Placeholder(..) | ty::Error(_) => (), - - // FIXME: These should ideally not exist as a self type. It would be nice for - // the builtin auto trait impls of coroutines to instead directly recurse - // into the witness. - ty::CoroutineWitness(..) => (), - - // These variants should not exist as a self type. - ty::Infer(ty::TyVar(_) | ty::FreshTy(_) | ty::FreshIntTy(_) | ty::FreshFloatTy(_)) - | ty::Param(_) - | ty::Bound(_, _) => bug!("unexpected self type: {self_ty}"), - } - } - - #[instrument(level = "trace", skip_all)] - fn assemble_blanket_impl_candidates<G: GoalKind<'tcx>>( - &mut self, - goal: Goal<'tcx, G>, - candidates: &mut Vec<Candidate<TyCtxt<'tcx>>>, - ) { - let tcx = self.interner(); - let trait_impls = tcx.trait_impls_of(goal.predicate.trait_def_id(tcx)); - for &impl_def_id in trait_impls.blanket_impls() { - // For every `default impl`, there's always a non-default `impl` - // that will *also* apply. There's no reason to register a candidate - // for this impl, since it is *not* proof that the trait goal holds. - if tcx.defaultness(impl_def_id).is_default() { - return; - } - - match G::consider_impl_candidate(self, goal, impl_def_id) { - Ok(candidate) => candidates.push(candidate), - Err(NoSolution) => (), - } - } + }, + ); } #[instrument(level = "trace", skip_all)] - fn assemble_builtin_impl_candidates<G: GoalKind<'tcx>>( + fn assemble_builtin_impl_candidates<G: GoalKind<Infcx>>( &mut self, - goal: Goal<'tcx, G>, - candidates: &mut Vec<Candidate<TyCtxt<'tcx>>>, + goal: Goal<I, G>, + candidates: &mut Vec<Candidate<I>>, ) { let tcx = self.interner(); let trait_def_id = goal.predicate.trait_def_id(tcx); @@ -499,43 +384,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 tcx.is_lang_item(trait_def_id, LangItem::Sized) { + } else if tcx.is_lang_item(trait_def_id, TraitSolverLangItem::Sized) { G::consider_builtin_sized_candidate(self, goal) - } else if tcx.is_lang_item(trait_def_id, LangItem::Copy) - || tcx.is_lang_item(trait_def_id, LangItem::Clone) + } else if tcx.is_lang_item(trait_def_id, TraitSolverLangItem::Copy) + || tcx.is_lang_item(trait_def_id, TraitSolverLangItem::Clone) { G::consider_builtin_copy_clone_candidate(self, goal) - } else if tcx.is_lang_item(trait_def_id, LangItem::PointerLike) { + } else if tcx.is_lang_item(trait_def_id, TraitSolverLangItem::PointerLike) { G::consider_builtin_pointer_like_candidate(self, goal) - } else if tcx.is_lang_item(trait_def_id, LangItem::FnPtrTrait) { + } else if tcx.is_lang_item(trait_def_id, TraitSolverLangItem::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 tcx.is_lang_item(trait_def_id, LangItem::AsyncFnKindHelper) { + } else if tcx.is_lang_item(trait_def_id, TraitSolverLangItem::AsyncFnKindHelper) { G::consider_builtin_async_fn_kind_helper_candidate(self, goal) - } else if tcx.is_lang_item(trait_def_id, LangItem::Tuple) { + } else if tcx.is_lang_item(trait_def_id, TraitSolverLangItem::Tuple) { G::consider_builtin_tuple_candidate(self, goal) - } else if tcx.is_lang_item(trait_def_id, LangItem::PointeeTrait) { + } else if tcx.is_lang_item(trait_def_id, TraitSolverLangItem::PointeeTrait) { G::consider_builtin_pointee_candidate(self, goal) - } else if tcx.is_lang_item(trait_def_id, LangItem::Future) { + } else if tcx.is_lang_item(trait_def_id, TraitSolverLangItem::Future) { G::consider_builtin_future_candidate(self, goal) - } else if tcx.is_lang_item(trait_def_id, LangItem::Iterator) { + } else if tcx.is_lang_item(trait_def_id, TraitSolverLangItem::Iterator) { G::consider_builtin_iterator_candidate(self, goal) - } else if tcx.is_lang_item(trait_def_id, LangItem::FusedIterator) { + } else if tcx.is_lang_item(trait_def_id, TraitSolverLangItem::FusedIterator) { G::consider_builtin_fused_iterator_candidate(self, goal) - } else if tcx.is_lang_item(trait_def_id, LangItem::AsyncIterator) { + } else if tcx.is_lang_item(trait_def_id, TraitSolverLangItem::AsyncIterator) { G::consider_builtin_async_iterator_candidate(self, goal) - } else if tcx.is_lang_item(trait_def_id, LangItem::Coroutine) { + } else if tcx.is_lang_item(trait_def_id, TraitSolverLangItem::Coroutine) { G::consider_builtin_coroutine_candidate(self, goal) - } else if tcx.is_lang_item(trait_def_id, LangItem::DiscriminantKind) { + } else if tcx.is_lang_item(trait_def_id, TraitSolverLangItem::DiscriminantKind) { G::consider_builtin_discriminant_kind_candidate(self, goal) - } else if tcx.is_lang_item(trait_def_id, LangItem::AsyncDestruct) { + } else if tcx.is_lang_item(trait_def_id, TraitSolverLangItem::AsyncDestruct) { G::consider_builtin_async_destruct_candidate(self, goal) - } else if tcx.is_lang_item(trait_def_id, LangItem::Destruct) { + } else if tcx.is_lang_item(trait_def_id, TraitSolverLangItem::Destruct) { G::consider_builtin_destruct_candidate(self, goal) - } else if tcx.is_lang_item(trait_def_id, LangItem::TransmuteTrait) { + } else if tcx.is_lang_item(trait_def_id, TraitSolverLangItem::TransmuteTrait) { G::consider_builtin_transmute_candidate(self, goal) } else { Err(NoSolution) @@ -545,18 +430,18 @@ impl<'tcx> EvalCtxt<'_, InferCtxt<'tcx>> { // There may be multiple unsize candidates for a trait with several supertraits: // `trait Foo: Bar<A> + Bar<B>` and `dyn Foo: Unsize<dyn Bar<_>>` - if tcx.is_lang_item(trait_def_id, LangItem::Unsize) { + if tcx.is_lang_item(trait_def_id, TraitSolverLangItem::Unsize) { candidates.extend(G::consider_structural_builtin_unsize_candidates(self, goal)); } } #[instrument(level = "trace", skip_all)] - fn assemble_param_env_candidates<G: GoalKind<'tcx>>( + fn assemble_param_env_candidates<G: GoalKind<Infcx>>( &mut self, - goal: Goal<'tcx, G>, - candidates: &mut Vec<Candidate<TyCtxt<'tcx>>>, + goal: Goal<I, G>, + candidates: &mut Vec<Candidate<I>>, ) { - for (i, assumption) in goal.param_env.caller_bounds().iter().enumerate() { + for (i, assumption) in goal.param_env.caller_bounds().into_iter().enumerate() { candidates.extend(G::probe_and_consider_implied_clause( self, CandidateSource::ParamEnv(i), @@ -568,10 +453,10 @@ impl<'tcx> EvalCtxt<'_, InferCtxt<'tcx>> { } #[instrument(level = "trace", skip_all)] - fn assemble_alias_bound_candidates<G: GoalKind<'tcx>>( + fn assemble_alias_bound_candidates<G: GoalKind<Infcx>>( &mut self, - goal: Goal<'tcx, G>, - candidates: &mut Vec<Candidate<TyCtxt<'tcx>>>, + goal: Goal<I, G>, + candidates: &mut Vec<Candidate<I>>, ) { let () = self.probe(|_| ProbeKind::NormalizedSelfTyAssembly).enter(|ecx| { ecx.assemble_alias_bound_candidates_recur(goal.predicate.self_ty(), goal, candidates); @@ -587,13 +472,13 @@ impl<'tcx> EvalCtxt<'_, InferCtxt<'tcx>> { /// If so, continue searching by recursively calling after normalization. // FIXME: This may recurse infinitely, but I can't seem to trigger it without // hitting another overflow error something. Add a depth parameter needed later. - fn assemble_alias_bound_candidates_recur<G: GoalKind<'tcx>>( + fn assemble_alias_bound_candidates_recur<G: GoalKind<Infcx>>( &mut self, - self_ty: Ty<'tcx>, - goal: Goal<'tcx, G>, - candidates: &mut Vec<Candidate<TyCtxt<'tcx>>>, + self_ty: I::Ty, + goal: Goal<I, G>, + candidates: &mut Vec<Candidate<I>>, ) { - let (kind, alias_ty) = match *self_ty.kind() { + let (kind, alias_ty) = match self_ty.kind() { ty::Bool | ty::Char | ty::Int(_) @@ -621,7 +506,7 @@ impl<'tcx> EvalCtxt<'_, InferCtxt<'tcx>> { | ty::Infer(ty::IntVar(_) | ty::FloatVar(_)) | ty::Error(_) => return, ty::Infer(ty::FreshTy(_) | ty::FreshIntTy(_) | ty::FreshFloatTy(_)) | ty::Bound(..) => { - bug!("unexpected self type for `{goal:?}`") + panic!("unexpected self type for `{goal:?}`") } ty::Infer(ty::TyVar(_)) => { @@ -638,16 +523,15 @@ impl<'tcx> EvalCtxt<'_, InferCtxt<'tcx>> { ty::Alias(kind @ (ty::Projection | ty::Opaque), alias_ty) => (kind, alias_ty), ty::Alias(ty::Inherent | ty::Weak, _) => { - self.interner().sess.dcx().span_delayed_bug( - DUMMY_SP, - format!("could not normalize {self_ty}, it is not WF"), - ); + self.interner().delay_bug(format!("could not normalize {self_ty:?}, it is not WF")); return; } }; - for assumption in - self.interner().item_bounds(alias_ty.def_id).instantiate(self.interner(), alias_ty.args) + for assumption in self + .interner() + .item_bounds(alias_ty.def_id) + .iter_instantiated(self.interner(), &alias_ty.args) { candidates.extend(G::probe_and_consider_implied_clause( self, @@ -672,18 +556,18 @@ impl<'tcx> EvalCtxt<'_, InferCtxt<'tcx>> { } #[instrument(level = "trace", skip_all)] - fn assemble_object_bound_candidates<G: GoalKind<'tcx>>( + fn assemble_object_bound_candidates<G: GoalKind<Infcx>>( &mut self, - goal: Goal<'tcx, G>, - candidates: &mut Vec<Candidate<TyCtxt<'tcx>>>, + goal: Goal<I, G>, + candidates: &mut Vec<Candidate<I>>, ) { let tcx = self.interner(); - if !tcx.trait_def(goal.predicate.trait_def_id(tcx)).implement_via_object { + if !tcx.trait_may_be_implemented_via_object(goal.predicate.trait_def_id(tcx)) { return; } let self_ty = goal.predicate.self_ty(); - let bounds = match *self_ty.kind() { + let bounds = match self_ty.kind() { ty::Bool | ty::Char | ty::Int(_) @@ -711,12 +595,12 @@ impl<'tcx> EvalCtxt<'_, InferCtxt<'tcx>> { | ty::Infer(ty::IntVar(_) | ty::FloatVar(_)) | ty::Error(_) => return, ty::Infer(ty::TyVar(_) | ty::FreshTy(_) | ty::FreshIntTy(_) | ty::FreshFloatTy(_)) - | ty::Bound(..) => bug!("unexpected self type for `{goal:?}`"), + | ty::Bound(..) => panic!("unexpected self type for `{goal:?}`"), ty::Dynamic(bounds, ..) => bounds, }; // Do not consider built-in object impls for non-object-safe types. - if bounds.principal_def_id().is_some_and(|def_id| !tcx.is_object_safe(def_id)) { + if bounds.principal_def_id().is_some_and(|def_id| !tcx.trait_is_object_safe(def_id)) { return; } @@ -745,7 +629,9 @@ 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); - for (idx, assumption) in supertraits(self.interner(), principal_trait_ref).enumerate() { + for (idx, assumption) in + Infcx::elaborate_supertraits(tcx, principal_trait_ref).enumerate() + { candidates.extend(G::probe_and_consider_object_bound_candidate( self, CandidateSource::BuiltinImpl(BuiltinImplSource::Object(idx)), @@ -763,10 +649,10 @@ impl<'tcx> EvalCtxt<'_, InferCtxt<'tcx>> { /// To do so we add an ambiguous candidate in case such an unknown impl could /// apply to the current goal. #[instrument(level = "trace", skip_all)] - fn assemble_coherence_unknowable_candidates<G: GoalKind<'tcx>>( + fn assemble_coherence_unknowable_candidates<G: GoalKind<Infcx>>( &mut self, - goal: Goal<'tcx, G>, - candidates: &mut Vec<Candidate<TyCtxt<'tcx>>>, + goal: Goal<I, G>, + candidates: &mut Vec<Candidate<I>>, ) { let tcx = self.interner(); @@ -792,13 +678,13 @@ impl<'tcx> EvalCtxt<'_, InferCtxt<'tcx>> { // to improve this however. However, this should make it fairly straightforward to refine // the filtering going forward, so it seems alright-ish for now. #[instrument(level = "debug", skip(self, goal))] - fn discard_impls_shadowed_by_env<G: GoalKind<'tcx>>( + fn discard_impls_shadowed_by_env<G: GoalKind<Infcx>>( &mut self, - goal: Goal<'tcx, G>, - candidates: &mut Vec<Candidate<TyCtxt<'tcx>>>, + goal: Goal<I, G>, + candidates: &mut Vec<Candidate<I>>, ) { let tcx = self.interner(); - let trait_goal: Goal<'tcx, ty::TraitPredicate<'tcx>> = + let trait_goal: Goal<I, ty::TraitPredicate<I>> = goal.with(tcx, goal.predicate.trait_ref(tcx)); let mut trait_candidates_from_env = vec![]; @@ -823,7 +709,7 @@ impl<'tcx> EvalCtxt<'_, InferCtxt<'tcx>> { false } CandidateSource::ParamEnv(_) | CandidateSource::AliasBound => true, - CandidateSource::CoherenceUnknowable => bug!("uh oh"), + CandidateSource::CoherenceUnknowable => panic!("uh oh"), }); } // If it is still ambiguous we instead just force the whole goal @@ -841,10 +727,7 @@ impl<'tcx> EvalCtxt<'_, InferCtxt<'tcx>> { /// to somehow try to merge the candidates into one. If that fails, we return /// ambiguity. #[instrument(level = "debug", skip(self), ret)] - pub(super) fn merge_candidates( - &mut self, - candidates: Vec<Candidate<TyCtxt<'tcx>>>, - ) -> QueryResult<'tcx> { + pub(super) fn merge_candidates(&mut self, candidates: Vec<Candidate<I>>) -> QueryResult<I> { // First try merging all candidates. This is complete and fully sound. let responses = candidates.iter().map(|c| c.result).collect::<Vec<_>>(); if let Some(result) = self.try_merge_responses(&responses) { diff --git a/compiler/rustc_trait_selection/src/solve/assembly/structural_traits.rs b/compiler/rustc_next_trait_solver/src/solve/assembly/structural_traits.rs index d6074617caf..202af76565a 100644 --- a/compiler/rustc_trait_selection/src/solve/assembly/structural_traits.rs +++ b/compiler/rustc_next_trait_solver/src/solve/assembly/structural_traits.rs @@ -3,26 +3,24 @@ use rustc_ast_ir::{Movability, Mutability}; use rustc_data_structures::fx::FxHashMap; -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::{self as ty, Interner, Upcast as _}; use rustc_type_ir_macros::{TypeFoldable_Generic, TypeVisitable_Generic}; +use tracing::instrument; -use crate::solve::EvalCtxt; +use crate::infcx::SolverDelegate; +use crate::solve::{EvalCtxt, Goal, NoSolution}; // Calculates the constituent types of a type for `auto trait` purposes. -// -// 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<Infcx, I>( ecx: &EvalCtxt<'_, Infcx>, ty: I::Ty, ) -> Result<Vec<ty::Binder<I, I::Ty>>, NoSolution> where - Infcx: InferCtxtLike<Interner = I>, + Infcx: SolverDelegate<Interner = I>, I: Interner, { let tcx = ecx.interner(); @@ -108,7 +106,7 @@ pub(in crate::solve) fn instantiate_constituent_tys_for_sized_trait<Infcx, I>( ty: I::Ty, ) -> Result<Vec<ty::Binder<I, I::Ty>>, NoSolution> where - Infcx: InferCtxtLike<Interner = I>, + Infcx: SolverDelegate<Interner = I>, I: Interner, { match ty.kind() { @@ -176,7 +174,7 @@ pub(in crate::solve) fn instantiate_constituent_tys_for_copy_clone_trait<Infcx, ty: I::Ty, ) -> Result<Vec<ty::Binder<I, I::Ty>>, NoSolution> where - Infcx: InferCtxtLike<Interner = I>, + Infcx: SolverDelegate<Interner = I>, I: Interner, { match ty.kind() { @@ -663,7 +661,7 @@ pub(in crate::solve) fn predicates_for_object_candidate<Infcx, I>( object_bounds: I::BoundExistentialPredicates, ) -> Vec<Goal<I, I::Predicate>> where - Infcx: InferCtxtLike<Interner = I>, + Infcx: SolverDelegate<Interner = I>, I: Interner, { let tcx = ecx.interner(); @@ -712,14 +710,14 @@ where .collect() } -struct ReplaceProjectionWith<'a, Infcx: InferCtxtLike<Interner = I>, I: Interner> { +struct ReplaceProjectionWith<'a, Infcx: SolverDelegate<Interner = I>, I: Interner> { ecx: &'a EvalCtxt<'a, Infcx>, param_env: I::ParamEnv, mapping: FxHashMap<I::DefId, ty::Binder<I, ty::ProjectionPredicate<I>>>, nested: Vec<Goal<I, I::Predicate>>, } -impl<Infcx: InferCtxtLike<Interner = I>, I: Interner> TypeFolder<I> +impl<Infcx: SolverDelegate<Interner = I>, I: Interner> TypeFolder<I> for ReplaceProjectionWith<'_, Infcx, I> { fn interner(&self) -> I { @@ -744,7 +742,7 @@ impl<Infcx: InferCtxtLike<Interner = I>, I: Interner> TypeFolder<I> ) .expect("expected to be able to unify goal projection with dyn's projection"), ); - proj.term.expect_type() + proj.term.expect_ty() } else { ty.super_fold_with(self) } diff --git a/compiler/rustc_trait_selection/src/solve/eval_ctxt/canonical.rs b/compiler/rustc_next_trait_solver/src/solve/eval_ctxt/canonical.rs index 0e0b9e98339..c6611285a3b 100644 --- a/compiler/rustc_trait_selection/src/solve/eval_ctxt/canonical.rs +++ b/compiler/rustc_next_trait_solver/src/solve/eval_ctxt/canonical.rs @@ -8,58 +8,53 @@ //! section of the [rustc-dev-guide][c]. //! //! [c]: https://rustc-dev-guide.rust-lang.org/solve/canonicalization.html -use super::{CanonicalInput, Certainty, EvalCtxt, Goal}; + +use std::iter; + +use rustc_index::IndexVec; +use rustc_type_ir::fold::TypeFoldable; +use rustc_type_ir::inherent::*; +use rustc_type_ir::{self as ty, Canonical, CanonicalVarValues, Interner}; +use tracing::{instrument, trace}; + +use crate::canonicalizer::{CanonicalizeMode, Canonicalizer}; +use crate::infcx::SolverDelegate; +use crate::resolve::EagerResolver; use crate::solve::eval_ctxt::NestedGoals; +use crate::solve::inspect; use crate::solve::{ - inspect, response_no_constraints_raw, CanonicalResponse, QueryResult, Response, + response_no_constraints_raw, CanonicalInput, CanonicalResponse, Certainty, EvalCtxt, + ExternalConstraintsData, Goal, MaybeCause, NestedNormalizationGoals, NoSolution, + PredefinedOpaquesData, QueryInput, QueryResult, Response, }; -use rustc_data_structures::fx::FxHashSet; -use rustc_index::IndexVec; -use rustc_infer::infer::canonical::query_response::make_query_region_constraints; -use rustc_infer::infer::canonical::{CanonicalExt, QueryRegionConstraints}; -use rustc_infer::infer::RegionVariableOrigin; -use rustc_infer::infer::{InferCtxt, InferOk}; -use rustc_infer::traits::solve::NestedNormalizationGoals; -use rustc_middle::bug; -use rustc_middle::infer::canonical::Canonical; -use rustc_middle::traits::query::NoSolution; -use rustc_middle::traits::solve::{ - ExternalConstraintsData, MaybeCause, PredefinedOpaquesData, QueryInput, -}; -use rustc_middle::traits::ObligationCause; -use rustc_middle::ty::{self, BoundVar, GenericArgKind, Ty, TyCtxt, TypeFoldable}; -use rustc_next_trait_solver::canonicalizer::{CanonicalizeMode, Canonicalizer}; -use rustc_next_trait_solver::resolve::EagerResolver; -use rustc_span::{Span, DUMMY_SP}; -use rustc_type_ir::CanonicalVarValues; -use rustc_type_ir::{InferCtxtLike, Interner}; -use std::assert_matches::assert_matches; -use std::iter; -use std::ops::Deref; -trait ResponseT<'tcx> { - fn var_values(&self) -> CanonicalVarValues<TyCtxt<'tcx>>; +trait ResponseT<I: Interner> { + fn var_values(&self) -> CanonicalVarValues<I>; } -impl<'tcx> ResponseT<'tcx> for Response<TyCtxt<'tcx>> { - fn var_values(&self) -> CanonicalVarValues<TyCtxt<'tcx>> { +impl<I: Interner> ResponseT<I> for Response<I> { + fn var_values(&self) -> CanonicalVarValues<I> { self.var_values } } -impl<'tcx, T> ResponseT<'tcx> for inspect::State<TyCtxt<'tcx>, T> { - fn var_values(&self) -> CanonicalVarValues<TyCtxt<'tcx>> { +impl<I: Interner, T> ResponseT<I> for inspect::State<I, T> { + fn var_values(&self) -> CanonicalVarValues<I> { self.var_values } } -impl<'tcx> EvalCtxt<'_, InferCtxt<'tcx>> { +impl<Infcx, I> EvalCtxt<'_, Infcx> +where + Infcx: SolverDelegate<Interner = I>, + I: Interner, +{ /// Canonicalizes the goal remembering the original values /// for each bound variable. - pub(super) fn canonicalize_goal<T: TypeFoldable<TyCtxt<'tcx>>>( + pub(super) fn canonicalize_goal<T: TypeFoldable<I>>( &self, - goal: Goal<'tcx, T>, - ) -> (Vec<ty::GenericArg<'tcx>>, CanonicalInput<'tcx, T>) { + goal: Goal<I, T>, + ) -> (Vec<I::GenericArg>, CanonicalInput<I, T>) { let opaque_types = self.infcx.clone_opaque_types_for_query_response(); let (goal, opaque_types) = (goal, opaque_types).fold_with(&mut EagerResolver::new(self.infcx)); @@ -89,7 +84,7 @@ impl<'tcx> EvalCtxt<'_, InferCtxt<'tcx>> { pub(in crate::solve) fn evaluate_added_goals_and_make_canonical_response( &mut self, certainty: Certainty, - ) -> QueryResult<'tcx> { + ) -> QueryResult<I> { self.inspect.make_canonical_response(certainty); let goals_certainty = self.try_evaluate_added_goals()?; @@ -102,8 +97,8 @@ impl<'tcx> EvalCtxt<'_, InferCtxt<'tcx>> { // We only check for leaks from universes which were entered inside // of the query. - self.infcx.leak_check(self.max_input_universe, None).map_err(|e| { - trace!(?e, "failed the leak check"); + self.infcx.leak_check(self.max_input_universe).map_err(|NoSolution| { + trace!("failed the leak check"); NoSolution })?; @@ -119,7 +114,7 @@ impl<'tcx> EvalCtxt<'_, InferCtxt<'tcx>> { if cfg!(debug_assertions) { assert!(normalizes_to_goals.is_empty()); if goals.is_empty() { - assert_matches!(goals_certainty, Certainty::Yes); + assert!(matches!(goals_certainty, Certainty::Yes)); } } (certainty, NestedNormalizationGoals(goals)) @@ -135,8 +130,7 @@ impl<'tcx> EvalCtxt<'_, InferCtxt<'tcx>> { // Remove any trivial region constraints once we've resolved regions external_constraints .region_constraints - .outlives - .retain(|(outlives, _)| outlives.0.as_region().map_or(true, |re| re != outlives.1)); + .retain(|outlives| outlives.0.as_region().map_or(true, |re| re != outlives.1)); let canonical = Canonicalizer::canonicalize( self.infcx, @@ -159,7 +153,7 @@ impl<'tcx> EvalCtxt<'_, InferCtxt<'tcx>> { pub(in crate::solve) fn make_ambiguous_response_no_constraints( &self, maybe_cause: MaybeCause, - ) -> CanonicalResponse<'tcx> { + ) -> CanonicalResponse<I> { response_no_constraints_raw( self.interner(), self.max_input_universe, @@ -179,8 +173,8 @@ impl<'tcx> EvalCtxt<'_, InferCtxt<'tcx>> { fn compute_external_query_constraints( &self, certainty: Certainty, - normalization_nested_goals: NestedNormalizationGoals<'tcx>, - ) -> ExternalConstraintsData<'tcx> { + normalization_nested_goals: NestedNormalizationGoals<I>, + ) -> ExternalConstraintsData<I> { // We only return region constraints once the certainty is `Yes`. This // is necessary as we may drop nested goals on ambiguity, which may result // in unconstrained inference variables in the region constraints. It also @@ -190,33 +184,24 @@ impl<'tcx> EvalCtxt<'_, InferCtxt<'tcx>> { // `tests/ui/higher-ranked/leak-check/leak-check-in-selection-5-ambig.rs` and // `tests/ui/higher-ranked/leak-check/leak-check-in-selection-6-ambig-unify.rs`. let region_constraints = if certainty == Certainty::Yes { - // Cannot use `take_registered_region_obligations` as we may compute the response - // inside of a `probe` whenever we have multiple choices inside of the solver. - let region_obligations = self.infcx.inner.borrow().region_obligations().to_owned(); - let mut region_constraints = self.infcx.with_region_constraints(|region_constraints| { - make_query_region_constraints( - self.interner(), - region_obligations.iter().map(|r_o| { - (r_o.sup_type, r_o.sub_region, r_o.origin.to_constraint_category()) - }), - region_constraints, - ) - }); - - let mut seen = FxHashSet::default(); - region_constraints.outlives.retain(|outlives| seen.insert(*outlives)); - region_constraints + self.infcx.make_deduplicated_outlives_constraints() } else { Default::default() }; - let mut opaque_types = self.infcx.clone_opaque_types_for_query_response(); - // Only return opaque type keys for newly-defined opaques - opaque_types.retain(|(a, _)| { - self.predefined_opaques_in_body.opaque_types.iter().all(|(pa, _)| pa != a) - }); - - ExternalConstraintsData { region_constraints, opaque_types, normalization_nested_goals } + ExternalConstraintsData { + region_constraints, + opaque_types: self + .infcx + .clone_opaque_types_for_query_response() + .into_iter() + // Only return *newly defined* opaque types. + .filter(|(a, _)| { + self.predefined_opaques_in_body.opaque_types.iter().all(|(pa, _)| pa != a) + }) + .collect(), + normalization_nested_goals, + } } /// After calling a canonical query, we apply the constraints returned @@ -229,10 +214,10 @@ impl<'tcx> EvalCtxt<'_, InferCtxt<'tcx>> { /// the `normalization_nested_goals` pub(super) fn instantiate_and_apply_query_response( &mut self, - param_env: ty::ParamEnv<'tcx>, - original_values: Vec<ty::GenericArg<'tcx>>, - response: CanonicalResponse<'tcx>, - ) -> (NestedNormalizationGoals<'tcx>, Certainty) { + param_env: I::ParamEnv, + original_values: Vec<I::GenericArg>, + response: CanonicalResponse<I>, + ) -> (NestedNormalizationGoals<I>, Certainty) { let instantiation = Self::compute_query_response_instantiation_values( self.infcx, &original_values, @@ -240,7 +225,7 @@ impl<'tcx> EvalCtxt<'_, InferCtxt<'tcx>> { ); let Response { var_values, external_constraints, certainty } = - response.instantiate(self.interner(), &instantiation); + self.infcx.instantiate_canonical(response, instantiation); Self::unify_query_var_values(self.infcx, param_env, &original_values, var_values); @@ -248,7 +233,7 @@ impl<'tcx> EvalCtxt<'_, InferCtxt<'tcx>> { region_constraints, opaque_types, normalization_nested_goals, - } = external_constraints.deref(); + } = &*external_constraints; self.register_region_constraints(region_constraints); self.register_new_opaque_types(opaque_types); (normalization_nested_goals.clone(), certainty) @@ -257,11 +242,11 @@ impl<'tcx> EvalCtxt<'_, InferCtxt<'tcx>> { /// This returns the canoncial variable values to instantiate the bound variables of /// the canonical response. This depends on the `original_values` for the /// bound variables. - fn compute_query_response_instantiation_values<T: ResponseT<'tcx>>( - infcx: &InferCtxt<'tcx>, - original_values: &[ty::GenericArg<'tcx>], - response: &Canonical<'tcx, T>, - ) -> CanonicalVarValues<TyCtxt<'tcx>> { + fn compute_query_response_instantiation_values<T: ResponseT<I>>( + infcx: &Infcx, + original_values: &[I::GenericArg], + response: &Canonical<I, T>, + ) -> CanonicalVarValues<I> { // FIXME: Longterm canonical queries should deal with all placeholders // created inside of the query directly instead of returning them to the // caller. @@ -283,35 +268,35 @@ impl<'tcx> EvalCtxt<'_, InferCtxt<'tcx>> { // inference variable of the input right away, which is more performant. let mut opt_values = IndexVec::from_elem_n(None, response.variables.len()); for (original_value, result_value) in iter::zip(original_values, var_values.var_values) { - match result_value.unpack() { - GenericArgKind::Type(t) => { - if let &ty::Bound(debruijn, b) = t.kind() { + match result_value.kind() { + ty::GenericArgKind::Type(t) => { + if let ty::Bound(debruijn, b) = t.kind() { assert_eq!(debruijn, ty::INNERMOST); - opt_values[b.var] = Some(*original_value); + opt_values[b.var()] = Some(*original_value); } } - GenericArgKind::Lifetime(r) => { - if let ty::ReBound(debruijn, br) = *r { + ty::GenericArgKind::Lifetime(r) => { + if let ty::ReBound(debruijn, br) = r.kind() { assert_eq!(debruijn, ty::INNERMOST); - opt_values[br.var] = Some(*original_value); + opt_values[br.var()] = Some(*original_value); } } - GenericArgKind::Const(c) => { - if let ty::ConstKind::Bound(debruijn, b) = c.kind() { + ty::GenericArgKind::Const(c) => { + if let ty::ConstKind::Bound(debruijn, bv) = c.kind() { assert_eq!(debruijn, ty::INNERMOST); - opt_values[b] = Some(*original_value); + opt_values[bv.var()] = Some(*original_value); } } } } - let var_values = infcx.tcx.mk_args_from_iter(response.variables.iter().enumerate().map( - |(index, info)| { + let var_values = infcx.interner().mk_args_from_iter( + response.variables.into_iter().enumerate().map(|(index, info)| { if info.universe() != ty::UniverseIndex::ROOT { // A variable from inside a binder of the query. While ideally these shouldn't // exist at all (see the FIXME at the start of this method), we have to deal with // them for now. - infcx.instantiate_canonical_var(DUMMY_SP, info, |idx| { + infcx.instantiate_canonical_var_with_infer(info, |idx| { ty::UniverseIndex::from(prev_universe.index() + idx.index()) }) } else if info.is_existential() { @@ -322,18 +307,18 @@ impl<'tcx> EvalCtxt<'_, InferCtxt<'tcx>> { // more placeholders then they should be able to. However the inference variables have // to "come from somewhere", so by equating them with the original values of the caller // later on, we pull them down into their correct universe again. - if let Some(v) = opt_values[BoundVar::from_usize(index)] { + if let Some(v) = opt_values[ty::BoundVar::from_usize(index)] { v } else { - infcx.instantiate_canonical_var(DUMMY_SP, info, |_| prev_universe) + infcx.instantiate_canonical_var_with_infer(info, |_| prev_universe) } } else { // For placeholders which were already part of the input, we simply map this // universal bound variable back the placeholder of the input. original_values[info.expect_placeholder_index()] } - }, - )); + }), + ); CanonicalVarValues { var_values } } @@ -352,39 +337,35 @@ impl<'tcx> EvalCtxt<'_, InferCtxt<'tcx>> { /// always relate them structurally here. #[instrument(level = "trace", skip(infcx))] fn unify_query_var_values( - infcx: &InferCtxt<'tcx>, - param_env: ty::ParamEnv<'tcx>, - original_values: &[ty::GenericArg<'tcx>], - var_values: CanonicalVarValues<TyCtxt<'tcx>>, + infcx: &Infcx, + param_env: I::ParamEnv, + original_values: &[I::GenericArg], + var_values: CanonicalVarValues<I>, ) { assert_eq!(original_values.len(), var_values.len()); - let cause = ObligationCause::dummy(); for (&orig, response) in iter::zip(original_values, var_values.var_values) { - let InferOk { value: (), obligations } = infcx - .at(&cause, param_env) - .eq_structurally_relating_aliases(orig, response) - .unwrap(); - assert!(obligations.is_empty()); + let goals = infcx.eq_structurally_relating_aliases(param_env, orig, response).unwrap(); + assert!(goals.is_empty()); } } - fn register_region_constraints(&mut self, region_constraints: &QueryRegionConstraints<'tcx>) { - for &(ty::OutlivesPredicate(lhs, rhs), _) in ®ion_constraints.outlives { - match lhs.unpack() { - GenericArgKind::Lifetime(lhs) => self.register_region_outlives(lhs, rhs), - GenericArgKind::Type(lhs) => self.register_ty_outlives(lhs, rhs), - GenericArgKind::Const(_) => bug!("const outlives: {lhs:?}: {rhs:?}"), + fn register_region_constraints( + &mut self, + outlives: &[ty::OutlivesPredicate<I, I::GenericArg>], + ) { + for &ty::OutlivesPredicate(lhs, rhs) in outlives { + match lhs.kind() { + ty::GenericArgKind::Lifetime(lhs) => self.register_region_outlives(lhs, rhs), + ty::GenericArgKind::Type(lhs) => self.register_ty_outlives(lhs, rhs), + ty::GenericArgKind::Const(_) => panic!("const outlives: {lhs:?}: {rhs:?}"), } } - - assert!(region_constraints.member_constraints.is_empty()); } - fn register_new_opaque_types(&mut self, opaque_types: &[(ty::OpaqueTypeKey<'tcx>, Ty<'tcx>)]) { + fn register_new_opaque_types(&mut self, opaque_types: &[(ty::OpaqueTypeKey<I>, I::Ty)]) { for &(key, ty) in opaque_types { - let hidden_ty = ty::OpaqueHiddenType { ty, span: DUMMY_SP }; - self.infcx.inject_new_hidden_type_unchecked(key, hidden_ty); + self.infcx.inject_new_hidden_type_unchecked(key, ty); } } } @@ -400,7 +381,7 @@ pub(in crate::solve) fn make_canonical_state<Infcx, T, I>( data: T, ) -> inspect::CanonicalState<I, T> where - Infcx: InferCtxtLike<Interner = I>, + Infcx: SolverDelegate<Interner = I>, I: Interner, T: TypeFoldable<I>, { @@ -415,45 +396,33 @@ where ) } -/// Instantiate a `CanonicalState`. -/// -/// Unlike for query responses, `CanonicalState` also track fresh inference -/// variables created while evaluating a goal. When creating two separate -/// `CanonicalState` during a single evaluation both may reference this -/// fresh inference variable. When instantiating them we now create separate -/// inference variables for it and have to unify them somehow. We do this -/// by extending the `var_values` while building the proof tree. -/// -/// This currently assumes that unifying the var values trivially succeeds. -/// Adding any inference constraints which weren't present when originally -/// computing the canonical query can result in bugs. -#[instrument(level = "trace", skip(infcx, span, param_env))] -pub(in crate::solve) fn instantiate_canonical_state<'tcx, T: TypeFoldable<TyCtxt<'tcx>>>( - infcx: &InferCtxt<'tcx>, - span: Span, - param_env: ty::ParamEnv<'tcx>, - orig_values: &mut Vec<ty::GenericArg<'tcx>>, - state: inspect::CanonicalState<TyCtxt<'tcx>, T>, -) -> T { +// FIXME: needs to be pub to be accessed by downstream +// `rustc_trait_selection::solve::inspect::analyse`. +pub fn instantiate_canonical_state<Infcx, I, T: TypeFoldable<I>>( + infcx: &Infcx, + span: Infcx::Span, + param_env: I::ParamEnv, + orig_values: &mut Vec<I::GenericArg>, + state: inspect::CanonicalState<I, T>, +) -> T +where + Infcx: SolverDelegate<Interner = I>, + I: Interner, +{ // In case any fresh inference variables have been created between `state` // and the previous instantiation, extend `orig_values` for it. assert!(orig_values.len() <= state.value.var_values.len()); - for i in orig_values.len()..state.value.var_values.len() { - let unconstrained = match state.value.var_values.var_values[i].unpack() { - ty::GenericArgKind::Lifetime(_) => { - infcx.next_region_var(RegionVariableOrigin::MiscVariable(span)).into() - } - ty::GenericArgKind::Type(_) => infcx.next_ty_var(span).into(), - ty::GenericArgKind::Const(_) => infcx.next_const_var(span).into(), - }; - + for &arg in &state.value.var_values.var_values[orig_values.len()..state.value.var_values.len()] + { + // FIXME: This is so ugly. + let unconstrained = infcx.fresh_var_for_kind_with_span(arg, span); orig_values.push(unconstrained); } let instantiation = EvalCtxt::compute_query_response_instantiation_values(infcx, orig_values, &state); - let inspect::State { var_values, data } = state.instantiate(infcx.tcx, &instantiation); + let inspect::State { var_values, data } = infcx.instantiate_canonical(state, instantiation); EvalCtxt::unify_query_var_values(infcx, param_env, orig_values, var_values); data diff --git a/compiler/rustc_trait_selection/src/solve/eval_ctxt/mod.rs b/compiler/rustc_next_trait_solver/src/solve/eval_ctxt/mod.rs index 6b8375b53e8..485758b91a2 100644 --- a/compiler/rustc_trait_selection/src/solve/eval_ctxt/mod.rs +++ b/compiler/rustc_next_trait_solver/src/solve/eval_ctxt/mod.rs @@ -1,43 +1,30 @@ +use std::ops::ControlFlow; + use rustc_data_structures::stack::ensure_sufficient_stack; -use rustc_hir::def_id::DefId; -use rustc_infer::infer::{InferCtxt, TyCtxtInferExt}; -use rustc_infer::traits::query::NoSolution; -use rustc_infer::traits::solve::{MaybeCause, NestedNormalizationGoals}; -use rustc_infer::traits::ObligationCause; -use rustc_macros::{extension, HashStable, HashStable_NoContext, TyDecodable, TyEncodable}; -use rustc_middle::bug; -use rustc_middle::traits::solve::{ - inspect, CanonicalInput, CanonicalResponse, Certainty, PredefinedOpaquesData, QueryResult, -}; -use rustc_middle::ty::AliasRelationDirection; -use rustc_middle::ty::TypeFolder; -use rustc_middle::ty::{ - self, InferCtxtLike, OpaqueTypeKey, Ty, TyCtxt, TypeFoldable, TypeVisitableExt, -}; -use rustc_span::DUMMY_SP; -use rustc_type_ir::fold::TypeSuperFoldable; +use rustc_macros::{HashStable_NoContext, TyDecodable, TyEncodable}; +use rustc_type_ir::fold::{TypeFoldable, TypeFolder, 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::visit::{TypeSuperVisitable, TypeVisitable, TypeVisitableExt, TypeVisitor}; +use rustc_type_ir::{self as ty, CanonicalVarValues, Interner}; use rustc_type_ir_macros::{Lift_Generic, TypeFoldable_Generic, TypeVisitable_Generic}; -use std::ops::ControlFlow; - -use crate::traits::coherence; - -use super::inspect::ProofTreeBuilder; -use super::{search_graph, GoalEvaluationKind, FIXPOINT_STEP_LIMIT}; -use super::{search_graph::SearchGraph, Goal}; -use super::{GoalSource, SolverMode}; -pub use select::InferCtxtSelectExt; +use tracing::{instrument, trace}; + +use crate::infcx::SolverDelegate; +use crate::solve::inspect::{self, ProofTreeBuilder}; +use crate::solve::search_graph::SearchGraph; +use crate::solve::{ + search_graph, CanonicalInput, CanonicalResponse, Certainty, Goal, GoalEvaluationKind, + GoalSource, MaybeCause, NestedNormalizationGoals, NoSolution, PredefinedOpaquesData, + QueryResult, SolverMode, FIXPOINT_STEP_LIMIT, +}; pub(super) mod canonical; mod probe; -mod select; -pub struct EvalCtxt<'a, Infcx, I = <Infcx as InferCtxtLike>::Interner> +pub struct EvalCtxt<'a, Infcx, I = <Infcx as SolverDelegate>::Interner> where - Infcx: InferCtxtLike<Interner = I>, + Infcx: SolverDelegate<Interner = I>, I: Interner, { /// The inference context that backs (mostly) inference and placeholder terms @@ -114,9 +101,9 @@ pub struct NestedGoals<I: Interner> { /// /// Forgetting to replace the RHS with a fresh inference variable when we evaluate /// this goal results in an ICE.. - pub normalizes_to_goals: Vec<ir::solve::Goal<I, ir::NormalizesTo<I>>>, + pub normalizes_to_goals: Vec<Goal<I, ty::NormalizesTo<I>>>, /// The rest of the goals which have not yet processed or remain ambiguous. - pub goals: Vec<(GoalSource, ir::solve::Goal<I, I::Predicate>)>, + pub goals: Vec<(GoalSource, Goal<I, I::Predicate>)>, } impl<I: Interner> NestedGoals<I> { @@ -129,14 +116,36 @@ impl<I: Interner> NestedGoals<I> { } } -#[derive(PartialEq, Eq, Debug, Hash, HashStable, Clone, Copy)] +#[derive(PartialEq, Eq, Debug, Hash, HashStable_NoContext, Clone, Copy)] pub enum GenerateProofTree { Yes, No, } -#[extension(pub trait InferCtxtEvalExt<'tcx>)] -impl<'tcx> InferCtxt<'tcx> { +pub trait SolverDelegateEvalExt: SolverDelegate { + fn evaluate_root_goal( + &self, + goal: Goal<Self::Interner, <Self::Interner as Interner>::Predicate>, + generate_proof_tree: GenerateProofTree, + ) -> (Result<(bool, Certainty), NoSolution>, Option<inspect::GoalEvaluation<Self::Interner>>); + + // FIXME: This is only exposed because we need to use it in `analyse.rs` + // which is not yet uplifted. Once that's done, we should remove this. + fn evaluate_root_goal_raw( + &self, + goal: Goal<Self::Interner, <Self::Interner as Interner>::Predicate>, + generate_proof_tree: GenerateProofTree, + ) -> ( + Result<(NestedNormalizationGoals<Self::Interner>, bool, Certainty), NoSolution>, + Option<inspect::GoalEvaluation<Self::Interner>>, + ); +} + +impl<Infcx, I> SolverDelegateEvalExt for Infcx +where + Infcx: SolverDelegate<Interner = I>, + I: Interner, +{ /// Evaluates a goal from **outside** of the trait solver. /// /// Using this while inside of the solver is wrong as it uses a new @@ -144,17 +153,34 @@ impl<'tcx> InferCtxt<'tcx> { #[instrument(level = "debug", skip(self))] fn evaluate_root_goal( &self, - goal: Goal<'tcx, ty::Predicate<'tcx>>, + goal: Goal<I, I::Predicate>, generate_proof_tree: GenerateProofTree, - ) -> (Result<(bool, Certainty), NoSolution>, Option<inspect::GoalEvaluation<TyCtxt<'tcx>>>) - { + ) -> (Result<(bool, Certainty), NoSolution>, Option<inspect::GoalEvaluation<I>>) { EvalCtxt::enter_root(self, generate_proof_tree, |ecx| { ecx.evaluate_goal(GoalEvaluationKind::Root, GoalSource::Misc, goal) }) } + + #[instrument(level = "debug", skip(self))] + fn evaluate_root_goal_raw( + &self, + goal: Goal<I, I::Predicate>, + generate_proof_tree: GenerateProofTree, + ) -> ( + Result<(NestedNormalizationGoals<I>, bool, Certainty), NoSolution>, + Option<inspect::GoalEvaluation<I>>, + ) { + EvalCtxt::enter_root(self, generate_proof_tree, |ecx| { + ecx.evaluate_goal_raw(GoalEvaluationKind::Root, GoalSource::Misc, goal) + }) + } } -impl<'a, 'tcx> EvalCtxt<'a, InferCtxt<'tcx>> { +impl<'a, Infcx, I> EvalCtxt<'a, Infcx> +where + Infcx: SolverDelegate<Interner = I>, + I: Interner, +{ pub(super) fn solver_mode(&self) -> SolverMode { self.search_graph.solver_mode() } @@ -165,14 +191,13 @@ impl<'a, 'tcx> EvalCtxt<'a, InferCtxt<'tcx>> { /// Creates a root evaluation context and search graph. This should only be /// used from outside of any evaluation, and other methods should be preferred - /// over using this manually (such as [`InferCtxtEvalExt::evaluate_root_goal`]). + /// over using this manually (such as [`SolverDelegateEvalExt::evaluate_root_goal`]). pub(super) fn enter_root<R>( - infcx: &InferCtxt<'tcx>, + infcx: &Infcx, generate_proof_tree: GenerateProofTree, - f: impl FnOnce(&mut EvalCtxt<'_, InferCtxt<'tcx>>) -> R, - ) -> (R, Option<inspect::GoalEvaluation<TyCtxt<'tcx>>>) { - let mode = if infcx.intercrate { SolverMode::Coherence } else { SolverMode::Normal }; - let mut search_graph = search_graph::SearchGraph::new(mode); + f: impl FnOnce(&mut EvalCtxt<'_, Infcx>) -> R, + ) -> (R, Option<inspect::GoalEvaluation<I>>) { + let mut search_graph = search_graph::SearchGraph::new(infcx.solver_mode()); let mut ecx = EvalCtxt { infcx, @@ -183,10 +208,10 @@ impl<'a, 'tcx> EvalCtxt<'a, InferCtxt<'tcx>> { // Only relevant when canonicalizing the response, // which we don't do within this evaluation context. predefined_opaques_in_body: infcx - .tcx + .interner() .mk_predefined_opaques_in_body(PredefinedOpaquesData::default()), max_input_universe: ty::UniverseIndex::ROOT, - variables: ty::List::empty(), + variables: Default::default(), var_values: CanonicalVarValues::dummy(), is_normalizes_to_goal: false, tainted: Ok(()), @@ -212,21 +237,14 @@ impl<'a, 'tcx> EvalCtxt<'a, InferCtxt<'tcx>> { /// This function takes care of setting up the inference context, setting the anchor, /// and registering opaques from the canonicalized input. fn enter_canonical<R>( - tcx: TyCtxt<'tcx>, - search_graph: &'a mut search_graph::SearchGraph<TyCtxt<'tcx>>, - canonical_input: CanonicalInput<'tcx>, - canonical_goal_evaluation: &mut ProofTreeBuilder<InferCtxt<'tcx>>, - f: impl FnOnce(&mut EvalCtxt<'_, InferCtxt<'tcx>>, Goal<'tcx, ty::Predicate<'tcx>>) -> R, + tcx: I, + search_graph: &'a mut search_graph::SearchGraph<I>, + canonical_input: CanonicalInput<I>, + canonical_goal_evaluation: &mut ProofTreeBuilder<Infcx>, + f: impl FnOnce(&mut EvalCtxt<'_, Infcx>, Goal<I, I::Predicate>) -> R, ) -> R { - let intercrate = match search_graph.solver_mode() { - SolverMode::Normal => false, - SolverMode::Coherence => true, - }; - let (ref infcx, input, var_values) = tcx - .infer_ctxt() - .intercrate(intercrate) - .with_next_trait_solver(true) - .build_with_canonical(DUMMY_SP, &canonical_input); + let (ref infcx, input, var_values) = + SolverDelegate::build_with_canonical(tcx, search_graph.solver_mode(), &canonical_input); let mut ecx = EvalCtxt { infcx, @@ -242,8 +260,7 @@ impl<'a, 'tcx> EvalCtxt<'a, InferCtxt<'tcx>> { }; for &(key, ty) in &input.predefined_opaques_in_body.opaque_types { - let hidden_ty = ty::OpaqueHiddenType { ty, span: DUMMY_SP }; - ecx.infcx.inject_new_hidden_type_unchecked(key, hidden_ty); + ecx.infcx.inject_new_hidden_type_unchecked(key, ty); } if !ecx.nested_goals.is_empty() { @@ -258,7 +275,8 @@ impl<'a, 'tcx> EvalCtxt<'a, InferCtxt<'tcx>> { // instead of taking them. This would cause an ICE here, since we have // assertions against dropping an `InferCtxt` without taking opaques. // FIXME: Once we remove support for the old impl we can remove this. - let _ = infcx.take_opaque_types(); + // FIXME: Could we make `build_with_canonical` into `enter_with_canonical` and call this at the end? + infcx.reset_opaque_types(); result } @@ -270,15 +288,15 @@ impl<'a, 'tcx> EvalCtxt<'a, InferCtxt<'tcx>> { /// logic of the solver. /// /// Instead of calling this function directly, use either [EvalCtxt::evaluate_goal] - /// if you're inside of the solver or [InferCtxtEvalExt::evaluate_root_goal] if you're + /// if you're inside of the solver or [SolverDelegateEvalExt::evaluate_root_goal] if you're /// outside of it. #[instrument(level = "debug", skip(tcx, search_graph, goal_evaluation), ret)] fn evaluate_canonical_goal( - tcx: TyCtxt<'tcx>, - search_graph: &'a mut search_graph::SearchGraph<TyCtxt<'tcx>>, - canonical_input: CanonicalInput<'tcx>, - goal_evaluation: &mut ProofTreeBuilder<InferCtxt<'tcx>>, - ) -> QueryResult<'tcx> { + tcx: I, + search_graph: &'a mut search_graph::SearchGraph<I>, + canonical_input: CanonicalInput<I>, + goal_evaluation: &mut ProofTreeBuilder<Infcx>, + ) -> QueryResult<I> { let mut canonical_goal_evaluation = goal_evaluation.new_canonical_goal_evaluation(canonical_input); @@ -317,7 +335,7 @@ impl<'a, 'tcx> EvalCtxt<'a, InferCtxt<'tcx>> { &mut self, goal_evaluation_kind: GoalEvaluationKind, source: GoalSource, - goal: Goal<'tcx, ty::Predicate<'tcx>>, + goal: Goal<I, I::Predicate>, ) -> Result<(bool, Certainty), NoSolution> { let (normalization_nested_goals, has_changed, certainty) = self.evaluate_goal_raw(goal_evaluation_kind, source, goal)?; @@ -338,8 +356,8 @@ impl<'a, 'tcx> EvalCtxt<'a, InferCtxt<'tcx>> { &mut self, goal_evaluation_kind: GoalEvaluationKind, _source: GoalSource, - goal: Goal<'tcx, ty::Predicate<'tcx>>, - ) -> Result<(NestedNormalizationGoals<'tcx>, bool, Certainty), NoSolution> { + goal: Goal<I, I::Predicate>, + ) -> Result<(NestedNormalizationGoals<I>, bool, Certainty), NoSolution> { let (orig_values, canonical_goal) = self.canonicalize_goal(goal); let mut goal_evaluation = self.inspect.new_goal_evaluation(goal, &orig_values, goal_evaluation_kind); @@ -379,10 +397,10 @@ impl<'a, 'tcx> EvalCtxt<'a, InferCtxt<'tcx>> { fn instantiate_response_discarding_overflow( &mut self, - param_env: ty::ParamEnv<'tcx>, - original_values: Vec<ty::GenericArg<'tcx>>, - response: CanonicalResponse<'tcx>, - ) -> (NestedNormalizationGoals<'tcx>, Certainty, bool) { + param_env: I::ParamEnv, + original_values: Vec<I::GenericArg>, + response: CanonicalResponse<I>, + ) -> (NestedNormalizationGoals<I>, Certainty, bool) { if let Certainty::Maybe(MaybeCause::Overflow { .. }) = response.value.certainty { return (NestedNormalizationGoals::empty(), response.value.certainty, false); } @@ -395,7 +413,7 @@ impl<'a, 'tcx> EvalCtxt<'a, InferCtxt<'tcx>> { (normalization_nested_goals, certainty, has_changed) } - fn compute_goal(&mut self, goal: Goal<'tcx, ty::Predicate<'tcx>>) -> QueryResult<'tcx> { + fn compute_goal(&mut self, goal: Goal<I, I::Predicate>) -> QueryResult<I> { let Goal { param_env, predicate } = goal; let kind = predicate.kind(); if let Some(kind) = kind.no_bound_vars() { @@ -431,7 +449,7 @@ impl<'a, 'tcx> EvalCtxt<'a, InferCtxt<'tcx>> { self.compute_const_evaluatable_goal(Goal { param_env, predicate: ct }) } ty::PredicateKind::ConstEquate(_, _) => { - bug!("ConstEquate should not be emitted when `-Znext-solver` is active") + panic!("ConstEquate should not be emitted when `-Znext-solver` is active") } ty::PredicateKind::NormalizesTo(predicate) => { self.compute_normalizes_to_goal(Goal { param_env, predicate }) @@ -567,21 +585,16 @@ impl<'a, 'tcx> EvalCtxt<'a, InferCtxt<'tcx>> { } /// Record impl args in the proof tree for later access by `InspectCandidate`. - pub(crate) fn record_impl_args(&mut self, impl_args: ty::GenericArgsRef<'tcx>) { + pub(crate) fn record_impl_args(&mut self, impl_args: I::GenericArgs) { self.inspect.record_impl_args(self.infcx, self.max_input_universe, impl_args) } -} -impl<Infcx: InferCtxtLike<Interner = I>, I: Interner> EvalCtxt<'_, Infcx> { pub(super) fn interner(&self) -> I { self.infcx.interner() } #[instrument(level = "trace", skip(self))] - pub(super) fn add_normalizes_to_goal( - &mut self, - mut goal: ir::solve::Goal<I, ir::NormalizesTo<I>>, - ) { + pub(super) fn add_normalizes_to_goal(&mut self, mut goal: Goal<I, ty::NormalizesTo<I>>) { goal.predicate = goal .predicate .fold_with(&mut ReplaceAliasWithInfer { ecx: self, param_env: goal.param_env }); @@ -590,11 +603,7 @@ impl<Infcx: InferCtxtLike<Interner = I>, I: Interner> EvalCtxt<'_, Infcx> { } #[instrument(level = "debug", skip(self))] - pub(super) fn add_goal( - &mut self, - source: GoalSource, - mut goal: ir::solve::Goal<I, I::Predicate>, - ) { + pub(super) fn add_goal(&mut self, source: GoalSource, mut goal: Goal<I, I::Predicate>) { goal.predicate = goal .predicate .fold_with(&mut ReplaceAliasWithInfer { ecx: self, param_env: goal.param_env }); @@ -606,7 +615,7 @@ impl<Infcx: InferCtxtLike<Interner = I>, I: Interner> EvalCtxt<'_, Infcx> { pub(super) fn add_goals( &mut self, source: GoalSource, - goals: impl IntoIterator<Item = ir::solve::Goal<I, I::Predicate>>, + goals: impl IntoIterator<Item = Goal<I, I::Predicate>>, ) { for goal in goals { self.add_goal(source, goal); @@ -629,8 +638,8 @@ impl<Infcx: InferCtxtLike<Interner = I>, I: Interner> EvalCtxt<'_, Infcx> { /// 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: I::Term) -> I::Term { match kind.kind() { - ir::TermKind::Ty(_) => self.next_ty_infer().into(), - ir::TermKind::Const(_) => self.next_const_infer().into(), + ty::TermKind::Ty(_) => self.next_ty_infer().into(), + ty::TermKind::Const(_) => self.next_const_infer().into(), } } @@ -639,20 +648,17 @@ impl<Infcx: InferCtxtLike<Interner = I>, I: Interner> EvalCtxt<'_, Infcx> { /// This is the case if the `term` does not occur in any other part of the predicate /// and is able to name all other placeholder and inference variables. #[instrument(level = "trace", skip(self), ret)] - pub(super) fn term_is_fully_unconstrained( - &self, - goal: ir::solve::Goal<I, ir::NormalizesTo<I>>, - ) -> bool { + pub(super) fn term_is_fully_unconstrained(&self, goal: Goal<I, ty::NormalizesTo<I>>) -> bool { let universe_of_term = match goal.predicate.term.kind() { - ir::TermKind::Ty(ty) => { - if let ir::Infer(ir::TyVar(vid)) = ty.kind() { + ty::TermKind::Ty(ty) => { + if let ty::Infer(ty::TyVar(vid)) = ty.kind() { self.infcx.universe_of_ty(vid).unwrap() } else { return false; } } - ir::TermKind::Const(ct) => { - if let ir::ConstKind::Infer(ir::InferConst::Var(vid)) = ct.kind() { + ty::TermKind::Const(ct) => { + if let ty::ConstKind::Infer(ty::InferConst::Var(vid)) = ct.kind() { self.infcx.universe_of_ct(vid).unwrap() } else { return false; @@ -660,14 +666,14 @@ impl<Infcx: InferCtxtLike<Interner = I>, I: Interner> EvalCtxt<'_, Infcx> { } }; - struct ContainsTermOrNotNameable<'a, Infcx: InferCtxtLike<Interner = I>, I: Interner> { + struct ContainsTermOrNotNameable<'a, Infcx: SolverDelegate<Interner = I>, I: Interner> { term: I::Term, - universe_of_term: ir::UniverseIndex, + universe_of_term: ty::UniverseIndex, infcx: &'a Infcx, } - impl<Infcx: InferCtxtLike<Interner = I>, I: Interner> ContainsTermOrNotNameable<'_, Infcx, I> { - fn check_nameable(&self, universe: ir::UniverseIndex) -> ControlFlow<()> { + impl<Infcx: SolverDelegate<Interner = I>, I: Interner> ContainsTermOrNotNameable<'_, Infcx, I> { + fn check_nameable(&self, universe: ty::UniverseIndex) -> ControlFlow<()> { if self.universe_of_term.can_name(universe) { ControlFlow::Continue(()) } else { @@ -676,15 +682,15 @@ impl<Infcx: InferCtxtLike<Interner = I>, I: Interner> EvalCtxt<'_, Infcx> { } } - impl<Infcx: InferCtxtLike<Interner = I>, I: Interner> TypeVisitor<I> + impl<Infcx: SolverDelegate<Interner = I>, I: Interner> TypeVisitor<I> for ContainsTermOrNotNameable<'_, Infcx, I> { type Result = ControlFlow<()>; 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() + ty::Infer(ty::TyVar(vid)) => { + if let ty::TermKind::Ty(term) = self.term.kind() + && let ty::Infer(ty::TyVar(term_vid)) = term.kind() && self.infcx.root_ty_var(vid) == self.infcx.root_ty_var(term_vid) { ControlFlow::Break(()) @@ -692,7 +698,7 @@ impl<Infcx: InferCtxtLike<Interner = I>, I: Interner> EvalCtxt<'_, Infcx> { self.check_nameable(self.infcx.universe_of_ty(vid).unwrap()) } } - ir::Placeholder(p) => self.check_nameable(p.universe()), + ty::Placeholder(p) => self.check_nameable(p.universe()), _ => { if t.has_non_region_infer() || t.has_placeholders() { t.super_visit_with(self) @@ -705,9 +711,9 @@ impl<Infcx: InferCtxtLike<Interner = I>, I: Interner> EvalCtxt<'_, Infcx> { fn visit_const(&mut self, c: I::Const) -> Self::Result { match c.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() + ty::ConstKind::Infer(ty::InferConst::Var(vid)) => { + if let ty::TermKind::Const(term) = self.term.kind() + && let ty::ConstKind::Infer(ty::InferConst::Var(term_vid)) = term.kind() && self.infcx.root_const_var(vid) == self.infcx.root_const_var(term_vid) { ControlFlow::Break(()) @@ -715,7 +721,7 @@ impl<Infcx: InferCtxtLike<Interner = I>, I: Interner> EvalCtxt<'_, Infcx> { self.check_nameable(self.infcx.universe_of_ct(vid).unwrap()) } } - ir::ConstKind::Placeholder(p) => self.check_nameable(p.universe()), + ty::ConstKind::Placeholder(p) => self.check_nameable(p.universe()), _ => { if c.has_non_region_infer() || c.has_placeholders() { c.super_visit_with(self) @@ -743,7 +749,7 @@ impl<Infcx: InferCtxtLike<Interner = I>, I: Interner> EvalCtxt<'_, Infcx> { lhs: T, rhs: T, ) -> Result<(), NoSolution> { - self.relate(param_env, lhs, ir::Variance::Invariant, rhs) + self.relate(param_env, lhs, ty::Variance::Invariant, rhs) } /// This should be used when relating a rigid alias with another type. @@ -755,8 +761,8 @@ impl<Infcx: InferCtxtLike<Interner = I>, I: Interner> EvalCtxt<'_, Infcx> { pub(super) fn relate_rigid_alias_non_alias( &mut self, param_env: I::ParamEnv, - alias: ir::AliasTerm<I>, - variance: ir::Variance, + alias: ty::AliasTerm<I>, + variance: ty::Variance, term: I::Term, ) -> Result<(), NoSolution> { // NOTE: this check is purely an optimization, the structural eq would @@ -772,7 +778,7 @@ impl<Infcx: InferCtxtLike<Interner = I>, I: Interner> EvalCtxt<'_, Infcx> { // 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 = ir::AliasTerm::new(tcx, alias.def_id, identity_args); + let rigid_ctor = ty::AliasTerm::new(tcx, alias.def_id, identity_args); let ctor_term = rigid_ctor.to_term(tcx); let obligations = self.infcx.eq_structurally_relating_aliases(param_env, term, ctor_term)?; @@ -805,7 +811,7 @@ impl<Infcx: InferCtxtLike<Interner = I>, I: Interner> EvalCtxt<'_, Infcx> { sub: T, sup: T, ) -> Result<(), NoSolution> { - self.relate(param_env, sub, ir::Variance::Covariant, sup) + self.relate(param_env, sub, ty::Variance::Covariant, sup) } #[instrument(level = "trace", skip(self, param_env), ret)] @@ -813,7 +819,7 @@ impl<Infcx: InferCtxtLike<Interner = I>, I: Interner> EvalCtxt<'_, Infcx> { &mut self, param_env: I::ParamEnv, lhs: T, - variance: ir::Variance, + variance: ty::Variance, rhs: T, ) -> Result<(), NoSolution> { let goals = self.infcx.relate(param_env, lhs, variance, rhs)?; @@ -832,20 +838,20 @@ impl<Infcx: InferCtxtLike<Interner = I>, I: Interner> EvalCtxt<'_, Infcx> { param_env: I::ParamEnv, lhs: T, rhs: T, - ) -> Result<Vec<ir::solve::Goal<I, I::Predicate>>, NoSolution> { - self.infcx.relate(param_env, lhs, ir::Variance::Invariant, rhs) + ) -> Result<Vec<Goal<I, I::Predicate>>, NoSolution> { + self.infcx.relate(param_env, lhs, ty::Variance::Invariant, rhs) } pub(super) fn instantiate_binder_with_infer<T: TypeFoldable<I> + Copy>( &self, - value: ir::Binder<I, T>, + value: ty::Binder<I, T>, ) -> T { self.infcx.instantiate_binder_with_infer(value) } pub(super) fn enter_forall<T: TypeFoldable<I> + Copy, U>( &self, - value: ir::Binder<I, T>, + value: ty::Binder<I, T>, f: impl FnOnce(T) -> U, ) -> U { self.infcx.enter_forall(value, f) @@ -865,89 +871,72 @@ impl<Infcx: InferCtxtLike<Interner = I>, I: Interner> EvalCtxt<'_, Infcx> { } 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()); + pub(super) fn register_ty_outlives(&self, ty: I::Ty, lt: I::Region) { + self.infcx.register_ty_outlives(ty, lt); } - pub(super) fn register_region_outlives(&self, a: ty::Region<'tcx>, b: ty::Region<'tcx>) { + pub(super) fn register_region_outlives(&self, a: I::Region, b: I::Region) { // `b : a` ==> `a <= b` - // (inlined from `InferCtxt::region_outlives_predicate`) - self.infcx.sub_regions( - rustc_infer::infer::SubregionOrigin::RelateRegionParamBound(DUMMY_SP), - b, - a, - ); + self.infcx.sub_regions(b, a); } /// Computes the list of goals required for `arg` to be well-formed pub(super) fn well_formed_goals( &self, - param_env: ty::ParamEnv<'tcx>, - arg: ty::GenericArg<'tcx>, - ) -> Option<impl Iterator<Item = Goal<'tcx, ty::Predicate<'tcx>>>> { - crate::traits::wf::unnormalized_obligations(self.infcx, param_env, arg) - .map(|obligations| obligations.into_iter().map(|obligation| obligation.into())) - } - - pub(super) fn is_transmutable( - &self, - src_and_dst: rustc_transmute::Types<'tcx>, - assume: rustc_transmute::Assume, - ) -> Result<Certainty, NoSolution> { - use rustc_transmute::Answer; - // FIXME(transmutability): This really should be returning nested goals for `Answer::If*` - match rustc_transmute::TransmuteTypeEnv::new(self.infcx).is_transmutable( - ObligationCause::dummy(), - src_and_dst, - assume, - ) { - Answer::Yes => Ok(Certainty::Yes), - Answer::No(_) | Answer::If(_) => Err(NoSolution), - } + param_env: I::ParamEnv, + arg: I::GenericArg, + ) -> Option<Vec<Goal<I, I::Predicate>>> { + self.infcx.well_formed_goals(param_env, arg) } pub(super) fn trait_ref_is_knowable( &mut self, - param_env: ty::ParamEnv<'tcx>, - trait_ref: ty::TraitRef<'tcx>, + param_env: I::ParamEnv, + trait_ref: ty::TraitRef<I>, ) -> Result<bool, NoSolution> { let infcx = self.infcx; let lazily_normalize_ty = |ty| self.structurally_normalize_ty(param_env, ty); - coherence::trait_ref_is_knowable(infcx, trait_ref, lazily_normalize_ty) - .map(|is_knowable| is_knowable.is_ok()) + infcx.trait_ref_is_knowable(trait_ref, lazily_normalize_ty) } - pub(super) fn can_define_opaque_ty(&self, def_id: impl Into<DefId>) -> bool { - self.infcx.can_define_opaque_ty(def_id) + pub(super) fn fetch_eligible_assoc_item( + &self, + param_env: I::ParamEnv, + goal_trait_ref: ty::TraitRef<I>, + trait_assoc_def_id: I::DefId, + impl_def_id: I::DefId, + ) -> Result<Option<I::DefId>, NoSolution> { + self.infcx.fetch_eligible_assoc_item( + param_env, + goal_trait_ref, + trait_assoc_def_id, + impl_def_id, + ) + } + + pub(super) fn can_define_opaque_ty(&self, def_id: I::LocalDefId) -> bool { + self.infcx.defining_opaque_types().contains(&def_id) } pub(super) fn insert_hidden_type( &mut self, - opaque_type_key: OpaqueTypeKey<'tcx>, - param_env: ty::ParamEnv<'tcx>, - hidden_ty: Ty<'tcx>, + opaque_type_key: ty::OpaqueTypeKey<I>, + param_env: I::ParamEnv, + hidden_ty: I::Ty, ) -> Result<(), NoSolution> { let mut goals = Vec::new(); - self.infcx.insert_hidden_type( - opaque_type_key, - DUMMY_SP, - param_env, - hidden_ty, - &mut goals, - )?; + self.infcx.insert_hidden_type(opaque_type_key, param_env, hidden_ty, &mut goals)?; self.add_goals(GoalSource::Misc, goals); Ok(()) } pub(super) fn add_item_bounds_for_hidden_type( &mut self, - opaque_def_id: DefId, - opaque_args: ty::GenericArgsRef<'tcx>, - param_env: ty::ParamEnv<'tcx>, - hidden_ty: Ty<'tcx>, + opaque_def_id: I::DefId, + opaque_args: I::GenericArgs, + param_env: I::ParamEnv, + hidden_ty: I::Ty, ) { let mut goals = Vec::new(); self.infcx.add_item_bounds_for_hidden_type( @@ -964,10 +953,10 @@ impl<'tcx> EvalCtxt<'_, InferCtxt<'tcx>> { // current inference context. pub(super) fn unify_existing_opaque_tys( &mut self, - param_env: ty::ParamEnv<'tcx>, - key: ty::OpaqueTypeKey<'tcx>, - ty: Ty<'tcx>, - ) -> Vec<CanonicalResponse<'tcx>> { + param_env: I::ParamEnv, + key: ty::OpaqueTypeKey<I>, + ty: I::Ty, + ) -> Vec<CanonicalResponse<I>> { // FIXME: Super inefficient to be cloning this... let opaques = self.infcx.clone_opaque_types_for_query_response(); @@ -986,7 +975,7 @@ impl<'tcx> EvalCtxt<'_, InferCtxt<'tcx>> { } ecx.eq(param_env, candidate_ty, ty)?; ecx.add_item_bounds_for_hidden_type( - candidate_key.def_id.to_def_id(), + candidate_key.def_id.into(), candidate_key.args, param_env, candidate_ty, @@ -1003,23 +992,20 @@ impl<'tcx> EvalCtxt<'_, InferCtxt<'tcx>> { // as an ambiguity rather than no-solution. pub(super) fn try_const_eval_resolve( &self, - param_env: ty::ParamEnv<'tcx>, - unevaluated: ty::UnevaluatedConst<'tcx>, - ) -> Option<ty::Const<'tcx>> { - use rustc_middle::mir::interpret::ErrorHandled; - match self.infcx.const_eval_resolve(param_env, unevaluated, DUMMY_SP) { - Ok(Some(val)) => Some(ty::Const::new_value( - self.interner(), - val, - self.interner() - .type_of(unevaluated.def) - .instantiate(self.interner(), unevaluated.args), - )), - Ok(None) | Err(ErrorHandled::TooGeneric(_)) => None, - Err(ErrorHandled::Reported(e, _)) => { - Some(ty::Const::new_error(self.interner(), e.into())) - } - } + param_env: I::ParamEnv, + unevaluated: ty::UnevaluatedConst<I>, + ) -> Option<I::Const> { + self.infcx.try_const_eval_resolve(param_env, unevaluated) + } + + pub(super) fn is_transmutable( + &mut self, + param_env: I::ParamEnv, + dst: I::Ty, + src: I::Ty, + assume: I::Const, + ) -> Result<Certainty, NoSolution> { + self.infcx.is_transmutable(param_env, dst, src, assume) } } @@ -1032,7 +1018,7 @@ impl<'tcx> EvalCtxt<'_, InferCtxt<'tcx>> { /// solving. See tests/ui/traits/next-solver/cycles/cycle-modulo-ambig-aliases.rs. struct ReplaceAliasWithInfer<'me, 'a, Infcx, I> where - Infcx: InferCtxtLike<Interner = I>, + Infcx: SolverDelegate<Interner = I>, I: Interner, { ecx: &'me mut EvalCtxt<'a, Infcx>, @@ -1041,7 +1027,7 @@ where impl<Infcx, I> TypeFolder<I> for ReplaceAliasWithInfer<'_, '_, Infcx, I> where - Infcx: InferCtxtLike<Interner = I>, + Infcx: SolverDelegate<Interner = I>, I: Interner, { fn interner(&self) -> I { @@ -1050,16 +1036,16 @@ where fn fold_ty(&mut self, ty: I::Ty) -> I::Ty { match ty.kind() { - ir::Alias(..) if !ty.has_escaping_bound_vars() => { + ty::Alias(..) if !ty.has_escaping_bound_vars() => { let infer_ty = self.ecx.next_ty_infer(); - let normalizes_to = ir::PredicateKind::AliasRelate( + let normalizes_to = ty::PredicateKind::AliasRelate( ty.into(), infer_ty.into(), - AliasRelationDirection::Equate, + ty::AliasRelationDirection::Equate, ); self.ecx.add_goal( GoalSource::Misc, - ir::solve::Goal::new(self.interner(), self.param_env, normalizes_to), + Goal::new(self.interner(), self.param_env, normalizes_to), ); infer_ty } @@ -1069,16 +1055,16 @@ where fn fold_const(&mut self, ct: I::Const) -> I::Const { match ct.kind() { - ir::ConstKind::Unevaluated(..) if !ct.has_escaping_bound_vars() => { + ty::ConstKind::Unevaluated(..) if !ct.has_escaping_bound_vars() => { let infer_ct = self.ecx.next_const_infer(); - let normalizes_to = ir::PredicateKind::AliasRelate( + let normalizes_to = ty::PredicateKind::AliasRelate( ct.into(), infer_ct.into(), - AliasRelationDirection::Equate, + ty::AliasRelationDirection::Equate, ); self.ecx.add_goal( GoalSource::Misc, - ir::solve::Goal::new(self.interner(), self.param_env, normalizes_to), + Goal::new(self.interner(), self.param_env, normalizes_to), ); infer_ct } diff --git a/compiler/rustc_trait_selection/src/solve/eval_ctxt/probe.rs b/compiler/rustc_next_trait_solver/src/solve/eval_ctxt/probe.rs index ad6fdd2707d..1c5358b3edb 100644 --- a/compiler/rustc_trait_selection/src/solve/eval_ctxt/probe.rs +++ b/compiler/rustc_next_trait_solver/src/solve/eval_ctxt/probe.rs @@ -1,15 +1,16 @@ -use crate::solve::assembly::Candidate; - -use super::EvalCtxt; -use rustc_next_trait_solver::solve::{ - inspect, BuiltinImplSource, CandidateSource, NoSolution, QueryResult, -}; -use rustc_type_ir::{InferCtxtLike, Interner}; use std::marker::PhantomData; +use rustc_type_ir::Interner; +use tracing::instrument; + +use crate::infcx::SolverDelegate; +use crate::solve::assembly::Candidate; +use crate::solve::inspect; +use crate::solve::{BuiltinImplSource, CandidateSource, EvalCtxt, NoSolution, QueryResult}; + pub(in crate::solve) struct ProbeCtxt<'me, 'a, Infcx, I, F, T> where - Infcx: InferCtxtLike<Interner = I>, + Infcx: SolverDelegate<Interner = I>, I: Interner, { ecx: &'me mut EvalCtxt<'a, Infcx, I>, @@ -20,7 +21,7 @@ where impl<Infcx, I, F, T> ProbeCtxt<'_, '_, Infcx, I, F, T> where F: FnOnce(&T) -> inspect::ProbeKind<I>, - Infcx: InferCtxtLike<Interner = I>, + Infcx: SolverDelegate<Interner = I>, I: Interner, { pub(in crate::solve) fn enter(self, f: impl FnOnce(&mut EvalCtxt<'_, Infcx>) -> T) -> T { @@ -56,7 +57,7 @@ where pub(in crate::solve) struct TraitProbeCtxt<'me, 'a, Infcx, I, F> where - Infcx: InferCtxtLike<Interner = I>, + Infcx: SolverDelegate<Interner = I>, I: Interner, { cx: ProbeCtxt<'me, 'a, Infcx, I, F, QueryResult<I>>, @@ -65,7 +66,7 @@ where impl<Infcx, I, F> TraitProbeCtxt<'_, '_, Infcx, I, F> where - Infcx: InferCtxtLike<Interner = I>, + Infcx: SolverDelegate<Interner = I>, I: Interner, F: FnOnce(&QueryResult<I>) -> inspect::ProbeKind<I>, { @@ -80,7 +81,7 @@ where impl<'a, Infcx, I> EvalCtxt<'a, Infcx, I> where - Infcx: InferCtxtLike<Interner = I>, + Infcx: SolverDelegate<Interner = I>, I: Interner, { /// `probe_kind` is only called when proof tree building is enabled so it can be diff --git a/compiler/rustc_trait_selection/src/solve/inspect/build.rs b/compiler/rustc_next_trait_solver/src/solve/inspect/build.rs index 35750598bc7..5fbec4b28d4 100644 --- a/compiler/rustc_trait_selection/src/solve/inspect/build.rs +++ b/compiler/rustc_next_trait_solver/src/solve/inspect/build.rs @@ -3,16 +3,19 @@ //! This code is *a bit* of a mess and can hopefully be //! mostly ignored. For a general overview of how it works, //! see the comment on [ProofTreeBuilder]. + use std::marker::PhantomData; use std::mem; +use rustc_type_ir::{self as ty, Interner}; + +use crate::infcx::SolverDelegate; use crate::solve::eval_ctxt::canonical; -use crate::solve::{self, inspect, GenerateProofTree}; -use rustc_middle::bug; -use rustc_next_trait_solver::solve::{ - CanonicalInput, Certainty, Goal, GoalSource, QueryInput, QueryResult, +use crate::solve::inspect; +use crate::solve::{ + CanonicalInput, Certainty, GenerateProofTree, Goal, GoalEvaluationKind, GoalSource, QueryInput, + QueryResult, }; -use rustc_type_ir::{self as ty, InferCtxtLike, Interner}; /// The core data structure when building proof trees. /// @@ -34,9 +37,9 @@ 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<Infcx, I = <Infcx as InferCtxtLike>::Interner> +pub(in crate::solve) struct ProofTreeBuilder<Infcx, I = <Infcx as SolverDelegate>::Interner> where - Infcx: InferCtxtLike<Interner = I>, + Infcx: SolverDelegate<Interner = I>, I: Interner, { _infcx: PhantomData<Infcx>, @@ -170,7 +173,7 @@ impl<I: Interner> WipCanonicalGoalEvaluationStep<I> { for _ in 0..self.probe_depth { match current.steps.last_mut() { Some(WipProbeStep::NestedProbe(p)) => current = p, - _ => bug!(), + _ => panic!(), } } current @@ -232,7 +235,7 @@ impl<I: Interner> WipProbeStep<I> { } } -impl<Infcx: InferCtxtLike<Interner = I>, I: Interner> ProofTreeBuilder<Infcx> { +impl<Infcx: SolverDelegate<Interner = I>, I: Interner> ProofTreeBuilder<Infcx> { fn new(state: impl Into<DebugSolver<I>>) -> ProofTreeBuilder<Infcx> { ProofTreeBuilder { state: Some(Box::new(state.into())), _infcx: PhantomData } } @@ -293,15 +296,15 @@ impl<Infcx: InferCtxtLike<Interner = I>, I: Interner> ProofTreeBuilder<Infcx> { &mut self, goal: Goal<I, I::Predicate>, orig_values: &[I::GenericArg], - kind: solve::GoalEvaluationKind, + kind: GoalEvaluationKind, ) -> ProofTreeBuilder<Infcx> { self.opt_nested(|| match kind { - solve::GoalEvaluationKind::Root => Some(WipGoalEvaluation { + GoalEvaluationKind::Root => Some(WipGoalEvaluation { uncanonicalized_goal: goal, orig_values: orig_values.to_vec(), evaluation: None, }), - solve::GoalEvaluationKind::Nested => None, + GoalEvaluationKind::Nested => None, }) } @@ -413,7 +416,7 @@ impl<Infcx: InferCtxtLike<Interner = I>, I: Interner> ProofTreeBuilder<Infcx> { Some(DebugSolver::CanonicalGoalEvaluationStep(state)) => { state.var_values.push(arg.into()); } - Some(s) => bug!("tried to add var values to {s:?}"), + Some(s) => panic!("tried to add var values to {s:?}"), } } @@ -430,7 +433,7 @@ impl<Infcx: InferCtxtLike<Interner = I>, I: Interner> ProofTreeBuilder<Infcx> { })); state.probe_depth += 1; } - Some(s) => bug!("tried to start probe to {s:?}"), + Some(s) => panic!("tried to start probe to {s:?}"), } } @@ -441,7 +444,7 @@ impl<Infcx: InferCtxtLike<Interner = I>, I: Interner> ProofTreeBuilder<Infcx> { let prev = state.current_evaluation_scope().kind.replace(probe_kind); assert_eq!(prev, None); } - _ => bug!(), + _ => panic!(), } } @@ -458,7 +461,7 @@ impl<Infcx: InferCtxtLike<Interner = I>, I: Interner> ProofTreeBuilder<Infcx> { let prev = state.current_evaluation_scope().final_state.replace(final_state); assert_eq!(prev, None); } - _ => bug!(), + _ => panic!(), } } @@ -494,7 +497,7 @@ impl<Infcx: InferCtxtLike<Interner = I>, I: Interner> ProofTreeBuilder<Infcx> { ); state.current_evaluation_scope().steps.push(WipProbeStep::AddGoal(source, goal)) } - _ => bug!(), + _ => panic!(), } } @@ -518,7 +521,7 @@ impl<Infcx: InferCtxtLike<Interner = I>, I: Interner> ProofTreeBuilder<Infcx> { .push(WipProbeStep::RecordImplArgs { impl_args }); } None => {} - _ => bug!(), + _ => panic!(), } } @@ -531,7 +534,7 @@ impl<Infcx: InferCtxtLike<Interner = I>, I: Interner> ProofTreeBuilder<Infcx> { .push(WipProbeStep::MakeCanonicalResponse { shallow_certainty }); } None => {} - _ => bug!(), + _ => panic!(), } } @@ -544,7 +547,7 @@ impl<Infcx: InferCtxtLike<Interner = I>, I: Interner> ProofTreeBuilder<Infcx> { state.var_values.truncate(num_var_values); state.probe_depth -= 1; } - _ => bug!(), + _ => panic!(), } self diff --git a/compiler/rustc_next_trait_solver/src/solve/inspect/mod.rs b/compiler/rustc_next_trait_solver/src/solve/inspect/mod.rs new file mode 100644 index 00000000000..0d8c0060126 --- /dev/null +++ b/compiler/rustc_next_trait_solver/src/solve/inspect/mod.rs @@ -0,0 +1,6 @@ +pub use rustc_type_ir::solve::inspect::*; + +mod build; +pub(in crate::solve) use build::*; + +pub use crate::solve::eval_ctxt::canonical::instantiate_canonical_state; diff --git a/compiler/rustc_trait_selection/src/solve/mod.rs b/compiler/rustc_next_trait_solver/src/solve/mod.rs index fdcf4ff11e4..02069016c2b 100644 --- a/compiler/rustc_trait_selection/src/solve/mod.rs +++ b/compiler/rustc_next_trait_solver/src/solve/mod.rs @@ -13,36 +13,23 @@ //! //! FIXME(@lcnr): Write that section. If you read this before then ask me //! about it on zulip. -use rustc_hir::def_id::DefId; -use rustc_infer::infer::canonical::{Canonical, CanonicalVarValues}; -use rustc_infer::infer::InferCtxt; -use rustc_infer::traits::query::NoSolution; -use rustc_macros::extension; -use rustc_middle::bug; -use rustc_middle::infer::canonical::CanonicalVarInfos; -use rustc_middle::traits::solve::{ - CanonicalResponse, Certainty, ExternalConstraintsData, Goal, GoalSource, QueryResult, Response, -}; -use rustc_middle::ty::{ - self, AliasRelationDirection, CoercePredicate, RegionOutlivesPredicate, SubtypePredicate, Ty, - TyCtxt, TypeOutlivesPredicate, UniverseIndex, -}; mod alias_relate; mod assembly; mod eval_ctxt; -mod fulfill; pub mod inspect; -mod normalize; mod normalizes_to; mod project_goals; mod search_graph; mod trait_goals; -pub use eval_ctxt::{EvalCtxt, GenerateProofTree, InferCtxtEvalExt, InferCtxtSelectExt}; -pub use fulfill::{FulfillmentCtxt, NextSolverError}; -pub(crate) use normalize::deeply_normalize_for_diagnostics; -pub use normalize::{deeply_normalize, deeply_normalize_with_skipped_universes}; +use rustc_type_ir::inherent::*; +pub use rustc_type_ir::solve::*; +use rustc_type_ir::{self as ty, Interner}; +use tracing::instrument; + +pub use self::eval_ctxt::{EvalCtxt, GenerateProofTree, SolverDelegateEvalExt}; +use crate::infcx::SolverDelegate; /// How many fixpoint iterations we should attempt inside of the solver before bailing /// with overflow. @@ -55,40 +42,30 @@ pub use normalize::{deeply_normalize, deeply_normalize_with_skipped_universes}; /// recursion limit again. However, this feels very unlikely. const FIXPOINT_STEP_LIMIT: usize = 8; -#[derive(Debug, Clone, Copy)] -enum SolverMode { - /// Ordinary trait solving, using everywhere except for coherence. - Normal, - /// Trait solving during coherence. There are a few notable differences - /// between coherence and ordinary trait solving. - /// - /// Most importantly, trait solving during coherence must not be incomplete, - /// i.e. return `Err(NoSolution)` for goals for which a solution exists. - /// This means that we must not make any guesses or arbitrary choices. - Coherence, -} - #[derive(Debug, Copy, Clone, PartialEq, Eq)] enum GoalEvaluationKind { Root, Nested, } -#[extension(trait CanonicalResponseExt)] -impl<'tcx> Canonical<'tcx, Response<TyCtxt<'tcx>>> { - fn has_no_inference_or_external_constraints(&self) -> bool { - self.value.external_constraints.region_constraints.is_empty() - && self.value.var_values.is_identity() - && self.value.external_constraints.opaque_types.is_empty() - } +fn has_no_inference_or_external_constraints<I: Interner>( + response: ty::Canonical<I, Response<I>>, +) -> bool { + response.value.external_constraints.region_constraints.is_empty() + && response.value.var_values.is_identity() + && response.value.external_constraints.opaque_types.is_empty() } -impl<'a, 'tcx> EvalCtxt<'a, InferCtxt<'tcx>> { +impl<'a, Infcx, I> EvalCtxt<'a, Infcx> +where + Infcx: SolverDelegate<Interner = I>, + I: Interner, +{ #[instrument(level = "trace", skip(self))] fn compute_type_outlives_goal( &mut self, - goal: Goal<'tcx, TypeOutlivesPredicate<'tcx>>, - ) -> QueryResult<'tcx> { + goal: Goal<I, ty::OutlivesPredicate<I, I::Ty>>, + ) -> QueryResult<I> { let ty::OutlivesPredicate(ty, lt) = goal.predicate; self.register_ty_outlives(ty, lt); self.evaluate_added_goals_and_make_canonical_response(Certainty::Yes) @@ -97,21 +74,18 @@ impl<'a, 'tcx> EvalCtxt<'a, InferCtxt<'tcx>> { #[instrument(level = "trace", skip(self))] fn compute_region_outlives_goal( &mut self, - goal: Goal<'tcx, RegionOutlivesPredicate<'tcx>>, - ) -> QueryResult<'tcx> { + goal: Goal<I, ty::OutlivesPredicate<I, I::Region>>, + ) -> QueryResult<I> { let ty::OutlivesPredicate(a, b) = goal.predicate; self.register_region_outlives(a, b); self.evaluate_added_goals_and_make_canonical_response(Certainty::Yes) } #[instrument(level = "trace", skip(self))] - fn compute_coerce_goal( - &mut self, - goal: Goal<'tcx, CoercePredicate<'tcx>>, - ) -> QueryResult<'tcx> { + fn compute_coerce_goal(&mut self, goal: Goal<I, ty::CoercePredicate<I>>) -> QueryResult<I> { self.compute_subtype_goal(Goal { param_env: goal.param_env, - predicate: SubtypePredicate { + predicate: ty::SubtypePredicate { a_is_expected: false, a: goal.predicate.a, b: goal.predicate.b, @@ -120,10 +94,7 @@ impl<'a, 'tcx> EvalCtxt<'a, InferCtxt<'tcx>> { } #[instrument(level = "trace", skip(self))] - fn compute_subtype_goal( - &mut self, - goal: Goal<'tcx, SubtypePredicate<'tcx>>, - ) -> QueryResult<'tcx> { + fn compute_subtype_goal(&mut self, goal: Goal<I, ty::SubtypePredicate<I>>) -> QueryResult<I> { if goal.predicate.a.is_ty_var() && goal.predicate.b.is_ty_var() { self.evaluate_added_goals_and_make_canonical_response(Certainty::AMBIGUOUS) } else { @@ -132,8 +103,8 @@ impl<'a, 'tcx> EvalCtxt<'a, InferCtxt<'tcx>> { } } - fn compute_object_safe_goal(&mut self, trait_def_id: DefId) -> QueryResult<'tcx> { - if self.interner().is_object_safe(trait_def_id) { + fn compute_object_safe_goal(&mut self, trait_def_id: I::DefId) -> QueryResult<I> { + if self.interner().trait_is_object_safe(trait_def_id) { self.evaluate_added_goals_and_make_canonical_response(Certainty::Yes) } else { Err(NoSolution) @@ -141,10 +112,7 @@ impl<'a, 'tcx> EvalCtxt<'a, InferCtxt<'tcx>> { } #[instrument(level = "trace", skip(self))] - fn compute_well_formed_goal( - &mut self, - goal: Goal<'tcx, ty::GenericArg<'tcx>>, - ) -> QueryResult<'tcx> { + fn compute_well_formed_goal(&mut self, goal: Goal<I, I::GenericArg>) -> QueryResult<I> { match self.well_formed_goals(goal.param_env, goal.predicate) { Some(goals) => { self.add_goals(GoalSource::Misc, goals); @@ -157,8 +125,8 @@ impl<'a, 'tcx> EvalCtxt<'a, InferCtxt<'tcx>> { #[instrument(level = "trace", skip(self))] fn compute_const_evaluatable_goal( &mut self, - Goal { param_env, predicate: ct }: Goal<'tcx, ty::Const<'tcx>>, - ) -> QueryResult<'tcx> { + Goal { param_env, predicate: ct }: Goal<I, I::Const>, + ) -> QueryResult<I> { match ct.kind() { ty::ConstKind::Unevaluated(uv) => { // We never return `NoSolution` here as `try_const_eval_resolve` emits an @@ -188,7 +156,7 @@ impl<'a, 'tcx> EvalCtxt<'a, InferCtxt<'tcx>> { // - `Bound` cannot exist as we don't have a binder around the self Type // - `Expr` is part of `feature(generic_const_exprs)` and is not implemented yet ty::ConstKind::Param(_) | ty::ConstKind::Bound(_, _) | ty::ConstKind::Expr(_) => { - bug!("unexpect const kind: {:?}", ct) + panic!("unexpect const kind: {:?}", ct) } } } @@ -196,8 +164,8 @@ impl<'a, 'tcx> EvalCtxt<'a, InferCtxt<'tcx>> { #[instrument(level = "trace", skip(self), ret)] fn compute_const_arg_has_type_goal( &mut self, - goal: Goal<'tcx, (ty::Const<'tcx>, Ty<'tcx>)>, - ) -> QueryResult<'tcx> { + goal: Goal<I, (I::Const, I::Ty)>, + ) -> QueryResult<I> { let (ct, ty) = goal.predicate; let ct_ty = match ct.kind() { @@ -214,7 +182,7 @@ impl<'a, 'tcx> EvalCtxt<'a, InferCtxt<'tcx>> { return self.evaluate_added_goals_and_make_canonical_response(Certainty::Yes); } ty::ConstKind::Unevaluated(uv) => { - self.interner().type_of(uv.def).instantiate(self.interner(), uv.args) + self.interner().type_of(uv.def).instantiate(self.interner(), &uv.args) } ty::ConstKind::Expr(_) => unimplemented!( "`feature(generic_const_exprs)` is not supported in the new trait solver" @@ -222,10 +190,10 @@ impl<'a, 'tcx> EvalCtxt<'a, InferCtxt<'tcx>> { ty::ConstKind::Param(_) => { unreachable!("`ConstKind::Param` should have been canonicalized to `Placeholder`") } - ty::ConstKind::Bound(_, _) => bug!("escaping bound vars in {:?}", ct), + ty::ConstKind::Bound(_, _) => panic!("escaping bound vars in {:?}", ct), ty::ConstKind::Value(ty, _) => ty, ty::ConstKind::Placeholder(placeholder) => { - placeholder.find_const_ty_from_env(goal.param_env) + self.interner().find_const_ty_from_env(goal.param_env, placeholder) } }; @@ -234,15 +202,19 @@ impl<'a, 'tcx> EvalCtxt<'a, InferCtxt<'tcx>> { } } -impl<'tcx> EvalCtxt<'_, InferCtxt<'tcx>> { +impl<Infcx, I> EvalCtxt<'_, Infcx> +where + Infcx: SolverDelegate<Interner = I>, + I: Interner, +{ /// 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]`. #[instrument(level = "trace", skip(self), ret)] fn try_merge_responses( &mut self, - responses: &[CanonicalResponse<'tcx>], - ) -> Option<CanonicalResponse<'tcx>> { + responses: &[CanonicalResponse<I>], + ) -> Option<CanonicalResponse<I>> { if responses.is_empty() { return None; } @@ -258,14 +230,14 @@ impl<'tcx> EvalCtxt<'_, InferCtxt<'tcx>> { .iter() .find(|response| { response.value.certainty == Certainty::Yes - && response.has_no_inference_or_external_constraints() + && has_no_inference_or_external_constraints(**response) }) .copied() } /// If we fail to merge responses we flounder and return overflow or ambiguity. #[instrument(level = "trace", skip(self), ret)] - fn flounder(&mut self, responses: &[CanonicalResponse<'tcx>]) -> QueryResult<'tcx> { + fn flounder(&mut self, responses: &[CanonicalResponse<I>]) -> QueryResult<I> { if responses.is_empty() { return Err(NoSolution); } @@ -275,7 +247,7 @@ impl<'tcx> EvalCtxt<'_, InferCtxt<'tcx>> { certainty.unify_with(response.value.certainty) }) else { - bug!("expected flounder response to be ambiguous") + panic!("expected flounder response to be ambiguous") }; Ok(self.make_ambiguous_response_no_constraints(maybe_cause)) @@ -289,9 +261,9 @@ impl<'tcx> EvalCtxt<'_, InferCtxt<'tcx>> { #[instrument(level = "trace", skip(self, param_env), ret)] fn structurally_normalize_ty( &mut self, - param_env: ty::ParamEnv<'tcx>, - ty: Ty<'tcx>, - ) -> Result<Ty<'tcx>, NoSolution> { + param_env: I::ParamEnv, + ty: I::Ty, + ) -> Result<I::Ty, NoSolution> { if let ty::Alias(..) = ty.kind() { let normalized_ty = self.next_ty_infer(); let alias_relate_goal = Goal::new( @@ -300,7 +272,7 @@ impl<'tcx> EvalCtxt<'_, InferCtxt<'tcx>> { ty::PredicateKind::AliasRelate( ty.into(), normalized_ty.into(), - AliasRelationDirection::Equate, + ty::AliasRelationDirection::Equate, ), ); self.add_goal(GoalSource::Misc, alias_relate_goal); @@ -312,17 +284,17 @@ impl<'tcx> EvalCtxt<'_, InferCtxt<'tcx>> { } } -fn response_no_constraints_raw<'tcx>( - tcx: TyCtxt<'tcx>, - max_universe: UniverseIndex, - variables: CanonicalVarInfos<'tcx>, +fn response_no_constraints_raw<I: Interner>( + tcx: I, + max_universe: ty::UniverseIndex, + variables: I::CanonicalVars, certainty: Certainty, -) -> CanonicalResponse<'tcx> { - Canonical { +) -> CanonicalResponse<I> { + ty::Canonical { max_universe, variables, value: Response { - var_values: CanonicalVarValues::make_identity(tcx, variables), + var_values: ty::CanonicalVarValues::make_identity(tcx, variables), // FIXME: maybe we should store the "no response" version in tcx, like // we do for tcx.types and stuff. external_constraints: tcx.mk_external_constraints(ExternalConstraintsData::default()), diff --git a/compiler/rustc_trait_selection/src/solve/normalizes_to/anon_const.rs b/compiler/rustc_next_trait_solver/src/solve/normalizes_to/anon_const.rs index a6e4b6ff4a8..0f1c1f13c16 100644 --- a/compiler/rustc_trait_selection/src/solve/normalizes_to/anon_const.rs +++ b/compiler/rustc_next_trait_solver/src/solve/normalizes_to/anon_const.rs @@ -1,14 +1,19 @@ -use crate::solve::EvalCtxt; -use rustc_infer::infer::InferCtxt; -use rustc_middle::traits::solve::{Certainty, Goal, QueryResult}; -use rustc_middle::ty; +use rustc_type_ir::{self as ty, Interner}; +use tracing::instrument; -impl<'tcx> EvalCtxt<'_, InferCtxt<'tcx>> { +use crate::infcx::SolverDelegate; +use crate::solve::{Certainty, EvalCtxt, Goal, QueryResult}; + +impl<Infcx, I> EvalCtxt<'_, Infcx> +where + Infcx: SolverDelegate<Interner = I>, + I: Interner, +{ #[instrument(level = "trace", skip(self), ret)] pub(super) fn normalize_anon_const( &mut self, - goal: Goal<'tcx, ty::NormalizesTo<'tcx>>, - ) -> QueryResult<'tcx> { + goal: Goal<I, ty::NormalizesTo<I>>, + ) -> QueryResult<I> { if let Some(normalized_const) = self.try_const_eval_resolve( goal.param_env, ty::UnevaluatedConst::new(goal.predicate.alias.def_id, goal.predicate.alias.args), diff --git a/compiler/rustc_trait_selection/src/solve/normalizes_to/inherent.rs b/compiler/rustc_next_trait_solver/src/solve/normalizes_to/inherent.rs index 41b2b9cd4d2..8436f3ad484 100644 --- a/compiler/rustc_trait_selection/src/solve/normalizes_to/inherent.rs +++ b/compiler/rustc_next_trait_solver/src/solve/normalizes_to/inherent.rs @@ -4,17 +4,21 @@ //! 1. instantiate generic parameters, //! 2. equate the self type, and //! 3. instantiate and register where clauses. -use rustc_infer::infer::InferCtxt; -use rustc_middle::traits::solve::{Certainty, Goal, GoalSource, QueryResult}; -use rustc_middle::ty; -use crate::solve::EvalCtxt; +use rustc_type_ir::{self as ty, Interner}; -impl<'tcx> EvalCtxt<'_, InferCtxt<'tcx>> { +use crate::infcx::SolverDelegate; +use crate::solve::{Certainty, EvalCtxt, Goal, GoalSource, QueryResult}; + +impl<Infcx, I> EvalCtxt<'_, Infcx> +where + Infcx: SolverDelegate<Interner = I>, + I: Interner, +{ pub(super) fn normalize_inherent_associated_type( &mut self, - goal: Goal<'tcx, ty::NormalizesTo<'tcx>>, - ) -> QueryResult<'tcx> { + goal: Goal<I, ty::NormalizesTo<I>>, + ) -> QueryResult<I> { let tcx = self.interner(); let inherent = goal.predicate.alias.expect_ty(tcx); @@ -25,7 +29,7 @@ impl<'tcx> EvalCtxt<'_, InferCtxt<'tcx>> { self.eq( goal.param_env, inherent.self_ty(), - tcx.type_of(impl_def_id).instantiate(tcx, impl_args), + tcx.type_of(impl_def_id).instantiate(tcx, &impl_args), )?; // Equate IAT with the RHS of the project goal @@ -40,12 +44,11 @@ impl<'tcx> EvalCtxt<'_, InferCtxt<'tcx>> { self.add_goals( GoalSource::Misc, tcx.predicates_of(inherent.def_id) - .instantiate(tcx, inherent_args) - .into_iter() - .map(|(pred, _)| goal.with(tcx, pred)), + .iter_instantiated(tcx, &inherent_args) + .map(|pred| goal.with(tcx, pred)), ); - let normalized = tcx.type_of(inherent.def_id).instantiate(tcx, inherent_args); + let normalized = tcx.type_of(inherent.def_id).instantiate(tcx, &inherent_args); self.instantiate_normalizes_to_term(goal, normalized.into()); self.evaluate_added_goals_and_make_canonical_response(Certainty::Yes) } diff --git a/compiler/rustc_trait_selection/src/solve/normalizes_to/mod.rs b/compiler/rustc_next_trait_solver/src/solve/normalizes_to/mod.rs index 60a15392e0b..ebc83bef513 100644 --- a/compiler/rustc_trait_selection/src/solve/normalizes_to/mod.rs +++ b/compiler/rustc_next_trait_solver/src/solve/normalizes_to/mod.rs @@ -1,35 +1,33 @@ -use crate::traits::specialization_graph::{self, LeafDef, Node}; - -use super::assembly::structural_traits::AsyncCallableRelevantTypes; -use super::assembly::{self, structural_traits, Candidate}; -use super::{EvalCtxt, GoalSource}; -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::solve::inspect::ProbeKind; -use rustc_infer::traits::solve::MaybeCause; -use rustc_infer::traits::Reveal; -use rustc_middle::traits::solve::{CandidateSource, Certainty, Goal, QueryResult}; -use rustc_middle::traits::BuiltinImplSource; -use rustc_middle::ty::fast_reject::{DeepRejectCtxt, TreatParams}; -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::{ErrorGuaranteed, DUMMY_SP}; - mod anon_const; mod inherent; mod opaque_types; mod weak_types; -impl<'tcx> EvalCtxt<'_, InferCtxt<'tcx>> { +use rustc_type_ir::inherent::*; +use rustc_type_ir::lang_items::TraitSolverLangItem; +use rustc_type_ir::Upcast as _; +use rustc_type_ir::{self as ty, Interner, NormalizesTo}; +use tracing::instrument; + +use crate::infcx::SolverDelegate; +use crate::solve::assembly::structural_traits::{self, AsyncCallableRelevantTypes}; +use crate::solve::assembly::{self, Candidate}; +use crate::solve::inspect::ProbeKind; +use crate::solve::{ + BuiltinImplSource, CandidateSource, Certainty, EvalCtxt, Goal, GoalSource, MaybeCause, + NoSolution, QueryResult, +}; + +impl<Infcx, I> EvalCtxt<'_, Infcx> +where + Infcx: SolverDelegate<Interner = I>, + I: Interner, +{ #[instrument(level = "trace", skip(self), ret)] pub(super) fn compute_normalizes_to_goal( &mut self, - goal: Goal<'tcx, NormalizesTo<'tcx>>, - ) -> QueryResult<'tcx> { + goal: Goal<I, NormalizesTo<I>>, + ) -> QueryResult<I> { self.set_is_normalizes_to_goal(); debug_assert!(self.term_is_fully_unconstrained(goal)); let normalize_result = self @@ -49,10 +47,7 @@ impl<'tcx> EvalCtxt<'_, InferCtxt<'tcx>> { /// Normalize the given alias by at least one step. If the alias is rigid, this /// returns `NoSolution`. #[instrument(level = "trace", skip(self), ret)] - fn normalize_at_least_one_step( - &mut self, - goal: Goal<'tcx, NormalizesTo<'tcx>>, - ) -> QueryResult<'tcx> { + fn normalize_at_least_one_step(&mut self, goal: Goal<I, NormalizesTo<I>>) -> QueryResult<I> { match goal.predicate.alias.kind(self.interner()) { ty::AliasTermKind::ProjectionTy | ty::AliasTermKind::ProjectionConst => { let candidates = self.assemble_and_evaluate_candidates(goal); @@ -72,38 +67,42 @@ impl<'tcx> EvalCtxt<'_, InferCtxt<'tcx>> { /// emit nested `AliasRelate` goals to structurally normalize the alias. pub fn instantiate_normalizes_to_term( &mut self, - goal: Goal<'tcx, NormalizesTo<'tcx>>, - term: ty::Term<'tcx>, + goal: Goal<I, NormalizesTo<I>>, + term: I::Term, ) { self.eq(goal.param_env, goal.predicate.term, term) .expect("expected goal term to be fully unconstrained"); } } -impl<'tcx> assembly::GoalKind<'tcx> for NormalizesTo<'tcx> { - fn self_ty(self) -> Ty<'tcx> { +impl<Infcx, I> assembly::GoalKind<Infcx> for NormalizesTo<I> +where + Infcx: SolverDelegate<Interner = I>, + I: Interner, +{ + fn self_ty(self) -> I::Ty { self.self_ty() } - fn trait_ref(self, tcx: TyCtxt<'tcx>) -> ty::TraitRef<'tcx> { + fn trait_ref(self, tcx: I) -> ty::TraitRef<I> { self.alias.trait_ref(tcx) } - fn with_self_ty(self, tcx: TyCtxt<'tcx>, self_ty: Ty<'tcx>) -> Self { + fn with_self_ty(self, tcx: I, self_ty: I::Ty) -> Self { self.with_self_ty(tcx, self_ty) } - fn trait_def_id(self, tcx: TyCtxt<'tcx>) -> DefId { + fn trait_def_id(self, tcx: I) -> I::DefId { self.trait_def_id(tcx) } fn probe_and_match_goal_against_assumption( - ecx: &mut EvalCtxt<'_, InferCtxt<'tcx>>, - source: CandidateSource<'tcx>, - goal: Goal<'tcx, Self>, - assumption: ty::Clause<'tcx>, - then: impl FnOnce(&mut EvalCtxt<'_, InferCtxt<'tcx>>) -> QueryResult<'tcx>, - ) -> Result<Candidate<TyCtxt<'tcx>>, NoSolution> { + ecx: &mut EvalCtxt<'_, Infcx>, + source: CandidateSource<I>, + goal: Goal<I, Self>, + assumption: I::Clause, + then: impl FnOnce(&mut EvalCtxt<'_, Infcx>) -> QueryResult<I>, + ) -> Result<Candidate<I>, NoSolution> { if let Some(projection_pred) = assumption.as_projection_clause() { if projection_pred.projection_def_id() == goal.predicate.def_id() { let tcx = ecx.interner(); @@ -121,9 +120,9 @@ impl<'tcx> assembly::GoalKind<'tcx> for NormalizesTo<'tcx> { // Add GAT where clauses from the trait's definition ecx.add_goals( GoalSource::Misc, - tcx.predicates_of(goal.predicate.def_id()) - .instantiate_own(tcx, goal.predicate.alias.args) - .map(|(pred, _)| goal.with(tcx, pred)), + tcx.own_predicates_of(goal.predicate.def_id()) + .iter_instantiated(tcx, &goal.predicate.alias.args) + .map(|pred| goal.with(tcx, pred)), ); then(ecx) @@ -137,24 +136,23 @@ impl<'tcx> assembly::GoalKind<'tcx> for NormalizesTo<'tcx> { } fn consider_impl_candidate( - ecx: &mut EvalCtxt<'_, InferCtxt<'tcx>>, - goal: Goal<'tcx, NormalizesTo<'tcx>>, - impl_def_id: DefId, - ) -> Result<Candidate<TyCtxt<'tcx>>, NoSolution> { + ecx: &mut EvalCtxt<'_, Infcx>, + goal: Goal<I, NormalizesTo<I>>, + impl_def_id: I::DefId, + ) -> Result<Candidate<I>, NoSolution> { let tcx = ecx.interner(); let goal_trait_ref = goal.predicate.alias.trait_ref(tcx); - let impl_trait_header = tcx.impl_trait_header(impl_def_id).unwrap(); - let drcx = DeepRejectCtxt { treat_obligation_params: TreatParams::ForLookup }; - if !drcx.args_may_unify( - goal.predicate.trait_ref(tcx).args, - impl_trait_header.trait_ref.skip_binder().args, + let impl_trait_ref = tcx.impl_trait_ref(impl_def_id); + if !ecx.interner().args_may_unify_deep( + goal.predicate.alias.trait_ref(tcx).args, + impl_trait_ref.skip_binder().args, ) { return Err(NoSolution); } // We have to ignore negative impls when projecting. - let impl_polarity = impl_trait_header.polarity; + let impl_polarity = tcx.impl_polarity(impl_def_id); match impl_polarity { ty::ImplPolarity::Negative => return Err(NoSolution), ty::ImplPolarity::Reservation => { @@ -165,30 +163,28 @@ impl<'tcx> assembly::GoalKind<'tcx> for NormalizesTo<'tcx> { ecx.probe_trait_candidate(CandidateSource::Impl(impl_def_id)).enter(|ecx| { let impl_args = ecx.fresh_args_for_item(impl_def_id); - let impl_trait_ref = impl_trait_header.trait_ref.instantiate(tcx, impl_args); + let impl_trait_ref = impl_trait_ref.instantiate(tcx, &impl_args); ecx.eq(goal.param_env, goal_trait_ref, impl_trait_ref)?; let where_clause_bounds = tcx .predicates_of(impl_def_id) - .instantiate(tcx, impl_args) - .predicates - .into_iter() + .iter_instantiated(tcx, &impl_args) .map(|pred| goal.with(tcx, pred)); ecx.add_goals(GoalSource::ImplWhereBound, where_clause_bounds); // Add GAT where clauses from the trait's definition ecx.add_goals( GoalSource::Misc, - tcx.predicates_of(goal.predicate.def_id()) - .instantiate_own(tcx, goal.predicate.alias.args) - .map(|(pred, _)| goal.with(tcx, pred)), + tcx.own_predicates_of(goal.predicate.def_id()) + .iter_instantiated(tcx, &goal.predicate.alias.args) + .map(|pred| goal.with(tcx, pred)), ); // In case the associated item is hidden due to specialization, we have to // return ambiguity this would otherwise be incomplete, resulting in // unsoundness during coherence (#105782). - let Some(assoc_def) = ecx.fetch_eligible_assoc_item_def( + let Some(target_item_def_id) = ecx.fetch_eligible_assoc_item( goal.param_env, goal_trait_ref, goal.predicate.def_id(), @@ -198,25 +194,23 @@ impl<'tcx> assembly::GoalKind<'tcx> for NormalizesTo<'tcx> { return ecx.evaluate_added_goals_and_make_canonical_response(Certainty::AMBIGUOUS); }; - let error_response = |ecx: &mut EvalCtxt<'_, InferCtxt<'tcx>>, reason| { - let guar = tcx.dcx().span_delayed_bug(tcx.def_span(assoc_def.item.def_id), reason); - let error_term = match assoc_def.item.kind { - ty::AssocKind::Const => ty::Const::new_error(tcx, guar).into(), - ty::AssocKind::Type => Ty::new_error(tcx, guar).into(), - // This makes no sense... - ty::AssocKind::Fn => span_bug!( - tcx.def_span(assoc_def.item.def_id), - "cannot project to an associated function" - ), + let error_response = |ecx: &mut EvalCtxt<'_, Infcx>, msg: &str| { + let guar = tcx.delay_bug(msg); + let error_term = match goal.predicate.alias.kind(tcx) { + ty::AliasTermKind::ProjectionTy => Ty::new_error(tcx, guar).into(), + ty::AliasTermKind::ProjectionConst => Const::new_error(tcx, guar).into(), + kind => panic!("expected projection, found {kind:?}"), }; ecx.instantiate_normalizes_to_term(goal, error_term); ecx.evaluate_added_goals_and_make_canonical_response(Certainty::Yes) }; - if !assoc_def.item.defaultness(tcx).has_value() { - return error_response(ecx, "missing value for assoc item in impl"); + if !tcx.has_item_definition(target_item_def_id) { + return error_response(ecx, "missing item"); } + let target_container_def_id = tcx.parent(target_item_def_id); + // Getting the right args here is complex, e.g. given: // - a goal `<Vec<u32> as Trait<i32>>::Assoc<u64>` // - the applicable impl `impl<T> Trait<i32> for Vec<T>` @@ -227,37 +221,40 @@ impl<'tcx> assembly::GoalKind<'tcx> for NormalizesTo<'tcx> { // // And then map these args to the args of the defining impl of `Assoc`, going // from `[u32, u64]` to `[u32, i32, u64]`. - let associated_item_args = - ecx.translate_args(&assoc_def, goal, impl_def_id, impl_args, impl_trait_ref)?; - - if !tcx.check_args_compatible(assoc_def.item.def_id, associated_item_args) { - return error_response( - ecx, - "associated item has mismatched generic item arguments", - ); + let target_args = ecx.translate_args( + goal, + impl_def_id, + impl_args, + impl_trait_ref, + target_container_def_id, + )?; + + if !tcx.check_args_compatible(target_item_def_id, target_args) { + return error_response(ecx, "associated item has mismatched arguments"); } // Finally we construct the actual value of the associated type. - let term = match assoc_def.item.kind { - ty::AssocKind::Type => tcx.type_of(assoc_def.item.def_id).map_bound(|ty| ty.into()), - ty::AssocKind::Const => { - if tcx.features().associated_const_equality { - bug!("associated const projection is not supported yet") + let term = match goal.predicate.alias.kind(tcx) { + ty::AliasTermKind::ProjectionTy => { + tcx.type_of(target_item_def_id).map_bound(|ty| ty.into()) + } + ty::AliasTermKind::ProjectionConst => { + if tcx.features().associated_const_equality() { + panic!("associated const projection is not supported yet") } else { ty::EarlyBinder::bind( - ty::Const::new_error_with_message( + Const::new_error_with_message( tcx, - DUMMY_SP, "associated const projection is not supported yet", ) .into(), ) } } - ty::AssocKind::Fn => unreachable!("we should never project to a fn"), + kind => panic!("expected projection, found {kind:?}"), }; - ecx.instantiate_normalizes_to_term(goal, term.instantiate(tcx, associated_item_args)); + ecx.instantiate_normalizes_to_term(goal, term.instantiate(tcx, &target_args)); ecx.evaluate_added_goals_and_make_canonical_response(Certainty::Yes) }) } @@ -265,63 +262,60 @@ impl<'tcx> assembly::GoalKind<'tcx> for NormalizesTo<'tcx> { /// Fail to normalize if the predicate contains an error, alternatively, we could normalize to `ty::Error` /// and succeed. Can experiment with this to figure out what results in better error messages. fn consider_error_guaranteed_candidate( - _ecx: &mut EvalCtxt<'_, InferCtxt<'tcx>>, - _guar: ErrorGuaranteed, - ) -> Result<Candidate<TyCtxt<'tcx>>, NoSolution> { + _ecx: &mut EvalCtxt<'_, Infcx>, + _guar: I::ErrorGuaranteed, + ) -> Result<Candidate<I>, NoSolution> { Err(NoSolution) } fn consider_auto_trait_candidate( - ecx: &mut EvalCtxt<'_, InferCtxt<'tcx>>, - goal: Goal<'tcx, Self>, - ) -> Result<Candidate<TyCtxt<'tcx>>, NoSolution> { - ecx.interner().dcx().span_delayed_bug( - ecx.interner().def_span(goal.predicate.def_id()), - "associated types not allowed on auto traits", - ); + ecx: &mut EvalCtxt<'_, Infcx>, + _goal: Goal<I, Self>, + ) -> Result<Candidate<I>, NoSolution> { + ecx.interner().delay_bug("associated types not allowed on auto traits"); Err(NoSolution) } fn consider_trait_alias_candidate( - _ecx: &mut EvalCtxt<'_, InferCtxt<'tcx>>, - goal: Goal<'tcx, Self>, - ) -> Result<Candidate<TyCtxt<'tcx>>, NoSolution> { - bug!("trait aliases do not have associated types: {:?}", goal); + _ecx: &mut EvalCtxt<'_, Infcx>, + goal: Goal<I, Self>, + ) -> Result<Candidate<I>, NoSolution> { + panic!("trait aliases do not have associated types: {:?}", goal); } fn consider_builtin_sized_candidate( - _ecx: &mut EvalCtxt<'_, InferCtxt<'tcx>>, - goal: Goal<'tcx, Self>, - ) -> Result<Candidate<TyCtxt<'tcx>>, NoSolution> { - bug!("`Sized` does not have an associated type: {:?}", goal); + _ecx: &mut EvalCtxt<'_, Infcx>, + goal: Goal<I, Self>, + ) -> Result<Candidate<I>, NoSolution> { + panic!("`Sized` does not have an associated type: {:?}", goal); } fn consider_builtin_copy_clone_candidate( - _ecx: &mut EvalCtxt<'_, InferCtxt<'tcx>>, - goal: Goal<'tcx, Self>, - ) -> Result<Candidate<TyCtxt<'tcx>>, NoSolution> { - bug!("`Copy`/`Clone` does not have an associated type: {:?}", goal); + _ecx: &mut EvalCtxt<'_, Infcx>, + goal: Goal<I, Self>, + ) -> Result<Candidate<I>, NoSolution> { + panic!("`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<Candidate<TyCtxt<'tcx>>, NoSolution> { - bug!("`PointerLike` does not have an associated type: {:?}", goal); + _ecx: &mut EvalCtxt<'_, Infcx>, + goal: Goal<I, Self>, + ) -> Result<Candidate<I>, NoSolution> { + panic!("`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<Candidate<TyCtxt<'tcx>>, NoSolution> { - bug!("`FnPtr` does not have an associated type: {:?}", goal); + _ecx: &mut EvalCtxt<'_, Infcx>, + goal: Goal<I, Self>, + ) -> Result<Candidate<I>, NoSolution> { + panic!("`FnPtr` does not have an associated type: {:?}", goal); } fn consider_builtin_fn_trait_candidates( - ecx: &mut EvalCtxt<'_, InferCtxt<'tcx>>, - goal: Goal<'tcx, Self>, + ecx: &mut EvalCtxt<'_, Infcx>, + goal: Goal<I, Self>, goal_kind: ty::ClosureKind, - ) -> Result<Candidate<TyCtxt<'tcx>>, NoSolution> { + ) -> Result<Candidate<I>, NoSolution> { let tcx = ecx.interner(); let tupled_inputs_and_output = match structural_traits::extract_tupled_inputs_and_output_from_callable( @@ -335,7 +329,7 @@ impl<'tcx> assembly::GoalKind<'tcx> for NormalizesTo<'tcx> { } }; let output_is_sized_pred = tupled_inputs_and_output.map_bound(|(_, output)| { - ty::TraitRef::new(tcx, tcx.require_lang_item(LangItem::Sized, None), [output]) + ty::TraitRef::new(tcx, tcx.require_lang_item(TraitSolverLangItem::Sized), [output]) }); let pred = tupled_inputs_and_output @@ -361,16 +355,16 @@ impl<'tcx> assembly::GoalKind<'tcx> for NormalizesTo<'tcx> { } fn consider_builtin_async_fn_trait_candidates( - ecx: &mut EvalCtxt<'_, InferCtxt<'tcx>>, - goal: Goal<'tcx, Self>, + ecx: &mut EvalCtxt<'_, Infcx>, + goal: Goal<I, Self>, goal_kind: ty::ClosureKind, - ) -> Result<Candidate<TyCtxt<'tcx>>, NoSolution> { + ) -> Result<Candidate<I>, NoSolution> { let tcx = ecx.interner(); let env_region = match goal_kind { ty::ClosureKind::Fn | ty::ClosureKind::FnMut => goal.predicate.alias.args.region_at(2), // Doesn't matter what this region is - ty::ClosureKind::FnOnce => tcx.lifetimes.re_static, + ty::ClosureKind::FnOnce => Region::new_static(tcx), }; let (tupled_inputs_and_output_and_coroutine, nested_preds) = structural_traits::extract_tupled_inputs_and_output_from_async_callable( @@ -381,7 +375,11 @@ impl<'tcx> assembly::GoalKind<'tcx> for NormalizesTo<'tcx> { )?; let output_is_sized_pred = tupled_inputs_and_output_and_coroutine.map_bound( |AsyncCallableRelevantTypes { output_coroutine_ty: output_ty, .. }| { - ty::TraitRef::new(tcx, tcx.require_lang_item(LangItem::Sized, None), [output_ty]) + ty::TraitRef::new( + tcx, + tcx.require_lang_item(TraitSolverLangItem::Sized), + [output_ty], + ) }, ); @@ -393,7 +391,7 @@ impl<'tcx> assembly::GoalKind<'tcx> for NormalizesTo<'tcx> { coroutine_return_ty, }| { let (projection_term, term) = if tcx - .is_lang_item(goal.predicate.def_id(), LangItem::CallOnceFuture) + .is_lang_item(goal.predicate.def_id(), TraitSolverLangItem::CallOnceFuture) { ( ty::AliasTerm::new( @@ -403,34 +401,41 @@ impl<'tcx> assembly::GoalKind<'tcx> for NormalizesTo<'tcx> { ), output_coroutine_ty.into(), ) - } else if tcx.is_lang_item(goal.predicate.def_id(), LangItem::CallRefFuture) { + } else if tcx + .is_lang_item(goal.predicate.def_id(), TraitSolverLangItem::CallRefFuture) + { ( ty::AliasTerm::new( tcx, goal.predicate.def_id(), [ - ty::GenericArg::from(goal.predicate.self_ty()), + I::GenericArg::from(goal.predicate.self_ty()), tupled_inputs_ty.into(), env_region.into(), ], ), output_coroutine_ty.into(), ) - } else if tcx.is_lang_item(goal.predicate.def_id(), LangItem::AsyncFnOnceOutput) - { + } else if tcx.is_lang_item( + goal.predicate.def_id(), + TraitSolverLangItem::AsyncFnOnceOutput, + ) { ( ty::AliasTerm::new( tcx, goal.predicate.def_id(), [ - ty::GenericArg::from(goal.predicate.self_ty()), + I::GenericArg::from(goal.predicate.self_ty()), tupled_inputs_ty.into(), ], ), coroutine_return_ty.into(), ) } else { - bug!("no such associated type in `AsyncFn*`: {:?}", goal.predicate.def_id()) + panic!( + "no such associated type in `AsyncFn*`: {:?}", + goal.predicate.def_id() + ) }; ty::ProjectionPredicate { projection_term, term } }, @@ -452,9 +457,9 @@ 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<Candidate<TyCtxt<'tcx>>, NoSolution> { + ecx: &mut EvalCtxt<'_, Infcx>, + goal: Goal<I, Self>, + ) -> Result<Candidate<I>, NoSolution> { let [ closure_fn_kind_ty, goal_kind_ty, @@ -464,7 +469,7 @@ impl<'tcx> assembly::GoalKind<'tcx> for NormalizesTo<'tcx> { coroutine_captures_by_ref_ty, ] = **goal.predicate.alias.args else { - bug!(); + panic!(); }; // Bail if the upvars haven't been constrained. @@ -499,18 +504,18 @@ impl<'tcx> assembly::GoalKind<'tcx> for NormalizesTo<'tcx> { } fn consider_builtin_tuple_candidate( - _ecx: &mut EvalCtxt<'_, InferCtxt<'tcx>>, - goal: Goal<'tcx, Self>, - ) -> Result<Candidate<TyCtxt<'tcx>>, NoSolution> { - bug!("`Tuple` does not have an associated type: {:?}", goal); + _ecx: &mut EvalCtxt<'_, Infcx>, + goal: Goal<I, Self>, + ) -> Result<Candidate<I>, NoSolution> { + panic!("`Tuple` does not have an associated type: {:?}", goal); } fn consider_builtin_pointee_candidate( - ecx: &mut EvalCtxt<'_, InferCtxt<'tcx>>, - goal: Goal<'tcx, Self>, - ) -> Result<Candidate<TyCtxt<'tcx>>, NoSolution> { + ecx: &mut EvalCtxt<'_, Infcx>, + goal: Goal<I, Self>, + ) -> Result<Candidate<I>, NoSolution> { let tcx = ecx.interner(); - let metadata_def_id = tcx.require_lang_item(LangItem::Metadata, None); + let metadata_def_id = tcx.require_lang_item(TraitSolverLangItem::Metadata); assert_eq!(metadata_def_id, goal.predicate.def_id()); ecx.probe_builtin_trait_candidate(BuiltinImplSource::Misc).enter(|ecx| { let metadata_ty = match goal.predicate.self_ty().kind() { @@ -532,16 +537,16 @@ impl<'tcx> assembly::GoalKind<'tcx> for NormalizesTo<'tcx> { | ty::CoroutineWitness(..) | ty::Never | ty::Foreign(..) - | ty::Dynamic(_, _, ty::DynStar) => tcx.types.unit, + | ty::Dynamic(_, _, ty::DynStar) => Ty::new_unit(tcx), - ty::Error(e) => Ty::new_error(tcx, *e), + ty::Error(e) => Ty::new_error(tcx, e), - ty::Str | ty::Slice(_) => tcx.types.usize, + ty::Str | ty::Slice(_) => Ty::new_usize(tcx), ty::Dynamic(_, _, ty::Dyn) => { - let dyn_metadata = tcx.require_lang_item(LangItem::DynMetadata, None); + let dyn_metadata = tcx.require_lang_item(TraitSolverLangItem::DynMetadata); tcx.type_of(dyn_metadata) - .instantiate(tcx, &[ty::GenericArg::from(goal.predicate.self_ty())]) + .instantiate(tcx, &[I::GenericArg::from(goal.predicate.self_ty())]) } ty::Alias(_, _) | ty::Param(_) | ty::Placeholder(..) => { @@ -551,32 +556,31 @@ impl<'tcx> assembly::GoalKind<'tcx> for NormalizesTo<'tcx> { // exist. Instead, `Pointee<Metadata = ()>` should be a supertrait of `Sized`. let sized_predicate = ty::TraitRef::new( tcx, - tcx.require_lang_item(LangItem::Sized, None), - [ty::GenericArg::from(goal.predicate.self_ty())], + tcx.require_lang_item(TraitSolverLangItem::Sized), + [I::GenericArg::from(goal.predicate.self_ty())], ); // FIXME(-Znext-solver=coinductive): Should this be `GoalSource::ImplWhereBound`? ecx.add_goal(GoalSource::Misc, goal.with(tcx, sized_predicate)); - tcx.types.unit + Ty::new_unit(tcx) } - ty::Adt(def, args) if def.is_struct() => match def.non_enum_variant().tail_opt() { - None => tcx.types.unit, - Some(tail_def) => { - let tail_ty = tail_def.ty(tcx, args); - Ty::new_projection(tcx, metadata_def_id, [tail_ty]) + ty::Adt(def, args) if def.is_struct() => match def.struct_tail_ty(tcx) { + None => Ty::new_unit(tcx), + Some(tail_ty) => { + Ty::new_projection(tcx, metadata_def_id, [tail_ty.instantiate(tcx, &args)]) } }, - ty::Adt(_, _) => tcx.types.unit, + ty::Adt(_, _) => Ty::new_unit(tcx), ty::Tuple(elements) => match elements.last() { - None => tcx.types.unit, + None => Ty::new_unit(tcx), Some(&tail_ty) => Ty::new_projection(tcx, metadata_def_id, [tail_ty]), }, ty::Infer( ty::TyVar(_) | ty::FreshTy(_) | ty::FreshIntTy(_) | ty::FreshFloatTy(_), ) - | ty::Bound(..) => bug!( + | ty::Bound(..) => panic!( "unexpected self ty `{:?}` when normalizing `<T as Pointee>::Metadata`", goal.predicate.self_ty() ), @@ -588,11 +592,11 @@ impl<'tcx> assembly::GoalKind<'tcx> for NormalizesTo<'tcx> { } fn consider_builtin_future_candidate( - ecx: &mut EvalCtxt<'_, InferCtxt<'tcx>>, - goal: Goal<'tcx, Self>, - ) -> Result<Candidate<TyCtxt<'tcx>>, NoSolution> { + ecx: &mut EvalCtxt<'_, Infcx>, + goal: Goal<I, Self>, + ) -> Result<Candidate<I>, NoSolution> { let self_ty = goal.predicate.self_ty(); - let ty::Coroutine(def_id, args) = *self_ty.kind() else { + let ty::Coroutine(def_id, args) = self_ty.kind() else { return Err(NoSolution); }; @@ -624,11 +628,11 @@ impl<'tcx> assembly::GoalKind<'tcx> for NormalizesTo<'tcx> { } fn consider_builtin_iterator_candidate( - ecx: &mut EvalCtxt<'_, InferCtxt<'tcx>>, - goal: Goal<'tcx, Self>, - ) -> Result<Candidate<TyCtxt<'tcx>>, NoSolution> { + ecx: &mut EvalCtxt<'_, Infcx>, + goal: Goal<I, Self>, + ) -> Result<Candidate<I>, NoSolution> { let self_ty = goal.predicate.self_ty(); - let ty::Coroutine(def_id, args) = *self_ty.kind() else { + let ty::Coroutine(def_id, args) = self_ty.kind() else { return Err(NoSolution); }; @@ -660,18 +664,18 @@ impl<'tcx> assembly::GoalKind<'tcx> for NormalizesTo<'tcx> { } fn consider_builtin_fused_iterator_candidate( - _ecx: &mut EvalCtxt<'_, InferCtxt<'tcx>>, - goal: Goal<'tcx, Self>, - ) -> Result<Candidate<TyCtxt<'tcx>>, NoSolution> { - bug!("`FusedIterator` does not have an associated type: {:?}", goal); + _ecx: &mut EvalCtxt<'_, Infcx>, + goal: Goal<I, Self>, + ) -> Result<Candidate<I>, NoSolution> { + panic!("`FusedIterator` does not have an associated type: {:?}", goal); } fn consider_builtin_async_iterator_candidate( - ecx: &mut EvalCtxt<'_, InferCtxt<'tcx>>, - goal: Goal<'tcx, Self>, - ) -> Result<Candidate<TyCtxt<'tcx>>, NoSolution> { + ecx: &mut EvalCtxt<'_, Infcx>, + goal: Goal<I, Self>, + ) -> Result<Candidate<I>, NoSolution> { let self_ty = goal.predicate.self_ty(); - let ty::Coroutine(def_id, args) = *self_ty.kind() else { + let ty::Coroutine(def_id, args) = self_ty.kind() else { return Err(NoSolution); }; @@ -687,10 +691,10 @@ impl<'tcx> assembly::GoalKind<'tcx> for NormalizesTo<'tcx> { // coroutine yield ty `Poll<Option<I>>`. let wrapped_expected_ty = Ty::new_adt( tcx, - tcx.adt_def(tcx.require_lang_item(LangItem::Poll, None)), + tcx.adt_def(tcx.require_lang_item(TraitSolverLangItem::Poll)), tcx.mk_args(&[Ty::new_adt( tcx, - tcx.adt_def(tcx.require_lang_item(LangItem::Option, None)), + tcx.adt_def(tcx.require_lang_item(TraitSolverLangItem::Option)), tcx.mk_args(&[expected_ty.into()]), ) .into()]), @@ -703,11 +707,11 @@ impl<'tcx> assembly::GoalKind<'tcx> for NormalizesTo<'tcx> { } fn consider_builtin_coroutine_candidate( - ecx: &mut EvalCtxt<'_, InferCtxt<'tcx>>, - goal: Goal<'tcx, Self>, - ) -> Result<Candidate<TyCtxt<'tcx>>, NoSolution> { + ecx: &mut EvalCtxt<'_, Infcx>, + goal: Goal<I, Self>, + ) -> Result<Candidate<I>, NoSolution> { let self_ty = goal.predicate.self_ty(); - let ty::Coroutine(def_id, args) = *self_ty.kind() else { + let ty::Coroutine(def_id, args) = self_ty.kind() else { return Err(NoSolution); }; @@ -719,15 +723,14 @@ impl<'tcx> assembly::GoalKind<'tcx> for NormalizesTo<'tcx> { let coroutine = args.as_coroutine(); - let term = if tcx.is_lang_item(goal.predicate.def_id(), LangItem::CoroutineReturn) { + let term = if tcx + .is_lang_item(goal.predicate.def_id(), TraitSolverLangItem::CoroutineReturn) + { coroutine.return_ty().into() - } else if tcx.is_lang_item(goal.predicate.def_id(), LangItem::CoroutineYield) { + } else if tcx.is_lang_item(goal.predicate.def_id(), TraitSolverLangItem::CoroutineYield) { coroutine.yield_ty().into() } else { - bug!( - "unexpected associated item `<{self_ty} as Coroutine>::{}`", - tcx.item_name(goal.predicate.def_id()) - ) + panic!("unexpected associated item `{:?}` for `{self_ty:?}`", goal.predicate.def_id()) }; Self::probe_and_consider_implied_clause( @@ -750,18 +753,18 @@ impl<'tcx> assembly::GoalKind<'tcx> for NormalizesTo<'tcx> { } fn consider_structural_builtin_unsize_candidates( - _ecx: &mut EvalCtxt<'_, InferCtxt<'tcx>>, - goal: Goal<'tcx, Self>, - ) -> Vec<Candidate<TyCtxt<'tcx>>> { - bug!("`Unsize` does not have an associated type: {:?}", goal); + _ecx: &mut EvalCtxt<'_, Infcx>, + goal: Goal<I, Self>, + ) -> Vec<Candidate<I>> { + panic!("`Unsize` does not have an associated type: {:?}", goal); } fn consider_builtin_discriminant_kind_candidate( - ecx: &mut EvalCtxt<'_, InferCtxt<'tcx>>, - goal: Goal<'tcx, Self>, - ) -> Result<Candidate<TyCtxt<'tcx>>, NoSolution> { + ecx: &mut EvalCtxt<'_, Infcx>, + goal: Goal<I, Self>, + ) -> Result<Candidate<I>, NoSolution> { let self_ty = goal.predicate.self_ty(); - let discriminant_ty = match *self_ty.kind() { + let discriminant_ty = match self_ty.kind() { ty::Bool | ty::Char | ty::Int(..) @@ -796,7 +799,7 @@ impl<'tcx> assembly::GoalKind<'tcx> for NormalizesTo<'tcx> { } ty::Infer(ty::TyVar(_) | ty::FreshTy(_) | ty::FreshIntTy(_) | ty::FreshFloatTy(_)) - | ty::Bound(..) => bug!( + | ty::Bound(..) => panic!( "unexpected self ty `{:?}` when normalizing `<T as DiscriminantKind>::Discriminant`", goal.predicate.self_ty() ), @@ -809,11 +812,11 @@ impl<'tcx> assembly::GoalKind<'tcx> for NormalizesTo<'tcx> { } fn consider_builtin_async_destruct_candidate( - ecx: &mut EvalCtxt<'_, InferCtxt<'tcx>>, - goal: Goal<'tcx, Self>, - ) -> Result<Candidate<TyCtxt<'tcx>>, NoSolution> { + ecx: &mut EvalCtxt<'_, Infcx>, + goal: Goal<I, Self>, + ) -> Result<Candidate<I>, NoSolution> { let self_ty = goal.predicate.self_ty(); - let async_destructor_ty = match *self_ty.kind() { + let async_destructor_ty = match self_ty.kind() { ty::Bool | ty::Char | ty::Int(..) @@ -844,12 +847,12 @@ impl<'tcx> assembly::GoalKind<'tcx> for NormalizesTo<'tcx> { ty::Infer(ty::TyVar(_) | ty::FreshTy(_) | ty::FreshIntTy(_) | ty::FreshFloatTy(_)) | ty::Foreign(..) - | ty::Bound(..) => bug!( + | ty::Bound(..) => panic!( "unexpected self ty `{:?}` when normalizing `<T as AsyncDestruct>::AsyncDestructor`", goal.predicate.self_ty() ), - ty::Pat(..) | ty::Dynamic(..) | ty::Coroutine(..) | ty::CoroutineWitness(..) => bug!( + ty::Pat(..) | ty::Dynamic(..) | ty::Coroutine(..) | ty::CoroutineWitness(..) => panic!( "`consider_builtin_async_destruct_candidate` is not yet implemented for type: {self_ty:?}" ), }; @@ -862,93 +865,56 @@ impl<'tcx> assembly::GoalKind<'tcx> for NormalizesTo<'tcx> { } fn consider_builtin_destruct_candidate( - _ecx: &mut EvalCtxt<'_, InferCtxt<'tcx>>, - goal: Goal<'tcx, Self>, - ) -> Result<Candidate<TyCtxt<'tcx>>, NoSolution> { - bug!("`Destruct` does not have an associated type: {:?}", goal); + _ecx: &mut EvalCtxt<'_, Infcx>, + goal: Goal<I, Self>, + ) -> Result<Candidate<I>, NoSolution> { + panic!("`Destruct` does not have an associated type: {:?}", goal); } fn consider_builtin_transmute_candidate( - _ecx: &mut EvalCtxt<'_, InferCtxt<'tcx>>, - goal: Goal<'tcx, Self>, - ) -> Result<Candidate<TyCtxt<'tcx>>, NoSolution> { - bug!("`BikeshedIntrinsicFrom` does not have an associated type: {:?}", goal) + _ecx: &mut EvalCtxt<'_, Infcx>, + goal: Goal<I, Self>, + ) -> Result<Candidate<I>, NoSolution> { + panic!("`BikeshedIntrinsicFrom` does not have an associated type: {:?}", goal) } } -impl<'tcx> EvalCtxt<'_, InferCtxt<'tcx>> { +impl<Infcx, I> EvalCtxt<'_, Infcx> +where + Infcx: SolverDelegate<Interner = I>, + I: Interner, +{ fn translate_args( &mut self, - assoc_def: &LeafDef, - goal: Goal<'tcx, ty::NormalizesTo<'tcx>>, - impl_def_id: DefId, - impl_args: ty::GenericArgsRef<'tcx>, - impl_trait_ref: rustc_type_ir::TraitRef<TyCtxt<'tcx>>, - ) -> Result<ty::GenericArgsRef<'tcx>, NoSolution> { + goal: Goal<I, ty::NormalizesTo<I>>, + impl_def_id: I::DefId, + impl_args: I::GenericArgs, + impl_trait_ref: rustc_type_ir::TraitRef<I>, + target_container_def_id: I::DefId, + ) -> Result<I::GenericArgs, NoSolution> { let tcx = self.interner(); - Ok(match assoc_def.defining_node { - Node::Trait(_) => goal.predicate.alias.args, - Node::Impl(target_impl_def_id) => { - if target_impl_def_id == impl_def_id { - // Same impl, no need to fully translate, just a rebase from - // the trait is sufficient. - goal.predicate.alias.args.rebase_onto(tcx, impl_trait_ref.def_id, impl_args) - } else { - let target_args = self.fresh_args_for_item(target_impl_def_id); - let target_trait_ref = tcx - .impl_trait_ref(target_impl_def_id) - .unwrap() - .instantiate(tcx, target_args); - // Relate source impl to target impl by equating trait refs. - self.eq(goal.param_env, impl_trait_ref, target_trait_ref)?; - // Also add predicates since they may be needed to constrain the - // target impl's params. - self.add_goals( - GoalSource::Misc, - tcx.predicates_of(target_impl_def_id) - .instantiate(tcx, target_args) - .into_iter() - .map(|(pred, _)| goal.with(tcx, pred)), - ); - goal.predicate.alias.args.rebase_onto(tcx, impl_trait_ref.def_id, target_args) - } - } - }) - } - - /// This behavior is also implemented in `rustc_ty_utils` and in the old `project` code. - /// - /// FIXME: We should merge these 3 implementations as it's likely that they otherwise - /// diverge. - #[instrument(level = "trace", skip(self, param_env), ret)] - fn fetch_eligible_assoc_item_def( - &self, - param_env: ty::ParamEnv<'tcx>, - goal_trait_ref: ty::TraitRef<'tcx>, - trait_assoc_def_id: DefId, - impl_def_id: DefId, - ) -> Result<Option<LeafDef>, NoSolution> { - let node_item = - specialization_graph::assoc_def(self.interner(), impl_def_id, trait_assoc_def_id) - .map_err(|ErrorGuaranteed { .. }| NoSolution)?; - - let eligible = if node_item.is_final() { - // Non-specializable items are always projectable. - true + Ok(if target_container_def_id == impl_trait_ref.def_id { + // Default value from the trait definition. No need to rebase. + goal.predicate.alias.args + } else if target_container_def_id == impl_def_id { + // Same impl, no need to fully translate, just a rebase from + // the trait is sufficient. + goal.predicate.alias.args.rebase_onto(tcx, impl_trait_ref.def_id, impl_args) } else { - // Only reveal a specializable default if we're past type-checking - // and the obligation is monomorphic, otherwise passes such as - // transmute checking and polymorphic MIR optimizations could - // get a result which isn't correct for all monomorphizations. - if param_env.reveal() == Reveal::All { - let poly_trait_ref = self.resolve_vars_if_possible(goal_trait_ref); - !poly_trait_ref.still_further_specializable() - } else { - trace!(?node_item.item.def_id, "not eligible due to default"); - false - } - }; - - if eligible { Ok(Some(node_item)) } else { Ok(None) } + let target_args = self.fresh_args_for_item(target_container_def_id); + let target_trait_ref = + tcx.impl_trait_ref(target_container_def_id).instantiate(tcx, &target_args); + // Relate source impl to target impl by equating trait refs. + self.eq(goal.param_env, impl_trait_ref, target_trait_ref)?; + // Also add predicates since they may be needed to constrain the + // target impl's params. + self.add_goals( + GoalSource::Misc, + tcx.predicates_of(target_container_def_id) + .iter_instantiated(tcx, &target_args) + .map(|pred| goal.with(tcx, pred)), + ); + goal.predicate.alias.args.rebase_onto(tcx, impl_trait_ref.def_id, target_args) + }) } } diff --git a/compiler/rustc_trait_selection/src/solve/normalizes_to/opaque_types.rs b/compiler/rustc_next_trait_solver/src/solve/normalizes_to/opaque_types.rs index 82464470b2a..710671b45d0 100644 --- a/compiler/rustc_trait_selection/src/solve/normalizes_to/opaque_types.rs +++ b/compiler/rustc_next_trait_solver/src/solve/normalizes_to/opaque_types.rs @@ -1,20 +1,23 @@ //! Computes a normalizes-to (projection) goal for opaque types. This goal //! behaves differently depending on the param-env's reveal mode and whether //! the opaque is in a defining scope. -use rustc_infer::infer::InferCtxt; -use rustc_middle::traits::query::NoSolution; -use rustc_middle::traits::solve::{Certainty, Goal, QueryResult}; -use rustc_middle::traits::Reveal; -use rustc_middle::ty; -use rustc_middle::ty::util::NotUniqueParam; -use crate::solve::{EvalCtxt, SolverMode}; +use rustc_index::bit_set::GrowableBitSet; +use rustc_type_ir::inherent::*; +use rustc_type_ir::{self as ty, Interner}; -impl<'tcx> EvalCtxt<'_, InferCtxt<'tcx>> { +use crate::infcx::SolverDelegate; +use crate::solve::{Certainty, EvalCtxt, Goal, NoSolution, QueryResult, Reveal, SolverMode}; + +impl<Infcx, I> EvalCtxt<'_, Infcx> +where + Infcx: SolverDelegate<Interner = I>, + I: Interner, +{ pub(super) fn normalize_opaque_type( &mut self, - goal: Goal<'tcx, ty::NormalizesTo<'tcx>>, - ) -> QueryResult<'tcx> { + goal: Goal<I, ty::NormalizesTo<I>>, + ) -> QueryResult<I> { let tcx = self.interner(); let opaque_ty = goal.predicate.alias; let expected = goal.predicate.term.as_type().expect("no such thing as an opaque const"); @@ -31,7 +34,7 @@ impl<'tcx> EvalCtxt<'_, InferCtxt<'tcx>> { return Err(NoSolution); } // FIXME: This may have issues when the args contain aliases... - match self.interner().uses_unique_placeholders_ignoring_regions(opaque_ty.args) { + match uses_unique_placeholders_ignoring_regions(self.interner(), opaque_ty.args) { Err(NotUniqueParam::NotParam(param)) if param.is_non_region_infer() => { return self.evaluate_added_goals_and_make_canonical_response( Certainty::AMBIGUOUS, @@ -60,6 +63,7 @@ impl<'tcx> EvalCtxt<'_, InferCtxt<'tcx>> { } // Otherwise, define a new opaque type + // FIXME: should we use `inject_hidden_type_unchecked` here? self.insert_hidden_type(opaque_type_key, goal.param_env, expected)?; self.add_item_bounds_for_hidden_type( opaque_ty.def_id, @@ -82,10 +86,51 @@ impl<'tcx> EvalCtxt<'_, InferCtxt<'tcx>> { } (Reveal::All, _) => { // FIXME: Add an assertion that opaque type storage is empty. - let actual = tcx.type_of(opaque_ty.def_id).instantiate(tcx, opaque_ty.args); + let actual = tcx.type_of(opaque_ty.def_id).instantiate(tcx, &opaque_ty.args); self.eq(goal.param_env, expected, actual)?; self.evaluate_added_goals_and_make_canonical_response(Certainty::Yes) } } } } + +/// Checks whether each generic argument is simply a unique generic placeholder. +/// +/// FIXME: Interner argument is needed to constrain the `I` parameter. +pub fn uses_unique_placeholders_ignoring_regions<I: Interner>( + _interner: I, + args: I::GenericArgs, +) -> Result<(), NotUniqueParam<I>> { + let mut seen = GrowableBitSet::default(); + for arg in args { + match arg.kind() { + // Ignore regions, since we can't resolve those in a canonicalized + // query in the trait solver. + ty::GenericArgKind::Lifetime(_) => {} + ty::GenericArgKind::Type(t) => match t.kind() { + ty::Placeholder(p) => { + if !seen.insert(p.var()) { + return Err(NotUniqueParam::DuplicateParam(t.into())); + } + } + _ => return Err(NotUniqueParam::NotParam(t.into())), + }, + ty::GenericArgKind::Const(c) => match c.kind() { + ty::ConstKind::Placeholder(p) => { + if !seen.insert(p.var()) { + return Err(NotUniqueParam::DuplicateParam(c.into())); + } + } + _ => return Err(NotUniqueParam::NotParam(c.into())), + }, + } + } + + Ok(()) +} + +// FIXME: This should check for dupes and non-params first, then infer vars. +pub enum NotUniqueParam<I: Interner> { + DuplicateParam(I::GenericArg), + NotParam(I::GenericArg), +} diff --git a/compiler/rustc_trait_selection/src/solve/normalizes_to/weak_types.rs b/compiler/rustc_next_trait_solver/src/solve/normalizes_to/weak_types.rs index 5442b9ccffc..45341917bb2 100644 --- a/compiler/rustc_trait_selection/src/solve/normalizes_to/weak_types.rs +++ b/compiler/rustc_next_trait_solver/src/solve/normalizes_to/weak_types.rs @@ -3,17 +3,21 @@ //! //! Since a weak alias is never ambiguous, this just computes the `type_of` of //! the alias and registers the where-clauses of the type alias. -use rustc_infer::infer::InferCtxt; -use rustc_middle::traits::solve::{Certainty, Goal, GoalSource, QueryResult}; -use rustc_middle::ty; -use crate::solve::EvalCtxt; +use rustc_type_ir::{self as ty, Interner}; -impl<'tcx> EvalCtxt<'_, InferCtxt<'tcx>> { +use crate::infcx::SolverDelegate; +use crate::solve::{Certainty, EvalCtxt, Goal, GoalSource, QueryResult}; + +impl<Infcx, I> EvalCtxt<'_, Infcx> +where + Infcx: SolverDelegate<Interner = I>, + I: Interner, +{ pub(super) fn normalize_weak_type( &mut self, - goal: Goal<'tcx, ty::NormalizesTo<'tcx>>, - ) -> QueryResult<'tcx> { + goal: Goal<I, ty::NormalizesTo<I>>, + ) -> QueryResult<I> { let tcx = self.interner(); let weak_ty = goal.predicate.alias; @@ -21,13 +25,11 @@ impl<'tcx> EvalCtxt<'_, InferCtxt<'tcx>> { self.add_goals( GoalSource::Misc, tcx.predicates_of(weak_ty.def_id) - .instantiate(tcx, weak_ty.args) - .predicates - .into_iter() + .iter_instantiated(tcx, &weak_ty.args) .map(|pred| goal.with(tcx, pred)), ); - let actual = tcx.type_of(weak_ty.def_id).instantiate(tcx, weak_ty.args); + let actual = tcx.type_of(weak_ty.def_id).instantiate(tcx, &weak_ty.args); self.instantiate_normalizes_to_term(goal, actual.into()); self.evaluate_added_goals_and_make_canonical_response(Certainty::Yes) diff --git a/compiler/rustc_trait_selection/src/solve/project_goals.rs b/compiler/rustc_next_trait_solver/src/solve/project_goals.rs index cae73cc2d07..4bb1fe5be6f 100644 --- a/compiler/rustc_trait_selection/src/solve/project_goals.rs +++ b/compiler/rustc_next_trait_solver/src/solve/project_goals.rs @@ -1,16 +1,19 @@ -use crate::solve::GoalSource; +use rustc_type_ir::{self as ty, Interner, ProjectionPredicate}; +use tracing::instrument; -use super::EvalCtxt; -use rustc_infer::infer::InferCtxt; -use rustc_middle::traits::solve::{Certainty, Goal, QueryResult}; -use rustc_middle::ty::{self, ProjectionPredicate}; +use crate::infcx::SolverDelegate; +use crate::solve::{Certainty, EvalCtxt, Goal, GoalSource, QueryResult}; -impl<'tcx> EvalCtxt<'_, InferCtxt<'tcx>> { +impl<Infcx, I> EvalCtxt<'_, Infcx> +where + Infcx: SolverDelegate<Interner = I>, + I: Interner, +{ #[instrument(level = "trace", skip(self), ret)] pub(super) fn compute_projection_goal( &mut self, - goal: Goal<'tcx, ProjectionPredicate<'tcx>>, - ) -> QueryResult<'tcx> { + goal: Goal<I, ProjectionPredicate<I>>, + ) -> QueryResult<I> { let tcx = self.interner(); let projection_term = goal.predicate.projection_term.to_term(tcx); let goal = goal.with( diff --git a/compiler/rustc_trait_selection/src/solve/search_graph.rs b/compiler/rustc_next_trait_solver/src/solve/search_graph.rs index 84878fea101..b923a121d81 100644 --- a/compiler/rustc_trait_selection/src/solve/search_graph.rs +++ b/compiler/rustc_next_trait_solver/src/solve/search_graph.rs @@ -1,22 +1,19 @@ use std::mem; use rustc_data_structures::fx::{FxHashMap, FxHashSet}; -use rustc_index::Idx; -use rustc_index::IndexVec; -use rustc_infer::infer::InferCtxt; -use rustc_middle::dep_graph::dep_kinds; -use rustc_middle::traits::solve::CacheData; -use rustc_middle::traits::solve::EvaluationCache; -use rustc_middle::ty::TyCtxt; -use rustc_next_trait_solver::solve::{CanonicalInput, Certainty, QueryResult}; -use rustc_session::Limit; +use rustc_index::{Idx, IndexVec}; use rustc_type_ir::inherent::*; use rustc_type_ir::Interner; +use tracing::debug; -use super::inspect; -use super::inspect::ProofTreeBuilder; -use super::SolverMode; -use crate::solve::FIXPOINT_STEP_LIMIT; +use crate::infcx::SolverDelegate; +use crate::solve::inspect::{self, ProofTreeBuilder}; +use crate::solve::{ + CacheData, CanonicalInput, Certainty, QueryResult, SolverMode, FIXPOINT_STEP_LIMIT, +}; + +#[derive(Copy, Clone, PartialEq, Eq, Debug)] +pub struct SolverLimit(usize); rustc_index::newtype_index! { #[orderable] @@ -39,7 +36,7 @@ bitflags::bitflags! { struct StackEntry<I: Interner> { input: CanonicalInput<I>, - available_depth: Limit, + available_depth: SolverLimit, /// The maximum depth reached by this stack entry, only up-to date /// for the top of the stack and lazily updated for the rest. @@ -168,19 +165,19 @@ impl<I: Interner> SearchGraph<I> { fn allowed_depth_for_nested( tcx: I, stack: &IndexVec<StackDepth, StackEntry<I>>, - ) -> Option<Limit> { + ) -> Option<SolverLimit> { if let Some(last) = stack.raw.last() { if last.available_depth.0 == 0 { return None; } Some(if last.encountered_overflow { - Limit(last.available_depth.0 / 4) + SolverLimit(last.available_depth.0 / 4) } else { - Limit(last.available_depth.0 - 1) + SolverLimit(last.available_depth.0 - 1) }) } else { - Some(Limit(tcx.recursion_limit())) + Some(SolverLimit(tcx.recursion_limit())) } } @@ -240,34 +237,26 @@ impl<I: Interner> SearchGraph<I> { !entry.is_empty() }); } -} -impl<'tcx> SearchGraph<TyCtxt<'tcx>> { /// The trait solver behavior is different for coherence /// so we use a separate cache. Alternatively we could use /// a single cache and share it between coherence and ordinary /// trait solving. - pub(super) fn global_cache(&self, tcx: TyCtxt<'tcx>) -> &'tcx EvaluationCache<'tcx> { - match self.mode { - SolverMode::Normal => &tcx.new_solver_evaluation_cache, - SolverMode::Coherence => &tcx.new_solver_coherence_evaluation_cache, - } + pub(super) fn global_cache(&self, tcx: I) -> I::EvaluationCache { + tcx.evaluation_cache(self.mode) } /// Probably the most involved method of the whole solver. /// /// Given some goal which is proven via the `prove_goal` closure, this /// handles caching, overflow, and coinductive cycles. - pub(super) fn with_new_goal( + pub(super) fn with_new_goal<Infcx: SolverDelegate<Interner = I>>( &mut self, - tcx: TyCtxt<'tcx>, - input: CanonicalInput<TyCtxt<'tcx>>, - inspect: &mut ProofTreeBuilder<InferCtxt<'tcx>>, - mut prove_goal: impl FnMut( - &mut Self, - &mut ProofTreeBuilder<InferCtxt<'tcx>>, - ) -> QueryResult<TyCtxt<'tcx>>, - ) -> QueryResult<TyCtxt<'tcx>> { + tcx: I, + input: CanonicalInput<I>, + inspect: &mut ProofTreeBuilder<Infcx>, + mut prove_goal: impl FnMut(&mut Self, &mut ProofTreeBuilder<Infcx>) -> QueryResult<I>, + ) -> QueryResult<I> { self.check_invariants(); // Check for overflow. let Some(available_depth) = Self::allowed_depth_for_nested(tcx, &self.stack) else { @@ -361,21 +350,20 @@ impl<'tcx> SearchGraph<TyCtxt<'tcx>> { // not tracked by the cache key and from outside of this anon task, it // must not be added to the global cache. Notably, this is the case for // trait solver cycles participants. - let ((final_entry, result), dep_node) = - tcx.dep_graph.with_anon_task(tcx, dep_kinds::TraitSelect, || { - for _ in 0..FIXPOINT_STEP_LIMIT { - match self.fixpoint_step_in_task(tcx, input, inspect, &mut prove_goal) { - StepResult::Done(final_entry, result) => return (final_entry, result), - StepResult::HasChanged => debug!("fixpoint changed provisional results"), - } + let ((final_entry, result), dep_node) = tcx.with_cached_task(|| { + for _ in 0..FIXPOINT_STEP_LIMIT { + match self.fixpoint_step_in_task(tcx, input, inspect, &mut prove_goal) { + StepResult::Done(final_entry, result) => return (final_entry, result), + StepResult::HasChanged => debug!("fixpoint changed provisional results"), } + } - debug!("canonical cycle overflow"); - let current_entry = self.pop_stack(); - debug_assert!(current_entry.has_been_used.is_empty()); - let result = Self::response_no_constraints(tcx, input, Certainty::overflow(false)); - (current_entry, result) - }); + debug!("canonical cycle overflow"); + let current_entry = self.pop_stack(); + debug_assert!(current_entry.has_been_used.is_empty()); + let result = Self::response_no_constraints(tcx, input, Certainty::overflow(false)); + (current_entry, result) + }); let proof_tree = inspect.finalize_canonical_goal_evaluation(tcx); @@ -423,16 +411,17 @@ impl<'tcx> SearchGraph<TyCtxt<'tcx>> { /// Try to fetch a previously computed result from the global cache, /// making sure to only do so if it would match the result of reevaluating /// this goal. - fn lookup_global_cache( + fn lookup_global_cache<Infcx: SolverDelegate<Interner = I>>( &mut self, - tcx: TyCtxt<'tcx>, - input: CanonicalInput<TyCtxt<'tcx>>, - available_depth: Limit, - inspect: &mut ProofTreeBuilder<InferCtxt<'tcx>>, - ) -> Option<QueryResult<TyCtxt<'tcx>>> { + tcx: I, + input: CanonicalInput<I>, + available_depth: SolverLimit, + inspect: &mut ProofTreeBuilder<Infcx>, + ) -> Option<QueryResult<I>> { let CacheData { result, proof_tree, additional_depth, encountered_overflow } = self .global_cache(tcx) - .get(tcx, input, self.stack.iter().map(|e| e.input), available_depth)?; + // FIXME: Awkward `Limit -> usize -> Limit`. + .get(tcx, input, self.stack.iter().map(|e| e.input), available_depth.0)?; // If we're building a proof tree and the current cache entry does not // contain a proof tree, we do not use the entry but instead recompute @@ -465,21 +454,22 @@ enum StepResult<I: Interner> { HasChanged, } -impl<'tcx> SearchGraph<TyCtxt<'tcx>> { +impl<I: Interner> SearchGraph<I> { /// When we encounter a coinductive cycle, we have to fetch the /// result of that cycle while we are still computing it. Because /// of this we continuously recompute the cycle until the result /// of the previous iteration is equal to the final result, at which /// point we are done. - fn fixpoint_step_in_task<F>( + fn fixpoint_step_in_task<Infcx, F>( &mut self, - tcx: TyCtxt<'tcx>, - input: CanonicalInput<TyCtxt<'tcx>>, - inspect: &mut ProofTreeBuilder<InferCtxt<'tcx>>, + tcx: I, + input: CanonicalInput<I>, + inspect: &mut ProofTreeBuilder<Infcx>, prove_goal: &mut F, - ) -> StepResult<TyCtxt<'tcx>> + ) -> StepResult<I> where - F: FnMut(&mut Self, &mut ProofTreeBuilder<InferCtxt<'tcx>>) -> QueryResult<TyCtxt<'tcx>>, + Infcx: SolverDelegate<Interner = I>, + F: FnMut(&mut Self, &mut ProofTreeBuilder<Infcx>) -> QueryResult<I>, { let result = prove_goal(self, inspect); let stack_entry = self.pop_stack(); @@ -533,15 +523,13 @@ impl<'tcx> SearchGraph<TyCtxt<'tcx>> { } fn response_no_constraints( - tcx: TyCtxt<'tcx>, - goal: CanonicalInput<TyCtxt<'tcx>>, + tcx: I, + goal: CanonicalInput<I>, certainty: Certainty, - ) -> QueryResult<TyCtxt<'tcx>> { + ) -> QueryResult<I> { Ok(super::response_no_constraints_raw(tcx, goal.max_universe, goal.variables, certainty)) } -} -impl<I: Interner> SearchGraph<I> { #[allow(rustc::potential_query_instability)] fn check_invariants(&self) { if !cfg!(debug_assertions) { diff --git a/compiler/rustc_trait_selection/src/solve/trait_goals.rs b/compiler/rustc_next_trait_solver/src/solve/trait_goals.rs index bcb2ea18f78..d1419bf5db9 100644 --- a/compiler/rustc_trait_selection/src/solve/trait_goals.rs +++ b/compiler/rustc_next_trait_solver/src/solve/trait_goals.rs @@ -1,60 +1,60 @@ //! Dealing with trait goals, i.e. `T: Trait<'a, U>`. -use super::assembly::structural_traits::AsyncCallableRelevantTypes; -use super::assembly::{self, structural_traits, Candidate}; -use super::{EvalCtxt, GoalSource, SolverMode}; +use rustc_ast_ir::Movability; use rustc_data_structures::fx::FxIndexSet; -use rustc_hir::def_id::DefId; -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}; -use rustc_middle::traits::{BuiltinImplSource, Reveal}; -use rustc_middle::ty::fast_reject::{DeepRejectCtxt, TreatParams}; -use rustc_middle::ty::{self, Ty, TyCtxt, Upcast}; -use rustc_middle::ty::{TraitPredicate, TypeVisitableExt}; -use rustc_span::ErrorGuaranteed; - -impl<'tcx> assembly::GoalKind<'tcx> for TraitPredicate<'tcx> { - fn self_ty(self) -> Ty<'tcx> { +use rustc_type_ir::inherent::*; +use rustc_type_ir::lang_items::TraitSolverLangItem; +use rustc_type_ir::visit::TypeVisitableExt as _; +use rustc_type_ir::{self as ty, Interner, TraitPredicate, Upcast as _}; +use tracing::{instrument, trace}; + +use crate::infcx::SolverDelegate; +use crate::solve::assembly::structural_traits::{self, AsyncCallableRelevantTypes}; +use crate::solve::assembly::{self, Candidate}; +use crate::solve::inspect::ProbeKind; +use crate::solve::{ + BuiltinImplSource, CandidateSource, Certainty, EvalCtxt, Goal, GoalSource, MaybeCause, + NoSolution, QueryResult, Reveal, SolverMode, +}; + +impl<Infcx, I> assembly::GoalKind<Infcx> for TraitPredicate<I> +where + Infcx: SolverDelegate<Interner = I>, + I: Interner, +{ + fn self_ty(self) -> I::Ty { self.self_ty() } - fn trait_ref(self, _: TyCtxt<'tcx>) -> ty::TraitRef<'tcx> { + fn trait_ref(self, _: I) -> ty::TraitRef<I> { self.trait_ref } - fn with_self_ty(self, tcx: TyCtxt<'tcx>, self_ty: Ty<'tcx>) -> Self { + fn with_self_ty(self, tcx: I, self_ty: I::Ty) -> Self { self.with_self_ty(tcx, self_ty) } - fn trait_def_id(self, _: TyCtxt<'tcx>) -> DefId { + fn trait_def_id(self, _: I) -> I::DefId { self.def_id() } fn consider_impl_candidate( - ecx: &mut EvalCtxt<'_, InferCtxt<'tcx>>, - goal: Goal<'tcx, TraitPredicate<'tcx>>, - impl_def_id: DefId, - ) -> Result<Candidate<TyCtxt<'tcx>>, NoSolution> { + ecx: &mut EvalCtxt<'_, Infcx>, + goal: Goal<I, TraitPredicate<I>>, + impl_def_id: I::DefId, + ) -> Result<Candidate<I>, NoSolution> { let tcx = ecx.interner(); - let impl_trait_header = tcx.impl_trait_header(impl_def_id).unwrap(); - let drcx = DeepRejectCtxt { treat_obligation_params: TreatParams::ForLookup }; - if !drcx.args_may_unify( - goal.predicate.trait_ref.args, - impl_trait_header.trait_ref.skip_binder().args, - ) { + let impl_trait_ref = tcx.impl_trait_ref(impl_def_id); + if !tcx + .args_may_unify_deep(goal.predicate.trait_ref.args, impl_trait_ref.skip_binder().args) + { return Err(NoSolution); } // An upper bound of the certainty of this goal, used to lower the certainty // of reservation impl to ambiguous during coherence. - let impl_polarity = impl_trait_header.polarity; + let impl_polarity = tcx.impl_polarity(impl_def_id); let maximal_certainty = match (impl_polarity, goal.predicate.polarity) { // In intercrate mode, this is ambiguous. But outside of intercrate, // it's not a real impl. @@ -77,14 +77,12 @@ impl<'tcx> assembly::GoalKind<'tcx> for TraitPredicate<'tcx> { ecx.probe_trait_candidate(CandidateSource::Impl(impl_def_id)).enter(|ecx| { let impl_args = ecx.fresh_args_for_item(impl_def_id); ecx.record_impl_args(impl_args); - let impl_trait_ref = impl_trait_header.trait_ref.instantiate(tcx, impl_args); + let impl_trait_ref = impl_trait_ref.instantiate(tcx, &impl_args); ecx.eq(goal.param_env, goal.predicate.trait_ref, impl_trait_ref)?; let where_clause_bounds = tcx .predicates_of(impl_def_id) - .instantiate(tcx, impl_args) - .predicates - .into_iter() + .iter_instantiated(tcx, &impl_args) .map(|pred| goal.with(tcx, pred)); ecx.add_goals(GoalSource::ImplWhereBound, where_clause_bounds); @@ -93,21 +91,21 @@ impl<'tcx> assembly::GoalKind<'tcx> for TraitPredicate<'tcx> { } fn consider_error_guaranteed_candidate( - ecx: &mut EvalCtxt<'_, InferCtxt<'tcx>>, - _guar: ErrorGuaranteed, - ) -> Result<Candidate<TyCtxt<'tcx>>, NoSolution> { + ecx: &mut EvalCtxt<'_, Infcx>, + _guar: I::ErrorGuaranteed, + ) -> Result<Candidate<I>, 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)) } fn probe_and_match_goal_against_assumption( - ecx: &mut EvalCtxt<'_, InferCtxt<'tcx>>, - source: CandidateSource<'tcx>, - goal: Goal<'tcx, Self>, - assumption: ty::Clause<'tcx>, - then: impl FnOnce(&mut EvalCtxt<'_, InferCtxt<'tcx>>) -> QueryResult<'tcx>, - ) -> Result<Candidate<TyCtxt<'tcx>>, NoSolution> { + ecx: &mut EvalCtxt<'_, Infcx>, + source: CandidateSource<I>, + goal: Goal<I, Self>, + assumption: I::Clause, + then: impl FnOnce(&mut EvalCtxt<'_, Infcx>) -> QueryResult<I>, + ) -> Result<Candidate<I>, 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 @@ -130,9 +128,9 @@ impl<'tcx> assembly::GoalKind<'tcx> for TraitPredicate<'tcx> { } fn consider_auto_trait_candidate( - ecx: &mut EvalCtxt<'_, InferCtxt<'tcx>>, - goal: Goal<'tcx, Self>, - ) -> Result<Candidate<TyCtxt<'tcx>>, NoSolution> { + ecx: &mut EvalCtxt<'_, Infcx>, + goal: Goal<I, Self>, + ) -> Result<Candidate<I>, NoSolution> { if goal.predicate.polarity != ty::PredicatePolarity::Positive { return Err(NoSolution); } @@ -159,7 +157,10 @@ impl<'tcx> assembly::GoalKind<'tcx> for TraitPredicate<'tcx> { if let ty::Alias(ty::Opaque, opaque_ty) = goal.predicate.self_ty().kind() { if matches!(goal.param_env.reveal(), Reveal::All) || matches!(ecx.solver_mode(), SolverMode::Coherence) - || ecx.can_define_opaque_ty(opaque_ty.def_id) + || opaque_ty + .def_id + .as_local() + .is_some_and(|def_id| ecx.can_define_opaque_ty(def_id)) { return Err(NoSolution); } @@ -173,9 +174,9 @@ impl<'tcx> assembly::GoalKind<'tcx> for TraitPredicate<'tcx> { } fn consider_trait_alias_candidate( - ecx: &mut EvalCtxt<'_, InferCtxt<'tcx>>, - goal: Goal<'tcx, Self>, - ) -> Result<Candidate<TyCtxt<'tcx>>, NoSolution> { + ecx: &mut EvalCtxt<'_, Infcx>, + goal: Goal<I, Self>, + ) -> Result<Candidate<I>, NoSolution> { if goal.predicate.polarity != ty::PredicatePolarity::Positive { return Err(NoSolution); } @@ -185,20 +186,18 @@ impl<'tcx> assembly::GoalKind<'tcx> for TraitPredicate<'tcx> { ecx.probe_builtin_trait_candidate(BuiltinImplSource::Misc).enter(|ecx| { let nested_obligations = tcx .predicates_of(goal.predicate.def_id()) - .instantiate(tcx, goal.predicate.trait_ref.args); + .iter_instantiated(tcx, &goal.predicate.trait_ref.args) + .map(|p| goal.with(tcx, p)); // FIXME(-Znext-solver=coinductive): Should this be `GoalSource::ImplWhereBound`? - ecx.add_goals( - GoalSource::Misc, - nested_obligations.predicates.into_iter().map(|p| goal.with(tcx, p)), - ); + ecx.add_goals(GoalSource::Misc, nested_obligations); ecx.evaluate_added_goals_and_make_canonical_response(Certainty::Yes) }) } fn consider_builtin_sized_candidate( - ecx: &mut EvalCtxt<'_, InferCtxt<'tcx>>, - goal: Goal<'tcx, Self>, - ) -> Result<Candidate<TyCtxt<'tcx>>, NoSolution> { + ecx: &mut EvalCtxt<'_, Infcx>, + goal: Goal<I, Self>, + ) -> Result<Candidate<I>, NoSolution> { if goal.predicate.polarity != ty::PredicatePolarity::Positive { return Err(NoSolution); } @@ -211,9 +210,9 @@ impl<'tcx> assembly::GoalKind<'tcx> for TraitPredicate<'tcx> { } fn consider_builtin_copy_clone_candidate( - ecx: &mut EvalCtxt<'_, InferCtxt<'tcx>>, - goal: Goal<'tcx, Self>, - ) -> Result<Candidate<TyCtxt<'tcx>>, NoSolution> { + ecx: &mut EvalCtxt<'_, Infcx>, + goal: Goal<I, Self>, + ) -> Result<Candidate<I>, NoSolution> { if goal.predicate.polarity != ty::PredicatePolarity::Positive { return Err(NoSolution); } @@ -226,28 +225,20 @@ impl<'tcx> assembly::GoalKind<'tcx> for TraitPredicate<'tcx> { } fn consider_builtin_pointer_like_candidate( - ecx: &mut EvalCtxt<'_, InferCtxt<'tcx>>, - goal: Goal<'tcx, Self>, - ) -> Result<Candidate<TyCtxt<'tcx>>, NoSolution> { + ecx: &mut EvalCtxt<'_, Infcx>, + goal: Goal<I, Self>, + ) -> Result<Candidate<I>, NoSolution> { if goal.predicate.polarity != ty::PredicatePolarity::Positive { return Err(NoSolution); } - // The regions of a type don't affect the size of the type let tcx = ecx.interner(); - // We should erase regions from both the param-env and type, since both - // may have infer regions. Specifically, after canonicalizing and instantiating, - // early bound regions turn into region vars in both the new and old solver. - let key = tcx.erase_regions(goal.param_env.and(goal.predicate.self_ty())); // But if there are inference variables, we have to wait until it's resolved. - if key.has_non_region_infer() { + if (goal.param_env, goal.predicate.self_ty()).has_non_region_infer() { return ecx.forced_ambiguity(MaybeCause::Ambiguity); } - if let Ok(layout) = tcx.layout_of(key) - && layout.layout.is_pointer_like(&tcx.data_layout) - { - // FIXME: We could make this faster by making a no-constraints response + if tcx.layout_is_pointer_like(goal.param_env, goal.predicate.self_ty()) { ecx.probe_builtin_trait_candidate(BuiltinImplSource::Misc) .enter(|ecx| ecx.evaluate_added_goals_and_make_canonical_response(Certainty::Yes)) } else { @@ -256,9 +247,9 @@ 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<Candidate<TyCtxt<'tcx>>, NoSolution> { + ecx: &mut EvalCtxt<'_, Infcx>, + goal: Goal<I, Self>, + ) -> Result<Candidate<I>, NoSolution> { let self_ty = goal.predicate.self_ty(); match goal.predicate.polarity { // impl FnPtr for FnPtr {} @@ -287,10 +278,10 @@ impl<'tcx> assembly::GoalKind<'tcx> for TraitPredicate<'tcx> { } fn consider_builtin_fn_trait_candidates( - ecx: &mut EvalCtxt<'_, InferCtxt<'tcx>>, - goal: Goal<'tcx, Self>, + ecx: &mut EvalCtxt<'_, Infcx>, + goal: Goal<I, Self>, goal_kind: ty::ClosureKind, - ) -> Result<Candidate<TyCtxt<'tcx>>, NoSolution> { + ) -> Result<Candidate<I>, NoSolution> { if goal.predicate.polarity != ty::PredicatePolarity::Positive { return Err(NoSolution); } @@ -308,7 +299,7 @@ impl<'tcx> assembly::GoalKind<'tcx> for TraitPredicate<'tcx> { } }; let output_is_sized_pred = tupled_inputs_and_output.map_bound(|(_, output)| { - ty::TraitRef::new(tcx, tcx.require_lang_item(LangItem::Sized, None), [output]) + ty::TraitRef::new(tcx, tcx.require_lang_item(TraitSolverLangItem::Sized), [output]) }); let pred = tupled_inputs_and_output @@ -328,10 +319,10 @@ impl<'tcx> assembly::GoalKind<'tcx> for TraitPredicate<'tcx> { } fn consider_builtin_async_fn_trait_candidates( - ecx: &mut EvalCtxt<'_, InferCtxt<'tcx>>, - goal: Goal<'tcx, Self>, + ecx: &mut EvalCtxt<'_, Infcx>, + goal: Goal<I, Self>, goal_kind: ty::ClosureKind, - ) -> Result<Candidate<TyCtxt<'tcx>>, NoSolution> { + ) -> Result<Candidate<I>, NoSolution> { if goal.predicate.polarity != ty::PredicatePolarity::Positive { return Err(NoSolution); } @@ -343,13 +334,13 @@ impl<'tcx> assembly::GoalKind<'tcx> for TraitPredicate<'tcx> { goal.predicate.self_ty(), goal_kind, // This region doesn't matter because we're throwing away the coroutine type - tcx.lifetimes.re_static, + Region::new_static(tcx), )?; let output_is_sized_pred = tupled_inputs_and_output_and_coroutine.map_bound( |AsyncCallableRelevantTypes { output_coroutine_ty, .. }| { ty::TraitRef::new( tcx, - tcx.require_lang_item(LangItem::Sized, None), + tcx.require_lang_item(TraitSolverLangItem::Sized), [output_coroutine_ty], ) }, @@ -379,11 +370,11 @@ 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<Candidate<TyCtxt<'tcx>>, NoSolution> { + ecx: &mut EvalCtxt<'_, Infcx>, + goal: Goal<I, Self>, + ) -> Result<Candidate<I>, NoSolution> { let [closure_fn_kind_ty, goal_kind_ty] = **goal.predicate.trait_ref.args else { - bug!(); + panic!(); }; let Some(closure_kind) = closure_fn_kind_ty.expect_ty().to_opt_closure_kind() else { @@ -406,9 +397,9 @@ impl<'tcx> assembly::GoalKind<'tcx> for TraitPredicate<'tcx> { /// impl Tuple for (T1, .., Tn) {} /// ``` fn consider_builtin_tuple_candidate( - ecx: &mut EvalCtxt<'_, InferCtxt<'tcx>>, - goal: Goal<'tcx, Self>, - ) -> Result<Candidate<TyCtxt<'tcx>>, NoSolution> { + ecx: &mut EvalCtxt<'_, Infcx>, + goal: Goal<I, Self>, + ) -> Result<Candidate<I>, NoSolution> { if goal.predicate.polarity != ty::PredicatePolarity::Positive { return Err(NoSolution); } @@ -422,9 +413,9 @@ impl<'tcx> assembly::GoalKind<'tcx> for TraitPredicate<'tcx> { } fn consider_builtin_pointee_candidate( - ecx: &mut EvalCtxt<'_, InferCtxt<'tcx>>, - goal: Goal<'tcx, Self>, - ) -> Result<Candidate<TyCtxt<'tcx>>, NoSolution> { + ecx: &mut EvalCtxt<'_, Infcx>, + goal: Goal<I, Self>, + ) -> Result<Candidate<I>, NoSolution> { if goal.predicate.polarity != ty::PredicatePolarity::Positive { return Err(NoSolution); } @@ -434,14 +425,14 @@ impl<'tcx> assembly::GoalKind<'tcx> for TraitPredicate<'tcx> { } fn consider_builtin_future_candidate( - ecx: &mut EvalCtxt<'_, InferCtxt<'tcx>>, - goal: Goal<'tcx, Self>, - ) -> Result<Candidate<TyCtxt<'tcx>>, NoSolution> { + ecx: &mut EvalCtxt<'_, Infcx>, + goal: Goal<I, Self>, + ) -> Result<Candidate<I>, NoSolution> { if goal.predicate.polarity != ty::PredicatePolarity::Positive { return Err(NoSolution); } - let ty::Coroutine(def_id, _) = *goal.predicate.self_ty().kind() else { + let ty::Coroutine(def_id, _) = goal.predicate.self_ty().kind() else { return Err(NoSolution); }; @@ -460,14 +451,14 @@ impl<'tcx> assembly::GoalKind<'tcx> for TraitPredicate<'tcx> { } fn consider_builtin_iterator_candidate( - ecx: &mut EvalCtxt<'_, InferCtxt<'tcx>>, - goal: Goal<'tcx, Self>, - ) -> Result<Candidate<TyCtxt<'tcx>>, NoSolution> { + ecx: &mut EvalCtxt<'_, Infcx>, + goal: Goal<I, Self>, + ) -> Result<Candidate<I>, NoSolution> { if goal.predicate.polarity != ty::PredicatePolarity::Positive { return Err(NoSolution); } - let ty::Coroutine(def_id, _) = *goal.predicate.self_ty().kind() else { + let ty::Coroutine(def_id, _) = goal.predicate.self_ty().kind() else { return Err(NoSolution); }; @@ -486,14 +477,14 @@ impl<'tcx> assembly::GoalKind<'tcx> for TraitPredicate<'tcx> { } fn consider_builtin_fused_iterator_candidate( - ecx: &mut EvalCtxt<'_, InferCtxt<'tcx>>, - goal: Goal<'tcx, Self>, - ) -> Result<Candidate<TyCtxt<'tcx>>, NoSolution> { + ecx: &mut EvalCtxt<'_, Infcx>, + goal: Goal<I, Self>, + ) -> Result<Candidate<I>, NoSolution> { if goal.predicate.polarity != ty::PredicatePolarity::Positive { return Err(NoSolution); } - let ty::Coroutine(def_id, _) = *goal.predicate.self_ty().kind() else { + let ty::Coroutine(def_id, _) = goal.predicate.self_ty().kind() else { return Err(NoSolution); }; @@ -510,14 +501,14 @@ impl<'tcx> assembly::GoalKind<'tcx> for TraitPredicate<'tcx> { } fn consider_builtin_async_iterator_candidate( - ecx: &mut EvalCtxt<'_, InferCtxt<'tcx>>, - goal: Goal<'tcx, Self>, - ) -> Result<Candidate<TyCtxt<'tcx>>, NoSolution> { + ecx: &mut EvalCtxt<'_, Infcx>, + goal: Goal<I, Self>, + ) -> Result<Candidate<I>, NoSolution> { if goal.predicate.polarity != ty::PredicatePolarity::Positive { return Err(NoSolution); } - let ty::Coroutine(def_id, _) = *goal.predicate.self_ty().kind() else { + let ty::Coroutine(def_id, _) = goal.predicate.self_ty().kind() else { return Err(NoSolution); }; @@ -536,15 +527,15 @@ impl<'tcx> assembly::GoalKind<'tcx> for TraitPredicate<'tcx> { } fn consider_builtin_coroutine_candidate( - ecx: &mut EvalCtxt<'_, InferCtxt<'tcx>>, - goal: Goal<'tcx, Self>, - ) -> Result<Candidate<TyCtxt<'tcx>>, NoSolution> { + ecx: &mut EvalCtxt<'_, Infcx>, + goal: Goal<I, Self>, + ) -> Result<Candidate<I>, NoSolution> { if goal.predicate.polarity != ty::PredicatePolarity::Positive { return Err(NoSolution); } let self_ty = goal.predicate.self_ty(); - let ty::Coroutine(def_id, args) = *self_ty.kind() else { + let ty::Coroutine(def_id, args) = self_ty.kind() else { return Err(NoSolution); }; @@ -568,9 +559,9 @@ impl<'tcx> assembly::GoalKind<'tcx> for TraitPredicate<'tcx> { } fn consider_builtin_discriminant_kind_candidate( - ecx: &mut EvalCtxt<'_, InferCtxt<'tcx>>, - goal: Goal<'tcx, Self>, - ) -> Result<Candidate<TyCtxt<'tcx>>, NoSolution> { + ecx: &mut EvalCtxt<'_, Infcx>, + goal: Goal<I, Self>, + ) -> Result<Candidate<I>, NoSolution> { if goal.predicate.polarity != ty::PredicatePolarity::Positive { return Err(NoSolution); } @@ -581,9 +572,9 @@ impl<'tcx> assembly::GoalKind<'tcx> for TraitPredicate<'tcx> { } fn consider_builtin_async_destruct_candidate( - ecx: &mut EvalCtxt<'_, InferCtxt<'tcx>>, - goal: Goal<'tcx, Self>, - ) -> Result<Candidate<TyCtxt<'tcx>>, NoSolution> { + ecx: &mut EvalCtxt<'_, Infcx>, + goal: Goal<I, Self>, + ) -> Result<Candidate<I>, NoSolution> { if goal.predicate.polarity != ty::PredicatePolarity::Positive { return Err(NoSolution); } @@ -594,9 +585,9 @@ impl<'tcx> assembly::GoalKind<'tcx> for TraitPredicate<'tcx> { } fn consider_builtin_destruct_candidate( - ecx: &mut EvalCtxt<'_, InferCtxt<'tcx>>, - goal: Goal<'tcx, Self>, - ) -> Result<Candidate<TyCtxt<'tcx>>, NoSolution> { + ecx: &mut EvalCtxt<'_, Infcx>, + goal: Goal<I, Self>, + ) -> Result<Candidate<I>, NoSolution> { if goal.predicate.polarity != ty::PredicatePolarity::Positive { return Err(NoSolution); } @@ -610,9 +601,9 @@ impl<'tcx> assembly::GoalKind<'tcx> for TraitPredicate<'tcx> { } fn consider_builtin_transmute_candidate( - ecx: &mut EvalCtxt<'_, InferCtxt<'tcx>>, - goal: Goal<'tcx, Self>, - ) -> Result<Candidate<TyCtxt<'tcx>>, NoSolution> { + ecx: &mut EvalCtxt<'_, Infcx>, + goal: Goal<I, Self>, + ) -> Result<Candidate<I>, NoSolution> { if goal.predicate.polarity != ty::PredicatePolarity::Positive { return Err(NoSolution); } @@ -622,22 +613,14 @@ impl<'tcx> assembly::GoalKind<'tcx> for TraitPredicate<'tcx> { return Err(NoSolution); } - // Erase regions because we compute layouts in `rustc_transmute`, - // which will ICE for region vars. - let args = ecx.interner().erase_regions(goal.predicate.trait_ref.args); - - let Some(assume) = - rustc_transmute::Assume::from_const(ecx.interner(), goal.param_env, args.const_at(2)) - else { - return Err(NoSolution); - }; - // FIXME: This actually should destructure the `Result` we get from transmutability and // register candiates. We probably need to register >1 since we may have an OR of ANDs. ecx.probe_builtin_trait_candidate(BuiltinImplSource::Misc).enter(|ecx| { let certainty = ecx.is_transmutable( - rustc_transmute::Types { dst: args.type_at(0), src: args.type_at(1) }, - assume, + goal.param_env, + goal.predicate.trait_ref.args.type_at(0), + goal.predicate.trait_ref.args.type_at(1), + goal.predicate.trait_ref.args.const_at(2), )?; ecx.evaluate_added_goals_and_make_canonical_response(certainty) }) @@ -651,9 +634,9 @@ impl<'tcx> assembly::GoalKind<'tcx> for TraitPredicate<'tcx> { /// impl<'a, T: Trait + 'a> Unsize<dyn Trait + 'a> for T {} /// ``` fn consider_structural_builtin_unsize_candidates( - ecx: &mut EvalCtxt<'_, InferCtxt<'tcx>>, - goal: Goal<'tcx, Self>, - ) -> Vec<Candidate<TyCtxt<'tcx>>> { + ecx: &mut EvalCtxt<'_, Infcx>, + goal: Goal<I, Self>, + ) -> Vec<Candidate<I>> { if goal.predicate.polarity != ty::PredicatePolarity::Positive { return vec![]; } @@ -676,7 +659,7 @@ impl<'tcx> assembly::GoalKind<'tcx> for TraitPredicate<'tcx> { let goal = goal.with(ecx.interner(), (a_ty, b_ty)); match (a_ty.kind(), b_ty.kind()) { - (ty::Infer(ty::TyVar(..)), ..) => bug!("unexpected infer {a_ty:?} {b_ty:?}"), + (ty::Infer(ty::TyVar(..)), ..) => panic!("unexpected infer {a_ty:?} {b_ty:?}"), (_, ty::Infer(ty::TyVar(..))) => { result_to_single(ecx.forced_ambiguity(MaybeCause::Ambiguity)) @@ -684,24 +667,24 @@ impl<'tcx> assembly::GoalKind<'tcx> for TraitPredicate<'tcx> { // Trait upcasting, or `dyn Trait + Auto + 'a` -> `dyn Trait + 'b`. ( - &ty::Dynamic(a_data, a_region, ty::Dyn), - &ty::Dynamic(b_data, b_region, ty::Dyn), + ty::Dynamic(a_data, a_region, ty::Dyn), + ty::Dynamic(b_data, b_region, ty::Dyn), ) => ecx.consider_builtin_dyn_upcast_candidates( goal, a_data, a_region, b_data, b_region, ), // `T` -> `dyn Trait` unsizing. - (_, &ty::Dynamic(b_region, b_data, ty::Dyn)) => result_to_single( + (_, ty::Dynamic(b_region, b_data, ty::Dyn)) => result_to_single( ecx.consider_builtin_unsize_to_dyn_candidate(goal, b_region, b_data), ), // `[T; N]` -> `[T]` unsizing - (&ty::Array(a_elem_ty, ..), &ty::Slice(b_elem_ty)) => { + (ty::Array(a_elem_ty, ..), ty::Slice(b_elem_ty)) => { result_to_single(ecx.consider_builtin_array_unsize(goal, a_elem_ty, b_elem_ty)) } // `Struct<T>` -> `Struct<U>` where `T: Unsize<U>` - (&ty::Adt(a_def, a_args), &ty::Adt(b_def, b_args)) + (ty::Adt(a_def, a_args), ty::Adt(b_def, b_args)) if a_def.is_struct() && a_def == b_def => { result_to_single( @@ -710,7 +693,7 @@ impl<'tcx> assembly::GoalKind<'tcx> for TraitPredicate<'tcx> { } // `(A, B, T)` -> `(A, B, U)` where `T: Unsize<U>` - (&ty::Tuple(a_tys), &ty::Tuple(b_tys)) + (ty::Tuple(a_tys), ty::Tuple(b_tys)) if a_tys.len() == b_tys.len() && !a_tys.is_empty() => { result_to_single(ecx.consider_builtin_tuple_unsize(goal, a_tys, b_tys)) @@ -722,7 +705,11 @@ impl<'tcx> assembly::GoalKind<'tcx> for TraitPredicate<'tcx> { } } -impl<'tcx> EvalCtxt<'_, InferCtxt<'tcx>> { +impl<Infcx, I> EvalCtxt<'_, Infcx> +where + Infcx: SolverDelegate<Interner = I>, + I: Interner, +{ /// Trait upcasting allows for coercions between trait objects: /// ```ignore (builtin impl example) /// trait Super {} @@ -734,12 +721,12 @@ impl<'tcx> EvalCtxt<'_, InferCtxt<'tcx>> { /// ``` fn consider_builtin_dyn_upcast_candidates( &mut self, - goal: Goal<'tcx, (Ty<'tcx>, Ty<'tcx>)>, - a_data: &'tcx ty::List<ty::PolyExistentialPredicate<'tcx>>, - a_region: ty::Region<'tcx>, - b_data: &'tcx ty::List<ty::PolyExistentialPredicate<'tcx>>, - b_region: ty::Region<'tcx>, - ) -> Vec<Candidate<TyCtxt<'tcx>>> { + goal: Goal<I, (I::Ty, I::Ty)>, + a_data: I::BoundExistentialPredicates, + a_region: I::Region, + b_data: I::BoundExistentialPredicates, + b_region: I::Region, + ) -> Vec<Candidate<I>> { let tcx = self.interner(); let Goal { predicate: (a_ty, _b_ty), .. } = goal; @@ -757,7 +744,10 @@ impl<'tcx> EvalCtxt<'_, InferCtxt<'tcx>> { a_data.principal(), )); } else if let Some(a_principal) = a_data.principal() { - for new_a_principal in supertraits(tcx, a_principal.with_self_ty(tcx, a_ty)).skip(1) { + for new_a_principal in + Infcx::elaborate_supertraits(self.interner(), a_principal.with_self_ty(tcx, a_ty)) + .skip(1) + { responses.extend(self.consider_builtin_upcast_to_principal( goal, CandidateSource::BuiltinImpl(BuiltinImplSource::TraitUpcasting), @@ -777,15 +767,15 @@ impl<'tcx> EvalCtxt<'_, InferCtxt<'tcx>> { fn consider_builtin_unsize_to_dyn_candidate( &mut self, - goal: Goal<'tcx, (Ty<'tcx>, Ty<'tcx>)>, - b_data: &'tcx ty::List<ty::PolyExistentialPredicate<'tcx>>, - b_region: ty::Region<'tcx>, - ) -> Result<Candidate<TyCtxt<'tcx>>, NoSolution> { + goal: Goal<I, (I::Ty, I::Ty)>, + b_data: I::BoundExistentialPredicates, + b_region: I::Region, + ) -> Result<Candidate<I>, NoSolution> { let tcx = self.interner(); let Goal { predicate: (a_ty, _), .. } = goal; // Can only unsize to an object-safe trait. - if b_data.principal_def_id().is_some_and(|def_id| !tcx.is_object_safe(def_id)) { + if b_data.principal_def_id().is_some_and(|def_id| !tcx.trait_is_object_safe(def_id)) { return Err(NoSolution); } @@ -794,7 +784,7 @@ impl<'tcx> EvalCtxt<'_, InferCtxt<'tcx>> { // (i.e. the principal, all of the associated types match, and any auto traits) ecx.add_goals( GoalSource::ImplWhereBound, - b_data.iter().map(|pred| goal.with(tcx, pred.with_self_ty(tcx, a_ty))), + b_data.into_iter().map(|pred| goal.with(tcx, pred.with_self_ty(tcx, a_ty))), ); // The type must be `Sized` to be unsized. @@ -802,7 +792,11 @@ impl<'tcx> EvalCtxt<'_, InferCtxt<'tcx>> { GoalSource::ImplWhereBound, goal.with( tcx, - ty::TraitRef::new(tcx, tcx.require_lang_item(LangItem::Sized, None), [a_ty]), + ty::TraitRef::new( + tcx, + tcx.require_lang_item(TraitSolverLangItem::Sized), + [a_ty], + ), ), ); @@ -814,24 +808,26 @@ impl<'tcx> EvalCtxt<'_, InferCtxt<'tcx>> { fn consider_builtin_upcast_to_principal( &mut self, - goal: Goal<'tcx, (Ty<'tcx>, Ty<'tcx>)>, - source: CandidateSource<'tcx>, - a_data: &'tcx ty::List<ty::PolyExistentialPredicate<'tcx>>, - a_region: ty::Region<'tcx>, - b_data: &'tcx ty::List<ty::PolyExistentialPredicate<'tcx>>, - b_region: ty::Region<'tcx>, - upcast_principal: Option<ty::PolyExistentialTraitRef<'tcx>>, - ) -> Result<Candidate<TyCtxt<'tcx>>, NoSolution> { + goal: Goal<I, (I::Ty, I::Ty)>, + source: CandidateSource<I>, + a_data: I::BoundExistentialPredicates, + a_region: I::Region, + b_data: I::BoundExistentialPredicates, + b_region: I::Region, + upcast_principal: Option<ty::Binder<I, ty::ExistentialTraitRef<I>>>, + ) -> Result<Candidate<I>, NoSolution> { let param_env = goal.param_env; // We may upcast to auto traits that are either explicitly listed in // the object type's bounds, or implied by the principal trait ref's // supertraits. - let a_auto_traits: FxIndexSet<DefId> = a_data + let a_auto_traits: FxIndexSet<I::DefId> = a_data .auto_traits() + .into_iter() .chain(a_data.principal_def_id().into_iter().flat_map(|principal_def_id| { self.interner() .supertrait_def_ids(principal_def_id) + .into_iter() .filter(|def_id| self.interner().trait_is_auto(*def_id)) })) .collect(); @@ -841,9 +837,9 @@ impl<'tcx> EvalCtxt<'_, InferCtxt<'tcx>> { // having any inference side-effects. We process obligations because // unification may initially succeed due to deferred projection equality. let projection_may_match = - |ecx: &mut EvalCtxt<'_, InferCtxt<'tcx>>, - source_projection: ty::PolyExistentialProjection<'tcx>, - target_projection: ty::PolyExistentialProjection<'tcx>| { + |ecx: &mut EvalCtxt<'_, Infcx>, + source_projection: ty::Binder<I, ty::ExistentialProjection<I>>, + target_projection: ty::Binder<I, ty::ExistentialProjection<I>>| { source_projection.item_def_id() == target_projection.item_def_id() && ecx .probe(|_| ProbeKind::UpcastProjectionCompatibility) @@ -875,7 +871,7 @@ impl<'tcx> EvalCtxt<'_, InferCtxt<'tcx>> { ty::ExistentialPredicate::Projection(target_projection) => { let target_projection = bound.rebind(target_projection); let mut matching_projections = - a_data.projection_bounds().filter(|source_projection| { + a_data.projection_bounds().into_iter().filter(|source_projection| { projection_may_match(ecx, *source_projection, target_projection) }); let Some(source_projection) = matching_projections.next() else { @@ -900,11 +896,7 @@ impl<'tcx> EvalCtxt<'_, InferCtxt<'tcx>> { // Also require that a_ty's lifetime outlives b_ty's lifetime. ecx.add_goal( GoalSource::ImplWhereBound, - Goal::new( - ecx.interner(), - param_env, - ty::Binder::dummy(ty::OutlivesPredicate(a_region, b_region)), - ), + Goal::new(ecx.interner(), param_env, ty::OutlivesPredicate(a_region, b_region)), ); ecx.evaluate_added_goals_and_make_canonical_response(Certainty::Yes) @@ -921,10 +913,10 @@ impl<'tcx> EvalCtxt<'_, InferCtxt<'tcx>> { /// `#[rustc_deny_explicit_impl]` in this case. fn consider_builtin_array_unsize( &mut self, - goal: Goal<'tcx, (Ty<'tcx>, Ty<'tcx>)>, - a_elem_ty: Ty<'tcx>, - b_elem_ty: Ty<'tcx>, - ) -> Result<Candidate<TyCtxt<'tcx>>, NoSolution> { + goal: Goal<I, (I::Ty, I::Ty)>, + a_elem_ty: I::Ty, + b_elem_ty: I::Ty, + ) -> Result<Candidate<I>, 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)) @@ -945,26 +937,25 @@ impl<'tcx> EvalCtxt<'_, InferCtxt<'tcx>> { /// ``` fn consider_builtin_struct_unsize( &mut self, - goal: Goal<'tcx, (Ty<'tcx>, Ty<'tcx>)>, - def: ty::AdtDef<'tcx>, - a_args: ty::GenericArgsRef<'tcx>, - b_args: ty::GenericArgsRef<'tcx>, - ) -> Result<Candidate<TyCtxt<'tcx>>, NoSolution> { + goal: Goal<I, (I::Ty, I::Ty)>, + def: I::AdtDef, + a_args: I::GenericArgs, + b_args: I::GenericArgs, + ) -> Result<Candidate<I>, NoSolution> { let tcx = self.interner(); let Goal { predicate: (_a_ty, b_ty), .. } = goal; - let unsizing_params = tcx.unsizing_params_for_adt(def.did()); + let unsizing_params = tcx.unsizing_params_for_adt(def.def_id()); // We must be unsizing some type parameters. This also implies // that the struct has a tail field. if unsizing_params.is_empty() { return Err(NoSolution); } - let tail_field = def.non_enum_variant().tail(); - let tail_field_ty = tcx.type_of(tail_field.did); + let tail_field_ty = def.struct_tail_ty(tcx).unwrap(); - let a_tail_ty = tail_field_ty.instantiate(tcx, a_args); - let b_tail_ty = tail_field_ty.instantiate(tcx, b_args); + let a_tail_ty = tail_field_ty.instantiate(tcx, &a_args); + let b_tail_ty = tail_field_ty.instantiate(tcx, &b_args); // Instantiate just the unsizing params from B into A. The type after // this instantiation must be equal to B. This is so we don't unsize @@ -973,7 +964,7 @@ impl<'tcx> EvalCtxt<'_, InferCtxt<'tcx>> { a_args .iter() .enumerate() - .map(|(i, a)| if unsizing_params.contains(i as u32) { b_args[i] } else { a }), + .map(|(i, a)| if unsizing_params.contains(i as u32) { b_args[i] } else { *a }), ); let unsized_a_ty = Ty::new_adt(tcx, def, new_a_args); @@ -986,7 +977,7 @@ impl<'tcx> EvalCtxt<'_, InferCtxt<'tcx>> { tcx, ty::TraitRef::new( tcx, - tcx.require_lang_item(LangItem::Unsize, None), + tcx.require_lang_item(TraitSolverLangItem::Unsize), [a_tail_ty, b_tail_ty], ), ), @@ -1007,10 +998,10 @@ impl<'tcx> EvalCtxt<'_, InferCtxt<'tcx>> { /// ``` fn consider_builtin_tuple_unsize( &mut self, - goal: Goal<'tcx, (Ty<'tcx>, Ty<'tcx>)>, - a_tys: &'tcx ty::List<Ty<'tcx>>, - b_tys: &'tcx ty::List<Ty<'tcx>>, - ) -> Result<Candidate<TyCtxt<'tcx>>, NoSolution> { + goal: Goal<I, (I::Ty, I::Ty)>, + a_tys: I::Tys, + b_tys: I::Tys, + ) -> Result<Candidate<I>, NoSolution> { let tcx = self.interner(); let Goal { predicate: (_a_ty, b_ty), .. } = goal; @@ -1029,7 +1020,7 @@ impl<'tcx> EvalCtxt<'_, InferCtxt<'tcx>> { tcx, ty::TraitRef::new( tcx, - tcx.require_lang_item(LangItem::Unsize, None), + tcx.require_lang_item(TraitSolverLangItem::Unsize), [a_last_ty, b_last_ty], ), ), @@ -1044,10 +1035,10 @@ impl<'tcx> EvalCtxt<'_, InferCtxt<'tcx>> { // the type's constituent types. fn disqualify_auto_trait_candidate_due_to_possible_impl( &mut self, - goal: Goal<'tcx, TraitPredicate<'tcx>>, - ) -> Option<Result<Candidate<TyCtxt<'tcx>>, NoSolution>> { + goal: Goal<I, TraitPredicate<I>>, + ) -> Option<Result<Candidate<I>, NoSolution>> { let self_ty = goal.predicate.self_ty(); - match *self_ty.kind() { + match self_ty.kind() { // Stall int and float vars until they are resolved to a concrete // numerical type. That's because the check for impls below treats // int vars as matching any impl. Even if we filtered such impls, @@ -1065,13 +1056,15 @@ impl<'tcx> EvalCtxt<'_, InferCtxt<'tcx>> { | ty::Alias(ty::Projection | ty::Weak | ty::Inherent, ..) | ty::Placeholder(..) => Some(Err(NoSolution)), - ty::Infer(_) | ty::Bound(_, _) => bug!("unexpected type `{self_ty}`"), + ty::Infer(_) | ty::Bound(_, _) => panic!("unexpected type `{self_ty:?}`"), // Coroutines have one special built-in candidate, `Unpin`, which // takes precedence over the structural auto trait candidate being // assembled. ty::Coroutine(def_id, _) - if self.interner().is_lang_item(goal.predicate.def_id(), LangItem::Unpin) => + if self + .interner() + .is_lang_item(goal.predicate.def_id(), TraitSolverLangItem::Unpin) => { match self.interner().coroutine_movability(def_id) { Movability::Static => Some(Err(NoSolution)), @@ -1144,13 +1137,13 @@ impl<'tcx> EvalCtxt<'_, InferCtxt<'tcx>> { /// wrapped in one. fn probe_and_evaluate_goal_for_constituent_tys( &mut self, - source: CandidateSource<'tcx>, - goal: Goal<'tcx, TraitPredicate<'tcx>>, + source: CandidateSource<I>, + goal: Goal<I, TraitPredicate<I>>, constituent_tys: impl Fn( - &EvalCtxt<'_, InferCtxt<'tcx>>, - Ty<'tcx>, - ) -> Result<Vec<ty::Binder<'tcx, Ty<'tcx>>>, NoSolution>, - ) -> Result<Candidate<TyCtxt<'tcx>>, NoSolution> { + &EvalCtxt<'_, Infcx>, + I::Ty, + ) -> Result<Vec<ty::Binder<I, I::Ty>>, NoSolution>, + ) -> Result<Candidate<I>, NoSolution> { self.probe_trait_candidate(source).enter(|ecx| { ecx.add_goals( GoalSource::ImplWhereBound, @@ -1173,8 +1166,8 @@ impl<'tcx> EvalCtxt<'_, InferCtxt<'tcx>> { #[instrument(level = "trace", skip(self))] pub(super) fn compute_trait_goal( &mut self, - goal: Goal<'tcx, TraitPredicate<'tcx>>, - ) -> QueryResult<'tcx> { + goal: Goal<I, TraitPredicate<I>>, + ) -> QueryResult<I> { let candidates = self.assemble_and_evaluate_candidates(goal); self.merge_candidates(candidates) } diff --git a/compiler/rustc_parse/src/errors.rs b/compiler/rustc_parse/src/errors.rs index f0ef1112f9e..46e15734853 100644 --- a/compiler/rustc_parse/src/errors.rs +++ b/compiler/rustc_parse/src/errors.rs @@ -3,7 +3,7 @@ use std::borrow::Cow; use rustc_ast::token::Token; use rustc_ast::{Path, Visibility}; use rustc_errors::{ - codes::*, Applicability, Diag, DiagCtxt, Diagnostic, EmissionGuarantee, Level, + codes::*, Applicability, Diag, DiagCtxtHandle, Diagnostic, EmissionGuarantee, Level, SubdiagMessageOp, Subdiagnostic, }; use rustc_macros::{Diagnostic, Subdiagnostic}; @@ -1052,7 +1052,7 @@ pub(crate) struct ExpectedIdentifier { impl<'a, G: EmissionGuarantee> Diagnostic<'a, G> for ExpectedIdentifier { #[track_caller] - fn into_diag(self, dcx: &'a DiagCtxt, level: Level) -> Diag<'a, G> { + fn into_diag(self, dcx: DiagCtxtHandle<'a>, level: Level) -> Diag<'a, G> { let token_descr = TokenDescription::from_token(&self.token); let mut diag = Diag::new( @@ -1112,7 +1112,7 @@ pub(crate) struct ExpectedSemi { impl<'a, G: EmissionGuarantee> Diagnostic<'a, G> for ExpectedSemi { #[track_caller] - fn into_diag(self, dcx: &'a DiagCtxt, level: Level) -> Diag<'a, G> { + fn into_diag(self, dcx: DiagCtxtHandle<'a>, level: Level) -> Diag<'a, G> { let token_descr = TokenDescription::from_token(&self.token); let mut diag = Diag::new( @@ -2699,12 +2699,13 @@ pub(crate) struct SingleColonImportPath { #[derive(Diagnostic)] #[diag(parse_bad_item_kind)] -#[help] pub(crate) struct BadItemKind { #[primary_span] pub span: Span, pub descr: &'static str, pub ctx: &'static str, + #[help] + pub help: Option<()>, } #[derive(Diagnostic)] diff --git a/compiler/rustc_parse/src/lexer/mod.rs b/compiler/rustc_parse/src/lexer/mod.rs index 43f4963b27a..511805cf8d6 100644 --- a/compiler/rustc_parse/src/lexer/mod.rs +++ b/compiler/rustc_parse/src/lexer/mod.rs @@ -7,7 +7,7 @@ use rustc_ast::ast::{self, AttrStyle}; use rustc_ast::token::{self, CommentKind, Delimiter, IdentIsRaw, Token, TokenKind}; use rustc_ast::tokenstream::TokenStream; use rustc_ast::util::unicode::contains_text_flow_control_chars; -use rustc_errors::{codes::*, Applicability, Diag, DiagCtxt, StashKey}; +use rustc_errors::{codes::*, Applicability, Diag, DiagCtxtHandle, StashKey}; use rustc_lexer::unescape::{self, EscapeError, Mode}; use rustc_lexer::{Base, DocStyle, RawStrError}; use rustc_lexer::{Cursor, LiteralKind}; @@ -113,8 +113,8 @@ struct StringReader<'psess, 'src> { } impl<'psess, 'src> StringReader<'psess, 'src> { - fn dcx(&self) -> &'psess DiagCtxt { - &self.psess.dcx + fn dcx(&self) -> DiagCtxtHandle<'psess> { + self.psess.dcx() } fn mk_sp(&self, lo: BytePos, hi: BytePos) -> Span { @@ -248,8 +248,8 @@ impl<'psess, 'src> StringReader<'psess, 'src> { let suffix = if suffix_start < self.pos { let string = self.str_from(suffix_start); if string == "_" { - self.psess - .dcx + self + .dcx() .emit_err(errors::UnderscoreLiteralSuffix { span: self.mk_sp(suffix_start, self.pos) }); None } else { @@ -597,8 +597,7 @@ impl<'psess, 'src> StringReader<'psess, 'src> { } fn report_non_started_raw_string(&self, start: BytePos, bad_char: char) -> ! { - self.psess - .dcx + self.dcx() .struct_span_fatal( self.mk_sp(start, self.pos), format!( diff --git a/compiler/rustc_parse/src/lexer/tokentrees.rs b/compiler/rustc_parse/src/lexer/tokentrees.rs index f7645446081..8e543454691 100644 --- a/compiler/rustc_parse/src/lexer/tokentrees.rs +++ b/compiler/rustc_parse/src/lexer/tokentrees.rs @@ -71,7 +71,7 @@ impl<'psess, 'src> TokenTreesReader<'psess, 'src> { fn eof_err(&mut self) -> PErr<'psess> { let msg = "this file contains an unclosed delimiter"; - let mut err = self.string_reader.psess.dcx.struct_span_err(self.token.span, msg); + let mut err = self.string_reader.dcx().struct_span_err(self.token.span, msg); for &(_, sp) in &self.diag_info.open_braces { err.span_label(sp, "unclosed delimiter"); self.diag_info.unmatched_delims.push(UnmatchedDelim { @@ -290,7 +290,7 @@ impl<'psess, 'src> TokenTreesReader<'psess, 'src> { // An unexpected closing delimiter (i.e., there is no matching opening delimiter). let token_str = token_to_string(&self.token); let msg = format!("unexpected closing delimiter: `{token_str}`"); - let mut err = self.string_reader.psess.dcx.struct_span_err(self.token.span, msg); + let mut err = self.string_reader.dcx().struct_span_err(self.token.span, msg); report_suspicious_mismatch_block( &mut err, diff --git a/compiler/rustc_parse/src/lexer/unescape_error_reporting.rs b/compiler/rustc_parse/src/lexer/unescape_error_reporting.rs index cad25c66827..b7a790fcf83 100644 --- a/compiler/rustc_parse/src/lexer/unescape_error_reporting.rs +++ b/compiler/rustc_parse/src/lexer/unescape_error_reporting.rs @@ -3,7 +3,7 @@ use std::iter::once; use std::ops::Range; -use rustc_errors::{Applicability, DiagCtxt, ErrorGuaranteed}; +use rustc_errors::{Applicability, DiagCtxtHandle, ErrorGuaranteed}; use rustc_lexer::unescape::{EscapeError, Mode}; use rustc_span::{BytePos, Span}; use tracing::debug; @@ -11,7 +11,7 @@ use tracing::debug; use crate::errors::{MoreThanOneCharNote, MoreThanOneCharSugg, NoBraceUnicodeSub, UnescapeError}; pub(crate) fn emit_unescape_error( - dcx: &DiagCtxt, + dcx: DiagCtxtHandle<'_>, // interior part of the literal, between quotes lit: &str, // full span of the literal, including quotes and any prefix diff --git a/compiler/rustc_parse/src/lexer/unicode_chars.rs b/compiler/rustc_parse/src/lexer/unicode_chars.rs index 8eb299108d1..0a82ede3b75 100644 --- a/compiler/rustc_parse/src/lexer/unicode_chars.rs +++ b/compiler/rustc_parse/src/lexer/unicode_chars.rs @@ -351,7 +351,7 @@ pub(super) fn check_for_substitution( let Some((_, ascii_name, token)) = ASCII_ARRAY.iter().find(|&&(s, _, _)| s == ascii_str) else { let msg = format!("substitution character not found for '{ch}'"); - reader.psess.dcx.span_bug(span, msg); + reader.dcx().span_bug(span, msg); }; // special help suggestion for "directed" double quotes diff --git a/compiler/rustc_parse/src/lib.rs b/compiler/rustc_parse/src/lib.rs index 25cab7252a3..5522127be83 100644 --- a/compiler/rustc_parse/src/lib.rs +++ b/compiler/rustc_parse/src/lib.rs @@ -73,7 +73,7 @@ pub fn new_parser_from_file<'a>( ) -> Result<Parser<'a>, Vec<Diag<'a>>> { let source_file = psess.source_map().load_file(path).unwrap_or_else(|e| { let msg = format!("couldn't read {}: {}", path.display(), e); - let mut err = psess.dcx.struct_fatal(msg); + let mut err = psess.dcx().struct_fatal(msg); if let Some(sp) = sp { err.span(sp); } @@ -115,7 +115,7 @@ fn source_file_to_stream<'psess>( override_span: Option<Span>, ) -> Result<TokenStream, Vec<Diag<'psess>>> { let src = source_file.src.as_ref().unwrap_or_else(|| { - psess.dcx.bug(format!( + psess.dcx().bug(format!( "cannot lex `source_file` without source: {}", psess.source_map().filename_for_diagnostics(&source_file.name) )); @@ -179,7 +179,7 @@ pub fn parse_cfg_attr( } } _ => { - psess.dcx.emit_err(errors::MalformedCfgAttr { + psess.dcx().emit_err(errors::MalformedCfgAttr { span: attr.span, sugg: CFG_ATTR_GRAMMAR_HELP, }); diff --git a/compiler/rustc_parse/src/parser/attr_wrapper.rs b/compiler/rustc_parse/src/parser/attr_wrapper.rs index 042ee21e3f7..b5480b6b7d2 100644 --- a/compiler/rustc_parse/src/parser/attr_wrapper.rs +++ b/compiler/rustc_parse/src/parser/attr_wrapper.rs @@ -41,7 +41,7 @@ impl AttrWrapper { } pub(crate) fn take_for_recovery(self, psess: &ParseSess) -> AttrVec { - psess.dcx.span_delayed_bug( + psess.dcx().span_delayed_bug( self.attrs.get(0).map(|attr| attr.span).unwrap_or(DUMMY_SP), "AttrVec is taken for recovery but no error is produced", ); diff --git a/compiler/rustc_parse/src/parser/diagnostics.rs b/compiler/rustc_parse/src/parser/diagnostics.rs index 17e62a8e046..c2b91488a11 100644 --- a/compiler/rustc_parse/src/parser/diagnostics.rs +++ b/compiler/rustc_parse/src/parser/diagnostics.rs @@ -1,7 +1,6 @@ use super::pat::Expected; use super::{ - BlockMode, CommaRecoveryMode, Parser, PathStyle, Restrictions, SemiColonMode, SeqSep, - TokenExpectType, TokenType, + BlockMode, CommaRecoveryMode, Parser, PathStyle, Restrictions, SemiColonMode, SeqSep, TokenType, }; use crate::errors::{ AmbiguousPlus, AsyncMoveBlockIn2015, AttributeOnParamType, BadQPathStage2, BadTypePlus, @@ -35,7 +34,7 @@ use rustc_ast::{ use rustc_ast_pretty::pprust; use rustc_data_structures::fx::FxHashSet; use rustc_errors::{ - pluralize, Applicability, Diag, DiagCtxt, ErrorGuaranteed, FatalError, PErr, PResult, + pluralize, Applicability, Diag, DiagCtxtHandle, ErrorGuaranteed, FatalError, PErr, PResult, Subdiagnostic, }; use rustc_session::errors::ExprParenthesesNeeded; @@ -241,8 +240,8 @@ impl<'a> DerefMut for SnapshotParser<'a> { } impl<'a> Parser<'a> { - pub fn dcx(&self) -> &'a DiagCtxt { - &self.psess.dcx + pub fn dcx(&self) -> DiagCtxtHandle<'a> { + self.psess.dcx() } /// Replace `self` with `snapshot.parser`. @@ -667,7 +666,7 @@ impl<'a> Parser<'a> { { err.note("you may be trying to write a c-string literal"); err.note("c-string literals require Rust 2021 or later"); - err.subdiagnostic(self.dcx(), HelpUseLatestEdition::new()); + err.subdiagnostic(HelpUseLatestEdition::new()); } // `pub` may be used for an item or `pub(crate)` @@ -1045,9 +1044,7 @@ impl<'a> Parser<'a> { /// passes through any errors encountered. Used for error recovery. pub(super) fn eat_to_tokens(&mut self, kets: &[&TokenKind]) { if let Err(err) = - self.parse_seq_to_before_tokens(kets, SeqSep::none(), TokenExpectType::Expect, |p| { - Ok(p.parse_token_tree()) - }) + self.parse_seq_to_before_tokens(kets, &[], SeqSep::none(), |p| Ok(p.parse_token_tree())) { err.cancel(); } @@ -2360,7 +2357,7 @@ impl<'a> Parser<'a> { let mut err = self.dcx().struct_span_err(span, msg); let sp = self.psess.source_map().start_point(self.token.span); if let Some(sp) = self.psess.ambiguous_block_expr_parse.borrow().get(&sp) { - err.subdiagnostic(self.dcx(), ExprParenthesesNeeded::surrounding(*sp)); + err.subdiagnostic(ExprParenthesesNeeded::surrounding(*sp)); } err.span_label(span, "expected expression"); diff --git a/compiler/rustc_parse/src/parser/expr.rs b/compiler/rustc_parse/src/parser/expr.rs index 4094fb53659..09f706143fa 100644 --- a/compiler/rustc_parse/src/parser/expr.rs +++ b/compiler/rustc_parse/src/parser/expr.rs @@ -4,7 +4,7 @@ use super::pat::{CommaRecoveryMode, Expected, RecoverColon, RecoverComma}; use super::ty::{AllowPlus, RecoverQPath, RecoverReturnSign}; use super::{ AttrWrapper, BlockMode, ClosureSpans, ForceCollect, Parser, PathStyle, Restrictions, - SemiColonMode, SeqSep, TokenExpectType, TokenType, Trailing, TrailingToken, + SemiColonMode, SeqSep, TokenType, Trailing, TrailingToken, }; use crate::errors; @@ -1443,7 +1443,7 @@ impl<'a> Parser<'a> { // If the input is something like `if a { 1 } else { 2 } | if a { 3 } else { 4 }` // then suggest parens around the lhs. if let Some(sp) = this.psess.ambiguous_block_expr_parse.borrow().get(&lo) { - err.subdiagnostic(this.dcx(), ExprParenthesesNeeded::surrounding(*sp)); + err.subdiagnostic(ExprParenthesesNeeded::surrounding(*sp)); } err }) @@ -2439,9 +2439,9 @@ impl<'a> Parser<'a> { self.expect(&token::BinOp(token::Or))?; let args = self .parse_seq_to_before_tokens( - &[&token::BinOp(token::Or), &token::OrOr], + &[&token::BinOp(token::Or)], + &[&token::OrOr], SeqSep::trailing_allowed(token::Comma), - TokenExpectType::NoExpect, |p| p.parse_fn_block_param(), )? .0; diff --git a/compiler/rustc_parse/src/parser/generics.rs b/compiler/rustc_parse/src/parser/generics.rs index 93a15c938ec..fde16ac957d 100644 --- a/compiler/rustc_parse/src/parser/generics.rs +++ b/compiler/rustc_parse/src/parser/generics.rs @@ -62,7 +62,7 @@ impl<'a> Parser<'a> { let snapshot = self.create_snapshot_for_diagnostic(); match self.parse_ty() { Ok(p) => { - if let TyKind::ImplTrait(_, bounds, None) = &p.kind { + if let TyKind::ImplTrait(_, bounds) = &p.kind { let span = impl_span.to(self.token.span.shrink_to_lo()); let mut err = self.dcx().struct_span_err( span, diff --git a/compiler/rustc_parse/src/parser/item.rs b/compiler/rustc_parse/src/parser/item.rs index 3f5a4afdad8..2db777a9f70 100644 --- a/compiler/rustc_parse/src/parser/item.rs +++ b/compiler/rustc_parse/src/parser/item.rs @@ -633,7 +633,7 @@ impl<'a> Parser<'a> { // This notably includes paths passed through `ty` macro fragments (#46438). TyKind::Path(None, path) => path, other => { - if let TyKind::ImplTrait(_, bounds, None) = other + if let TyKind::ImplTrait(_, bounds) = other && let [bound] = bounds.as_slice() { // Suggest removing extra `impl` keyword: @@ -707,15 +707,25 @@ impl<'a> Parser<'a> { }; let (ident, item_kind) = if self.eat(&token::PathSep) { - let (suffixes, _) = self.parse_delim_comma_seq(Delimiter::Brace, |p| { - Ok((p.parse_path_segment_ident()?, rename(p)?)) - })?; + let suffixes = if self.eat(&token::BinOp(token::Star)) { + None + } else { + let parse_suffix = |p: &mut Self| Ok((p.parse_path_segment_ident()?, rename(p)?)); + Some(self.parse_delim_comma_seq(Delimiter::Brace, parse_suffix)?.0) + }; let deleg = DelegationMac { qself, prefix: path, suffixes, body: body(self)? }; (Ident::empty(), ItemKind::DelegationMac(Box::new(deleg))) } else { let rename = rename(self)?; let ident = rename.unwrap_or_else(|| path.segments.last().unwrap().ident); - let deleg = Delegation { id: DUMMY_NODE_ID, qself, path, rename, body: body(self)? }; + let deleg = Delegation { + id: DUMMY_NODE_ID, + qself, + path, + rename, + body: body(self)?, + from_glob: false, + }; (ident, ItemKind::Delegation(Box::new(deleg))) }; @@ -1237,7 +1247,11 @@ impl<'a> Parser<'a> { // FIXME(#100717): needs variant for each `ItemKind` (instead of using `ItemKind::descr()`) let span = self.psess.source_map().guess_head_span(span); let descr = kind.descr(); - self.dcx().emit_err(errors::BadItemKind { span, descr, ctx }); + let help = match kind { + ItemKind::DelegationMac(deleg) if deleg.suffixes.is_none() => None, + _ => Some(()), + }; + self.dcx().emit_err(errors::BadItemKind { span, descr, ctx, help }); None } @@ -1966,7 +1980,7 @@ impl<'a> Parser<'a> { if self.token.kind == token::Not { if let Err(mut err) = self.unexpected() { // Encounter the macro invocation - err.subdiagnostic(self.dcx(), MacroExpandsToAdtField { adt_ty }); + err.subdiagnostic(MacroExpandsToAdtField { adt_ty }); return Err(err); } } @@ -2382,13 +2396,10 @@ impl<'a> Parser<'a> { .into_iter() .any(|s| self.prev_token.is_ident_named(s)); - err.subdiagnostic( - self.dcx(), - errors::FnTraitMissingParen { - span: self.prev_token.span, - machine_applicable, - }, - ); + err.subdiagnostic(errors::FnTraitMissingParen { + span: self.prev_token.span, + machine_applicable, + }); } return Err(err); } diff --git a/compiler/rustc_parse/src/parser/mod.rs b/compiler/rustc_parse/src/parser/mod.rs index f4cab480669..2f12459da57 100644 --- a/compiler/rustc_parse/src/parser/mod.rs +++ b/compiler/rustc_parse/src/parser/mod.rs @@ -335,18 +335,6 @@ impl TokenType { } } -/// Used by [`Parser::expect_any_with_type`]. -#[derive(Copy, Clone, Debug)] -enum TokenExpectType { - /// Unencountered tokens are inserted into [`Parser::expected_tokens`]. - /// See [`Parser::check`]. - Expect, - - /// Unencountered tokens are not inserted into [`Parser::expected_tokens`]. - /// See [`Parser::check_noexpect`]. - NoExpect, -} - /// A sequence separator. #[derive(Debug)] struct SeqSep { @@ -807,11 +795,13 @@ impl<'a> Parser<'a> { } /// Checks if the next token is contained within `kets`, and returns `true` if so. - fn expect_any_with_type(&mut self, kets: &[&TokenKind], expect: TokenExpectType) -> bool { - kets.iter().any(|k| match expect { - TokenExpectType::Expect => self.check(k), - TokenExpectType::NoExpect => self.check_noexpect(k), - }) + fn expect_any_with_type( + &mut self, + kets_expected: &[&TokenKind], + kets_not_expected: &[&TokenKind], + ) -> bool { + kets_expected.iter().any(|k| self.check(k)) + || kets_not_expected.iter().any(|k| self.check_noexpect(k)) } /// Parses a sequence until the specified delimiters. The function @@ -819,9 +809,9 @@ impl<'a> Parser<'a> { /// closing bracket. fn parse_seq_to_before_tokens<T>( &mut self, - kets: &[&TokenKind], + kets_expected: &[&TokenKind], + kets_not_expected: &[&TokenKind], sep: SeqSep, - expect: TokenExpectType, mut f: impl FnMut(&mut Parser<'a>) -> PResult<'a, T>, ) -> PResult<'a, (ThinVec<T>, Trailing, Recovered)> { let mut first = true; @@ -829,7 +819,7 @@ impl<'a> Parser<'a> { let mut trailing = Trailing::No; let mut v = ThinVec::new(); - while !self.expect_any_with_type(kets, expect) { + while !self.expect_any_with_type(kets_expected, kets_not_expected) { if let token::CloseDelim(..) | token::Eof = self.token.kind { break; } @@ -927,7 +917,8 @@ impl<'a> Parser<'a> { if self.token == token::Colon { // we will try to recover in `maybe_recover_struct_lit_bad_delims` return Err(expect_err); - } else if let [token::CloseDelim(Delimiter::Parenthesis)] = kets + } else if let [token::CloseDelim(Delimiter::Parenthesis)] = + kets_expected { return Err(expect_err); } else { @@ -940,7 +931,9 @@ impl<'a> Parser<'a> { } } } - if sep.trailing_sep_allowed && self.expect_any_with_type(kets, expect) { + if sep.trailing_sep_allowed + && self.expect_any_with_type(kets_expected, kets_not_expected) + { trailing = Trailing::Yes; break; } @@ -1020,7 +1013,7 @@ impl<'a> Parser<'a> { sep: SeqSep, f: impl FnMut(&mut Parser<'a>) -> PResult<'a, T>, ) -> PResult<'a, (ThinVec<T>, Trailing, Recovered)> { - self.parse_seq_to_before_tokens(&[ket], sep, TokenExpectType::Expect, f) + self.parse_seq_to_before_tokens(&[ket], &[], sep, f) } /// Parses a sequence, including only the closing delimiter. The function @@ -1592,7 +1585,7 @@ pub(crate) fn make_unclosed_delims_error( if let Some(sp) = unmatched.unclosed_span { spans.push(sp); }; - let err = psess.dcx.create_err(MismatchedClosingDelimiter { + let err = psess.dcx().create_err(MismatchedClosingDelimiter { spans, delimiter: pprust::token_kind_to_string(&token::CloseDelim(found_delim)).to_string(), unmatched: unmatched.found_span, diff --git a/compiler/rustc_parse/src/parser/pat.rs b/compiler/rustc_parse/src/parser/pat.rs index 921e71a1f96..03aea0888d9 100644 --- a/compiler/rustc_parse/src/parser/pat.rs +++ b/compiler/rustc_parse/src/parser/pat.rs @@ -850,7 +850,7 @@ impl<'a> Parser<'a> { let sp = self.psess.source_map().start_point(self.token.span); if let Some(sp) = self.psess.ambiguous_block_expr_parse.borrow().get(&sp) { - err.subdiagnostic(self.dcx(), ExprParenthesesNeeded::surrounding(*sp)); + err.subdiagnostic(ExprParenthesesNeeded::surrounding(*sp)); } Err(err) diff --git a/compiler/rustc_parse/src/parser/tests.rs b/compiler/rustc_parse/src/parser/tests.rs index 79a6cf1b541..3a4690670af 100644 --- a/compiler/rustc_parse/src/parser/tests.rs +++ b/compiler/rustc_parse/src/parser/tests.rs @@ -61,7 +61,7 @@ where { let mut p = string_to_parser(&psess, s); let x = f(&mut p).unwrap(); - p.psess.dcx.abort_if_errors(); + p.dcx().abort_if_errors(); x } @@ -193,7 +193,7 @@ impl<T: Write> Write for Shared<T> { #[allow(rustc::untranslatable_diagnostic)] // no translation needed for tests fn test_harness(file_text: &str, span_labels: Vec<SpanLabel>, expected_output: &str) { create_default_session_globals_then(|| { - let (handler, source_map, output) = create_test_handler(); + let (dcx, source_map, output) = create_test_handler(); source_map.new_source_file(Path::new("test.rs").to_owned().into(), file_text.to_owned()); let primary_span = make_span(&file_text, &span_labels[0].start, &span_labels[0].end); @@ -205,7 +205,7 @@ fn test_harness(file_text: &str, span_labels: Vec<SpanLabel>, expected_output: & println!("text: {:?}", source_map.span_to_snippet(span)); } - handler.span_err(msp, "foo"); + dcx.handle().span_err(msp, "foo"); assert!( expected_output.chars().next() == Some('\n'), diff --git a/compiler/rustc_parse/src/parser/ty.rs b/compiler/rustc_parse/src/parser/ty.rs index 5bed0317e5e..fcd623b477f 100644 --- a/compiler/rustc_parse/src/parser/ty.rs +++ b/compiler/rustc_parse/src/parser/ty.rs @@ -9,7 +9,7 @@ use crate::errors::{ use crate::{maybe_recover_from_interpolated_ty_qpath, maybe_whole}; use rustc_ast::ptr::P; -use rustc_ast::token::{self, Delimiter, Token, TokenKind}; +use rustc_ast::token::{self, BinOpToken, Delimiter, Token, TokenKind}; use rustc_ast::util::case::Case; use rustc_ast::{ self as ast, BareFnTy, BoundAsyncness, BoundConstness, BoundPolarity, FnRetTy, GenericBound, @@ -316,7 +316,7 @@ impl<'a> Parser<'a> { TyKind::TraitObject(bounds, TraitObjectSyntax::Dyn) } (TyKind::TraitObject(bounds, _), kw::Impl) => { - TyKind::ImplTrait(ast::DUMMY_NODE_ID, bounds, None) + TyKind::ImplTrait(ast::DUMMY_NODE_ID, bounds) } _ => return Err(err), }; @@ -670,33 +670,26 @@ impl<'a> Parser<'a> { }) } - // parse precise captures, if any. This is `use<'lt, 'lt, P, P>`; a list of - // lifetimes and ident params (including SelfUpper). These are validated later - // for order, duplication, and whether they actually reference params. - let precise_capturing = if self.eat_keyword(kw::Use) { - let use_span = self.prev_token.span; - self.psess.gated_spans.gate(sym::precise_capturing, use_span); - let (args, args_span) = self.parse_precise_capturing_args()?; - Some(P((args, use_span.to(args_span)))) - } else { - None - }; - // Always parse bounds greedily for better error recovery. let bounds = self.parse_generic_bounds()?; *impl_dyn_multi = bounds.len() > 1 || self.prev_token.kind == TokenKind::BinOp(token::Plus); - Ok(TyKind::ImplTrait(ast::DUMMY_NODE_ID, bounds, precise_capturing)) + Ok(TyKind::ImplTrait(ast::DUMMY_NODE_ID, bounds)) } fn parse_precise_capturing_args( &mut self, ) -> PResult<'a, (ThinVec<PreciseCapturingArg>, Span)> { let lo = self.token.span; - let (args, _) = self.parse_unspanned_seq( - &TokenKind::Lt, - &TokenKind::Gt, + self.expect_lt()?; + let (args, _, _) = self.parse_seq_to_before_tokens( + &[&TokenKind::Gt], + &[ + &TokenKind::Ge, + &TokenKind::BinOp(BinOpToken::Shr), + &TokenKind::BinOpEq(BinOpToken::Shr), + ], SeqSep::trailing_allowed(token::Comma), |self_| { if self_.check_keyword(kw::SelfUpper) { @@ -717,6 +710,7 @@ impl<'a> Parser<'a> { } }, )?; + self.expect_gt()?; Ok((args, lo.to(self.prev_token.span))) } @@ -828,6 +822,7 @@ impl<'a> Parser<'a> { || self.check(&token::OpenDelim(Delimiter::Parenthesis)) || self.check_keyword(kw::Const) || self.check_keyword(kw::Async) + || self.check_keyword(kw::Use) } /// Parses a bound according to the grammar: @@ -844,6 +839,14 @@ impl<'a> Parser<'a> { let bound = if self.token.is_lifetime() { self.error_lt_bound_with_modifiers(modifiers); self.parse_generic_lt_bound(lo, inner_lo, has_parens)? + } else if self.eat_keyword(kw::Use) { + // parse precise captures, if any. This is `use<'lt, 'lt, P, P>`; a list of + // lifetimes and ident params (including SelfUpper). These are validated later + // for order, duplication, and whether they actually reference params. + let use_span = self.prev_token.span; + self.psess.gated_spans.gate(sym::precise_capturing, use_span); + let (args, args_span) = self.parse_precise_capturing_args()?; + GenericBound::Use(args, use_span.to(args_span)) } else { self.parse_generic_ty_bound(lo, has_parens, modifiers, &leading_token)? }; @@ -1003,7 +1006,7 @@ impl<'a> Parser<'a> { Applicability::MaybeIncorrect, ) } - TyKind::ImplTrait(_, bounds, None) + TyKind::ImplTrait(_, bounds) if let [GenericBound::Trait(tr, ..), ..] = bounds.as_slice() => { ( diff --git a/compiler/rustc_parse/src/validate_attr.rs b/compiler/rustc_parse/src/validate_attr.rs index 19d6f512572..4ca52146039 100644 --- a/compiler/rustc_parse/src/validate_attr.rs +++ b/compiler/rustc_parse/src/validate_attr.rs @@ -65,7 +65,7 @@ pub fn parse_meta<'a>(psess: &'a ParseSess, attr: &Attribute) -> PResult<'a, Met let res = match res { Ok(lit) => { if token_lit.suffix.is_some() { - let mut err = psess.dcx.struct_span_err( + let mut err = psess.dcx().struct_span_err( expr.span, "suffixed literals are not allowed in attributes", ); @@ -98,7 +98,7 @@ pub fn parse_meta<'a>(psess: &'a ParseSess, attr: &Attribute) -> PResult<'a, Met // the error because an earlier error will have already // been reported. let msg = "attribute value must be a literal"; - let mut err = psess.dcx.struct_span_err(expr.span, msg); + let mut err = psess.dcx().struct_span_err(expr.span, msg); if let ast::ExprKind::Err(_) = expr.kind { err.downgrade_to_delayed_bug(); } @@ -114,7 +114,7 @@ fn check_meta_bad_delim(psess: &ParseSess, span: DelimSpan, delim: Delimiter) { if let Delimiter::Parenthesis = delim { return; } - psess.dcx.emit_err(errors::MetaBadDelim { + psess.dcx().emit_err(errors::MetaBadDelim { span: span.entire(), sugg: errors::MetaBadDelimSugg { open: span.open, close: span.close }, }); @@ -124,7 +124,7 @@ pub(super) fn check_cfg_attr_bad_delim(psess: &ParseSess, span: DelimSpan, delim if let Delimiter::Parenthesis = delim { return; } - psess.dcx.emit_err(errors::CfgAttrBadDelim { + psess.dcx().emit_err(errors::CfgAttrBadDelim { span: span.entire(), sugg: errors::MetaBadDelimSugg { open: span.open, close: span.close }, }); @@ -191,7 +191,7 @@ fn emit_malformed_attribute( } else { suggestions.sort(); psess - .dcx + .dcx() .struct_span_err(span, error_msg) .with_span_suggestions( span, diff --git a/compiler/rustc_passes/messages.ftl b/compiler/rustc_passes/messages.ftl index 07c82065a80..84dbd192723 100644 --- a/compiler/rustc_passes/messages.ftl +++ b/compiler/rustc_passes/messages.ftl @@ -595,6 +595,15 @@ passes_pass_by_value = passes_proc_macro_bad_sig = {$kind} has incorrect signature +passes_remove_fields = + consider removing { $num -> + [one] this + *[other] these + } { $num -> + [one] field + *[other] fields + } + passes_repr_conflicting = conflicting representation hints diff --git a/compiler/rustc_passes/src/check_attr.rs b/compiler/rustc_passes/src/check_attr.rs index 6ce7c41acc8..a0b3470df6d 100644 --- a/compiler/rustc_passes/src/check_attr.rs +++ b/compiler/rustc_passes/src/check_attr.rs @@ -8,8 +8,8 @@ use crate::{errors, fluent_generated as fluent}; use rustc_ast::{ast, AttrKind, AttrStyle, Attribute, LitKind}; use rustc_ast::{MetaItemKind, MetaItemLit, NestedMetaItem}; use rustc_data_structures::fx::FxHashMap; -use rustc_errors::StashKey; -use rustc_errors::{Applicability, DiagCtxt, IntoDiagArg, MultiSpan}; +use rustc_errors::{Applicability, IntoDiagArg, MultiSpan}; +use rustc_errors::{DiagCtxtHandle, StashKey}; use rustc_feature::{ is_unsafe_attr, AttributeDuplicates, AttributeType, BuiltinAttribute, BUILTIN_ATTRIBUTE_MAP, }; @@ -99,7 +99,7 @@ struct CheckAttrVisitor<'tcx> { } impl<'tcx> CheckAttrVisitor<'tcx> { - fn dcx(&self) -> &'tcx DiagCtxt { + fn dcx(&self) -> DiagCtxtHandle<'tcx> { self.tcx.dcx() } diff --git a/compiler/rustc_passes/src/dead.rs b/compiler/rustc_passes/src/dead.rs index 6a74ddc5508..69386c0fbdb 100644 --- a/compiler/rustc_passes/src/dead.rs +++ b/compiler/rustc_passes/src/dead.rs @@ -24,8 +24,7 @@ use rustc_target::abi::FieldIdx; use std::mem; use crate::errors::{ - ChangeFieldsToBeOfUnitType, IgnoredDerivedImpls, MultipleDeadCodes, ParentInfo, - UselessAssignment, + ChangeFields, IgnoredDerivedImpls, MultipleDeadCodes, ParentInfo, UselessAssignment, }; // Any local node that may call something in its body block should be @@ -1071,17 +1070,50 @@ impl<'tcx> DeadVisitor<'tcx> { }; let diag = match report_on { - ReportOn::TupleField => MultipleDeadCodes::UnusedTupleStructFields { - multiple, - num, - descr, - participle, - name_list, - change_fields_suggestion: ChangeFieldsToBeOfUnitType { num, spans: spans.clone() }, - parent_info, - ignored_derived_impls, - }, - + ReportOn::TupleField => { + let tuple_fields = if let Some(parent_id) = parent_item + && let node = tcx.hir_node_by_def_id(parent_id) + && let hir::Node::Item(hir::Item { + kind: hir::ItemKind::Struct(hir::VariantData::Tuple(fields, _, _), _), + .. + }) = node + { + *fields + } else { + &[] + }; + + let trailing_tuple_fields = if tuple_fields.len() >= dead_codes.len() { + LocalDefIdSet::from_iter( + tuple_fields + .iter() + .skip(tuple_fields.len() - dead_codes.len()) + .map(|f| f.def_id), + ) + } else { + LocalDefIdSet::default() + }; + + let fields_suggestion = + // Suggest removal if all tuple fields are at the end. + // Otherwise suggest removal or changing to unit type + if dead_codes.iter().all(|dc| trailing_tuple_fields.contains(&dc.def_id)) { + ChangeFields::Remove { num } + } else { + ChangeFields::ChangeToUnitTypeOrRemove { num, spans: spans.clone() } + }; + + MultipleDeadCodes::UnusedTupleStructFields { + multiple, + num, + descr, + participle, + name_list, + change_fields_suggestion: fields_suggestion, + parent_info, + ignored_derived_impls, + } + } ReportOn::NamedField => MultipleDeadCodes::DeadCodes { multiple, num, diff --git a/compiler/rustc_passes/src/errors.rs b/compiler/rustc_passes/src/errors.rs index a935f1ad7d3..d27b94ebd22 100644 --- a/compiler/rustc_passes/src/errors.rs +++ b/compiler/rustc_passes/src/errors.rs @@ -6,8 +6,8 @@ use std::{ use crate::fluent_generated as fluent; use rustc_ast::{ast, Label}; use rustc_errors::{ - codes::*, Applicability, Diag, DiagCtxt, DiagSymbolList, Diagnostic, EmissionGuarantee, Level, - MultiSpan, SubdiagMessageOp, Subdiagnostic, + codes::*, Applicability, Diag, DiagCtxtHandle, DiagSymbolList, Diagnostic, EmissionGuarantee, + Level, MultiSpan, SubdiagMessageOp, Subdiagnostic, }; use rustc_hir::{self as hir, ExprKind, Target}; use rustc_macros::{Diagnostic, LintDiagnostic, Subdiagnostic}; @@ -880,7 +880,7 @@ pub struct ItemFollowingInnerAttr { impl<G: EmissionGuarantee> Diagnostic<'_, G> for InvalidAttrAtCrateLevel { #[track_caller] - fn into_diag(self, dcx: &'_ DiagCtxt, level: Level) -> Diag<'_, G> { + fn into_diag(self, dcx: DiagCtxtHandle<'_>, level: Level) -> Diag<'_, G> { let mut diag = Diag::new(dcx, level, fluent::passes_invalid_attr_at_crate_level); diag.span(self.span); diag.arg("name", self.name); @@ -1030,7 +1030,7 @@ pub struct BreakNonLoop<'a> { impl<'a, G: EmissionGuarantee> Diagnostic<'_, G> for BreakNonLoop<'a> { #[track_caller] - fn into_diag(self, dcx: &DiagCtxt, level: Level) -> Diag<'_, G> { + fn into_diag(self, dcx: DiagCtxtHandle<'_>, level: Level) -> Diag<'_, G> { let mut diag = Diag::new(dcx, level, fluent::passes_break_non_loop); diag.span(self.span); diag.code(E0571); @@ -1176,7 +1176,7 @@ pub struct NakedFunctionsAsmBlock { impl<G: EmissionGuarantee> Diagnostic<'_, G> for NakedFunctionsAsmBlock { #[track_caller] - fn into_diag(self, dcx: &DiagCtxt, level: Level) -> Diag<'_, G> { + fn into_diag(self, dcx: DiagCtxtHandle<'_>, level: Level) -> Diag<'_, G> { let mut diag = Diag::new(dcx, level, fluent::passes_naked_functions_asm_block); diag.span(self.span); diag.code(E0787); @@ -1264,7 +1264,7 @@ pub struct NoMainErr { impl<'a, G: EmissionGuarantee> Diagnostic<'a, G> for NoMainErr { #[track_caller] - fn into_diag(self, dcx: &'a DiagCtxt, level: Level) -> Diag<'a, G> { + fn into_diag(self, dcx: DiagCtxtHandle<'a>, level: Level) -> Diag<'a, G> { let mut diag = Diag::new(dcx, level, fluent::passes_no_main_function); diag.span(DUMMY_SP); diag.code(E0601); @@ -1322,7 +1322,7 @@ pub struct DuplicateLangItem { impl<G: EmissionGuarantee> Diagnostic<'_, G> for DuplicateLangItem { #[track_caller] - fn into_diag(self, dcx: &DiagCtxt, level: Level) -> Diag<'_, G> { + fn into_diag(self, dcx: DiagCtxtHandle<'_>, level: Level) -> Diag<'_, G> { let mut diag = Diag::new( dcx, level, @@ -1574,7 +1574,7 @@ pub enum MultipleDeadCodes<'tcx> { participle: &'tcx str, name_list: DiagSymbolList, #[subdiagnostic] - change_fields_suggestion: ChangeFieldsToBeOfUnitType, + change_fields_suggestion: ChangeFields, #[subdiagnostic] parent_info: Option<ParentInfo<'tcx>>, #[subdiagnostic] @@ -1601,11 +1601,18 @@ pub struct IgnoredDerivedImpls { } #[derive(Subdiagnostic)] -#[multipart_suggestion(passes_change_fields_to_be_of_unit_type, applicability = "has-placeholders")] -pub struct ChangeFieldsToBeOfUnitType { - pub num: usize, - #[suggestion_part(code = "()")] - pub spans: Vec<Span>, +pub enum ChangeFields { + #[multipart_suggestion( + passes_change_fields_to_be_of_unit_type, + applicability = "has-placeholders" + )] + ChangeToUnitTypeOrRemove { + num: usize, + #[suggestion_part(code = "()")] + spans: Vec<Span>, + }, + #[help(passes_remove_fields)] + Remove { num: usize }, } #[derive(Diagnostic)] diff --git a/compiler/rustc_passes/src/hir_stats.rs b/compiler/rustc_passes/src/hir_stats.rs index d49298781a2..0ba61f8e8b4 100644 --- a/compiler/rustc_passes/src/hir_stats.rs +++ b/compiler/rustc_passes/src/hir_stats.rs @@ -429,7 +429,7 @@ impl<'v> hir_visit::Visitor<'v> for StatCollector<'v> { fn visit_param_bound(&mut self, b: &'v hir::GenericBound<'v>) { record_variants!( (self, b, b, Id::None, hir, GenericBound, GenericBound), - [Trait, Outlives] + [Trait, Outlives, Use] ); hir_visit::walk_param_bound(self, b) } @@ -659,7 +659,7 @@ impl<'v> ast_visit::Visitor<'v> for StatCollector<'v> { fn visit_param_bound(&mut self, b: &'v ast::GenericBound, _ctxt: BoundKind) { record_variants!( (self, b, b, Id::None, ast, GenericBound, GenericBound), - [Trait, Outlives] + [Trait, Outlives, Use] ); ast_visit::walk_param_bound(self, b) } diff --git a/compiler/rustc_privacy/src/lib.rs b/compiler/rustc_privacy/src/lib.rs index fb57d42f6df..d3705626938 100644 --- a/compiler/rustc_privacy/src/lib.rs +++ b/compiler/rustc_privacy/src/lib.rs @@ -973,8 +973,12 @@ impl<'tcx> NamePrivacyVisitor<'tcx> { impl<'tcx> Visitor<'tcx> for NamePrivacyVisitor<'tcx> { fn visit_nested_body(&mut self, body_id: hir::BodyId) { - let old_maybe_typeck_results = - self.maybe_typeck_results.replace(self.tcx.typeck_body(body_id)); + let new_typeck_results = self.tcx.typeck_body(body_id); + // Do not try reporting privacy violations if we failed to infer types. + if new_typeck_results.tainted_by_errors.is_some() { + return; + } + let old_maybe_typeck_results = self.maybe_typeck_results.replace(new_typeck_results); self.visit_body(self.tcx.hir().body(body_id)); self.maybe_typeck_results = old_maybe_typeck_results; } diff --git a/compiler/rustc_query_system/src/query/job.rs b/compiler/rustc_query_system/src/query/job.rs index 248a741af90..3f44b11850e 100644 --- a/compiler/rustc_query_system/src/query/job.rs +++ b/compiler/rustc_query_system/src/query/job.rs @@ -4,7 +4,7 @@ use crate::query::plumbing::CycleError; use crate::query::DepKind; use crate::query::{QueryContext, QueryStackFrame}; use rustc_data_structures::fx::FxHashMap; -use rustc_errors::{Diag, DiagCtxt}; +use rustc_errors::{Diag, DiagCtxtHandle}; use rustc_hir::def::DefKind; use rustc_session::Session; use rustc_span::Span; @@ -600,7 +600,7 @@ pub fn report_cycle<'a>( pub fn print_query_stack<Qcx: QueryContext>( qcx: Qcx, mut current_query: Option<QueryJobId>, - dcx: &DiagCtxt, + dcx: DiagCtxtHandle<'_>, num_frames: Option<usize>, mut file: Option<std::fs::File>, ) -> usize { diff --git a/compiler/rustc_resolve/src/build_reduced_graph.rs b/compiler/rustc_resolve/src/build_reduced_graph.rs index 689109b2840..e035749fc39 100644 --- a/compiler/rustc_resolve/src/build_reduced_graph.rs +++ b/compiler/rustc_resolve/src/build_reduced_graph.rs @@ -19,6 +19,7 @@ use rustc_ast::{self as ast, AssocItem, AssocItemKind, MetaItemKind, StmtKind}; use rustc_ast::{Block, ForeignItem, ForeignItemKind, Impl, Item, ItemKind, NodeId}; use rustc_attr as attr; use rustc_data_structures::sync::Lrc; +use rustc_expand::base::ResolverExpand; use rustc_expand::expand::AstFragment; use rustc_hir::def::{self, *}; use rustc_hir::def_id::{DefId, LocalDefId, CRATE_DEF_ID}; @@ -1358,6 +1359,14 @@ impl<'a, 'b, 'tcx> Visitor<'b> for BuildReducedGraphVisitor<'a, 'b, 'tcx> { self.visit_invoc_in_module(item.id); } AssocCtxt::Impl => { + let invoc_id = item.id.placeholder_to_expn_id(); + if !self.r.glob_delegation_invoc_ids.contains(&invoc_id) { + self.r + .impl_unexpanded_invocations + .entry(self.r.invocation_parent(invoc_id)) + .or_default() + .insert(invoc_id); + } self.visit_invoc(item.id); } } @@ -1379,18 +1388,21 @@ impl<'a, 'b, 'tcx> Visitor<'b> for BuildReducedGraphVisitor<'a, 'b, 'tcx> { self.r.feed_visibility(feed, vis); } + let ns = match item.kind { + AssocItemKind::Const(..) | AssocItemKind::Delegation(..) | AssocItemKind::Fn(..) => { + ValueNS + } + AssocItemKind::Type(..) => TypeNS, + AssocItemKind::MacCall(_) | AssocItemKind::DelegationMac(..) => bug!(), // handled above + }; if ctxt == AssocCtxt::Trait { - let ns = match item.kind { - AssocItemKind::Const(..) - | AssocItemKind::Delegation(..) - | AssocItemKind::Fn(..) => ValueNS, - AssocItemKind::Type(..) => TypeNS, - AssocItemKind::MacCall(_) | AssocItemKind::DelegationMac(..) => bug!(), // handled above - }; - let parent = self.parent_scope.module; let expansion = self.parent_scope.expansion; self.r.define(parent, item.ident, ns, (self.res(def_id), vis, item.span, expansion)); + } else if !matches!(&item.kind, AssocItemKind::Delegation(deleg) if deleg.from_glob) { + let impl_def_id = self.r.tcx.local_parent(local_def_id); + let key = BindingKey::new(item.ident.normalize_to_macros_2_0(), ns); + self.r.impl_binding_keys.entry(impl_def_id).or_default().insert(key); } visit::walk_assoc_item(self, item, ctxt); diff --git a/compiler/rustc_resolve/src/def_collector.rs b/compiler/rustc_resolve/src/def_collector.rs index ca97d10617b..fb6e55f2b7b 100644 --- a/compiler/rustc_resolve/src/def_collector.rs +++ b/compiler/rustc_resolve/src/def_collector.rs @@ -144,8 +144,9 @@ impl<'a, 'b, 'tcx> visit::Visitor<'a> for DefCollector<'a, 'b, 'tcx> { } ItemKind::GlobalAsm(..) => DefKind::GlobalAsm, ItemKind::Use(..) => return visit::walk_item(self, i), - ItemKind::MacCall(..) => return self.visit_macro_invoc(i.id), - ItemKind::DelegationMac(..) => unreachable!(), + ItemKind::MacCall(..) | ItemKind::DelegationMac(..) => { + return self.visit_macro_invoc(i.id); + } }; let def_id = self.create_def(i.id, i.ident.name, def_kind, i.span); @@ -294,8 +295,9 @@ impl<'a, 'b, 'tcx> visit::Visitor<'a> for DefCollector<'a, 'b, 'tcx> { AssocItemKind::Fn(..) | AssocItemKind::Delegation(..) => DefKind::AssocFn, AssocItemKind::Const(..) => DefKind::AssocConst, AssocItemKind::Type(..) => DefKind::AssocTy, - AssocItemKind::MacCall(..) => return self.visit_macro_invoc(i.id), - AssocItemKind::DelegationMac(..) => unreachable!(), + AssocItemKind::MacCall(..) | AssocItemKind::DelegationMac(..) => { + return self.visit_macro_invoc(i.id); + } }; let def = self.create_def(i.id, i.ident.name, def_kind, i.span); diff --git a/compiler/rustc_resolve/src/diagnostics.rs b/compiler/rustc_resolve/src/diagnostics.rs index 8d470c6c61e..263daa11ec3 100644 --- a/compiler/rustc_resolve/src/diagnostics.rs +++ b/compiler/rustc_resolve/src/diagnostics.rs @@ -6,7 +6,7 @@ use rustc_ast::{MetaItemKind, NestedMetaItem}; use rustc_ast_pretty::pprust; use rustc_data_structures::fx::FxHashSet; use rustc_errors::{ - codes::*, report_ambiguity_error, struct_span_code_err, Applicability, Diag, DiagCtxt, + codes::*, report_ambiguity_error, struct_span_code_err, Applicability, Diag, DiagCtxtHandle, ErrorGuaranteed, MultiSpan, SuggestionStyle, }; use rustc_feature::BUILTIN_ATTRIBUTES; @@ -120,7 +120,7 @@ fn reduce_impl_span_to_impl_keyword(sm: &SourceMap, impl_span: Span) -> Span { } impl<'a, 'tcx> Resolver<'a, 'tcx> { - pub(crate) fn dcx(&self) -> &'tcx DiagCtxt { + pub(crate) fn dcx(&self) -> DiagCtxtHandle<'tcx> { self.tcx.dcx() } @@ -334,12 +334,9 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> { Some((import, _, true)) if should_remove_import && !import.is_glob() => { // Simple case - remove the entire import. Due to the above match arm, this can // only be a single use so just remove it entirely. - err.subdiagnostic( - self.tcx.dcx(), - errors::ToolOnlyRemoveUnnecessaryImport { - span: import.use_span_with_attributes, - }, - ); + err.subdiagnostic(errors::ToolOnlyRemoveUnnecessaryImport { + span: import.use_span_with_attributes, + }); } Some((import, span, _)) => { self.add_suggestion_for_rename_of_use(&mut err, name, import, span); @@ -405,12 +402,9 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> { } if let Some(suggestion) = suggestion { - err.subdiagnostic( - self.dcx(), - ChangeImportBindingSuggestion { span: binding_span, suggestion }, - ); + err.subdiagnostic(ChangeImportBindingSuggestion { span: binding_span, suggestion }); } else { - err.subdiagnostic(self.dcx(), ChangeImportBinding { span: binding_span }); + err.subdiagnostic(ChangeImportBinding { span: binding_span }); } } @@ -458,20 +452,19 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> { // previous imports. if found_closing_brace { if let Some(span) = extend_span_to_previous_binding(self.tcx.sess, span) { - err.subdiagnostic(self.dcx(), errors::ToolOnlyRemoveUnnecessaryImport { span }); + err.subdiagnostic(errors::ToolOnlyRemoveUnnecessaryImport { span }); } else { // Remove the entire line if we cannot extend the span back, this indicates an // `issue_52891::{self}` case. - err.subdiagnostic( - self.dcx(), - errors::RemoveUnnecessaryImport { span: import.use_span_with_attributes }, - ); + err.subdiagnostic(errors::RemoveUnnecessaryImport { + span: import.use_span_with_attributes, + }); } return; } - err.subdiagnostic(self.dcx(), errors::RemoveUnnecessaryImport { span }); + err.subdiagnostic(errors::RemoveUnnecessaryImport { span }); } pub(crate) fn lint_if_path_starts_with_module( @@ -682,10 +675,10 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> { .dcx() .create_err(errors::VariableIsNotBoundInAllPatterns { multispan: msp, name }); for sp in target_sp { - err.subdiagnostic(self.dcx(), errors::PatternDoesntBindName { span: sp, name }); + err.subdiagnostic(errors::PatternDoesntBindName { span: sp, name }); } for sp in origin_sp { - err.subdiagnostic(self.dcx(), errors::VariableNotInAllPatterns { span: sp }); + err.subdiagnostic(errors::VariableNotInAllPatterns { span: sp }); } if could_be_path { let import_suggestions = self.lookup_import_candidates( @@ -1446,12 +1439,12 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> { ); if macro_kind == MacroKind::Bang && ident.name == sym::macro_rules { - err.subdiagnostic(self.dcx(), MaybeMissingMacroRulesName { span: ident.span }); + err.subdiagnostic(MaybeMissingMacroRulesName { span: ident.span }); return; } if macro_kind == MacroKind::Derive && (ident.name == sym::Send || ident.name == sym::Sync) { - err.subdiagnostic(self.dcx(), ExplicitUnsafeTraits { span: ident.span, ident }); + err.subdiagnostic(ExplicitUnsafeTraits { span: ident.span, ident }); return; } @@ -1467,14 +1460,14 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> { let scope = self.local_macro_def_scopes[&def_id]; let parent_nearest = parent_scope.module.nearest_parent_mod(); if Some(parent_nearest) == scope.opt_def_id() { - err.subdiagnostic(self.dcx(), MacroDefinedLater { span: unused_ident.span }); - err.subdiagnostic(self.dcx(), MacroSuggMovePosition { span: ident.span, ident }); + err.subdiagnostic(MacroDefinedLater { span: unused_ident.span }); + err.subdiagnostic(MacroSuggMovePosition { span: ident.span, ident }); return; } } if self.macro_names.contains(&ident.normalize_to_macros_2_0()) { - err.subdiagnostic(self.dcx(), AddedMacroUse); + err.subdiagnostic(AddedMacroUse); return; } @@ -1484,13 +1477,10 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> { let span = self.def_span(def_id); let source_map = self.tcx.sess.source_map(); let head_span = source_map.guess_head_span(span); - err.subdiagnostic( - self.dcx(), - ConsiderAddingADerive { - span: head_span.shrink_to_lo(), - suggestion: "#[derive(Default)]\n".to_string(), - }, - ); + err.subdiagnostic(ConsiderAddingADerive { + span: head_span.shrink_to_lo(), + suggestion: "#[derive(Default)]\n".to_string(), + }); } for ns in [Namespace::MacroNS, Namespace::TypeNS, Namespace::ValueNS] { if let Ok(binding) = self.early_resolve_ident_in_lexical_scope( @@ -1533,7 +1523,7 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> { imported_ident: ident, imported_ident_desc: &desc, }; - err.subdiagnostic(self.tcx.dcx(), note); + err.subdiagnostic(note); // Silence the 'unused import' warning we might get, // since this diagnostic already covers that import. self.record_use(ident, binding, Used::Other); @@ -1544,7 +1534,7 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> { imported_ident: ident, imported_ident_desc: &desc, }; - err.subdiagnostic(self.tcx.dcx(), note); + err.subdiagnostic(note); return; } } @@ -1599,7 +1589,7 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> { } }; did_label_def_span = true; - err.subdiagnostic(self.tcx.dcx(), label); + err.subdiagnostic(label); } let (span, msg, sugg) = if let SuggestionTarget::SimilarlyNamed = suggestion.target @@ -1790,7 +1780,7 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> { outer_ident_descr: this_res.descr(), outer_ident, }; - err.subdiagnostic(self.tcx.dcx(), label); + err.subdiagnostic(label); } } @@ -1805,14 +1795,14 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> { non_exhaustive = Some(attr.span); } else if let Some(span) = ctor_fields_span { let label = errors::ConstructorPrivateIfAnyFieldPrivate { span }; - err.subdiagnostic(self.tcx.dcx(), label); + err.subdiagnostic(label); if let Res::Def(_, d) = res && let Some(fields) = self.field_visibility_spans.get(&d) { let spans = fields.iter().map(|span| *span).collect(); let sugg = errors::ConsiderMakingTheFieldPublic { spans, number_of_fields: fields.len() }; - err.subdiagnostic(self.tcx.dcx(), sugg); + err.subdiagnostic(sugg); } } @@ -1921,7 +1911,7 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> { first, dots: next_binding.is_some(), }; - err.subdiagnostic(self.tcx.dcx(), note); + err.subdiagnostic(note); } // We prioritize shorter paths, non-core imports and direct imports over the alternatives. sugg_paths.sort_by_key(|(p, reexport)| (p.len(), p[0] == "core", *reexport)); @@ -1940,7 +1930,7 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> { } else { errors::ImportIdent::Directly { span: dedup_span, ident, path } }; - err.subdiagnostic(self.tcx.dcx(), sugg); + err.subdiagnostic(sugg); break; } @@ -2521,14 +2511,14 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> { } let note = errors::FoundItemConfigureOut { span: name.span }; - err.subdiagnostic(self.tcx.dcx(), note); + err.subdiagnostic(note); if let MetaItemKind::List(nested) = &cfg.kind && let NestedMetaItem::MetaItem(meta_item) = &nested[0] && let MetaItemKind::NameValue(feature_name) = &meta_item.kind { let note = errors::ItemWasBehindFeature { feature: feature_name.symbol }; - err.subdiagnostic(self.tcx.dcx(), note); + err.subdiagnostic(note); } } } diff --git a/compiler/rustc_resolve/src/ident.rs b/compiler/rustc_resolve/src/ident.rs index b6a23317dc9..7d531385e21 100644 --- a/compiler/rustc_resolve/src/ident.rs +++ b/compiler/rustc_resolve/src/ident.rs @@ -966,7 +966,7 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> { for single_import in &resolution.single_imports { let Some(import_vis) = single_import.vis.get() else { // This branch handles a cycle in single imports, which occurs - // when we've previously captured the `vis` value during an import + // when we've previously **steal** the `vis` value during an import // process. // // For example: @@ -998,21 +998,28 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> { let Some(module) = single_import.imported_module.get() else { return Err((Undetermined, Weak::No)); }; - let ImportKind::Single { source: ident, target, target_bindings, .. } = - &single_import.kind + let ImportKind::Single { source, target, target_bindings, .. } = &single_import.kind else { unreachable!(); }; - if (ident != target) && target_bindings.iter().all(|binding| binding.get().is_none()) { + if source != target { // This branch allows the binding to be defined or updated later if the target name - // can hide the source but these bindings are not obtained. - // avoiding module inconsistency between the resolve process and the finalize process. - // See more details in #124840 - return Err((Undetermined, Weak::No)); + // can hide the source. + if target_bindings.iter().all(|binding| binding.get().is_none()) { + // None of the target bindings are available, so we can't determine + // if this binding is correct or not. + // See more details in #124840 + return Err((Undetermined, Weak::No)); + } else if target_bindings[ns].get().is_none() && binding.is_some() { + // `binding.is_some()` avoids the condition where the binding + // truly doesn't exist in this namespace and should return `Err(Determined)`. + return Err((Undetermined, Weak::No)); + } } + match self.resolve_ident_in_module( module, - *ident, + *source, ns, &single_import.parent_scope, None, diff --git a/compiler/rustc_resolve/src/imports.rs b/compiler/rustc_resolve/src/imports.rs index 6c7afb305ba..96a4647b942 100644 --- a/compiler/rustc_resolve/src/imports.rs +++ b/compiler/rustc_resolve/src/imports.rs @@ -1294,12 +1294,12 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> { // exclude decl_macro if self.get_macro_by_def_id(def_id).macro_rules => { - err.subdiagnostic(self.dcx(), ConsiderAddingMacroExport { + err.subdiagnostic( ConsiderAddingMacroExport { span: binding.span, }); } _ => { - err.subdiagnostic(self.dcx(), ConsiderMarkingAsPub { + err.subdiagnostic( ConsiderMarkingAsPub { span: import.span, ident, }); diff --git a/compiler/rustc_resolve/src/late.rs b/compiler/rustc_resolve/src/late.rs index fa711d932b6..5ab6ba23a7d 100644 --- a/compiler/rustc_resolve/src/late.rs +++ b/compiler/rustc_resolve/src/late.rs @@ -310,9 +310,10 @@ enum LifetimeRibKind { /// error on default object bounds (e.g., `Box<dyn Foo>`). AnonymousReportError, - /// Resolves elided lifetimes to `'static`, but gives a warning that this behavior - /// is a bug and will be reverted soon. - AnonymousWarn(NodeId), + /// Resolves elided lifetimes to `'static` if there are no other lifetimes in scope, + /// otherwise give a warning that the previous behavior of introducing a new early-bound + /// lifetime is a bug and will be removed (if `emit_lint` is enabled). + StaticIfNoLifetimeInScope { lint_id: NodeId, emit_lint: bool }, /// Signal we cannot find which should be the anonymous lifetime. ElisionFailure, @@ -798,7 +799,7 @@ impl<'a: 'ast, 'ast, 'tcx> Visitor<'ast> for LateResolutionVisitor<'a, '_, 'ast, self.r.record_partial_res(ty.id, PartialRes::new(res)); visit::walk_ty(self, ty) } - TyKind::ImplTrait(node_id, _, _) => { + TyKind::ImplTrait(node_id, _) => { let candidates = self.lifetime_elision_candidates.take(); visit::walk_ty(self, ty); self.record_lifetime_params_for_impl_trait(*node_id); @@ -1212,7 +1213,7 @@ impl<'a: 'ast, 'ast, 'tcx> Visitor<'ast> for LateResolutionVisitor<'a, '_, 'ast, } LifetimeRibKind::AnonymousCreateParameter { .. } | LifetimeRibKind::AnonymousReportError - | LifetimeRibKind::AnonymousWarn(_) + | LifetimeRibKind::StaticIfNoLifetimeInScope { .. } | LifetimeRibKind::Elided(_) | LifetimeRibKind::ElisionFailure | LifetimeRibKind::ConcreteAnonConst(_) @@ -1580,7 +1581,7 @@ impl<'a: 'ast, 'b, 'ast, 'tcx> LateResolutionVisitor<'a, 'b, 'ast, 'tcx> { // lifetime would be illegal. LifetimeRibKind::Item | LifetimeRibKind::AnonymousReportError - | LifetimeRibKind::AnonymousWarn(_) + | LifetimeRibKind::StaticIfNoLifetimeInScope { .. } | LifetimeRibKind::ElisionFailure => Some(LifetimeUseSet::Many), // An anonymous lifetime is legal here, and bound to the right // place, go ahead. @@ -1643,7 +1644,7 @@ impl<'a: 'ast, 'b, 'ast, 'tcx> LateResolutionVisitor<'a, 'b, 'ast, 'tcx> { | LifetimeRibKind::Generics { .. } | LifetimeRibKind::ElisionFailure | LifetimeRibKind::AnonymousReportError - | LifetimeRibKind::AnonymousWarn(_) => {} + | LifetimeRibKind::StaticIfNoLifetimeInScope { .. } => {} } } @@ -1677,16 +1678,36 @@ impl<'a: 'ast, 'b, 'ast, 'tcx> LateResolutionVisitor<'a, 'b, 'ast, 'tcx> { self.record_lifetime_res(lifetime.id, res, elision_candidate); return; } - LifetimeRibKind::AnonymousWarn(node_id) => { - self.r.lint_buffer.buffer_lint( - lint::builtin::ELIDED_LIFETIMES_IN_ASSOCIATED_CONSTANT, - node_id, - lifetime.ident.span, - lint::BuiltinLintDiag::AssociatedConstElidedLifetime { - elided, - span: lifetime.ident.span, - }, - ); + LifetimeRibKind::StaticIfNoLifetimeInScope { lint_id: node_id, emit_lint } => { + let mut lifetimes_in_scope = vec![]; + for rib in &self.lifetime_ribs[..i] { + lifetimes_in_scope.extend(rib.bindings.iter().map(|(ident, _)| ident.span)); + // Consider any anonymous lifetimes, too + if let LifetimeRibKind::AnonymousCreateParameter { binder, .. } = rib.kind + && let Some(extra) = self.r.extra_lifetime_params_map.get(&binder) + { + lifetimes_in_scope.extend(extra.iter().map(|(ident, _, _)| ident.span)); + } + } + if lifetimes_in_scope.is_empty() { + self.record_lifetime_res( + lifetime.id, + LifetimeRes::Static, + elision_candidate, + ); + return; + } else if emit_lint { + self.r.lint_buffer.buffer_lint( + lint::builtin::ELIDED_LIFETIMES_IN_ASSOCIATED_CONSTANT, + node_id, + lifetime.ident.span, + lint::BuiltinLintDiag::AssociatedConstElidedLifetime { + elided, + span: lifetime.ident.span, + lifetimes_in_scope: lifetimes_in_scope.into(), + }, + ); + } } LifetimeRibKind::AnonymousReportError => { if elided { @@ -1904,7 +1925,7 @@ impl<'a: 'ast, 'b, 'ast, 'tcx> LateResolutionVisitor<'a, 'b, 'ast, 'tcx> { // impl Foo for std::cell::Ref<u32> // note lack of '_ // async fn foo(_: std::cell::Ref<u32>) { ... } LifetimeRibKind::AnonymousCreateParameter { report_in_path: true, .. } - | LifetimeRibKind::AnonymousWarn(_) => { + | LifetimeRibKind::StaticIfNoLifetimeInScope { .. } => { let sess = self.r.tcx.sess; let subdiag = rustc_errors::elided_lifetime_in_path_suggestion( sess.source_map(), @@ -2838,19 +2859,27 @@ impl<'a: 'ast, 'b, 'ast, 'tcx> LateResolutionVisitor<'a, 'b, 'ast, 'tcx> { kind: LifetimeBinderKind::ConstItem, }, |this| { - this.visit_generics(generics); - this.visit_ty(ty); - - // Only impose the restrictions of `ConstRibKind` for an - // actual constant expression in a provided default. - if let Some(expr) = expr { - // We allow arbitrary const expressions inside of associated consts, - // even if they are potentially not const evaluatable. - // - // Type parameters can already be used and as associated consts are - // not used as part of the type system, this is far less surprising. - this.resolve_const_body(expr, None); - } + this.with_lifetime_rib( + LifetimeRibKind::StaticIfNoLifetimeInScope { + lint_id: item.id, + emit_lint: false, + }, + |this| { + this.visit_generics(generics); + this.visit_ty(ty); + + // Only impose the restrictions of `ConstRibKind` for an + // actual constant expression in a provided default. + if let Some(expr) = expr { + // We allow arbitrary const expressions inside of associated consts, + // even if they are potentially not const evaluatable. + // + // Type parameters can already be used and as associated consts are + // not used as part of the type system, this is far less surprising. + this.resolve_const_body(expr, None); + } + }, + ) }, ); } @@ -3030,30 +3059,37 @@ impl<'a: 'ast, 'b, 'ast, 'tcx> LateResolutionVisitor<'a, 'b, 'ast, 'tcx> { kind: LifetimeBinderKind::ConstItem, }, |this| { - this.with_lifetime_rib(LifetimeRibKind::AnonymousWarn(item.id), |this| { - // If this is a trait impl, ensure the const - // exists in trait - this.check_trait_item( - item.id, - item.ident, - &item.kind, - ValueNS, - item.span, - seen_trait_items, - |i, s, c| ConstNotMemberOfTrait(i, s, c), - ); + this.with_lifetime_rib( + LifetimeRibKind::StaticIfNoLifetimeInScope { + lint_id: item.id, + // In impls, it's not a hard error yet due to backcompat. + emit_lint: true, + }, + |this| { + // If this is a trait impl, ensure the const + // exists in trait + this.check_trait_item( + item.id, + item.ident, + &item.kind, + ValueNS, + item.span, + seen_trait_items, + |i, s, c| ConstNotMemberOfTrait(i, s, c), + ); - this.visit_generics(generics); - this.visit_ty(ty); - if let Some(expr) = expr { - // We allow arbitrary const expressions inside of associated consts, - // even if they are potentially not const evaluatable. - // - // Type parameters can already be used and as associated consts are - // not used as part of the type system, this is far less surprising. - this.resolve_const_body(expr, None); - } - }); + this.visit_generics(generics); + this.visit_ty(ty); + if let Some(expr) = expr { + // We allow arbitrary const expressions inside of associated consts, + // even if they are potentially not const evaluatable. + // + // Type parameters can already be used and as associated consts are + // not used as part of the type system, this is far less surprising. + this.resolve_const_body(expr, None); + } + }, + ); }, ); } diff --git a/compiler/rustc_resolve/src/late/diagnostics.rs b/compiler/rustc_resolve/src/late/diagnostics.rs index be24755d4c5..764cc350182 100644 --- a/compiler/rustc_resolve/src/late/diagnostics.rs +++ b/compiler/rustc_resolve/src/late/diagnostics.rs @@ -829,7 +829,7 @@ impl<'a: 'ast, 'ast, 'tcx> LateResolutionVisitor<'a, '_, 'ast, 'tcx> { auto-traits; structs and enums can't be bound in that way", ); if bounds.iter().all(|bound| match bound { - ast::GenericBound::Outlives(_) => true, + ast::GenericBound::Outlives(_) | ast::GenericBound::Use(..) => true, ast::GenericBound::Trait(tr, _) => tr.span == base_error.span, }) { let mut sugg = vec![]; @@ -1109,14 +1109,11 @@ impl<'a: 'ast, 'ast, 'tcx> LateResolutionVisitor<'a, '_, 'ast, 'tcx> { Side::Start => (segment.ident.span.between(range.span), " @ ".into()), Side::End => (range.span.to(segment.ident.span), format!("{} @ ..", segment.ident)), }; - err.subdiagnostic( - self.r.dcx(), - errors::UnexpectedResUseAtOpInSlicePatWithRangeSugg { - span, - ident: segment.ident, - snippet, - }, - ); + err.subdiagnostic(errors::UnexpectedResUseAtOpInSlicePatWithRangeSugg { + span, + ident: segment.ident, + snippet, + }); } enum Side { @@ -1208,13 +1205,10 @@ impl<'a: 'ast, 'ast, 'tcx> LateResolutionVisitor<'a, '_, 'ast, 'tcx> { }); if let Some(param) = param { - err.subdiagnostic( - self.r.dcx(), - errors::UnexpectedResChangeTyToConstParamSugg { - span: param.shrink_to_lo(), - applicability, - }, - ); + err.subdiagnostic(errors::UnexpectedResChangeTyToConstParamSugg { + span: param.shrink_to_lo(), + applicability, + }); } } @@ -3210,7 +3204,7 @@ impl<'a: 'ast, 'ast, 'tcx> LateResolutionVisitor<'a, '_, 'ast, 'tcx> { .inputs .iter() .filter_map(|param| match ¶m.ty.kind { - TyKind::ImplTrait(_, bounds, _) => Some(bounds), + TyKind::ImplTrait(_, bounds) => Some(bounds), _ => None, }) .flat_map(|bounds| bounds.into_iter()) diff --git a/compiler/rustc_resolve/src/lib.rs b/compiler/rustc_resolve/src/lib.rs index 9557b0f5ebc..3a831a7f19e 100644 --- a/compiler/rustc_resolve/src/lib.rs +++ b/compiler/rustc_resolve/src/lib.rs @@ -1089,7 +1089,7 @@ pub struct Resolver<'a, 'tcx> { single_segment_macro_resolutions: Vec<(Ident, MacroKind, ParentScope<'a>, Option<NameBinding<'a>>)>, multi_segment_macro_resolutions: - Vec<(Vec<Segment>, Span, MacroKind, ParentScope<'a>, Option<Res>)>, + Vec<(Vec<Segment>, Span, MacroKind, ParentScope<'a>, Option<Res>, Namespace)>, builtin_attrs: Vec<(Ident, ParentScope<'a>)>, /// `derive(Copy)` marks items they are applied to so they are treated specially later. /// Derive macros cannot modify the item themselves and have to store the markers in the global @@ -1163,6 +1163,15 @@ pub struct Resolver<'a, 'tcx> { doc_link_resolutions: FxHashMap<LocalDefId, DocLinkResMap>, doc_link_traits_in_scope: FxHashMap<LocalDefId, Vec<DefId>>, all_macro_rules: FxHashMap<Symbol, Res>, + + /// Invocation ids of all glob delegations. + glob_delegation_invoc_ids: FxHashSet<LocalExpnId>, + /// Analogue of module `unexpanded_invocations` but in trait impls, excluding glob delegations. + /// Needed because glob delegations wait for all other neighboring macros to expand. + impl_unexpanded_invocations: FxHashMap<LocalDefId, FxHashSet<LocalExpnId>>, + /// Simplified analogue of module `resolutions` but in trait impls, excluding glob delegations. + /// Needed because glob delegations exclude explicitly defined names. + impl_binding_keys: FxHashMap<LocalDefId, FxHashSet<BindingKey>>, } /// Nothing really interesting here; it just provides memory for the rest of the crate. @@ -1504,6 +1513,9 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> { doc_link_traits_in_scope: Default::default(), all_macro_rules: Default::default(), delegation_fn_sigs: Default::default(), + glob_delegation_invoc_ids: Default::default(), + impl_unexpanded_invocations: Default::default(), + impl_binding_keys: Default::default(), }; let root_parent_scope = ParentScope::module(graph_root, &resolver); diff --git a/compiler/rustc_resolve/src/macros.rs b/compiler/rustc_resolve/src/macros.rs index 268e7f06d04..87794d11cea 100644 --- a/compiler/rustc_resolve/src/macros.rs +++ b/compiler/rustc_resolve/src/macros.rs @@ -5,7 +5,7 @@ use crate::errors::CannotDetermineMacroResolution; use crate::errors::{self, AddAsNonDerive, CannotFindIdentInThisScope}; use crate::errors::{MacroExpectedFound, RemoveSurroundingDerive}; use crate::Namespace::*; -use crate::{BuiltinMacroState, Determinacy, MacroData, Used}; +use crate::{BindingKey, BuiltinMacroState, Determinacy, MacroData, Used}; use crate::{DeriveData, Finalize, ParentScope, ResolutionError, Resolver, ScopeSet}; use crate::{ModuleKind, ModuleOrUniformRoot, NameBinding, PathResult, Segment, ToNameBinding}; use rustc_ast::expand::StrippedCfgItem; @@ -198,6 +198,11 @@ impl<'a, 'tcx> ResolverExpand for Resolver<'a, 'tcx> { self.output_macro_rules_scopes.insert(expansion, output_macro_rules_scope); parent_scope.module.unexpanded_invocations.borrow_mut().remove(&expansion); + if let Some(unexpanded_invocations) = + self.impl_unexpanded_invocations.get_mut(&self.invocation_parent(expansion)) + { + unexpanded_invocations.remove(&expansion); + } } fn register_builtin_macro(&mut self, name: Symbol, ext: SyntaxExtensionKind) { @@ -262,15 +267,21 @@ impl<'a, 'tcx> ResolverExpand for Resolver<'a, 'tcx> { } }; - let (path, kind, inner_attr, derives) = match invoc.kind { - InvocationKind::Attr { ref attr, ref derives, .. } => ( - &attr.get_normal_item().path, - MacroKind::Attr, - attr.style == ast::AttrStyle::Inner, - self.arenas.alloc_ast_paths(derives), - ), - InvocationKind::Bang { ref mac, .. } => (&mac.path, MacroKind::Bang, false, &[][..]), - InvocationKind::Derive { ref path, .. } => (path, MacroKind::Derive, false, &[][..]), + let (mut derives, mut inner_attr, mut deleg_impl) = (&[][..], false, None); + let (path, kind) = match invoc.kind { + InvocationKind::Attr { ref attr, derives: ref attr_derives, .. } => { + derives = self.arenas.alloc_ast_paths(attr_derives); + inner_attr = attr.style == ast::AttrStyle::Inner; + (&attr.get_normal_item().path, MacroKind::Attr) + } + InvocationKind::Bang { ref mac, .. } => (&mac.path, MacroKind::Bang), + InvocationKind::Derive { ref path, .. } => (path, MacroKind::Derive), + InvocationKind::GlobDelegation { ref item } => { + let ast::AssocItemKind::DelegationMac(deleg) = &item.kind else { unreachable!() }; + deleg_impl = Some(self.invocation_parent(invoc_id)); + // It is sufficient to consider glob delegation a bang macro for now. + (&deleg.prefix, MacroKind::Bang) + } }; // Derives are not included when `invocations` are collected, so we have to add them here. @@ -286,10 +297,11 @@ impl<'a, 'tcx> ResolverExpand for Resolver<'a, 'tcx> { node_id, force, soft_custom_inner_attributes_gate(path, invoc), + deleg_impl, )?; let span = invoc.span(); - let def_id = res.opt_def_id(); + let def_id = if deleg_impl.is_some() { None } else { res.opt_def_id() }; invoc_id.set_expn_data( ext.expn_data( parent_scope.expansion, @@ -452,6 +464,45 @@ impl<'a, 'tcx> ResolverExpand for Resolver<'a, 'tcx> { fn registered_tools(&self) -> &RegisteredTools { self.registered_tools } + + fn register_glob_delegation(&mut self, invoc_id: LocalExpnId) { + self.glob_delegation_invoc_ids.insert(invoc_id); + } + + fn glob_delegation_suffixes( + &mut self, + trait_def_id: DefId, + impl_def_id: LocalDefId, + ) -> Result<Vec<(Ident, Option<Ident>)>, Indeterminate> { + let target_trait = self.expect_module(trait_def_id); + if !target_trait.unexpanded_invocations.borrow().is_empty() { + return Err(Indeterminate); + } + // FIXME: Instead of waiting try generating all trait methods, and pruning + // the shadowed ones a bit later, e.g. when all macro expansion completes. + // Pros: expansion will be stuck less (but only in exotic cases), the implementation may be + // less hacky. + // Cons: More code is generated just to be deleted later, deleting already created `DefId`s + // may be nontrivial. + if let Some(unexpanded_invocations) = self.impl_unexpanded_invocations.get(&impl_def_id) + && !unexpanded_invocations.is_empty() + { + return Err(Indeterminate); + } + + let mut idents = Vec::new(); + target_trait.for_each_child(self, |this, ident, ns, _binding| { + // FIXME: Adjust hygiene for idents from globs, like for glob imports. + if let Some(overriding_keys) = this.impl_binding_keys.get(&impl_def_id) + && overriding_keys.contains(&BindingKey::new(ident.normalize_to_macros_2_0(), ns)) + { + // The name is overridden, do not produce it from the glob delegation. + } else { + idents.push((ident, None)); + } + }); + Ok(idents) + } } impl<'a, 'tcx> Resolver<'a, 'tcx> { @@ -468,15 +519,40 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> { node_id: NodeId, force: bool, soft_custom_inner_attributes_gate: bool, + deleg_impl: Option<LocalDefId>, ) -> Result<(Lrc<SyntaxExtension>, Res), Indeterminate> { - let (ext, res) = match self.resolve_macro_path(path, Some(kind), parent_scope, true, force) - { + let (ext, res) = match self.resolve_macro_or_delegation_path( + path, + Some(kind), + parent_scope, + true, + force, + deleg_impl, + ) { Ok((Some(ext), res)) => (ext, res), Ok((None, res)) => (self.dummy_ext(kind), res), Err(Determinacy::Determined) => (self.dummy_ext(kind), Res::Err), Err(Determinacy::Undetermined) => return Err(Indeterminate), }; + // Everything below is irrelevant to glob delegation, take a shortcut. + if deleg_impl.is_some() { + if !matches!(res, Res::Err | Res::Def(DefKind::Trait, _)) { + self.dcx().emit_err(MacroExpectedFound { + span: path.span, + expected: "trait", + article: "a", + found: res.descr(), + macro_path: &pprust::path_to_string(path), + remove_surrounding_derive: None, + add_as_non_derive: None, + }); + return Ok((self.dummy_ext(kind), Res::Err)); + } + + return Ok((ext, res)); + } + // Report errors for the resolved macro. for segment in &path.segments { if let Some(args) = &segment.args { @@ -606,11 +682,24 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> { trace: bool, force: bool, ) -> Result<(Option<Lrc<SyntaxExtension>>, Res), Determinacy> { + self.resolve_macro_or_delegation_path(path, kind, parent_scope, trace, force, None) + } + + fn resolve_macro_or_delegation_path( + &mut self, + path: &ast::Path, + kind: Option<MacroKind>, + parent_scope: &ParentScope<'a>, + trace: bool, + force: bool, + deleg_impl: Option<LocalDefId>, + ) -> Result<(Option<Lrc<SyntaxExtension>>, Res), Determinacy> { let path_span = path.span; let mut path = Segment::from_path(path); // Possibly apply the macro helper hack - if kind == Some(MacroKind::Bang) + if deleg_impl.is_none() + && kind == Some(MacroKind::Bang) && path.len() == 1 && path[0].ident.span.ctxt().outer_expn_data().local_inner_macros { @@ -618,13 +707,17 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> { path.insert(0, Segment::from_ident(root)); } - let res = if path.len() > 1 { - let res = match self.maybe_resolve_path(&path, Some(MacroNS), parent_scope) { + let res = if deleg_impl.is_some() || path.len() > 1 { + let ns = if deleg_impl.is_some() { TypeNS } else { MacroNS }; + let res = match self.maybe_resolve_path(&path, Some(ns), parent_scope) { PathResult::NonModule(path_res) if let Some(res) = path_res.full_res() => Ok(res), PathResult::Indeterminate if !force => return Err(Determinacy::Undetermined), PathResult::NonModule(..) | PathResult::Indeterminate | PathResult::Failed { .. } => Err(Determinacy::Determined), + PathResult::Module(ModuleOrUniformRoot::Module(module)) => { + Ok(module.res().unwrap()) + } PathResult::Module(..) => unreachable!(), }; @@ -636,6 +729,7 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> { kind, *parent_scope, res.ok(), + ns, )); } @@ -670,7 +764,18 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> { res }; - res.map(|res| (self.get_macro(res).map(|macro_data| macro_data.ext.clone()), res)) + let res = res?; + let ext = match deleg_impl { + Some(impl_def_id) => match res { + def::Res::Def(DefKind::Trait, def_id) => { + let edition = self.tcx.sess.edition(); + Some(Lrc::new(SyntaxExtension::glob_delegation(def_id, impl_def_id, edition))) + } + _ => None, + }, + None => self.get_macro(res).map(|macro_data| macro_data.ext.clone()), + }; + Ok((ext, res)) } pub(crate) fn finalize_macro_resolutions(&mut self, krate: &Crate) { @@ -706,14 +811,14 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> { }; let macro_resolutions = mem::take(&mut self.multi_segment_macro_resolutions); - for (mut path, path_span, kind, parent_scope, initial_res) in macro_resolutions { + for (mut path, path_span, kind, parent_scope, initial_res, ns) in macro_resolutions { // FIXME: Path resolution will ICE if segment IDs present. for seg in &mut path { seg.id = None; } match self.resolve_path( &path, - Some(MacroNS), + Some(ns), &parent_scope, Some(Finalize::new(ast::CRATE_NODE_ID, path_span)), None, @@ -721,6 +826,15 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> { PathResult::NonModule(path_res) if let Some(res) = path_res.full_res() => { check_consistency(self, &path, path_span, kind, initial_res, res) } + // This may be a trait for glob delegation expansions. + PathResult::Module(ModuleOrUniformRoot::Module(module)) => check_consistency( + self, + &path, + path_span, + kind, + initial_res, + module.res().unwrap(), + ), path_res @ (PathResult::NonModule(..) | PathResult::Failed { .. }) => { let mut suggestion = None; let (span, label, module) = 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 2cb0c06e336..742ec4c377c 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 @@ -288,9 +288,10 @@ pub fn transform_instance<'tcx>( mut instance: Instance<'tcx>, options: TransformTyOptions, ) -> Instance<'tcx> { - if (matches!(instance.def, ty::InstanceDef::Virtual(..)) + // FIXME: account for async-drop-glue + if (matches!(instance.def, ty::InstanceKind::Virtual(..)) && tcx.is_lang_item(instance.def_id(), LangItem::DropInPlace)) - || matches!(instance.def, ty::InstanceDef::DropGlue(..)) + || matches!(instance.def, ty::InstanceKind::DropGlue(..)) { // Adjust the type ids of DropGlues // @@ -316,7 +317,7 @@ pub fn transform_instance<'tcx>( let predicates = tcx.mk_poly_existential_predicates(&[ty::Binder::dummy(predicate)]); let self_ty = Ty::new_dynamic(tcx, predicates, tcx.lifetimes.re_erased, ty::Dyn); instance.args = tcx.mk_args_trait(self_ty, List::empty()); - } else if let ty::InstanceDef::Virtual(def_id, _) = instance.def { + } else if let ty::InstanceKind::Virtual(def_id, _) = instance.def { // Transform self into a trait object of the trait that defines the method for virtual // functions to match the type erasure done below. let upcast_ty = match tcx.trait_of_item(def_id) { @@ -343,7 +344,7 @@ pub fn transform_instance<'tcx>( tcx.types.unit }; instance.args = tcx.mk_args_trait(self_ty, instance.args.into_iter().skip(1)); - } else if let ty::InstanceDef::VTableShim(def_id) = instance.def + } else if let ty::InstanceKind::VTableShim(def_id) = instance.def && let Some(trait_id) = tcx.trait_of_item(def_id) { // Adjust the type ids of VTableShims to the type id expected in the call sites for the @@ -387,7 +388,7 @@ pub fn transform_instance<'tcx>( // If we ever *do* start encoding the vtable index, we will need to generate an alias set // based on which vtables we are putting this method into, as there will be more than one // index value when supertraits are involved. - instance.def = ty::InstanceDef::Virtual(method_id, 0); + instance.def = ty::InstanceKind::Virtual(method_id, 0); let abstract_trait_args = tcx.mk_args_trait(invoke_ty, trait_ref.args.into_iter().skip(1)); instance.args = instance.args.rebase_onto(tcx, impl_id, abstract_trait_args); @@ -442,7 +443,7 @@ pub fn transform_instance<'tcx>( .expect("No call-family function on closure-like Fn trait?") .def_id; - instance.def = ty::InstanceDef::Virtual(call, 0); + instance.def = ty::InstanceKind::Virtual(call, 0); instance.args = abstract_args; } } diff --git a/compiler/rustc_sanitizers/src/kcfi/typeid/mod.rs b/compiler/rustc_sanitizers/src/kcfi/typeid/mod.rs index 436c398e39b..651ba612469 100644 --- a/compiler/rustc_sanitizers/src/kcfi/typeid/mod.rs +++ b/compiler/rustc_sanitizers/src/kcfi/typeid/mod.rs @@ -3,7 +3,7 @@ //! //! For more information about LLVM KCFI and cross-language LLVM KCFI support for the Rust compiler, //! see the tracking issue #123479. -use rustc_middle::ty::{Instance, InstanceDef, ReifyReason, Ty, TyCtxt}; +use rustc_middle::ty::{Instance, InstanceKind, ReifyReason, Ty, TyCtxt}; use rustc_target::abi::call::FnAbi; use std::hash::Hasher; use twox_hash::XxHash64; @@ -44,7 +44,7 @@ pub fn typeid_for_instance<'tcx>( // // This was implemented for KCFI support in #123106 and #123052 (which introduced the // ReifyReason). The tracking issue for KCFI support for Rust is #123479. - if matches!(instance.def, InstanceDef::ReifyShim(_, Some(ReifyReason::FnPtr))) { + if matches!(instance.def, InstanceKind::ReifyShim(_, Some(ReifyReason::FnPtr))) { options.insert(TypeIdOptions::USE_CONCRETE_SELF); } // A KCFI type metadata identifier is a 32-bit constant produced by taking the lower half of the diff --git a/compiler/rustc_session/src/config.rs b/compiler/rustc_session/src/config.rs index a622f1b577d..24143808ef4 100644 --- a/compiler/rustc_session/src/config.rs +++ b/compiler/rustc_session/src/config.rs @@ -149,7 +149,14 @@ pub enum InstrumentCoverage { #[derive(Clone, Copy, Debug, PartialEq, Eq, Hash, Default)] pub struct CoverageOptions { pub level: CoverageLevel, - // Other boolean or enum-valued options might be added here. + + /// `-Z coverage-options=no-mir-spans`: Don't extract block coverage spans + /// from MIR statements/terminators, making it easier to inspect/debug + /// branch and MC/DC coverage mappings. + /// + /// For internal debugging only. If other code changes would make it hard + /// to keep supporting this flag, remove it. + pub no_mir_spans: bool, } /// Controls whether branch coverage or MC/DC coverage is enabled. @@ -1304,6 +1311,20 @@ pub fn build_target_config(early_dcx: &EarlyDiagCtxt, opts: &Options, sysroot: & for warning in warnings.warning_messages() { early_dcx.early_warn(warning) } + + // The `wasm32-wasi` target is being renamed to `wasm32-wasip1` as + // part of rust-lang/compiler-team#607 and + // rust-lang/compiler-team#695. Warn unconditionally on usage to + // raise awareness of the renaming. This code will be deleted in + // October 2024. + if opts.target_triple.triple() == "wasm32-wasi" { + early_dcx.early_warn( + "the `wasm32-wasi` target is being renamed to \ + `wasm32-wasip1` and the `wasm32-wasi` target will be \ + removed from nightly in October 2024 and removed from \ + stable Rust in January 2025", + ) + } if !matches!(target.pointer_width, 16 | 32 | 64) { early_dcx.early_fatal(format!( "target specification was invalid: unrecognized target-pointer-width {}", diff --git a/compiler/rustc_session/src/errors.rs b/compiler/rustc_session/src/errors.rs index dce56382a53..4cbc1b57022 100644 --- a/compiler/rustc_session/src/errors.rs +++ b/compiler/rustc_session/src/errors.rs @@ -3,8 +3,8 @@ use std::num::NonZero; use rustc_ast::token; use rustc_ast::util::literal::LitError; use rustc_errors::{ - codes::*, Diag, DiagCtxt, DiagMessage, Diagnostic, EmissionGuarantee, ErrorGuaranteed, Level, - MultiSpan, + codes::*, Diag, DiagCtxtHandle, DiagMessage, Diagnostic, EmissionGuarantee, ErrorGuaranteed, + Level, MultiSpan, }; use rustc_macros::{Diagnostic, Subdiagnostic}; use rustc_span::{Span, Symbol}; @@ -19,7 +19,7 @@ pub(crate) struct FeatureGateError { impl<'a, G: EmissionGuarantee> Diagnostic<'a, G> for FeatureGateError { #[track_caller] - fn into_diag(self, dcx: &'a DiagCtxt, level: Level) -> Diag<'a, G> { + fn into_diag(self, dcx: DiagCtxtHandle<'a>, level: Level) -> Diag<'a, G> { Diag::new(dcx, level, self.explain).with_span(self.span).with_code(E0658) } } @@ -401,7 +401,7 @@ pub fn report_lit_error( valid.then(|| format!("0{}{}", base_char.to_ascii_lowercase(), &suffix[1..])) } - let dcx = &psess.dcx; + let dcx = psess.dcx(); match err { LitError::InvalidSuffix(suffix) => { dcx.emit_err(InvalidLiteralSuffix { span, kind: lit.kind.descr(), suffix }) diff --git a/compiler/rustc_session/src/options.rs b/compiler/rustc_session/src/options.rs index fd4a3a9e6ce..145af50117c 100644 --- a/compiler/rustc_session/src/options.rs +++ b/compiler/rustc_session/src/options.rs @@ -395,7 +395,8 @@ mod desc { pub const parse_optimization_fuel: &str = "crate=integer"; pub const parse_dump_mono_stats: &str = "`markdown` (default) or `json`"; pub const parse_instrument_coverage: &str = parse_bool; - pub const parse_coverage_options: &str = "`block` | `branch` | `condition` | `mcdc`"; + pub const parse_coverage_options: &str = + "`block` | `branch` | `condition` | `mcdc` | `no-mir-spans`"; pub const parse_instrument_xray: &str = "either a boolean (`yes`, `no`, `on`, `off`, etc), or a comma separated list of settings: `always` or `never` (mutually exclusive), `ignore-loops`, `instruction-threshold=N`, `skip-entry`, `skip-exit`"; pub const parse_unpretty: &str = "`string` or `string=string`"; pub const parse_treat_err_as_bug: &str = "either no value or a non-negative number"; @@ -963,6 +964,7 @@ mod parse { "branch" => slot.level = CoverageLevel::Branch, "condition" => slot.level = CoverageLevel::Condition, "mcdc" => slot.level = CoverageLevel::Mcdc, + "no-mir-spans" => slot.no_mir_spans = true, _ => return false, } } diff --git a/compiler/rustc_session/src/parse.rs b/compiler/rustc_session/src/parse.rs index df07f81bc45..200505aaea2 100644 --- a/compiler/rustc_session/src/parse.rs +++ b/compiler/rustc_session/src/parse.rs @@ -15,8 +15,8 @@ use rustc_data_structures::fx::{FxHashMap, FxIndexMap, FxIndexSet}; use rustc_data_structures::sync::{AppendOnlyVec, Lock, Lrc}; use rustc_errors::emitter::{stderr_destination, HumanEmitter, SilentEmitter}; use rustc_errors::{ - fallback_fluent_bundle, ColorConfig, Diag, DiagCtxt, DiagMessage, EmissionGuarantee, MultiSpan, - StashKey, + fallback_fluent_bundle, ColorConfig, Diag, DiagCtxt, DiagCtxtHandle, DiagMessage, + EmissionGuarantee, MultiSpan, StashKey, }; use rustc_feature::{find_feature_issue, GateIssue, UnstableFeatures}; use rustc_span::edition::Edition; @@ -106,12 +106,12 @@ pub fn feature_err_issue( // Cancel an earlier warning for this same error, if it exists. if let Some(span) = span.primary_span() { - if let Some(err) = sess.psess.dcx.steal_non_err(span, StashKey::EarlySyntaxWarning) { + if let Some(err) = sess.dcx().steal_non_err(span, StashKey::EarlySyntaxWarning) { err.cancel() } } - let mut err = sess.psess.dcx.create_err(FeatureGateError { span, explain: explain.into() }); + let mut err = sess.dcx().create_err(FeatureGateError { span, explain: explain.into() }); add_feature_diagnostics_for_issue(&mut err, sess, feature, issue, false, None); err } @@ -140,7 +140,7 @@ pub fn feature_warn_issue( issue: GateIssue, explain: &'static str, ) { - let mut err = sess.psess.dcx.struct_span_warn(span, explain); + let mut err = sess.dcx().struct_span_warn(span, explain); add_feature_diagnostics_for_issue(&mut err, sess, feature, issue, false, None); // Decorate this as a future-incompatibility lint as in rustc_middle::lint::lint_level @@ -178,30 +178,30 @@ pub fn add_feature_diagnostics_for_issue<G: EmissionGuarantee>( inject_span: Option<Span>, ) { if let Some(n) = find_feature_issue(feature, issue) { - err.subdiagnostic(sess.dcx(), FeatureDiagnosticForIssue { n }); + err.subdiagnostic(FeatureDiagnosticForIssue { n }); } // #23973: do not suggest `#![feature(...)]` if we are in beta/stable if sess.psess.unstable_features.is_nightly_build() { if feature_from_cli { - err.subdiagnostic(sess.dcx(), CliFeatureDiagnosticHelp { feature }); + err.subdiagnostic(CliFeatureDiagnosticHelp { feature }); } else if let Some(span) = inject_span { - err.subdiagnostic(sess.dcx(), FeatureDiagnosticSuggestion { feature, span }); + err.subdiagnostic(FeatureDiagnosticSuggestion { feature, span }); } else { - err.subdiagnostic(sess.dcx(), FeatureDiagnosticHelp { feature }); + err.subdiagnostic(FeatureDiagnosticHelp { feature }); } if sess.opts.unstable_opts.ui_testing { - err.subdiagnostic(sess.dcx(), SuggestUpgradeCompiler::ui_testing()); + err.subdiagnostic(SuggestUpgradeCompiler::ui_testing()); } else if let Some(suggestion) = SuggestUpgradeCompiler::new() { - err.subdiagnostic(sess.dcx(), suggestion); + err.subdiagnostic(suggestion); } } } /// Info about a parsing session. pub struct ParseSess { - pub dcx: DiagCtxt, + dcx: DiagCtxt, pub unstable_features: UnstableFeatures, pub config: Cfg, pub check_config: CheckCfg, @@ -326,4 +326,8 @@ impl ParseSess { // AppendOnlyVec, so we resort to this scheme. self.proc_macro_quoted_spans.iter_enumerated() } + + pub fn dcx(&self) -> DiagCtxtHandle<'_> { + self.dcx.handle() + } } diff --git a/compiler/rustc_session/src/session.rs b/compiler/rustc_session/src/session.rs index 87bbfcf07c8..89d029fa6e0 100644 --- a/compiler/rustc_session/src/session.rs +++ b/compiler/rustc_session/src/session.rs @@ -22,8 +22,8 @@ use rustc_errors::emitter::{stderr_destination, DynEmitter, HumanEmitter, HumanR use rustc_errors::json::JsonEmitter; use rustc_errors::registry::Registry; use rustc_errors::{ - codes::*, fallback_fluent_bundle, Diag, DiagCtxt, DiagMessage, Diagnostic, ErrorGuaranteed, - FatalAbort, FluentBundle, LazyFallbackBundle, TerminalUrl, + codes::*, fallback_fluent_bundle, Diag, DiagCtxt, DiagCtxtHandle, DiagMessage, Diagnostic, + ErrorGuaranteed, FatalAbort, FluentBundle, LazyFallbackBundle, TerminalUrl, }; use rustc_macros::HashStable_Generic; pub use rustc_span::def_id::StableCrateId; @@ -328,8 +328,8 @@ impl Session { } #[inline] - pub fn dcx(&self) -> &DiagCtxt { - &self.psess.dcx + pub fn dcx(&self) -> DiagCtxtHandle<'_> { + self.psess.dcx() } #[inline] @@ -363,6 +363,11 @@ impl Session { && self.opts.unstable_opts.coverage_options.level >= CoverageLevel::Mcdc } + /// True if `-Zcoverage-options=no-mir-spans` was passed. + pub fn coverage_no_mir_spans(&self) -> bool { + self.opts.unstable_opts.coverage_options.no_mir_spans + } + pub fn is_sanitizer_cfi_enabled(&self) -> bool { self.opts.unstable_opts.sanitizer.contains(SanitizerSet::CFI) } @@ -1065,7 +1070,7 @@ pub fn build_session( match profiler { Ok(profiler) => Some(Arc::new(profiler)), Err(e) => { - dcx.emit_warn(errors::FailedToCreateProfiler { err: e.to_string() }); + dcx.handle().emit_warn(errors::FailedToCreateProfiler { err: e.to_string() }); None } } @@ -1366,7 +1371,7 @@ impl EarlyDiagCtxt { /// format. Any errors prior to that will cause an abort and all stashed diagnostics of the /// previous dcx will be emitted. pub fn abort_if_error_and_set_error_format(&mut self, output: ErrorOutputType) { - self.dcx.abort_if_errors(); + self.dcx.handle().abort_if_errors(); let emitter = mk_emitter(output); self.dcx = DiagCtxt::new(emitter); @@ -1375,44 +1380,44 @@ impl EarlyDiagCtxt { #[allow(rustc::untranslatable_diagnostic)] #[allow(rustc::diagnostic_outside_of_impl)] pub fn early_note(&self, msg: impl Into<DiagMessage>) { - self.dcx.note(msg) + self.dcx.handle().note(msg) } #[allow(rustc::untranslatable_diagnostic)] #[allow(rustc::diagnostic_outside_of_impl)] pub fn early_help(&self, msg: impl Into<DiagMessage>) { - self.dcx.struct_help(msg).emit() + self.dcx.handle().struct_help(msg).emit() } #[allow(rustc::untranslatable_diagnostic)] #[allow(rustc::diagnostic_outside_of_impl)] #[must_use = "ErrorGuaranteed must be returned from `run_compiler` in order to exit with a non-zero status code"] pub fn early_err(&self, msg: impl Into<DiagMessage>) -> ErrorGuaranteed { - self.dcx.err(msg) + self.dcx.handle().err(msg) } #[allow(rustc::untranslatable_diagnostic)] #[allow(rustc::diagnostic_outside_of_impl)] pub fn early_fatal(&self, msg: impl Into<DiagMessage>) -> ! { - self.dcx.fatal(msg) + self.dcx.handle().fatal(msg) } #[allow(rustc::untranslatable_diagnostic)] #[allow(rustc::diagnostic_outside_of_impl)] pub fn early_struct_fatal(&self, msg: impl Into<DiagMessage>) -> Diag<'_, FatalAbort> { - self.dcx.struct_fatal(msg) + self.dcx.handle().struct_fatal(msg) } #[allow(rustc::untranslatable_diagnostic)] #[allow(rustc::diagnostic_outside_of_impl)] pub fn early_warn(&self, msg: impl Into<DiagMessage>) { - self.dcx.warn(msg) + self.dcx.handle().warn(msg) } #[allow(rustc::untranslatable_diagnostic)] #[allow(rustc::diagnostic_outside_of_impl)] pub fn early_struct_warn(&self, msg: impl Into<DiagMessage>) -> Diag<'_, ()> { - self.dcx.struct_warn(msg) + self.dcx.handle().struct_warn(msg) } } diff --git a/compiler/rustc_smir/src/rustc_smir/builder.rs b/compiler/rustc_smir/src/rustc_smir/builder.rs index 577373cbc95..42fa6989ddc 100644 --- a/compiler/rustc_smir/src/rustc_smir/builder.rs +++ b/compiler/rustc_smir/src/rustc_smir/builder.rs @@ -19,7 +19,7 @@ impl<'tcx> BodyBuilder<'tcx> { pub fn new(tcx: TyCtxt<'tcx>, instance: ty::Instance<'tcx>) -> Self { let instance = match instance.def { // To get the fallback body of an intrinsic, we need to convert it to an item. - ty::InstanceDef::Intrinsic(def_id) => ty::Instance::new(def_id, instance.args), + ty::InstanceKind::Intrinsic(def_id) => ty::Instance::new(def_id, instance.args), _ => instance, }; BodyBuilder { tcx, instance } diff --git a/compiler/rustc_smir/src/rustc_smir/context.rs b/compiler/rustc_smir/src/rustc_smir/context.rs index 4348bc31bf9..9afd507ce11 100644 --- a/compiler/rustc_smir/src/rustc_smir/context.rs +++ b/compiler/rustc_smir/src/rustc_smir/context.rs @@ -60,7 +60,7 @@ impl<'tcx> Context for TablesWrapper<'tcx> { fn mir_body(&self, item: stable_mir::DefId) -> stable_mir::mir::Body { let mut tables = self.0.borrow_mut(); let def_id = tables[item]; - tables.tcx.instance_mir(rustc_middle::ty::InstanceDef::Item(def_id)).stable(&mut tables) + tables.tcx.instance_mir(rustc_middle::ty::InstanceKind::Item(def_id)).stable(&mut tables) } fn has_body(&self, def: DefId) -> bool { @@ -548,13 +548,13 @@ impl<'tcx> Context for TablesWrapper<'tcx> { fn is_empty_drop_shim(&self, def: InstanceDef) -> bool { let tables = self.0.borrow_mut(); let instance = tables.instances[def]; - matches!(instance.def, ty::InstanceDef::DropGlue(_, None)) + matches!(instance.def, ty::InstanceKind::DropGlue(_, None)) } fn is_empty_async_drop_ctor_shim(&self, def: InstanceDef) -> bool { let tables = self.0.borrow_mut(); let instance = tables.instances[def]; - matches!(instance.def, ty::InstanceDef::AsyncDropGlueCtorShim(_, None)) + matches!(instance.def, ty::InstanceKind::AsyncDropGlueCtorShim(_, None)) } fn mono_instance(&self, def_id: stable_mir::DefId) -> stable_mir::mir::mono::Instance { diff --git a/compiler/rustc_smir/src/rustc_smir/convert/ty.rs b/compiler/rustc_smir/src/rustc_smir/convert/ty.rs index e3cd7187e77..9cd841bba10 100644 --- a/compiler/rustc_smir/src/rustc_smir/convert/ty.rs +++ b/compiler/rustc_smir/src/rustc_smir/convert/ty.rs @@ -839,22 +839,22 @@ impl<'tcx> Stable<'tcx> for ty::Instance<'tcx> { fn stable(&self, tables: &mut Tables<'_>) -> Self::T { let def = tables.instance_def(tables.tcx.lift(*self).unwrap()); let kind = match self.def { - ty::InstanceDef::Item(..) => stable_mir::mir::mono::InstanceKind::Item, - ty::InstanceDef::Intrinsic(..) => stable_mir::mir::mono::InstanceKind::Intrinsic, - ty::InstanceDef::Virtual(_def_id, idx) => { + ty::InstanceKind::Item(..) => stable_mir::mir::mono::InstanceKind::Item, + ty::InstanceKind::Intrinsic(..) => stable_mir::mir::mono::InstanceKind::Intrinsic, + ty::InstanceKind::Virtual(_def_id, idx) => { stable_mir::mir::mono::InstanceKind::Virtual { idx } } - ty::InstanceDef::VTableShim(..) - | ty::InstanceDef::ReifyShim(..) - | ty::InstanceDef::FnPtrAddrShim(..) - | ty::InstanceDef::ClosureOnceShim { .. } - | ty::InstanceDef::ConstructCoroutineInClosureShim { .. } - | ty::InstanceDef::CoroutineKindShim { .. } - | ty::InstanceDef::ThreadLocalShim(..) - | ty::InstanceDef::DropGlue(..) - | ty::InstanceDef::CloneShim(..) - | ty::InstanceDef::FnPtrShim(..) - | ty::InstanceDef::AsyncDropGlueCtorShim(..) => { + ty::InstanceKind::VTableShim(..) + | ty::InstanceKind::ReifyShim(..) + | ty::InstanceKind::FnPtrAddrShim(..) + | ty::InstanceKind::ClosureOnceShim { .. } + | ty::InstanceKind::ConstructCoroutineInClosureShim { .. } + | ty::InstanceKind::CoroutineKindShim { .. } + | ty::InstanceKind::ThreadLocalShim(..) + | ty::InstanceKind::DropGlue(..) + | ty::InstanceKind::CloneShim(..) + | ty::InstanceKind::FnPtrShim(..) + | ty::InstanceKind::AsyncDropGlueCtorShim(..) => { stable_mir::mir::mono::InstanceKind::Shim } }; diff --git a/compiler/rustc_smir/src/rustc_smir/mod.rs b/compiler/rustc_smir/src/rustc_smir/mod.rs index 89f9adfcfd6..82522e995d6 100644 --- a/compiler/rustc_smir/src/rustc_smir/mod.rs +++ b/compiler/rustc_smir/src/rustc_smir/mod.rs @@ -60,9 +60,9 @@ impl<'tcx> Tables<'tcx> { self.item_has_body(def_id) || !matches!( instance.def, - ty::InstanceDef::Virtual(..) - | ty::InstanceDef::Intrinsic(..) - | ty::InstanceDef::Item(..) + ty::InstanceKind::Virtual(..) + | ty::InstanceKind::Intrinsic(..) + | ty::InstanceKind::Item(..) ) } diff --git a/compiler/rustc_span/src/lib.rs b/compiler/rustc_span/src/lib.rs index 9c557ed148c..99ac973497e 100644 --- a/compiler/rustc_span/src/lib.rs +++ b/compiler/rustc_span/src/lib.rs @@ -1065,33 +1065,41 @@ impl Span { #[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<ExpnId> { - 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<ExpnId> { - 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<Option<ExpnId>> { - 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 } @@ -1101,9 +1109,11 @@ impl Span { expn_id: ExpnId, glob_span: Span, ) -> Option<Option<ExpnId>> { - 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 } diff --git a/compiler/rustc_span/src/span_encoding.rs b/compiler/rustc_span/src/span_encoding.rs index 31d2a9db01d..116056a69c1 100644 --- a/compiler/rustc_span/src/span_encoding.rs +++ b/compiler/rustc_span/src/span_encoding.rs @@ -327,43 +327,24 @@ impl Span { // interner and can fall back to `Span::new`. #[inline] pub fn map_ctxt(self, update: impl FnOnce(SyntaxContext) -> SyntaxContext) -> Span { - let (updated_ctxt32, data); match_span_kind! { self, InlineCtxt(span) => { - updated_ctxt32 = update(SyntaxContext::from_u16(span.ctxt)).as_u32(); + let 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 { - return InlineCtxt::span(span.lo, span.len, updated_ctxt32 as u16); - } - 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 self; - } - 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(); + return if updated_ctxt32 <= MAX_CTXT { + InlineCtxt::span(span.lo, span.len, updated_ctxt32 as u16) + } else { + span.data().with_ctxt(SyntaxContext::from_u32(updated_ctxt32)) + }; }, + InlineParent(_span) => {}, + PartiallyInterned(_span) => {}, + Interned(_span) => {}, } - // We could not keep the span in the same inline format, fall back to the complete logic. - data.with_ctxt(SyntaxContext::from_u32(updated_ctxt32)) + let data = self.data_untracked(); + data.with_ctxt(update(data.ctxt)) } // Returns either syntactic context, if it can be retrieved without taking the interner lock, diff --git a/compiler/rustc_span/src/symbol.rs b/compiler/rustc_span/src/symbol.rs index f44fa1bcb4f..9fa8086c8fa 100644 --- a/compiler/rustc_span/src/symbol.rs +++ b/compiler/rustc_span/src/symbol.rs @@ -1678,6 +1678,7 @@ symbols! { shadow_call_stack, shl, shl_assign, + shorter_tail_lifetimes, should_panic, shr, shr_assign, diff --git a/compiler/rustc_symbol_mangling/src/errors.rs b/compiler/rustc_symbol_mangling/src/errors.rs index b5721ee489d..9b87a1419fa 100644 --- a/compiler/rustc_symbol_mangling/src/errors.rs +++ b/compiler/rustc_symbol_mangling/src/errors.rs @@ -1,6 +1,6 @@ //! Errors emitted by symbol_mangling. -use rustc_errors::{Diag, DiagCtxt, Diagnostic, EmissionGuarantee, Level}; +use rustc_errors::{Diag, DiagCtxtHandle, Diagnostic, EmissionGuarantee, Level}; use rustc_span::Span; use std::fmt; @@ -14,7 +14,7 @@ pub struct TestOutput { // natural language, and (b) it's only used in tests. So we construct it // manually and avoid the fluent machinery. impl<G: EmissionGuarantee> Diagnostic<'_, G> for TestOutput { - fn into_diag(self, dcx: &'_ DiagCtxt, level: Level) -> Diag<'_, G> { + fn into_diag(self, dcx: DiagCtxtHandle<'_>, level: Level) -> Diag<'_, G> { let TestOutput { span, kind, content } = self; #[allow(rustc::untranslatable_diagnostic)] diff --git a/compiler/rustc_symbol_mangling/src/legacy.rs b/compiler/rustc_symbol_mangling/src/legacy.rs index 75cac6c7992..9edd2ff9b1a 100644 --- a/compiler/rustc_symbol_mangling/src/legacy.rs +++ b/compiler/rustc_symbol_mangling/src/legacy.rs @@ -56,8 +56,8 @@ pub(super) fn mangle<'tcx>( printer .print_def_path( def_id, - if let ty::InstanceDef::DropGlue(_, _) | ty::InstanceDef::AsyncDropGlueCtorShim(_, _) = - instance.def + if let ty::InstanceKind::DropGlue(_, _) + | ty::InstanceKind::AsyncDropGlueCtorShim(_, _) = instance.def { // Add the name of the dropped type to the symbol name &*instance.args @@ -68,13 +68,13 @@ pub(super) fn mangle<'tcx>( .unwrap(); match instance.def { - ty::InstanceDef::ThreadLocalShim(..) => { + ty::InstanceKind::ThreadLocalShim(..) => { printer.write_str("{{tls-shim}}").unwrap(); } - ty::InstanceDef::VTableShim(..) => { + ty::InstanceKind::VTableShim(..) => { printer.write_str("{{vtable-shim}}").unwrap(); } - ty::InstanceDef::ReifyShim(_, reason) => { + ty::InstanceKind::ReifyShim(_, reason) => { printer.write_str("{{reify-shim").unwrap(); match reason { Some(ReifyReason::FnPtr) => printer.write_str("-fnptr").unwrap(), @@ -85,8 +85,8 @@ pub(super) fn mangle<'tcx>( } // FIXME(async_closures): This shouldn't be needed when we fix // `Instance::ty`/`Instance::def_id`. - ty::InstanceDef::ConstructCoroutineInClosureShim { .. } - | ty::InstanceDef::CoroutineKindShim { .. } => { + ty::InstanceKind::ConstructCoroutineInClosureShim { .. } + | ty::InstanceKind::CoroutineKindShim { .. } => { printer.write_str("{{fn-once-shim}}").unwrap(); } _ => {} diff --git a/compiler/rustc_symbol_mangling/src/v0.rs b/compiler/rustc_symbol_mangling/src/v0.rs index 55479bce6fc..42c4fa83d1b 100644 --- a/compiler/rustc_symbol_mangling/src/v0.rs +++ b/compiler/rustc_symbol_mangling/src/v0.rs @@ -43,14 +43,14 @@ pub(super) fn mangle<'tcx>( // Append `::{shim:...#0}` to shims that can coexist with a non-shim instance. let shim_kind = match instance.def { - ty::InstanceDef::ThreadLocalShim(_) => Some("tls"), - ty::InstanceDef::VTableShim(_) => Some("vtable"), - ty::InstanceDef::ReifyShim(_, None) => Some("reify"), - ty::InstanceDef::ReifyShim(_, Some(ReifyReason::FnPtr)) => Some("reify_fnptr"), - ty::InstanceDef::ReifyShim(_, Some(ReifyReason::Vtable)) => Some("reify_vtable"), - - ty::InstanceDef::ConstructCoroutineInClosureShim { .. } - | ty::InstanceDef::CoroutineKindShim { .. } => Some("fn_once"), + ty::InstanceKind::ThreadLocalShim(_) => Some("tls"), + ty::InstanceKind::VTableShim(_) => Some("vtable"), + ty::InstanceKind::ReifyShim(_, None) => Some("reify"), + ty::InstanceKind::ReifyShim(_, Some(ReifyReason::FnPtr)) => Some("reify_fnptr"), + ty::InstanceKind::ReifyShim(_, Some(ReifyReason::Vtable)) => Some("reify_vtable"), + + ty::InstanceKind::ConstructCoroutineInClosureShim { .. } + | ty::InstanceKind::CoroutineKindShim { .. } => Some("fn_once"), _ => None, }; diff --git a/compiler/rustc_target/src/spec/base/redox.rs b/compiler/rustc_target/src/spec/base/redox.rs index 468fe478549..9070791e9df 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 adea2caabbe..42860b1059e 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 00000000000..83252fadb78 --- /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/errors.rs b/compiler/rustc_trait_selection/src/errors.rs index b442446f79b..a46cba35b2d 100644 --- a/compiler/rustc_trait_selection/src/errors.rs +++ b/compiler/rustc_trait_selection/src/errors.rs @@ -1,6 +1,6 @@ use crate::fluent_generated as fluent; use rustc_errors::{ - codes::*, Applicability, Diag, DiagCtxt, Diagnostic, EmissionGuarantee, Level, + codes::*, Applicability, Diag, DiagCtxtHandle, Diagnostic, EmissionGuarantee, Level, SubdiagMessageOp, Subdiagnostic, }; use rustc_macros::{Diagnostic, Subdiagnostic}; @@ -59,7 +59,7 @@ pub struct NegativePositiveConflict<'tcx> { impl<G: EmissionGuarantee> Diagnostic<'_, G> for NegativePositiveConflict<'_> { #[track_caller] - fn into_diag(self, dcx: &DiagCtxt, level: Level) -> Diag<'_, G> { + fn into_diag(self, dcx: DiagCtxtHandle<'_>, level: Level) -> Diag<'_, G> { let mut diag = Diag::new(dcx, level, fluent::trait_selection_negative_positive_conflict); diag.arg("trait_desc", self.trait_desc.print_only_trait_path().to_string()); diag.arg("self_desc", self.self_ty.map_or_else(|| "none".to_string(), |ty| ty.to_string())); diff --git a/compiler/rustc_trait_selection/src/solve.rs b/compiler/rustc_trait_selection/src/solve.rs new file mode 100644 index 00000000000..a7c8cc5a32b --- /dev/null +++ b/compiler/rustc_trait_selection/src/solve.rs @@ -0,0 +1,12 @@ +pub use rustc_next_trait_solver::solve::*; + +mod fulfill; +mod infcx; +pub mod inspect; +mod normalize; +mod select; + +pub use fulfill::{FulfillmentCtxt, NextSolverError}; +pub(crate) use normalize::deeply_normalize_for_diagnostics; +pub use normalize::{deeply_normalize, deeply_normalize_with_skipped_universes}; +pub use select::InferCtxtSelectExt; diff --git a/compiler/rustc_trait_selection/src/solve/fulfill.rs b/compiler/rustc_trait_selection/src/solve/fulfill.rs index 3c01d1a65f5..8937ed467a1 100644 --- a/compiler/rustc_trait_selection/src/solve/fulfill.rs +++ b/compiler/rustc_trait_selection/src/solve/fulfill.rs @@ -12,13 +12,14 @@ use rustc_infer::traits::{ use rustc_middle::bug; use rustc_middle::ty::error::{ExpectedFound, TypeError}; use rustc_middle::ty::{self, TyCtxt}; +use rustc_next_trait_solver::solve::{GenerateProofTree, SolverDelegateEvalExt as _}; use rustc_span::symbol::sym; use crate::traits::{FulfillmentError, FulfillmentErrorCode, ScrubbedTraitError}; -use super::eval_ctxt::GenerateProofTree; +use super::infcx::SolverDelegate; use super::inspect::{self, ProofTreeInferCtxtExt, ProofTreeVisitor}; -use super::{Certainty, InferCtxtEvalExt}; +use super::Certainty; /// A trait engine using the new trait solver. /// @@ -83,7 +84,9 @@ impl<'tcx> ObligationStorage<'tcx> { // change. self.overflowed.extend(self.pending.extract_if(|o| { let goal = o.clone().into(); - let result = infcx.evaluate_root_goal(goal, GenerateProofTree::No).0; + let result = <&SolverDelegate<'tcx>>::from(infcx) + .evaluate_root_goal(goal, GenerateProofTree::No) + .0; match result { Ok((has_changed, _)) => has_changed, _ => false, @@ -165,7 +168,9 @@ where let mut has_changed = false; for obligation in self.obligations.unstalled_for_select() { let goal = obligation.clone().into(); - let result = infcx.evaluate_root_goal(goal, GenerateProofTree::No).0; + let result = <&SolverDelegate<'tcx>>::from(infcx) + .evaluate_root_goal(goal, GenerateProofTree::No) + .0; self.inspect_evaluated_obligation(infcx, &obligation, &result); let (changed, certainty) = match result { Ok(result) => result, @@ -288,7 +293,10 @@ fn fulfillment_error_for_stalled<'tcx>( root_obligation: PredicateObligation<'tcx>, ) -> FulfillmentError<'tcx> { let (code, refine_obligation) = infcx.probe(|_| { - match infcx.evaluate_root_goal(root_obligation.clone().into(), GenerateProofTree::No).0 { + match <&SolverDelegate<'tcx>>::from(infcx) + .evaluate_root_goal(root_obligation.clone().into(), GenerateProofTree::No) + .0 + { Ok((_, Certainty::Maybe(MaybeCause::Ambiguity))) => { (FulfillmentErrorCode::Ambiguity { overflow: None }, true) } diff --git a/compiler/rustc_trait_selection/src/solve/infcx.rs b/compiler/rustc_trait_selection/src/solve/infcx.rs new file mode 100644 index 00000000000..e574166cbfc --- /dev/null +++ b/compiler/rustc_trait_selection/src/solve/infcx.rs @@ -0,0 +1,435 @@ +use std::ops::Deref; + +use rustc_data_structures::fx::FxHashSet; +use rustc_hir::def_id::{DefId, LocalDefId}; +use rustc_infer::infer::canonical::query_response::make_query_region_constraints; +use rustc_infer::infer::canonical::{ + Canonical, CanonicalExt as _, CanonicalVarInfo, CanonicalVarValues, +}; +use rustc_infer::infer::{ + BoundRegionConversionTime, InferCtxt, RegionVariableOrigin, SubregionOrigin, TyCtxtInferExt, +}; +use rustc_infer::traits::solve::Goal; +use rustc_infer::traits::util::supertraits; +use rustc_infer::traits::{ObligationCause, Reveal}; +use rustc_middle::ty::fold::TypeFoldable; +use rustc_middle::ty::{self, Ty, TyCtxt, TypeVisitableExt as _}; +use rustc_span::{ErrorGuaranteed, Span, DUMMY_SP}; +use rustc_type_ir::relate::Relate; +use rustc_type_ir::solve::{Certainty, NoSolution, SolverMode}; + +use crate::traits::coherence::trait_ref_is_knowable; +use crate::traits::specialization_graph; + +#[repr(transparent)] +pub struct SolverDelegate<'tcx>(InferCtxt<'tcx>); + +impl<'a, 'tcx> From<&'a InferCtxt<'tcx>> for &'a SolverDelegate<'tcx> { + fn from(infcx: &'a InferCtxt<'tcx>) -> Self { + // SAFETY: `repr(transparent)` + unsafe { std::mem::transmute(infcx) } + } +} + +impl<'tcx> Deref for SolverDelegate<'tcx> { + type Target = InferCtxt<'tcx>; + + fn deref(&self) -> &Self::Target { + &self.0 + } +} + +impl<'tcx> rustc_next_trait_solver::infcx::SolverDelegate for SolverDelegate<'tcx> { + type Interner = TyCtxt<'tcx>; + + fn interner(&self) -> TyCtxt<'tcx> { + self.0.tcx + } + + type Span = Span; + + fn solver_mode(&self) -> ty::solve::SolverMode { + match self.intercrate { + true => SolverMode::Coherence, + false => SolverMode::Normal, + } + } + + fn build_with_canonical<V>( + interner: TyCtxt<'tcx>, + solver_mode: SolverMode, + canonical: &Canonical<'tcx, V>, + ) -> (Self, V, CanonicalVarValues<'tcx>) + where + V: TypeFoldable<TyCtxt<'tcx>>, + { + let (infcx, value, vars) = interner + .infer_ctxt() + .with_next_trait_solver(true) + .intercrate(match solver_mode { + SolverMode::Normal => false, + SolverMode::Coherence => true, + }) + .build_with_canonical(DUMMY_SP, canonical); + (SolverDelegate(infcx), value, vars) + } + + fn universe(&self) -> ty::UniverseIndex { + self.0.universe() + } + + fn create_next_universe(&self) -> ty::UniverseIndex { + self.0.create_next_universe() + } + + fn universe_of_ty(&self, vid: ty::TyVid) -> Option<ty::UniverseIndex> { + // FIXME(BoxyUwU): this is kind of jank and means that printing unresolved + // ty infers will give you the universe of the var it resolved to not the universe + // it actually had. It also means that if you have a `?0.1` and infer it to `u8` then + // try to print out `?0.1` it will just print `?0`. + match self.0.probe_ty_var(vid) { + Err(universe) => Some(universe), + Ok(_) => None, + } + } + + fn universe_of_lt(&self, lt: ty::RegionVid) -> Option<ty::UniverseIndex> { + match self.0.inner.borrow_mut().unwrap_region_constraints().probe_value(lt) { + Err(universe) => Some(universe), + Ok(_) => None, + } + } + + fn universe_of_ct(&self, ct: ty::ConstVid) -> Option<ty::UniverseIndex> { + // Same issue as with `universe_of_ty` + match self.0.probe_const_var(ct) { + Err(universe) => Some(universe), + Ok(_) => None, + } + } + + fn root_ty_var(&self, var: ty::TyVid) -> ty::TyVid { + self.0.root_var(var) + } + + fn root_const_var(&self, var: ty::ConstVid) -> ty::ConstVid { + self.0.root_const_var(var) + } + + fn opportunistic_resolve_ty_var(&self, vid: ty::TyVid) -> Ty<'tcx> { + match self.0.probe_ty_var(vid) { + Ok(ty) => ty, + Err(_) => Ty::new_var(self.0.tcx, self.0.root_var(vid)), + } + } + + fn opportunistic_resolve_int_var(&self, vid: ty::IntVid) -> Ty<'tcx> { + self.0.opportunistic_resolve_int_var(vid) + } + + fn opportunistic_resolve_float_var(&self, vid: ty::FloatVid) -> Ty<'tcx> { + self.0.opportunistic_resolve_float_var(vid) + } + + fn opportunistic_resolve_ct_var(&self, vid: ty::ConstVid) -> ty::Const<'tcx> { + match self.0.probe_const_var(vid) { + Ok(ct) => ct, + Err(_) => ty::Const::new_var(self.0.tcx, self.0.root_const_var(vid)), + } + } + + fn opportunistic_resolve_effect_var(&self, vid: ty::EffectVid) -> ty::Const<'tcx> { + match self.0.probe_effect_var(vid) { + Some(ct) => ct, + None => ty::Const::new_infer( + self.0.tcx, + ty::InferConst::EffectVar(self.0.root_effect_var(vid)), + ), + } + } + + fn opportunistic_resolve_lt_var(&self, vid: ty::RegionVid) -> ty::Region<'tcx> { + self.0 + .inner + .borrow_mut() + .unwrap_region_constraints() + .opportunistic_resolve_var(self.0.tcx, vid) + } + + fn defining_opaque_types(&self) -> &'tcx ty::List<LocalDefId> { + self.0.defining_opaque_types() + } + + fn next_ty_infer(&self) -> Ty<'tcx> { + self.0.next_ty_var(DUMMY_SP) + } + + fn next_const_infer(&self) -> ty::Const<'tcx> { + self.0.next_const_var(DUMMY_SP) + } + + fn fresh_args_for_item(&self, def_id: DefId) -> ty::GenericArgsRef<'tcx> { + self.0.fresh_args_for_item(DUMMY_SP, def_id) + } + + fn fresh_var_for_kind_with_span( + &self, + arg: ty::GenericArg<'tcx>, + span: Span, + ) -> ty::GenericArg<'tcx> { + match arg.unpack() { + ty::GenericArgKind::Lifetime(_) => { + self.next_region_var(RegionVariableOrigin::MiscVariable(span)).into() + } + ty::GenericArgKind::Type(_) => self.next_ty_var(span).into(), + ty::GenericArgKind::Const(_) => self.next_const_var(span).into(), + } + } + + fn instantiate_binder_with_infer<T: TypeFoldable<TyCtxt<'tcx>> + Copy>( + &self, + value: ty::Binder<'tcx, T>, + ) -> T { + self.0.instantiate_binder_with_fresh_vars( + DUMMY_SP, + BoundRegionConversionTime::HigherRankedType, + value, + ) + } + + fn enter_forall<T: TypeFoldable<TyCtxt<'tcx>> + Copy, U>( + &self, + value: ty::Binder<'tcx, T>, + f: impl FnOnce(T) -> U, + ) -> U { + self.0.enter_forall(value, f) + } + + fn relate<T: Relate<TyCtxt<'tcx>>>( + &self, + param_env: ty::ParamEnv<'tcx>, + lhs: T, + variance: ty::Variance, + rhs: T, + ) -> Result<Vec<Goal<'tcx, ty::Predicate<'tcx>>>, NoSolution> { + self.0.at(&ObligationCause::dummy(), param_env).relate_no_trace(lhs, variance, rhs) + } + + fn eq_structurally_relating_aliases<T: Relate<TyCtxt<'tcx>>>( + &self, + param_env: ty::ParamEnv<'tcx>, + lhs: T, + rhs: T, + ) -> Result<Vec<Goal<'tcx, ty::Predicate<'tcx>>>, NoSolution> { + self.0 + .at(&ObligationCause::dummy(), param_env) + .eq_structurally_relating_aliases_no_trace(lhs, rhs) + } + + fn resolve_vars_if_possible<T>(&self, value: T) -> T + where + T: TypeFoldable<TyCtxt<'tcx>>, + { + self.0.resolve_vars_if_possible(value) + } + + fn probe<T>(&self, probe: impl FnOnce() -> T) -> T { + self.0.probe(|_| probe()) + } + + fn leak_check(&self, max_input_universe: ty::UniverseIndex) -> Result<(), NoSolution> { + self.0.leak_check(max_input_universe, None).map_err(|_| NoSolution) + } + + fn elaborate_supertraits( + interner: TyCtxt<'tcx>, + trait_ref: ty::Binder<'tcx, ty::TraitRef<'tcx>>, + ) -> impl Iterator<Item = ty::Binder<'tcx, ty::TraitRef<'tcx>>> { + supertraits(interner, trait_ref) + } + + fn try_const_eval_resolve( + &self, + param_env: ty::ParamEnv<'tcx>, + unevaluated: ty::UnevaluatedConst<'tcx>, + ) -> Option<ty::Const<'tcx>> { + use rustc_middle::mir::interpret::ErrorHandled; + match self.const_eval_resolve(param_env, unevaluated, DUMMY_SP) { + Ok(Some(val)) => Some(ty::Const::new_value( + self.tcx, + val, + self.tcx.type_of(unevaluated.def).instantiate(self.tcx, unevaluated.args), + )), + Ok(None) | Err(ErrorHandled::TooGeneric(_)) => None, + Err(ErrorHandled::Reported(e, _)) => Some(ty::Const::new_error(self.tcx, e.into())), + } + } + + fn sub_regions(&self, sub: ty::Region<'tcx>, sup: ty::Region<'tcx>) { + self.0.sub_regions(SubregionOrigin::RelateRegionParamBound(DUMMY_SP), sub, sup) + } + + fn register_ty_outlives(&self, ty: Ty<'tcx>, r: ty::Region<'tcx>) { + self.0.register_region_obligation_with_cause(ty, r, &ObligationCause::dummy()); + } + + fn well_formed_goals( + &self, + param_env: ty::ParamEnv<'tcx>, + arg: ty::GenericArg<'tcx>, + ) -> Option<Vec<Goal<'tcx, ty::Predicate<'tcx>>>> { + crate::traits::wf::unnormalized_obligations(&self.0, param_env, arg).map(|obligations| { + obligations.into_iter().map(|obligation| obligation.into()).collect() + }) + } + + fn clone_opaque_types_for_query_response(&self) -> Vec<(ty::OpaqueTypeKey<'tcx>, Ty<'tcx>)> { + self.0.clone_opaque_types_for_query_response() + } + + fn make_deduplicated_outlives_constraints( + &self, + ) -> Vec<ty::OutlivesPredicate<'tcx, ty::GenericArg<'tcx>>> { + // Cannot use `take_registered_region_obligations` as we may compute the response + // inside of a `probe` whenever we have multiple choices inside of the solver. + let region_obligations = self.0.inner.borrow().region_obligations().to_owned(); + let region_constraints = self.0.with_region_constraints(|region_constraints| { + make_query_region_constraints( + self.tcx, + region_obligations + .iter() + .map(|r_o| (r_o.sup_type, r_o.sub_region, r_o.origin.to_constraint_category())), + region_constraints, + ) + }); + + assert_eq!(region_constraints.member_constraints, vec![]); + + let mut seen = FxHashSet::default(); + region_constraints + .outlives + .into_iter() + .filter(|&(outlives, _)| seen.insert(outlives)) + .map(|(outlives, _)| outlives) + .collect() + } + + fn instantiate_canonical<V>( + &self, + canonical: Canonical<'tcx, V>, + values: CanonicalVarValues<'tcx>, + ) -> V + where + V: TypeFoldable<TyCtxt<'tcx>>, + { + canonical.instantiate(self.tcx, &values) + } + + fn instantiate_canonical_var_with_infer( + &self, + cv_info: CanonicalVarInfo<'tcx>, + universe_map: impl Fn(ty::UniverseIndex) -> ty::UniverseIndex, + ) -> ty::GenericArg<'tcx> { + self.0.instantiate_canonical_var(DUMMY_SP, cv_info, universe_map) + } + + fn insert_hidden_type( + &self, + opaque_type_key: ty::OpaqueTypeKey<'tcx>, + param_env: ty::ParamEnv<'tcx>, + hidden_ty: Ty<'tcx>, + goals: &mut Vec<Goal<'tcx, ty::Predicate<'tcx>>>, + ) -> Result<(), NoSolution> { + self.0 + .insert_hidden_type(opaque_type_key, DUMMY_SP, param_env, hidden_ty, goals) + .map_err(|_| NoSolution) + } + + fn add_item_bounds_for_hidden_type( + &self, + def_id: DefId, + args: ty::GenericArgsRef<'tcx>, + param_env: ty::ParamEnv<'tcx>, + hidden_ty: Ty<'tcx>, + goals: &mut Vec<Goal<'tcx, ty::Predicate<'tcx>>>, + ) { + self.0.add_item_bounds_for_hidden_type(def_id, args, param_env, hidden_ty, goals); + } + + fn inject_new_hidden_type_unchecked(&self, key: ty::OpaqueTypeKey<'tcx>, hidden_ty: Ty<'tcx>) { + self.0.inject_new_hidden_type_unchecked( + key, + ty::OpaqueHiddenType { ty: hidden_ty, span: DUMMY_SP }, + ) + } + + fn reset_opaque_types(&self) { + let _ = self.take_opaque_types(); + } + + fn trait_ref_is_knowable<E: std::fmt::Debug>( + &self, + trait_ref: ty::TraitRef<'tcx>, + lazily_normalize_ty: impl FnMut(Ty<'tcx>) -> Result<Ty<'tcx>, E>, + ) -> Result<bool, E> { + trait_ref_is_knowable(&self.0, trait_ref, lazily_normalize_ty) + .map(|is_knowable| is_knowable.is_ok()) + } + + fn fetch_eligible_assoc_item( + &self, + param_env: ty::ParamEnv<'tcx>, + goal_trait_ref: ty::TraitRef<'tcx>, + trait_assoc_def_id: DefId, + impl_def_id: DefId, + ) -> Result<Option<DefId>, NoSolution> { + let node_item = specialization_graph::assoc_def(self.tcx, impl_def_id, trait_assoc_def_id) + .map_err(|ErrorGuaranteed { .. }| NoSolution)?; + + let eligible = if node_item.is_final() { + // Non-specializable items are always projectable. + true + } else { + // Only reveal a specializable default if we're past type-checking + // and the obligation is monomorphic, otherwise passes such as + // transmute checking and polymorphic MIR optimizations could + // get a result which isn't correct for all monomorphizations. + if param_env.reveal() == Reveal::All { + let poly_trait_ref = self.resolve_vars_if_possible(goal_trait_ref); + !poly_trait_ref.still_further_specializable() + } else { + trace!(?node_item.item.def_id, "not eligible due to default"); + false + } + }; + + // FIXME: Check for defaultness here may cause diagnostics problems. + if eligible { Ok(Some(node_item.item.def_id)) } else { Ok(None) } + } + + fn is_transmutable( + &self, + param_env: ty::ParamEnv<'tcx>, + dst: Ty<'tcx>, + src: Ty<'tcx>, + assume: ty::Const<'tcx>, + ) -> Result<Certainty, NoSolution> { + // Erase regions because we compute layouts in `rustc_transmute`, + // which will ICE for region vars. + let (dst, src) = self.tcx.erase_regions((dst, src)); + + let Some(assume) = rustc_transmute::Assume::from_const(self.tcx, param_env, assume) else { + return Err(NoSolution); + }; + + // FIXME(transmutability): This really should be returning nested goals for `Answer::If*` + match rustc_transmute::TransmuteTypeEnv::new(&self.0).is_transmutable( + ObligationCause::dummy(), + rustc_transmute::Types { src, dst }, + assume, + ) { + rustc_transmute::Answer::Yes => Ok(Certainty::Yes), + rustc_transmute::Answer::No(_) | rustc_transmute::Answer::If(_) => Err(NoSolution), + } + } +} diff --git a/compiler/rustc_trait_selection/src/solve/inspect.rs b/compiler/rustc_trait_selection/src/solve/inspect.rs new file mode 100644 index 00000000000..f100a8c2ff0 --- /dev/null +++ b/compiler/rustc_trait_selection/src/solve/inspect.rs @@ -0,0 +1,4 @@ +pub use rustc_next_trait_solver::solve::inspect::*; + +mod analyse; +pub use analyse::*; diff --git a/compiler/rustc_trait_selection/src/solve/inspect/analyse.rs b/compiler/rustc_trait_selection/src/solve/inspect/analyse.rs index 464c188b6e3..cb621487125 100644 --- a/compiler/rustc_trait_selection/src/solve/inspect/analyse.rs +++ b/compiler/rustc_trait_selection/src/solve/inspect/analyse.rs @@ -13,18 +13,16 @@ use rustc_ast_ir::try_visit; use rustc_ast_ir::visit::VisitorResult; 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, MaybeCause}; +use rustc_middle::traits::solve::{Certainty, Goal, GoalSource, NoSolution, QueryResult}; use rustc_middle::traits::ObligationCause; use rustc_middle::ty::{TyCtxt, TypeFoldable}; use rustc_middle::{bug, ty}; use rustc_next_trait_solver::resolve::EagerResolver; +use rustc_next_trait_solver::solve::inspect::{self, instantiate_canonical_state}; +use rustc_next_trait_solver::solve::{GenerateProofTree, MaybeCause, SolverDelegateEvalExt as _}; use rustc_span::{Span, DUMMY_SP}; -use crate::solve::eval_ctxt::canonical; -use crate::solve::{EvalCtxt, GoalEvaluationKind, GoalSource}; -use crate::solve::{GenerateProofTree, InferCtxtEvalExt}; +use crate::solve::infcx::SolverDelegate; use crate::traits::ObligationCtxt; pub struct InspectConfig { @@ -32,7 +30,7 @@ pub struct InspectConfig { } pub struct InspectGoal<'a, 'tcx> { - infcx: &'a InferCtxt<'tcx>, + infcx: &'a SolverDelegate<'tcx>, depth: usize, orig_values: Vec<ty::GenericArg<'tcx>>, goal: Goal<'tcx, ty::Predicate<'tcx>>, @@ -162,16 +160,10 @@ impl<'a, 'tcx> InspectCandidate<'a, 'tcx> { match **step { inspect::ProbeStep::AddGoal(source, goal) => instantiated_goals.push(( source, - canonical::instantiate_canonical_state( - infcx, - span, - param_env, - &mut orig_values, - goal, - ), + instantiate_canonical_state(infcx, span, param_env, &mut orig_values, goal), )), inspect::ProbeStep::RecordImplArgs { impl_args } => { - opt_impl_args = Some(canonical::instantiate_canonical_state( + opt_impl_args = Some(instantiate_canonical_state( infcx, span, param_env, @@ -184,13 +176,8 @@ impl<'a, 'tcx> InspectCandidate<'a, 'tcx> { } } - let () = canonical::instantiate_canonical_state( - infcx, - span, - param_env, - &mut orig_values, - self.final_state, - ); + let () = + instantiate_canonical_state(infcx, span, param_env, &mut orig_values, self.final_state); if let Some(term_hack) = self.goal.normalizes_to_term_hack { // FIXME: We ignore the expected term of `NormalizesTo` goals @@ -219,16 +206,7 @@ impl<'a, 'tcx> InspectCandidate<'a, 'tcx> { // instantiating the candidate it is already constrained to the result of another // candidate. let proof_tree = infcx - .probe(|_| { - EvalCtxt::enter_root(infcx, GenerateProofTree::Yes, |ecx| { - ecx.evaluate_goal_raw( - GoalEvaluationKind::Root, - GoalSource::Misc, - goal, - ) - }) - }) - .1; + .probe(|_| infcx.evaluate_root_goal_raw(goal, GenerateProofTree::Yes).1); InspectGoal::new( infcx, self.goal.depth + 1, @@ -388,6 +366,8 @@ impl<'a, 'tcx> InspectGoal<'a, 'tcx> { normalizes_to_term_hack: Option<NormalizesToTermHack<'tcx>>, source: GoalSource, ) -> Self { + let infcx = <&SolverDelegate<'tcx>>::from(infcx); + let inspect::GoalEvaluation { uncanonicalized_goal, orig_values, evaluation } = root; let result = evaluation.result.and_then(|ok| { if let Some(term_hack) = normalizes_to_term_hack { @@ -449,7 +429,8 @@ impl<'tcx> InferCtxt<'tcx> { depth: usize, visitor: &mut V, ) -> V::Result { - let (_, proof_tree) = self.evaluate_root_goal(goal, GenerateProofTree::Yes); + let (_, proof_tree) = + <&SolverDelegate<'tcx>>::from(self).evaluate_root_goal(goal, GenerateProofTree::Yes); let proof_tree = proof_tree.unwrap(); visitor.visit_goal(&InspectGoal::new(self, depth, proof_tree, None, GoalSource::Misc)) } diff --git a/compiler/rustc_trait_selection/src/solve/inspect/mod.rs b/compiler/rustc_trait_selection/src/solve/inspect/mod.rs deleted file mode 100644 index 60d52305a6b..00000000000 --- a/compiler/rustc_trait_selection/src/solve/inspect/mod.rs +++ /dev/null @@ -1,7 +0,0 @@ -pub use rustc_middle::traits::solve::inspect::*; - -mod build; -pub(in crate::solve) use build::*; - -mod analyse; -pub use analyse::*; diff --git a/compiler/rustc_trait_selection/src/solve/eval_ctxt/select.rs b/compiler/rustc_trait_selection/src/solve/select.rs index 257fd263b94..257fd263b94 100644 --- a/compiler/rustc_trait_selection/src/solve/eval_ctxt/select.rs +++ b/compiler/rustc_trait_selection/src/solve/select.rs 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 f632f1ad4f2..038f11c60b8 100644 --- a/compiler/rustc_trait_selection/src/traits/error_reporting/suggestions.rs +++ b/compiler/rustc_trait_selection/src/traits/error_reporting/suggestions.rs @@ -4705,14 +4705,11 @@ fn hint_missing_borrow<'tcx>( } if !to_borrow.is_empty() { - err.subdiagnostic(infcx.dcx(), errors::AdjustSignatureBorrow::Borrow { to_borrow }); + err.subdiagnostic(errors::AdjustSignatureBorrow::Borrow { to_borrow }); } if !remove_borrow.is_empty() { - err.subdiagnostic( - infcx.dcx(), - errors::AdjustSignatureBorrow::RemoveBorrow { remove_borrow }, - ); + err.subdiagnostic(errors::AdjustSignatureBorrow::RemoveBorrow { remove_borrow }); } } diff --git a/compiler/rustc_trait_selection/src/traits/select/mod.rs b/compiler/rustc_trait_selection/src/traits/select/mod.rs index b4019585771..fe047f9966f 100644 --- a/compiler/rustc_trait_selection/src/traits/select/mod.rs +++ b/compiler/rustc_trait_selection/src/traits/select/mod.rs @@ -19,7 +19,7 @@ use super::{ }; use crate::infer::{InferCtxt, InferOk, TypeFreshener}; -use crate::solve::InferCtxtSelectExt; +use crate::solve::InferCtxtSelectExt as _; use crate::traits::error_reporting::TypeErrCtxtExt; use crate::traits::normalize::normalize_with_depth; use crate::traits::normalize::normalize_with_depth_to; diff --git a/compiler/rustc_transmute/src/layout/tree.rs b/compiler/rustc_transmute/src/layout/tree.rs index 241381f5875..865f9487213 100644 --- a/compiler/rustc_transmute/src/layout/tree.rs +++ b/compiler/rustc_transmute/src/layout/tree.rs @@ -341,37 +341,29 @@ pub(crate) mod rustc { // 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 + // 1. enums that are uninhabited ZSTs + // 2. enums that delegate their layout to a variant + // 3. enums with multiple 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); + Variants::Single { .. } + if layout.abi.is_uninhabited() && layout.size == Size::ZERO => + { + // The layout representation of uninhabited, ZST enums is + // defined to be like that of the `!` type, as opposed of a + // typical enum. Consequently, they cannot be descended into + // as if they typical enums. We therefore special-case this + // scenario and simply return an uninhabited `Tree`. Ok(Self::uninhabited()) } Variants::Single { index } => { - // `Variants::Single` on non-uninhabited enums denotes that + // `Variants::Single` on enums with variants 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. + // 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. diff --git a/compiler/rustc_ty_utils/src/abi.rs b/compiler/rustc_ty_utils/src/abi.rs index c5ea85c90dc..f1dd94839fe 100644 --- a/compiler/rustc_ty_utils/src/abi.rs +++ b/compiler/rustc_ty_utils/src/abi.rs @@ -5,7 +5,7 @@ use rustc_middle::query::Providers; use rustc_middle::ty::layout::{ fn_can_unwind, FnAbiError, HasParamEnv, HasTyCtxt, LayoutCx, LayoutOf, TyAndLayout, }; -use rustc_middle::ty::{self, InstanceDef, Ty, TyCtxt}; +use rustc_middle::ty::{self, InstanceKind, Ty, TyCtxt}; use rustc_session::config::OptLevel; use rustc_span::def_id::DefId; use rustc_target::abi::call::{ @@ -33,7 +33,7 @@ fn fn_sig_for_fn_abi<'tcx>( instance: ty::Instance<'tcx>, param_env: ty::ParamEnv<'tcx>, ) -> ty::PolyFnSig<'tcx> { - if let InstanceDef::ThreadLocalShim(..) = instance.def { + if let InstanceKind::ThreadLocalShim(..) = instance.def { return ty::Binder::dummy(tcx.mk_fn_sig( [], tcx.thread_local_ptr_ty(instance.def_id()), @@ -63,7 +63,7 @@ fn fn_sig_for_fn_abi<'tcx>( _ => unreachable!(), }; - if let ty::InstanceDef::VTableShim(..) = instance.def { + if let ty::InstanceKind::VTableShim(..) = instance.def { // Modify `fn(self, ...)` to `fn(self: *mut Self, ...)`. sig = sig.map_bound(|mut sig| { let mut inputs_and_output = sig.inputs_and_output.to_vec(); @@ -121,7 +121,7 @@ fn fn_sig_for_fn_abi<'tcx>( let mut coroutine_kind = args.as_coroutine_closure().kind(); let env_ty = - if let InstanceDef::ConstructCoroutineInClosureShim { receiver_by_ref, .. } = + if let InstanceKind::ConstructCoroutineInClosureShim { receiver_by_ref, .. } = instance.def { coroutine_kind = ty::ClosureKind::FnOnce; @@ -174,7 +174,7 @@ fn fn_sig_for_fn_abi<'tcx>( // make sure we respect the `target_kind` in that shim. // FIXME(async_closures): This shouldn't be needed, and we should be populating // a separate def-id for these bodies. - if let InstanceDef::CoroutineKindShim { .. } = instance.def { + if let InstanceKind::CoroutineKindShim { .. } = instance.def { // Grab the parent coroutine-closure. It has the same args for the purposes // of instantiation, so this will be okay to do. let ty::CoroutineClosure(_, coroutine_closure_args) = *tcx @@ -386,7 +386,7 @@ fn fn_abi_of_instance<'tcx>( extra_args, caller_location, Some(instance.def_id()), - matches!(instance.def, ty::InstanceDef::Virtual(..)), + matches!(instance.def, ty::InstanceKind::Virtual(..)), ) } diff --git a/compiler/rustc_ty_utils/src/instance.rs b/compiler/rustc_ty_utils/src/instance.rs index fcd808b5946..c50a490a9dc 100644 --- a/compiler/rustc_ty_utils/src/instance.rs +++ b/compiler/rustc_ty_utils/src/instance.rs @@ -34,7 +34,7 @@ fn resolve_instance<'tcx>( } else { let def = if tcx.intrinsic(def_id).is_some() { debug!(" => intrinsic"); - ty::InstanceDef::Intrinsic(def_id) + ty::InstanceKind::Intrinsic(def_id) } else if tcx.is_lang_item(def_id, LangItem::DropInPlace) { let ty = args.type_at(0); @@ -53,10 +53,10 @@ fn resolve_instance<'tcx>( _ => return Ok(None), } - ty::InstanceDef::DropGlue(def_id, Some(ty)) + ty::InstanceKind::DropGlue(def_id, Some(ty)) } else { debug!(" => trivial drop glue"); - ty::InstanceDef::DropGlue(def_id, None) + ty::InstanceKind::DropGlue(def_id, None) } } else if tcx.is_lang_item(def_id, LangItem::AsyncDropInPlace) { let ty = args.type_at(0); @@ -75,15 +75,15 @@ fn resolve_instance<'tcx>( _ => return Ok(None), } debug!(" => nontrivial async drop glue ctor"); - ty::InstanceDef::AsyncDropGlueCtorShim(def_id, Some(ty)) + ty::InstanceKind::AsyncDropGlueCtorShim(def_id, Some(ty)) } else { debug!(" => trivial async drop glue ctor"); - ty::InstanceDef::AsyncDropGlueCtorShim(def_id, None) + ty::InstanceKind::AsyncDropGlueCtorShim(def_id, None) } } else { debug!(" => free item"); // FIXME(effects): we may want to erase the effect param if that is present on this item. - ty::InstanceDef::Item(def_id) + ty::InstanceKind::Item(def_id) }; Ok(Some(Instance { def, args })) @@ -226,7 +226,7 @@ fn resolve_associated_item<'tcx>( .copied() .position(|def_id| def_id == trait_item_id); offset.map(|offset| Instance { - def: ty::InstanceDef::Virtual(trait_item_id, vtable_base + offset), + def: ty::InstanceKind::Virtual(trait_item_id, vtable_base + offset), args: rcvr_args, }) } @@ -248,7 +248,7 @@ fn resolve_associated_item<'tcx>( }; Some(Instance { - def: ty::InstanceDef::CloneShim(trait_item_id, self_ty), + def: ty::InstanceKind::CloneShim(trait_item_id, self_ty), args: rcvr_args, }) } else { @@ -265,7 +265,7 @@ fn resolve_associated_item<'tcx>( return Ok(None); } Some(Instance { - def: ty::InstanceDef::FnPtrAddrShim(trait_item_id, self_ty), + def: ty::InstanceKind::FnPtrAddrShim(trait_item_id, self_ty), args: rcvr_args, }) } else { @@ -283,7 +283,7 @@ fn resolve_associated_item<'tcx>( { // For compiler developers who'd like to add new items to `Fn`/`FnMut`/`FnOnce`, // you either need to generate a shim body, or perhaps return - // `InstanceDef::Item` pointing to a trait default method body if + // `InstanceKind::Item` pointing to a trait default method body if // it is given a default implementation by the trait. bug!( "no definition for `{trait_ref}::{}` for built-in callable type", @@ -295,7 +295,7 @@ fn resolve_associated_item<'tcx>( Some(Instance::resolve_closure(tcx, closure_def_id, args, target_kind)) } ty::FnDef(..) | ty::FnPtr(..) => Some(Instance { - def: ty::InstanceDef::FnPtrShim(trait_item_id, rcvr_args.type_at(0)), + def: ty::InstanceKind::FnPtrShim(trait_item_id, rcvr_args.type_at(0)), args: rcvr_args, }), ty::CoroutineClosure(coroutine_closure_def_id, args) => { @@ -308,7 +308,7 @@ fn resolve_associated_item<'tcx>( Some(Instance::new(coroutine_closure_def_id, args)) } else { Some(Instance { - def: ty::InstanceDef::ConstructCoroutineInClosureShim { + def: ty::InstanceKind::ConstructCoroutineInClosureShim { coroutine_closure_def_id, receiver_by_ref: target_kind != ty::ClosureKind::FnOnce, }, @@ -331,7 +331,7 @@ fn resolve_associated_item<'tcx>( // If we're computing `AsyncFnOnce` for a by-ref closure then // construct a new body that has the right return types. Some(Instance { - def: ty::InstanceDef::ConstructCoroutineInClosureShim { + def: ty::InstanceKind::ConstructCoroutineInClosureShim { coroutine_closure_def_id, receiver_by_ref: false, }, @@ -345,7 +345,7 @@ fn resolve_associated_item<'tcx>( Some(Instance::resolve_closure(tcx, closure_def_id, args, target_kind)) } ty::FnDef(..) | ty::FnPtr(..) => Some(Instance { - def: ty::InstanceDef::FnPtrShim(trait_item_id, rcvr_args.type_at(0)), + def: ty::InstanceKind::FnPtrShim(trait_item_id, rcvr_args.type_at(0)), args: rcvr_args, }), _ => bug!( diff --git a/compiler/rustc_type_ir/src/binder.rs b/compiler/rustc_type_ir/src/binder.rs index e50d59ba5f0..5042a38fdb8 100644 --- a/compiler/rustc_type_ir/src/binder.rs +++ b/compiler/rustc_type_ir/src/binder.rs @@ -361,6 +361,7 @@ impl<I: Interner> TypeVisitor<I> for ValidateBoundVars<I> { #[cfg_attr(feature = "nightly", derive(TyEncodable, TyDecodable, HashStable_NoContext))] pub struct EarlyBinder<I: Interner, T> { value: T, + #[derivative(Debug = "ignore")] _tcx: PhantomData<I>, } diff --git a/compiler/rustc_type_ir/src/infcx.rs b/compiler/rustc_type_ir/src/infcx.rs deleted file mode 100644 index 4a5f34e3542..00000000000 --- a/compiler/rustc_type_ir/src/infcx.rs +++ /dev/null @@ -1,77 +0,0 @@ -use crate::fold::TypeFoldable; -use crate::relate::Relate; -use crate::solve::{Goal, NoSolution}; -use crate::{self as ty, Interner}; - -pub trait InferCtxtLike: Sized { - type Interner: Interner; - - fn interner(&self) -> Self::Interner; - - fn universe_of_ty(&self, ty: ty::TyVid) -> Option<ty::UniverseIndex>; - fn universe_of_lt(&self, lt: ty::RegionVid) -> Option<ty::UniverseIndex>; - fn universe_of_ct(&self, ct: ty::ConstVid) -> Option<ty::UniverseIndex>; - - 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) -> <Self::Interner as Interner>::Ty; - fn opportunistic_resolve_int_var(&self, vid: ty::IntVid) -> <Self::Interner as Interner>::Ty; - fn opportunistic_resolve_float_var( - &self, - vid: ty::FloatVid, - ) -> <Self::Interner as Interner>::Ty; - fn opportunistic_resolve_ct_var( - &self, - vid: ty::ConstVid, - ) -> <Self::Interner as Interner>::Const; - fn opportunistic_resolve_effect_var( - &self, - vid: ty::EffectVid, - ) -> <Self::Interner as Interner>::Const; - fn opportunistic_resolve_lt_var( - &self, - vid: ty::RegionVid, - ) -> <Self::Interner as Interner>::Region; - - fn defining_opaque_types(&self) -> <Self::Interner as Interner>::DefiningOpaqueTypes; - - fn next_ty_infer(&self) -> <Self::Interner as Interner>::Ty; - fn next_const_infer(&self) -> <Self::Interner as Interner>::Const; - fn fresh_args_for_item( - &self, - def_id: <Self::Interner as Interner>::DefId, - ) -> <Self::Interner as Interner>::GenericArgs; - - fn instantiate_binder_with_infer<T: TypeFoldable<Self::Interner> + Copy>( - &self, - value: ty::Binder<Self::Interner, T>, - ) -> T; - - fn enter_forall<T: TypeFoldable<Self::Interner> + Copy, U>( - &self, - value: ty::Binder<Self::Interner, T>, - f: impl FnOnce(T) -> U, - ) -> U; - - fn relate<T: Relate<Self::Interner>>( - &self, - param_env: <Self::Interner as Interner>::ParamEnv, - lhs: T, - variance: ty::Variance, - rhs: T, - ) -> Result<Vec<Goal<Self::Interner, <Self::Interner as Interner>::Predicate>>, NoSolution>; - - fn eq_structurally_relating_aliases<T: Relate<Self::Interner>>( - &self, - param_env: <Self::Interner as Interner>::ParamEnv, - lhs: T, - rhs: T, - ) -> Result<Vec<Goal<Self::Interner, <Self::Interner as Interner>::Predicate>>, NoSolution>; - - fn resolve_vars_if_possible<T>(&self, value: T) -> T - where - T: TypeFoldable<Self::Interner>; - - fn probe<T>(&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 6b84592978a..64d3400976a 100644 --- a/compiler/rustc_type_ir/src/inherent.rs +++ b/compiler/rustc_type_ir/src/inherent.rs @@ -8,9 +8,11 @@ use std::hash::Hash; use std::ops::Deref; use rustc_ast_ir::Mutability; +use rustc_data_structures::fx::FxHashSet; use crate::fold::{TypeFoldable, TypeSuperFoldable}; use crate::relate::Relate; +use crate::solve::{CacheData, CanonicalInput, QueryResult, Reveal}; use crate::visit::{Flags, TypeSuperVisitable, TypeVisitable}; use crate::{self as ty, CollectAndApply, Interner, UpcastFrom}; @@ -27,10 +29,14 @@ pub trait Ty<I: Interner<Ty = Self>>: + Relate<I> + Flags { + fn new_unit(interner: I) -> Self; + fn new_bool(interner: I) -> Self; fn new_u8(interner: I) -> Self; + fn new_usize(interner: I) -> Self; + fn new_infer(interner: I, var: ty::InferTy) -> Self; fn new_var(interner: I, var: ty::TyVid) -> Self; @@ -107,6 +113,10 @@ pub trait Ty<I: Interner<Ty = Self>>: matches!(self.kind(), ty::Infer(ty::TyVar(_))) } + fn is_fn_ptr(self) -> bool { + matches!(self.kind(), ty::FnPtr(_)) + } + fn fn_sig(self, interner: I) -> ty::Binder<I, ty::FnSig<I>> { match self.kind() { ty::FnPtr(sig) => sig, @@ -126,6 +136,49 @@ pub trait Ty<I: Interner<Ty = Self>>: _ => panic!("Ty::fn_sig() called on non-fn type: {:?}", self), } } + + fn discriminant_ty(self, interner: I) -> I::Ty; + + fn async_destructor_ty(self, interner: I) -> I::Ty; + + /// Returns `true` when the outermost type cannot be further normalized, + /// resolved, or instantiated. This includes all primitive types, but also + /// things like ADTs and trait objects, sice even if their arguments or + /// nested types may be further simplified, the outermost [`ty::TyKind`] or + /// type constructor remains the same. + fn is_known_rigid(self) -> bool { + match self.kind() { + ty::Bool + | ty::Char + | ty::Int(_) + | ty::Uint(_) + | ty::Float(_) + | ty::Adt(_, _) + | ty::Foreign(_) + | ty::Str + | ty::Array(_, _) + | ty::Pat(_, _) + | ty::Slice(_) + | ty::RawPtr(_, _) + | ty::Ref(_, _, _) + | ty::FnDef(_, _) + | ty::FnPtr(_) + | ty::Dynamic(_, _, _) + | ty::Closure(_, _) + | ty::CoroutineClosure(_, _) + | ty::Coroutine(_, _) + | ty::CoroutineWitness(..) + | ty::Never + | ty::Tuple(_) => true, + + ty::Error(_) + | ty::Infer(_) + | ty::Alias(_, _) + | ty::Param(_) + | ty::Bound(_, _) + | ty::Placeholder(_) => false, + } + } } pub trait Tys<I: Interner<Tys = Self>>: @@ -200,6 +253,12 @@ pub trait Const<I: Interner<Const = Self>>: fn new_expr(interner: I, expr: I::ExprConst) -> Self; + fn new_error(interner: I, guar: I::ErrorGuaranteed) -> Self; + + fn new_error_with_message(interner: I, msg: impl ToString) -> Self { + Self::new_error(interner, interner.delay_bug(msg)) + } + fn is_ct_var(self) -> bool { matches!(self.kind(), ty::ConstKind::Infer(ty::InferConst::Var(_))) } @@ -221,6 +280,37 @@ pub trait GenericArg<I: Interner<GenericArg = Self>>: + From<I::Region> + From<I::Const> { + fn as_type(&self) -> Option<I::Ty> { + if let ty::GenericArgKind::Type(ty) = self.kind() { Some(ty) } else { None } + } + + fn expect_ty(&self) -> I::Ty { + self.as_type().expect("expected a type") + } + + fn as_const(&self) -> Option<I::Const> { + if let ty::GenericArgKind::Const(c) = self.kind() { Some(c) } else { None } + } + + fn expect_const(&self) -> I::Const { + self.as_const().expect("expected a const") + } + + fn as_region(&self) -> Option<I::Region> { + if let ty::GenericArgKind::Lifetime(c) = self.kind() { Some(c) } else { None } + } + + fn expect_region(&self) -> I::Region { + self.as_region().expect("expected a const") + } + + fn is_non_region_infer(self) -> bool { + match self.kind() { + ty::GenericArgKind::Lifetime(_) => false, + ty::GenericArgKind::Type(ty) => ty.is_ty_var(), + ty::GenericArgKind::Const(ct) => ct.is_ct_var(), + } + } } pub trait Term<I: Interner<Term = Self>>: @@ -230,7 +320,7 @@ pub trait Term<I: Interner<Term = Self>>: if let ty::TermKind::Ty(ty) = self.kind() { Some(ty) } else { None } } - fn expect_type(&self) -> I::Ty { + fn expect_ty(&self) -> I::Ty { self.as_type().expect("expected a type, but found a const") } @@ -248,6 +338,19 @@ pub trait Term<I: Interner<Term = Self>>: ty::TermKind::Const(ct) => ct.is_ct_var(), } } + + fn to_alias_term(self) -> Option<ty::AliasTerm<I>> { + match self.kind() { + ty::TermKind::Ty(ty) => match ty.kind() { + ty::Alias(_kind, alias_ty) => Some(alias_ty.into()), + _ => None, + }, + ty::TermKind::Const(ct) => match ct.kind() { + ty::ConstKind::Unevaluated(uv) => Some(uv.into()), + _ => None, + }, + } + } } pub trait GenericArgs<I: Interner<GenericArgs = Self>>: @@ -260,8 +363,19 @@ pub trait GenericArgs<I: Interner<GenericArgs = Self>>: + Default + Relate<I> { + fn rebase_onto( + self, + interner: I, + source_def_id: I::DefId, + target: I::GenericArgs, + ) -> I::GenericArgs; + fn type_at(self, i: usize) -> I::Ty; + fn region_at(self, i: usize) -> I::Region; + + fn const_at(self, i: usize) -> I::Const; + fn identity_for_item(interner: I, def_id: I::DefId) -> I::GenericArgs; fn extend_with_error( @@ -301,6 +415,9 @@ pub trait Predicate<I: Interner<Predicate = Self>>: + UpcastFrom<I, ty::NormalizesTo<I>> + UpcastFrom<I, ty::TraitRef<I>> + UpcastFrom<I, ty::Binder<I, ty::TraitRef<I>>> + + UpcastFrom<I, ty::TraitPredicate<I>> + + UpcastFrom<I, ty::OutlivesPredicate<I, I::Ty>> + + UpcastFrom<I, ty::OutlivesPredicate<I, I::Region>> + IntoKind<Kind = ty::Binder<I, ty::PredicateKind<I>>> { fn is_coinductive(self, interner: I) -> bool; @@ -316,9 +433,34 @@ pub trait Clause<I: Interner<Clause = Self>>: + Eq + TypeFoldable<I> // FIXME: Remove these, uplift the `Upcast` impls. + + UpcastFrom<I, ty::TraitRef<I>> + UpcastFrom<I, ty::Binder<I, ty::TraitRef<I>>> + + UpcastFrom<I, ty::ProjectionPredicate<I>> + UpcastFrom<I, ty::Binder<I, ty::ProjectionPredicate<I>>> + + IntoKind<Kind = ty::Binder<I, ty::ClauseKind<I>>> { + fn as_trait_clause(self) -> Option<ty::Binder<I, ty::TraitPredicate<I>>> { + self.kind() + .map_bound(|clause| { + if let ty::ClauseKind::Trait(t) = clause { + Some(t) + } else { + None + } + }) + .transpose() + } + fn as_projection_clause(self) -> Option<ty::Binder<I, ty::ProjectionPredicate<I>>> { + self.kind() + .map_bound(|clause| { + if let ty::ClauseKind::Projection(p) = clause { + Some(p) + } else { + None + } + }) + .transpose() + } } /// Common capabilities of placeholder kinds @@ -350,16 +492,81 @@ pub trait ParamLike { pub trait AdtDef<I: Interner>: Copy + Debug + Hash + Eq { fn def_id(self) -> I::DefId; + fn is_struct(self) -> bool; + + /// Returns the type of the struct tail. + /// + /// Expects the `AdtDef` to be a struct. If it is not, then this will panic. + fn struct_tail_ty(self, interner: I) -> Option<ty::EarlyBinder<I, I::Ty>>; + fn is_phantom_data(self) -> bool; // FIXME: perhaps use `all_fields` and expose `FieldDef`. - fn all_field_tys(self, interner: I) -> ty::EarlyBinder<I, impl Iterator<Item = I::Ty>>; + fn all_field_tys(self, interner: I) -> ty::EarlyBinder<I, impl IntoIterator<Item = I::Ty>>; fn sized_constraint(self, interner: I) -> Option<ty::EarlyBinder<I, I::Ty>>; } +pub trait ParamEnv<I: Interner>: Copy + Debug + Hash + Eq + TypeFoldable<I> { + fn reveal(self) -> Reveal; + + fn caller_bounds(self) -> impl IntoIterator<Item = I::Clause>; +} + pub trait Features<I: Interner>: Copy { fn generic_const_exprs(self) -> bool; fn coroutine_clone(self) -> bool; + + fn associated_const_equality(self) -> bool; +} + +pub trait EvaluationCache<I: Interner> { + /// Insert a final result into the global cache. + fn insert( + &self, + tcx: I, + key: CanonicalInput<I>, + proof_tree: Option<I::CanonicalGoalEvaluationStepRef>, + additional_depth: usize, + encountered_overflow: bool, + cycle_participants: FxHashSet<CanonicalInput<I>>, + dep_node: I::DepNodeIndex, + result: QueryResult<I>, + ); + + /// Try to fetch a cached result, checking the recursion limit + /// and handling root goals of coinductive cycles. + /// + /// If this returns `Some` the cache result can be used. + fn get( + &self, + tcx: I, + key: CanonicalInput<I>, + stack_entries: impl IntoIterator<Item = CanonicalInput<I>>, + available_depth: usize, + ) -> Option<CacheData<I>>; +} + +pub trait DefId<I: Interner>: Copy + Debug + Hash + Eq + TypeFoldable<I> { + fn as_local(self) -> Option<I::LocalDefId>; +} + +pub trait BoundExistentialPredicates<I: Interner>: + Copy + + Debug + + Hash + + Eq + + Relate<I> + + IntoIterator<Item = ty::Binder<I, ty::ExistentialPredicate<I>>> +{ + fn principal_def_id(self) -> Option<I::DefId>; + + fn principal(self) -> Option<ty::Binder<I, ty::ExistentialTraitRef<I>>>; + + fn auto_traits(self) -> impl IntoIterator<Item = I::DefId>; + + fn projection_bounds( + self, + ) -> impl IntoIterator<Item = ty::Binder<I, ty::ExistentialProjection<I>>>; } diff --git a/compiler/rustc_type_ir/src/interner.rs b/compiler/rustc_type_ir/src/interner.rs index a2b71e1fc25..59ca95c09cd 100644 --- a/compiler/rustc_type_ir/src/interner.rs +++ b/compiler/rustc_type_ir/src/interner.rs @@ -1,4 +1,5 @@ use rustc_ast_ir::Movability; +use rustc_index::bit_set::BitSet; use smallvec::SmallVec; use std::fmt::Debug; use std::hash::Hash; @@ -10,6 +11,7 @@ use crate::ir_print::IrPrint; use crate::lang_items::TraitSolverLangItem; use crate::relate::Relate; use crate::solve::inspect::CanonicalGoalEvaluationStep; +use crate::solve::{ExternalConstraintsData, PredefinedOpaquesData, SolverMode}; use crate::visit::{Flags, TypeSuperVisitable, TypeVisitable}; use crate::{self as ty}; @@ -28,8 +30,8 @@ pub trait Interner: + IrPrint<ty::CoercePredicate<Self>> + IrPrint<ty::FnSig<Self>> { - type DefId: Copy + Debug + Hash + Eq + TypeFoldable<Self>; - type AdtDef: AdtDef<Self>; + type DefId: DefId<Self>; + type LocalDefId: Copy + Debug + Hash + Eq + Into<Self::DefId> + TypeFoldable<Self>; type GenericArgs: GenericArgs<Self>; type GenericArgsSlice: Copy + Debug + Hash + Eq + Deref<Target = [Self::GenericArg]>; @@ -44,16 +46,53 @@ pub trait Interner: + Default; type BoundVarKind: Copy + Debug + Hash + Eq; - type CanonicalVars: Copy + Debug + Hash + Eq + IntoIterator<Item = ty::CanonicalVarInfo<Self>>; - type PredefinedOpaques: Copy + Debug + Hash + Eq; - type DefiningOpaqueTypes: Copy + Debug + Hash + Default + Eq + TypeVisitable<Self>; - type ExternalConstraints: Copy + Debug + Hash + Eq; + type PredefinedOpaques: Copy + + Debug + + Hash + + Eq + + TypeFoldable<Self> + + Deref<Target = PredefinedOpaquesData<Self>>; + fn mk_predefined_opaques_in_body( + self, + data: PredefinedOpaquesData<Self>, + ) -> Self::PredefinedOpaques; + + type DefiningOpaqueTypes: Copy + + Debug + + Hash + + Default + + Eq + + TypeVisitable<Self> + + Deref<Target: Deref<Target = [Self::LocalDefId]>>; type CanonicalGoalEvaluationStepRef: Copy + Debug + Hash + Eq + Deref<Target = CanonicalGoalEvaluationStep<Self>>; + type CanonicalVars: Copy + + Debug + + Hash + + Eq + + IntoIterator<Item = ty::CanonicalVarInfo<Self>> + + Deref<Target: Deref<Target = [ty::CanonicalVarInfo<Self>]>> + + Default; + fn mk_canonical_var_infos(self, infos: &[ty::CanonicalVarInfo<Self>]) -> Self::CanonicalVars; + + type ExternalConstraints: Copy + + Debug + + Hash + + Eq + + TypeFoldable<Self> + + Deref<Target = ExternalConstraintsData<Self>>; + fn mk_external_constraints( + self, + data: ExternalConstraintsData<Self>, + ) -> Self::ExternalConstraints; + + type DepNodeIndex; + fn with_cached_task<T>(self, task: impl FnOnce() -> T) -> (T, Self::DepNodeIndex); + // Kinds of tys type Ty: Ty<Self>; type Tys: Tys<Self>; @@ -64,12 +103,7 @@ pub trait Interner: // Things stored inside of tys type ErrorGuaranteed: Copy + Debug + Hash + Eq; - type BoundExistentialPredicates: Copy - + Debug - + Hash - + Eq - + Relate<Self> - + IntoIterator<Item = ty::Binder<Self, ty::ExistentialPredicate<Self>>>; + type BoundExistentialPredicates: BoundExistentialPredicates<Self>; type AllocId: Copy + Debug + Hash + Eq; type Pat: Copy + Debug + Hash + Eq + Debug + Relate<Self>; type Safety: Safety<Self>; @@ -91,24 +125,31 @@ pub trait Interner: type PlaceholderRegion: PlaceholderLike; // Predicates - type ParamEnv: Copy + Debug + Hash + Eq + TypeFoldable<Self>; + type ParamEnv: ParamEnv<Self>; type Predicate: Predicate<Self>; type Clause: Clause<Self>; type Clauses: Copy + Debug + Hash + Eq + TypeSuperVisitable<Self> + Flags; - fn expand_abstract_consts<T: TypeFoldable<Self>>(self, t: T) -> T; + type EvaluationCache: EvaluationCache<Self>; + fn evaluation_cache(self, mode: SolverMode) -> Self::EvaluationCache; - fn mk_canonical_var_infos(self, infos: &[ty::CanonicalVarInfo<Self>]) -> Self::CanonicalVars; + fn expand_abstract_consts<T: TypeFoldable<Self>>(self, t: T) -> T; type GenericsOf: GenericsOf<Self>; fn generics_of(self, def_id: Self::DefId) -> Self::GenericsOf; - type VariancesOf: Copy + Debug + Deref<Target = [ty::Variance]>; + type VariancesOf: Copy + + Debug + + Deref<Target = [ty::Variance]> + // FIXME: This is terrible! + + IntoIterator<Item: Deref<Target = ty::Variance>>; fn variances_of(self, def_id: Self::DefId) -> Self::VariancesOf; - // FIXME: Remove after uplifting `EarlyBinder` fn type_of(self, def_id: Self::DefId) -> ty::EarlyBinder<Self, Self::Ty>; + type AdtDef: AdtDef<Self>; + fn adt_def(self, adt_def_id: Self::DefId) -> Self::AdtDef; + fn alias_ty_kind(self, alias: ty::AliasTy<Self>) -> ty::AliasTyKind; fn alias_term_kind(self, alias: ty::AliasTerm<Self>) -> ty::AliasTermKind; @@ -126,6 +167,8 @@ pub trait Interner: I: Iterator<Item = T>, T: CollectAndApply<Self::GenericArg, Self::GenericArgs>; + fn check_args_compatible(self, def_id: Self::DefId, args: Self::GenericArgs) -> bool; + fn check_and_mk_args( self, def_id: Self::DefId, @@ -170,6 +213,17 @@ pub trait Interner: def_id: Self::DefId, ) -> ty::EarlyBinder<Self, impl IntoIterator<Item = Self::Clause>>; + fn predicates_of( + self, + def_id: Self::DefId, + ) -> ty::EarlyBinder<Self, impl IntoIterator<Item = Self::Clause>>; + + fn own_predicates_of( + self, + def_id: Self::DefId, + ) -> ty::EarlyBinder<Self, impl IntoIterator<Item = Self::Clause>>; + + // FIXME: Rename this so it's obvious it's only *immediate* super predicates. fn super_predicates_of( self, def_id: Self::DefId, @@ -179,7 +233,64 @@ pub trait Interner: fn require_lang_item(self, lang_item: TraitSolverLangItem) -> Self::DefId; + fn is_lang_item(self, def_id: Self::DefId, lang_item: TraitSolverLangItem) -> bool; + fn associated_type_def_ids(self, def_id: Self::DefId) -> impl IntoIterator<Item = Self::DefId>; + + // FIXME: move `fast_reject` into `rustc_type_ir`. + fn args_may_unify_deep( + self, + obligation_args: Self::GenericArgs, + impl_args: Self::GenericArgs, + ) -> bool; + + fn for_each_relevant_impl( + self, + trait_def_id: Self::DefId, + self_ty: Self::Ty, + f: impl FnMut(Self::DefId), + ); + + fn has_item_definition(self, def_id: Self::DefId) -> bool; + + fn impl_is_default(self, impl_def_id: Self::DefId) -> bool; + + fn impl_trait_ref(self, impl_def_id: Self::DefId) -> ty::EarlyBinder<Self, ty::TraitRef<Self>>; + + fn impl_polarity(self, impl_def_id: Self::DefId) -> ty::ImplPolarity; + + fn trait_is_auto(self, trait_def_id: Self::DefId) -> bool; + + fn trait_is_alias(self, trait_def_id: Self::DefId) -> bool; + + fn trait_is_object_safe(self, trait_def_id: Self::DefId) -> bool; + + fn trait_may_be_implemented_via_object(self, trait_def_id: Self::DefId) -> bool; + + fn fn_trait_kind_from_def_id(self, trait_def_id: Self::DefId) -> Option<ty::ClosureKind>; + + fn async_fn_trait_kind_from_def_id(self, trait_def_id: Self::DefId) -> Option<ty::ClosureKind>; + + fn supertrait_def_ids(self, trait_def_id: Self::DefId) + -> impl IntoIterator<Item = Self::DefId>; + + fn delay_bug(self, msg: impl ToString) -> Self::ErrorGuaranteed; + + fn is_general_coroutine(self, coroutine_def_id: Self::DefId) -> bool; + fn coroutine_is_async(self, coroutine_def_id: Self::DefId) -> bool; + fn coroutine_is_gen(self, coroutine_def_id: Self::DefId) -> bool; + fn coroutine_is_async_gen(self, coroutine_def_id: Self::DefId) -> bool; + + fn layout_is_pointer_like(self, param_env: Self::ParamEnv, ty: Self::Ty) -> bool; + + type UnsizingParams: Deref<Target = BitSet<u32>>; + fn unsizing_params_for_adt(self, adt_def_id: Self::DefId) -> Self::UnsizingParams; + + fn find_const_ty_from_env( + self, + param_env: Self::ParamEnv, + placeholder: Self::PlaceholderConst, + ) -> Self::Ty; } /// 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 index 9a3b324fcd7..cf5ec1ab3fe 100644 --- a/compiler/rustc_type_ir/src/lang_items.rs +++ b/compiler/rustc_type_ir/src/lang_items.rs @@ -1,8 +1,36 @@ /// 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, + // tidy-alphabetical-start + AsyncDestruct, AsyncFnKindHelper, AsyncFnKindUpvars, + AsyncFnOnceOutput, + AsyncIterator, + CallOnceFuture, + CallRefFuture, + Clone, + Copy, + Coroutine, + CoroutineReturn, + CoroutineYield, + Destruct, + DiscriminantKind, + DynMetadata, + FnPtrTrait, + FusedIterator, + Future, + FutureOutput, + Iterator, + Metadata, + Option, + PointeeTrait, + PointerLike, + Poll, + Sized, + TransmuteTrait, + Tuple, + Unpin, + Unsize, + // tidy-alphabetical-end } diff --git a/compiler/rustc_type_ir/src/lib.rs b/compiler/rustc_type_ir/src/lib.rs index 4775a0f8cbb..130ea231bf7 100644 --- a/compiler/rustc_type_ir/src/lib.rs +++ b/compiler/rustc_type_ir/src/lib.rs @@ -45,8 +45,8 @@ mod canonical; mod const_kind; mod flags; mod generic_arg; -mod infcx; mod interner; +mod opaque_ty; mod predicate; mod predicate_kind; mod region_kind; @@ -61,8 +61,8 @@ pub use codec::*; pub use const_kind::*; pub use flags::*; pub use generic_arg::*; -pub use infcx::InferCtxtLike; pub use interner::*; +pub use opaque_ty::*; pub use predicate::*; pub use predicate_kind::*; pub use region_kind::*; diff --git a/compiler/rustc_type_ir/src/opaque_ty.rs b/compiler/rustc_type_ir/src/opaque_ty.rs new file mode 100644 index 00000000000..60737066597 --- /dev/null +++ b/compiler/rustc_type_ir/src/opaque_ty.rs @@ -0,0 +1,51 @@ +use rustc_macros::{HashStable_NoContext, TyDecodable, TyEncodable}; +use rustc_type_ir_macros::{TypeFoldable_Generic, TypeVisitable_Generic}; + +use crate::inherent::*; +use crate::{self as ty, Interner}; + +#[derive(derivative::Derivative)] +#[derivative( + Clone(bound = ""), + Hash(bound = ""), + PartialEq(bound = ""), + Eq(bound = ""), + Debug(bound = ""), + Copy(bound = "") +)] +#[derive(TypeVisitable_Generic, TypeFoldable_Generic)] +#[cfg_attr(feature = "nightly", derive(TyEncodable, TyDecodable, HashStable_NoContext))] +pub struct OpaqueTypeKey<I: Interner> { + pub def_id: I::LocalDefId, + pub args: I::GenericArgs, +} + +impl<I: Interner> OpaqueTypeKey<I> { + pub fn iter_captured_args(self, tcx: I) -> impl Iterator<Item = (usize, I::GenericArg)> { + let variances = tcx.variances_of(self.def_id.into()); + std::iter::zip(self.args, variances.into_iter()).enumerate().filter_map(|(i, (arg, v))| { + match (arg.kind(), *v) { + (_, ty::Invariant) => Some((i, arg)), + (ty::GenericArgKind::Lifetime(_), ty::Bivariant) => None, + _ => panic!("unexpected opaque type arg variance"), + } + }) + } + + pub fn fold_captured_lifetime_args( + self, + tcx: I, + mut f: impl FnMut(I::Region) -> I::Region, + ) -> Self { + let Self { def_id, args } = self; + let variances = tcx.variances_of(def_id.into()); + let args = + std::iter::zip(args, variances.into_iter()).map(|(arg, v)| match (arg.kind(), *v) { + (ty::GenericArgKind::Lifetime(_), ty::Bivariant) => arg, + (ty::GenericArgKind::Lifetime(lt), _) => f(lt).into(), + _ => arg, + }); + let args = tcx.mk_args_from_iter(args); + Self { def_id, args } + } +} diff --git a/compiler/rustc_type_ir/src/predicate.rs b/compiler/rustc_type_ir/src/predicate.rs index c0713dc50d2..7a3376c7218 100644 --- a/compiler/rustc_type_ir/src/predicate.rs +++ b/compiler/rustc_type_ir/src/predicate.rs @@ -7,7 +7,7 @@ use rustc_type_ir_macros::{Lift_Generic, TypeFoldable_Generic, TypeVisitable_Gen use crate::inherent::*; use crate::lift::Lift; -use crate::upcast::Upcast; +use crate::upcast::{Upcast, UpcastFrom}; use crate::visit::TypeVisitableExt as _; use crate::{self as ty, Interner}; @@ -166,6 +166,12 @@ impl<I: Interner> ty::Binder<I, TraitPredicate<I>> { } } +impl<I: Interner> UpcastFrom<I, TraitRef<I>> for TraitPredicate<I> { + fn upcast_from(from: TraitRef<I>, _tcx: I) -> Self { + TraitPredicate { trait_ref: from, polarity: PredicatePolarity::Positive } + } +} + impl<I: Interner> fmt::Debug for TraitPredicate<I> { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { // FIXME(effects) printing? @@ -479,8 +485,8 @@ pub struct AliasTerm<I: Interner> { /// aka. `interner.parent(def_id)`. pub def_id: I::DefId, - /// This field exists to prevent the creation of `AliasTerm` without using - /// [AliasTerm::new]. + /// This field exists to prevent the creation of `AliasTerm` without using [`AliasTerm::new`]. + #[derivative(Debug = "ignore")] _use_alias_term_new_instead: (), } diff --git a/compiler/rustc_type_ir/src/region_kind.rs b/compiler/rustc_type_ir/src/region_kind.rs index 37c9532ad89..7abcc370c88 100644 --- a/compiler/rustc_type_ir/src/region_kind.rs +++ b/compiler/rustc_type_ir/src/region_kind.rs @@ -154,7 +154,7 @@ pub enum RegionKind<I: Interner> { /// parameters via `tcx.liberate_late_bound_regions`. They are then treated /// the same way as `ReEarlyParam` while inside of the function. /// - /// See <https://rustc-dev-guide.rust-lang.org/early-late-bound-summary.html> for + /// See <https://rustc-dev-guide.rust-lang.org/early-late-bound-params/early-late-bound-summary.html> for /// more info about early and late bound lifetime parameters. ReLateParam(I::LateParamRegion), diff --git a/compiler/rustc_type_ir/src/solve.rs b/compiler/rustc_type_ir/src/solve.rs index 6a89a8a4cc3..7934f996f0b 100644 --- a/compiler/rustc_type_ir/src/solve.rs +++ b/compiler/rustc_type_ir/src/solve.rs @@ -7,7 +7,68 @@ use std::hash::Hash; use rustc_macros::{HashStable_NoContext, TyDecodable, TyEncodable}; use rustc_type_ir_macros::{Lift_Generic, TypeFoldable_Generic, TypeVisitable_Generic}; -use crate::{Canonical, CanonicalVarValues, Interner, Upcast}; +use crate::{self as ty, Canonical, CanonicalVarValues, Interner, Upcast}; + +/// Depending on the stage of compilation, we want projection to be +/// more or less conservative. +#[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)] +#[cfg_attr(feature = "nightly", derive(TyDecodable, TyEncodable, HashStable_NoContext))] +pub enum Reveal { + /// At type-checking time, we refuse to project any associated + /// type that is marked `default`. Non-`default` ("final") types + /// are always projected. This is necessary in general for + /// soundness of specialization. However, we *could* allow + /// projections in fully-monomorphic cases. We choose not to, + /// because we prefer for `default type` to force the type + /// definition to be treated abstractly by any consumers of the + /// impl. Concretely, that means that the following example will + /// fail to compile: + /// + /// ```compile_fail,E0308 + /// #![feature(specialization)] + /// trait Assoc { + /// type Output; + /// } + /// + /// impl<T> Assoc for T { + /// default type Output = bool; + /// } + /// + /// fn main() { + /// let x: <() as Assoc>::Output = true; + /// } + /// ``` + /// + /// We also do not reveal the hidden type of opaque types during + /// type-checking. + UserFacing, + + /// At codegen time, all monomorphic projections will succeed. + /// Also, `impl Trait` is normalized to the concrete type, + /// which has to be already collected by type-checking. + /// + /// NOTE: as `impl Trait`'s concrete type should *never* + /// be observable directly by the user, `Reveal::All` + /// should not be used by checks which may expose + /// type equality or type contents to the user. + /// There are some exceptions, e.g., around auto traits and + /// transmute-checking, which expose some details, but + /// not the whole concrete type of the `impl Trait`. + All, +} + +#[derive(Debug, Clone, Copy)] +pub enum SolverMode { + /// Ordinary trait solving, using everywhere except for coherence. + Normal, + /// Trait solving during coherence. There are a few notable differences + /// between coherence and ordinary trait solving. + /// + /// Most importantly, trait solving during coherence must not be incomplete, + /// i.e. return `Err(NoSolution)` for goals for which a solution exists. + /// This means that we must not make any guesses or arbitrary choices. + Coherence, +} pub type CanonicalInput<I, T = <I as Interner>::Predicate> = Canonical<I, QueryInput<I, T>>; pub type CanonicalResponse<I> = Canonical<I, Response<I>>; @@ -95,6 +156,22 @@ pub struct QueryInput<I: Interner, P> { pub predefined_opaques_in_body: I::PredefinedOpaques, } +/// Opaques that are defined in the inference context before a query is called. +#[derive(derivative::Derivative)] +#[derivative( + Clone(bound = ""), + Hash(bound = ""), + PartialEq(bound = ""), + Eq(bound = ""), + Debug(bound = ""), + Default(bound = "") +)] +#[derive(TypeVisitable_Generic, TypeFoldable_Generic)] +#[cfg_attr(feature = "nightly", derive(TyDecodable, TyEncodable, HashStable_NoContext))] +pub struct PredefinedOpaquesData<I: Interner> { + pub opaque_types: Vec<(ty::OpaqueTypeKey<I>, I::Ty)>, +} + /// Possible ways the given goal can be proven. #[derive(derivative::Derivative)] #[derivative( @@ -206,6 +283,47 @@ pub struct Response<I: Interner> { pub external_constraints: I::ExternalConstraints, } +/// Additional constraints returned on success. +#[derive(derivative::Derivative)] +#[derivative( + Clone(bound = ""), + Hash(bound = ""), + PartialEq(bound = ""), + Eq(bound = ""), + Debug(bound = ""), + Default(bound = "") +)] +#[derive(TypeVisitable_Generic, TypeFoldable_Generic)] +#[cfg_attr(feature = "nightly", derive(HashStable_NoContext))] +pub struct ExternalConstraintsData<I: Interner> { + pub region_constraints: Vec<ty::OutlivesPredicate<I, I::GenericArg>>, + pub opaque_types: Vec<(ty::OpaqueTypeKey<I>, I::Ty)>, + pub normalization_nested_goals: NestedNormalizationGoals<I>, +} + +#[derive(derivative::Derivative)] +#[derivative( + Clone(bound = ""), + Hash(bound = ""), + PartialEq(bound = ""), + Eq(bound = ""), + Debug(bound = ""), + Default(bound = "") +)] +#[derive(TypeVisitable_Generic, TypeFoldable_Generic)] +#[cfg_attr(feature = "nightly", derive(HashStable_NoContext))] +pub struct NestedNormalizationGoals<I: Interner>(pub Vec<(GoalSource, Goal<I, I::Predicate>)>); + +impl<I: Interner> NestedNormalizationGoals<I> { + pub fn empty() -> Self { + NestedNormalizationGoals(vec![]) + } + + pub fn is_empty(&self) -> bool { + self.0.is_empty() + } +} + #[derive(Clone, Copy, Hash, PartialEq, Eq, Debug)] #[cfg_attr(feature = "nightly", derive(HashStable_NoContext))] pub enum Certainty { @@ -267,3 +385,12 @@ impl MaybeCause { } } } + +#[derive(derivative::Derivative)] +#[derivative(PartialEq(bound = ""), Eq(bound = ""), Debug(bound = ""))] +pub struct CacheData<I: Interner> { + pub result: QueryResult<I>, + pub proof_tree: Option<I::CanonicalGoalEvaluationStepRef>, + pub additional_depth: usize, + pub encountered_overflow: bool, +} diff --git a/compiler/rustc_type_ir/src/ty_kind.rs b/compiler/rustc_type_ir/src/ty_kind.rs index 8b4ad2f5ed0..915888ab59b 100644 --- a/compiler/rustc_type_ir/src/ty_kind.rs +++ b/compiler/rustc_type_ir/src/ty_kind.rs @@ -452,8 +452,8 @@ pub struct AliasTy<I: Interner> { /// aka. `interner.parent(def_id)`. pub def_id: I::DefId, - /// This field exists to prevent the creation of `AliasTy` without using - /// [AliasTy::new]. + /// This field exists to prevent the creation of `AliasTy` without using [`AliasTy::new`]. + #[derivative(Debug = "ignore")] pub(crate) _use_alias_ty_new_instead: (), } diff --git a/config.example.toml b/config.example.toml index 76541ee4e9e..679abcdc777 100644 --- a/config.example.toml +++ b/config.example.toml @@ -321,8 +321,7 @@ # # If `extended = false`, the only one of these built by default is rustdoc. # -# If `extended = true`, they're all included, with the exception of -# rust-demangler which additionally requires `profiler = true` to be set. +# If `extended = true`, they are all included. # # If any enabled tool fails to build, the installation fails. #tools = [ @@ -334,7 +333,6 @@ # "rust-analyzer-proc-macro-srv", # "analysis", # "src", -# "rust-demangler", # if profiler = true #] # Verbosity level: 0 == not verbose, 1 == verbose, 2 == very verbose, 3 == print environment variables on each rustc invocation diff --git a/library/core/src/error.rs b/library/core/src/error.rs index 042a8c9925f..150e4f3f318 100644 --- a/library/core/src/error.rs +++ b/library/core/src/error.rs @@ -928,7 +928,7 @@ pub(crate) mod tags { /// An `Option` with a type tag `I`. /// /// Since this struct implements `Erased`, the type can be erased to make a dynamically typed -/// option. The type can be checked dynamically using `Erased::tag_id` and since this is statically +/// option. The type can be checked dynamically using `Tagged::tag_id` and since this is statically /// checked for the concrete type, there is some degree of type safety. #[repr(transparent)] pub(crate) struct TaggedOption<'a, I: tags::Type<'a>>(pub Option<I::Reified>); diff --git a/library/core/src/future/async_drop.rs b/library/core/src/future/async_drop.rs index 5c3a0a98b10..63193bbfb35 100644 --- a/library/core/src/future/async_drop.rs +++ b/library/core/src/future/async_drop.rs @@ -1,4 +1,4 @@ -#![unstable(feature = "async_drop", issue = "none")] +#![unstable(feature = "async_drop", issue = "126482")] use crate::fmt; use crate::future::{Future, IntoFuture}; @@ -10,27 +10,27 @@ use crate::task::{ready, Context, Poll}; /// Asynchronously drops a value by running `AsyncDrop::async_drop` /// on a value and its fields recursively. -#[unstable(feature = "async_drop", issue = "none")] +#[unstable(feature = "async_drop", issue = "126482")] pub fn async_drop<T>(value: T) -> AsyncDropOwning<T> { AsyncDropOwning { value: MaybeUninit::new(value), dtor: None, _pinned: PhantomPinned } } /// A future returned by the [`async_drop`]. -#[unstable(feature = "async_drop", issue = "none")] +#[unstable(feature = "async_drop", issue = "126482")] pub struct AsyncDropOwning<T> { value: MaybeUninit<T>, dtor: Option<AsyncDropInPlace<T>>, _pinned: PhantomPinned, } -#[unstable(feature = "async_drop", issue = "none")] +#[unstable(feature = "async_drop", issue = "126482")] impl<T> fmt::Debug for AsyncDropOwning<T> { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { f.debug_struct("AsyncDropOwning").finish_non_exhaustive() } } -#[unstable(feature = "async_drop", issue = "none")] +#[unstable(feature = "async_drop", issue = "126482")] impl<T> Future for AsyncDropOwning<T> { type Output = (); @@ -86,24 +86,24 @@ unsafe fn async_drop_in_place_raw<T: ?Sized>( /// returned future stores the `to_drop` pointer and user is required /// to guarantee that dropped value doesn't move. /// -#[unstable(feature = "async_drop", issue = "none")] +#[unstable(feature = "async_drop", issue = "126482")] pub unsafe fn async_drop_in_place<T: ?Sized>(to_drop: *mut T) -> AsyncDropInPlace<T> { // SAFETY: `async_drop_in_place_raw` has the same safety requirements unsafe { AsyncDropInPlace(async_drop_in_place_raw(to_drop)) } } /// A future returned by the [`async_drop_in_place`]. -#[unstable(feature = "async_drop", issue = "none")] +#[unstable(feature = "async_drop", issue = "126482")] pub struct AsyncDropInPlace<T: ?Sized>(<T as AsyncDestruct>::AsyncDestructor); -#[unstable(feature = "async_drop", issue = "none")] +#[unstable(feature = "async_drop", issue = "126482")] impl<T: ?Sized> fmt::Debug for AsyncDropInPlace<T> { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { f.debug_struct("AsyncDropInPlace").finish_non_exhaustive() } } -#[unstable(feature = "async_drop", issue = "none")] +#[unstable(feature = "async_drop", issue = "126482")] impl<T: ?Sized> Future for AsyncDropInPlace<T> { type Output = (); @@ -117,18 +117,18 @@ impl<T: ?Sized> Future for AsyncDropInPlace<T> { // FIXME(zetanumbers): Add same restrictions on AsyncDrop impls as // with Drop impls /// Custom code within the asynchronous destructor. -#[unstable(feature = "async_drop", issue = "none")] +#[unstable(feature = "async_drop", issue = "126482")] #[lang = "async_drop"] pub trait AsyncDrop { /// A future returned by the [`AsyncDrop::async_drop`] to be part /// of the async destructor. - #[unstable(feature = "async_drop", issue = "none")] + #[unstable(feature = "async_drop", issue = "126482")] type Dropper<'a>: Future<Output = ()> where Self: 'a; /// Constructs the asynchronous destructor for this type. - #[unstable(feature = "async_drop", issue = "none")] + #[unstable(feature = "async_drop", issue = "126482")] fn async_drop(self: Pin<&mut Self>) -> Self::Dropper<'_>; } diff --git a/library/core/src/future/mod.rs b/library/core/src/future/mod.rs index 873cccc7e96..3a1451abfa4 100644 --- a/library/core/src/future/mod.rs +++ b/library/core/src/future/mod.rs @@ -37,7 +37,7 @@ pub use ready::{ready, Ready}; #[stable(feature = "future_poll_fn", since = "1.64.0")] pub use poll_fn::{poll_fn, PollFn}; -#[unstable(feature = "async_drop", issue = "none")] +#[unstable(feature = "async_drop", issue = "126482")] pub use async_drop::{async_drop, async_drop_in_place, AsyncDrop, AsyncDropInPlace}; /// This type is needed because: diff --git a/library/core/src/num/int_macros.rs b/library/core/src/num/int_macros.rs index 55bb6166f10..44889484963 100644 --- a/library/core/src/num/int_macros.rs +++ b/library/core/src/num/int_macros.rs @@ -2784,8 +2784,10 @@ macro_rules! int_impl { /// /// In other words, the result is `self / rhs` rounded to the integer `q` /// such that `self >= q * rhs`. - /// If `self > 0`, this is equal to round towards zero (the default in Rust); - /// if `self < 0`, this is equal to round towards +/- infinity. + /// If `self > 0`, this is equal to rounding towards zero (the default in Rust); + /// if `self < 0`, this is equal to rounding away from zero (towards +/- infinity). + /// If `rhs > 0`, this is equal to rounding towards -infinity; + /// if `rhs < 0`, this is equal to rounding towards +infinity. /// /// # Panics /// @@ -2823,8 +2825,8 @@ macro_rules! int_impl { /// Calculates the least nonnegative remainder of `self (mod rhs)`. /// /// This is done as if by the Euclidean division algorithm -- given - /// `r = self.rem_euclid(rhs)`, `self = rhs * self.div_euclid(rhs) + r`, and - /// `0 <= r < abs(rhs)`. + /// `r = self.rem_euclid(rhs)`, the result satisfies + /// `self = rhs * self.div_euclid(rhs) + r` and `0 <= r < abs(rhs)`. /// /// # Panics /// diff --git a/library/core/src/panic.rs b/library/core/src/panic.rs index b5a0932221a..56ede02673c 100644 --- a/library/core/src/panic.rs +++ b/library/core/src/panic.rs @@ -12,6 +12,8 @@ use crate::any::Any; pub use self::location::Location; #[stable(feature = "panic_hooks", since = "1.10.0")] pub use self::panic_info::PanicInfo; +#[unstable(feature = "panic_info_message", issue = "66745")] +pub use self::panic_info::PanicMessage; #[stable(feature = "catch_unwind", since = "1.9.0")] pub use self::unwind_safe::{AssertUnwindSafe, RefUnwindSafe, UnwindSafe}; diff --git a/library/core/src/panic/panic_info.rs b/library/core/src/panic/panic_info.rs index 78cf1d2e98e..91953fd656b 100644 --- a/library/core/src/panic/panic_info.rs +++ b/library/core/src/panic/panic_info.rs @@ -1,4 +1,4 @@ -use crate::fmt; +use crate::fmt::{self, Display}; use crate::panic::Location; /// A struct providing information about a panic. @@ -18,6 +18,17 @@ pub struct PanicInfo<'a> { force_no_backtrace: bool, } +/// A message that was given to the `panic!()` macro. +/// +/// The [`Display`] implementation of this type will format the message with the arguments +/// that were given to the `panic!()` macro. +/// +/// See [`PanicInfo::message`]. +#[unstable(feature = "panic_info_message", issue = "66745")] +pub struct PanicMessage<'a> { + message: fmt::Arguments<'a>, +} + impl<'a> PanicInfo<'a> { #[inline] pub(crate) fn new( @@ -29,12 +40,26 @@ impl<'a> PanicInfo<'a> { PanicInfo { location, message, can_unwind, force_no_backtrace } } - /// The message that was given to the `panic!` macro, - /// ready to be formatted with e.g. [`fmt::write`]. + /// The message that was given to the `panic!` macro. + /// + /// # Example + /// + /// The type returned by this method implements `Display`, so it can + /// be passed directly to [`write!()`] and similar macros. + /// + /// [`write!()`]: core::write + /// + /// ```ignore (no_std) + /// #[panic_handler] + /// fn panic_handler(panic_info: &PanicInfo<'_>) -> ! { + /// write!(DEBUG_OUTPUT, "panicked: {}", panic_info.message()); + /// loop {} + /// } + /// ``` #[must_use] #[unstable(feature = "panic_info_message", issue = "66745")] - pub fn message(&self) -> fmt::Arguments<'_> { - self.message + pub fn message(&self) -> PanicMessage<'_> { + PanicMessage { message: self.message } } /// Returns information about the location from which the panic originated, @@ -116,7 +141,7 @@ impl<'a> PanicInfo<'a> { } #[stable(feature = "panic_hook_display", since = "1.26.0")] -impl fmt::Display for PanicInfo<'_> { +impl Display for PanicInfo<'_> { fn fmt(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result { formatter.write_str("panicked at ")?; self.location.fmt(formatter)?; @@ -125,3 +150,41 @@ impl fmt::Display for PanicInfo<'_> { Ok(()) } } + +impl<'a> PanicMessage<'a> { + /// Get the formatted message, if it has no arguments to be formatted at runtime. + /// + /// This can be used to avoid allocations in some cases. + /// + /// # Guarantees + /// + /// For `panic!("just a literal")`, this function is guaranteed to + /// return `Some("just a literal")`. + /// + /// For most cases with placeholders, this function will return `None`. + /// + /// See [`fmt::Arguments::as_str`] for details. + #[unstable(feature = "panic_info_message", issue = "66745")] + #[rustc_const_unstable(feature = "const_arguments_as_str", issue = "103900")] + #[must_use] + #[inline] + pub const fn as_str(&self) -> Option<&'static str> { + self.message.as_str() + } +} + +#[unstable(feature = "panic_info_message", issue = "66745")] +impl Display for PanicMessage<'_> { + #[inline] + fn fmt(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result { + formatter.write_fmt(self.message) + } +} + +#[unstable(feature = "panic_info_message", issue = "66745")] +impl fmt::Debug for PanicMessage<'_> { + #[inline] + fn fmt(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result { + formatter.write_fmt(self.message) + } +} diff --git a/library/core/src/ptr/mod.rs b/library/core/src/ptr/mod.rs index 6661f6ee78b..a8a47b69632 100644 --- a/library/core/src/ptr/mod.rs +++ b/library/core/src/ptr/mod.rs @@ -237,7 +237,7 @@ //! pointer. For code which *does* cast a usize to a pointer, the scope of the change depends //! on exactly what you're doing. //! -//! In general you just need to make sure that if you want to convert a usize address to a +//! In general, you just need to make sure that if you want to convert a usize address to a //! pointer and then use that pointer to read/write memory, you need to keep around a pointer //! that has sufficient provenance to perform that read/write itself. In this way all of your //! casts from an address to a pointer are essentially just applying offsets/indexing. @@ -309,7 +309,7 @@ //! i.e. the usual "ZSTs are fake, do what you want" rules apply *but* this only applies //! for actual forgery (integers cast to pointers). If you borrow some struct's field //! that *happens* to be zero-sized, the resulting pointer will have provenance tied to -//! that allocation and it will still get invalidated if the allocation gets deallocated. +//! that allocation, and it will still get invalidated if the allocation gets deallocated. //! In the future we may introduce an API to make such a forged allocation explicit. //! //! * [`wrapping_offset`][] a pointer outside its provenance. This includes pointers @@ -698,7 +698,7 @@ pub const fn dangling_mut<T>() -> *mut T { /// /// If there is no 'exposed' provenance that justifies the way this pointer will be used, /// the program has undefined behavior. In particular, the aliasing rules still apply: pointers -/// and references that have been invalidated due to aliasing accesses cannot be used any more, +/// and references that have been invalidated due to aliasing accesses cannot be used anymore, /// even if they have been exposed! /// /// Note that there is no algorithm that decides which provenance will be used. You can think of this @@ -1097,7 +1097,7 @@ const unsafe fn swap_nonoverlapping_simple_untyped<T>(x: *mut T, y: *mut T, coun // If we end up here, it's because we're using a simple type -- like // a small power-of-two-sized thing -- or a special type with particularly // large alignment, particularly SIMD types. - // Thus we're fine just reading-and-writing it, as either it's small + // Thus, we're fine just reading-and-writing it, as either it's small // and that works well anyway or it's special and the type's author // presumably wanted things to be done in the larger chunk. @@ -1290,7 +1290,7 @@ pub const unsafe fn read<T>(src: *const T) -> T { // provides enough information to know that this is a typed operation. // However, as of March 2023 the compiler was not capable of taking advantage - // of that information. Thus the implementation here switched to an intrinsic, + // of that information. Thus, the implementation here switched to an intrinsic, // which lowers to `_0 = *src` in MIR, to address a few issues: // // - Using `MaybeUninit::assume_init` after a `copy_nonoverlapping` was not @@ -1570,7 +1570,7 @@ pub const unsafe fn write<T>(dst: *mut T, src: T) { /// As a result, using `&packed.unaligned as *const FieldType` causes immediate /// *undefined behavior* in your program. /// -/// Instead you must use the [`ptr::addr_of_mut!`](addr_of_mut) +/// Instead, you must use the [`ptr::addr_of_mut!`](addr_of_mut) /// macro to create the pointer. You may use that returned pointer together with /// this function. /// diff --git a/library/core/src/slice/rotate.rs b/library/core/src/slice/rotate.rs index fa8c238f8e7..1d7b8633979 100644 --- a/library/core/src/slice/rotate.rs +++ b/library/core/src/slice/rotate.rs @@ -71,7 +71,9 @@ pub unsafe fn ptr_rotate<T>(mut left: usize, mut mid: *mut T, mut right: usize) if (right == 0) || (left == 0) { return; } - if (left + right < 24) || (mem::size_of::<T>() > mem::size_of::<[usize; 4]>()) { + if !cfg!(feature = "optimize_for_size") + && ((left + right < 24) || (mem::size_of::<T>() > 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<T>(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::<BufType>() / mem::size_of::<T>() { + } else if !cfg!(feature = "optimize_for_size") + && cmp::min(left, right) <= mem::size_of::<BufType>() / mem::size_of::<T>() + { // 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/core/src/sync/atomic.rs b/library/core/src/sync/atomic.rs index 482bd19705c..c709ea2a15d 100644 --- a/library/core/src/sync/atomic.rs +++ b/library/core/src/sync/atomic.rs @@ -183,7 +183,7 @@ //! //! let spinlock_clone = Arc::clone(&spinlock); //! -//! let thread = thread::spawn(move|| { +//! let thread = thread::spawn(move || { //! spinlock_clone.store(0, Ordering::Release); //! }); //! diff --git a/library/std/src/backtrace.rs b/library/std/src/backtrace.rs index e3e0cde8afe..4d376753cb6 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 b240e4e2c45..87aad8f764b 100644 --- a/library/std/src/error.rs +++ b/library/std/src/error.rs @@ -429,7 +429,7 @@ impl<E> Report<E> { /// 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/os/hermit/io/mod.rs b/library/std/src/os/hermit/io/mod.rs index 524dfae0d63..df93f63a003 100644 --- a/library/std/src/os/hermit/io/mod.rs +++ b/library/std/src/os/hermit/io/mod.rs @@ -1,13 +1,4 @@ -#![stable(feature = "os_fd", since = "1.66.0")] +#![stable(feature = "rust1", since = "1.0.0")] -mod net; -#[path = "../../fd/owned.rs"] -mod owned; -#[path = "../../fd/raw.rs"] -mod raw; - -// Export the types and traits for the public API. -#[stable(feature = "os_fd", since = "1.66.0")] -pub use owned::*; -#[stable(feature = "os_fd", since = "1.66.0")] -pub use raw::*; +#[stable(feature = "rust1", since = "1.0.0")] +pub use crate::os::fd::*; diff --git a/library/std/src/os/mod.rs b/library/std/src/os/mod.rs index ca3584e82f9..d2a7b316b81 100644 --- a/library/std/src/os/mod.rs +++ b/library/std/src/os/mod.rs @@ -160,7 +160,7 @@ pub(crate) mod watchos; #[cfg(target_os = "xous")] pub mod xous; -#[cfg(any(unix, target_os = "wasi", doc))] +#[cfg(any(unix, target_os = "hermit", target_os = "wasi", doc))] pub mod fd; #[cfg(any(target_os = "linux", target_os = "android", doc))] diff --git a/library/std/src/panicking.rs b/library/std/src/panicking.rs index 8fd8134c111..ebd05415695 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))] @@ -593,19 +593,18 @@ pub fn panicking() -> bool { #[panic_handler] pub fn begin_panic_handler(info: &core::panic::PanicInfo<'_>) -> ! { struct FormatStringPayload<'a> { - inner: &'a fmt::Arguments<'a>, + inner: &'a core::panic::PanicMessage<'a>, string: Option<String>, } impl FormatStringPayload<'_> { fn fill(&mut self) -> &mut String { - use crate::fmt::Write; - let inner = self.inner; // Lazily, the first time this gets called, run the actual string formatting. self.string.get_or_insert_with(|| { let mut s = String::new(); - let _err = s.write_fmt(*inner); + let mut fmt = fmt::Formatter::new(&mut s); + let _err = fmt::Display::fmt(&inner, &mut fmt); s }) } @@ -627,7 +626,11 @@ pub fn begin_panic_handler(info: &core::panic::PanicInfo<'_>) -> ! { impl fmt::Display for FormatStringPayload<'_> { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - if let Some(s) = &self.string { f.write_str(s) } else { f.write_fmt(*self.inner) } + if let Some(s) = &self.string { + f.write_str(s) + } else { + fmt::Display::fmt(&self.inner, f) + } } } @@ -655,7 +658,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 +730,7 @@ pub const fn begin_panic<M: Any + Send>(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/rt.rs b/library/std/src/rt.rs index 46f691d7b75..b03fa1c01f2 100644 --- a/library/std/src/rt.rs +++ b/library/std/src/rt.rs @@ -156,7 +156,7 @@ fn lang_start<T: crate::process::Termination + 'static>( 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/barrier.rs b/library/std/src/sync/barrier.rs index b4bac081e7a..82cc13a74b7 100644 --- a/library/std/src/sync/barrier.rs +++ b/library/std/src/sync/barrier.rs @@ -20,7 +20,7 @@ use crate::sync::{Condvar, Mutex}; /// let c = Arc::clone(&barrier); /// // The same messages will be printed together. /// // You will NOT see any interleaving. -/// handles.push(thread::spawn(move|| { +/// handles.push(thread::spawn(move || { /// println!("before wait"); /// c.wait(); /// println!("after wait"); @@ -115,7 +115,7 @@ impl Barrier { /// let c = Arc::clone(&barrier); /// // The same messages will be printed together. /// // You will NOT see any interleaving. - /// handles.push(thread::spawn(move|| { + /// handles.push(thread::spawn(move || { /// println!("before wait"); /// c.wait(); /// println!("after wait"); diff --git a/library/std/src/sync/condvar.rs b/library/std/src/sync/condvar.rs index b20574e4f14..f9f83fb4f63 100644 --- a/library/std/src/sync/condvar.rs +++ b/library/std/src/sync/condvar.rs @@ -88,7 +88,7 @@ impl WaitTimeoutResult { /// let pair2 = Arc::clone(&pair); /// /// // Inside of our lock, spawn a new thread, and then wait for it to start. -/// thread::spawn(move|| { +/// thread::spawn(move || { /// let (lock, cvar) = &*pair2; /// let mut started = lock.lock().unwrap(); /// *started = true; @@ -166,7 +166,7 @@ impl Condvar { /// let pair = Arc::new((Mutex::new(false), Condvar::new())); /// let pair2 = Arc::clone(&pair); /// - /// thread::spawn(move|| { + /// thread::spawn(move || { /// let (lock, cvar) = &*pair2; /// let mut started = lock.lock().unwrap(); /// *started = true; @@ -221,7 +221,7 @@ impl Condvar { /// let pair = Arc::new((Mutex::new(true), Condvar::new())); /// let pair2 = Arc::clone(&pair); /// - /// thread::spawn(move|| { + /// thread::spawn(move || { /// let (lock, cvar) = &*pair2; /// let mut pending = lock.lock().unwrap(); /// *pending = false; @@ -280,7 +280,7 @@ impl Condvar { /// let pair = Arc::new((Mutex::new(false), Condvar::new())); /// let pair2 = Arc::clone(&pair); /// - /// thread::spawn(move|| { + /// thread::spawn(move || { /// let (lock, cvar) = &*pair2; /// let mut started = lock.lock().unwrap(); /// *started = true; @@ -352,7 +352,7 @@ impl Condvar { /// let pair = Arc::new((Mutex::new(false), Condvar::new())); /// let pair2 = Arc::clone(&pair); /// - /// thread::spawn(move|| { + /// thread::spawn(move || { /// let (lock, cvar) = &*pair2; /// let mut started = lock.lock().unwrap(); /// *started = true; @@ -420,7 +420,7 @@ impl Condvar { /// let pair = Arc::new((Mutex::new(true), Condvar::new())); /// let pair2 = Arc::clone(&pair); /// - /// thread::spawn(move|| { + /// thread::spawn(move || { /// let (lock, cvar) = &*pair2; /// let mut pending = lock.lock().unwrap(); /// *pending = false; @@ -484,7 +484,7 @@ impl Condvar { /// let pair = Arc::new((Mutex::new(false), Condvar::new())); /// let pair2 = Arc::clone(&pair); /// - /// thread::spawn(move|| { + /// thread::spawn(move || { /// let (lock, cvar) = &*pair2; /// let mut started = lock.lock().unwrap(); /// *started = true; @@ -524,7 +524,7 @@ impl Condvar { /// let pair = Arc::new((Mutex::new(false), Condvar::new())); /// let pair2 = Arc::clone(&pair); /// - /// thread::spawn(move|| { + /// thread::spawn(move || { /// let (lock, cvar) = &*pair2; /// let mut started = lock.lock().unwrap(); /// *started = true; diff --git a/library/std/src/sync/mpsc/mod.rs b/library/std/src/sync/mpsc/mod.rs index d353c7bd5de..feee6948db4 100644 --- a/library/std/src/sync/mpsc/mod.rs +++ b/library/std/src/sync/mpsc/mod.rs @@ -51,7 +51,7 @@ //! //! // Create a simple streaming channel //! let (tx, rx) = channel(); -//! thread::spawn(move|| { +//! thread::spawn(move || { //! tx.send(10).unwrap(); //! }); //! assert_eq!(rx.recv().unwrap(), 10); @@ -69,7 +69,7 @@ //! let (tx, rx) = channel(); //! for i in 0..10 { //! let tx = tx.clone(); -//! thread::spawn(move|| { +//! thread::spawn(move || { //! tx.send(i).unwrap(); //! }); //! } @@ -99,7 +99,7 @@ //! use std::sync::mpsc::sync_channel; //! //! let (tx, rx) = sync_channel::<i32>(0); -//! thread::spawn(move|| { +//! thread::spawn(move || { //! // This will wait for the parent thread to start receiving //! tx.send(53).unwrap(); //! }); @@ -510,7 +510,7 @@ pub enum TrySendError<T> { /// let (sender, receiver) = channel(); /// /// // Spawn off an expensive computation -/// thread::spawn(move|| { +/// thread::spawn(move || { /// # fn expensive_computation() {} /// sender.send(expensive_computation()).unwrap(); /// }); @@ -561,7 +561,7 @@ pub fn channel<T>() -> (Sender<T>, Receiver<T>) { /// // this returns immediately /// sender.send(1).unwrap(); /// -/// thread::spawn(move|| { +/// thread::spawn(move || { /// // this will block until the previous message has been received /// sender.send(2).unwrap(); /// }); diff --git a/library/std/src/sys_common/backtrace.rs b/library/std/src/sys/backtrace.rs index 67711dbd5bc..0b2338fd7de 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 8f70cefc601..8aa35c40fe0 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_common/mod.rs b/library/std/src/sys_common/mod.rs index 3a38ba1100f..200ea028a08 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/local.rs b/library/std/src/thread/local.rs index aed185637fd..f147c5fdcd1 100644 --- a/library/std/src/thread/local.rs +++ b/library/std/src/thread/local.rs @@ -62,7 +62,7 @@ use crate::fmt; /// FOO.set(2); /// /// // each thread starts out with the initial value of 1 -/// let t = thread::spawn(move|| { +/// let t = thread::spawn(move || { /// assert_eq!(FOO.get(), 1); /// FOO.set(3); /// }); diff --git a/library/std/src/thread/mod.rs b/library/std/src/thread/mod.rs index 83e27dfb746..c8ee365392f 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 127699b8641..9c24742cff1 100644 --- a/src/bootstrap/Cargo.lock +++ b/src/bootstrap/Cargo.lock @@ -18,12 +18,6 @@ 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" source = "registry+https://github.com/rust-lang/crates.io-index" @@ -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/src/core/build_steps/clippy.rs b/src/bootstrap/src/core/build_steps/clippy.rs index 01b5e99116f..40a2112b192 100644 --- a/src/bootstrap/src/core/build_steps/clippy.rs +++ b/src/bootstrap/src/core/build_steps/clippy.rs @@ -322,7 +322,6 @@ lint_any!( RemoteTestServer, "src/tools/remote-test-server", "remote-test-server"; Rls, "src/tools/rls", "rls"; RustAnalyzer, "src/tools/rust-analyzer", "rust-analyzer"; - RustDemangler, "src/tools/rust-demangler", "rust-demangler"; Rustdoc, "src/tools/rustdoc", "clippy"; Rustfmt, "src/tools/rustfmt", "rustfmt"; RustInstaller, "src/tools/rust-installer", "rust-installer"; diff --git a/src/bootstrap/src/core/build_steps/dist.rs b/src/bootstrap/src/core/build_steps/dist.rs index f651f751441..54136d2aebd 100644 --- a/src/bootstrap/src/core/build_steps/dist.rs +++ b/src/bootstrap/src/core/build_steps/dist.rs @@ -1460,62 +1460,6 @@ impl Step for Rustfmt { } #[derive(Debug, PartialOrd, Ord, Clone, Hash, PartialEq, Eq)] -pub struct RustDemangler { - pub compiler: Compiler, - pub target: TargetSelection, -} - -impl Step for RustDemangler { - type Output = Option<GeneratedTarball>; - const DEFAULT: bool = true; - const ONLY_HOSTS: bool = true; - - fn should_run(run: ShouldRun<'_>) -> ShouldRun<'_> { - // While other tools use `should_build_extended_tool` to decide whether to be run by - // default or not, `rust-demangler` must be build when *either* it's enabled as a tool like - // the other ones or if `profiler = true`. Because we don't know the target at this stage - // we run the step by default when only `extended = true`, and decide whether to actually - // run it or not later. - let default = run.builder.config.extended; - run.alias("rust-demangler").default_condition(default) - } - - fn make_run(run: RunConfig<'_>) { - run.builder.ensure(RustDemangler { - compiler: run.builder.compiler_for( - run.builder.top_stage, - run.builder.config.build, - run.target, - ), - target: run.target, - }); - } - - fn run(self, builder: &Builder<'_>) -> Option<GeneratedTarball> { - let compiler = self.compiler; - let target = self.target; - - // Only build this extended tool if explicitly included in `tools`, or if `profiler = true` - let condition = should_build_extended_tool(builder, "rust-demangler") - || builder.config.profiler_enabled(target); - if builder.config.extended && !condition { - return None; - } - - let rust_demangler = - builder.ensure(tool::RustDemangler { compiler, target, extra_features: Vec::new() }); - - // Prepare the image directory - let mut tarball = Tarball::new(builder, "rust-demangler", &target.triple); - tarball.set_overlay(OverlayKind::RustDemangler); - tarball.is_preview(true); - tarball.add_file(rust_demangler, "bin", 0o755); - tarball.add_legal_and_readme_to("share/doc/rust-demangler"); - Some(tarball.generate()) - } -} - -#[derive(Debug, PartialOrd, Ord, Clone, Hash, PartialEq, Eq)] pub struct Extended { stage: u32, host: TargetSelection, @@ -1572,7 +1516,6 @@ impl Step for Extended { add_component!("rust-docs" => Docs { host: target }); add_component!("rust-json-docs" => JsonDocs { host: target }); - add_component!("rust-demangler"=> RustDemangler { compiler, target }); add_component!("cargo" => Cargo { compiler, target }); add_component!("rustfmt" => Rustfmt { compiler, target }); add_component!("rls" => Rls { compiler, target }); @@ -1636,7 +1579,7 @@ impl Step for Extended { let xform = |p: &Path| { let mut contents = t!(fs::read_to_string(p)); - for tool in &["rust-demangler", "miri", "rust-docs"] { + for tool in &["miri", "rust-docs"] { if !built_tools.contains(tool) { contents = filter(&contents, tool); } @@ -1677,7 +1620,7 @@ impl Step for Extended { prepare("rust-analysis"); prepare("clippy"); prepare("rust-analyzer"); - for tool in &["rust-docs", "rust-demangler", "miri", "rustc-codegen-cranelift"] { + for tool in &["rust-docs", "miri", "rustc-codegen-cranelift"] { if built_tools.contains(tool) { prepare(tool); } @@ -1717,8 +1660,6 @@ impl Step for Extended { "rust-analyzer-preview".to_string() } else if name == "clippy" { "clippy-preview".to_string() - } else if name == "rust-demangler" { - "rust-demangler-preview".to_string() } else if name == "miri" { "miri-preview".to_string() } else if name == "rustc-codegen-cranelift" { @@ -1738,7 +1679,7 @@ impl Step for Extended { prepare("cargo"); prepare("rust-analysis"); prepare("rust-std"); - for tool in &["clippy", "rust-analyzer", "rust-docs", "rust-demangler", "miri"] { + for tool in &["clippy", "rust-analyzer", "rust-docs", "miri"] { if built_tools.contains(tool) { prepare(tool); } @@ -1862,25 +1803,6 @@ impl Step for Extended { .arg(etc.join("msi/remove-duplicates.xsl")), ); } - if built_tools.contains("rust-demangler") { - builder.run( - Command::new(&heat) - .current_dir(&exe) - .arg("dir") - .arg("rust-demangler") - .args(heat_flags) - .arg("-cg") - .arg("RustDemanglerGroup") - .arg("-dr") - .arg("RustDemangler") - .arg("-var") - .arg("var.RustDemanglerDir") - .arg("-out") - .arg(exe.join("RustDemanglerGroup.wxs")) - .arg("-t") - .arg(etc.join("msi/remove-duplicates.xsl")), - ); - } if built_tools.contains("miri") { builder.run( Command::new(&heat) @@ -1958,9 +1880,6 @@ impl Step for Extended { if built_tools.contains("rust-docs") { cmd.arg("-dDocsDir=rust-docs"); } - if built_tools.contains("rust-demangler") { - cmd.arg("-dRustDemanglerDir=rust-demangler"); - } if built_tools.contains("rust-analyzer") { cmd.arg("-dRustAnalyzerDir=rust-analyzer"); } @@ -1987,9 +1906,6 @@ impl Step for Extended { if built_tools.contains("miri") { candle("MiriGroup.wxs".as_ref()); } - if built_tools.contains("rust-demangler") { - candle("RustDemanglerGroup.wxs".as_ref()); - } if built_tools.contains("rust-analyzer") { candle("RustAnalyzerGroup.wxs".as_ref()); } @@ -2031,9 +1947,6 @@ impl Step for Extended { if built_tools.contains("rust-analyzer") { cmd.arg("RustAnalyzerGroup.wixobj"); } - if built_tools.contains("rust-demangler") { - cmd.arg("RustDemanglerGroup.wixobj"); - } if built_tools.contains("rust-docs") { cmd.arg("DocsGroup.wixobj"); } diff --git a/src/bootstrap/src/core/build_steps/install.rs b/src/bootstrap/src/core/build_steps/install.rs index 6a75f35c93a..c47233ca42a 100644 --- a/src/bootstrap/src/core/build_steps/install.rs +++ b/src/bootstrap/src/core/build_steps/install.rs @@ -265,22 +265,6 @@ install!((self, builder, _config), ); } }; - RustDemangler, alias = "rust-demangler", Self::should_build(_config), only_hosts: true, { - // NOTE: Even though `should_build` may return true for `extended` default tools, - // dist::RustDemangler may still return None, unless the target-dependent `profiler` config - // is also true, or the `tools` array explicitly includes "rust-demangler". - if let Some(tarball) = builder.ensure(dist::RustDemangler { - compiler: self.compiler, - target: self.target - }) { - install_sh(builder, "rust-demangler", self.compiler.stage, Some(self.target), &tarball); - } else { - builder.info( - &format!("skipping Install RustDemangler stage{} ({})", - self.compiler.stage, self.target), - ); - } - }; Rustc, path = "compiler/rustc", true, only_hosts: true, { let tarball = builder.ensure(dist::Rustc { compiler: builder.compiler(builder.top_stage, self.target), diff --git a/src/bootstrap/src/core/build_steps/test.rs b/src/bootstrap/src/core/build_steps/test.rs index 7556a19c90c..445096e9786 100644 --- a/src/bootstrap/src/core/build_steps/test.rs +++ b/src/bootstrap/src/core/build_steps/test.rs @@ -433,65 +433,6 @@ impl Step for Rustfmt { } #[derive(Debug, Clone, PartialEq, Eq, Hash)] -pub struct RustDemangler { - stage: u32, - host: TargetSelection, -} - -impl Step for RustDemangler { - type Output = (); - const ONLY_HOSTS: bool = true; - - fn should_run(run: ShouldRun<'_>) -> ShouldRun<'_> { - run.path("src/tools/rust-demangler") - } - - fn make_run(run: RunConfig<'_>) { - run.builder.ensure(RustDemangler { stage: run.builder.top_stage, host: run.target }); - } - - /// Runs `cargo test` for rust-demangler. - fn run(self, builder: &Builder<'_>) { - let stage = self.stage; - let host = self.host; - let compiler = builder.compiler(stage, host); - - let rust_demangler = builder.ensure(tool::RustDemangler { - compiler, - target: self.host, - extra_features: Vec::new(), - }); - let mut cargo = tool::prepare_tool_cargo( - builder, - compiler, - Mode::ToolRustc, - host, - "test", - "src/tools/rust-demangler", - SourceType::InTree, - &[], - ); - - let dir = testdir(builder, compiler.host); - t!(fs::create_dir_all(dir)); - - cargo.env("RUST_DEMANGLER_DRIVER_PATH", rust_demangler); - cargo.add_rustc_lib_path(builder); - - run_cargo_test( - cargo, - &[], - &[], - "rust-demangler", - "rust-demangler", - compiler, - host, - builder, - ); - } -} - -#[derive(Debug, Clone, PartialEq, Eq, Hash)] pub struct Miri { target: TargetSelection, } diff --git a/src/bootstrap/src/core/build_steps/tool.rs b/src/bootstrap/src/core/build_steps/tool.rs index e0a9674ae5a..613484788b6 100644 --- a/src/bootstrap/src/core/build_steps/tool.rs +++ b/src/bootstrap/src/core/build_steps/tool.rs @@ -964,7 +964,6 @@ tool_extended!((self, builder), // But `builder.cargo` doesn't know how to handle ToolBootstrap in stages other than 0, // and this is close enough for now. Rls, "src/tools/rls", "rls", stable=true, tool_std=true; - RustDemangler, "src/tools/rust-demangler", "rust-demangler", stable=false, tool_std=true; Rustfmt, "src/tools/rustfmt", "rustfmt", stable=true, add_bins_to_sysroot = ["rustfmt", "cargo-fmt"]; ); diff --git a/src/bootstrap/src/core/builder.rs b/src/bootstrap/src/core/builder.rs index d9e4cbae17d..3c4806a1311 100644 --- a/src/bootstrap/src/core/builder.rs +++ b/src/bootstrap/src/core/builder.rs @@ -736,7 +736,6 @@ impl<'a> Builder<'a> { tool::Rls, tool::RustAnalyzer, tool::RustAnalyzerProcMacroSrv, - tool::RustDemangler, tool::Rustdoc, tool::Clippy, tool::CargoClippy, @@ -774,7 +773,6 @@ impl<'a> Builder<'a> { clippy::RemoteTestServer, clippy::Rls, clippy::RustAnalyzer, - clippy::RustDemangler, clippy::Rustdoc, clippy::Rustfmt, clippy::RustInstaller, @@ -842,7 +840,6 @@ impl<'a> Builder<'a> { test::Miri, test::CargoMiri, test::Clippy, - test::RustDemangler, test::CompiletestTest, test::CrateRunMakeSupport, test::RustdocJSStd, @@ -903,7 +900,6 @@ impl<'a> Builder<'a> { dist::Rls, dist::RustAnalyzer, dist::Rustfmt, - dist::RustDemangler, dist::Clippy, dist::Miri, dist::LlvmTools, @@ -930,7 +926,6 @@ impl<'a> Builder<'a> { install::Cargo, install::RustAnalyzer, install::Rustfmt, - install::RustDemangler, install::Clippy, install::Miri, install::LlvmTools, @@ -1036,23 +1031,12 @@ impl<'a> Builder<'a> { } pub fn doc_rust_lang_org_channel(&self) -> String { - // When using precompiled compiler from CI, we need to use CI rustc's channel and - // ignore `rust.channel` from the configuration. Otherwise most of the rustdoc tests - // will fail due to incompatible `DOC_RUST_LANG_ORG_CHANNEL`. - let channel = if let Some(commit) = self.config.download_rustc_commit() { - self.config - .read_file_by_commit(&PathBuf::from("src/ci/channel"), commit) - .trim() - .to_owned() - } else { - match &*self.config.channel { - "stable" => &self.version, - "beta" => "beta", - "nightly" | "dev" => "nightly", - // custom build of rustdoc maybe? link to the latest stable docs just in case - _ => "stable", - } - .to_owned() + let channel = match &*self.config.channel { + "stable" => &self.version, + "beta" => "beta", + "nightly" | "dev" => "nightly", + // custom build of rustdoc maybe? link to the latest stable docs just in case + _ => "stable", }; format!("https://doc.rust-lang.org/{channel}") diff --git a/src/bootstrap/src/core/config/config.rs b/src/bootstrap/src/core/config/config.rs index a1d8ca3cbca..0438dee7241 100644 --- a/src/bootstrap/src/core/config/config.rs +++ b/src/bootstrap/src/core/config/config.rs @@ -1718,7 +1718,23 @@ impl Config { config.omit_git_hash = omit_git_hash.unwrap_or(default); config.rust_info = GitInfo::new(config.omit_git_hash, &config.src); - if config.rust_info.is_from_tarball() && !is_user_configured_rust_channel { + // We need to override `rust.channel` if it's manually specified when using the CI rustc. + // This is because if the compiler uses a different channel than the one specified in config.toml, + // tests may fail due to using a different channel than the one used by the compiler during tests. + if let Some(commit) = &config.download_rustc_commit { + if is_user_configured_rust_channel { + println!( + "WARNING: `rust.download-rustc` is enabled. The `rust.channel` option will be overridden by the CI rustc's channel." + ); + + let channel = config + .read_file_by_commit(&PathBuf::from("src/ci/channel"), commit) + .trim() + .to_owned(); + + config.channel = channel; + } + } else if config.rust_info.is_from_tarball() && !is_user_configured_rust_channel { ci_channel.clone_into(&mut config.channel); } diff --git a/src/bootstrap/src/lib.rs b/src/bootstrap/src/lib.rs index abf407ea91e..449d8c128ec 100644 --- a/src/bootstrap/src/lib.rs +++ b/src/bootstrap/src/lib.rs @@ -520,10 +520,12 @@ impl Build { return; } - // check_submodule - let checked_out_hash = - output(helpers::git(Some(&absolute_path)).args(["rev-parse", "HEAD"])); - // update_submodules + let submodule_git = || helpers::git(Some(&absolute_path)); + + // Determine commit checked out in submodule. + let checked_out_hash = output(submodule_git().args(["rev-parse", "HEAD"])); + let checked_out_hash = checked_out_hash.trim_end(); + // Determine commit that the submodule *should* have. let recorded = output(helpers::git(Some(&self.src)).args(["ls-tree", "HEAD"]).arg(relative_path)); let actual_hash = recorded @@ -531,8 +533,7 @@ impl Build { .nth(2) .unwrap_or_else(|| panic!("unexpected output `{}`", recorded)); - // update_submodule - if actual_hash == checked_out_hash.trim_end() { + if actual_hash == checked_out_hash { // already checked out return; } @@ -581,26 +582,22 @@ 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(helpers::git(Some(&absolute_path)).args([ - "diff-index", - "--quiet", - "HEAD", - ])) - .allow_failure() - .output_mode(match self.is_verbose() { - true => OutputMode::PrintAll, - false => OutputMode::PrintOutput, - }), + BootstrapCommand::from(submodule_git().args(["diff-index", "--quiet", "HEAD"])) + .allow_failure() + .output_mode(match self.is_verbose() { + true => OutputMode::PrintAll, + false => OutputMode::PrintOutput, + }), ); if has_local_modifications { - self.run(helpers::git(Some(&absolute_path)).args(["stash", "push"])); + self.run(submodule_git().args(["stash", "push"])); } - self.run(helpers::git(Some(&absolute_path)).args(["reset", "-q", "--hard"])); - self.run(helpers::git(Some(&absolute_path)).args(["clean", "-qdfx"])); + self.run(submodule_git().args(["reset", "-q", "--hard"])); + self.run(submodule_git().args(["clean", "-qdfx"])); if has_local_modifications { - self.run(helpers::git(Some(&absolute_path)).args(["stash", "pop"])); + self.run(submodule_git().args(["stash", "pop"])); } } diff --git a/src/bootstrap/src/utils/helpers.rs b/src/bootstrap/src/utils/helpers.rs index 13d1346b3d9..4b6dc45b436 100644 --- a/src/bootstrap/src/utils/helpers.rs +++ b/src/bootstrap/src/utils/helpers.rs @@ -501,6 +501,16 @@ pub fn git(source_dir: Option<&Path>) -> Command { if let Some(source_dir) = source_dir { git.current_dir(source_dir); + // If we are running inside git (e.g. via a hook), `GIT_DIR` is set and takes precedence + // over the current dir. Un-set it to make the current dir matter. + git.env_remove("GIT_DIR"); + // Also un-set some other variables, to be on the safe side (based on cargo's + // `fetch_with_cli`). In particular un-setting `GIT_INDEX_FILE` is required to fix some odd + // misbehavior. + git.env_remove("GIT_WORK_TREE") + .env_remove("GIT_INDEX_FILE") + .env_remove("GIT_OBJECT_DIRECTORY") + .env_remove("GIT_ALTERNATE_OBJECT_DIRECTORIES"); } git diff --git a/src/bootstrap/src/utils/tarball.rs b/src/bootstrap/src/utils/tarball.rs index 57cdf7473a1..fd934f18de2 100644 --- a/src/bootstrap/src/utils/tarball.rs +++ b/src/bootstrap/src/utils/tarball.rs @@ -23,7 +23,6 @@ pub(crate) enum OverlayKind { Clippy, Miri, Rustfmt, - RustDemangler, Rls, RustAnalyzer, RustcCodegenCranelift, @@ -58,9 +57,6 @@ impl OverlayKind { "src/tools/rustfmt/LICENSE-APACHE", "src/tools/rustfmt/LICENSE-MIT", ], - OverlayKind::RustDemangler => { - &["src/tools/rust-demangler/README.md", "LICENSE-APACHE", "LICENSE-MIT"] - } OverlayKind::Rls => &["src/tools/rls/README.md", "LICENSE-APACHE", "LICENSE-MIT"], OverlayKind::RustAnalyzer => &[ "src/tools/rust-analyzer/README.md", @@ -85,7 +81,6 @@ impl OverlayKind { match self { OverlayKind::Rust => builder.rust_version(), OverlayKind::Llvm => builder.rust_version(), - OverlayKind::RustDemangler => builder.release_num("rust-demangler"), OverlayKind::Cargo => { builder.cargo_info.version(builder, &builder.release_num("cargo")) } diff --git a/src/ci/docker/scripts/fuchsia-test-runner.py b/src/ci/docker/scripts/fuchsia-test-runner.py index d791550a8db..115ee69a589 100755 --- a/src/ci/docker/scripts/fuchsia-test-runner.py +++ b/src/ci/docker/scripts/fuchsia-test-runner.py @@ -8,34 +8,137 @@ https://doc.rust-lang.org/stable/rustc/platform-support/fuchsia.html#aarch64-unk """ import argparse +from concurrent.futures import ThreadPoolExecutor from dataclasses import dataclass import glob -import hashlib +import io import json +import logging import os import platform +import shlex import shutil import subprocess import sys -from typing import ClassVar, List - - -@dataclass +from pathlib import Path +from typing import ClassVar, List, Optional + + +def check_call_with_logging( + args, *, stdout_handler, stderr_handler, check=True, text=True, **kwargs +): + stdout_handler(f"Subprocess: {shlex.join(str(arg) for arg in args)}") + + with subprocess.Popen( + args, + text=text, + stdout=subprocess.PIPE, + stderr=subprocess.PIPE, + **kwargs, + ) as process: + with ThreadPoolExecutor(max_workers=2) as executor: + + def exhaust_pipe(handler, pipe): + for line in pipe: + handler(line.rstrip()) + + executor_out = executor.submit( + exhaust_pipe, stdout_handler, process.stdout + ) + executor_err = executor.submit( + exhaust_pipe, stderr_handler, process.stderr + ) + executor_out.result() + executor_err.result() + retcode = process.poll() + if check and retcode: + raise subprocess.CalledProcessError(retcode, process.args) + return subprocess.CompletedProcess(process.args, retcode) + + +def check_output_with_logging( + args, *, stdout_handler, stderr_handler, check=True, text=True, **kwargs +): + stdout_handler(f"Subprocess: {shlex.join(str(arg) for arg in args)}") + + buf = io.StringIO() + + with subprocess.Popen( + args, + text=text, + stdout=subprocess.PIPE, + stderr=subprocess.PIPE, + **kwargs, + ) as process: + with ThreadPoolExecutor(max_workers=2) as executor: + + def exhaust_stdout(handler, buf, pipe): + for line in pipe: + handler(line.rstrip()) + buf.write(line) + buf.write("\n") + + def exhaust_stderr(handler, pipe): + for line in pipe: + handler(line.rstrip()) + + executor_out = executor.submit( + exhaust_stdout, stdout_handler, buf, process.stdout + ) + executor_err = executor.submit( + exhaust_stderr, stderr_handler, process.stderr + ) + executor_out.result() + executor_err.result() + retcode = process.poll() + if check and retcode: + raise subprocess.CalledProcessError(retcode, process.args) + + return buf.getvalue() + + +def atomic_link(link: Path, target: Path): + link_dir = link.parent + os.makedirs(link_dir, exist_ok=True) + link_file = link.name + tmp_file = link_dir.joinpath(link_file + "_tmp") + os.link(target, tmp_file) + try: + os.rename(tmp_file, link) + except Exception as e: + raise e + finally: + if tmp_file.exists(): + os.remove(tmp_file) + + +@dataclass(kw_only=True) class TestEnvironment: - rust_build_dir: str - sdk_dir: str + rust_build_dir: Path + sdk_dir: Path target: str + toolchain_dir: Path + local_pb_path: Optional[Path] + use_local_pb: bool verbose: bool = False + env_logger = logging.getLogger("env") + subprocess_logger = logging.getLogger("env.subprocess") + __tmp_dir = None + @staticmethod - def tmp_dir(): + def tmp_dir() -> Path: + if TestEnvironment.__tmp_dir: + return TestEnvironment.__tmp_dir tmp_dir = os.environ.get("TEST_TOOLCHAIN_TMP_DIR") if tmp_dir is not None: - return os.path.abspath(tmp_dir) - return os.path.join(os.path.dirname(__file__), "tmp~") + TestEnvironment.__tmp_dir = Path(tmp_dir).absolute() + else: + TestEnvironment.__tmp_dir = Path(__file__).parent.joinpath("tmp~") + return TestEnvironment.__tmp_dir @staticmethod - def triple_to_arch(triple): + def triple_to_arch(triple) -> str: if "x86_64" in triple: return "x64" elif "aarch64" in triple: @@ -44,61 +147,175 @@ class TestEnvironment: raise Exception(f"Unrecognized target triple {triple}") @classmethod - def env_file_path(cls): - return os.path.join(cls.tmp_dir(), "test_env.json") + def env_file_path(cls) -> Path: + return cls.tmp_dir().joinpath("test_env.json") @classmethod def from_args(cls, args): + local_pb_path = args.local_product_bundle_path + if local_pb_path is not None: + local_pb_path = Path(local_pb_path).absolute() + return cls( - os.path.abspath(args.rust_build), - os.path.abspath(args.sdk), - args.target, + rust_build_dir=Path(args.rust_build).absolute(), + sdk_dir=Path(args.sdk).absolute(), + target=args.target, + toolchain_dir=Path(args.toolchain_dir).absolute(), + local_pb_path=local_pb_path, + use_local_pb=args.use_local_product_bundle_if_exists, verbose=args.verbose, ) @classmethod def read_from_file(cls): with open(cls.env_file_path(), encoding="utf-8") as f: - test_env = json.loads(f.read()) + test_env = json.load(f) + local_pb_path = test_env["local_pb_path"] + if local_pb_path is not None: + local_pb_path = Path(local_pb_path) + return cls( - test_env["rust_build_dir"], - test_env["sdk_dir"], - test_env["target"], + rust_build_dir=Path(test_env["rust_build_dir"]), + sdk_dir=Path(test_env["sdk_dir"]), + target=test_env["target"], + toolchain_dir=Path(test_env["toolchain_dir"]), + local_pb_path=local_pb_path, + use_local_pb=test_env["use_local_pb"], verbose=test_env["verbose"], ) + def build_id(self, binary): + llvm_readelf = Path(self.toolchain_dir).joinpath("bin", "llvm-readelf") + process = subprocess.run( + args=[ + llvm_readelf, + "-n", + "--elf-output-style=JSON", + binary, + ], + stdout=subprocess.PIPE, + stderr=subprocess.STDOUT, + ) + if process.returncode: + self.env_logger.error( + f"llvm-readelf failed for binary {binary} with output {process.stdout}" + ) + raise Exception(f"Unreadable build-id for binary {binary}") + data = json.loads(process.stdout) + if len(data) != 1: + raise Exception( + f"Unreadable output from llvm-readelf for binary {binary}" + ) + notes = data[0]["Notes"] + for note in notes: + note_section = note["NoteSection"] + if note_section["Name"] == ".note.gnu.build-id": + return note_section["Note"]["Build ID"] + raise Exception(f"Build ID not found for binary {binary}") + + def generate_buildid_dir( + self, + binary: Path, + build_id_dir: Path, + build_id: str, + log_handler: logging.Logger, + ): + os.makedirs(build_id_dir, exist_ok=True) + suffix = ".debug" + # Hardlink the original binary + build_id_prefix_dir = build_id_dir.joinpath(build_id[:2]) + unstripped_binary = build_id_prefix_dir.joinpath(build_id[2:] + suffix) + build_id_prefix_dir.mkdir(parents=True, exist_ok=True) + atomic_link(unstripped_binary, binary) + assert unstripped_binary.exists() + stripped_binary = unstripped_binary.with_suffix("") + llvm_objcopy = Path(self.toolchain_dir).joinpath("bin", "llvm-objcopy") + strip_mode = "--strip-sections" + check_call_with_logging( + [ + llvm_objcopy, + strip_mode, + unstripped_binary, + stripped_binary, + ], + stdout_handler=log_handler.info, + stderr_handler=log_handler.error, + ) + return stripped_binary + def write_to_file(self): with open(self.env_file_path(), "w", encoding="utf-8") as f: - f.write(json.dumps(self.__dict__)) + local_pb_path = self.local_pb_path + if local_pb_path is not None: + local_pb_path = str(local_pb_path) + + json.dump( + { + "rust_build_dir": str(self.rust_build_dir), + "sdk_dir": str(self.sdk_dir), + "target": self.target, + "toolchain_dir": str(self.toolchain_dir), + "local_pb_path": local_pb_path, + "use_local_pb": self.use_local_pb, + "verbose": self.verbose, + }, + f, + ) - def package_server_log_path(self): - return os.path.join(self.tmp_dir(), "package_server_log") + def setup_logging(self, log_to_file=False): + fs = logging.Formatter("%(asctime)s %(levelname)s:%(name)s:%(message)s") + if log_to_file: + logfile_handler = logging.FileHandler( + self.tmp_dir().joinpath("log") + ) + logfile_handler.setLevel(logging.DEBUG) + logfile_handler.setFormatter(fs) + logging.getLogger().addHandler(logfile_handler) + stream_handler = logging.StreamHandler(sys.stdout) + stream_handler.setFormatter(fs) + if self.verbose: + stream_handler.setLevel(logging.DEBUG) + else: + stream_handler.setLevel(logging.INFO) + logging.getLogger().addHandler(stream_handler) + logging.getLogger().setLevel(logging.DEBUG) + + @property + def package_server_log_path(self) -> Path: + return self.tmp_dir().joinpath("package_server_log") + + @property + def emulator_log_path(self) -> Path: + return self.tmp_dir().joinpath("emulator_log") - def emulator_log_path(self): - return os.path.join(self.tmp_dir(), "emulator_log") + @property + def packages_dir(self) -> Path: + return self.tmp_dir().joinpath("packages") - def packages_dir(self): - return os.path.join(self.tmp_dir(), "packages") + @property + def output_dir(self) -> Path: + return self.tmp_dir().joinpath("output") - def output_dir(self): - return os.path.join(self.tmp_dir(), "output") + def read_sdk_version(self): + meta_json_path = Path(self.sdk_dir).joinpath("meta", "manifest.json") + with open(meta_json_path, encoding="utf-8") as f: + meta_json = json.load(f) + return meta_json["id"] TEST_REPO_NAME: ClassVar[str] = "rust-testing" - def repo_dir(self): - return os.path.join(self.tmp_dir(), self.TEST_REPO_NAME) + def repo_dir(self) -> Path: + return self.tmp_dir().joinpath(self.TEST_REPO_NAME) - def libs_dir(self): - return os.path.join( - self.rust_build_dir, + def libs_dir(self) -> Path: + return self.rust_build_dir.joinpath( "host", "stage2", "lib", ) - def rustlibs_dir(self): - return os.path.join( - self.libs_dir(), + def rustlibs_dir(self) -> Path: + return self.libs_dir().joinpath( "rustlib", self.target, "lib", @@ -112,8 +329,8 @@ class TestEnvironment: return "a64" raise Exception(f"Unrecognized host architecture {machine}") - def tool_path(self, tool): - return os.path.join(self.sdk_dir, "tools", self.sdk_arch(), tool) + def tool_path(self, tool) -> Path: + return Path(self.sdk_dir).joinpath("tools", self.sdk_arch(), tool) def host_arch_triple(self): machine = platform.machine() @@ -123,45 +340,25 @@ class TestEnvironment: return "aarch64-unknown-linux-gnu" raise Exception(f"Unrecognized host architecture {machine}") - def zxdb_script_path(self): - return os.path.join(self.tmp_dir(), "zxdb_script") - - def pm_lockfile_path(self): - return os.path.join(self.tmp_dir(), "pm.lock") - - def log_info(self, msg): - print(msg) - - def log_debug(self, msg): - if self.verbose: - print(msg) - - def subprocess_output(self): - if self.verbose: - return sys.stdout - return subprocess.DEVNULL - - def check_call(self, args, **kwargs): - self.log_info(f"Running: {' '.join(args)}") - return subprocess.check_call(args, **kwargs) - - def check_output(self, args, **kwargs): - self.log_info(f"Running: {' '.join(args)}") - return subprocess.check_output(args, **kwargs) + def zxdb_script_path(self) -> Path: + return Path(self.tmp_dir(), "zxdb_script") + @property def ffx_daemon_log_path(self): - return os.path.join(self.tmp_dir(), "ffx_daemon_log") + return self.tmp_dir().joinpath("ffx_daemon_log") + @property def ffx_isolate_dir(self): - return os.path.join(self.tmp_dir(), "ffx_isolate") + return self.tmp_dir().joinpath("ffx_isolate") + @property def home_dir(self): - return os.path.join(self.tmp_dir(), "user-home") + return self.tmp_dir().joinpath("user-home") def start_ffx_isolation(self): # Most of this is translated directly from ffx's isolate library - os.mkdir(self.ffx_isolate_dir()) - os.mkdir(self.home_dir()) + os.mkdir(self.ffx_isolate_dir) + os.mkdir(self.home_dir) ffx_path = self.tool_path("ffx") ffx_env = self.ffx_cmd_env() @@ -170,7 +367,7 @@ class TestEnvironment: # We want this to be a long-running process that persists after the script finishes # pylint: disable=consider-using-with with open( - self.ffx_daemon_log_path(), "w", encoding="utf-8" + self.ffx_daemon_log_path, "w", encoding="utf-8" ) as ffx_daemon_log_file: subprocess.Popen( [ @@ -184,7 +381,7 @@ class TestEnvironment: ) # Disable analytics - self.check_call( + check_call_with_logging( [ ffx_path, "config", @@ -192,8 +389,8 @@ class TestEnvironment: "disable", ], env=ffx_env, - stdout=self.subprocess_output(), - stderr=self.subprocess_output(), + stdout_handler=self.subprocess_logger.debug, + stderr_handler=self.subprocess_logger.debug, ) # Set configs @@ -203,7 +400,7 @@ class TestEnvironment: "test.experimental_structured_output": "true", } for key, value in configs.items(): - self.check_call( + check_call_with_logging( [ ffx_path, "config", @@ -212,14 +409,14 @@ class TestEnvironment: value, ], env=ffx_env, - stdout=self.subprocess_output(), - stderr=self.subprocess_output(), + stdout_handler=self.subprocess_logger.debug, + stderr_handler=self.subprocess_logger.debug, ) def ffx_cmd_env(self): return { - "HOME": self.home_dir(), - "FFX_ISOLATE_DIR": self.ffx_isolate_dir(), + "HOME": self.home_dir, + "FFX_ISOLATE_DIR": self.ffx_isolate_dir, # We want to use our own specified temp directory "TMP": self.tmp_dir(), "TEMP": self.tmp_dir(), @@ -228,16 +425,15 @@ class TestEnvironment: } def stop_ffx_isolation(self): - self.check_call( + check_call_with_logging( [ self.tool_path("ffx"), "daemon", "stop", - "-w", ], env=self.ffx_cmd_env(), - stdout=self.subprocess_output(), - stderr=self.subprocess_output(), + stdout_handler=self.subprocess_logger.debug, + stderr_handler=self.subprocess_logger.debug, ) def start(self): @@ -256,22 +452,23 @@ class TestEnvironment: """ # Initialize temp directory - if not os.path.exists(self.tmp_dir()): - os.mkdir(self.tmp_dir()) - elif len(os.listdir(self.tmp_dir())) != 0: - raise Exception(f"Temp directory is not clean (in {self.tmp_dir()})") - - os.mkdir(self.output_dir()) + os.makedirs(self.tmp_dir(), exist_ok=True) + if len(os.listdir(self.tmp_dir())) != 0: + raise Exception( + f"Temp directory is not clean (in {self.tmp_dir()})" + ) + self.setup_logging(log_to_file=True) + os.mkdir(self.output_dir) ffx_path = self.tool_path("ffx") ffx_env = self.ffx_cmd_env() # Start ffx isolation - self.log_info("Starting ffx isolation...") + self.env_logger.info("Starting ffx isolation...") self.start_ffx_isolation() # Stop any running emulators (there shouldn't be any) - self.check_call( + check_call_with_logging( [ ffx_path, "emu", @@ -279,79 +476,95 @@ class TestEnvironment: "--all", ], env=ffx_env, - stdout=self.subprocess_output(), - stderr=self.subprocess_output(), + stdout_handler=self.subprocess_logger.debug, + stderr_handler=self.subprocess_logger.debug, ) - # 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 = "21.20240610.2.1" + if not self.local_pb_path: + self.local_pb_path = os.path.join(self.tmp_dir(), "local_pb") + else: + self.local_pb_path = os.path.abspath(self.local_pb_path) - out = self.check_output( - [ - ffx_path, - "--machine", - "json", - "product", - "lookup", - product_name, - fuchsia_version, - "--base-url", - "gs://fuchsia/development/" + fuchsia_version, - ], - env=ffx_env, - stderr=self.subprocess_output(), - ) + if self.use_local_pb and os.path.exists(self.local_pb_path): + self.env_logger.info( + 'Using existing emulator image at "%s"' % self.local_pb_path + ) + else: + shutil.rmtree(self.local_pb_path, ignore_errors=True) - self.log_debug(out) + # Look up the product bundle transfer manifest. + self.env_logger.info( + "Looking up the product bundle transfer manifest..." + ) + product_name = "minimal." + self.triple_to_arch(self.target) + sdk_version = self.read_sdk_version() - try: - transfer_manifest_url = json.loads(out)["transfer_manifest_url"] - except Exception as e: - print(e) - raise Exception("Unable to parse transfer manifest") from e + output = check_output_with_logging( + [ + ffx_path, + "--machine", + "json", + "product", + "lookup", + product_name, + sdk_version, + "--base-url", + "gs://fuchsia/development/" + sdk_version, + ], + env=ffx_env, + stdout_handler=self.subprocess_logger.debug, + stderr_handler=self.subprocess_logger.debug, + ) - # Download the product bundle. - product_bundle_dir = os.path.join(self.tmp_dir(), 'product-bundle') - self.check_call( - [ - ffx_path, - "product", - "download", - transfer_manifest_url, - product_bundle_dir, - "--force", - ], - env=ffx_env, - stdout=self.subprocess_output(), - stderr=self.subprocess_output(), - ) + try: + transfer_manifest_url = json.loads(output)[ + "transfer_manifest_url" + ] + except Exception as e: + print(e) + raise Exception("Unable to parse transfer manifest") from e + + # Download the product bundle. + self.env_logger.info("Downloading the product bundle...") + check_call_with_logging( + [ + ffx_path, + "product", + "download", + transfer_manifest_url, + self.local_pb_path, + ], + env=ffx_env, + stdout_handler=self.subprocess_logger.debug, + stderr_handler=self.subprocess_logger.debug, + ) # Start emulator + self.env_logger.info("Starting emulator...") + # FIXME: condition --accel hyper on target arch matching host arch - self.check_call( + check_call_with_logging( [ ffx_path, "emu", "start", - product_bundle_dir, + self.local_pb_path, "--headless", "--log", - self.emulator_log_path(), + self.emulator_log_path, "--net", - "tap", + "auto", "--accel", - "hyper", + "auto", ], env=ffx_env, - stdout=self.subprocess_output(), - stderr=self.subprocess_output(), + stdout_handler=self.subprocess_logger.debug, + stderr_handler=self.subprocess_logger.debug, ) # Create new package repo - self.log_info("Creating package repo...") - self.check_call( + self.env_logger.info("Creating package repo...") + check_call_with_logging( [ ffx_path, "repository", @@ -359,11 +572,12 @@ class TestEnvironment: self.repo_dir(), ], env=ffx_env, - stdout=self.subprocess_output(), - stderr=self.subprocess_output(), + stdout_handler=self.subprocess_logger.debug, + stderr_handler=self.subprocess_logger.debug, ) - self.check_call( + # Add repository + check_call_with_logging( [ ffx_path, "repository", @@ -373,15 +587,12 @@ class TestEnvironment: self.repo_dir(), ], env=ffx_env, - stdout=self.subprocess_output(), - stderr=self.subprocess_output(), + stdout_handler=self.subprocess_logger.debug, + stderr_handler=self.subprocess_logger.debug, ) - # Write to file - self.write_to_file() - # Start repository server - self.check_call( + check_call_with_logging( [ ffx_path, "repository", @@ -391,12 +602,12 @@ class TestEnvironment: "[::]:0", ], env=ffx_env, - stdout=self.subprocess_output(), - stderr=self.subprocess_output(), + stdout_handler=self.subprocess_logger.debug, + stderr_handler=self.subprocess_logger.debug, ) # Register with newly-started emulator - self.check_call( + check_call_with_logging( [ ffx_path, "target", @@ -406,11 +617,14 @@ class TestEnvironment: self.TEST_REPO_NAME, ], env=ffx_env, - stdout=self.subprocess_output(), - stderr=self.subprocess_output(), + stdout_handler=self.subprocess_logger.debug, + stderr_handler=self.subprocess_logger.debug, ) - self.log_info("Success! Your environment is ready to run tests.") + # Write to file + self.write_to_file() + + self.env_logger.info("Success! Your environment is ready to run tests.") # FIXME: shardify this # `facet` statement required for TCP testing via @@ -481,7 +695,7 @@ class TestEnvironment: - Forward the test's stdout and stderr as this script's stdout and stderr """ - bin_path = os.path.abspath(args.bin_path) + bin_path = Path(args.bin_path).absolute() # Find libstd and libtest libstd_paths = glob.glob(os.path.join(self.rustlibs_dir(), "libstd-*.so")) @@ -490,233 +704,240 @@ class TestEnvironment: if not libstd_paths: raise Exception(f"Failed to locate libstd (in {self.rustlibs_dir()})") - # Build a unique, deterministic name for the test using the name of the - # binary and the last 6 hex digits of the hash of the full path - def path_checksum(path): - m = hashlib.sha256() - m.update(path.encode("utf-8")) - return m.hexdigest()[0:6] - base_name = os.path.basename(os.path.dirname(args.bin_path)) exe_name = base_name.lower().replace(".", "_") - package_name = f"{exe_name}_{path_checksum(bin_path)}" - - package_dir = os.path.join(self.packages_dir(), package_name) - cml_path = os.path.join(package_dir, "meta", f"{package_name}.cml") - cm_path = os.path.join(package_dir, "meta", f"{package_name}.cm") - manifest_path = os.path.join(package_dir, f"{package_name}.manifest") - manifest_json_path = os.path.join(package_dir, "package_manifest.json") - far_path = os.path.join(package_dir, f"{package_name}-0.far") + build_id = self.build_id(bin_path) + package_name = f"{exe_name}_{build_id}" + + package_dir = self.packages_dir.joinpath(package_name) + package_dir.mkdir(parents=True, exist_ok=True) + meta_dir = package_dir.joinpath("meta") + meta_dir.mkdir(parents=True, exist_ok=True) + meta_package_path = meta_dir.joinpath("package") + cml_path = meta_dir.joinpath(f"{package_name}.cml") + cm_path = meta_dir.joinpath(f"{package_name}.cm") + manifest_path = package_dir.joinpath(f"{package_name}.manifest") shared_libs = args.shared_libs[: args.n] arguments = args.shared_libs[args.n :] - test_output_dir = os.path.join(self.output_dir(), package_name) + test_output_dir = self.output_dir.joinpath(package_name) # Clean and create temporary output directory - if os.path.exists(test_output_dir): + if test_output_dir.exists(): shutil.rmtree(test_output_dir) - - os.mkdir(test_output_dir) + test_output_dir.mkdir(parents=True) # Open log file - log_path = os.path.join(test_output_dir, "log") - with open(log_path, "w", encoding="utf-8") as log_file: - - def log(msg): - print(msg, file=log_file) - log_file.flush() + runner_logger = logging.getLogger(f"env.package.{package_name}") + runner_logger.setLevel(logging.DEBUG) + logfile_handler = logging.FileHandler(test_output_dir.joinpath("log")) + logfile_handler.setLevel(logging.DEBUG) + logfile_handler.setFormatter( + logging.Formatter("%(levelname)s:%(name)s:%(message)s") + ) + runner_logger.addHandler(logfile_handler) + + runner_logger.info(f"Bin path: {bin_path}") + runner_logger.info("Setting up package...") + + # Link binary to build-id dir and strip it. + build_id_dir = self.tmp_dir().joinpath(".build-id") + stripped_binary = self.generate_buildid_dir( + binary=bin_path, + build_id_dir=build_id_dir, + build_id=build_id, + log_handler=runner_logger, + ) + runner_logger.info(f"Stripped Bin path: {stripped_binary}") - log(f"Bin path: {bin_path}") + runner_logger.info("Writing CML...") - log("Writing CML...") + # Write and compile CML + with open(cml_path, "w", encoding="utf-8") as cml: + # Collect environment variables + env_vars = "" + for var_name in self.TEST_ENV_VARS: + var_value = os.getenv(var_name) + if var_value is not None: + env_vars += f'\n "{var_name}={var_value}",' - # Write and compile CML - with open(cml_path, "w", encoding="utf-8") as cml: - # Collect environment variables - env_vars = "" - for var_name in self.TEST_ENV_VARS: - var_value = os.getenv(var_name) - if var_value is not None: - env_vars += f'\n "{var_name}={var_value}",' + # Default to no backtrace for test suite + if os.getenv("RUST_BACKTRACE") is None: + env_vars += '\n "RUST_BACKTRACE=0",' - # Default to no backtrace for test suite - if os.getenv("RUST_BACKTRACE") is None: - env_vars += '\n "RUST_BACKTRACE=0",' + # Use /tmp as the test temporary directory + env_vars += '\n "RUST_TEST_TMPDIR=/tmp",' - # Use /tmp as the test temporary directory - env_vars += '\n "RUST_TEST_TMPDIR=/tmp",' + cml.write( + self.CML_TEMPLATE.format(env_vars=env_vars, exe_name=exe_name) + ) - cml.write( - self.CML_TEMPLATE.format(env_vars=env_vars, exe_name=exe_name) - ) + runner_logger.info("Compiling CML...") - log("Compiling CML...") + check_call_with_logging( + [ + self.tool_path("cmc"), + "compile", + cml_path, + "--includepath", + ".", + "--output", + cm_path, + ], + stdout_handler=runner_logger.info, + stderr_handler=runner_logger.warning, + ) - self.check_call( - [ - self.tool_path("cmc"), - "compile", - cml_path, - "--includepath", - ".", - "--output", - cm_path, - ], - stdout=log_file, - stderr=log_file, + runner_logger.info("Writing meta/package...") + with open(meta_package_path, "w", encoding="utf-8") as f: + json.dump({"name": package_name, "version": "0"}, f) + + runner_logger.info("Writing manifest...") + + # Write package manifest + with open(manifest_path, "w", encoding="utf-8") as manifest: + manifest.write( + self.MANIFEST_TEMPLATE.format( + bin_path=stripped_binary, + exe_name=exe_name, + package_dir=package_dir, + package_name=package_name, + target=self.target, + sdk_dir=self.sdk_dir, + libstd_name=os.path.basename(libstd_paths[0]), + libstd_path=libstd_paths[0], + target_arch=self.triple_to_arch(self.target), + ) ) - - log("Writing manifest...") - - # Write, build, and archive manifest - with open(manifest_path, "w", encoding="utf-8") as manifest: + # `libtest`` was historically a shared library, but now seems to be (sometimes?) + # statically linked. If we find it as a shared library, include it in the manifest. + if libtest_paths: manifest.write( - self.MANIFEST_TEMPLATE.format( - bin_path=bin_path, - exe_name=exe_name, - package_dir=package_dir, - package_name=package_name, - target=self.target, - sdk_dir=self.sdk_dir, - libstd_name=os.path.basename(libstd_paths[0]), - libstd_path=libstd_paths[0], - target_arch=self.triple_to_arch(self.target), - ) + f"lib/{os.path.basename(libtest_paths[0])}={libtest_paths[0]}\n" ) - # `libtest`` was historically a shared library, but now seems to be (sometimes?) - # statically linked. If we find it as a shared library, include it in the manifest. - if libtest_paths: - manifest.write( - f"lib/{os.path.basename(libtest_paths[0])}={libtest_paths[0]}\n" - ) - for shared_lib in shared_libs: - manifest.write(f"lib/{os.path.basename(shared_lib)}={shared_lib}\n") - - log("Determining API level...") - out = self.check_output( - [ - self.tool_path("ffx"), - "--machine", - "json", - "version", - ], - env=self.ffx_cmd_env(), - stderr=log_file, - ) - api_level = json.loads(out)["tool_version"]["api_level"] + for shared_lib in shared_libs: + manifest.write(f"lib/{os.path.basename(shared_lib)}={shared_lib}\n") - log("Compiling and archiving manifest...") + runner_logger.info("Determining API level...") + out = check_output_with_logging( + [ + self.tool_path("ffx"), + "--machine", + "json", + "version", + ], + env=self.ffx_cmd_env(), + stdout_handler=self.subprocess_logger.debug, + stderr_handler=self.subprocess_logger.debug, + ) + api_level = json.loads(out)["tool_version"]["api_level"] - self.check_call( - [ - self.tool_path("ffx"), - "package", - "build", - manifest_path, - "-o", - package_dir, - "--api-level", - str(api_level), - ], - env=self.ffx_cmd_env(), - stdout=log_file, - stderr=log_file, - ) + runner_logger.info("Compiling manifest...") - self.check_call( - [ - self.tool_path("ffx"), - "package", - "archive", - "create", - "-o", - far_path, - manifest_json_path, - ], - env=self.ffx_cmd_env(), - stdout=log_file, - stderr=log_file, - ) + check_call_with_logging( + [ + self.tool_path("ffx"), + "package", + "build", + manifest_path, + "-o", + package_dir, + "--api-level", + str(api_level), + ], + env=self.ffx_cmd_env(), + stdout_handler=runner_logger.info, + stderr_handler=runner_logger.warning, + ) - log("Publishing package to repo...") + runner_logger.info("Publishing package to repo...") - # Publish package to repo - self.check_call( - [ - self.tool_path("ffx"), - "repository", - "publish", - "--package", - os.path.join(package_dir, "package_manifest.json"), - self.repo_dir(), - ], - stdout=log_file, - stderr=log_file, - ) + # Publish package to repo + check_call_with_logging( + [ + self.tool_path("ffx"), + "repository", + "publish", + "--package", + os.path.join(package_dir, "package_manifest.json"), + self.repo_dir(), + ], + env=self.ffx_cmd_env(), + stdout_handler=runner_logger.info, + stderr_handler=runner_logger.warning, + ) - log("Running ffx test...") + runner_logger.info("Running ffx test...") - # Run test on emulator - subprocess.run( - [ - self.tool_path("ffx"), - "test", - "run", - f"fuchsia-pkg://{self.TEST_REPO_NAME}/{package_name}#meta/{package_name}.cm", - "--min-severity-logs", - "TRACE", - "--output-directory", - test_output_dir, - "--", - ] - + arguments, - env=self.ffx_cmd_env(), - check=False, - stdout=log_file, - stderr=log_file, - ) + # Run test on emulator + check_call_with_logging( + [ + self.tool_path("ffx"), + "test", + "run", + f"fuchsia-pkg://{self.TEST_REPO_NAME}/{package_name}#meta/{package_name}.cm", + "--min-severity-logs", + "TRACE", + "--output-directory", + test_output_dir, + "--", + ] + + arguments, + env=self.ffx_cmd_env(), + check=False, + stdout_handler=runner_logger.info, + stderr_handler=runner_logger.warning, + ) - log("Reporting test suite output...") + runner_logger.info("Reporting test suite output...") - # Read test suite output - run_summary_path = os.path.join(test_output_dir, "run_summary.json") - if os.path.exists(run_summary_path): - with open(run_summary_path, encoding="utf-8") as f: - run_summary = json.loads(f.read()) + # Read test suite output + run_summary_path = test_output_dir.joinpath("run_summary.json") + if not run_summary_path.exists(): + runner_logger.error("Failed to open test run summary") + return 254 - suite = run_summary["data"]["suites"][0] - case = suite["cases"][0] + with open(run_summary_path, encoding="utf-8") as f: + run_summary = json.load(f) - return_code = 0 if case["outcome"] == "PASSED" else 1 + suite = run_summary["data"]["suites"][0] + case = suite["cases"][0] - artifacts = case["artifacts"] - artifact_dir = case["artifact_dir"] - stdout_path = None - stderr_path = None + return_code = 0 if case["outcome"] == "PASSED" else 1 - for path, artifact in artifacts.items(): - artifact_path = os.path.join(test_output_dir, artifact_dir, path) - artifact_type = artifact["artifact_type"] + artifacts = case["artifacts"] + artifact_dir = case["artifact_dir"] + stdout_path = None + stderr_path = None - if artifact_type == "STDERR": - stderr_path = artifact_path - elif artifact_type == "STDOUT": - stdout_path = artifact_path + for path, artifact in artifacts.items(): + artifact_path = os.path.join(test_output_dir, artifact_dir, path) + artifact_type = artifact["artifact_type"] - if stdout_path is not None and os.path.exists(stdout_path): - with open(stdout_path, encoding="utf-8") as f: - print(f.read(), file=sys.stdout, end="") + if artifact_type == "STDERR": + stderr_path = artifact_path + elif artifact_type == "STDOUT": + stdout_path = artifact_path - if stderr_path is not None and os.path.exists(stderr_path): - with open(stderr_path, encoding="utf-8") as f: - print(f.read(), file=sys.stderr, end="") + if stdout_path is not None: + if not os.path.exists(stdout_path): + runner_logger.error( + f"stdout file {stdout_path} does not exist." + ) else: - log("Failed to open test run summary") - return_code = 254 - - log("Done!") + with open(stdout_path, encoding="utf-8", errors="ignore") as f: + runner_logger.info(f.read()) + if stderr_path is not None: + if not os.path.exists(stderr_path): + runner_logger.error( + f"stderr file {stderr_path} does not exist." + ) + else: + with open(stderr_path, encoding="utf-8", errors="ignore") as f: + runner_logger.error(f.read()) + runner_logger.info("Done!") return return_code def stop(self): @@ -730,65 +951,65 @@ class TestEnvironment: During cleanup, this function will stop the emulator, package server, and update server, then delete all temporary files. If an error is encountered while stopping any running processes, the temporary files will not be deleted. - Passing --delete-tmp will force the process to delete the files anyway. + Passing --cleanup will force the process to delete the files anyway. """ - self.log_debug("Reporting logs...") + self.env_logger.debug("Reporting logs...") # Print test log files - for test_dir in os.listdir(self.output_dir()): - log_path = os.path.join(self.output_dir(), test_dir, "log") - self.log_debug(f"\n---- Logs for test '{test_dir}' ----\n") + for test_dir in os.listdir(self.output_dir): + log_path = os.path.join(self.output_dir, test_dir, "log") + self.env_logger.debug(f"\n---- Logs for test '{test_dir}' ----\n") if os.path.exists(log_path): - with open(log_path, encoding="utf-8") as log: - self.log_debug(log.read()) + with open(log_path, encoding="utf-8", errors="ignore") as log: + self.env_logger.debug(log.read()) else: - self.log_debug("No logs found") + self.env_logger.debug("No logs found") # Print the emulator log - self.log_debug("\n---- Emulator logs ----\n") - if os.path.exists(self.emulator_log_path()): - with open(self.emulator_log_path(), encoding="utf-8") as log: - self.log_debug(log.read()) + self.env_logger.debug("\n---- Emulator logs ----\n") + if os.path.exists(self.emulator_log_path): + with open(self.emulator_log_path, encoding="utf-8") as log: + self.env_logger.debug(log.read()) else: - self.log_debug("No emulator logs found") + self.env_logger.debug("No emulator logs found") # Print the package server log - self.log_debug("\n---- Package server log ----\n") - if os.path.exists(self.package_server_log_path()): - with open(self.package_server_log_path(), encoding="utf-8") as log: - self.log_debug(log.read()) + self.env_logger.debug("\n---- Package server log ----\n") + if os.path.exists(self.package_server_log_path): + with open(self.package_server_log_path, encoding="utf-8") as log: + self.env_logger.debug(log.read()) else: - self.log_debug("No package server log found") + self.env_logger.debug("No package server log found") # Print the ffx daemon log - self.log_debug("\n---- ffx daemon log ----\n") - if os.path.exists(self.ffx_daemon_log_path()): - with open(self.ffx_daemon_log_path(), encoding="utf-8") as log: - self.log_debug(log.read()) + self.env_logger.debug("\n---- ffx daemon log ----\n") + if os.path.exists(self.ffx_daemon_log_path): + with open(self.ffx_daemon_log_path, encoding="utf-8") as log: + self.env_logger.debug(log.read()) else: - self.log_debug("No ffx daemon log found") + self.env_logger.debug("No ffx daemon log found") # Shut down the emulator - self.log_info("Stopping emulator...") - self.check_call( + self.env_logger.info("Stopping emulator...") + check_call_with_logging( [ self.tool_path("ffx"), "emu", "stop", ], env=self.ffx_cmd_env(), - stdout=self.subprocess_output(), - stderr=self.subprocess_output(), + stdout_handler=self.subprocess_logger.debug, + stderr_handler=self.subprocess_logger.debug, ) # Stop ffx isolation - self.log_info("Stopping ffx isolation...") + self.env_logger.info("Stopping ffx isolation...") self.stop_ffx_isolation() - def delete_tmp(self): + def cleanup(self): # Remove temporary files - self.log_info("Deleting temporary files...") + self.env_logger.info("Deleting temporary files...") shutil.rmtree(self.tmp_dir(), ignore_errors=True) def debug(self, args): @@ -816,7 +1037,7 @@ class TestEnvironment: f"--symbol-path={self.rust_dir}/lib/rustlib/{self.target}/lib", ] - # Add rust source if it's available + # Add rust source if it's available rust_src_map = None if args.rust_src is not None: # This matches the remapped prefix used by compiletest. There's no @@ -908,21 +1129,24 @@ def start(args): def run(args): test_env = TestEnvironment.read_from_file() + test_env.setup_logging(log_to_file=True) return test_env.run(args) def stop(args): test_env = TestEnvironment.read_from_file() + test_env.setup_logging(log_to_file=False) test_env.stop() - if not args.no_delete: - test_env.delete_tmp() + if not args.no_cleanup: + test_env.cleanup() return 0 -def delete_tmp(args): +def cleanup(args): del args test_env = TestEnvironment.read_from_file() - test_env.delete_tmp() + test_env.setup_logging(log_to_file=False) + test_env.cleanup() return 0 @@ -934,6 +1158,7 @@ def debug(args): def syslog(args): test_env = TestEnvironment.read_from_file() + test_env.setup_logging(log_to_file=True) test_env.syslog(args) return 0 @@ -973,6 +1198,21 @@ def main(): help="the target platform to test", required=True, ) + start_parser.add_argument( + "--toolchain-dir", + help="the toolchain directory", + required=True, + ) + start_parser.add_argument( + "--local-product-bundle-path", + help="the path where the product-bundle should be downloaded to", + ) + start_parser.add_argument( + "--use-local-product-bundle-if-exists", + help="if the product bundle already exists in the local path, use " + "it instead of downloading it again", + action="store_true", + ) start_parser.set_defaults(func=start) run_parser = subparsers.add_parser( @@ -993,18 +1233,23 @@ def main(): "stop", help="shuts down and cleans up the testing environment" ) stop_parser.add_argument( - "--no-delete", + "--no-cleanup", default=False, action="store_true", help="don't delete temporary files after stopping", ) stop_parser.set_defaults(func=stop) - delete_parser = subparsers.add_parser( - "delete-tmp", + cleanup_parser = subparsers.add_parser( + "cleanup", help="deletes temporary files after the testing environment has been manually cleaned up", ) - delete_parser.set_defaults(func=delete_tmp) + cleanup_parser.set_defaults(func=cleanup) + + syslog_parser = subparsers.add_parser( + "syslog", help="prints the device syslog" + ) + syslog_parser.set_defaults(func=syslog) debug_parser = subparsers.add_parser( "debug", @@ -1033,9 +1278,6 @@ def main(): ) debug_parser.set_defaults(func=debug) - syslog_parser = subparsers.add_parser("syslog", help="prints the device syslog") - syslog_parser.set_defaults(func=syslog) - args = parser.parse_args() return args.func(args) diff --git a/src/doc/book b/src/doc/book -Subproject 5228bfac8267ad24659a81b92ec5417976b5edb +Subproject 45c1a6d69edfd1fc91fb7504cb73958dbd09441 diff --git a/src/doc/edition-guide b/src/doc/edition-guide -Subproject bbaabbe088e21a81a0d9ae6757705020d5d7b41 +Subproject cb58c430b4e8054c2cb81d2d4434092c482a93d diff --git a/src/doc/reference b/src/doc/reference -Subproject 6019b76f5b28938565b251bbba0bf5cc5c43d86 +Subproject 0b805c65804019b0ac8f2fe3117afad82a6069b diff --git a/src/doc/rust-by-example b/src/doc/rust-by-example -Subproject 4840dca06cadf48b305d3ce0aeafde7f80933f8 +Subproject b1d97bd6113aba732b2091ce093c76f2d05bb8a diff --git a/src/doc/rustc-dev-guide b/src/doc/rustc-dev-guide -Subproject 6a7374bd87cbac0f8be4fd4877d8186d9c31398 +Subproject aec82168dd3121289a194b381f56076fc789a4d diff --git a/src/doc/rustc/src/SUMMARY.md b/src/doc/rustc/src/SUMMARY.md index 201ace5ce3a..e76ebb8f8aa 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/instrument-coverage.md b/src/doc/rustc/src/instrument-coverage.md index 32dc992c42f..ed091d8fc57 100644 --- a/src/doc/rustc/src/instrument-coverage.md +++ b/src/doc/rustc/src/instrument-coverage.md @@ -49,12 +49,6 @@ One option for a Rust demangler is [`rustfilt`], which can be installed with: cargo install rustfilt ``` -Another option, if you are building from the Rust compiler source distribution, is to use the `rust-demangler` tool included in the Rust source distribution, which can be built with: - -```shell -$ ./x.py build rust-demangler -``` - [`rustfilt`]: https://crates.io/crates/rustfilt ## Compiling with coverage enabled @@ -164,7 +158,7 @@ $ llvm-cov show -Xdemangler=rustfilt target/debug/examples/formatjson5 \ Some of the more notable options in this example include: -- `--Xdemangler=rustfilt` - the command name or path used to demangle Rust symbols (`rustfilt` in the example, but this could also be a path to the `rust-demangler` tool) +- `--Xdemangler=rustfilt` - the command name or path used to demangle Rust symbols (`rustfilt` in the example) - `target/debug/examples/formatjson5` - the instrumented binary (from which to extract the coverage map) - `--instr-profile=<path-to-file>.profdata` - the location of the `.profdata` file created by `llvm-profdata merge` (from the `.profraw` file generated by the instrumented binary) - `--name=<exact-function-name>` - to show coverage for a specific function (or, consider using another filter option, such as `--name-regex=<pattern>`) diff --git a/src/doc/rustc/src/platform-support.md b/src/doc/rustc/src/platform-support.md index e55bb3bd155..834e909c065 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,7 +258,7 @@ 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-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) @@ -300,6 +300,7 @@ 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-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] diff --git a/src/doc/rustc/src/platform-support/apple-ios-macabi.md b/src/doc/rustc/src/platform-support/apple-ios-macabi.md index 278ee94b6d4..15ba31e0f06 100644 --- a/src/doc/rustc/src/platform-support/apple-ios-macabi.md +++ b/src/doc/rustc/src/platform-support/apple-ios-macabi.md @@ -9,6 +9,8 @@ Apple Mac Catalyst targets. ## Target maintainers +- [@badboy](https://github.com/badboy) +- [@BlackHoleFox](https://github.com/BlackHoleFox) - [@madsmtm](https://github.com/madsmtm) ## Requirements 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 00000000000..1b3321956ef --- /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 = [ + "<HOST_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 <https://static.redox-os.org/toolchain/>. diff --git a/src/librustdoc/clean/mod.rs b/src/librustdoc/clean/mod.rs index 2dcbbf0d150..da41f974068 100644 --- a/src/librustdoc/clean/mod.rs +++ b/src/librustdoc/clean/mod.rs @@ -228,6 +228,8 @@ fn clean_generic_bound<'tcx>( GenericBound::TraitBound(clean_poly_trait_ref(t, cx), modifier) } + // FIXME(precise_capturing): Implement rustdoc support + hir::GenericBound::Use(..) => return None, }) } diff --git a/src/librustdoc/config.rs b/src/librustdoc/config.rs index 78d4129f642..45bd1616e83 100644 --- a/src/librustdoc/config.rs +++ b/src/librustdoc/config.rs @@ -8,6 +8,7 @@ use std::path::PathBuf; use std::str::FromStr; use rustc_data_structures::fx::FxHashMap; +use rustc_errors::DiagCtxtHandle; use rustc_session::config::{ self, parse_crate_types_from_list, parse_externs, parse_target_triple, CrateType, }; @@ -383,9 +384,10 @@ impl Options { }; let dcx = new_dcx(error_format, None, diagnostic_width, &unstable_opts); + let dcx = dcx.handle(); // check for deprecated options - check_deprecated_options(matches, &dcx); + check_deprecated_options(matches, dcx); if matches.opt_strs("passes") == ["list"] { println!("Available passes for running rustdoc:"); @@ -458,7 +460,7 @@ impl Options { println!("rustdoc: [check-theme] Starting tests! (Ignoring all other arguments)"); for theme_file in to_check.iter() { print!(" - Checking \"{theme_file}\"..."); - let (success, differences) = theme::test_theme_against(theme_file, &paths, &dcx); + let (success, differences) = theme::test_theme_against(theme_file, &paths, dcx); if !differences.is_empty() || !success { println!(" FAILED"); errors += 1; @@ -603,7 +605,7 @@ impl Options { .with_help("arguments to --theme must have a .css extension") .emit(); } - let (success, ret) = theme::test_theme_against(&theme_file, &paths, &dcx); + let (success, ret) = theme::test_theme_against(&theme_file, &paths, dcx); if !success { dcx.fatal(format!("error loading theme file: \"{theme_s}\"")); } else if !ret.is_empty() { @@ -630,7 +632,7 @@ impl Options { &matches.opt_strs("markdown-before-content"), &matches.opt_strs("markdown-after-content"), nightly_options::match_is_nightly_build(matches), - &dcx, + dcx, &mut id_map, edition, &None, @@ -741,9 +743,9 @@ impl Options { ); } - let scrape_examples_options = ScrapeExamplesOptions::new(matches, &dcx); + let scrape_examples_options = ScrapeExamplesOptions::new(matches, dcx); let with_examples = matches.opt_strs("with-examples"); - let call_locations = crate::scrape_examples::load_call_locations(with_examples, &dcx); + let call_locations = crate::scrape_examples::load_call_locations(with_examples, dcx); let unstable_features = rustc_feature::UnstableFeatures::from_environment(crate_name.as_deref()); @@ -847,7 +849,7 @@ fn parse_remap_path_prefix( } /// Prints deprecation warnings for deprecated options -fn check_deprecated_options(matches: &getopts::Matches, dcx: &rustc_errors::DiagCtxt) { +fn check_deprecated_options(matches: &getopts::Matches, dcx: DiagCtxtHandle<'_>) { let deprecated_flags = []; for &flag in deprecated_flags.iter() { diff --git a/src/librustdoc/core.rs b/src/librustdoc/core.rs index ce098a1bcfb..5d8e61f9fa0 100644 --- a/src/librustdoc/core.rs +++ b/src/librustdoc/core.rs @@ -3,7 +3,7 @@ use rustc_data_structures::sync::Lrc; use rustc_data_structures::unord::UnordSet; use rustc_errors::emitter::{stderr_destination, DynEmitter, HumanEmitter}; use rustc_errors::json::JsonEmitter; -use rustc_errors::{codes::*, ErrorGuaranteed, TerminalUrl}; +use rustc_errors::{codes::*, DiagCtxtHandle, ErrorGuaranteed, TerminalUrl}; use rustc_feature::UnstableFeatures; use rustc_hir::def::Res; use rustc_hir::def_id::{DefId, DefIdMap, DefIdSet, LocalDefId}; @@ -379,7 +379,7 @@ pub(crate) fn run_global_ctxt( ); } - fn report_deprecated_attr(name: &str, dcx: &rustc_errors::DiagCtxt, sp: Span) { + fn report_deprecated_attr(name: &str, dcx: DiagCtxtHandle<'_>, sp: Span) { let mut msg = dcx.struct_span_warn(sp, format!("the `#![doc({name})]` attribute is deprecated")); msg.note( diff --git a/src/librustdoc/doctest.rs b/src/librustdoc/doctest.rs index 81a7463deca..40cc4a9d441 100644 --- a/src/librustdoc/doctest.rs +++ b/src/librustdoc/doctest.rs @@ -7,7 +7,7 @@ pub(crate) use markdown::test as test_markdown; use rustc_ast as ast; use rustc_data_structures::fx::{FxHashMap, FxHashSet}; -use rustc_errors::{ColorConfig, ErrorGuaranteed, FatalError}; +use rustc_errors::{ColorConfig, DiagCtxtHandle, ErrorGuaranteed, FatalError}; use rustc_hir::def_id::LOCAL_CRATE; use rustc_hir::CRATE_HIR_ID; use rustc_interface::interface; @@ -90,10 +90,7 @@ fn get_doctest_dir() -> io::Result<TempDir> { TempFileBuilder::new().prefix("rustdoctest").tempdir() } -pub(crate) fn run( - dcx: &rustc_errors::DiagCtxt, - options: RustdocOptions, -) -> Result<(), ErrorGuaranteed> { +pub(crate) fn run(dcx: DiagCtxtHandle<'_>, options: RustdocOptions) -> Result<(), ErrorGuaranteed> { let invalid_codeblock_attributes_name = crate::lint::INVALID_CODEBLOCK_ATTRIBUTES.name; // See core::create_config for what's going on here. diff --git a/src/librustdoc/doctest/make.rs b/src/librustdoc/doctest/make.rs index 599611407ed..74833c11362 100644 --- a/src/librustdoc/doctest/make.rs +++ b/src/librustdoc/doctest/make.rs @@ -229,7 +229,7 @@ fn check_for_main_and_extern_crate( // dcx. Any errors in the tests will be reported when the test file is compiled, // Note that we still need to cancel the errors above otherwise `Diag` will panic on // drop. - psess.dcx.reset_err_count(); + psess.dcx().reset_err_count(); (found_main, found_extern_crate, found_macro) }) diff --git a/src/librustdoc/externalfiles.rs b/src/librustdoc/externalfiles.rs index 03ee042aa8d..62cdc0bd5a6 100644 --- a/src/librustdoc/externalfiles.rs +++ b/src/librustdoc/externalfiles.rs @@ -1,4 +1,5 @@ use crate::html::markdown::{ErrorCodes, HeadingOffset, IdMap, Markdown, Playground}; +use rustc_errors::DiagCtxtHandle; use rustc_span::edition::Edition; use std::fs; use std::path::Path; @@ -27,7 +28,7 @@ impl ExternalHtml { md_before_content: &[String], md_after_content: &[String], nightly_build: bool, - dcx: &rustc_errors::DiagCtxt, + dcx: DiagCtxtHandle<'_>, id_map: &mut IdMap, edition: Edition, playground: &Option<Playground>, @@ -75,7 +76,7 @@ pub(crate) enum LoadStringError { pub(crate) fn load_string<P: AsRef<Path>>( file_path: P, - dcx: &rustc_errors::DiagCtxt, + dcx: DiagCtxtHandle<'_>, ) -> Result<String, LoadStringError> { let file_path = file_path.as_ref(); let contents = match fs::read(file_path) { @@ -98,7 +99,7 @@ pub(crate) fn load_string<P: AsRef<Path>>( } } -fn load_external_files(names: &[String], dcx: &rustc_errors::DiagCtxt) -> Option<String> { +fn load_external_files(names: &[String], dcx: DiagCtxtHandle<'_>) -> Option<String> { let mut out = String::new(); for name in names { let Ok(s) = load_string(name, dcx) else { return None }; diff --git a/src/librustdoc/lib.rs b/src/librustdoc/lib.rs index d6e715d48ea..fb4cd218b84 100644 --- a/src/librustdoc/lib.rs +++ b/src/librustdoc/lib.rs @@ -77,7 +77,7 @@ use std::io::{self, IsTerminal}; use std::process; use std::sync::{atomic::AtomicBool, Arc}; -use rustc_errors::{ErrorGuaranteed, FatalError}; +use rustc_errors::{DiagCtxtHandle, ErrorGuaranteed, FatalError}; use rustc_interface::interface; use rustc_middle::ty::TyCtxt; use rustc_session::config::{make_crate_type_option, ErrorOutputType, RustcOptGroup}; @@ -670,7 +670,7 @@ fn usage(argv0: &str) { /// A result type used by several functions under `main()`. type MainResult = Result<(), ErrorGuaranteed>; -pub(crate) fn wrap_return(dcx: &rustc_errors::DiagCtxt, res: Result<(), String>) -> MainResult { +pub(crate) fn wrap_return(dcx: DiagCtxtHandle<'_>, res: Result<(), String>) -> MainResult { match res { Ok(()) => dcx.has_errors().map_or(Ok(()), Err), Err(err) => Err(dcx.err(err)), @@ -732,12 +732,13 @@ fn main_args( None => return Ok(()), }; - let diag = + let dcx = core::new_dcx(options.error_format, None, options.diagnostic_width, &options.unstable_opts); + let dcx = dcx.handle(); match (options.should_test, options.markdown_input()) { - (true, Some(_)) => return wrap_return(&diag, doctest::test_markdown(options)), - (true, None) => return doctest::run(&diag, options), + (true, Some(_)) => return wrap_return(dcx, doctest::test_markdown(options)), + (true, None) => return doctest::run(dcx, options), (false, Some(input)) => { let input = input.to_owned(); let edition = options.edition; @@ -747,7 +748,7 @@ fn main_args( // requires session globals and a thread pool, so we use // `run_compiler`. return wrap_return( - &diag, + dcx, interface::run_compiler(config, |_compiler| { markdown::render(&input, render_options, edition) }), diff --git a/src/librustdoc/scrape_examples.rs b/src/librustdoc/scrape_examples.rs index e9b380fdeac..5a595e03953 100644 --- a/src/librustdoc/scrape_examples.rs +++ b/src/librustdoc/scrape_examples.rs @@ -7,6 +7,7 @@ use crate::formats::renderer::FormatRenderer; use crate::html::render::Context; use rustc_data_structures::fx::FxHashMap; +use rustc_errors::DiagCtxtHandle; use rustc_hir::{ self as hir, intravisit::{self, Visitor}, @@ -38,7 +39,7 @@ pub(crate) struct ScrapeExamplesOptions { } impl ScrapeExamplesOptions { - pub(crate) fn new(matches: &getopts::Matches, dcx: &rustc_errors::DiagCtxt) -> Option<Self> { + pub(crate) fn new(matches: &getopts::Matches, dcx: DiagCtxtHandle<'_>) -> Option<Self> { let output_path = matches.opt_str("scrape-examples-output-path"); let target_crates = matches.opt_strs("scrape-examples-target-crate"); let scrape_tests = matches.opt_present("scrape-tests"); @@ -336,7 +337,7 @@ pub(crate) fn run( // options. pub(crate) fn load_call_locations( with_examples: Vec<String>, - dcx: &rustc_errors::DiagCtxt, + dcx: DiagCtxtHandle<'_>, ) -> AllCallLocations { let mut all_calls: AllCallLocations = FxHashMap::default(); for path in with_examples { diff --git a/src/librustdoc/theme.rs b/src/librustdoc/theme.rs index 31d32e23f8e..2fa54a9cd81 100644 --- a/src/librustdoc/theme.rs +++ b/src/librustdoc/theme.rs @@ -5,7 +5,7 @@ use std::iter::Peekable; use std::path::Path; use std::str::Chars; -use rustc_errors::DiagCtxt; +use rustc_errors::DiagCtxtHandle; #[cfg(test)] mod tests; @@ -236,7 +236,7 @@ pub(crate) fn get_differences( pub(crate) fn test_theme_against<P: AsRef<Path>>( f: &P, origin: &FxHashMap<String, CssPath>, - dcx: &DiagCtxt, + dcx: DiagCtxtHandle<'_>, ) -> (bool, Vec<String>) { let against = match fs::read_to_string(f) .map_err(|e| e.to_string()) diff --git a/src/tools/build-manifest/src/main.rs b/src/tools/build-manifest/src/main.rs index b4d47cba7c5..a709aab7ce2 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", diff --git a/src/tools/cargo b/src/tools/cargo -Subproject a1f47ec3f7cd076986f1bfcd7061f2e8cb1a726 +Subproject 3ed207e416fb2f678a40cc79c02dcf4f936a21c diff --git a/src/tools/clippy/clippy_lints/src/needless_maybe_sized.rs b/src/tools/clippy/clippy_lints/src/needless_maybe_sized.rs index 06ae1723a03..4922c87b206 100644 --- a/src/tools/clippy/clippy_lints/src/needless_maybe_sized.rs +++ b/src/tools/clippy/clippy_lints/src/needless_maybe_sized.rs @@ -73,7 +73,7 @@ fn type_param_bounds<'tcx>(generics: &'tcx Generics<'tcx>) -> impl Iterator<Item predicate_pos, bound_pos, }), - GenericBound::Outlives(_) => None, + GenericBound::Outlives(_) | GenericBound::Use(..) => None, }) .filter(|bound| !bound.trait_bound.span.from_expansion()), ) diff --git a/src/tools/clippy/clippy_utils/src/ast_utils.rs b/src/tools/clippy/clippy_utils/src/ast_utils.rs index c70f5c2df84..fb43f7d80af 100644 --- a/src/tools/clippy/clippy_utils/src/ast_utils.rs +++ b/src/tools/clippy/clippy_utils/src/ast_utils.rs @@ -724,11 +724,8 @@ pub fn eq_ty(l: &Ty, r: &Ty) -> bool { (Tup(l), Tup(r)) => over(l, r, |l, r| eq_ty(l, r)), (Path(lq, lp), Path(rq, rp)) => both(lq, rq, eq_qself) && eq_path(lp, rp), (TraitObject(lg, ls), TraitObject(rg, rs)) => ls == rs && over(lg, rg, eq_generic_bound), - (ImplTrait(_, lg, lc), ImplTrait(_, rg, rc)) => { + (ImplTrait(_, lg), ImplTrait(_, rg)) => { over(lg, rg, eq_generic_bound) - && both(lc, rc, |lc, rc| { - over(lc.0.as_slice(), rc.0.as_slice(), eq_precise_capture) - }) }, (Typeof(l), Typeof(r)) => eq_expr(&l.value, &r.value), (MacCall(l), MacCall(r)) => eq_mac_call(l, r), diff --git a/src/tools/clippy/src/driver.rs b/src/tools/clippy/src/driver.rs index f79da26964f..6117e76897f 100644 --- a/src/tools/clippy/src/driver.rs +++ b/src/tools/clippy/src/driver.rs @@ -180,12 +180,12 @@ pub fn main() { rustc_driver::init_rustc_env_logger(&early_dcx); - let using_internal_features = rustc_driver::install_ice_hook(BUG_REPORT_URL, |handler| { + let using_internal_features = rustc_driver::install_ice_hook(BUG_REPORT_URL, |dcx| { // FIXME: this macro calls unwrap internally but is called in a panicking context! It's not // as simple as moving the call from the hook to main, because `install_ice_hook` doesn't // accept a generic closure. let version_info = rustc_tools_util::get_version_info!(); - handler.note(format!("Clippy version: {version_info}")); + dcx.handle().note(format!("Clippy version: {version_info}")); }); exit(rustc_driver::catch_with_exit_code(move || { diff --git a/src/tools/linkchecker/Cargo.toml b/src/tools/linkchecker/Cargo.toml index 05049aabc7d..f1be6e9e749 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 32f935de730..7321bd1bb52 100644 --- a/src/tools/linkchecker/main.rs +++ b/src/tools/linkchecker/main.rs @@ -503,7 +503,7 @@ fn maybe_redirect(source: &str) -> Option<String> { fn parse_html<Sink: TokenSink>(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/miri/src/diagnostics.rs b/src/tools/miri/src/diagnostics.rs index 14e29aa423d..12fb76f3972 100644 --- a/src/tools/miri/src/diagnostics.rs +++ b/src/tools/miri/src/diagnostics.rs @@ -566,7 +566,7 @@ pub fn report_msg<'tcx>( let is_local = machine.is_local(frame_info); // No span for non-local frames and the first frame (which is the error site). if is_local && idx > 0 { - err.subdiagnostic(err.dcx, frame_info.as_note(machine.tcx)); + err.subdiagnostic(frame_info.as_note(machine.tcx)); } else { let sm = sess.source_map(); let span = sm.span_to_embeddable_string(frame_info.span); diff --git a/src/tools/miri/src/intrinsics/mod.rs b/src/tools/miri/src/intrinsics/mod.rs index 74e39ffd933..313eac36337 100644 --- a/src/tools/miri/src/intrinsics/mod.rs +++ b/src/tools/miri/src/intrinsics/mod.rs @@ -57,7 +57,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { ); } Ok(Some(ty::Instance { - def: ty::InstanceDef::Item(instance.def_id()), + def: ty::InstanceKind::Item(instance.def_id()), args: instance.args, })) } 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 d88781ed225..112a9687837 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 d88781ed225..112a9687837 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 447f7cae6ce..8dd76edafea 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 bae34149807..55f66a275b6 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 3b7a1511fa0..5829c1897bb 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 7694cc70b22..d4abf19cd1e 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 e6a4380ea51..507f17abf4e 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 23e2021eeef..a5d8b4d2eeb 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 20a0ddb9019..62fbbf942cb 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/storage-live-dead-var.rs b/src/tools/miri/tests/fail/storage-live-dead-var.rs new file mode 100644 index 00000000000..83ab98d79d1 --- /dev/null +++ b/src/tools/miri/tests/fail/storage-live-dead-var.rs @@ -0,0 +1,14 @@ +#![feature(core_intrinsics, custom_mir)] +use std::intrinsics::mir::*; + +#[custom_mir(dialect = "runtime")] +fn main() { + mir! { + let val: i32; + { + val = 42; //~ERROR: accessing a dead local variable + StorageLive(val); // too late... (but needs to be here to make `val` not implicitly live) + Return() + } + } +} diff --git a/src/tools/miri/tests/fail/storage-live-dead-var.stderr b/src/tools/miri/tests/fail/storage-live-dead-var.stderr new file mode 100644 index 00000000000..ccc77b1c978 --- /dev/null +++ b/src/tools/miri/tests/fail/storage-live-dead-var.stderr @@ -0,0 +1,15 @@ +error: Undefined Behavior: accessing a dead local variable + --> $DIR/storage-live-dead-var.rs:LL:CC + | +LL | val = 42; + | ^^^^^^^^ accessing a dead local variable + | + = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior + = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information + = note: BACKTRACE: + = note: inside `main` at $DIR/storage-live-dead-var.rs:LL:CC + +note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace + +error: aborting due to 1 previous error + diff --git a/src/tools/miri/tests/fail/storage-live-resets-var.rs b/src/tools/miri/tests/fail/storage-live-resets-var.rs new file mode 100644 index 00000000000..bfdd9e78943 --- /dev/null +++ b/src/tools/miri/tests/fail/storage-live-resets-var.rs @@ -0,0 +1,17 @@ +#![feature(core_intrinsics, custom_mir)] +use std::intrinsics::mir::*; + +#[custom_mir(dialect = "runtime")] +fn main() { + mir! { + let val: i32; + let _val2: i32; + { + StorageLive(val); + val = 42; + StorageLive(val); // reset val to `uninit` + _val2 = val; //~ERROR: uninitialized + Return() + } + } +} diff --git a/src/tools/miri/tests/fail/storage-live-resets-var.stderr b/src/tools/miri/tests/fail/storage-live-resets-var.stderr new file mode 100644 index 00000000000..07d39cc9d6b --- /dev/null +++ b/src/tools/miri/tests/fail/storage-live-resets-var.stderr @@ -0,0 +1,15 @@ +error: Undefined Behavior: constructing invalid value: encountered uninitialized memory, but expected an integer + --> $DIR/storage-live-resets-var.rs:LL:CC + | +LL | _val2 = val; + | ^^^^^^^^^^^ constructing invalid value: encountered uninitialized memory, but expected an integer + | + = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior + = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information + = note: BACKTRACE: + = note: inside `main` at $DIR/storage-live-resets-var.rs:LL:CC + +note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace + +error: aborting due to 1 previous error + diff --git a/src/tools/miri/tests/fail/terminate-terminator.stderr b/src/tools/miri/tests/fail/terminate-terminator.stderr index f737adc561d..a5fa0b3e07a 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 7e722f7be32..547d550d3d0 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 bc24d6de734..c05950ebdc7 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 (<fn() as std::ops::FnOnce<()>>::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 246e54becd8..b56d983d429 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 (<fn() as std::ops::FnOnce<()>>::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 c48061d64d0..b06dd1da3c6 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: <fn() as std::ops::FnOnce<()>>::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 4596cadb958..84bdda59fce 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: <fn() as std::ops::FnOnce<()>>::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/run-make-support/src/command.rs b/src/tools/run-make-support/src/command.rs index dab18dca2ff..f39bcfd60df 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_contains, assert_not_contains, handle_failed_output}; +use crate::{assert_contains, assert_equals, 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. @@ -21,6 +21,7 @@ use crate::{assert_contains, assert_not_contains, handle_failed_output}; /// /// [`run`]: Self::run /// [`run_fail`]: Self::run_fail +/// [`run_unchecked`]: Self::run_unchecked #[derive(Debug)] pub struct Command { cmd: StdCommand, @@ -116,6 +117,15 @@ impl Command { output } + /// Run the command but do not check its exit status. + /// Only use if you explicitly don't care about the exit status. + /// Prefer to use [`Self::run`] and [`Self::run_fail`] + /// whenever possible. + #[track_caller] + pub fn run_unchecked(&mut self) -> CompletedProcess { + self.command_output() + } + #[track_caller] fn command_output(&mut self) -> CompletedProcess { self.drop_bomb.defuse(); @@ -163,41 +173,45 @@ impl CompletedProcess { self.output.status } - /// Checks that trimmed `stdout` matches trimmed `content`. + /// Checks that trimmed `stdout` matches trimmed `expected`. #[track_caller] - pub fn assert_stdout_equals<S: AsRef<str>>(&self, content: S) -> &Self { - assert_eq!(self.stdout_utf8().trim(), content.as_ref().trim()); + pub fn assert_stdout_equals<S: AsRef<str>>(&self, expected: S) -> &Self { + assert_equals(self.stdout_utf8().trim(), expected.as_ref().trim()); self } + /// Checks that `stdout` does not contain `unexpected`. #[track_caller] - pub fn assert_stdout_contains<S: AsRef<str>>(self, needle: S) -> Self { - assert_contains(&self.stdout_utf8(), needle.as_ref()); + pub fn assert_stdout_not_contains<S: AsRef<str>>(&self, unexpected: S) -> &Self { + assert_not_contains(&self.stdout_utf8(), unexpected.as_ref()); self } + /// Checks that `stdout` contains `expected`. #[track_caller] - pub fn assert_stdout_not_contains<S: AsRef<str>>(&self, needle: S) -> &Self { - assert_not_contains(&self.stdout_utf8(), needle.as_ref()); + pub fn assert_stdout_contains<S: AsRef<str>>(&self, expected: S) -> &Self { + assert_contains(&self.stdout_utf8(), expected.as_ref()); self } - /// Checks that trimmed `stderr` matches trimmed `content`. + /// Checks that trimmed `stderr` matches trimmed `expected`. #[track_caller] - pub fn assert_stderr_equals<S: AsRef<str>>(&self, content: S) -> &Self { - assert_eq!(self.stderr_utf8().trim(), content.as_ref().trim()); + pub fn assert_stderr_equals<S: AsRef<str>>(&self, expected: S) -> &Self { + assert_equals(self.stderr_utf8().trim(), expected.as_ref().trim()); self } + /// Checks that `stderr` contains `expected`. #[track_caller] - pub fn assert_stderr_contains<S: AsRef<str>>(&self, needle: S) -> &Self { - assert_contains(&self.stderr_utf8(), needle.as_ref()); + pub fn assert_stderr_contains<S: AsRef<str>>(&self, expected: S) -> &Self { + assert_contains(&self.stderr_utf8(), expected.as_ref()); self } + /// Checks that `stderr` does not contain `unexpected`. #[track_caller] - pub fn assert_stderr_not_contains<S: AsRef<str>>(&self, needle: S) -> &Self { - assert_not_contains(&self.stdout_utf8(), needle.as_ref()); + pub fn assert_stderr_not_contains<S: AsRef<str>>(&self, unexpected: S) -> &Self { + assert_not_contains(&self.stdout_utf8(), unexpected.as_ref()); self } diff --git a/src/tools/run-make-support/src/lib.rs b/src/tools/run-make-support/src/lib.rs index ba4524c150c..f4c101cf81c 100644 --- a/src/tools/run-make-support/src/lib.rs +++ b/src/tools/run-make-support/src/lib.rs @@ -30,7 +30,8 @@ pub use cc::{cc, extra_c_flags, extra_cxx_flags, Cc}; pub use clang::{clang, Clang}; pub use diff::{diff, Diff}; pub use llvm::{ - llvm_filecheck, llvm_profdata, llvm_readobj, LlvmFilecheck, LlvmProfdata, LlvmReadobj, + llvm_filecheck, llvm_objdump, llvm_profdata, llvm_readobj, LlvmFilecheck, LlvmObjdump, + LlvmProfdata, LlvmReadobj, }; pub use run::{cmd, run, run_fail, run_with_args}; pub use rustc::{aux_build, rustc, Rustc}; @@ -214,6 +215,38 @@ pub fn cwd() -> PathBuf { env::current_dir().unwrap() } +// FIXME(Oneirical): This will no longer be required after compiletest receives the ability +// to manipulate read-only files. See https://github.com/rust-lang/rust/issues/126334 +/// Ensure that the path P is read-only while the test runs, and restore original permissions +/// at the end so compiletest can clean up. +/// This will panic on Windows if the path is a directory (as it would otherwise do nothing) +#[track_caller] +pub fn test_while_readonly<P: AsRef<Path>, F: FnOnce() + std::panic::UnwindSafe>( + path: P, + closure: F, +) { + let path = path.as_ref(); + if is_windows() && path.is_dir() { + eprintln!("This helper function cannot be used on Windows to make directories readonly."); + eprintln!( + "See the official documentation: + https://doc.rust-lang.org/std/fs/struct.Permissions.html#method.set_readonly" + ); + panic!("`test_while_readonly` on directory detected while on Windows."); + } + let metadata = fs_wrapper::metadata(&path); + let original_perms = metadata.permissions(); + + let mut new_perms = original_perms.clone(); + new_perms.set_readonly(true); + fs_wrapper::set_permissions(&path, new_perms); + + let success = std::panic::catch_unwind(closure); + + fs_wrapper::set_permissions(&path, original_perms); + success.unwrap(); +} + /// Use `cygpath -w` on a path to get a Windows path string back. This assumes that `cygpath` is /// available on the platform! #[track_caller] @@ -271,6 +304,34 @@ pub fn set_host_rpath(cmd: &mut Command) { }); } +/// Read the contents of a file that cannot simply be read by +/// read_to_string, due to invalid utf8 data, then assert that it contains `expected`. +#[track_caller] +pub fn invalid_utf8_contains<P: AsRef<Path>>(path: P, expected: &str) { + let buffer = fs_wrapper::read(path.as_ref()); + if !String::from_utf8_lossy(&buffer).contains(expected) { + eprintln!("=== FILE CONTENTS (LOSSY) ==="); + eprintln!("{}", String::from_utf8_lossy(&buffer)); + eprintln!("=== SPECIFIED TEXT ==="); + eprintln!("{}", expected); + panic!("specified text was not found in file"); + } +} + +/// Read the contents of a file that cannot simply be read by +/// read_to_string, due to invalid utf8 data, then assert that it does not contain `expected`. +#[track_caller] +pub fn invalid_utf8_not_contains<P: AsRef<Path>>(path: P, expected: &str) { + let buffer = fs_wrapper::read(path.as_ref()); + if String::from_utf8_lossy(&buffer).contains(expected) { + eprintln!("=== FILE CONTENTS (LOSSY) ==="); + eprintln!("{}", String::from_utf8_lossy(&buffer)); + eprintln!("=== SPECIFIED TEXT ==="); + eprintln!("{}", expected); + panic!("specified text was unexpectedly found in file"); + } +} + /// Copy a directory into another. pub fn copy_dir_all(src: impl AsRef<Path>, dst: impl AsRef<Path>) { fn copy_dir_all_inner(src: impl AsRef<Path>, dst: impl AsRef<Path>) -> io::Result<()> { @@ -332,6 +393,18 @@ pub fn read_dir<F: Fn(&Path)>(dir: impl AsRef<Path>, callback: F) { } } +/// Check that `actual` is equal to `expected`. Panic otherwise. +#[track_caller] +pub fn assert_equals(actual: &str, expected: &str) { + if actual != expected { + eprintln!("=== ACTUAL TEXT ==="); + eprintln!("{}", actual); + eprintln!("=== EXPECTED ==="); + eprintln!("{}", expected); + panic!("expected text was not found in actual text"); + } +} + /// Check that `haystack` contains `needle`. Panic otherwise. #[track_caller] pub fn assert_contains(haystack: &str, needle: &str) { @@ -468,6 +541,15 @@ macro_rules! impl_common_helpers { self.cmd.run_fail() } + /// Run the command but do not check its exit status. + /// Only use if you explicitly don't care about the exit status. + /// Prefer to use [`Self::run`] and [`Self::run_fail`] + /// whenever possible. + #[track_caller] + pub fn run_unchecked(&mut self) -> crate::command::CompletedProcess { + self.cmd.run_unchecked() + } + /// Set the path where the command will be run. pub fn current_dir<P: AsRef<::std::path::Path>>(&mut self, path: P) -> &mut Self { self.cmd.current_dir(path); diff --git a/src/tools/run-make-support/src/llvm.rs b/src/tools/run-make-support/src/llvm.rs index 414251abda2..99bce08fc23 100644 --- a/src/tools/run-make-support/src/llvm.rs +++ b/src/tools/run-make-support/src/llvm.rs @@ -2,24 +2,33 @@ use std::path::{Path, PathBuf}; use crate::{env_var, Command}; -/// Construct a new `llvm-readobj` invocation. This assumes that `llvm-readobj` is available -/// at `$LLVM_BIN_DIR/llvm-readobj`. +/// Construct a new `llvm-readobj` invocation with the `GNU` output style. +/// 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() } +/// Construct a new `llvm-objdump` invocation. This assumes that `llvm-objdump` is available +/// at `$LLVM_BIN_DIR/llvm-objdump`. +pub fn llvm_objdump() -> LlvmObjdump { + LlvmObjdump::new() +} + /// A `llvm-readobj` invocation builder. #[derive(Debug)] #[must_use] @@ -41,9 +50,17 @@ pub struct LlvmFilecheck { cmd: Command, } +/// A `llvm-objdump` invocation builder. +#[derive(Debug)] +#[must_use] +pub struct LlvmObjdump { + cmd: Command, +} + crate::impl_common_helpers!(LlvmReadobj); crate::impl_common_helpers!(LlvmProfdata); crate::impl_common_helpers!(LlvmFilecheck); +crate::impl_common_helpers!(LlvmObjdump); /// Generate the path to the bin directory of LLVM. #[must_use] @@ -53,12 +70,24 @@ 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`. + /// Construct a new `llvm-readobj` invocation with the `GNU` output style. + /// 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); - Self { cmd } + let mut readobj = Self { cmd }; + readobj.elf_output_style("GNU"); + readobj + } + + /// Specify the format of the ELF information. + /// + /// Valid options are `LLVM` (default), `GNU`, and `JSON`. + pub fn elf_output_style(&mut self, style: &str) -> &mut Self { + self.cmd.arg("--elf-output-style"); + self.cmd.arg(style); + self } /// Provide an input file. @@ -72,11 +101,19 @@ impl LlvmReadobj { self.cmd.arg("--file-header"); self } + + /// Specify the section to display. + pub fn section(&mut self, section: &str) -> &mut Self { + self.cmd.arg("--string-dump"); + self.cmd.arg(section); + self + } } 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 +144,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); @@ -125,3 +163,19 @@ impl LlvmFilecheck { self } } + +impl LlvmObjdump { + /// Construct a new `llvm-objdump` invocation. This assumes that `llvm-objdump` is available + /// at `$LLVM_BIN_DIR/llvm-objdump`. + pub fn new() -> Self { + let llvm_objdump = llvm_bin_dir().join("llvm-objdump"); + let cmd = Command::new(llvm_objdump); + Self { cmd } + } + + /// Provide an input file. + pub fn input<P: AsRef<Path>>(&mut self, path: P) -> &mut Self { + self.cmd.arg(path.as_ref()); + self + } +} 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 3c719356e8f..00000000000 --- a/src/tools/run-make-support/src/llvm_readobj.rs +++ /dev/null @@ -1,45 +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)] -#[must_use] -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<P: AsRef<Path>>(&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/rust-demangler/Cargo.toml b/src/tools/rust-demangler/Cargo.toml deleted file mode 100644 index 2bb73b3262d..00000000000 --- a/src/tools/rust-demangler/Cargo.toml +++ /dev/null @@ -1,16 +0,0 @@ -[package] -name = "rust-demangler" -version = "0.0.1" -edition = "2021" - -[dependencies] -regex = "1.0" -rustc-demangle = "0.1.17" - -[lib] -name = "rust_demangler" -doctest = false - -[[bin]] -name = "rust-demangler" -test = false diff --git a/src/tools/rust-demangler/README.md b/src/tools/rust-demangler/README.md deleted file mode 100644 index 4e8a689a13a..00000000000 --- a/src/tools/rust-demangler/README.md +++ /dev/null @@ -1,36 +0,0 @@ -# rust-demangler - -_Demangles rustc mangled names._ - -`rust-demangler` supports the requirements of the [`llvm-cov show -Xdemangler` -option](https://llvm.org/docs/CommandGuide/llvm-cov.html#cmdoption-llvm-cov-show-xdemangler), -to perform Rust-specific symbol demangling: - -> _The demangler is expected to read a newline-separated list of symbols from -> stdin and write a newline-separated list of the same length to stdout._ - -To use `rust-demangler` with `llvm-cov` for example: - -```shell -$ TARGET="${PWD}/build/x86_64-unknown-linux-gnu" -$ "${TARGET}"/llvm/bin/llvm-cov show \ - --Xdemangler=path/to/rust-demangler \ - --instr-profile=main.profdata ./main --show-line-counts-or-regions -``` - -`rust-demangler` is a Rust "extended tool", used in Rust compiler tests, and -optionally included in Rust distributions that enable coverage profiling. Symbol -demangling is implemented using the -[rustc-demangle](https://crates.io/crates/rustc-demangle) crate. - -_(Note, for Rust developers, the third-party tool -[`rustfilt`](https://crates.io/crates/rustfilt) also supports `llvm-cov` symbol -demangling. `rustfilt` is a more generalized tool that searches any body of -text, using pattern matching, to find and demangle Rust symbols.)_ - -## License - -Rust-demangler is distributed under the terms of both the MIT license and the -Apache License (Version 2.0). - -See [LICENSE-APACHE](/LICENSE-APACHE) and [LICENSE-MIT](/LICENSE-MIT) for details. diff --git a/src/tools/rust-demangler/src/lib.rs b/src/tools/rust-demangler/src/lib.rs deleted file mode 100644 index 1d972229d95..00000000000 --- a/src/tools/rust-demangler/src/lib.rs +++ /dev/null @@ -1,21 +0,0 @@ -use regex::Regex; -use rustc_demangle::demangle; -use std::str::Lines; - -const REPLACE_COLONS: &str = "::"; - -pub fn create_disambiguator_re() -> Regex { - Regex::new(r"\[[a-f0-9]{5,16}\]::").unwrap() -} - -pub fn demangle_lines(lines: Lines<'_>, strip_crate_disambiguators: Option<Regex>) -> Vec<String> { - let mut demangled_lines = Vec::new(); - for mangled in lines { - let mut demangled = demangle(mangled).to_string(); - if let Some(re) = &strip_crate_disambiguators { - demangled = re.replace_all(&demangled, REPLACE_COLONS).to_string(); - } - demangled_lines.push(demangled); - } - demangled_lines -} diff --git a/src/tools/rust-demangler/src/main.rs b/src/tools/rust-demangler/src/main.rs deleted file mode 100644 index 1b5ef5d2442..00000000000 --- a/src/tools/rust-demangler/src/main.rs +++ /dev/null @@ -1,97 +0,0 @@ -//! Demangles rustc mangled names. -//! -//! Note regarding crate disambiguators: -//! -//! Some demangled symbol paths can include "crate disambiguator" suffixes, represented as a large -//! hexadecimal value enclosed in square braces, and appended to the name of the crate. a suffix to the -//! original crate name. For example, the `core` crate, here, includes a disambiguator: -//! -//! ```rust -//! <generics::Firework<f64> as core[a7a74cee373f048]::ops::drop::Drop>::drop -//! ``` -//! -//! These disambiguators are known to vary depending on environmental circumstances. As a result, -//! tests that compare results including demangled names can fail across development environments, -//! particularly with cross-platform testing. Also, the resulting crate paths are not syntactically -//! valid, and don't match the original source symbol paths, which can impact development tools. -//! -//! For these reasons, by default, `rust-demangler` uses a heuristic to remove crate disambiguators -//! from their original demangled representation before printing them to standard output. If crate -//! disambiguators are required, add the `-d` (or `--disambiguators`) flag, and the disambiguators -//! will not be removed. -//! -//! Also note that the disambiguators are stripped by a Regex pattern that is tolerant to some -//! variation in the number of hexadecimal digits. The disambiguators come from a hash value, which -//! typically generates a 16-digit hex representation on a 64-bit architecture; however, leading -//! zeros are not included, which can shorten the hex digit length, and a different hash algorithm -//! that might also be dependent on the architecture, might shorten the length even further. A -//! minimum length of 5 digits is assumed, which should be more than sufficient to support hex -//! representations that generate only 8-digits of precision with an extremely rare (but not -//! impossible) result with up to 3 leading zeros. -//! -//! Using a minimum number of digits less than 5 risks the possibility of stripping demangled name -//! components with a similar pattern. For example, some closures instantiated multiple times -//! include their own disambiguators, demangled as non-hashed zero-based indexes in square brackets. -//! These disambiguators seem to have more analytical value (for instance, in coverage analysis), so -//! they are not removed. - -use rust_demangler::*; -use std::io::{self, Read, Write}; - -fn main() -> io::Result<()> { - // FIXME(richkadel): In Issue #77615 discussed updating the `rustc-demangle` library, to provide - // an option to generate demangled names without including crate disambiguators. If that - // happens, update this tool to use that option (if the `-d` flag is not set) instead stripping - // them via the Regex heuristic. The update the doc comments and help. - - // Strip hashed hexadecimal crate disambiguators. Leading zeros are not enforced, and can be - // different across different platform/architecture types, so while 16 hex digits are common, - // they can also be shorter. - // - // Also note that a demangled symbol path may include the `[<digits>]` pattern, with zero-based - // indexes (such as for closures, and possibly for types defined in anonymous scopes). Preferably - // these should not be stripped. - // - // The minimum length of 5 digits supports the possibility that some target architecture (maybe - // a 32-bit or smaller architecture) could generate a hash value with a maximum of 8 digits, - // and more than three leading zeros should be extremely unlikely. Conversely, it should be - // sufficient to assume the zero-based indexes for closures and anonymous scopes will never - // exceed the value 9999. - let mut strip_crate_disambiguators = Some(create_disambiguator_re()); - - let mut args = std::env::args(); - let progname = args.next().unwrap(); - for arg in args { - if arg == "--disambiguators" || arg == "-d" { - strip_crate_disambiguators = None; - } else { - eprintln!(); - eprintln!("Usage: {} [-d|--disambiguators]", progname); - eprintln!(); - eprintln!( - "This tool converts a list of Rust mangled symbols (one per line) into a\n\ - corresponding list of demangled symbols." - ); - eprintln!(); - eprintln!( - "With -d (--disambiguators), Rust symbols mangled with the v0 symbol mangler may\n\ - include crate disambiguators (a hexadecimal hash value, typically up to 16 digits\n\ - long, enclosed in square brackets)." - ); - eprintln!(); - eprintln!( - "By default, crate disambiguators are removed, using a heuristics-based regular\n\ - expression. (See the `rust-demangler` doc comments for more information.)" - ); - eprintln!(); - std::process::exit(1) - } - } - - let mut buffer = String::new(); - io::stdin().read_to_string(&mut buffer)?; - let mut demangled_lines = demangle_lines(buffer.lines(), strip_crate_disambiguators); - demangled_lines.push("".to_string()); // ensure a trailing newline - io::stdout().write_all(demangled_lines.join("\n").as_bytes())?; - Ok(()) -} diff --git a/src/tools/rust-demangler/tests/lib.rs b/src/tools/rust-demangler/tests/lib.rs deleted file mode 100644 index 85019df7867..00000000000 --- a/src/tools/rust-demangler/tests/lib.rs +++ /dev/null @@ -1,84 +0,0 @@ -use rust_demangler::*; - -const MANGLED_INPUT: &str = r" -_RNvC6_123foo3bar -_RNqCs4fqI2P2rA04_11utf8_identsu30____7hkackfecea1cbdathfdh9hlq6y -_RNCNCNgCs6DXkGYLi8lr_2cc5spawn00B5_ -_RNCINkXs25_NgCsbmNqQUJIY6D_4core5sliceINyB9_4IterhENuNgNoBb_4iter8iterator8Iterator9rpositionNCNgNpB9_6memchr7memrchrs_0E0Bb_ -_RINbNbCskIICzLVDPPb_5alloc5alloc8box_freeDINbNiB4_5boxed5FnBoxuEp6OutputuEL_ECs1iopQbuBiw2_3std -INtC8arrayvec8ArrayVechKj7b_E -_RMCs4fqI2P2rA04_13const_genericINtB0_8UnsignedKhb_E -_RMCs4fqI2P2rA04_13const_genericINtB0_6SignedKs98_E -_RMCs4fqI2P2rA04_13const_genericINtB0_6SignedKanb_E -_RMCs4fqI2P2rA04_13const_genericINtB0_4BoolKb0_E -_RMCs4fqI2P2rA04_13const_genericINtB0_4BoolKb1_E -_RMCs4fqI2P2rA04_13const_genericINtB0_4CharKc76_E -_RMCs4fqI2P2rA04_13const_genericINtB0_4CharKca_E -_RMCs4fqI2P2rA04_13const_genericINtB0_4CharKc2202_E -_RNvNvMCs4fqI2P2rA04_13const_genericINtB4_3FooKpE3foo3FOO -_RC3foo.llvm.9D1C9369 -_RC3foo.llvm.9D1C9369@@16 -_RNvC9backtrace3foo.llvm.A5310EB9 -_RNvNtNtNtNtCs92dm3009vxr_4rand4rngs7adapter9reseeding4fork23FORK_HANDLER_REGISTERED.0.0 -"; - -const DEMANGLED_OUTPUT: &str = r" -123foo[0]::bar -utf8_idents[317d481089b8c8fe]::საჭმელად_გემრიელი_სადილი -cc[4d6468d6c9fd4bb3]::spawn::{closure#0}::{closure#0} -<core[846817f741e54dfd]::slice::Iter<u8> as core[846817f741e54dfd]::iter::iterator::Iterator>::rposition::<core[846817f741e54dfd]::slice::memchr::memrchr::{closure#1}>::{closure#0} -alloc[f15a878b47eb696b]::alloc::box_free::<dyn alloc[f15a878b47eb696b]::boxed::FnBox<(), Output = ()>> -INtC8arrayvec8ArrayVechKj7b_E -<const_generic[317d481089b8c8fe]::Unsigned<11u8>> -<const_generic[317d481089b8c8fe]::Signed<152i16>> -<const_generic[317d481089b8c8fe]::Signed<-11i8>> -<const_generic[317d481089b8c8fe]::Bool<false>> -<const_generic[317d481089b8c8fe]::Bool<true>> -<const_generic[317d481089b8c8fe]::Char<'v'>> -<const_generic[317d481089b8c8fe]::Char<'\n'>> -<const_generic[317d481089b8c8fe]::Char<'∂'>> -<const_generic[317d481089b8c8fe]::Foo<_>>::foo::FOO -foo[0] -foo[0] -backtrace[0]::foo -rand[693ea8e72247470f]::rngs::adapter::reseeding::fork::FORK_HANDLER_REGISTERED.0.0 -"; - -const DEMANGLED_OUTPUT_NO_CRATE_DISAMBIGUATORS: &str = r" -123foo[0]::bar -utf8_idents::საჭმელად_გემრიელი_სადილი -cc::spawn::{closure#0}::{closure#0} -<core::slice::Iter<u8> as core::iter::iterator::Iterator>::rposition::<core::slice::memchr::memrchr::{closure#1}>::{closure#0} -alloc::alloc::box_free::<dyn alloc::boxed::FnBox<(), Output = ()>> -INtC8arrayvec8ArrayVechKj7b_E -<const_generic::Unsigned<11u8>> -<const_generic::Signed<152i16>> -<const_generic::Signed<-11i8>> -<const_generic::Bool<false>> -<const_generic::Bool<true>> -<const_generic::Char<'v'>> -<const_generic::Char<'\n'>> -<const_generic::Char<'∂'>> -<const_generic::Foo<_>>::foo::FOO -foo[0] -foo[0] -backtrace[0]::foo -rand::rngs::adapter::reseeding::fork::FORK_HANDLER_REGISTERED.0.0 -"; - -#[test] -fn test_demangle_lines() { - let demangled_lines = demangle_lines(MANGLED_INPUT.lines(), None); - for (expected, actual) in DEMANGLED_OUTPUT.lines().zip(demangled_lines) { - assert_eq!(expected, actual); - } -} - -#[test] -fn test_demangle_lines_no_crate_disambiguators() { - let demangled_lines = demangle_lines(MANGLED_INPUT.lines(), Some(create_disambiguator_re())); - for (expected, actual) in DEMANGLED_OUTPUT_NO_CRATE_DISAMBIGUATORS.lines().zip(demangled_lines) - { - assert_eq!(expected, actual); - } -} diff --git a/src/tools/rustfmt/src/parse/macros/cfg_if.rs b/src/tools/rustfmt/src/parse/macros/cfg_if.rs index 5fc988e4319..b91d203d531 100644 --- a/src/tools/rustfmt/src/parse/macros/cfg_if.rs +++ b/src/tools/rustfmt/src/parse/macros/cfg_if.rs @@ -67,7 +67,7 @@ fn parse_cfg_if_inner<'a>( Ok(None) => continue, Err(err) => { err.cancel(); - parser.psess.dcx.reset_err_count(); + parser.psess.dcx().reset_err_count(); return Err( "Expected item inside cfg_if block, but failed to parse it as an item", ); diff --git a/src/tools/rustfmt/src/parse/macros/lazy_static.rs b/src/tools/rustfmt/src/parse/macros/lazy_static.rs index badd9569950..7026935294a 100644 --- a/src/tools/rustfmt/src/parse/macros/lazy_static.rs +++ b/src/tools/rustfmt/src/parse/macros/lazy_static.rs @@ -16,8 +16,8 @@ pub(crate) fn parse_lazy_static( ($method:ident $(,)* $($arg:expr),* $(,)*) => { match parser.$method($($arg,)*) { Ok(val) => { - if parser.psess.dcx.has_errors().is_some() { - parser.psess.dcx.reset_err_count(); + if parser.psess.dcx().has_errors().is_some() { + parser.psess.dcx().reset_err_count(); return None; } else { val @@ -25,7 +25,7 @@ pub(crate) fn parse_lazy_static( } Err(err) => { err.cancel(); - parser.psess.dcx.reset_err_count(); + parser.psess.dcx().reset_err_count(); return None; } } diff --git a/src/tools/rustfmt/src/parse/macros/mod.rs b/src/tools/rustfmt/src/parse/macros/mod.rs index cbcc0b2d636..89169e10715 100644 --- a/src/tools/rustfmt/src/parse/macros/mod.rs +++ b/src/tools/rustfmt/src/parse/macros/mod.rs @@ -29,8 +29,8 @@ fn parse_macro_arg<'a, 'b: 'a>(parser: &'a mut Parser<'b>) -> Option<MacroArg> { if Parser::nonterminal_may_begin_with($nt_kind, &cloned_parser.token) { match $try_parse(&mut cloned_parser) { Ok(x) => { - if parser.psess.dcx.has_errors().is_some() { - parser.psess.dcx.reset_err_count(); + if parser.psess.dcx().has_errors().is_some() { + parser.psess.dcx().reset_err_count(); } else { // Parsing succeeded. *parser = cloned_parser; @@ -39,7 +39,7 @@ fn parse_macro_arg<'a, 'b: 'a>(parser: &'a mut Parser<'b>) -> Option<MacroArg> { } Err(e) => { e.cancel(); - parser.psess.dcx.reset_err_count(); + parser.psess.dcx().reset_err_count(); } } } diff --git a/src/tools/rustfmt/src/parse/session.rs b/src/tools/rustfmt/src/parse/session.rs index 1a39d212386..f4fbabaf6c9 100644 --- a/src/tools/rustfmt/src/parse/session.rs +++ b/src/tools/rustfmt/src/parse/session.rs @@ -210,7 +210,9 @@ impl ParseSess { rustc_driver::DEFAULT_LOCALE_RESOURCES.to_vec(), false, ); - self.raw_psess.dcx.make_silent(fallback_bundle, None, false); + self.raw_psess + .dcx() + .make_silent(fallback_bundle, None, false); } pub(crate) fn span_to_filename(&self, span: Span) -> FileName { @@ -286,11 +288,11 @@ impl ParseSess { } pub(super) fn has_errors(&self) -> bool { - self.raw_psess.dcx.has_errors().is_some() + self.raw_psess.dcx().has_errors().is_some() } pub(super) fn reset_errors(&self) { - self.raw_psess.dcx.reset_err_count(); + self.raw_psess.dcx().reset_err_count(); } } diff --git a/src/tools/rustfmt/src/spanned.rs b/src/tools/rustfmt/src/spanned.rs index 4aaf7fdb27f..28911f8af1d 100644 --- a/src/tools/rustfmt/src/spanned.rs +++ b/src/tools/rustfmt/src/spanned.rs @@ -181,6 +181,7 @@ impl Spanned for ast::GenericBound { match *self { ast::GenericBound::Trait(ref ptr, _) => ptr.span, ast::GenericBound::Outlives(ref l) => l.ident.span, + ast::GenericBound::Use(_, span) => span, } } } diff --git a/src/tools/rustfmt/src/types.rs b/src/tools/rustfmt/src/types.rs index 7d14d9e727a..c2c192738c9 100644 --- a/src/tools/rustfmt/src/types.rs +++ b/src/tools/rustfmt/src/types.rs @@ -563,6 +563,8 @@ impl Rewrite for ast::GenericBound { .map(|s| if has_paren { format!("({})", s) } else { s }) } ast::GenericBound::Outlives(ref lifetime) => lifetime.rewrite(context, shape), + // FIXME(precise_capturing): Should implement formatting before stabilization. + ast::GenericBound::Use(..) => None, } } } @@ -843,11 +845,7 @@ impl Rewrite for ast::Ty { rewrite_macro(mac, None, context, shape, MacroPosition::Expression) } ast::TyKind::ImplicitSelf => Some(String::from("")), - ast::TyKind::ImplTrait(_, ref it, ref captures) => { - // FIXME(precise_capturing): Implement formatting. - if captures.is_some() { - return None; - } + ast::TyKind::ImplTrait(_, ref it) => { // Empty trait is not a parser error. if it.is_empty() { return Some("impl".to_owned()); @@ -932,6 +930,8 @@ fn is_generic_bounds_in_order(generic_bounds: &[ast::GenericBound]) -> bool { let is_trait = |b: &ast::GenericBound| match b { ast::GenericBound::Outlives(..) => false, ast::GenericBound::Trait(..) => true, + // FIXME(precise_capturing): This ordering fn should be reworked. + ast::GenericBound::Use(..) => false, }; let is_lifetime = |b: &ast::GenericBound| !is_trait(b); let last_trait_index = generic_bounds.iter().rposition(is_trait); @@ -966,6 +966,8 @@ fn join_bounds_inner( let is_bound_extendable = |s: &str, b: &ast::GenericBound| match b { ast::GenericBound::Outlives(..) => true, ast::GenericBound::Trait(..) => last_line_extendable(s), + // FIXME(precise_capturing): This ordering fn should be reworked. + ast::GenericBound::Use(..) => true, }; // Whether a GenericBound item is a PathSegment segment that includes internal array @@ -1110,8 +1112,7 @@ fn join_bounds_inner( pub(crate) fn opaque_ty(ty: &Option<ptr::P<ast::Ty>>) -> Option<&ast::GenericBounds> { ty.as_ref().and_then(|t| match &t.kind { - // FIXME(precise_capturing): Implement support here - ast::TyKind::ImplTrait(_, bounds, _) => Some(bounds), + ast::TyKind::ImplTrait(_, bounds) => Some(bounds), _ => None, }) } diff --git a/src/tools/tidy/src/allowed_run_make_makefiles.txt b/src/tools/tidy/src/allowed_run_make_makefiles.txt index fdd0be79a4d..eb2e8c2542e 100644 --- a/src/tools/tidy/src/allowed_run_make_makefiles.txt +++ b/src/tools/tidy/src/allowed_run_make_makefiles.txt @@ -1,4 +1,3 @@ -run-make/allocator-shim-circular-deps/Makefile run-make/archive-duplicate-names/Makefile run-make/atomic-lock-free/Makefile run-make/branch-protection-check-IBT/Makefile @@ -35,12 +34,10 @@ run-make/emit-shared-files/Makefile run-make/emit-stack-sizes/Makefile run-make/emit-to-stdout/Makefile run-make/env-dep-info/Makefile -run-make/error-found-staticlib-instead-crate/Makefile run-make/error-writing-dependencies/Makefile run-make/export-executable-symbols/Makefile run-make/extern-diff-internal-name/Makefile run-make/extern-flag-disambiguates/Makefile -run-make/extern-flag-fun/Makefile run-make/extern-flag-pathless/Makefile run-make/extern-flag-rename-transitive/Makefile run-make/extern-fn-explicit-align/Makefile @@ -61,20 +58,15 @@ run-make/foreign-double-unwind/Makefile run-make/foreign-exceptions/Makefile run-make/foreign-rust-exceptions/Makefile run-make/glibc-staticlib-args/Makefile -run-make/inaccessible-temp-dir/Makefile run-make/include_bytes_deps/Makefile run-make/incr-add-rust-src-component/Makefile run-make/incr-foreign-head-span/Makefile -run-make/incremental-debugger-visualizer/Makefile -run-make/incremental-session-fail/Makefile run-make/inline-always-many-cgu/Makefile run-make/interdependent-c-libraries/Makefile run-make/intrinsic-unreachable/Makefile run-make/invalid-library/Makefile run-make/invalid-so/Makefile -run-make/invalid-staticlib/Makefile run-make/issue-107094/Makefile -run-make/issue-10971-temps-dir/Makefile run-make/issue-109934-lto-debuginfo/Makefile run-make/issue-14698/Makefile run-make/issue-15460/Makefile @@ -83,7 +75,6 @@ run-make/issue-20626/Makefile run-make/issue-22131/Makefile run-make/issue-25581/Makefile run-make/issue-26006/Makefile -run-make/issue-26092/Makefile run-make/issue-28595/Makefile run-make/issue-33329/Makefile run-make/issue-35164/Makefile @@ -92,8 +83,6 @@ run-make/issue-37839/Makefile run-make/issue-40535/Makefile run-make/issue-47384/Makefile run-make/issue-47551/Makefile -run-make/issue-51671/Makefile -run-make/issue-64153/Makefile run-make/issue-68794-textrel-on-minimal-lib/Makefile run-make/issue-69368/Makefile run-make/issue-83045/Makefile @@ -109,10 +98,8 @@ run-make/libtest-json/Makefile run-make/libtest-junit/Makefile run-make/libtest-padding/Makefile run-make/libtest-thread-limit/Makefile -run-make/link-arg/Makefile run-make/link-args-order/Makefile run-make/link-cfg/Makefile -run-make/link-dedup/Makefile run-make/link-framework/Makefile run-make/link-path-order/Makefile run-make/linkage-attr-on-static/Makefile @@ -140,20 +127,14 @@ run-make/missing-crate-dependency/Makefile run-make/mixing-libs/Makefile run-make/msvc-opt-minsize/Makefile run-make/native-link-modifier-bundle/Makefile -run-make/native-link-modifier-verbatim-linker/Makefile -run-make/native-link-modifier-verbatim-rustc/Makefile run-make/native-link-modifier-whole-archive/Makefile run-make/no-alloc-shim/Makefile run-make/no-builtins-attribute/Makefile -run-make/no-builtins-lto/Makefile run-make/no-duplicate-libs/Makefile run-make/obey-crate-type-flag/Makefile run-make/optimization-remarks-dir-pgo/Makefile run-make/optimization-remarks-dir/Makefile -run-make/output-filename-conflicts-with-directory/Makefile -run-make/output-filename-overwrites-input/Makefile run-make/output-type-permutations/Makefile -run-make/output-with-hyphens/Makefile run-make/override-aliased-flags/Makefile run-make/overwrite-input/Makefile run-make/panic-abort-eh_frame/Makefile @@ -202,8 +183,6 @@ run-make/rustdoc-io-error/Makefile run-make/sanitizer-cdylib-link/Makefile run-make/sanitizer-dylib-link/Makefile run-make/sanitizer-staticlib-link/Makefile -run-make/separate-link-fail/Makefile -run-make/separate-link/Makefile run-make/sepcomp-cci-copies/Makefile run-make/sepcomp-inlining/Makefile run-make/sepcomp-separate/Makefile @@ -237,7 +216,6 @@ run-make/unknown-mod-stdin/Makefile run-make/unstable-flag-required/Makefile run-make/use-suggestions-rust-2018/Makefile run-make/used-cdylib-macos/Makefile -run-make/used/Makefile run-make/volatile-intrinsics/Makefile run-make/wasm-exceptions-nostd/Makefile run-make/wasm-override-linker/Makefile diff --git a/tests/assembly/targets/targets-elf.rs b/tests/assembly/targets/targets-elf.rs index 4c54fe639e3..b069e667bf5 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/error-provide.rs b/tests/codegen/error-provide.rs new file mode 100644 index 00000000000..68dd383e5cc --- /dev/null +++ b/tests/codegen/error-provide.rs @@ -0,0 +1,50 @@ +// Codegen test for #126242 + +//@ compile-flags: -O +#![crate_type = "lib"] +#![feature(error_generic_member_access)] +use std::error::Request; +use std::fmt; + +#[derive(Debug)] +struct MyBacktrace1 {} + +#[derive(Debug)] +struct MyBacktrace2 {} + +#[derive(Debug)] +struct MyBacktrace3 {} + +#[derive(Debug)] +struct MyError { + backtrace1: MyBacktrace1, + backtrace2: MyBacktrace2, + backtrace3: MyBacktrace3, + other: MyBacktrace3, +} + +impl fmt::Display for MyError { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + write!(f, "Example Error") + } +} + +impl std::error::Error for MyError { + // CHECK-LABEL: @provide + #[no_mangle] + fn provide<'a>(&'a self, request: &mut Request<'a>) { + // LLVM should be able to optimize multiple .provide_* calls into a switch table + // and eliminate redundant ones, rather than compare one-by-one. + + // CHECK-NEXT: start: + // CHECK-NEXT: %[[SCRUTINEE:[^ ]+]] = load i64, ptr + // CHECK-NEXT: switch i64 %[[SCRUTINEE]], label %{{.*}} [ + // CHECK-COUNT-3: i64 {{.*}}, label %{{.*}} + // CHECK-NEXT: ] + request + .provide_ref::<MyBacktrace1>(&self.backtrace1) + .provide_ref::<MyBacktrace3>(&self.other) + .provide_ref::<MyBacktrace2>(&self.backtrace2) + .provide_ref::<MyBacktrace3>(&self.backtrace3); + } +} diff --git a/tests/coverage/attr/nested.cov-map b/tests/coverage/attr/nested.cov-map new file mode 100644 index 00000000000..a613bb7f8cd --- /dev/null +++ b/tests/coverage/attr/nested.cov-map @@ -0,0 +1,100 @@ +Function name: <<<nested::MyOuter as nested::MyTrait>::trait_method::MyMiddle as nested::MyTrait>::trait_method::MyInner as nested::MyTrait>::trait_method (unused) +Raw bytes (9): 0x[01, 01, 00, 01, 00, 39, 15, 02, 16] +Number of files: 1 +- file 0 => global file 1 +Number of expressions: 0 +Number of file 0 mappings: 1 +- Code(Zero) at (prev + 57, 21) to (start + 2, 22) + +Function name: <<<nested::MyOuter>::outer_method::MyMiddle>::middle_method::MyInner>::inner_method (unused) +Raw bytes (9): 0x[01, 01, 00, 01, 00, 23, 15, 02, 16] +Number of files: 1 +- file 0 => global file 1 +Number of expressions: 0 +Number of file 0 mappings: 1 +- Code(Zero) at (prev + 35, 21) to (start + 2, 22) + +Function name: <<nested::MyOuter as nested::MyTrait>::trait_method::MyMiddle as nested::MyTrait>::trait_method (unused) +Raw bytes (9): 0x[01, 01, 00, 01, 00, 36, 0d, 08, 0e] +Number of files: 1 +- file 0 => global file 1 +Number of expressions: 0 +Number of file 0 mappings: 1 +- Code(Zero) at (prev + 54, 13) to (start + 8, 14) + +Function name: <<nested::MyOuter>::outer_method::MyMiddle>::middle_method (unused) +Raw bytes (9): 0x[01, 01, 00, 01, 00, 20, 0d, 08, 0e] +Number of files: 1 +- file 0 => global file 1 +Number of expressions: 0 +Number of file 0 mappings: 1 +- Code(Zero) at (prev + 32, 13) to (start + 8, 14) + +Function name: nested::closure_expr +Raw bytes (14): 0x[01, 01, 00, 02, 01, 44, 01, 01, 0f, 01, 0b, 05, 01, 02] +Number of files: 1 +- file 0 => global file 1 +Number of expressions: 0 +Number of file 0 mappings: 2 +- Code(Counter(0)) at (prev + 68, 1) to (start + 1, 15) +- Code(Counter(0)) at (prev + 11, 5) to (start + 1, 2) + +Function name: nested::closure_expr::{closure#0}::{closure#0} (unused) +Raw bytes (14): 0x[01, 01, 00, 02, 00, 47, 1a, 01, 17, 00, 04, 0d, 01, 0a] +Number of files: 1 +- file 0 => global file 1 +Number of expressions: 0 +Number of file 0 mappings: 2 +- Code(Zero) at (prev + 71, 26) to (start + 1, 23) +- Code(Zero) at (prev + 4, 13) to (start + 1, 10) + +Function name: nested::closure_expr::{closure#0}::{closure#0}::{closure#0} (unused) +Raw bytes (9): 0x[01, 01, 00, 01, 00, 48, 1d, 02, 0e] +Number of files: 1 +- file 0 => global file 1 +Number of expressions: 0 +Number of file 0 mappings: 1 +- Code(Zero) at (prev + 72, 29) to (start + 2, 14) + +Function name: nested::closure_tail +Raw bytes (14): 0x[01, 01, 00, 02, 01, 53, 01, 01, 0f, 01, 11, 05, 01, 02] +Number of files: 1 +- file 0 => global file 1 +Number of expressions: 0 +Number of file 0 mappings: 2 +- Code(Counter(0)) at (prev + 83, 1) to (start + 1, 15) +- Code(Counter(0)) at (prev + 17, 5) to (start + 1, 2) + +Function name: nested::closure_tail::{closure#0}::{closure#0} (unused) +Raw bytes (14): 0x[01, 01, 00, 02, 00, 58, 14, 01, 1f, 00, 06, 15, 01, 12] +Number of files: 1 +- file 0 => global file 1 +Number of expressions: 0 +Number of file 0 mappings: 2 +- Code(Zero) at (prev + 88, 20) to (start + 1, 31) +- Code(Zero) at (prev + 6, 21) to (start + 1, 18) + +Function name: nested::closure_tail::{closure#0}::{closure#0}::{closure#0} (unused) +Raw bytes (9): 0x[01, 01, 00, 01, 00, 5a, 1c, 02, 1a] +Number of files: 1 +- file 0 => global file 1 +Number of expressions: 0 +Number of file 0 mappings: 1 +- Code(Zero) at (prev + 90, 28) to (start + 2, 26) + +Function name: nested::outer_fn::middle_fn (unused) +Raw bytes (9): 0x[01, 01, 00, 01, 00, 11, 05, 05, 06] +Number of files: 1 +- file 0 => global file 1 +Number of expressions: 0 +Number of file 0 mappings: 1 +- Code(Zero) at (prev + 17, 5) to (start + 5, 6) + +Function name: nested::outer_fn::middle_fn::inner_fn (unused) +Raw bytes (9): 0x[01, 01, 00, 01, 00, 12, 09, 02, 0a] +Number of files: 1 +- file 0 => global file 1 +Number of expressions: 0 +Number of file 0 mappings: 1 +- Code(Zero) at (prev + 18, 9) to (start + 2, 10) + diff --git a/tests/coverage/attr/nested.coverage b/tests/coverage/attr/nested.coverage new file mode 100644 index 00000000000..13129572aec --- /dev/null +++ b/tests/coverage/attr/nested.coverage @@ -0,0 +1,111 @@ + LL| |#![feature(coverage_attribute, stmt_expr_attributes)] + LL| |//@ edition: 2021 + LL| | + LL| |// Demonstrates the interaction between #[coverage(off)] and various kinds of + LL| |// nested function. + LL| | + LL| |// FIXME(#126625): Coverage attributes should apply recursively to nested functions. + LL| |// FIXME(#126626): When an inner (non-closure) function has `#[coverage(off)]`, + LL| |// its lines can still be marked with misleading execution counts from its enclosing + LL| |// function. + LL| | + LL| |#[coverage(off)] + LL| |fn do_stuff() {} + LL| | + LL| |#[coverage(off)] + LL| |fn outer_fn() { + LL| 0| fn middle_fn() { + LL| 0| fn inner_fn() { + LL| 0| do_stuff(); + LL| 0| } + LL| 0| do_stuff(); + LL| 0| } + LL| | do_stuff(); + LL| |} + LL| | + LL| |struct MyOuter; + LL| |impl MyOuter { + LL| | #[coverage(off)] + LL| | fn outer_method(&self) { + LL| | struct MyMiddle; + LL| | impl MyMiddle { + LL| 0| fn middle_method(&self) { + LL| 0| struct MyInner; + LL| 0| impl MyInner { + LL| 0| fn inner_method(&self) { + LL| 0| do_stuff(); + LL| 0| } + LL| 0| } + LL| 0| do_stuff(); + LL| 0| } + LL| | } + LL| | do_stuff(); + LL| | } + LL| |} + LL| | + LL| |trait MyTrait { + LL| | fn trait_method(&self); + LL| |} + LL| |impl MyTrait for MyOuter { + LL| | #[coverage(off)] + LL| | fn trait_method(&self) { + LL| | struct MyMiddle; + LL| | impl MyTrait for MyMiddle { + LL| 0| fn trait_method(&self) { + LL| 0| struct MyInner; + LL| 0| impl MyTrait for MyInner { + LL| 0| fn trait_method(&self) { + LL| 0| do_stuff(); + LL| 0| } + LL| 0| } + LL| 0| do_stuff(); + LL| 0| } + LL| | } + LL| | do_stuff(); + LL| | } + LL| |} + LL| | + LL| 1|fn closure_expr() { + LL| 1| let _outer = #[coverage(off)] + LL| | || { + LL| 0| let _middle = || { + LL| 0| let _inner = || { + LL| 0| do_stuff(); + LL| 0| }; + LL| 0| do_stuff(); + LL| 0| }; + LL| | do_stuff(); + LL| | }; + LL| 1| do_stuff(); + LL| 1|} + LL| | + LL| |// This syntax is allowed, even without #![feature(stmt_expr_attributes)]. + LL| 1|fn closure_tail() { + LL| 1| let _outer = { + LL| | #[coverage(off)] + LL| | || { + LL| | let _middle = { + LL| 0| || { + LL| 0| let _inner = { + LL| 0| || { + LL| 0| do_stuff(); + LL| 0| } + LL| | }; + LL| 0| do_stuff(); + LL| 0| } + LL| | }; + LL| | do_stuff(); + LL| | } + LL| | }; + LL| 1| do_stuff(); + LL| 1|} + LL| | + LL| |#[coverage(off)] + LL| |fn main() { + LL| | outer_fn(); + LL| | MyOuter.outer_method(); + LL| | MyOuter.trait_method(); + LL| | closure_expr(); + LL| | closure_tail(); + LL| |} + diff --git a/tests/coverage/attr/nested.rs b/tests/coverage/attr/nested.rs new file mode 100644 index 00000000000..c7ff835f44f --- /dev/null +++ b/tests/coverage/attr/nested.rs @@ -0,0 +1,110 @@ +#![feature(coverage_attribute, stmt_expr_attributes)] +//@ edition: 2021 + +// Demonstrates the interaction between #[coverage(off)] and various kinds of +// nested function. + +// FIXME(#126625): Coverage attributes should apply recursively to nested functions. +// FIXME(#126626): When an inner (non-closure) function has `#[coverage(off)]`, +// its lines can still be marked with misleading execution counts from its enclosing +// function. + +#[coverage(off)] +fn do_stuff() {} + +#[coverage(off)] +fn outer_fn() { + fn middle_fn() { + fn inner_fn() { + do_stuff(); + } + do_stuff(); + } + do_stuff(); +} + +struct MyOuter; +impl MyOuter { + #[coverage(off)] + fn outer_method(&self) { + struct MyMiddle; + impl MyMiddle { + fn middle_method(&self) { + struct MyInner; + impl MyInner { + fn inner_method(&self) { + do_stuff(); + } + } + do_stuff(); + } + } + do_stuff(); + } +} + +trait MyTrait { + fn trait_method(&self); +} +impl MyTrait for MyOuter { + #[coverage(off)] + fn trait_method(&self) { + struct MyMiddle; + impl MyTrait for MyMiddle { + fn trait_method(&self) { + struct MyInner; + impl MyTrait for MyInner { + fn trait_method(&self) { + do_stuff(); + } + } + do_stuff(); + } + } + do_stuff(); + } +} + +fn closure_expr() { + let _outer = #[coverage(off)] + || { + let _middle = || { + let _inner = || { + do_stuff(); + }; + do_stuff(); + }; + do_stuff(); + }; + do_stuff(); +} + +// This syntax is allowed, even without #![feature(stmt_expr_attributes)]. +fn closure_tail() { + let _outer = { + #[coverage(off)] + || { + let _middle = { + || { + let _inner = { + || { + do_stuff(); + } + }; + do_stuff(); + } + }; + do_stuff(); + } + }; + do_stuff(); +} + +#[coverage(off)] +fn main() { + outer_fn(); + MyOuter.outer_method(); + MyOuter.trait_method(); + closure_expr(); + closure_tail(); +} diff --git a/tests/coverage/attr/off-on-sandwich.cov-map b/tests/coverage/attr/off-on-sandwich.cov-map new file mode 100644 index 00000000000..72b96420cb5 --- /dev/null +++ b/tests/coverage/attr/off-on-sandwich.cov-map @@ -0,0 +1,32 @@ +Function name: off_on_sandwich::dense_a::dense_b +Raw bytes (9): 0x[01, 01, 00, 01, 01, 14, 05, 07, 06] +Number of files: 1 +- file 0 => global file 1 +Number of expressions: 0 +Number of file 0 mappings: 1 +- Code(Counter(0)) at (prev + 20, 5) to (start + 7, 6) + +Function name: off_on_sandwich::sparse_a::sparse_b +Raw bytes (9): 0x[01, 01, 00, 01, 01, 22, 05, 10, 06] +Number of files: 1 +- file 0 => global file 1 +Number of expressions: 0 +Number of file 0 mappings: 1 +- Code(Counter(0)) at (prev + 34, 5) to (start + 16, 6) + +Function name: off_on_sandwich::sparse_a::sparse_b::sparse_c +Raw bytes (9): 0x[01, 01, 00, 01, 01, 26, 09, 0b, 0a] +Number of files: 1 +- file 0 => global file 1 +Number of expressions: 0 +Number of file 0 mappings: 1 +- Code(Counter(0)) at (prev + 38, 9) to (start + 11, 10) + +Function name: off_on_sandwich::sparse_a::sparse_b::sparse_c::sparse_d +Raw bytes (9): 0x[01, 01, 00, 01, 01, 29, 0d, 07, 0e] +Number of files: 1 +- file 0 => global file 1 +Number of expressions: 0 +Number of file 0 mappings: 1 +- Code(Counter(0)) at (prev + 41, 13) to (start + 7, 14) + diff --git a/tests/coverage/attr/off-on-sandwich.coverage b/tests/coverage/attr/off-on-sandwich.coverage new file mode 100644 index 00000000000..e831b0e926e --- /dev/null +++ b/tests/coverage/attr/off-on-sandwich.coverage @@ -0,0 +1,58 @@ + LL| |#![feature(coverage_attribute)] + LL| |//@ edition: 2021 + LL| | + LL| |// Demonstrates the interaction of `#[coverage(off)]` and `#[coverage(on)]` + LL| |// in nested functions. + LL| | + LL| |// FIXME(#126625): Coverage attributes should apply recursively to nested functions. + LL| |// FIXME(#126626): When an inner (non-closure) function has `#[coverage(off)]`, + LL| |// its lines can still be marked with misleading execution counts from its enclosing + LL| |// function. + LL| | + LL| |#[coverage(off)] + LL| |fn do_stuff() {} + LL| | + LL| |#[coverage(off)] + LL| |fn dense_a() { + LL| | dense_b(); + LL| | dense_b(); + LL| | #[coverage(on)] + LL| 2| fn dense_b() { + LL| 2| dense_c(); + LL| 2| dense_c(); + LL| 2| #[coverage(off)] + LL| 2| fn dense_c() { + LL| 2| do_stuff(); + LL| 2| } + LL| 2| } + LL| |} + LL| | + LL| |#[coverage(off)] + LL| |fn sparse_a() { + LL| | sparse_b(); + LL| | sparse_b(); + LL| 2| fn sparse_b() { + LL| 2| sparse_c(); + LL| 2| sparse_c(); + LL| 2| #[coverage(on)] + LL| 4| fn sparse_c() { + LL| 4| sparse_d(); + LL| 4| sparse_d(); + LL| 8| fn sparse_d() { + LL| 8| sparse_e(); + LL| 8| sparse_e(); + LL| 8| #[coverage(off)] + LL| 8| fn sparse_e() { + LL| 8| do_stuff(); + LL| 8| } + LL| 8| } + LL| 4| } + LL| 2| } + LL| |} + LL| | + LL| |#[coverage(off)] + LL| |fn main() { + LL| | dense_a(); + LL| | sparse_a(); + LL| |} + diff --git a/tests/coverage/attr/off-on-sandwich.rs b/tests/coverage/attr/off-on-sandwich.rs new file mode 100644 index 00000000000..6b21b180223 --- /dev/null +++ b/tests/coverage/attr/off-on-sandwich.rs @@ -0,0 +1,57 @@ +#![feature(coverage_attribute)] +//@ edition: 2021 + +// Demonstrates the interaction of `#[coverage(off)]` and `#[coverage(on)]` +// in nested functions. + +// FIXME(#126625): Coverage attributes should apply recursively to nested functions. +// FIXME(#126626): When an inner (non-closure) function has `#[coverage(off)]`, +// its lines can still be marked with misleading execution counts from its enclosing +// function. + +#[coverage(off)] +fn do_stuff() {} + +#[coverage(off)] +fn dense_a() { + dense_b(); + dense_b(); + #[coverage(on)] + fn dense_b() { + dense_c(); + dense_c(); + #[coverage(off)] + fn dense_c() { + do_stuff(); + } + } +} + +#[coverage(off)] +fn sparse_a() { + sparse_b(); + sparse_b(); + fn sparse_b() { + sparse_c(); + sparse_c(); + #[coverage(on)] + fn sparse_c() { + sparse_d(); + sparse_d(); + fn sparse_d() { + sparse_e(); + sparse_e(); + #[coverage(off)] + fn sparse_e() { + do_stuff(); + } + } + } + } +} + +#[coverage(off)] +fn main() { + dense_a(); + sparse_a(); +} diff --git a/tests/coverage/branch/no-mir-spans.cov-map b/tests/coverage/branch/no-mir-spans.cov-map new file mode 100644 index 00000000000..cb19211913f --- /dev/null +++ b/tests/coverage/branch/no-mir-spans.cov-map @@ -0,0 +1,52 @@ +Function name: no_mir_spans::while_cond +Raw bytes (16): 0x[01, 01, 00, 02, 01, 10, 01, 00, 11, 20, 05, 09, 04, 0b, 00, 10] +Number of files: 1 +- file 0 => global file 1 +Number of expressions: 0 +Number of file 0 mappings: 2 +- Code(Counter(0)) at (prev + 16, 1) to (start + 0, 17) +- Branch { true: Counter(1), false: Counter(2) } at (prev + 4, 11) to (start + 0, 16) + true = c1 + false = c2 + +Function name: no_mir_spans::while_cond_not +Raw bytes (16): 0x[01, 01, 00, 02, 01, 19, 01, 00, 15, 20, 09, 05, 04, 0b, 00, 14] +Number of files: 1 +- file 0 => global file 1 +Number of expressions: 0 +Number of file 0 mappings: 2 +- Code(Counter(0)) at (prev + 25, 1) to (start + 0, 21) +- Branch { true: Counter(2), false: Counter(1) } at (prev + 4, 11) to (start + 0, 20) + true = c2 + false = c1 + +Function name: no_mir_spans::while_op_and +Raw bytes (25): 0x[01, 01, 01, 09, 0d, 03, 01, 22, 01, 00, 13, 20, 09, 05, 05, 0b, 00, 10, 20, 02, 0d, 00, 14, 00, 19] +Number of files: 1 +- file 0 => global file 1 +Number of expressions: 1 +- expression 0 operands: lhs = Counter(2), rhs = Counter(3) +Number of file 0 mappings: 3 +- Code(Counter(0)) at (prev + 34, 1) to (start + 0, 19) +- Branch { true: Counter(2), false: Counter(1) } at (prev + 5, 11) to (start + 0, 16) + true = c2 + false = c1 +- Branch { true: Expression(0, Sub), false: Counter(3) } at (prev + 0, 20) to (start + 0, 25) + true = (c2 - c3) + false = c3 + +Function name: no_mir_spans::while_op_or +Raw bytes (25): 0x[01, 01, 01, 09, 0d, 03, 01, 2d, 01, 00, 12, 20, 05, 09, 05, 0b, 00, 10, 20, 0d, 02, 00, 14, 00, 19] +Number of files: 1 +- file 0 => global file 1 +Number of expressions: 1 +- expression 0 operands: lhs = Counter(2), rhs = Counter(3) +Number of file 0 mappings: 3 +- Code(Counter(0)) at (prev + 45, 1) to (start + 0, 18) +- Branch { true: Counter(1), false: Counter(2) } at (prev + 5, 11) to (start + 0, 16) + true = c1 + false = c2 +- Branch { true: Counter(3), false: Expression(0, Sub) } at (prev + 0, 20) to (start + 0, 25) + true = c3 + false = (c2 - c3) + diff --git a/tests/coverage/branch/no-mir-spans.coverage b/tests/coverage/branch/no-mir-spans.coverage new file mode 100644 index 00000000000..2cae98ed3ff --- /dev/null +++ b/tests/coverage/branch/no-mir-spans.coverage @@ -0,0 +1,77 @@ + LL| |#![feature(coverage_attribute)] + LL| |//@ edition: 2021 + LL| |//@ compile-flags: -Zcoverage-options=branch,no-mir-spans + LL| |//@ llvm-cov-flags: --show-branches=count + LL| | + LL| |// Tests the behaviour of the `-Zcoverage-options=no-mir-spans` debugging flag. + LL| |// The actual code below is just some non-trivial code copied from another test + LL| |// (`while.rs`), and has no particular significance. + LL| | + LL| |macro_rules! no_merge { + LL| | () => { + LL| | for _ in 0..1 {} + LL| | }; + LL| |} + LL| | + LL| 1|fn while_cond() { + LL| | no_merge!(); + LL| | + LL| | let mut a = 8; + LL| | while a > 0 { + ------------------ + | Branch (LL:11): [True: 8, False: 1] + ------------------ + LL| | a -= 1; + LL| | } + LL| |} + LL| | + LL| 1|fn while_cond_not() { + LL| | no_merge!(); + LL| | + LL| | let mut a = 8; + LL| | while !(a == 0) { + ------------------ + | Branch (LL:11): [True: 8, False: 1] + ------------------ + LL| | a -= 1; + LL| | } + LL| |} + LL| | + LL| 1|fn while_op_and() { + LL| | no_merge!(); + LL| | + LL| | let mut a = 8; + LL| | let mut b = 4; + LL| | while a > 0 && b > 0 { + ------------------ + | Branch (LL:11): [True: 5, False: 0] + | Branch (LL:20): [True: 4, False: 1] + ------------------ + LL| | a -= 1; + LL| | b -= 1; + LL| | } + LL| |} + LL| | + LL| 1|fn while_op_or() { + LL| | no_merge!(); + LL| | + LL| | let mut a = 4; + LL| | let mut b = 8; + LL| | while a > 0 || b > 0 { + ------------------ + | Branch (LL:11): [True: 4, False: 5] + | Branch (LL:20): [True: 4, False: 1] + ------------------ + LL| | a -= 1; + LL| | b -= 1; + LL| | } + LL| |} + LL| | + LL| |#[coverage(off)] + LL| |fn main() { + LL| | while_cond(); + LL| | while_cond_not(); + LL| | while_op_and(); + LL| | while_op_or(); + LL| |} + diff --git a/tests/coverage/branch/no-mir-spans.rs b/tests/coverage/branch/no-mir-spans.rs new file mode 100644 index 00000000000..acb268f2d45 --- /dev/null +++ b/tests/coverage/branch/no-mir-spans.rs @@ -0,0 +1,62 @@ +#![feature(coverage_attribute)] +//@ edition: 2021 +//@ compile-flags: -Zcoverage-options=branch,no-mir-spans +//@ llvm-cov-flags: --show-branches=count + +// Tests the behaviour of the `-Zcoverage-options=no-mir-spans` debugging flag. +// The actual code below is just some non-trivial code copied from another test +// (`while.rs`), and has no particular significance. + +macro_rules! no_merge { + () => { + for _ in 0..1 {} + }; +} + +fn while_cond() { + no_merge!(); + + let mut a = 8; + while a > 0 { + a -= 1; + } +} + +fn while_cond_not() { + no_merge!(); + + let mut a = 8; + while !(a == 0) { + a -= 1; + } +} + +fn while_op_and() { + no_merge!(); + + let mut a = 8; + let mut b = 4; + while a > 0 && b > 0 { + a -= 1; + b -= 1; + } +} + +fn while_op_or() { + no_merge!(); + + let mut a = 4; + let mut b = 8; + while a > 0 || b > 0 { + a -= 1; + b -= 1; + } +} + +#[coverage(off)] +fn main() { + while_cond(); + while_cond_not(); + while_op_and(); + while_op_or(); +} diff --git a/tests/coverage/mcdc_non_control_flow.cov-map b/tests/coverage/mcdc_non_control_flow.cov-map new file mode 100644 index 00000000000..937c36e1f16 --- /dev/null +++ b/tests/coverage/mcdc_non_control_flow.cov-map @@ -0,0 +1,204 @@ +Function name: mcdc_non_control_flow::assign_3 +Raw bytes (89): 0x[01, 01, 09, 05, 07, 0b, 11, 09, 0d, 01, 05, 01, 05, 22, 11, 01, 05, 22, 11, 01, 05, 0a, 01, 16, 01, 00, 28, 03, 01, 09, 00, 0a, 01, 00, 0d, 00, 0e, 28, 00, 03, 00, 0d, 00, 18, 30, 05, 22, 01, 00, 02, 00, 0d, 00, 0e, 22, 00, 12, 00, 13, 30, 1e, 11, 02, 03, 00, 00, 12, 00, 13, 1e, 00, 17, 00, 18, 30, 09, 0d, 03, 00, 00, 00, 17, 00, 18, 03, 01, 05, 01, 02] +Number of files: 1 +- file 0 => global file 1 +Number of expressions: 9 +- expression 0 operands: lhs = Counter(1), rhs = Expression(1, Add) +- expression 1 operands: lhs = Expression(2, Add), rhs = Counter(4) +- expression 2 operands: lhs = Counter(2), rhs = Counter(3) +- expression 3 operands: lhs = Counter(0), rhs = Counter(1) +- expression 4 operands: lhs = Counter(0), rhs = Counter(1) +- expression 5 operands: lhs = Expression(8, Sub), rhs = Counter(4) +- expression 6 operands: lhs = Counter(0), rhs = Counter(1) +- expression 7 operands: lhs = Expression(8, Sub), rhs = Counter(4) +- expression 8 operands: lhs = Counter(0), rhs = Counter(1) +Number of file 0 mappings: 10 +- Code(Counter(0)) at (prev + 22, 1) to (start + 0, 40) +- Code(Expression(0, Add)) at (prev + 1, 9) to (start + 0, 10) + = (c1 + ((c2 + c3) + c4)) +- Code(Counter(0)) at (prev + 0, 13) to (start + 0, 14) +- MCDCDecision { bitmap_idx: 0, conditions_num: 3 } at (prev + 0, 13) to (start + 0, 24) +- MCDCBranch { true: Counter(1), false: Expression(8, Sub), condition_id: 1, true_next_id: 0, false_next_id: 2 } at (prev + 0, 13) to (start + 0, 14) + true = c1 + false = (c0 - c1) +- Code(Expression(8, Sub)) at (prev + 0, 18) to (start + 0, 19) + = (c0 - c1) +- MCDCBranch { true: Expression(7, Sub), false: Counter(4), condition_id: 2, true_next_id: 3, false_next_id: 0 } at (prev + 0, 18) to (start + 0, 19) + true = ((c0 - c1) - c4) + false = c4 +- Code(Expression(7, Sub)) at (prev + 0, 23) to (start + 0, 24) + = ((c0 - c1) - c4) +- MCDCBranch { true: Counter(2), false: Counter(3), condition_id: 3, true_next_id: 0, false_next_id: 0 } at (prev + 0, 23) to (start + 0, 24) + true = c2 + false = c3 +- Code(Expression(0, Add)) at (prev + 1, 5) to (start + 1, 2) + = (c1 + ((c2 + c3) + c4)) + +Function name: mcdc_non_control_flow::assign_3_bis +Raw bytes (85): 0x[01, 01, 07, 07, 11, 09, 0d, 01, 05, 05, 09, 16, 1a, 05, 09, 01, 05, 0a, 01, 1b, 01, 00, 2c, 03, 01, 09, 00, 0a, 01, 00, 0d, 00, 0e, 28, 00, 03, 00, 0d, 00, 18, 30, 05, 1a, 01, 03, 02, 00, 0d, 00, 0e, 05, 00, 12, 00, 13, 30, 09, 16, 03, 00, 02, 00, 12, 00, 13, 13, 00, 17, 00, 18, 30, 0d, 11, 02, 00, 00, 00, 17, 00, 18, 03, 01, 05, 01, 02] +Number of files: 1 +- file 0 => global file 1 +Number of expressions: 7 +- expression 0 operands: lhs = Expression(1, Add), rhs = Counter(4) +- expression 1 operands: lhs = Counter(2), rhs = Counter(3) +- expression 2 operands: lhs = Counter(0), rhs = Counter(1) +- expression 3 operands: lhs = Counter(1), rhs = Counter(2) +- expression 4 operands: lhs = Expression(5, Sub), rhs = Expression(6, Sub) +- expression 5 operands: lhs = Counter(1), rhs = Counter(2) +- expression 6 operands: lhs = Counter(0), rhs = Counter(1) +Number of file 0 mappings: 10 +- Code(Counter(0)) at (prev + 27, 1) to (start + 0, 44) +- Code(Expression(0, Add)) at (prev + 1, 9) to (start + 0, 10) + = ((c2 + c3) + c4) +- Code(Counter(0)) at (prev + 0, 13) to (start + 0, 14) +- MCDCDecision { bitmap_idx: 0, conditions_num: 3 } at (prev + 0, 13) to (start + 0, 24) +- MCDCBranch { true: Counter(1), false: Expression(6, Sub), condition_id: 1, true_next_id: 3, false_next_id: 2 } at (prev + 0, 13) to (start + 0, 14) + true = c1 + false = (c0 - c1) +- Code(Counter(1)) at (prev + 0, 18) to (start + 0, 19) +- MCDCBranch { true: Counter(2), false: Expression(5, Sub), condition_id: 3, true_next_id: 0, false_next_id: 2 } at (prev + 0, 18) to (start + 0, 19) + true = c2 + false = (c1 - c2) +- Code(Expression(4, Add)) at (prev + 0, 23) to (start + 0, 24) + = ((c1 - c2) + (c0 - c1)) +- MCDCBranch { true: Counter(3), false: Counter(4), condition_id: 2, true_next_id: 0, false_next_id: 0 } at (prev + 0, 23) to (start + 0, 24) + true = c3 + false = c4 +- Code(Expression(0, Add)) at (prev + 1, 5) to (start + 1, 2) + = ((c2 + c3) + c4) + +Function name: mcdc_non_control_flow::assign_and +Raw bytes (64): 0x[01, 01, 04, 07, 0e, 09, 0d, 01, 05, 01, 05, 08, 01, 0c, 01, 00, 21, 03, 01, 09, 00, 0a, 01, 00, 0d, 00, 0e, 28, 00, 02, 00, 0d, 00, 13, 30, 05, 0e, 01, 02, 00, 00, 0d, 00, 0e, 05, 00, 12, 00, 13, 30, 09, 0d, 02, 00, 00, 00, 12, 00, 13, 03, 01, 05, 01, 02] +Number of files: 1 +- file 0 => global file 1 +Number of expressions: 4 +- expression 0 operands: lhs = Expression(1, Add), rhs = Expression(3, Sub) +- expression 1 operands: lhs = Counter(2), rhs = Counter(3) +- expression 2 operands: lhs = Counter(0), rhs = Counter(1) +- expression 3 operands: lhs = Counter(0), rhs = Counter(1) +Number of file 0 mappings: 8 +- Code(Counter(0)) at (prev + 12, 1) to (start + 0, 33) +- Code(Expression(0, Add)) at (prev + 1, 9) to (start + 0, 10) + = ((c2 + c3) + (c0 - c1)) +- Code(Counter(0)) at (prev + 0, 13) to (start + 0, 14) +- MCDCDecision { bitmap_idx: 0, conditions_num: 2 } at (prev + 0, 13) to (start + 0, 19) +- MCDCBranch { true: Counter(1), false: Expression(3, Sub), condition_id: 1, true_next_id: 2, false_next_id: 0 } at (prev + 0, 13) to (start + 0, 14) + true = c1 + false = (c0 - c1) +- Code(Counter(1)) at (prev + 0, 18) to (start + 0, 19) +- MCDCBranch { true: Counter(2), false: Counter(3), condition_id: 2, true_next_id: 0, false_next_id: 0 } at (prev + 0, 18) to (start + 0, 19) + true = c2 + false = c3 +- Code(Expression(0, Add)) at (prev + 1, 5) to (start + 1, 2) + = ((c2 + c3) + (c0 - c1)) + +Function name: mcdc_non_control_flow::assign_or +Raw bytes (64): 0x[01, 01, 04, 07, 0d, 05, 09, 01, 05, 01, 05, 08, 01, 11, 01, 00, 20, 03, 01, 09, 00, 0a, 01, 00, 0d, 00, 0e, 28, 00, 02, 00, 0d, 00, 13, 30, 05, 0e, 01, 00, 02, 00, 0d, 00, 0e, 0e, 00, 12, 00, 13, 30, 09, 0d, 02, 00, 00, 00, 12, 00, 13, 03, 01, 05, 01, 02] +Number of files: 1 +- file 0 => global file 1 +Number of expressions: 4 +- expression 0 operands: lhs = Expression(1, Add), rhs = Counter(3) +- expression 1 operands: lhs = Counter(1), rhs = Counter(2) +- expression 2 operands: lhs = Counter(0), rhs = Counter(1) +- expression 3 operands: lhs = Counter(0), rhs = Counter(1) +Number of file 0 mappings: 8 +- Code(Counter(0)) at (prev + 17, 1) to (start + 0, 32) +- Code(Expression(0, Add)) at (prev + 1, 9) to (start + 0, 10) + = ((c1 + c2) + c3) +- Code(Counter(0)) at (prev + 0, 13) to (start + 0, 14) +- MCDCDecision { bitmap_idx: 0, conditions_num: 2 } at (prev + 0, 13) to (start + 0, 19) +- MCDCBranch { true: Counter(1), false: Expression(3, Sub), condition_id: 1, true_next_id: 0, false_next_id: 2 } at (prev + 0, 13) to (start + 0, 14) + true = c1 + false = (c0 - c1) +- Code(Expression(3, Sub)) at (prev + 0, 18) to (start + 0, 19) + = (c0 - c1) +- MCDCBranch { true: Counter(2), false: Counter(3), condition_id: 2, true_next_id: 0, false_next_id: 0 } at (prev + 0, 18) to (start + 0, 19) + true = c2 + false = c3 +- Code(Expression(0, Add)) at (prev + 1, 5) to (start + 1, 2) + = ((c1 + c2) + c3) + +Function name: mcdc_non_control_flow::foo +Raw bytes (9): 0x[01, 01, 00, 01, 01, 25, 01, 02, 02] +Number of files: 1 +- file 0 => global file 1 +Number of expressions: 0 +Number of file 0 mappings: 1 +- Code(Counter(0)) at (prev + 37, 1) to (start + 2, 2) + +Function name: mcdc_non_control_flow::func_call +Raw bytes (52): 0x[01, 01, 03, 01, 05, 0b, 02, 09, 0d, 06, 01, 29, 01, 01, 0a, 28, 00, 02, 01, 09, 00, 0f, 30, 05, 02, 01, 02, 00, 00, 09, 00, 0a, 05, 00, 0e, 00, 0f, 30, 09, 0d, 02, 00, 00, 00, 0e, 00, 0f, 07, 01, 01, 00, 02] +Number of files: 1 +- file 0 => global file 1 +Number of expressions: 3 +- expression 0 operands: lhs = Counter(0), rhs = Counter(1) +- expression 1 operands: lhs = Expression(2, Add), rhs = Expression(0, Sub) +- expression 2 operands: lhs = Counter(2), rhs = Counter(3) +Number of file 0 mappings: 6 +- Code(Counter(0)) at (prev + 41, 1) to (start + 1, 10) +- MCDCDecision { bitmap_idx: 0, conditions_num: 2 } at (prev + 1, 9) to (start + 0, 15) +- MCDCBranch { true: Counter(1), false: Expression(0, Sub), condition_id: 1, true_next_id: 2, false_next_id: 0 } at (prev + 0, 9) to (start + 0, 10) + true = c1 + false = (c0 - c1) +- Code(Counter(1)) at (prev + 0, 14) to (start + 0, 15) +- MCDCBranch { true: Counter(2), false: Counter(3), condition_id: 2, true_next_id: 0, false_next_id: 0 } at (prev + 0, 14) to (start + 0, 15) + true = c2 + false = c3 +- Code(Expression(1, Add)) at (prev + 1, 1) to (start + 0, 2) + = ((c2 + c3) + (c0 - c1)) + +Function name: mcdc_non_control_flow::right_comb_tree +Raw bytes (139): 0x[01, 01, 13, 07, 1a, 0b, 19, 0f, 15, 13, 11, 09, 0d, 01, 05, 01, 05, 05, 19, 05, 19, 4a, 15, 05, 19, 4a, 15, 05, 19, 46, 11, 4a, 15, 05, 19, 46, 11, 4a, 15, 05, 19, 0e, 01, 20, 01, 00, 41, 03, 01, 09, 00, 0a, 01, 00, 0d, 00, 0e, 28, 00, 05, 00, 0d, 00, 2a, 30, 05, 1a, 01, 02, 00, 00, 0d, 00, 0e, 05, 00, 13, 00, 14, 30, 4a, 19, 02, 03, 00, 00, 13, 00, 14, 4a, 00, 19, 00, 1a, 30, 46, 15, 03, 04, 00, 00, 19, 00, 1a, 46, 00, 1f, 00, 20, 30, 42, 11, 04, 05, 00, 00, 1f, 00, 20, 42, 00, 24, 00, 27, 30, 09, 0d, 05, 00, 00, 00, 24, 00, 27, 03, 01, 05, 01, 02] +Number of files: 1 +- file 0 => global file 1 +Number of expressions: 19 +- expression 0 operands: lhs = Expression(1, Add), rhs = Expression(6, Sub) +- expression 1 operands: lhs = Expression(2, Add), rhs = Counter(6) +- expression 2 operands: lhs = Expression(3, Add), rhs = Counter(5) +- expression 3 operands: lhs = Expression(4, Add), rhs = Counter(4) +- expression 4 operands: lhs = Counter(2), rhs = Counter(3) +- expression 5 operands: lhs = Counter(0), rhs = Counter(1) +- expression 6 operands: lhs = Counter(0), rhs = Counter(1) +- expression 7 operands: lhs = Counter(1), rhs = Counter(6) +- expression 8 operands: lhs = Counter(1), rhs = Counter(6) +- expression 9 operands: lhs = Expression(18, Sub), rhs = Counter(5) +- expression 10 operands: lhs = Counter(1), rhs = Counter(6) +- expression 11 operands: lhs = Expression(18, Sub), rhs = Counter(5) +- expression 12 operands: lhs = Counter(1), rhs = Counter(6) +- expression 13 operands: lhs = Expression(17, Sub), rhs = Counter(4) +- expression 14 operands: lhs = Expression(18, Sub), rhs = Counter(5) +- expression 15 operands: lhs = Counter(1), rhs = Counter(6) +- expression 16 operands: lhs = Expression(17, Sub), rhs = Counter(4) +- expression 17 operands: lhs = Expression(18, Sub), rhs = Counter(5) +- expression 18 operands: lhs = Counter(1), rhs = Counter(6) +Number of file 0 mappings: 14 +- Code(Counter(0)) at (prev + 32, 1) to (start + 0, 65) +- Code(Expression(0, Add)) at (prev + 1, 9) to (start + 0, 10) + = (((((c2 + c3) + c4) + c5) + c6) + (c0 - c1)) +- Code(Counter(0)) at (prev + 0, 13) to (start + 0, 14) +- MCDCDecision { bitmap_idx: 0, conditions_num: 5 } at (prev + 0, 13) to (start + 0, 42) +- MCDCBranch { true: Counter(1), false: Expression(6, Sub), condition_id: 1, true_next_id: 2, false_next_id: 0 } at (prev + 0, 13) to (start + 0, 14) + true = c1 + false = (c0 - c1) +- Code(Counter(1)) at (prev + 0, 19) to (start + 0, 20) +- MCDCBranch { true: Expression(18, Sub), false: Counter(6), condition_id: 2, true_next_id: 3, false_next_id: 0 } at (prev + 0, 19) to (start + 0, 20) + true = (c1 - c6) + false = c6 +- Code(Expression(18, Sub)) at (prev + 0, 25) to (start + 0, 26) + = (c1 - c6) +- MCDCBranch { true: Expression(17, Sub), false: Counter(5), condition_id: 3, true_next_id: 4, false_next_id: 0 } at (prev + 0, 25) to (start + 0, 26) + true = ((c1 - c6) - c5) + false = c5 +- Code(Expression(17, Sub)) at (prev + 0, 31) to (start + 0, 32) + = ((c1 - c6) - c5) +- MCDCBranch { true: Expression(16, Sub), false: Counter(4), condition_id: 4, true_next_id: 5, false_next_id: 0 } at (prev + 0, 31) to (start + 0, 32) + true = (((c1 - c6) - c5) - c4) + false = c4 +- Code(Expression(16, Sub)) at (prev + 0, 36) to (start + 0, 39) + = (((c1 - c6) - c5) - c4) +- MCDCBranch { true: Counter(2), false: Counter(3), condition_id: 5, true_next_id: 0, false_next_id: 0 } at (prev + 0, 36) to (start + 0, 39) + true = c2 + false = c3 +- Code(Expression(0, Add)) at (prev + 1, 5) to (start + 1, 2) + = (((((c2 + c3) + c4) + c5) + c6) + (c0 - c1)) + diff --git a/tests/coverage/mcdc_non_control_flow.coverage b/tests/coverage/mcdc_non_control_flow.coverage new file mode 100644 index 00000000000..cd733885a98 --- /dev/null +++ b/tests/coverage/mcdc_non_control_flow.coverage @@ -0,0 +1,202 @@ + LL| |#![feature(coverage_attribute)] + LL| |//@ edition: 2021 + LL| |//@ min-llvm-version: 18 + LL| |//@ compile-flags: -Zcoverage-options=mcdc + LL| |//@ llvm-cov-flags: --show-mcdc + LL| | + LL| |// This test ensures that boolean expressions that are not inside control flow + LL| |// decisions are correctly instrumented. + LL| | + LL| |use core::hint::black_box; + LL| | + LL| 3|fn assign_and(a: bool, b: bool) { + LL| 3| let x = a && b; + ^2 + ------------------ + |---> MC/DC Decision Region (LL:13) to (LL:19) + | + | Number of Conditions: 2 + | Condition C1 --> (LL:13) + | Condition C2 --> (LL:18) + | + | Executed MC/DC Test Vectors: + | + | C1, C2 Result + | 1 { F, - = F } + | 2 { T, F = F } + | 3 { T, T = T } + | + | C1-Pair: covered: (1,3) + | C2-Pair: covered: (2,3) + | MC/DC Coverage for Decision: 100.00% + | + ------------------ + LL| 3| black_box(x); + LL| 3|} + LL| | + LL| 3|fn assign_or(a: bool, b: bool) { + LL| 3| let x = a || b; + ^1 + ------------------ + |---> MC/DC Decision Region (LL:13) to (LL:19) + | + | Number of Conditions: 2 + | Condition C1 --> (LL:13) + | Condition C2 --> (LL:18) + | + | Executed MC/DC Test Vectors: + | + | C1, C2 Result + | 1 { F, F = F } + | 2 { T, - = T } + | + | C1-Pair: covered: (1,2) + | C2-Pair: not covered + | MC/DC Coverage for Decision: 50.00% + | + ------------------ + LL| 3| black_box(x); + LL| 3|} + LL| | + LL| 4|fn assign_3(a: bool, b: bool, c: bool) { + LL| 4| let x = a || b && c; + ^2 ^1 + ------------------ + |---> MC/DC Decision Region (LL:13) to (LL:24) + | + | Number of Conditions: 3 + | Condition C1 --> (LL:13) + | Condition C2 --> (LL:18) + | Condition C3 --> (LL:23) + | + | Executed MC/DC Test Vectors: + | + | C1, C2, C3 Result + | 1 { F, F, - = F } + | 2 { T, -, - = T } + | 3 { F, T, T = T } + | + | C1-Pair: covered: (1,2) + | C2-Pair: covered: (1,3) + | C3-Pair: not covered + | MC/DC Coverage for Decision: 66.67% + | + ------------------ + LL| 4| black_box(x); + LL| 4|} + LL| | + LL| 4|fn assign_3_bis(a: bool, b: bool, c: bool) { + LL| 4| let x = a && b || c; + ^2 ^3 + ------------------ + |---> MC/DC Decision Region (LL:13) to (LL:24) + | + | Number of Conditions: 3 + | Condition C1 --> (LL:13) + | Condition C2 --> (LL:18) + | Condition C3 --> (LL:23) + | + | Executed MC/DC Test Vectors: + | + | C1, C2, C3 Result + | 1 { T, F, F = F } + | 2 { F, -, T = T } + | 3 { T, T, - = T } + | + | C1-Pair: not covered + | C2-Pair: covered: (1,3) + | C3-Pair: not covered + | MC/DC Coverage for Decision: 33.33% + | + ------------------ + LL| 4| black_box(x); + LL| 4|} + LL| | + LL| 3|fn right_comb_tree(a: bool, b: bool, c: bool, d: bool, e: bool) { + LL| 3| let x = a && (b && (c && (d && (e)))); + ^2 ^1 ^1 ^1 + ------------------ + |---> MC/DC Decision Region (LL:13) to (LL:42) + | + | Number of Conditions: 5 + | Condition C1 --> (LL:13) + | Condition C2 --> (LL:19) + | Condition C3 --> (LL:25) + | Condition C4 --> (LL:31) + | Condition C5 --> (LL:36) + | + | Executed MC/DC Test Vectors: + | + | C1, C2, C3, C4, C5 Result + | 1 { F, -, -, -, - = F } + | 2 { T, F, -, -, - = F } + | 3 { T, T, T, T, T = T } + | + | C1-Pair: covered: (1,3) + | C2-Pair: covered: (2,3) + | C3-Pair: not covered + | C4-Pair: not covered + | C5-Pair: not covered + | MC/DC Coverage for Decision: 40.00% + | + ------------------ + LL| 3| black_box(x); + LL| 3|} + LL| | + LL| 3|fn foo(a: bool) -> bool { + LL| 3| black_box(a) + LL| 3|} + LL| | + LL| 3|fn func_call(a: bool, b: bool) { + LL| 3| foo(a && b); + ^2 + ------------------ + |---> MC/DC Decision Region (LL:9) to (LL:15) + | + | Number of Conditions: 2 + | Condition C1 --> (LL:9) + | Condition C2 --> (LL:14) + | + | Executed MC/DC Test Vectors: + | + | C1, C2 Result + | 1 { F, - = F } + | 2 { T, F = F } + | 3 { T, T = T } + | + | C1-Pair: covered: (1,3) + | C2-Pair: covered: (2,3) + | MC/DC Coverage for Decision: 100.00% + | + ------------------ + LL| 3|} + LL| | + LL| |#[coverage(off)] + LL| |fn main() { + LL| | assign_and(true, false); + LL| | assign_and(true, true); + LL| | assign_and(false, false); + LL| | + LL| | assign_or(true, false); + LL| | assign_or(true, true); + LL| | assign_or(false, false); + LL| | + LL| | assign_3(true, false, false); + LL| | assign_3(true, true, false); + LL| | assign_3(false, false, true); + LL| | assign_3(false, true, true); + LL| | + LL| | assign_3_bis(true, false, false); + LL| | assign_3_bis(true, true, false); + LL| | assign_3_bis(false, false, true); + LL| | assign_3_bis(false, true, true); + LL| | + LL| | right_comb_tree(false, false, false, true, true); + LL| | right_comb_tree(true, false, false, true, true); + LL| | right_comb_tree(true, true, true, true, true); + LL| | + LL| | func_call(true, false); + LL| | func_call(true, true); + LL| | func_call(false, false); + LL| |} + diff --git a/tests/coverage/mcdc_non_control_flow.rs b/tests/coverage/mcdc_non_control_flow.rs new file mode 100644 index 00000000000..85c0a6c6ae5 --- /dev/null +++ b/tests/coverage/mcdc_non_control_flow.rs @@ -0,0 +1,72 @@ +#![feature(coverage_attribute)] +//@ edition: 2021 +//@ min-llvm-version: 18 +//@ compile-flags: -Zcoverage-options=mcdc +//@ llvm-cov-flags: --show-mcdc + +// This test ensures that boolean expressions that are not inside control flow +// decisions are correctly instrumented. + +use core::hint::black_box; + +fn assign_and(a: bool, b: bool) { + let x = a && b; + black_box(x); +} + +fn assign_or(a: bool, b: bool) { + let x = a || b; + black_box(x); +} + +fn assign_3(a: bool, b: bool, c: bool) { + let x = a || b && c; + black_box(x); +} + +fn assign_3_bis(a: bool, b: bool, c: bool) { + let x = a && b || c; + black_box(x); +} + +fn right_comb_tree(a: bool, b: bool, c: bool, d: bool, e: bool) { + let x = a && (b && (c && (d && (e)))); + black_box(x); +} + +fn foo(a: bool) -> bool { + black_box(a) +} + +fn func_call(a: bool, b: bool) { + foo(a && b); +} + +#[coverage(off)] +fn main() { + assign_and(true, false); + assign_and(true, true); + assign_and(false, false); + + assign_or(true, false); + assign_or(true, true); + assign_or(false, false); + + assign_3(true, false, false); + assign_3(true, true, false); + assign_3(false, false, true); + assign_3(false, true, true); + + assign_3_bis(true, false, false); + assign_3_bis(true, true, false); + assign_3_bis(false, false, true); + assign_3_bis(false, true, true); + + right_comb_tree(false, false, false, true, true); + right_comb_tree(true, false, false, true, true); + right_comb_tree(true, true, true, true, true); + + func_call(true, false); + func_call(true, true); + func_call(false, false); +} diff --git a/tests/crashes/126148.rs b/tests/crashes/126148.rs new file mode 100644 index 00000000000..79f8887b401 --- /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<Error> 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 00000000000..2219a6cb5fa --- /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<const B: bool>; + +struct Thing<T = Cond<0>>(T); + +impl Thing {} diff --git a/tests/crashes/126267.rs b/tests/crashes/126267.rs new file mode 100644 index 00000000000..c0604b90a67 --- /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<Src, Dst>() + where + Dst: BikeshedIntrinsicFrom<Src>, // safety is NOT assumed + { + } +} + +fn test() { + struct Src; + type Dst = Error; + assert::is_transmutable::<Src, Dst>(); +} diff --git a/tests/crashes/126269.rs b/tests/crashes/126269.rs new file mode 100644 index 00000000000..ca4b76eb930 --- /dev/null +++ b/tests/crashes/126269.rs @@ -0,0 +1,12 @@ +//@ known-bug: rust-lang/rust#126269 +#![feature(coerce_unsized)] + +pub enum Foo<T> { + Bar([T; usize::MAX]), +} + +use std::ops::CoerceUnsized; + +impl<T, U> CoerceUnsized<U> for T {} + +fn main() {} diff --git a/tests/crashes/126272.rs b/tests/crashes/126272.rs new file mode 100644 index 00000000000..3412c7d8f0f --- /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<std::fmt::Debug>, +} + +#[derive(Debug, PartialEq, Eq, ConstParamTy)] +struct Bar<T>(T); + +struct Test<const F: Foo>; + +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 00000000000..4b28c466b55 --- /dev/null +++ b/tests/crashes/126359.rs @@ -0,0 +1,9 @@ +//@ known-bug: rust-lang/rust#126359 + +struct OppOrder<const N: u8 = 3, T = u32> { + arr: [T; N], +} + +fn main() { + let _ = OppOrder::<3, u32> { arr: [0, 0, 0] }; +} diff --git a/tests/crashes/126377.rs b/tests/crashes/126377.rs new file mode 100644 index 00000000000..f8b9b693b65 --- /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::<Src, Dst, {0u8}, false, false, false>(); +} diff --git a/tests/crashes/126416.rs b/tests/crashes/126416.rs new file mode 100644 index 00000000000..9b6c5169d44 --- /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<O, F>(&mut self, _: F) + where + F: for<'a> FnOnce(<F as Output<i32>>::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 00000000000..0a025aabcf2 --- /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 00000000000..2209bb9bd94 --- /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 00000000000..e6469da4785 --- /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/or_pattern.rs b/tests/mir-opt/or_pattern.rs new file mode 100644 index 00000000000..0ad0ce8ead1 --- /dev/null +++ b/tests/mir-opt/or_pattern.rs @@ -0,0 +1,24 @@ +// skip-filecheck + +// EMIT_MIR or_pattern.shortcut_second_or.SimplifyCfg-initial.after.mir +fn shortcut_second_or() { + // Check that after matching `0`, failing to match `2 | 3` skips trying to match `(1, 2 | 3)`. + match ((0, 0), 0) { + (x @ (0, _) | x @ (_, 1), y @ 2 | y @ 3) => {} + _ => {} + } +} + +// EMIT_MIR or_pattern.single_switchint.SimplifyCfg-initial.after.mir +fn single_switchint() { + // Check how many `SwitchInt`s we do. In theory a single one is necessary. + match (1, true) { + (1, true) => 1, + (2, false) => 2, + (1 | 2, true | false) => 3, + (3 | 4, true | false) => 4, + _ => 5, + }; +} + +fn main() {} diff --git a/tests/mir-opt/or_pattern.shortcut_second_or.SimplifyCfg-initial.after.mir b/tests/mir-opt/or_pattern.shortcut_second_or.SimplifyCfg-initial.after.mir new file mode 100644 index 00000000000..56edd38a6da --- /dev/null +++ b/tests/mir-opt/or_pattern.shortcut_second_or.SimplifyCfg-initial.after.mir @@ -0,0 +1,100 @@ +// MIR for `shortcut_second_or` after SimplifyCfg-initial + +fn shortcut_second_or() -> () { + let mut _0: (); + let mut _1: ((i32, i32), i32); + let mut _2: (i32, i32); + let _3: (i32, i32); + let _4: i32; + scope 1 { + debug x => _3; + debug y => _4; + } + + bb0: { + StorageLive(_1); + StorageLive(_2); + _2 = (const 0_i32, const 0_i32); + _1 = (move _2, const 0_i32); + StorageDead(_2); + PlaceMention(_1); + switchInt(((_1.0: (i32, i32)).0: i32)) -> [0: bb4, otherwise: bb2]; + } + + bb1: { + _0 = const (); + goto -> bb14; + } + + bb2: { + switchInt(((_1.0: (i32, i32)).1: i32)) -> [1: bb3, otherwise: bb1]; + } + + bb3: { + switchInt((_1.1: i32)) -> [2: bb7, 3: bb8, otherwise: bb1]; + } + + bb4: { + switchInt((_1.1: i32)) -> [2: bb5, 3: bb6, otherwise: bb1]; + } + + bb5: { + falseEdge -> [real: bb10, imaginary: bb6]; + } + + bb6: { + falseEdge -> [real: bb11, imaginary: bb2]; + } + + bb7: { + falseEdge -> [real: bb12, imaginary: bb8]; + } + + bb8: { + falseEdge -> [real: bb13, imaginary: bb1]; + } + + bb9: { + _0 = const (); + StorageDead(_4); + StorageDead(_3); + goto -> bb14; + } + + bb10: { + StorageLive(_3); + _3 = (_1.0: (i32, i32)); + StorageLive(_4); + _4 = (_1.1: i32); + goto -> bb9; + } + + bb11: { + StorageLive(_3); + _3 = (_1.0: (i32, i32)); + StorageLive(_4); + _4 = (_1.1: i32); + goto -> bb9; + } + + bb12: { + StorageLive(_3); + _3 = (_1.0: (i32, i32)); + StorageLive(_4); + _4 = (_1.1: i32); + goto -> bb9; + } + + bb13: { + StorageLive(_3); + _3 = (_1.0: (i32, i32)); + StorageLive(_4); + _4 = (_1.1: i32); + goto -> bb9; + } + + bb14: { + StorageDead(_1); + return; + } +} diff --git a/tests/mir-opt/or_pattern.single_switchint.SimplifyCfg-initial.after.mir b/tests/mir-opt/or_pattern.single_switchint.SimplifyCfg-initial.after.mir new file mode 100644 index 00000000000..eafe95b4a11 --- /dev/null +++ b/tests/mir-opt/or_pattern.single_switchint.SimplifyCfg-initial.after.mir @@ -0,0 +1,75 @@ +// MIR for `single_switchint` after SimplifyCfg-initial + +fn single_switchint() -> () { + let mut _0: (); + let _1: i32; + let mut _2: (i32, bool); + + bb0: { + StorageLive(_1); + StorageLive(_2); + _2 = (const 1_i32, const true); + PlaceMention(_2); + switchInt((_2.0: i32)) -> [1: bb2, 2: bb4, otherwise: bb1]; + } + + bb1: { + switchInt((_2.0: i32)) -> [3: bb8, 4: bb8, otherwise: bb7]; + } + + bb2: { + switchInt((_2.1: bool)) -> [0: bb6, otherwise: bb3]; + } + + bb3: { + falseEdge -> [real: bb9, imaginary: bb4]; + } + + bb4: { + switchInt((_2.1: bool)) -> [0: bb5, otherwise: bb6]; + } + + bb5: { + falseEdge -> [real: bb10, imaginary: bb6]; + } + + bb6: { + falseEdge -> [real: bb11, imaginary: bb1]; + } + + bb7: { + _1 = const 5_i32; + goto -> bb13; + } + + bb8: { + falseEdge -> [real: bb12, imaginary: bb7]; + } + + bb9: { + _1 = const 1_i32; + goto -> bb13; + } + + bb10: { + _1 = const 2_i32; + goto -> bb13; + } + + bb11: { + _1 = const 3_i32; + goto -> bb13; + } + + bb12: { + _1 = const 4_i32; + goto -> bb13; + } + + bb13: { + StorageDead(_2); + StorageDead(_1); + _0 = const (); + return; + } +} diff --git a/tests/run-make/CURRENT_RUSTC_VERSION/rmake.rs b/tests/run-make/CURRENT_RUSTC_VERSION/rmake.rs index b3227b79559..d937514c2ca 100644 --- a/tests/run-make/CURRENT_RUSTC_VERSION/rmake.rs +++ b/tests/run-make/CURRENT_RUSTC_VERSION/rmake.rs @@ -12,7 +12,6 @@ fn main() { let output = rustc().input("main.rs").emit("metadata").extern_("stable", "libstable.rmeta").run(); - let version = fs_wrapper::read_to_string(source_root().join("src/version")); let expected_string = format!("stable since {}", version.trim()); output.assert_stderr_contains(expected_string); diff --git a/tests/run-make/allocator-shim-circular-deps/Makefile b/tests/run-make/allocator-shim-circular-deps/Makefile deleted file mode 100644 index f667e2e2ec2..00000000000 --- a/tests/run-make/allocator-shim-circular-deps/Makefile +++ /dev/null @@ -1,12 +0,0 @@ -# This test is designed to intentionally introduce a circular dependency scenario to check that a specific compiler bug doesn't make a resurgence. -# The bug in question arose when at least one crate required a global allocator, and that crate was placed after the one defining it in the linker order. -# The generated symbols.o should not result in any linker errors. -# See https://github.com/rust-lang/rust/issues/112715 - -# ignore-cross-compile -include ../tools.mk - -all: - rm -rf $(TMPDIR) && mkdir $(TMPDIR) - $(RUSTC) my_lib.rs - $(RUSTC) main.rs --test --extern my_lib=$(TMPDIR)/libmy_lib.rlib diff --git a/tests/run-make/allocator-shim-circular-deps/rmake.rs b/tests/run-make/allocator-shim-circular-deps/rmake.rs new file mode 100644 index 00000000000..7d6b0bd204a --- /dev/null +++ b/tests/run-make/allocator-shim-circular-deps/rmake.rs @@ -0,0 +1,16 @@ +// This test is designed to intentionally introduce a circular dependency scenario to check +// that a specific compiler bug doesn't make a resurgence. +// The bug in question arose when at least one crate +// required a global allocator, and that crate was placed after +// the one defining it in the linker order. +// The generated symbols.o should not result in any linker errors. +// See https://github.com/rust-lang/rust/issues/112715 + +//@ ignore-cross-compile + +use run_make_support::{rust_lib_name, rustc}; + +fn main() { + rustc().input("my_lib.rs").run(); + rustc().input("main.rs").arg("--test").extern_("my_lib", rust_lib_name("my_lib")).run(); +} diff --git a/tests/run-make/issue-51671/app.rs b/tests/run-make/bin-emit-no-symbols/app.rs index e9dc1e9744f..e9dc1e9744f 100644 --- a/tests/run-make/issue-51671/app.rs +++ b/tests/run-make/bin-emit-no-symbols/app.rs diff --git a/tests/run-make/bin-emit-no-symbols/rmake.rs b/tests/run-make/bin-emit-no-symbols/rmake.rs new file mode 100644 index 00000000000..5586e53c050 --- /dev/null +++ b/tests/run-make/bin-emit-no-symbols/rmake.rs @@ -0,0 +1,16 @@ +// When setting the crate type as a "bin" (in app.rs), +// this could cause a bug where some symbols would not be +// emitted in the object files. This has been fixed, and +// this test checks that the correct symbols have been successfully +// emitted inside the object files. +// See https://github.com/rust-lang/rust/issues/51671 + +use run_make_support::{llvm_readobj, rustc}; + +fn main() { + rustc().emit("obj").input("app.rs").run(); + let out = llvm_readobj().input("app.o").arg("--symbols").run(); + out.assert_stdout_contains("rust_begin_unwind"); + out.assert_stdout_contains("rust_eh_personality"); + out.assert_stdout_contains("__rg_oom"); +} diff --git a/tests/run-make/issue-26092/blank.rs b/tests/run-make/clear-error-blank-output/blank.rs index f328e4d9d04..f328e4d9d04 100644 --- a/tests/run-make/issue-26092/blank.rs +++ b/tests/run-make/clear-error-blank-output/blank.rs diff --git a/tests/run-make/clear-error-blank-output/rmake.rs b/tests/run-make/clear-error-blank-output/rmake.rs new file mode 100644 index 00000000000..e0f042cf805 --- /dev/null +++ b/tests/run-make/clear-error-blank-output/rmake.rs @@ -0,0 +1,13 @@ +// When an empty output file is passed to rustc, the ensuing error message +// should be clear. However, calling file_stem on an empty path returns None, +// which, when unwrapped, causes a panic, stopping execution of rustc +// and printing an obscure message instead of reaching the helpful +// error message. This test checks that the panic does not occur. +// See https://github.com/rust-lang/rust/pull/26199 + +use run_make_support::rustc; + +fn main() { + let output = rustc().output("").stdin(b"fn main() {}").run_fail(); + output.assert_stderr_not_contains("panic"); +} diff --git a/tests/run-make/const_fn_mir/rmake.rs b/tests/run-make/const_fn_mir/rmake.rs index a4cc4299b1b..1ba93421855 100644 --- a/tests/run-make/const_fn_mir/rmake.rs +++ b/tests/run-make/const_fn_mir/rmake.rs @@ -1,5 +1,7 @@ // The `needs-unwind -Cpanic=abort` gives a different MIR output. +//@ needs-unwind + use run_make_support::{cwd, diff, rustc}; fn main() { diff --git a/tests/run-make/error-found-staticlib-instead-crate/Makefile b/tests/run-make/error-found-staticlib-instead-crate/Makefile deleted file mode 100644 index 0eae41d720c..00000000000 --- a/tests/run-make/error-found-staticlib-instead-crate/Makefile +++ /dev/null @@ -1,5 +0,0 @@ -include ../tools.mk - -all: - $(RUSTC) foo.rs --crate-type staticlib - $(RUSTC) bar.rs 2>&1 | $(CGREP) "found staticlib" diff --git a/tests/run-make/error-found-staticlib-instead-crate/rmake.rs b/tests/run-make/error-found-staticlib-instead-crate/rmake.rs new file mode 100644 index 00000000000..8c707092b7e --- /dev/null +++ b/tests/run-make/error-found-staticlib-instead-crate/rmake.rs @@ -0,0 +1,11 @@ +// When rustc is looking for a crate but is given a staticlib instead, +// the error message should be helpful and indicate precisely the cause +// of the compilation failure. +// See https://github.com/rust-lang/rust/pull/21978 + +use run_make_support::rustc; + +fn main() { + rustc().input("foo.rs").crate_type("staticlib").run(); + rustc().input("bar.rs").run_fail().assert_stderr_contains("found staticlib"); +} diff --git a/tests/run-make/extern-flag-fun/Makefile b/tests/run-make/extern-flag-fun/Makefile deleted file mode 100644 index 687cdfd7675..00000000000 --- a/tests/run-make/extern-flag-fun/Makefile +++ /dev/null @@ -1,20 +0,0 @@ -# ignore-cross-compile -include ../tools.mk - -all: - $(RUSTC) bar.rs --crate-type=rlib - $(RUSTC) bar.rs --crate-type=rlib -C extra-filename=-a - $(RUSTC) bar-alt.rs --crate-type=rlib - $(RUSTC) foo.rs --extern bar=no-exist && exit 1 || exit 0 - $(RUSTC) foo.rs --extern bar=foo.rs && exit 1 || exit 0 - $(RUSTC) foo.rs \ - --extern bar=$(TMPDIR)/libbar.rlib \ - --extern bar=$(TMPDIR)/libbar-alt.rlib \ - && exit 1 || exit 0 - $(RUSTC) foo.rs \ - --extern bar=$(TMPDIR)/libbar.rlib \ - --extern bar=$(TMPDIR)/libbar-a.rlib - $(RUSTC) foo.rs --extern bar=$(TMPDIR)/libbar.rlib - # Try to be sneaky and load a private crate from with a non-private name. - $(RUSTC) rustc.rs -Zforce-unstable-if-unmarked --crate-type=rlib - $(RUSTC) gated_unstable.rs --extern alloc=$(TMPDIR)/librustc.rlib 2>&1 | $(CGREP) 'rustc_private' diff --git a/tests/run-make/extern-flag-fun/rmake.rs b/tests/run-make/extern-flag-fun/rmake.rs new file mode 100644 index 00000000000..c1825f6bbb8 --- /dev/null +++ b/tests/run-make/extern-flag-fun/rmake.rs @@ -0,0 +1,38 @@ +// The --extern flag can override the default crate search of +// the compiler and directly fetch a given path. There are a few rules +// to follow: for example, there can't be more than one rlib, the crates must +// be valid ("no-exist" in this test), and private crates can't be loaded +// as non-private. This test checks that these rules are enforced. +// See https://github.com/rust-lang/rust/pull/15319 + +use run_make_support::{rust_lib_name, rustc}; + +fn main() { + rustc().input("bar.rs").crate_type("rlib").run(); + // Exactly the same rlib as the first line, only the filename changes. + rustc().input("bar.rs").crate_type("rlib").extra_filename("-a").run(); + rustc().input("bar-alt.rs").crate_type("rlib").run(); + // The crate must be valid. + rustc().input("foo.rs").extern_("bar", "no-exist").run_fail(); + rustc().input("foo.rs").extern_("bar", "foo.rs").run_fail(); + // Compilation fails with two different rlibs. + rustc() + .input("foo.rs") + .extern_("bar", rust_lib_name("bar")) + .extern_("bar", rust_lib_name("bar-alt")) + .run_fail(); + // Even though this one has seemingly two rlibs, they are one and the same. + rustc() + .input("foo.rs") + .extern_("bar", rust_lib_name("bar")) + .extern_("bar", rust_lib_name("bar-a")) + .run(); + rustc().input("foo.rs").extern_("bar", rust_lib_name("bar")).run(); + // Try to be sneaky and load a private crate from with a non-private name. + rustc().input("rustc.rs").arg("-Zforce-unstable-if-unmarked").crate_type("rlib").run(); + rustc() + .input("gated_unstable.rs") + .extern_("alloc", rust_lib_name("rustc")) + .run_fail() + .assert_stderr_contains("rustc_private"); +} diff --git a/tests/run-make/inaccessible-temp-dir/Makefile b/tests/run-make/inaccessible-temp-dir/Makefile deleted file mode 100644 index abdba4eb861..00000000000 --- a/tests/run-make/inaccessible-temp-dir/Makefile +++ /dev/null @@ -1,32 +0,0 @@ -# only-linux -# ignore-arm - linker error on `armhf-gnu` - -include ../tools.mk - -# Issue #66530: We would ICE if someone compiled with `-o /dev/null`, -# because we would try to generate auxiliary files in `/dev/` (which -# at least the OS X file system rejects). -# -# An attempt to `-Ztemps-dir` into a directory we cannot write into should -# indeed be an error; but not an ICE. -# -# However, some folks run tests as root, which can write `/dev/` and end -# up clobbering `/dev/null`. Instead we'll use an inaccessible path, which -# also used to ICE, but even root can't magically write there. -# -# Note that `-Ztemps-dir` uses `create_dir_all` so it is not sufficient to -# use a directory with non-existing parent like `/does-not-exist/output`. - -all: - # Create an inaccessible directory - mkdir $(TMPDIR)/inaccessible - chmod 000 $(TMPDIR)/inaccessible - - # Run rustc with `-Ztemps-dir` set to a directory - # *inside* the inaccessible one, so that it can't create it - $(RUSTC) program.rs -Ztemps-dir=$(TMPDIR)/inaccessible/tmp 2>&1 \ - | $(CGREP) 'failed to find or create the directory specified by `--temps-dir`' - - # Make the inaccessible directory accessible, - # so that compiletest can delete the temp dir - chmod +rw $(TMPDIR)/inaccessible diff --git a/tests/run-make/inaccessible-temp-dir/rmake.rs b/tests/run-make/inaccessible-temp-dir/rmake.rs new file mode 100644 index 00000000000..be24e47b6de --- /dev/null +++ b/tests/run-make/inaccessible-temp-dir/rmake.rs @@ -0,0 +1,38 @@ +// Issue #66530: We would ICE if someone compiled with `-o /dev/null`, +// because we would try to generate auxiliary files in `/dev/` (which +// at least the OS X file system rejects). +// +// An attempt to `-Ztemps-dir` into a directory we cannot write into should +// indeed be an error; but not an ICE. +// +// However, some folks run tests as root, which can write `/dev/` and end +// up clobbering `/dev/null`. Instead we'll use an inaccessible path, which +// also used to ICE, but even root can't magically write there. +// +// Note that `-Ztemps-dir` uses `create_dir_all` so it is not sufficient to +// use a directory with non-existing parent like `/does-not-exist/output`. +// See https://github.com/rust-lang/rust/issues/66530 + +//@ ignore-arm +// Reason: linker error on `armhf-gnu` +//@ ignore-windows +// Reason: `set_readonly` has no effect on directories +// and does not prevent modification. + +use run_make_support::{fs_wrapper, rustc, test_while_readonly}; + +fn main() { + // Create an inaccessible directory. + fs_wrapper::create_dir("inaccessible"); + test_while_readonly("inaccessible", || { + // Run rustc with `-Z temps-dir` set to a directory *inside* the inaccessible one, + // so that it can't create `tmp`. + rustc() + .input("program.rs") + .arg("-Ztemps-dir=inaccessible/tmp") + .run_fail() + .assert_stderr_contains( + "failed to find or create the directory specified by `--temps-dir`", + ); + }); +} diff --git a/tests/run-make/incremental-debugger-visualizer/Makefile b/tests/run-make/incremental-debugger-visualizer/Makefile deleted file mode 100644 index 8cfe41597ad..00000000000 --- a/tests/run-make/incremental-debugger-visualizer/Makefile +++ /dev/null @@ -1,49 +0,0 @@ -include ../tools.mk - -# This test makes sure that changes to files referenced via #[debugger_visualizer] -# are picked up when compiling incrementally. - -# We have to copy the source to $(TMPDIR) because Github CI mounts the source -# directory as readonly. We need to apply modifications to some of the source -# file. -SRC_DIR := $(TMPDIR)/src -INCR_CACHE_DIR := $(TMPDIR)/incremental - -all: - rm -rf $(TMPDIR)/* - mkdir $(SRC_DIR) - cp ./foo.rs $(SRC_DIR) - echo "GDB script v1" > $(SRC_DIR)/foo.py - echo "Natvis v1" > $(SRC_DIR)/foo.natvis - $(RUSTC) $(SRC_DIR)/foo.rs \ - --crate-type=rlib \ - --emit metadata \ - -C incremental=$(INCR_CACHE_DIR) \ - -Z incremental-verify-ich - $(CGREP) "GDB script v1" < $(TMPDIR)/libfoo.rmeta - $(CGREP) "Natvis v1" < $(TMPDIR)/libfoo.rmeta - - # Change only the GDB script and check that the change has been picked up - echo "GDB script v2" > $(SRC_DIR)/foo.py - $(RUSTC) $(SRC_DIR)/foo.rs \ - --crate-type=rlib \ - --emit metadata \ - -C incremental=$(INCR_CACHE_DIR) \ - -Z incremental-verify-ich - - $(CGREP) "GDB script v2" < $(TMPDIR)/libfoo.rmeta - $(CGREP) -v "GDB script v1" < $(TMPDIR)/libfoo.rmeta - $(CGREP) "Natvis v1" < $(TMPDIR)/libfoo.rmeta - - # Now change the Natvis version and check that the change has been picked up - echo "Natvis v2" > $(SRC_DIR)/foo.natvis - $(RUSTC) $(SRC_DIR)/foo.rs \ - --crate-type=rlib \ - --emit metadata \ - -C incremental=$(INCR_CACHE_DIR) \ - -Z incremental-verify-ich - - $(CGREP) "GDB script v2" < $(TMPDIR)/libfoo.rmeta - $(CGREP) -v "GDB script v1" < $(TMPDIR)/libfoo.rmeta - $(CGREP) "Natvis v2" < $(TMPDIR)/libfoo.rmeta - $(CGREP) -v "Natvis v1" < $(TMPDIR)/libfoo.rmeta diff --git a/tests/run-make/incremental-debugger-visualizer/rmake.rs b/tests/run-make/incremental-debugger-visualizer/rmake.rs new file mode 100644 index 00000000000..1ef3af87353 --- /dev/null +++ b/tests/run-make/incremental-debugger-visualizer/rmake.rs @@ -0,0 +1,56 @@ +// This test ensures that changes to files referenced via #[debugger_visualizer] +// (in this case, foo.py and foo.natvis) are picked up when compiling incrementally. +// See https://github.com/rust-lang/rust/pull/111641 + +use run_make_support::{fs_wrapper, invalid_utf8_contains, invalid_utf8_not_contains, rustc}; +use std::io::Read; + +fn main() { + fs_wrapper::create_file("foo.py"); + fs_wrapper::write("foo.py", "GDB script v1"); + fs_wrapper::create_file("foo.natvis"); + fs_wrapper::write("foo.natvis", "Natvis v1"); + rustc() + .input("foo.rs") + .crate_type("rlib") + .emit("metadata") + .incremental("incremental") + .arg("-Zincremental-verify-ich") + .run(); + + invalid_utf8_contains("libfoo.rmeta", "GDB script v1"); + invalid_utf8_contains("libfoo.rmeta", "Natvis v1"); + + // Change only the GDB script and check that the change has been picked up + fs_wrapper::remove_file("foo.py"); + fs_wrapper::create_file("foo.py"); + fs_wrapper::write("foo.py", "GDB script v2"); + rustc() + .input("foo.rs") + .crate_type("rlib") + .emit("metadata") + .incremental("incremental") + .arg("-Zincremental-verify-ich") + .run(); + + invalid_utf8_contains("libfoo.rmeta", "GDB script v2"); + invalid_utf8_not_contains("libfoo.rmeta", "GDB script v1"); + invalid_utf8_contains("libfoo.rmeta", "Natvis v1"); + + // Now change the Natvis version and check that the change has been picked up + fs_wrapper::remove_file("foo.natvis"); + fs_wrapper::create_file("foo.natvis"); + fs_wrapper::write("foo.natvis", "Natvis v2"); + rustc() + .input("foo.rs") + .crate_type("rlib") + .emit("metadata") + .incremental("incremental") + .arg("-Zincremental-verify-ich") + .run(); + + invalid_utf8_contains("libfoo.rmeta", "GDB script v2"); + invalid_utf8_not_contains("libfoo.rmeta", "GDB script v1"); + invalid_utf8_not_contains("libfoo.rmeta", "Natvis v1"); + invalid_utf8_contains("libfoo.rmeta", "Natvis v2"); +} diff --git a/tests/run-make/incremental-session-fail/Makefile b/tests/run-make/incremental-session-fail/Makefile deleted file mode 100644 index f43eece2eb7..00000000000 --- a/tests/run-make/incremental-session-fail/Makefile +++ /dev/null @@ -1,14 +0,0 @@ -include ../tools.mk - -SESSION_DIR := $(TMPDIR)/session -OUTPUT_FILE := $(TMPDIR)/build-output - -all: - echo $(TMPDIR) - # Make it so that rustc will fail to create a session directory. - touch $(SESSION_DIR) - # Check exit code is 1 for an error, and not 101 for ICE. - $(RUSTC) foo.rs --crate-type=rlib -C incremental=$(SESSION_DIR) > $(OUTPUT_FILE) 2>&1; [ $$? -eq 1 ] - $(CGREP) "could not create incremental compilation crate directory" < $(OUTPUT_FILE) - # -v tests are fragile, hopefully this text won't change - $(CGREP) -v "internal compiler error" < $(OUTPUT_FILE) diff --git a/tests/run-make/incremental-session-fail/rmake.rs b/tests/run-make/incremental-session-fail/rmake.rs new file mode 100644 index 00000000000..0283709f2cf --- /dev/null +++ b/tests/run-make/incremental-session-fail/rmake.rs @@ -0,0 +1,15 @@ +// Failing to create the directory where output incremental +// files would be stored used to cause an ICE (Internal Compiler +// Error). This was patched in #85698, and this test checks that +// the ensuing compilation failure is not an ICE. +// See https://github.com/rust-lang/rust/pull/85698 + +use run_make_support::{fs_wrapper, rustc}; + +fn main() { + fs_wrapper::create_file("session"); + // rustc should fail to create the session directory here. + let out = rustc().input("foo.rs").crate_type("rlib").incremental("session").run_fail(); + out.assert_stderr_contains("could not create incremental compilation crate directory"); + out.assert_stderr_not_contains("internal compiler error"); +} diff --git a/tests/run-make/invalid-staticlib/Makefile b/tests/run-make/invalid-staticlib/Makefile deleted file mode 100644 index 3f0f74ce3cb..00000000000 --- a/tests/run-make/invalid-staticlib/Makefile +++ /dev/null @@ -1,5 +0,0 @@ -include ../tools.mk - -all: - touch $(TMPDIR)/libfoo.a - echo | $(RUSTC) - --crate-type=rlib -lstatic=foo 2>&1 | $(CGREP) "failed to add native library" diff --git a/tests/run-make/invalid-staticlib/rmake.rs b/tests/run-make/invalid-staticlib/rmake.rs new file mode 100644 index 00000000000..45129293247 --- /dev/null +++ b/tests/run-make/invalid-staticlib/rmake.rs @@ -0,0 +1,17 @@ +// If the static library provided is not valid (in this test, +// created as an empty file), +// rustc should print a normal error message and not throw +// an internal compiler error (ICE). +// See https://github.com/rust-lang/rust/pull/28673 + +use run_make_support::{fs_wrapper, rustc, static_lib_name}; + +fn main() { + fs_wrapper::create_file(static_lib_name("foo")); + rustc() + .arg("-") + .crate_type("rlib") + .arg("-lstatic=foo") + .run_fail() + .assert_stderr_contains("failed to add native library"); +} diff --git a/tests/run-make/issue-10971-temps-dir/Makefile b/tests/run-make/issue-10971-temps-dir/Makefile deleted file mode 100644 index 6e1649a58d2..00000000000 --- a/tests/run-make/issue-10971-temps-dir/Makefile +++ /dev/null @@ -1,10 +0,0 @@ -include ../tools.mk - -# Regression test for issue #10971 -# Running two invocations in parallel would overwrite each other's temp files. - -all: - touch $(TMPDIR)/lib.rs - - $(RUSTC) --crate-type=lib -Z temps-dir=$(TMPDIR)/temp1 $(TMPDIR)/lib.rs & \ - $(RUSTC) --crate-type=staticlib -Z temps-dir=$(TMPDIR)/temp2 $(TMPDIR)/lib.rs diff --git a/tests/run-make/issue-26092/Makefile b/tests/run-make/issue-26092/Makefile deleted file mode 100644 index 96822e7690b..00000000000 --- a/tests/run-make/issue-26092/Makefile +++ /dev/null @@ -1,6 +0,0 @@ -include ../tools.mk - -# This test ensures that rustc does not panic with `-o ""` option. - -all: - $(RUSTC) -o "" blank.rs 2>&1 | $(CGREP) -i 'panic' && exit 1 || exit 0 diff --git a/tests/run-make/issue-47551/Makefile b/tests/run-make/issue-47551/Makefile index 5a6ac725701..3fe0a6e74e0 100644 --- a/tests/run-make/issue-47551/Makefile +++ b/tests/run-make/issue-47551/Makefile @@ -4,6 +4,7 @@ include ../tools.mk all: - $(RUSTC) eh_frame-terminator.rs + # --target $(TARGET) ensures the right gcc flags are used for cross compilation + $(RUSTC) --target $(TARGET) eh_frame-terminator.rs $(call RUN,eh_frame-terminator) | $(CGREP) '1122334455667788' objdump --dwarf=frames $(TMPDIR)/eh_frame-terminator | $(CGREP) 'ZERO terminator' diff --git a/tests/run-make/issue-51671/Makefile b/tests/run-make/issue-51671/Makefile deleted file mode 100644 index c9364536992..00000000000 --- a/tests/run-make/issue-51671/Makefile +++ /dev/null @@ -1,9 +0,0 @@ -include ../tools.mk - -# ignore-windows-msvc - -all: - $(RUSTC) --emit=obj app.rs - nm $(TMPDIR)/app.o | $(CGREP) rust_begin_unwind - nm $(TMPDIR)/app.o | $(CGREP) rust_eh_personality - nm $(TMPDIR)/app.o | $(CGREP) __rg_oom diff --git a/tests/run-make/issue-64153/Makefile b/tests/run-make/issue-64153/Makefile deleted file mode 100644 index f42ea620fb9..00000000000 --- a/tests/run-make/issue-64153/Makefile +++ /dev/null @@ -1,26 +0,0 @@ -include ../tools.mk - -# `llvm-objdump`'s output looks different on windows than on other platforms. -# It should be enough to check on Unix platforms, so: -# ignore-windows - -# Staticlibs don't include Rust object files from upstream crates if the same -# code was already pulled into the lib via LTO. However, the bug described in -# https://github.com/rust-lang/rust/issues/64153 lead to this exclusion not -# working properly if the upstream crate was compiled with an explicit filename -# (via `-o`). -# -# This test makes sure that functions defined in the upstream crates do not -# appear twice in the final staticlib when listing all the symbols from it. - -all: - $(RUSTC) --crate-type rlib upstream.rs -o $(TMPDIR)/libupstream.rlib -Ccodegen-units=1 - $(RUSTC) --crate-type staticlib downstream.rs -Clto -Ccodegen-units=1 -o $(TMPDIR)/libdownstream.a - # Dump all the symbols from the staticlib into `syms` - "$(LLVM_BIN_DIR)"/llvm-objdump -t $(TMPDIR)/libdownstream.a > $(TMPDIR)/syms - # Count the global instances of `issue64153_test_function`. There'll be 2 - # if the `upstream` object file got erroneously included twice. - # The line we are testing for with the regex looks something like: - # 0000000000000000 g F .text.issue64153_test_function 00000023 issue64153_test_function - grep -c -e "[[:space:]]g[[:space:]]*F[[:space:]].*issue64153_test_function" $(TMPDIR)/syms > $(TMPDIR)/count - [ "$$(cat $(TMPDIR)/count)" -eq "1" ] diff --git a/tests/run-make/link-arg/Makefile b/tests/run-make/link-arg/Makefile deleted file mode 100644 index 103527c3e14..00000000000 --- a/tests/run-make/link-arg/Makefile +++ /dev/null @@ -1,5 +0,0 @@ -include ../tools.mk -RUSTC_FLAGS = -C link-arg="-lfoo" -C link-arg="-lbar" --print link-args - -all: - $(RUSTC) $(RUSTC_FLAGS) empty.rs | $(CGREP) lfoo lbar diff --git a/tests/run-make/link-arg/rmake.rs b/tests/run-make/link-arg/rmake.rs new file mode 100644 index 00000000000..a6d68800792 --- /dev/null +++ b/tests/run-make/link-arg/rmake.rs @@ -0,0 +1,20 @@ +// In 2016, the rustc flag "-C link-arg" was introduced - it can be repeatedly used +// to add single arguments to the linker. This test passes 2 arguments to the linker using it, +// then checks that the compiler's output contains the arguments passed to it. +// This ensures that the compiler successfully parses this flag. +// See https://github.com/rust-lang/rust/pull/36574 + +use run_make_support::rustc; + +fn main() { + // We are only checking for the output of --print=link-args, + // rustc failing or succeeding does not matter. + let out = rustc() + .input("empty.rs") + .link_arg("-lfoo") + .link_arg("-lbar") + .print("link-args") + .run_unchecked(); + out.assert_stdout_contains("lfoo"); + out.assert_stdout_contains("lbar"); +} diff --git a/tests/run-make/link-dedup/Makefile b/tests/run-make/link-dedup/Makefile deleted file mode 100644 index eff18ab48ab..00000000000 --- a/tests/run-make/link-dedup/Makefile +++ /dev/null @@ -1,12 +0,0 @@ -# ignore-msvc - -include ../tools.mk - -all: - $(RUSTC) depa.rs - $(RUSTC) depb.rs - $(RUSTC) depc.rs - $(RUSTC) empty.rs --cfg bar 2>&1 | $(CGREP) '"-ltesta" "-ltestb" "-ltesta"' - $(RUSTC) empty.rs 2>&1 | $(CGREP) '"-ltesta"' - $(RUSTC) empty.rs 2>&1 | $(CGREP) -v '"-ltestb"' - $(RUSTC) empty.rs 2>&1 | $(CGREP) -v '"-ltesta" "-ltesta" "-ltesta"' diff --git a/tests/run-make/link-dedup/rmake.rs b/tests/run-make/link-dedup/rmake.rs new file mode 100644 index 00000000000..9bff3a4b44c --- /dev/null +++ b/tests/run-make/link-dedup/rmake.rs @@ -0,0 +1,24 @@ +// When native libraries are passed to the linker, there used to be an annoyance +// where multiple instances of the same library in a row would cause duplication in +// outputs. This has been fixed, and this test checks that it stays fixed. +// With the --cfg flag, -ltestb gets added to the output, breaking up the chain of -ltesta. +// Without the --cfg flag, there should be a single -ltesta, no more, no less. +// See https://github.com/rust-lang/rust/pull/84794 + +//@ ignore-msvc + +use run_make_support::rustc; + +fn main() { + rustc().input("depa.rs").run(); + rustc().input("depb.rs").run(); + rustc().input("depc.rs").run(); + let output = rustc().input("empty.rs").cfg("bar").run_fail(); + output.assert_stderr_contains(r#""-ltesta" "-ltestb" "-ltesta""#); + let output = rustc().input("empty.rs").run_fail(); + output.assert_stderr_contains(r#""-ltesta""#); + let output = rustc().input("empty.rs").run_fail(); + output.assert_stderr_not_contains(r#""-ltestb""#); + let output = rustc().input("empty.rs").run_fail(); + output.assert_stderr_not_contains(r#""-ltesta" "-ltesta" "-ltesta""#); +} diff --git a/tests/run-make/issue-64153/downstream.rs b/tests/run-make/lto-avoid-object-duplication/downstream.rs index e03704665d4..e03704665d4 100644 --- a/tests/run-make/issue-64153/downstream.rs +++ b/tests/run-make/lto-avoid-object-duplication/downstream.rs diff --git a/tests/run-make/lto-avoid-object-duplication/rmake.rs b/tests/run-make/lto-avoid-object-duplication/rmake.rs new file mode 100644 index 00000000000..b0e7494cb51 --- /dev/null +++ b/tests/run-make/lto-avoid-object-duplication/rmake.rs @@ -0,0 +1,40 @@ +// ignore-tidy-tab +// Staticlibs don't include Rust object files from upstream crates if the same +// code was already pulled into the lib via LTO. However, the bug described in +// https://github.com/rust-lang/rust/issues/64153 lead to this exclusion not +// working properly if the upstream crate was compiled with an explicit filename +// (via `-o`). + +// This test makes sure that functions defined in the upstream crates do not +// appear twice in the final staticlib when listing all the symbols from it. + +//@ ignore-windows +// Reason: `llvm-objdump`'s output looks different on windows than on other platforms. +// Only checking on Unix platforms should suffice. +//FIXME(Oneirical): This could be adapted to work on Windows by checking how +// that output differs. + +use run_make_support::{llvm_objdump, regex, rust_lib_name, rustc, static_lib_name}; + +fn main() { + rustc() + .crate_type("rlib") + .input("upstream.rs") + .output(rust_lib_name("upstream")) + .codegen_units(1) + .run(); + rustc() + .crate_type("staticlib") + .input("downstream.rs") + .arg("-Clto") + .output(static_lib_name("downstream")) + .codegen_units(1) + .run(); + let syms = llvm_objdump().arg("-t").input(static_lib_name("downstream")).run().stdout_utf8(); + let re = regex::Regex::new(r#"\s*g\s*F\s.*issue64153_test_function"#).unwrap(); + // Count the global instances of `issue64153_test_function`. There'll be 2 + // if the `upstream` object file got erroneously included twice. + // The line we are testing for with the regex looks something like: + // 0000000000000000 g F .text.issue64153_test_function 00000023 issue64153_test_function + assert_eq!(re.find_iter(syms.as_str()).count(), 1); +} diff --git a/tests/run-make/issue-64153/upstream.rs b/tests/run-make/lto-avoid-object-duplication/upstream.rs index 861a00298ea..861a00298ea 100644 --- a/tests/run-make/issue-64153/upstream.rs +++ b/tests/run-make/lto-avoid-object-duplication/upstream.rs diff --git a/tests/run-make/native-link-modifier-verbatim-linker/Makefile b/tests/run-make/native-link-modifier-verbatim-linker/Makefile deleted file mode 100644 index 47ed2a14291..00000000000 --- a/tests/run-make/native-link-modifier-verbatim-linker/Makefile +++ /dev/null @@ -1,15 +0,0 @@ -# ignore-cross-compile -# ignore-apple - -include ../tools.mk - -all: - # Verbatim allows specify precise name. - $(RUSTC) local_native_dep.rs --crate-type=staticlib -o $(TMPDIR)/local_some_strange_name.ext - $(RUSTC) main.rs -l static:+verbatim=local_some_strange_name.ext - - # With verbatim any other name cannot be used (local). - $(RUSTC) local_native_dep.rs --crate-type=staticlib -o $(TMPDIR)/liblocal_native_dep.a - $(RUSTC) local_native_dep.rs --crate-type=staticlib -o $(TMPDIR)/local_native_dep.a - $(RUSTC) local_native_dep.rs --crate-type=staticlib -o $(TMPDIR)/local_native_dep.lib - $(RUSTC) main.rs -l static:+verbatim=local_native_dep 2>&1 | $(CGREP) "local_native_dep" diff --git a/tests/run-make/native-link-modifier-verbatim-linker/rmake.rs b/tests/run-make/native-link-modifier-verbatim-linker/rmake.rs new file mode 100644 index 00000000000..6868cb368cc --- /dev/null +++ b/tests/run-make/native-link-modifier-verbatim-linker/rmake.rs @@ -0,0 +1,41 @@ +// `verbatim` is a native link modifier that forces rustc to only accept libraries with +// a specified name. This test checks that this modifier works as intended. +// This test is the same as native-link-modifier-rustc, but without rlibs. +// See https://github.com/rust-lang/rust/issues/99425 + +//@ ignore-apple +// Reason: linking fails due to the unusual ".ext" staticlib name. + +use run_make_support::rustc; + +fn main() { + // Verbatim allows for the specification of a precise name + // - in this case, the unconventional ".ext" extension. + rustc() + .input("local_native_dep.rs") + .crate_type("staticlib") + .output("local_some_strange_name.ext") + .run(); + rustc().input("main.rs").arg("-lstatic:+verbatim=local_some_strange_name.ext").run(); + + // This section voluntarily avoids using static_lib_name helpers to be verbatim. + // With verbatim, even these common library names are refused + // - it wants local_native_dep without + // any file extensions. + rustc() + .input("local_native_dep.rs") + .crate_type("staticlib") + .output("liblocal_native_dep.a") + .run(); + rustc().input("local_native_dep.rs").crate_type("staticlib").output("local_native_dep.a").run(); + rustc() + .input("local_native_dep.rs") + .crate_type("staticlib") + .output("local_native_dep.lib") + .run(); + rustc() + .input("main.rs") + .arg("-lstatic:+verbatim=local_native_dep") + .run_fail() + .assert_stderr_contains("local_native_dep"); +} diff --git a/tests/run-make/native-link-modifier-verbatim-rustc/Makefile b/tests/run-make/native-link-modifier-verbatim-rustc/Makefile deleted file mode 100644 index dfd6ec50fc0..00000000000 --- a/tests/run-make/native-link-modifier-verbatim-rustc/Makefile +++ /dev/null @@ -1,12 +0,0 @@ -include ../tools.mk - -all: - # Verbatim allows specify precise name. - $(RUSTC) upstream_native_dep.rs --crate-type=staticlib -o $(TMPDIR)/upstream_some_strange_name.ext - $(RUSTC) rust_dep.rs -l static:+verbatim=upstream_some_strange_name.ext --crate-type rlib - - # With verbatim any other name cannot be used (upstream). - $(RUSTC) upstream_native_dep.rs --crate-type=staticlib -o $(TMPDIR)/libupstream_native_dep.a - $(RUSTC) upstream_native_dep.rs --crate-type=staticlib -o $(TMPDIR)/upstream_native_dep.a - $(RUSTC) upstream_native_dep.rs --crate-type=staticlib -o $(TMPDIR)/upstream_native_dep.lib - $(RUSTC) rust_dep.rs -l static:+verbatim=upstream_native_dep --crate-type rlib 2>&1 | $(CGREP) "upstream_native_dep" diff --git a/tests/run-make/native-link-modifier-verbatim-rustc/rmake.rs b/tests/run-make/native-link-modifier-verbatim-rustc/rmake.rs new file mode 100644 index 00000000000..703b8a80ef3 --- /dev/null +++ b/tests/run-make/native-link-modifier-verbatim-rustc/rmake.rs @@ -0,0 +1,47 @@ +// `verbatim` is a native link modifier that forces rustc to only accept libraries with +// a specified name. This test checks that this modifier works as intended. +// This test is the same as native-link-modifier-linker, but with rlibs. +// See https://github.com/rust-lang/rust/issues/99425 + +use run_make_support::rustc; + +fn main() { + // Verbatim allows for the specification of a precise name + // - in this case, the unconventional ".ext" extension. + rustc() + .input("upstream_native_dep.rs") + .crate_type("staticlib") + .output("upstream_some_strange_name.ext") + .run(); + rustc() + .input("rust_dep.rs") + .crate_type("rlib") + .arg("-lstatic:+verbatim=upstream_some_strange_name.ext") + .run(); + + // This section voluntarily avoids using static_lib_name helpers to be verbatim. + // With verbatim, even these common library names are refused + // - it wants upstream_native_dep without + // any file extensions. + rustc() + .input("upstream_native_dep.rs") + .crate_type("staticlib") + .output("libupstream_native_dep.a") + .run(); + rustc() + .input("upstream_native_dep.rs") + .crate_type("staticlib") + .output("upstream_native_dep.a") + .run(); + rustc() + .input("upstream_native_dep.rs") + .crate_type("staticlib") + .output("upstream_native_dep.lib") + .run(); + rustc() + .input("rust_dep.rs") + .crate_type("rlib") + .arg("-lstatic:+verbatim=upstream_native_dep") + .run_fail() + .assert_stderr_contains("upstream_native_dep"); +} diff --git a/tests/run-make/no-builtins-lto/Makefile b/tests/run-make/no-builtins-lto/Makefile deleted file mode 100644 index c8f05d9918b..00000000000 --- a/tests/run-make/no-builtins-lto/Makefile +++ /dev/null @@ -1,9 +0,0 @@ -include ../tools.mk - -all: - # Compile a `#![no_builtins]` rlib crate - $(RUSTC) no_builtins.rs - # Build an executable that depends on that crate using LTO. The no_builtins crate doesn't - # participate in LTO, so its rlib must be explicitly linked into the final binary. Verify this by - # grepping the linker arguments. - $(RUSTC) main.rs -C lto --print link-args | $(CGREP) 'libno_builtins.rlib' diff --git a/tests/run-make/no-builtins-lto/rmake.rs b/tests/run-make/no-builtins-lto/rmake.rs new file mode 100644 index 00000000000..8e0c3a63649 --- /dev/null +++ b/tests/run-make/no-builtins-lto/rmake.rs @@ -0,0 +1,20 @@ +// The rlib produced by a no_builtins crate should be explicitely linked +// during compilation, and as a result be present in the linker arguments. +// See the comments inside this file for more details. +// See https://github.com/rust-lang/rust/pull/35637 + +use run_make_support::{rust_lib_name, rustc}; + +fn main() { + // Compile a `#![no_builtins]` rlib crate + rustc().input("no_builtins.rs").run(); + // Build an executable that depends on that crate using LTO. The no_builtins crate doesn't + // participate in LTO, so its rlib must be explicitly + // linked into the final binary. Verify this by grepping the linker arguments. + rustc() + .input("main.rs") + .arg("-Clto") + .print("link-args") + .run() + .assert_stdout_contains(rust_lib_name("no_builtins")); +} diff --git a/tests/run-make/output-filename-conflicts-with-directory/Makefile b/tests/run-make/output-filename-conflicts-with-directory/Makefile deleted file mode 100644 index 45221356cd9..00000000000 --- a/tests/run-make/output-filename-conflicts-with-directory/Makefile +++ /dev/null @@ -1,7 +0,0 @@ -include ../tools.mk - -all: - cp foo.rs $(TMPDIR)/foo.rs - mkdir $(TMPDIR)/foo - $(RUSTC) $(TMPDIR)/foo.rs -o $(TMPDIR)/foo 2>&1 \ - | $(CGREP) -e "the generated executable for the input file \".*foo\.rs\" conflicts with the existing directory \".*foo\"" diff --git a/tests/run-make/output-filename-conflicts-with-directory/rmake.rs b/tests/run-make/output-filename-conflicts-with-directory/rmake.rs new file mode 100644 index 00000000000..4b5c9e8d118 --- /dev/null +++ b/tests/run-make/output-filename-conflicts-with-directory/rmake.rs @@ -0,0 +1,14 @@ +// ignore-tidy-linelength +// When the compiled executable would conflict with a directory, a +// rustc error should be displayed instead of a verbose and +// potentially-confusing linker error. +// See https://github.com/rust-lang/rust/pull/47203 + +use run_make_support::{fs_wrapper, rustc}; + +fn main() { + fs_wrapper::create_dir("foo"); + rustc().input("foo.rs").output("foo").run_fail().assert_stderr_contains( + r#"the generated executable for the input file "foo.rs" conflicts with the existing directory "foo""#, + ); +} diff --git a/tests/run-make/output-filename-overwrites-input/Makefile b/tests/run-make/output-filename-overwrites-input/Makefile deleted file mode 100644 index fe5d231382d..00000000000 --- a/tests/run-make/output-filename-overwrites-input/Makefile +++ /dev/null @@ -1,14 +0,0 @@ -# ignore-cross-compile -include ../tools.mk - -all: - cp foo.rs $(TMPDIR)/foo - $(RUSTC) $(TMPDIR)/foo -o $(TMPDIR)/foo 2>&1 \ - | $(CGREP) -e "the input file \".*foo\" would be overwritten by the generated executable" - cp bar.rs $(TMPDIR)/bar.rlib - $(RUSTC) $(TMPDIR)/bar.rlib -o $(TMPDIR)/bar.rlib 2>&1 \ - | $(CGREP) -e "the input file \".*bar.rlib\" would be overwritten by the generated executable" - $(RUSTC) foo.rs 2>&1 && $(RUSTC) -Z ls=root $(TMPDIR)/foo 2>&1 - cp foo.rs $(TMPDIR)/foo.rs - $(RUSTC) $(TMPDIR)/foo.rs -o $(TMPDIR)/foo.rs 2>&1 \ - | $(CGREP) -e "the input file \".*foo.rs\" would be overwritten by the generated executable" diff --git a/tests/run-make/output-filename-overwrites-input/rmake.rs b/tests/run-make/output-filename-overwrites-input/rmake.rs new file mode 100644 index 00000000000..c6055e818a1 --- /dev/null +++ b/tests/run-make/output-filename-overwrites-input/rmake.rs @@ -0,0 +1,21 @@ +// If rustc is invoked on a file that would be overwritten by the +// compilation, the compilation should fail, to avoid accidental loss. +// See https://github.com/rust-lang/rust/pull/46814 + +//@ ignore-cross-compile + +use run_make_support::{fs_wrapper, rustc}; + +fn main() { + fs_wrapper::copy("foo.rs", "foo"); + rustc().input("foo").output("foo").run_fail().assert_stderr_contains( + r#"the input file "foo" would be overwritten by the generated executable"#, + ); + fs_wrapper::copy("bar.rs", "bar.rlib"); + rustc().input("bar.rlib").output("bar.rlib").run_fail().assert_stderr_contains( + r#"the input file "bar.rlib" would be overwritten by the generated executable"#, + ); + rustc().input("foo.rs").output("foo.rs").run_fail().assert_stderr_contains( + r#"the input file "foo.rs" would be overwritten by the generated executable"#, + ); +} diff --git a/tests/run-make/output-with-hyphens/Makefile b/tests/run-make/output-with-hyphens/Makefile deleted file mode 100644 index 846c9a66a89..00000000000 --- a/tests/run-make/output-with-hyphens/Makefile +++ /dev/null @@ -1,8 +0,0 @@ -# ignore-cross-compile -include ../tools.mk - -all: - $(RUSTC) foo-bar.rs --crate-type bin - [ -f $(TMPDIR)/$(call BIN,foo-bar) ] - $(RUSTC) foo-bar.rs --crate-type lib - [ -f $(TMPDIR)/libfoo_bar.rlib ] diff --git a/tests/run-make/output-with-hyphens/rmake.rs b/tests/run-make/output-with-hyphens/rmake.rs new file mode 100644 index 00000000000..79deb772bc5 --- /dev/null +++ b/tests/run-make/output-with-hyphens/rmake.rs @@ -0,0 +1,17 @@ +// Rust files with hyphens in their filename should +// not result in compiled libraries keeping that hyphen - +// it should become an underscore. Only bin executables +// should keep the hyphen. This test ensures that this rule +// remains enforced. +// See https://github.com/rust-lang/rust/pull/23786 + +//@ ignore-cross-compile + +use run_make_support::{bin_name, path, rust_lib_name, rustc}; + +fn main() { + rustc().input("foo-bar.rs").crate_type("bin").run(); + assert!(path(bin_name("foo-bar")).exists()); + rustc().input("foo-bar.rs").crate_type("lib").run(); + assert!(path(rust_lib_name("foo_bar")).exists()); +} diff --git a/tests/run-make/parallel-rustc-no-overwrite/rmake.rs b/tests/run-make/parallel-rustc-no-overwrite/rmake.rs new file mode 100644 index 00000000000..3f032cf3762 --- /dev/null +++ b/tests/run-make/parallel-rustc-no-overwrite/rmake.rs @@ -0,0 +1,25 @@ +// When two instances of rustc are invoked in parallel, they +// can conflict on their temporary files and overwrite each others', +// leading to unsuccessful compilation. The -Z temps-dir flag adds +// separate designated directories for each rustc invocation, preventing +// conflicts. This test uses this flag and checks for successful compilation. +// See https://github.com/rust-lang/rust/pull/83846 + +use run_make_support::{fs_wrapper, rustc}; +use std::sync::{Arc, Barrier}; +use std::thread; + +fn main() { + fs_wrapper::create_file("lib.rs"); + let barrier = Arc::new(Barrier::new(2)); + let handle = { + let barrier = Arc::clone(&barrier); + thread::spawn(move || { + barrier.wait(); + rustc().crate_type("lib").arg("-Ztemps-dir=temp1").input("lib.rs").run(); + }) + }; + barrier.wait(); + rustc().crate_type("staticlib").arg("-Ztemps-dir=temp2").input("lib.rs").run(); + handle.join().expect("lib thread panicked"); +} diff --git a/tests/run-make/separate-link-fail/Makefile b/tests/run-make/separate-link-fail/Makefile deleted file mode 100644 index bfd18fbf972..00000000000 --- a/tests/run-make/separate-link-fail/Makefile +++ /dev/null @@ -1,7 +0,0 @@ -include ../tools.mk - -all: - echo 'fn main(){}' > $(TMPDIR)/main.rs - # Make sure that this fails - ! $(RUSTC) -Z link-only $(TMPDIR)/main.rs 2> $(TMPDIR)/stderr.txt - $(CGREP) "The input does not look like a .rlink file" < $(TMPDIR)/stderr.txt diff --git a/tests/run-make/separate-link-fail/foo.rs b/tests/run-make/separate-link-fail/foo.rs new file mode 100644 index 00000000000..f328e4d9d04 --- /dev/null +++ b/tests/run-make/separate-link-fail/foo.rs @@ -0,0 +1 @@ +fn main() {} diff --git a/tests/run-make/separate-link-fail/rmake.rs b/tests/run-make/separate-link-fail/rmake.rs new file mode 100644 index 00000000000..b5d5300de68 --- /dev/null +++ b/tests/run-make/separate-link-fail/rmake.rs @@ -0,0 +1,15 @@ +// rustc usually wants Rust code as its input. The flag `link-only` is one +// exception, where a .rlink file is instead requested. The compiler should +// fail when the user is wrongly passing the original Rust code +// instead of the generated .rlink file when this flag is on. +// https://github.com/rust-lang/rust/issues/95297 + +use run_make_support::rustc; + +fn main() { + rustc() + .arg("-Zlink-only") + .input("foo.rs") + .run_fail() + .assert_stderr_contains("The input does not look like a .rlink file"); +} diff --git a/tests/run-make/separate-link/Makefile b/tests/run-make/separate-link/Makefile deleted file mode 100644 index d01158d9f5f..00000000000 --- a/tests/run-make/separate-link/Makefile +++ /dev/null @@ -1,7 +0,0 @@ -# ignore-cross-compile -include ../tools.mk - -all: - echo 'fn main(){}' | $(RUSTC) -Z no-link - - $(RUSTC) -Z link-only $(TMPDIR)/rust_out.rlink - $(call RUN,rust_out) diff --git a/tests/run-make/separate-link/rmake.rs b/tests/run-make/separate-link/rmake.rs new file mode 100644 index 00000000000..e91b25489bc --- /dev/null +++ b/tests/run-make/separate-link/rmake.rs @@ -0,0 +1,14 @@ +// The compiler flags no-link (and by extension, link-only) used to be broken +// due to changes in encoding/decoding. This was patched, and this test checks +// that these flags are not broken again, resulting in successful compilation. +// See https://github.com/rust-lang/rust/issues/77857 + +//@ ignore-cross-compile + +use run_make_support::{run, rustc}; + +fn main() { + rustc().stdin(b"fn main(){}").arg("-Zno-link").arg("-").run(); + rustc().arg("-Zlink-only").input("rust_out.rlink").run(); + run("rust_out"); +} diff --git a/tests/run-make/used/Makefile b/tests/run-make/used/Makefile deleted file mode 100644 index e80eb9e4020..00000000000 --- a/tests/run-make/used/Makefile +++ /dev/null @@ -1,7 +0,0 @@ -include ../tools.mk - -# ignore-windows-msvc - -all: - $(RUSTC) -C opt-level=3 --emit=obj used.rs - nm $(TMPDIR)/used.o | $(CGREP) FOO diff --git a/tests/run-make/used/rmake.rs b/tests/run-make/used/rmake.rs new file mode 100644 index 00000000000..56ef5c6b9cc --- /dev/null +++ b/tests/run-make/used/rmake.rs @@ -0,0 +1,15 @@ +// This test ensures that the compiler is keeping static variables, even if not referenced +// by another part of the program, in the output object file. +// +// It comes from #39987 which implements this RFC for the #[used] attribute: +// https://rust-lang.github.io/rfcs/2386-used.html + +//@ ignore-msvc + +use run_make_support::{cmd, rustc}; + +fn main() { + rustc().opt_level("3").emit("obj").input("used.rs").run(); + + cmd("nm").arg("used.o").run().assert_stdout_contains("FOO"); +} diff --git a/tests/rustdoc-ui/doctest/auxiliary/pub_trait.rs b/tests/rustdoc-ui/doctest/auxiliary/pub_trait.rs new file mode 100644 index 00000000000..0a47fdc74d7 --- /dev/null +++ b/tests/rustdoc-ui/doctest/auxiliary/pub_trait.rs @@ -0,0 +1 @@ +pub trait Trait {} diff --git a/tests/rustdoc-ui/doctest/non-local-defs-impl.rs b/tests/rustdoc-ui/doctest/non-local-defs-impl.rs new file mode 100644 index 00000000000..c984e097c04 --- /dev/null +++ b/tests/rustdoc-ui/doctest/non-local-defs-impl.rs @@ -0,0 +1,31 @@ +//@ check-fail +//@ edition:2018 +//@ failure-status: 101 +//@ aux-build:pub_trait.rs +//@ compile-flags: --test --test-args --test-threads=1 +//@ normalize-stdout-test: "tests/rustdoc-ui/doctest" -> "$$DIR" +//@ normalize-stdout-test "finished in \d+\.\d+s" -> "finished in $$TIME" + +#![doc(test(attr(deny(non_local_definitions))))] +#![doc(test(attr(allow(dead_code))))] + +/// This will produce a warning: +/// ```rust,no_run +/// # extern crate pub_trait; +/// # use pub_trait::Trait; +/// +/// struct Local; +/// impl Trait for &Local {} +/// ``` +/// +/// But this shoudln't produce a warning: +/// ```rust,no_run +/// # extern crate pub_trait; +/// # use pub_trait::Trait; +/// +/// struct Local; +/// impl Trait for &Local {} +/// +/// # fn main() {} +/// ``` +pub fn doctest() {} diff --git a/tests/rustdoc-ui/doctest/non-local-defs-impl.stdout b/tests/rustdoc-ui/doctest/non-local-defs-impl.stdout new file mode 100644 index 00000000000..27797e22f8e --- /dev/null +++ b/tests/rustdoc-ui/doctest/non-local-defs-impl.stdout @@ -0,0 +1,37 @@ + +running 2 tests +test $DIR/non-local-defs-impl.rs - doctest (line 13) - compile ... FAILED +test $DIR/non-local-defs-impl.rs - doctest (line 22) - compile ... ok + +failures: + +---- $DIR/non-local-defs-impl.rs - doctest (line 13) stdout ---- +error: non-local `impl` definition, `impl` blocks should be written at the same level as their item + --> $DIR/non-local-defs-impl.rs:18:1 + | +LL | impl Trait for &Local {} + | ^^^^^-----^^^^^------ + | | | + | | `&'_ Local` is not local + | | help: remove `&` to make the `impl` local + | `Trait` is not local + | + = 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` + = help: make this doc-test a standalone test with its own `fn main() { ... }` + = note: this lint may become deny-by-default in the edition 2024 and higher, see the tracking issue <https://github.com/rust-lang/rust/issues/120363> +note: the lint level is defined here + --> $DIR/non-local-defs-impl.rs:11:9 + | +LL | #![deny(non_local_definitions)] + | ^^^^^^^^^^^^^^^^^^^^^ + +error: aborting due to 1 previous error + +Couldn't compile the test. + +failures: + $DIR/non-local-defs-impl.rs - doctest (line 13) + +test result: FAILED. 1 passed; 1 failed; 0 ignored; 0 measured; 0 filtered out; finished in $TIME + diff --git a/tests/ui-fulldeps/internal-lints/diagnostics.rs b/tests/ui-fulldeps/internal-lints/diagnostics.rs index 7c3a2c97474..5fcff74064a 100644 --- a/tests/ui-fulldeps/internal-lints/diagnostics.rs +++ b/tests/ui-fulldeps/internal-lints/diagnostics.rs @@ -14,8 +14,8 @@ extern crate rustc_session; extern crate rustc_span; use rustc_errors::{ - Diag, DiagCtxt, DiagInner, DiagMessage, Diagnostic, EmissionGuarantee, Level, LintDiagnostic, - SubdiagMessageOp, SubdiagMessage, Subdiagnostic, + Diag, DiagCtxtHandle, DiagInner, DiagMessage, Diagnostic, EmissionGuarantee, Level, + LintDiagnostic, SubdiagMessage, SubdiagMessageOp, Subdiagnostic, }; use rustc_macros::{Diagnostic, Subdiagnostic}; use rustc_span::Span; @@ -39,7 +39,7 @@ struct Note { pub struct UntranslatableInDiagnostic; impl<'a, G: EmissionGuarantee> Diagnostic<'a, G> for UntranslatableInDiagnostic { - fn into_diag(self, dcx: &'a DiagCtxt, level: Level) -> Diag<'a, G> { + fn into_diag(self, dcx: DiagCtxtHandle<'a>, level: Level) -> Diag<'a, G> { Diag::new(dcx, level, "untranslatable diagnostic") //~^ ERROR diagnostics should be created using translatable messages } @@ -48,7 +48,7 @@ impl<'a, G: EmissionGuarantee> Diagnostic<'a, G> for UntranslatableInDiagnostic pub struct TranslatableInDiagnostic; impl<'a, G: EmissionGuarantee> Diagnostic<'a, G> for TranslatableInDiagnostic { - fn into_diag(self, dcx: &'a DiagCtxt, level: Level) -> Diag<'a, G> { + fn into_diag(self, dcx: DiagCtxtHandle<'a>, level: Level) -> Diag<'a, G> { Diag::new(dcx, level, crate::fluent_generated::no_crate_example) } } @@ -81,7 +81,7 @@ impl Subdiagnostic for TranslatableInAddtoDiag { pub struct UntranslatableInLintDiagnostic; impl<'a> LintDiagnostic<'a, ()> for UntranslatableInLintDiagnostic { - fn decorate_lint<'b, >(self, diag: &'b mut Diag<'a, ()>) { + fn decorate_lint<'b>(self, diag: &'b mut Diag<'a, ()>) { diag.note("untranslatable diagnostic"); //~^ ERROR diagnostics should be created using translatable messages } @@ -95,7 +95,7 @@ impl<'a> LintDiagnostic<'a, ()> for TranslatableInLintDiagnostic { } } -pub fn make_diagnostics<'a>(dcx: &'a DiagCtxt) { +pub fn make_diagnostics<'a>(dcx: DiagCtxtHandle<'a>) { let _diag = dcx.struct_err(crate::fluent_generated::no_crate_example); //~^ ERROR diagnostics should only be created in `Diagnostic`/`Subdiagnostic`/`LintDiagnostic` impls @@ -107,7 +107,7 @@ pub fn make_diagnostics<'a>(dcx: &'a DiagCtxt) { // Check that `rustc_lint_diagnostics`-annotated functions aren't themselves linted for // `diagnostic_outside_of_impl`. #[rustc_lint_diagnostics] -pub fn skipped_because_of_annotation<'a>(dcx: &'a DiagCtxt) { +pub fn skipped_because_of_annotation<'a>(dcx: DiagCtxtHandle<'a>) { #[allow(rustc::untranslatable_diagnostic)] let _diag = dcx.struct_err("untranslatable diagnostic"); // okay! } diff --git a/tests/ui/associated-consts/double-elided.rs b/tests/ui/associated-consts/double-elided.rs index fd0317781bb..6831b599374 100644 --- a/tests/ui/associated-consts/double-elided.rs +++ b/tests/ui/associated-consts/double-elided.rs @@ -1,12 +1,10 @@ +//@ check-pass + struct S; impl S { const C: &&str = &""; - //~^ WARN `&` without an explicit lifetime name cannot be used here - //~| WARN this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! - //~| WARN `&` without an explicit lifetime name cannot be used here - //~| WARN this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! - //~| ERROR in type `&&str`, reference has a longer lifetime than the data it references + // Now resolves to `&'static &'static str`. } fn main() {} diff --git a/tests/ui/associated-consts/double-elided.stderr b/tests/ui/associated-consts/double-elided.stderr deleted file mode 100644 index 67834788ccd..00000000000 --- a/tests/ui/associated-consts/double-elided.stderr +++ /dev/null @@ -1,47 +0,0 @@ -warning: `&` without an explicit lifetime name cannot be used here - --> $DIR/double-elided.rs:4:14 - | -LL | const C: &&str = &""; - | ^ - | - = 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 #115010 <https://github.com/rust-lang/rust/issues/115010> - = note: `#[warn(elided_lifetimes_in_associated_constant)]` on by default -help: use the `'static` lifetime - | -LL | const C: &'static &str = &""; - | +++++++ - -warning: `&` without an explicit lifetime name cannot be used here - --> $DIR/double-elided.rs:4:15 - | -LL | const C: &&str = &""; - | ^ - | - = 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 #115010 <https://github.com/rust-lang/rust/issues/115010> -help: use the `'static` lifetime - | -LL | const C: &&'static str = &""; - | +++++++ - -error[E0491]: in type `&&str`, reference has a longer lifetime than the data it references - --> $DIR/double-elided.rs:4:5 - | -LL | const C: &&str = &""; - | ^^^^^^^^^^^^^^^^^^^^^ - | -note: the pointer is valid for the anonymous lifetime as defined here - --> $DIR/double-elided.rs:4:14 - | -LL | const C: &&str = &""; - | ^ -note: but the referenced data is only valid for the anonymous lifetime as defined here - --> $DIR/double-elided.rs:4:14 - | -LL | const C: &&str = &""; - | ^ - -error: aborting due to 1 previous error; 2 warnings emitted - -For more information about this error, try `rustc --explain E0491`. diff --git a/tests/ui/associated-consts/infer-placeholder-in-non-suggestable-pos.rs b/tests/ui/associated-consts/infer-placeholder-in-non-suggestable-pos.rs index 1e0b77b0d3b..40896c32e11 100644 --- a/tests/ui/associated-consts/infer-placeholder-in-non-suggestable-pos.rs +++ b/tests/ui/associated-consts/infer-placeholder-in-non-suggestable-pos.rs @@ -5,8 +5,6 @@ trait Trait { impl Trait for () { const ASSOC: &dyn Fn(_) = 1i32; //~^ ERROR the placeholder `_` is not allowed within types on item signatures for associated constants - //~| WARN `&` without an explicit lifetime name cannot be used here - //~| WARN this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! } fn main() {} diff --git a/tests/ui/associated-consts/infer-placeholder-in-non-suggestable-pos.stderr b/tests/ui/associated-consts/infer-placeholder-in-non-suggestable-pos.stderr index e946491a084..6b8ba9af7a0 100644 --- a/tests/ui/associated-consts/infer-placeholder-in-non-suggestable-pos.stderr +++ b/tests/ui/associated-consts/infer-placeholder-in-non-suggestable-pos.stderr @@ -1,23 +1,9 @@ -warning: `&` without an explicit lifetime name cannot be used here - --> $DIR/infer-placeholder-in-non-suggestable-pos.rs:6:18 - | -LL | const ASSOC: &dyn Fn(_) = 1i32; - | ^ - | - = 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 #115010 <https://github.com/rust-lang/rust/issues/115010> - = note: `#[warn(elided_lifetimes_in_associated_constant)]` on by default -help: use the `'static` lifetime - | -LL | const ASSOC: &'static dyn Fn(_) = 1i32; - | +++++++ - error[E0121]: the placeholder `_` is not allowed within types on item signatures for associated constants --> $DIR/infer-placeholder-in-non-suggestable-pos.rs:6:26 | LL | const ASSOC: &dyn Fn(_) = 1i32; | ^ not allowed in type signatures -error: aborting due to 1 previous error; 1 warning emitted +error: aborting due to 1 previous error For more information about this error, try `rustc --explain E0121`. diff --git a/tests/ui/associated-consts/wrong-projection-self-ty-invalid-bivariant-arg.rs b/tests/ui/associated-consts/wrong-projection-self-ty-invalid-bivariant-arg.rs new file mode 100644 index 00000000000..e2fc2961a44 --- /dev/null +++ b/tests/ui/associated-consts/wrong-projection-self-ty-invalid-bivariant-arg.rs @@ -0,0 +1,10 @@ +struct Fail<T>; +//~^ ERROR: type parameter `T` is never used + +impl Fail<i32> { + const C: () = (); +} + +fn main() { + Fail::<()>::C +} diff --git a/tests/ui/associated-consts/wrong-projection-self-ty-invalid-bivariant-arg.stderr b/tests/ui/associated-consts/wrong-projection-self-ty-invalid-bivariant-arg.stderr new file mode 100644 index 00000000000..f0a6ccf243a --- /dev/null +++ b/tests/ui/associated-consts/wrong-projection-self-ty-invalid-bivariant-arg.stderr @@ -0,0 +1,12 @@ +error[E0392]: type parameter `T` is never used + --> $DIR/wrong-projection-self-ty-invalid-bivariant-arg.rs:1:13 + | +LL | struct Fail<T>; + | ^ unused type parameter + | + = help: consider removing `T`, referring to it in a field, or using a marker such as `PhantomData` + = help: if you intended `T` to be a const parameter, use `const T: /* Type */` instead + +error: aborting due to 1 previous error + +For more information about this error, try `rustc --explain E0392`. diff --git a/tests/ui/associated-consts/wrong-projection-self-ty-invalid-bivariant-arg2.rs b/tests/ui/associated-consts/wrong-projection-self-ty-invalid-bivariant-arg2.rs new file mode 100644 index 00000000000..cb53d902ba1 --- /dev/null +++ b/tests/ui/associated-consts/wrong-projection-self-ty-invalid-bivariant-arg2.rs @@ -0,0 +1,17 @@ +trait Proj { + type Assoc; +} +impl<T> Proj for T { + type Assoc = T; +} + +struct Fail<T: Proj<Assoc = U>, U>(T); + +impl Fail<i32, i32> { + const C: () = (); +} + +fn main() { + Fail::<i32, u32>::C + //~^ ERROR: type mismatch +} diff --git a/tests/ui/associated-consts/wrong-projection-self-ty-invalid-bivariant-arg2.stderr b/tests/ui/associated-consts/wrong-projection-self-ty-invalid-bivariant-arg2.stderr new file mode 100644 index 00000000000..0d63b7f5b29 --- /dev/null +++ b/tests/ui/associated-consts/wrong-projection-self-ty-invalid-bivariant-arg2.stderr @@ -0,0 +1,20 @@ +error[E0271]: type mismatch resolving `<i32 as Proj>::Assoc == u32` + --> $DIR/wrong-projection-self-ty-invalid-bivariant-arg2.rs:15:5 + | +LL | Fail::<i32, u32>::C + | ^^^^^^^^^^^^^^^^ type mismatch resolving `<i32 as Proj>::Assoc == u32` + | +note: expected this to be `u32` + --> $DIR/wrong-projection-self-ty-invalid-bivariant-arg2.rs:5:18 + | +LL | type Assoc = T; + | ^ +note: required by a bound in `Fail` + --> $DIR/wrong-projection-self-ty-invalid-bivariant-arg2.rs:8:21 + | +LL | struct Fail<T: Proj<Assoc = U>, U>(T); + | ^^^^^^^^^ required by this bound in `Fail` + +error: aborting due to 1 previous error + +For more information about this error, try `rustc --explain E0271`. diff --git a/tests/ui/async-await/async-closures/wrong-fn-kind.stderr b/tests/ui/async-await/async-closures/wrong-fn-kind.stderr index e56389b3202..6f07a6feed3 100644 --- a/tests/ui/async-await/async-closures/wrong-fn-kind.stderr +++ b/tests/ui/async-await/async-closures/wrong-fn-kind.stderr @@ -20,15 +20,16 @@ LL | fn needs_async_fn(_: impl async Fn()) {} | ^^^^^^^^^^ required by this bound in `needs_async_fn` error[E0596]: cannot borrow `x` as mutable, as it is a captured variable in a `Fn` closure - --> $DIR/wrong-fn-kind.rs:9:29 + --> $DIR/wrong-fn-kind.rs:9:20 | LL | fn needs_async_fn(_: impl async Fn()) {} | --------------- change this to accept `FnMut` instead of `Fn` ... LL | needs_async_fn(async || { - | _____--------------_--------_^ - | | | | - | | | in this closure + | -------------- ^------- + | | | + | _____|______________in this closure + | | | | | expects `Fn` instead of `FnMut` LL | | LL | | x += 1; diff --git a/tests/ui/borrowck/unmatched-arg-and-hir-arg-issue-126385.rs b/tests/ui/borrowck/unmatched-arg-and-hir-arg-issue-126385.rs new file mode 100644 index 00000000000..637c47f2939 --- /dev/null +++ b/tests/ui/borrowck/unmatched-arg-and-hir-arg-issue-126385.rs @@ -0,0 +1,14 @@ +// This test was triggering a `span_bug` crash, which was then fixed by +// downgrading it to a `span_delayed_bug`. + +pub struct MyStruct<'field> { + field: &'field [u32], +} + +impl MyStruct<'_> { + pub fn f(field: &[u32]) -> Self<u32> { //~ ERROR type arguments are not allowed on self type + Self { field } //~ ERROR lifetime may not live long enough + } +} + +fn main() {} diff --git a/tests/ui/borrowck/unmatched-arg-and-hir-arg-issue-126385.stderr b/tests/ui/borrowck/unmatched-arg-and-hir-arg-issue-126385.stderr new file mode 100644 index 00000000000..0ae301b2090 --- /dev/null +++ b/tests/ui/borrowck/unmatched-arg-and-hir-arg-issue-126385.stderr @@ -0,0 +1,34 @@ +error[E0109]: type arguments are not allowed on self type + --> $DIR/unmatched-arg-and-hir-arg-issue-126385.rs:9:37 + | +LL | pub fn f(field: &[u32]) -> Self<u32> { + | ---- ^^^ type argument not allowed + | | + | not allowed on self type + | +note: `Self` is of type `MyStruct<'_>` + --> $DIR/unmatched-arg-and-hir-arg-issue-126385.rs:4:12 + | +LL | pub struct MyStruct<'field> { + | ^^^^^^^^ `Self` corresponds to this type +... +LL | impl MyStruct<'_> { + | ----------------- `Self` is on type `MyStruct` in this `impl` +help: the `Self` type doesn't accept type parameters, use the concrete type's name `MyStruct` instead if you want to specify its type parameters + | +LL | pub fn f(field: &[u32]) -> MyStruct<u32> { + | ~~~~~~~~ + +error: lifetime may not live long enough + --> $DIR/unmatched-arg-and-hir-arg-issue-126385.rs:10:9 + | +LL | pub fn f(field: &[u32]) -> Self<u32> { + | - --------- return type is MyStruct<'2> + | | + | let's call the lifetime of this reference `'1` +LL | Self { field } + | ^^^^^^^^^^^^^^ associated function was supposed to return data with lifetime `'2` but it is returning data with lifetime `'1` + +error: aborting due to 2 previous errors + +For more information about this error, try `rustc --explain E0109`. diff --git a/tests/ui/closures/wrong-closure-arg-suggestion-125325.rs b/tests/ui/closures/wrong-closure-arg-suggestion-125325.rs new file mode 100644 index 00000000000..ce575697cf6 --- /dev/null +++ b/tests/ui/closures/wrong-closure-arg-suggestion-125325.rs @@ -0,0 +1,29 @@ +// Regression test for #125325 + +// Tests that we suggest changing an `impl Fn` param +// to `impl FnMut` when the provided closure arg +// is trying to mutate the closure env. +// Ensures that it works that way for both +// functions and methods + +struct S; + +impl S { + fn assoc_func(&self, _f: impl Fn()) -> usize { + 0 + } +} + +fn func(_f: impl Fn()) -> usize { + 0 +} + +fn test_func(s: &S) -> usize { + let mut x = (); + s.assoc_func(|| x = ()); + //~^ cannot assign to `x`, as it is a captured variable in a `Fn` closure + func(|| x = ()) + //~^ cannot assign to `x`, as it is a captured variable in a `Fn` closure +} + +fn main() {} diff --git a/tests/ui/closures/wrong-closure-arg-suggestion-125325.stderr b/tests/ui/closures/wrong-closure-arg-suggestion-125325.stderr new file mode 100644 index 00000000000..e0cce8c4b31 --- /dev/null +++ b/tests/ui/closures/wrong-closure-arg-suggestion-125325.stderr @@ -0,0 +1,28 @@ +error[E0594]: cannot assign to `x`, as it is a captured variable in a `Fn` closure + --> $DIR/wrong-closure-arg-suggestion-125325.rs:23:21 + | +LL | fn assoc_func(&self, _f: impl Fn()) -> usize { + | --------- change this to accept `FnMut` instead of `Fn` +... +LL | s.assoc_func(|| x = ()); + | --------------^^^^^^- + | | | | + | | | cannot assign + | | in this closure + | expects `Fn` instead of `FnMut` + +error[E0594]: cannot assign to `x`, as it is a captured variable in a `Fn` closure + --> $DIR/wrong-closure-arg-suggestion-125325.rs:25:13 + | +LL | fn func(_f: impl Fn()) -> usize { + | --------- change this to accept `FnMut` instead of `Fn` +... +LL | func(|| x = ()) + | ---- -- ^^^^^^ cannot assign + | | | + | | in this closure + | expects `Fn` instead of `FnMut` + +error: aborting due to 2 previous errors + +For more information about this error, try `rustc --explain E0594`. diff --git a/tests/ui/coercion/coerce-issue-49593-box-never-windows.nofallback.stderr b/tests/ui/coercion/coerce-issue-49593-box-never-windows.nofallback.stderr deleted file mode 100644 index b976f70acf7..00000000000 --- a/tests/ui/coercion/coerce-issue-49593-box-never-windows.nofallback.stderr +++ /dev/null @@ -1,19 +0,0 @@ -error[E0277]: the trait bound `(): std::error::Error` is not satisfied - --> $DIR/coerce-issue-49593-box-never-windows.rs:18:53 - | -LL | /* *mut $0 is coerced to Box<dyn Error> here */ Box::<_ /* ! */>::new(x) - | ^^^^^^^^^^^^^^^^^^^^^^^^ the trait `std::error::Error` is not implemented for `()` - | - = note: required for the cast from `Box<()>` to `Box<(dyn std::error::Error + 'static)>` - -error[E0277]: the trait bound `(): std::error::Error` is not satisfied - --> $DIR/coerce-issue-49593-box-never-windows.rs:23:49 - | -LL | /* *mut $0 is coerced to *mut Error here */ raw_ptr_box::<_ /* ! */>(x) - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ the trait `std::error::Error` is not implemented for `()` - | - = note: required for the cast from `*mut ()` to `*mut (dyn std::error::Error + 'static)` - -error: aborting due to 2 previous errors - -For more information about this error, try `rustc --explain E0277`. diff --git a/tests/ui/coercion/coerce-issue-49593-box-never-windows.rs b/tests/ui/coercion/coerce-issue-49593-box-never-windows.rs deleted file mode 100644 index b317841ab6e..00000000000 --- a/tests/ui/coercion/coerce-issue-49593-box-never-windows.rs +++ /dev/null @@ -1,58 +0,0 @@ -//@ revisions: nofallback fallback -//@ only-windows - the number of `Error` impls is platform-dependent -//@[fallback] check-pass -//@[nofallback] check-fail - -#![feature(never_type)] -#![cfg_attr(fallback, feature(never_type_fallback))] -#![allow(unreachable_code)] - -use std::error::Error; -use std::mem; - -fn raw_ptr_box<T>(t: T) -> *mut T { - panic!() -} - -fn foo(x: !) -> Box<dyn Error> { - /* *mut $0 is coerced to Box<dyn Error> here */ Box::<_ /* ! */>::new(x) - //[nofallback]~^ ERROR trait bound `(): std::error::Error` is not satisfied -} - -fn foo_raw_ptr(x: !) -> *mut dyn Error { - /* *mut $0 is coerced to *mut Error here */ raw_ptr_box::<_ /* ! */>(x) - //[nofallback]~^ ERROR trait bound `(): std::error::Error` is not satisfied -} - -fn no_coercion(d: *mut dyn Error) -> *mut dyn Error { - /* an unsize coercion won't compile here, and it is indeed not used - because there is nothing requiring the _ to be Sized */ - d as *mut _ -} - -trait Xyz {} -struct S; -struct T; -impl Xyz for S {} -impl Xyz for T {} - -fn foo_no_never() { - let mut x /* : Option<S> */ = None; - let mut first_iter = false; - loop { - if !first_iter { - let y: Box<dyn Xyz> - = /* Box<$0> is coerced to Box<Xyz> here */ Box::new(x.unwrap()); - } - - x = Some(S); - first_iter = true; - } - - let mut y : Option<S> = None; - // assert types are equal - mem::swap(&mut x, &mut y); -} - -fn main() { -} diff --git a/tests/ui/coercion/coerce-issue-49593-box-never.fallback.stderr b/tests/ui/coercion/coerce-issue-49593-box-never.fallback.stderr new file mode 100644 index 00000000000..ef5633f7134 --- /dev/null +++ b/tests/ui/coercion/coerce-issue-49593-box-never.fallback.stderr @@ -0,0 +1,11 @@ +error[E0277]: the trait bound `(): std::error::Error` is not satisfied + --> $DIR/coerce-issue-49593-box-never.rs:18:5 + | +LL | Box::<_ /* ! */>::new(x) + | ^^^^^^^^^^^^^^^^^^^^^^^^ the trait `std::error::Error` is not implemented for `()` + | + = note: required for the cast from `Box<()>` to `Box<(dyn std::error::Error + 'static)>` + +error: aborting due to 1 previous error + +For more information about this error, try `rustc --explain E0277`. diff --git a/tests/ui/coercion/coerce-issue-49593-box-never.nofallback.stderr b/tests/ui/coercion/coerce-issue-49593-box-never.nofallback.stderr index 0d98fa93e5a..7222af43b01 100644 --- a/tests/ui/coercion/coerce-issue-49593-box-never.nofallback.stderr +++ b/tests/ui/coercion/coerce-issue-49593-box-never.nofallback.stderr @@ -1,16 +1,16 @@ error[E0277]: the trait bound `(): std::error::Error` is not satisfied - --> $DIR/coerce-issue-49593-box-never.rs:18:53 + --> $DIR/coerce-issue-49593-box-never.rs:18:5 | -LL | /* *mut $0 is coerced to Box<dyn Error> here */ Box::<_ /* ! */>::new(x) - | ^^^^^^^^^^^^^^^^^^^^^^^^ the trait `std::error::Error` is not implemented for `()` +LL | Box::<_ /* ! */>::new(x) + | ^^^^^^^^^^^^^^^^^^^^^^^^ the trait `std::error::Error` is not implemented for `()` | = note: required for the cast from `Box<()>` to `Box<(dyn std::error::Error + 'static)>` error[E0277]: the trait bound `(): std::error::Error` is not satisfied - --> $DIR/coerce-issue-49593-box-never.rs:23:49 + --> $DIR/coerce-issue-49593-box-never.rs:24:5 | -LL | /* *mut $0 is coerced to *mut Error here */ raw_ptr_box::<_ /* ! */>(x) - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ the trait `std::error::Error` is not implemented for `()` +LL | raw_ptr_box::<_ /* ! */>(x) + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ the trait `std::error::Error` is not implemented for `()` | = note: required for the cast from `*mut ()` to `*mut (dyn std::error::Error + 'static)` diff --git a/tests/ui/coercion/coerce-issue-49593-box-never.rs b/tests/ui/coercion/coerce-issue-49593-box-never.rs index 19a2c036fbc..53071be47dc 100644 --- a/tests/ui/coercion/coerce-issue-49593-box-never.rs +++ b/tests/ui/coercion/coerce-issue-49593-box-never.rs @@ -1,7 +1,5 @@ //@ revisions: nofallback fallback -//@ ignore-windows - the number of `Error` impls is platform-dependent -//@[fallback] check-pass -//@[nofallback] check-fail +//@check-fail #![feature(never_type)] #![cfg_attr(fallback, feature(never_type_fallback))] @@ -15,18 +13,21 @@ fn raw_ptr_box<T>(t: T) -> *mut T { } fn foo(x: !) -> Box<dyn Error> { - /* *mut $0 is coerced to Box<dyn Error> here */ Box::<_ /* ! */>::new(x) - //[nofallback]~^ ERROR trait bound `(): std::error::Error` is not satisfied + // Subtyping during method resolution will generate new inference vars and + // subtype them. Thus fallback will not fall back to `!`, but `()` instead. + Box::<_ /* ! */>::new(x) + //~^ ERROR trait bound `(): std::error::Error` is not satisfied } fn foo_raw_ptr(x: !) -> *mut dyn Error { - /* *mut $0 is coerced to *mut Error here */ raw_ptr_box::<_ /* ! */>(x) + /* *mut $0 is coerced to *mut Error here */ + raw_ptr_box::<_ /* ! */>(x) //[nofallback]~^ ERROR trait bound `(): std::error::Error` is not satisfied } fn no_coercion(d: *mut dyn Error) -> *mut dyn Error { /* an unsize coercion won't compile here, and it is indeed not used - because there is nothing requiring the _ to be Sized */ + because there is nothing requiring the _ to be Sized */ d as *mut _ } @@ -49,10 +50,9 @@ fn foo_no_never() { first_iter = true; } - let mut y : Option<S> = None; + let mut y: Option<S> = None; // assert types are equal mem::swap(&mut x, &mut y); } -fn main() { -} +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 bd65cee58d9..4f15be4c7c8 100644 --- a/tests/ui/coherence/occurs-check/associated-type.next.stderr +++ b/tests/ui/coherence/occurs-check/associated-type.next.stderr @@ -1,7 +1,7 @@ - WARN rustc_infer::infer::relate::generalize may incompletely handle alias type: AliasTy { args: [*const ?1t, '^0.Named(DefId(0:27 ~ associated_type[f554]::{impl#3}::'a#1), "'a")], def_id: DefId(0:5 ~ associated_type[f554]::ToUnit::Unit), _use_alias_ty_new_instead: () } - WARN rustc_infer::infer::relate::generalize may incompletely handle alias type: AliasTy { args: [*const ?1t, '^0.Named(DefId(0:27 ~ associated_type[f554]::{impl#3}::'a#1), "'a")], def_id: DefId(0:5 ~ associated_type[f554]::ToUnit::Unit), _use_alias_ty_new_instead: () } - WARN rustc_infer::infer::relate::generalize may incompletely handle alias type: AliasTy { args: [*const ?1t, '^0.Named(DefId(0:27 ~ associated_type[f554]::{impl#3}::'a#1), "'a")], def_id: DefId(0:5 ~ associated_type[f554]::ToUnit::Unit), _use_alias_ty_new_instead: () } - WARN rustc_infer::infer::relate::generalize may incompletely handle alias type: AliasTy { args: [*const ?1t, '^0.Named(DefId(0:27 ~ associated_type[f554]::{impl#3}::'a#1), "'a")], def_id: DefId(0:5 ~ associated_type[f554]::ToUnit::Unit), _use_alias_ty_new_instead: () } + WARN rustc_infer::infer::relate::generalize may incompletely handle alias type: AliasTy { args: [*const ?1t, '^0.Named(DefId(0:27 ~ associated_type[f554]::{impl#3}::'a#1), "'a")], def_id: DefId(0:5 ~ associated_type[f554]::ToUnit::Unit) } + WARN rustc_infer::infer::relate::generalize may incompletely handle alias type: AliasTy { args: [*const ?1t, '^0.Named(DefId(0:27 ~ associated_type[f554]::{impl#3}::'a#1), "'a")], def_id: DefId(0:5 ~ associated_type[f554]::ToUnit::Unit) } + WARN rustc_infer::infer::relate::generalize may incompletely handle alias type: AliasTy { args: [*const ?1t, '^0.Named(DefId(0:27 ~ associated_type[f554]::{impl#3}::'a#1), "'a")], def_id: DefId(0:5 ~ associated_type[f554]::ToUnit::Unit) } + WARN rustc_infer::infer::relate::generalize may incompletely handle alias type: AliasTy { args: [*const ?1t, '^0.Named(DefId(0:27 ~ associated_type[f554]::{impl#3}::'a#1), "'a")], def_id: DefId(0:5 ~ associated_type[f554]::ToUnit::Unit) } error[E0119]: conflicting implementations of trait `Overlap<for<'a> fn(&'a (), ())>` for type `for<'a> fn(&'a (), ())` --> $DIR/associated-type.rs:31:1 | diff --git a/tests/ui/coherence/occurs-check/associated-type.old.stderr b/tests/ui/coherence/occurs-check/associated-type.old.stderr index d26f7665ee7..329086ab7df 100644 --- a/tests/ui/coherence/occurs-check/associated-type.old.stderr +++ b/tests/ui/coherence/occurs-check/associated-type.old.stderr @@ -1,11 +1,11 @@ - WARN rustc_infer::infer::relate::generalize may incompletely handle alias type: AliasTy { args: [*const ?1t, '^0.Named(DefId(0:27 ~ associated_type[f554]::{impl#3}::'a#1), "'a")], def_id: DefId(0:5 ~ associated_type[f554]::ToUnit::Unit), _use_alias_ty_new_instead: () } - WARN rustc_infer::infer::relate::generalize may incompletely handle alias type: AliasTy { args: [*const ?1t, !2_0.Named(DefId(0:27 ~ associated_type[f554]::{impl#3}::'a#1), "'a")], def_id: DefId(0:5 ~ associated_type[f554]::ToUnit::Unit), _use_alias_ty_new_instead: () } - WARN rustc_infer::infer::relate::generalize may incompletely handle alias type: AliasTy { args: [*const ?1t, '^0.Named(DefId(0:27 ~ associated_type[f554]::{impl#3}::'a#1), "'a")], def_id: DefId(0:5 ~ associated_type[f554]::ToUnit::Unit), _use_alias_ty_new_instead: () } - WARN rustc_infer::infer::relate::generalize may incompletely handle alias type: AliasTy { args: [*const ?1t, !2_0.Named(DefId(0:27 ~ associated_type[f554]::{impl#3}::'a#1), "'a")], def_id: DefId(0:5 ~ associated_type[f554]::ToUnit::Unit), _use_alias_ty_new_instead: () } - WARN rustc_infer::infer::relate::generalize may incompletely handle alias type: AliasTy { args: [*const ?1t, '^0.Named(DefId(0:27 ~ associated_type[f554]::{impl#3}::'a#1), "'a")], def_id: DefId(0:5 ~ associated_type[f554]::ToUnit::Unit), _use_alias_ty_new_instead: () } - WARN rustc_infer::infer::relate::generalize may incompletely handle alias type: AliasTy { args: [*const ?1t, !2_0.Named(DefId(0:27 ~ associated_type[f554]::{impl#3}::'a#1), "'a")], def_id: DefId(0:5 ~ associated_type[f554]::ToUnit::Unit), _use_alias_ty_new_instead: () } - WARN rustc_infer::infer::relate::generalize may incompletely handle alias type: AliasTy { args: [*const ?1t, '^0.Named(DefId(0:27 ~ associated_type[f554]::{impl#3}::'a#1), "'a")], def_id: DefId(0:5 ~ associated_type[f554]::ToUnit::Unit), _use_alias_ty_new_instead: () } - WARN rustc_infer::infer::relate::generalize may incompletely handle alias type: AliasTy { args: [*const ?1t, !2_0.Named(DefId(0:27 ~ associated_type[f554]::{impl#3}::'a#1), "'a")], def_id: DefId(0:5 ~ associated_type[f554]::ToUnit::Unit), _use_alias_ty_new_instead: () } + WARN rustc_infer::infer::relate::generalize may incompletely handle alias type: AliasTy { args: [*const ?1t, '^0.Named(DefId(0:27 ~ associated_type[f554]::{impl#3}::'a#1), "'a")], def_id: DefId(0:5 ~ associated_type[f554]::ToUnit::Unit) } + WARN rustc_infer::infer::relate::generalize may incompletely handle alias type: AliasTy { args: [*const ?1t, !2_0.Named(DefId(0:27 ~ associated_type[f554]::{impl#3}::'a#1), "'a")], def_id: DefId(0:5 ~ associated_type[f554]::ToUnit::Unit) } + WARN rustc_infer::infer::relate::generalize may incompletely handle alias type: AliasTy { args: [*const ?1t, '^0.Named(DefId(0:27 ~ associated_type[f554]::{impl#3}::'a#1), "'a")], def_id: DefId(0:5 ~ associated_type[f554]::ToUnit::Unit) } + WARN rustc_infer::infer::relate::generalize may incompletely handle alias type: AliasTy { args: [*const ?1t, !2_0.Named(DefId(0:27 ~ associated_type[f554]::{impl#3}::'a#1), "'a")], def_id: DefId(0:5 ~ associated_type[f554]::ToUnit::Unit) } + WARN rustc_infer::infer::relate::generalize may incompletely handle alias type: AliasTy { args: [*const ?1t, '^0.Named(DefId(0:27 ~ associated_type[f554]::{impl#3}::'a#1), "'a")], def_id: DefId(0:5 ~ associated_type[f554]::ToUnit::Unit) } + WARN rustc_infer::infer::relate::generalize may incompletely handle alias type: AliasTy { args: [*const ?1t, !2_0.Named(DefId(0:27 ~ associated_type[f554]::{impl#3}::'a#1), "'a")], def_id: DefId(0:5 ~ associated_type[f554]::ToUnit::Unit) } + WARN rustc_infer::infer::relate::generalize may incompletely handle alias type: AliasTy { args: [*const ?1t, '^0.Named(DefId(0:27 ~ associated_type[f554]::{impl#3}::'a#1), "'a")], def_id: DefId(0:5 ~ associated_type[f554]::ToUnit::Unit) } + WARN rustc_infer::infer::relate::generalize may incompletely handle alias type: AliasTy { args: [*const ?1t, !2_0.Named(DefId(0:27 ~ associated_type[f554]::{impl#3}::'a#1), "'a")], def_id: DefId(0:5 ~ associated_type[f554]::ToUnit::Unit) } error[E0119]: conflicting implementations of trait `Overlap<for<'a> fn(&'a (), _)>` for type `for<'a> fn(&'a (), _)` --> $DIR/associated-type.rs:31:1 | diff --git a/tests/ui/const-generics/generic_arg_infer/issue-91614.stderr b/tests/ui/const-generics/generic_arg_infer/issue-91614.stderr index 5ee42c19dd3..563406ad5ea 100644 --- a/tests/ui/const-generics/generic_arg_infer/issue-91614.stderr +++ b/tests/ui/const-generics/generic_arg_infer/issue-91614.stderr @@ -15,7 +15,7 @@ note: required by a bound in `Mask::<T, N>::splat` --> $SRC_DIR/core/src/../../portable-simd/crates/core_simd/src/masks.rs:LL:COL help: consider giving `y` an explicit type, where the type for type parameter `T` is specified | -LL | let y: Mask<_, N> = Mask::<_, _>::splat(false); +LL | let y: Mask<T, N> = Mask::<_, _>::splat(false); | ++++++++++++ error: aborting due to 1 previous error diff --git a/tests/ui/consts/assoc-const-elided-lifetime.stderr b/tests/ui/consts/assoc-const-elided-lifetime.stderr index a1eeaff4ba8..3e847298c35 100644 --- a/tests/ui/consts/assoc-const-elided-lifetime.stderr +++ b/tests/ui/consts/assoc-const-elided-lifetime.stderr @@ -6,6 +6,11 @@ LL | const FOO: Foo<'_> = Foo { x: PhantomData::<&()> }; | = 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 #115010 <https://github.com/rust-lang/rust/issues/115010> +note: cannot automatically infer `'static` because of other lifetimes in scope + --> $DIR/assoc-const-elided-lifetime.rs:9:6 + | +LL | impl<'a> Foo<'a> { + | ^^ note: the lint level is defined here --> $DIR/assoc-const-elided-lifetime.rs:1:9 | @@ -24,6 +29,13 @@ LL | const BAR: &() = &(); | = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! = note: for more information, see issue #115010 <https://github.com/rust-lang/rust/issues/115010> +note: cannot automatically infer `'static` because of other lifetimes in scope + --> $DIR/assoc-const-elided-lifetime.rs:9:6 + | +LL | impl<'a> Foo<'a> { + | ^^ +LL | const FOO: Foo<'_> = Foo { x: PhantomData::<&()> }; + | ^^ help: use the `'static` lifetime | LL | const BAR: &'static () = &(); diff --git a/tests/ui/consts/static-default-lifetime/elided-lifetime.rs b/tests/ui/consts/static-default-lifetime/elided-lifetime.rs new file mode 100644 index 00000000000..95d59f9b894 --- /dev/null +++ b/tests/ui/consts/static-default-lifetime/elided-lifetime.rs @@ -0,0 +1,22 @@ +#![deny(elided_lifetimes_in_associated_constant)] + +struct Foo<'a>(&'a ()); + +impl Foo<'_> { + const STATIC: &str = ""; + //~^ ERROR `&` without an explicit lifetime name cannot be used here + //~| WARN this was previously accepted by the compiler but is being phased out +} + +trait Bar { + const STATIC: &str; +} + +impl Bar for Foo<'_> { + const STATIC: &str = ""; + //~^ ERROR `&` without an explicit lifetime name cannot be used here + //~| WARN this was previously accepted by the compiler but is being phased out + //~| ERROR const not compatible with trait +} + +fn main() {} diff --git a/tests/ui/consts/static-default-lifetime/elided-lifetime.stderr b/tests/ui/consts/static-default-lifetime/elided-lifetime.stderr new file mode 100644 index 00000000000..d4fc1717538 --- /dev/null +++ b/tests/ui/consts/static-default-lifetime/elided-lifetime.stderr @@ -0,0 +1,59 @@ +error: `&` without an explicit lifetime name cannot be used here + --> $DIR/elided-lifetime.rs:6:19 + | +LL | const STATIC: &str = ""; + | ^ + | + = 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 #115010 <https://github.com/rust-lang/rust/issues/115010> +note: cannot automatically infer `'static` because of other lifetimes in scope + --> $DIR/elided-lifetime.rs:5:10 + | +LL | impl Foo<'_> { + | ^^ +note: the lint level is defined here + --> $DIR/elided-lifetime.rs:1:9 + | +LL | #![deny(elided_lifetimes_in_associated_constant)] + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +help: use the `'static` lifetime + | +LL | const STATIC: &'static str = ""; + | +++++++ + +error: `&` without an explicit lifetime name cannot be used here + --> $DIR/elided-lifetime.rs:16:19 + | +LL | const STATIC: &str = ""; + | ^ + | + = 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 #115010 <https://github.com/rust-lang/rust/issues/115010> +note: cannot automatically infer `'static` because of other lifetimes in scope + --> $DIR/elided-lifetime.rs:15:18 + | +LL | impl Bar for Foo<'_> { + | ^^ +help: use the `'static` lifetime + | +LL | const STATIC: &'static str = ""; + | +++++++ + +error[E0308]: const not compatible with trait + --> $DIR/elided-lifetime.rs:16:5 + | +LL | const STATIC: &str = ""; + | ^^^^^^^^^^^^^^^^^^ lifetime mismatch + | + = note: expected reference `&'static _` + found reference `&_` +note: the anonymous lifetime as defined here... + --> $DIR/elided-lifetime.rs:15:18 + | +LL | impl Bar for Foo<'_> { + | ^^ + = note: ...does not necessarily outlive the static lifetime + +error: aborting due to 3 previous errors + +For more information about this error, try `rustc --explain E0308`. diff --git a/tests/ui/consts/static-default-lifetime/generic-associated-const.rs b/tests/ui/consts/static-default-lifetime/generic-associated-const.rs new file mode 100644 index 00000000000..721920bd810 --- /dev/null +++ b/tests/ui/consts/static-default-lifetime/generic-associated-const.rs @@ -0,0 +1,19 @@ +#![deny(elided_lifetimes_in_associated_constant)] +#![feature(generic_const_items)] +//~^ WARN the feature `generic_const_items` is incomplete + +struct A; +impl A { + const GAC_TYPE<T>: &str = ""; + const GAC_LIFETIME<'a>: &str = ""; + //~^ ERROR `&` without an explicit lifetime name cannot be used here + //~| WARN this was previously accepted by the compiler but is being phased out +} + +trait Trait { + const GAC_TYPE<T>: &str = ""; + const GAC_LIFETIME<'a>: &str = ""; + //~^ ERROR missing lifetime specifier +} + +fn main() {} diff --git a/tests/ui/consts/static-default-lifetime/generic-associated-const.stderr b/tests/ui/consts/static-default-lifetime/generic-associated-const.stderr new file mode 100644 index 00000000000..2ecab3442a9 --- /dev/null +++ b/tests/ui/consts/static-default-lifetime/generic-associated-const.stderr @@ -0,0 +1,46 @@ +error[E0106]: missing lifetime specifier + --> $DIR/generic-associated-const.rs:15:29 + | +LL | const GAC_LIFETIME<'a>: &str = ""; + | ^ expected named lifetime parameter + | +help: consider using the `'a` lifetime + | +LL | const GAC_LIFETIME<'a>: &'a str = ""; + | ++ + +warning: the feature `generic_const_items` is incomplete and may not be safe to use and/or cause compiler crashes + --> $DIR/generic-associated-const.rs:2:12 + | +LL | #![feature(generic_const_items)] + | ^^^^^^^^^^^^^^^^^^^ + | + = note: see issue #113521 <https://github.com/rust-lang/rust/issues/113521> for more information + = note: `#[warn(incomplete_features)]` on by default + +error: `&` without an explicit lifetime name cannot be used here + --> $DIR/generic-associated-const.rs:8:29 + | +LL | const GAC_LIFETIME<'a>: &str = ""; + | ^ + | + = 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 #115010 <https://github.com/rust-lang/rust/issues/115010> +note: cannot automatically infer `'static` because of other lifetimes in scope + --> $DIR/generic-associated-const.rs:8:24 + | +LL | const GAC_LIFETIME<'a>: &str = ""; + | ^^ +note: the lint level is defined here + --> $DIR/generic-associated-const.rs:1:9 + | +LL | #![deny(elided_lifetimes_in_associated_constant)] + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +help: use the `'static` lifetime + | +LL | const GAC_LIFETIME<'a>: &'static str = ""; + | +++++++ + +error: aborting due to 2 previous errors; 1 warning emitted + +For more information about this error, try `rustc --explain E0106`. diff --git a/tests/ui/consts/static-default-lifetime/inner-item.rs b/tests/ui/consts/static-default-lifetime/inner-item.rs new file mode 100644 index 00000000000..061b240a40d --- /dev/null +++ b/tests/ui/consts/static-default-lifetime/inner-item.rs @@ -0,0 +1,21 @@ +//@ check-pass + +struct Foo<'a>(&'a ()); + +impl<'a> Foo<'a> { + fn hello(self) { + const INNER: &str = ""; + } +} + +impl Foo<'_> { + fn implicit(self) { + const INNER: &str = ""; + } + + fn fn_lifetime(&self) { + const INNER: &str = ""; + } +} + +fn main() {} diff --git a/tests/ui/consts/static-default-lifetime/static-trait-impl.rs b/tests/ui/consts/static-default-lifetime/static-trait-impl.rs new file mode 100644 index 00000000000..025fda4df58 --- /dev/null +++ b/tests/ui/consts/static-default-lifetime/static-trait-impl.rs @@ -0,0 +1,20 @@ +#![deny(elided_lifetimes_in_associated_constant)] + +trait Bar<'a> { + const STATIC: &'a str; +} + +struct A; +impl Bar<'_> for A { + const STATIC: &str = ""; + //~^ ERROR `&` without an explicit lifetime name cannot be used here + //~| WARN this was previously accepted by the compiler but is being phased out + //~| ERROR const not compatible with trait +} + +struct B; +impl Bar<'static> for B { + const STATIC: &str = ""; +} + +fn main() {} diff --git a/tests/ui/consts/static-default-lifetime/static-trait-impl.stderr b/tests/ui/consts/static-default-lifetime/static-trait-impl.stderr new file mode 100644 index 00000000000..8e4c27875ab --- /dev/null +++ b/tests/ui/consts/static-default-lifetime/static-trait-impl.stderr @@ -0,0 +1,45 @@ +error: `&` without an explicit lifetime name cannot be used here + --> $DIR/static-trait-impl.rs:9:19 + | +LL | const STATIC: &str = ""; + | ^ + | + = 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 #115010 <https://github.com/rust-lang/rust/issues/115010> +note: cannot automatically infer `'static` because of other lifetimes in scope + --> $DIR/static-trait-impl.rs:8:10 + | +LL | impl Bar<'_> for A { + | ^^ +note: the lint level is defined here + --> $DIR/static-trait-impl.rs:1:9 + | +LL | #![deny(elided_lifetimes_in_associated_constant)] + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +help: use the `'static` lifetime + | +LL | const STATIC: &'static str = ""; + | +++++++ + +error[E0308]: const not compatible with trait + --> $DIR/static-trait-impl.rs:9:5 + | +LL | const STATIC: &str = ""; + | ^^^^^^^^^^^^^^^^^^ lifetime mismatch + | + = note: expected reference `&_` + found reference `&_` +note: the anonymous lifetime as defined here... + --> $DIR/static-trait-impl.rs:8:10 + | +LL | impl Bar<'_> for A { + | ^^ +note: ...does not necessarily outlive the anonymous lifetime as defined here + --> $DIR/static-trait-impl.rs:8:10 + | +LL | impl Bar<'_> for A { + | ^^ + +error: aborting due to 2 previous errors + +For more information about this error, try `rustc --explain E0308`. diff --git a/tests/ui/coroutine/break-inside-coroutine-issue-124495.rs b/tests/ui/coroutine/break-inside-coroutine-issue-124495.rs index 5d93db56722..97c3d06c023 100644 --- a/tests/ui/coroutine/break-inside-coroutine-issue-124495.rs +++ b/tests/ui/coroutine/break-inside-coroutine-issue-124495.rs @@ -18,6 +18,7 @@ async gen fn async_gen_fn() { fn main() { let _ = async { break; }; //~ ERROR `break` inside `async` block + let _ = async || { break; }; //~ ERROR `break` inside `async` closure let _ = gen { break; }; //~ ERROR `break` inside `gen` block diff --git a/tests/ui/coroutine/break-inside-coroutine-issue-124495.stderr b/tests/ui/coroutine/break-inside-coroutine-issue-124495.stderr index a7f37fad35e..f030961b7ed 100644 --- a/tests/ui/coroutine/break-inside-coroutine-issue-124495.stderr +++ b/tests/ui/coroutine/break-inside-coroutine-issue-124495.stderr @@ -38,16 +38,16 @@ LL | let _ = async { break; }; | enclosing `async` block error[E0267]: `break` inside `async` closure - --> $DIR/break-inside-coroutine-issue-124495.rs:21:24 + --> $DIR/break-inside-coroutine-issue-124495.rs:22:24 | LL | let _ = async || { break; }; - | --^^^^^--- - | | | - | | cannot `break` inside `async` closure - | enclosing `async` closure + | -----------^^^^^--- + | | | + | | cannot `break` inside `async` closure + | enclosing `async` closure error[E0267]: `break` inside `gen` block - --> $DIR/break-inside-coroutine-issue-124495.rs:23:19 + --> $DIR/break-inside-coroutine-issue-124495.rs:24:19 | LL | let _ = gen { break; }; | ------^^^^^--- @@ -56,7 +56,7 @@ LL | let _ = gen { break; }; | enclosing `gen` block error[E0267]: `break` inside `async gen` block - --> $DIR/break-inside-coroutine-issue-124495.rs:25:25 + --> $DIR/break-inside-coroutine-issue-124495.rs:26:25 | LL | let _ = async gen { break; }; | ------------^^^^^--- diff --git a/tests/ui/coverage-attr/bad-syntax.rs b/tests/ui/coverage-attr/bad-syntax.rs new file mode 100644 index 00000000000..8783714992b --- /dev/null +++ b/tests/ui/coverage-attr/bad-syntax.rs @@ -0,0 +1,58 @@ +#![feature(coverage_attribute)] + +// Tests the error messages produced (or not produced) by various unusual +// uses of the `#[coverage(..)]` attribute. + +// FIXME(#84605): Multiple coverage attributes with the same value are useless, +// and should probably produce a diagnostic. +#[coverage(off)] +#[coverage(off)] +fn multiple_consistent() {} + +// FIXME(#84605): When there are multiple inconsistent coverage attributes, +// it's unclear which one will prevail. +#[coverage(off)] +#[coverage(on)] +fn multiple_inconsistent() {} + +#[coverage] //~ ERROR expected `coverage(off)` or `coverage(on)` +fn bare_word() {} + +// FIXME(#84605): This shows as multiple different errors, one of which suggests +// writing bare `#[coverage]`, which is not allowed. +#[coverage = true] +//~^ ERROR expected `coverage(off)` or `coverage(on)` +//~| ERROR malformed `coverage` attribute input +//~| HELP the following are the possible correct uses +//~| SUGGESTION #[coverage(on|off)] +fn key_value() {} + +#[coverage()] //~ ERROR expected `coverage(off)` or `coverage(on)` +fn list_empty() {} + +#[coverage(off, off)] //~ ERROR expected `coverage(off)` or `coverage(on)` +fn list_consistent() {} + +#[coverage(off, on)] //~ ERROR expected `coverage(off)` or `coverage(on)` +fn list_inconsistent() {} + +#[coverage(bogus)] //~ ERROR expected `coverage(off)` or `coverage(on)` +fn bogus_word() {} + +#[coverage(bogus, off)] //~ ERROR expected `coverage(off)` or `coverage(on)` +fn bogus_word_before() {} + +#[coverage(off, bogus)] //~ ERROR expected `coverage(off)` or `coverage(on)` +fn bogus_word_after() {} + +#[coverage(off,)] +fn comma_after() {} + +// FIXME(#84605): This shows as multiple different errors. +#[coverage(,off)] +//~^ ERROR expected identifier, found `,` +//~| HELP remove this comma +//~| ERROR expected `coverage(off)` or `coverage(on)` +fn comma_before() {} + +fn main() {} diff --git a/tests/ui/coverage-attr/bad-syntax.stderr b/tests/ui/coverage-attr/bad-syntax.stderr new file mode 100644 index 00000000000..f6181d12a94 --- /dev/null +++ b/tests/ui/coverage-attr/bad-syntax.stderr @@ -0,0 +1,78 @@ +error: malformed `coverage` attribute input + --> $DIR/bad-syntax.rs:23:1 + | +LL | #[coverage = true] + | ^^^^^^^^^^^^^^^^^^ + | +help: the following are the possible correct uses + | +LL | #[coverage(on|off)] + | +LL | #[coverage] + | + +error: expected identifier, found `,` + --> $DIR/bad-syntax.rs:52:12 + | +LL | #[coverage(,off)] + | ^ + | | + | expected identifier + | help: remove this comma + +error: expected `coverage(off)` or `coverage(on)` + --> $DIR/bad-syntax.rs:18:1 + | +LL | #[coverage] + | ^^^^^^^^^^^ + +error: expected `coverage(off)` or `coverage(on)` + --> $DIR/bad-syntax.rs:23:1 + | +LL | #[coverage = true] + | ^^^^^^^^^^^^^^^^^^ + +error: expected `coverage(off)` or `coverage(on)` + --> $DIR/bad-syntax.rs:30:1 + | +LL | #[coverage()] + | ^^^^^^^^^^^^^ + +error: expected `coverage(off)` or `coverage(on)` + --> $DIR/bad-syntax.rs:33:1 + | +LL | #[coverage(off, off)] + | ^^^^^^^^^^^^^^^^^^^^^ + +error: expected `coverage(off)` or `coverage(on)` + --> $DIR/bad-syntax.rs:36:1 + | +LL | #[coverage(off, on)] + | ^^^^^^^^^^^^^^^^^^^^ + +error: expected `coverage(off)` or `coverage(on)` + --> $DIR/bad-syntax.rs:39:1 + | +LL | #[coverage(bogus)] + | ^^^^^^^^^^^^^^^^^^ + +error: expected `coverage(off)` or `coverage(on)` + --> $DIR/bad-syntax.rs:42:1 + | +LL | #[coverage(bogus, off)] + | ^^^^^^^^^^^^^^^^^^^^^^^ + +error: expected `coverage(off)` or `coverage(on)` + --> $DIR/bad-syntax.rs:45:1 + | +LL | #[coverage(off, bogus)] + | ^^^^^^^^^^^^^^^^^^^^^^^ + +error: expected `coverage(off)` or `coverage(on)` + --> $DIR/bad-syntax.rs:52:1 + | +LL | #[coverage(,off)] + | ^^^^^^^^^^^^^^^^^ + +error: aborting due to 11 previous errors + diff --git a/tests/ui/lint/no-coverage.rs b/tests/ui/coverage-attr/no-coverage.rs index 907d25d333e..907d25d333e 100644 --- a/tests/ui/lint/no-coverage.rs +++ b/tests/ui/coverage-attr/no-coverage.rs diff --git a/tests/ui/lint/no-coverage.stderr b/tests/ui/coverage-attr/no-coverage.stderr index a87b0fb49f0..a87b0fb49f0 100644 --- a/tests/ui/lint/no-coverage.stderr +++ b/tests/ui/coverage-attr/no-coverage.stderr diff --git a/tests/ui/delegation/body-identity-glob.rs b/tests/ui/delegation/body-identity-glob.rs new file mode 100644 index 00000000000..58b644f46d6 --- /dev/null +++ b/tests/ui/delegation/body-identity-glob.rs @@ -0,0 +1,32 @@ +//@ check-pass + +#![feature(fn_delegation)] +#![allow(incomplete_features)] + +trait Trait { + fn foo(&self) {} + fn bar(&self) {} +} + +impl Trait for u8 {} + +struct S(u8); + +mod to_import { + pub fn check(arg: &u8) -> &u8 { arg } +} + +impl Trait for S { + reuse Trait::* { + use to_import::check; + + let _arr = Some(self.0).map(|x| [x * 2; 3]); + check(&self.0) + } +} + +fn main() { + let s = S(0); + s.foo(); + s.bar(); +} diff --git a/tests/ui/delegation/empty-glob.rs b/tests/ui/delegation/empty-glob.rs new file mode 100644 index 00000000000..d98579d8972 --- /dev/null +++ b/tests/ui/delegation/empty-glob.rs @@ -0,0 +1,11 @@ +#![feature(fn_delegation)] +#![allow(incomplete_features)] + +trait Trait {} + +struct S; +impl S { + reuse Trait::*; //~ ERROR empty glob delegation is not supported +} + +fn main() {} diff --git a/tests/ui/delegation/empty-glob.stderr b/tests/ui/delegation/empty-glob.stderr new file mode 100644 index 00000000000..f4d282f6a0f --- /dev/null +++ b/tests/ui/delegation/empty-glob.stderr @@ -0,0 +1,8 @@ +error: empty glob delegation is not supported + --> $DIR/empty-glob.rs:8:5 + | +LL | reuse Trait::*; + | ^^^^^^^^^^^^^^^ + +error: aborting due to 1 previous error + diff --git a/tests/ui/delegation/glob-bad-path.rs b/tests/ui/delegation/glob-bad-path.rs new file mode 100644 index 00000000000..7bc4f0153a3 --- /dev/null +++ b/tests/ui/delegation/glob-bad-path.rs @@ -0,0 +1,12 @@ +#![feature(fn_delegation)] +#![allow(incomplete_features)] + +trait Trait {} +struct S; + +impl Trait for u8 { + reuse unresolved::*; //~ ERROR failed to resolve: use of undeclared crate or module `unresolved` + reuse S::*; //~ ERROR expected trait, found struct `S` +} + +fn main() {} diff --git a/tests/ui/delegation/glob-bad-path.stderr b/tests/ui/delegation/glob-bad-path.stderr new file mode 100644 index 00000000000..0c06364b3f0 --- /dev/null +++ b/tests/ui/delegation/glob-bad-path.stderr @@ -0,0 +1,15 @@ +error: expected trait, found struct `S` + --> $DIR/glob-bad-path.rs:9:11 + | +LL | reuse S::*; + | ^ not a trait + +error[E0433]: failed to resolve: use of undeclared crate or module `unresolved` + --> $DIR/glob-bad-path.rs:8:11 + | +LL | reuse unresolved::*; + | ^^^^^^^^^^ use of undeclared crate or module `unresolved` + +error: aborting due to 2 previous errors + +For more information about this error, try `rustc --explain E0433`. diff --git a/tests/ui/delegation/glob-glob-conflict.rs b/tests/ui/delegation/glob-glob-conflict.rs new file mode 100644 index 00000000000..2843bf8c493 --- /dev/null +++ b/tests/ui/delegation/glob-glob-conflict.rs @@ -0,0 +1,33 @@ +#![feature(fn_delegation)] +#![allow(incomplete_features)] + +trait Trait1 { + fn method(&self) -> u8; +} +trait Trait2 { + fn method(&self) -> u8; +} +trait Trait { + fn method(&self) -> u8; +} + +impl Trait1 for u8 { + fn method(&self) -> u8 { 0 } +} +impl Trait1 for u16 { + fn method(&self) -> u8 { 1 } +} +impl Trait2 for u8 { + fn method(&self) -> u8 { 2 } +} + +impl Trait for u8 { + reuse Trait1::*; + reuse Trait2::*; //~ ERROR duplicate definitions with name `method` +} +impl Trait for u16 { + reuse Trait1::*; + reuse Trait1::*; //~ ERROR duplicate definitions with name `method` +} + +fn main() {} diff --git a/tests/ui/delegation/glob-glob-conflict.stderr b/tests/ui/delegation/glob-glob-conflict.stderr new file mode 100644 index 00000000000..8c7e5a4b023 --- /dev/null +++ b/tests/ui/delegation/glob-glob-conflict.stderr @@ -0,0 +1,25 @@ +error[E0201]: duplicate definitions with name `method`: + --> $DIR/glob-glob-conflict.rs:26:5 + | +LL | fn method(&self) -> u8; + | ----------------------- item in trait +... +LL | reuse Trait1::*; + | ---------------- previous definition here +LL | reuse Trait2::*; + | ^^^^^^^^^^^^^^^^ duplicate definition + +error[E0201]: duplicate definitions with name `method`: + --> $DIR/glob-glob-conflict.rs:30:5 + | +LL | fn method(&self) -> u8; + | ----------------------- item in trait +... +LL | reuse Trait1::*; + | ---------------- previous definition here +LL | reuse Trait1::*; + | ^^^^^^^^^^^^^^^^ duplicate definition + +error: aborting due to 2 previous errors + +For more information about this error, try `rustc --explain E0201`. diff --git a/tests/ui/delegation/glob-glob.rs b/tests/ui/delegation/glob-glob.rs new file mode 100644 index 00000000000..ef7f9a15e19 --- /dev/null +++ b/tests/ui/delegation/glob-glob.rs @@ -0,0 +1,36 @@ +//@ check-pass + +#![feature(fn_delegation)] +#![allow(incomplete_features)] + +mod inner { + pub trait TraitFoo { + fn foo(&self) -> u8; + } + pub trait TraitBar { + fn bar(&self) -> u8; + } + + impl TraitFoo for u8 { + fn foo(&self) -> u8 { 0 } + } + impl TraitBar for u8 { + fn bar(&self) -> u8 { 1 } + } +} + +trait Trait { + fn foo(&self) -> u8; + fn bar(&self) -> u8; +} + +impl Trait for u8 { + reuse inner::TraitFoo::*; + reuse inner::TraitBar::*; +} + +fn main() { + let u = 0u8; + u.foo(); + u.bar(); +} diff --git a/tests/ui/delegation/glob-non-fn.rs b/tests/ui/delegation/glob-non-fn.rs new file mode 100644 index 00000000000..ab312d51f49 --- /dev/null +++ b/tests/ui/delegation/glob-non-fn.rs @@ -0,0 +1,38 @@ +#![feature(fn_delegation)] +#![allow(incomplete_features)] + +trait Trait { + fn method(&self); + const CONST: u8; + type Type; + #[allow(non_camel_case_types)] + type method; +} + +impl Trait for u8 { + fn method(&self) {} + const CONST: u8 = 0; + type Type = u8; + type method = u8; +} + +struct Good(u8); +impl Trait for Good { + reuse Trait::* { &self.0 } + // Explicit definitions for non-delegatable items. + const CONST: u8 = 0; + type Type = u8; + type method = u8; +} + +struct Bad(u8); +impl Trait for Bad { //~ ERROR not all trait items implemented, missing: `CONST`, `Type`, `method` + reuse Trait::* { &self.0 } + //~^ ERROR item `CONST` is an associated method, which doesn't match its trait `Trait` + //~| ERROR item `Type` is an associated method, which doesn't match its trait `Trait` + //~| ERROR duplicate definitions with name `method` + //~| ERROR expected function, found associated constant `Trait::CONST` + //~| ERROR expected function, found associated type `Trait::Type` +} + +fn main() {} diff --git a/tests/ui/delegation/glob-non-fn.stderr b/tests/ui/delegation/glob-non-fn.stderr new file mode 100644 index 00000000000..4b918c53b84 --- /dev/null +++ b/tests/ui/delegation/glob-non-fn.stderr @@ -0,0 +1,62 @@ +error[E0324]: item `CONST` is an associated method, which doesn't match its trait `Trait` + --> $DIR/glob-non-fn.rs:30:5 + | +LL | const CONST: u8; + | ---------------- item in trait +... +LL | reuse Trait::* { &self.0 } + | ^^^^^^^^^^^^^^^^^^^^^^^^^^ does not match trait + +error[E0324]: item `Type` is an associated method, which doesn't match its trait `Trait` + --> $DIR/glob-non-fn.rs:30:5 + | +LL | type Type; + | ---------- item in trait +... +LL | reuse Trait::* { &self.0 } + | ^^^^^^^^^^^^^^^^^^^^^^^^^^ does not match trait + +error[E0201]: duplicate definitions with name `method`: + --> $DIR/glob-non-fn.rs:30:5 + | +LL | fn method(&self); + | ----------------- item in trait +... +LL | reuse Trait::* { &self.0 } + | ^^^^^^^^^^^^^^^^^^^^^^^^^^ + | | + | duplicate definition + | previous definition here + +error[E0423]: expected function, found associated constant `Trait::CONST` + --> $DIR/glob-non-fn.rs:30:11 + | +LL | reuse Trait::* { &self.0 } + | ^^^^^ not a function + +error[E0423]: expected function, found associated type `Trait::Type` + --> $DIR/glob-non-fn.rs:30:11 + | +LL | reuse Trait::* { &self.0 } + | ^^^^^ + | + = note: can't use a type alias as a constructor + +error[E0046]: not all trait items implemented, missing: `CONST`, `Type`, `method` + --> $DIR/glob-non-fn.rs:29:1 + | +LL | const CONST: u8; + | --------------- `CONST` from trait +LL | type Type; + | --------- `Type` from trait +LL | #[allow(non_camel_case_types)] +LL | type method; + | ----------- `method` from trait +... +LL | impl Trait for Bad { + | ^^^^^^^^^^^^^^^^^^ missing `CONST`, `Type`, `method` in implementation + +error: aborting due to 6 previous errors + +Some errors have detailed explanations: E0046, E0201, E0324, E0423. +For more information about an error, try `rustc --explain E0046`. diff --git a/tests/ui/delegation/glob-non-impl.rs b/tests/ui/delegation/glob-non-impl.rs new file mode 100644 index 00000000000..d523731eeb3 --- /dev/null +++ b/tests/ui/delegation/glob-non-impl.rs @@ -0,0 +1,20 @@ +#![feature(fn_delegation)] +#![allow(incomplete_features)] + +trait Trait { + fn method() {} +} + +reuse Trait::*; //~ ERROR glob delegation is only supported in impls + +trait OtherTrait { + reuse Trait::*; //~ ERROR glob delegation is only supported in impls +} + +extern { + reuse Trait::*; //~ ERROR delegation is not supported in `extern` blocks +} + +fn main() { + reuse Trait::*; //~ ERROR glob delegation is only supported in impls +} diff --git a/tests/ui/delegation/glob-non-impl.stderr b/tests/ui/delegation/glob-non-impl.stderr new file mode 100644 index 00000000000..ea458fd5e90 --- /dev/null +++ b/tests/ui/delegation/glob-non-impl.stderr @@ -0,0 +1,26 @@ +error: delegation is not supported in `extern` blocks + --> $DIR/glob-non-impl.rs:15:5 + | +LL | reuse Trait::*; + | ^^^^^^^^^^^^^^^ + +error: glob delegation is only supported in impls + --> $DIR/glob-non-impl.rs:8:1 + | +LL | reuse Trait::*; + | ^^^^^^^^^^^^^^^ + +error: glob delegation is only supported in impls + --> $DIR/glob-non-impl.rs:11:5 + | +LL | reuse Trait::*; + | ^^^^^^^^^^^^^^^ + +error: glob delegation is only supported in impls + --> $DIR/glob-non-impl.rs:19:5 + | +LL | reuse Trait::*; + | ^^^^^^^^^^^^^^^ + +error: aborting due to 4 previous errors + diff --git a/tests/ui/delegation/glob-override.rs b/tests/ui/delegation/glob-override.rs new file mode 100644 index 00000000000..1d0dcf1df6e --- /dev/null +++ b/tests/ui/delegation/glob-override.rs @@ -0,0 +1,37 @@ +//@ check-pass + +#![feature(fn_delegation)] +#![allow(incomplete_features)] + +trait Trait { + fn foo(&self) -> u8; + fn bar(&self) -> u8; +} + +impl Trait for u8 { + fn foo(&self) -> u8 { 0 } + fn bar(&self) -> u8 { 1 } +} + +struct S(u8); +struct Z(u8); + +impl Trait for S { + reuse Trait::* { &self.0 } + fn bar(&self) -> u8 { 2 } +} + +impl Trait for Z { + reuse Trait::* { &self.0 } + reuse Trait::bar { &self.0 } +} + +fn main() { + let s = S(2); + s.foo(); + s.bar(); + + let z = Z(2); + z.foo(); + z.bar(); +} diff --git a/tests/ui/delegation/glob.rs b/tests/ui/delegation/glob.rs new file mode 100644 index 00000000000..5bc80c16648 --- /dev/null +++ b/tests/ui/delegation/glob.rs @@ -0,0 +1,35 @@ +//@ check-pass + +#![feature(fn_delegation)] +#![allow(incomplete_features)] + +trait Trait { + fn foo(&self) -> u8; + fn bar(&self) -> u8; +} + +impl Trait for u8 { + fn foo(&self) -> u8 { 0 } + fn bar(&self) -> u8 { 1 } +} + +struct S(u8); +struct Z(u8); + +impl Trait for S { + reuse Trait::* { &self.0 } +} + +impl Trait for Z { + reuse <u8 as Trait>::* { &self.0 } +} + +fn main() { + let s = S(2); + s.foo(); + s.bar(); + + let z = Z(3); + z.foo(); + z.bar(); +} diff --git a/tests/ui/delegation/macro-inside-glob.rs b/tests/ui/delegation/macro-inside-glob.rs new file mode 100644 index 00000000000..1d529341c5b --- /dev/null +++ b/tests/ui/delegation/macro-inside-glob.rs @@ -0,0 +1,26 @@ +//@ check-pass + +#![feature(fn_delegation)] +#![allow(incomplete_features)] + +trait Trait { + fn foo(&self) -> u8 { 0 } + fn bar(&self) -> u8 { 1 } +} + +impl Trait for u8 {} + +struct S(u8); + +// Macro expansion works inside delegation items. +macro_rules! u8 { () => { u8 } } +macro_rules! self_0 { ($self:ident) => { &$self.0 } } +impl Trait for S { + reuse <u8!() as Trait>::* { self_0!(self) } +} + +fn main() { + let s = S(2); + s.foo(); + s.bar(); +} diff --git a/tests/ui/drop/auxiliary/edition-2021-macros.rs b/tests/ui/drop/auxiliary/edition-2021-macros.rs new file mode 100644 index 00000000000..8a6444f8614 --- /dev/null +++ b/tests/ui/drop/auxiliary/edition-2021-macros.rs @@ -0,0 +1,8 @@ +//@ edition:2021 + +#[macro_export] +macro_rules! edition_2021_block { + ($($c:tt)*) => { + { $($c)* } + } +} diff --git a/tests/ui/drop/auxiliary/edition-2024-macros.rs b/tests/ui/drop/auxiliary/edition-2024-macros.rs new file mode 100644 index 00000000000..236340bfed4 --- /dev/null +++ b/tests/ui/drop/auxiliary/edition-2024-macros.rs @@ -0,0 +1,9 @@ +//@ edition:2024 +//@ compile-flags: -Zunstable-options + +#[macro_export] +macro_rules! edition_2024_block { + ($($c:tt)*) => { + { $($c)* } + } +} diff --git a/tests/ui/drop/tail-expr-drop-order-negative.edition2024.stderr b/tests/ui/drop/tail-expr-drop-order-negative.edition2024.stderr new file mode 100644 index 00000000000..75fc34e409b --- /dev/null +++ b/tests/ui/drop/tail-expr-drop-order-negative.edition2024.stderr @@ -0,0 +1,16 @@ +error[E0716]: temporary value dropped while borrowed + --> $DIR/tail-expr-drop-order-negative.rs:11:15 + | +LL | x.replace(std::cell::RefCell::new(123).borrow()).is_some() + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - temporary value is freed at the end of this statement + | | + | creates a temporary value which is freed while still in use +LL | +LL | } + | - borrow might be used here, when `x` is dropped and runs the destructor for type `Option<Ref<'_, i32>>` + | + = note: consider using a `let` binding to create a longer lived value + +error: aborting due to 1 previous error + +For more information about this error, try `rustc --explain E0716`. diff --git a/tests/ui/drop/tail-expr-drop-order-negative.rs b/tests/ui/drop/tail-expr-drop-order-negative.rs new file mode 100644 index 00000000000..c570b3a1ee2 --- /dev/null +++ b/tests/ui/drop/tail-expr-drop-order-negative.rs @@ -0,0 +1,17 @@ +//@ revisions: edition2021 edition2024 +//@ [edition2024] compile-flags: -Zunstable-options +//@ [edition2024] edition: 2024 +//@ [edition2021] check-pass + +#![feature(shorter_tail_lifetimes)] + +fn why_would_you_do_this() -> bool { + let mut x = None; + // Make a temporary `RefCell` and put a `Ref` that borrows it in `x`. + x.replace(std::cell::RefCell::new(123).borrow()).is_some() + //[edition2024]~^ ERROR: temporary value dropped while borrowed +} + +fn main() { + why_would_you_do_this(); +} diff --git a/tests/ui/drop/tail-expr-drop-order.rs b/tests/ui/drop/tail-expr-drop-order.rs new file mode 100644 index 00000000000..5d87f980b15 --- /dev/null +++ b/tests/ui/drop/tail-expr-drop-order.rs @@ -0,0 +1,108 @@ +//@ aux-build:edition-2021-macros.rs +//@ aux-build:edition-2024-macros.rs +//@ compile-flags: -Z validate-mir -Zunstable-options +//@ edition: 2024 +//@ run-pass + +#![feature(shorter_tail_lifetimes)] +#![allow(unused_imports)] +#![allow(dead_code)] +#![allow(unused_variables)] + +#[macro_use] +extern crate edition_2021_macros; +#[macro_use] +extern crate edition_2024_macros; +use std::cell::RefCell; +use std::convert::TryInto; + +#[derive(Default)] +struct DropOrderCollector(RefCell<Vec<u32>>); + +struct LoudDrop<'a>(&'a DropOrderCollector, u32); + +impl Drop for LoudDrop<'_> { + fn drop(&mut self) { + println!("{}", self.1); + self.0.0.borrow_mut().push(self.1); + } +} + +impl DropOrderCollector { + fn option_loud_drop(&self, n: u32) -> Option<LoudDrop> { + Some(LoudDrop(self, n)) + } + + fn loud_drop(&self, n: u32) -> LoudDrop { + LoudDrop(self, n) + } + + fn assert_sorted(&self, expected: usize) { + let result = self.0.borrow(); + assert_eq!(result.len(), expected); + for i in 1..result.len() { + assert!( + result[i - 1] < result[i], + "inversion at {} ({} followed by {})", + i - 1, + result[i - 1], + result[i] + ); + } + } +} + +fn edition_2021_around_2021() { + let c = DropOrderCollector::default(); + let _ = edition_2021_block! { + let a = c.loud_drop(1); + edition_2021_block! { + let b = c.loud_drop(0); + c.loud_drop(2).1 + } + }; + c.assert_sorted(3); +} + +fn edition_2021_around_2024() { + let c = DropOrderCollector::default(); + let _ = edition_2021_block! { + let a = c.loud_drop(2); + edition_2024_block! { + let b = c.loud_drop(1); + c.loud_drop(0).1 + } + }; + c.assert_sorted(3); +} + +fn edition_2024_around_2021() { + let c = DropOrderCollector::default(); + let _ = edition_2024_block! { + let a = c.loud_drop(2); + edition_2021_block! { + let b = c.loud_drop(0); + c.loud_drop(1).1 + } + }; + c.assert_sorted(3); +} + +fn edition_2024_around_2024() { + let c = DropOrderCollector::default(); + let _ = edition_2024_block! { + let a = c.loud_drop(2); + edition_2024_block! { + let b = c.loud_drop(1); + c.loud_drop(0).1 + } + }; + c.assert_sorted(3); +} + +fn main() { + edition_2021_around_2021(); + edition_2021_around_2024(); + edition_2024_around_2021(); + edition_2024_around_2024(); +} diff --git a/tests/ui/feature-gates/feature-gate-precise-capturing.rs b/tests/ui/feature-gates/feature-gate-precise-capturing.rs index 0c3b4977623..47a21539d37 100644 --- a/tests/ui/feature-gates/feature-gate-precise-capturing.rs +++ b/tests/ui/feature-gates/feature-gate-precise-capturing.rs @@ -1,4 +1,4 @@ -fn hello() -> impl use<> Sized {} +fn hello() -> impl Sized + use<> {} //~^ ERROR precise captures on `impl Trait` are experimental fn main() {} diff --git a/tests/ui/feature-gates/feature-gate-precise-capturing.stderr b/tests/ui/feature-gates/feature-gate-precise-capturing.stderr index 102b39148f9..04365408880 100644 --- a/tests/ui/feature-gates/feature-gate-precise-capturing.stderr +++ b/tests/ui/feature-gates/feature-gate-precise-capturing.stderr @@ -1,8 +1,8 @@ error[E0658]: precise captures on `impl Trait` are experimental - --> $DIR/feature-gate-precise-capturing.rs:1:20 + --> $DIR/feature-gate-precise-capturing.rs:1:28 | -LL | fn hello() -> impl use<> Sized {} - | ^^^ +LL | fn hello() -> impl Sized + use<> {} + | ^^^ | = note: see issue #123432 <https://github.com/rust-lang/rust/issues/123432> for more information = help: add `#![feature(precise_capturing)]` to the crate attributes to enable diff --git a/tests/ui/feature-gates/feature-gate-shorter_tail_lifetimes.rs b/tests/ui/feature-gates/feature-gate-shorter_tail_lifetimes.rs new file mode 100644 index 00000000000..5292c44bb2d --- /dev/null +++ b/tests/ui/feature-gates/feature-gate-shorter_tail_lifetimes.rs @@ -0,0 +1,8 @@ +fn f() -> usize { + let c = std::cell::RefCell::new(".."); + c.borrow().len() //~ ERROR: `c` does not live long enough +} + +fn main() { + let _ = f(); +} diff --git a/tests/ui/feature-gates/feature-gate-shorter_tail_lifetimes.stderr b/tests/ui/feature-gates/feature-gate-shorter_tail_lifetimes.stderr new file mode 100644 index 00000000000..648c3d5daa1 --- /dev/null +++ b/tests/ui/feature-gates/feature-gate-shorter_tail_lifetimes.stderr @@ -0,0 +1,26 @@ +error[E0597]: `c` does not live long enough + --> $DIR/feature-gate-shorter_tail_lifetimes.rs:3:5 + | +LL | let c = std::cell::RefCell::new(".."); + | - binding `c` declared here +LL | c.borrow().len() + | ^--------- + | | + | borrowed value does not live long enough + | a temporary with access to the borrow is created here ... +LL | } + | - + | | + | `c` dropped here while still borrowed + | ... and the borrow might be used here, when that temporary is dropped and runs the destructor for type `Ref<'_, &str>` + | + = note: the temporary is part of an expression at the end of a block; + consider forcing this temporary to be dropped sooner, before the block's local variables are dropped +help: for example, you could save the expression's value in a new local variable `x` and then make `x` be the expression at the end of the block + | +LL | let x = c.borrow().len(); x + | +++++++ +++ + +error: aborting due to 1 previous error + +For more information about this error, try `rustc --explain E0597`. diff --git a/tests/ui/higher-ranked/structually-relate-aliases.stderr b/tests/ui/higher-ranked/structually-relate-aliases.stderr index e1cffa0fc37..2f1dfd19c48 100644 --- a/tests/ui/higher-ranked/structually-relate-aliases.stderr +++ b/tests/ui/higher-ranked/structually-relate-aliases.stderr @@ -1,5 +1,5 @@ - WARN rustc_infer::infer::relate::generalize may incompletely handle alias type: AliasTy { args: [?1t, '^0.Named(DefId(0:15 ~ structually_relate_aliases[de75]::{impl#1}::'a), "'a")], def_id: DefId(0:5 ~ structually_relate_aliases[de75]::ToUnit::Unit), _use_alias_ty_new_instead: () } - WARN rustc_infer::infer::relate::generalize may incompletely handle alias type: AliasTy { args: [?1t, !2_0.Named(DefId(0:15 ~ structually_relate_aliases[de75]::{impl#1}::'a), "'a")], def_id: DefId(0:5 ~ structually_relate_aliases[de75]::ToUnit::Unit), _use_alias_ty_new_instead: () } + WARN rustc_infer::infer::relate::generalize may incompletely handle alias type: AliasTy { args: [?1t, '^0.Named(DefId(0:15 ~ structually_relate_aliases[de75]::{impl#1}::'a), "'a")], def_id: DefId(0:5 ~ structually_relate_aliases[de75]::ToUnit::Unit) } + WARN rustc_infer::infer::relate::generalize may incompletely handle alias type: AliasTy { args: [?1t, !2_0.Named(DefId(0:15 ~ structually_relate_aliases[de75]::{impl#1}::'a), "'a")], def_id: DefId(0:5 ~ structually_relate_aliases[de75]::ToUnit::Unit) } error[E0277]: the trait bound `for<'a> T: ToUnit<'a>` is not satisfied --> $DIR/structually-relate-aliases.rs:13:36 | diff --git a/tests/ui/impl-trait/call_method_ambiguous.next.stderr b/tests/ui/impl-trait/call_method_ambiguous.next.stderr index cd222aa7ae9..a1f9a8b40a8 100644 --- a/tests/ui/impl-trait/call_method_ambiguous.next.stderr +++ b/tests/ui/impl-trait/call_method_ambiguous.next.stderr @@ -1,5 +1,5 @@ error[E0282]: type annotations needed - --> $DIR/call_method_ambiguous.rs:29:13 + --> $DIR/call_method_ambiguous.rs:28:13 | LL | let mut iter = foo(n - 1, m); | ^^^^^^^^ diff --git a/tests/ui/impl-trait/call_method_ambiguous.rs b/tests/ui/impl-trait/call_method_ambiguous.rs index c26c01e002d..4dac605d6b8 100644 --- a/tests/ui/impl-trait/call_method_ambiguous.rs +++ b/tests/ui/impl-trait/call_method_ambiguous.rs @@ -3,7 +3,6 @@ //@[current] run-pass #![feature(precise_capturing)] -#![allow(incomplete_features)] trait Get { fn get(&mut self) -> u32; @@ -24,7 +23,7 @@ where } } -fn foo(n: usize, m: &mut ()) -> impl use<'_> Get { +fn foo(n: usize, m: &mut ()) -> impl Get + use<'_> { if n > 0 { let mut iter = foo(n - 1, m); //[next]~^ type annotations needed diff --git a/tests/ui/impl-trait/lazy_subtyping_of_opaques.rs b/tests/ui/impl-trait/lazy_subtyping_of_opaques.rs index 65331894725..8fd1f35645a 100644 --- a/tests/ui/impl-trait/lazy_subtyping_of_opaques.rs +++ b/tests/ui/impl-trait/lazy_subtyping_of_opaques.rs @@ -2,58 +2,23 @@ //! No hidden types are being constrained in the subtyping predicate, but type and //! lifetime variables get subtyped in the generic parameter list of the opaque. -use std::iter; - -mod either { - pub enum Either<L, R> { - Left(L), - Right(R), - } - - impl<L: Iterator, R: Iterator<Item = L::Item>> Iterator for Either<L, R> { - type Item = L::Item; - fn next(&mut self) -> Option<Self::Item> { - todo!() - } - } - pub use self::Either::{Left, Right}; -} - -pub enum BabeConsensusLogRef<'a> { - NextEpochData(BabeNextEpochRef<'a>), - NextConfigData, -} - -impl<'a> BabeConsensusLogRef<'a> { - pub fn scale_encoding( - &self, - ) -> impl Iterator<Item = impl AsRef<[u8]> + Clone + 'a> + Clone + 'a { - //~^ ERROR is not satisfied - //~| ERROR is not satisfied - //~| ERROR is not satisfied - match self { - BabeConsensusLogRef::NextEpochData(digest) => either::Left(either::Left( - digest.scale_encoding().map(either::Left).map(either::Left), - )), - BabeConsensusLogRef::NextConfigData => either::Right( - // The Opaque type from ``scale_encoding` gets used opaquely here, while the `R` - // generic parameter of `Either` contains type variables that get subtyped and the - // opaque type contains lifetime variables that get subtyped. - iter::once(either::Right(either::Left([1]))) - .chain(std::iter::once([1]).map(either::Right).map(either::Right)), - ), - } - } -} - -pub struct BabeNextEpochRef<'a>(&'a ()); - -impl<'a> BabeNextEpochRef<'a> { - pub fn scale_encoding( - &self, - ) -> impl Iterator<Item = impl AsRef<[u8]> + Clone + 'a> + Clone + 'a { - std::iter::once([1]) +//@ check-pass + +fn foo() -> impl Default + Copy { + if false { + let x = Default::default(); + // add `Subtype(?x, ?y)` obligation + let y = x; + + // Make a tuple `(?x, ?y)` and equate it with `(impl Default, u32)`. + // For us to try and prove a `Subtype(impl Default, u32)` obligation, + // we have to instantiate both `?x` and `?y` without any + // `select_where_possible` calls inbetween. + let mut tup = &mut (x, y); + let assign_tup = &mut (foo(), 1u32); + tup = assign_tup; } + 1u32 } fn main() {} diff --git a/tests/ui/impl-trait/lazy_subtyping_of_opaques.stderr b/tests/ui/impl-trait/lazy_subtyping_of_opaques.stderr deleted file mode 100644 index 2f8c957c2c7..00000000000 --- a/tests/ui/impl-trait/lazy_subtyping_of_opaques.stderr +++ /dev/null @@ -1,21 +0,0 @@ -error[E0277]: the trait bound `Either<Either<Map<Map<impl Iterator<Item = impl AsRef<[u8]> + Clone + '_> + Clone + '_, fn(impl AsRef<[u8]> + Clone + '_) -> Either<impl AsRef<[u8]> + Clone + '_, _> {Either::<impl AsRef<[u8]> + Clone + '_, _>::Left}>, fn(Either<impl AsRef<[u8]> + Clone + '_, _>) -> Either<Either<impl AsRef<[u8]> + Clone + '_, _>, Either<[{integer}; 1], [{integer}; 1]>> {Either::<Either<impl AsRef<[u8]> + Clone + '_, _>, Either<[{integer}; 1], [{integer}; 1]>>::Left}>, _>, std::iter::Chain<std::iter::Once<Either<Either<impl AsRef<[u8]> + Clone + '_, _>, Either<[{integer}; 1], [{integer}; 1]>>>, Map<Map<std::iter::Once<[{integer}; 1]>, fn([{integer}; 1]) -> Either<[{integer}; 1], [{integer}; 1]> {Either::<[{integer}; 1], [{integer}; 1]>::Right}>, fn(Either<[{integer}; 1], [{integer}; 1]>) -> Either<Either<impl AsRef<[u8]> + Clone + '_, _>, Either<[{integer}; 1], [{integer}; 1]>> {Either::<Either<impl AsRef<[u8]> + Clone + '_, _>, Either<[{integer}; 1], [{integer}; 1]>>::Right}>>>: Clone` is not satisfied - --> $DIR/lazy_subtyping_of_opaques.rs:30:10 - | -LL | ) -> impl Iterator<Item = impl AsRef<[u8]> + Clone + 'a> + Clone + 'a { - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ the trait `Clone` is not implemented for `Either<Either<Map<Map<impl Iterator<Item = impl AsRef<[u8]> + Clone + '_> + Clone + '_, fn(impl AsRef<[u8]> + Clone + '_) -> Either<impl AsRef<[u8]> + Clone + '_, _> {Either::<impl AsRef<[u8]> + Clone + '_, _>::Left}>, fn(Either<impl AsRef<[u8]> + Clone + '_, _>) -> Either<Either<impl AsRef<[u8]> + Clone + '_, _>, Either<[{integer}; 1], [{integer}; 1]>> {Either::<Either<impl AsRef<[u8]> + Clone + '_, _>, Either<[{integer}; 1], [{integer}; 1]>>::Left}>, _>, std::iter::Chain<std::iter::Once<Either<Either<impl AsRef<[u8]> + Clone + '_, _>, Either<[{integer}; 1], [{integer}; 1]>>>, Map<Map<std::iter::Once<[{integer}; 1]>, fn([{integer}; 1]) -> Either<[{integer}; 1], [{integer}; 1]> {Either::<[{integer}; 1], [{integer}; 1]>::Right}>, fn(Either<[{integer}; 1], [{integer}; 1]>) -> Either<Either<impl AsRef<[u8]> + Clone + '_, _>, Either<[{integer}; 1], [{integer}; 1]>> {Either::<Either<impl AsRef<[u8]> + Clone + '_, _>, Either<[{integer}; 1], [{integer}; 1]>>::Right}>>>` - -error[E0277]: the trait bound `Either<Either<impl AsRef<[u8]> + Clone + '_, _>, Either<[{integer}; 1], [{integer}; 1]>>: AsRef<[u8]>` is not satisfied - --> $DIR/lazy_subtyping_of_opaques.rs:30:31 - | -LL | ) -> impl Iterator<Item = impl AsRef<[u8]> + Clone + 'a> + Clone + 'a { - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ the trait `AsRef<[u8]>` is not implemented for `Either<Either<impl AsRef<[u8]> + Clone + '_, _>, Either<[{integer}; 1], [{integer}; 1]>>` - -error[E0277]: the trait bound `Either<Either<impl AsRef<[u8]> + Clone + '_, _>, Either<[{integer}; 1], [{integer}; 1]>>: Clone` is not satisfied - --> $DIR/lazy_subtyping_of_opaques.rs:30:31 - | -LL | ) -> impl Iterator<Item = impl AsRef<[u8]> + Clone + 'a> + Clone + 'a { - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ the trait `Clone` is not implemented for `Either<Either<impl AsRef<[u8]> + Clone + '_, _>, Either<[{integer}; 1], [{integer}; 1]>>` - -error: aborting due to 3 previous errors - -For more information about this error, try `rustc --explain E0277`. diff --git a/tests/ui/impl-trait/precise-capturing/apit.rs b/tests/ui/impl-trait/precise-capturing/apit.rs index efcac9ebb0b..64c15d6df96 100644 --- a/tests/ui/impl-trait/precise-capturing/apit.rs +++ b/tests/ui/impl-trait/precise-capturing/apit.rs @@ -1,7 +1,6 @@ #![feature(precise_capturing)] -//~^ WARN the feature `precise_capturing` is incomplete -fn hello(_: impl use<> Sized) {} -//~^ ERROR `use<...>` precise capturing syntax not allowed on argument-position `impl Trait` +fn hello(_: impl Sized + use<>) {} +//~^ ERROR `use<...>` precise capturing syntax not allowed in argument-position `impl Trait` fn main() {} diff --git a/tests/ui/impl-trait/precise-capturing/apit.stderr b/tests/ui/impl-trait/precise-capturing/apit.stderr index 96548f5732f..1d6225a1ff8 100644 --- a/tests/ui/impl-trait/precise-capturing/apit.stderr +++ b/tests/ui/impl-trait/precise-capturing/apit.stderr @@ -1,17 +1,8 @@ -warning: the feature `precise_capturing` is incomplete and may not be safe to use and/or cause compiler crashes - --> $DIR/apit.rs:1:12 +error: `use<...>` precise capturing syntax not allowed in argument-position `impl Trait` + --> $DIR/apit.rs:3:26 | -LL | #![feature(precise_capturing)] - | ^^^^^^^^^^^^^^^^^ - | - = note: see issue #123432 <https://github.com/rust-lang/rust/issues/123432> for more information - = note: `#[warn(incomplete_features)]` on by default - -error: `use<...>` precise capturing syntax not allowed on argument-position `impl Trait` - --> $DIR/apit.rs:4:18 - | -LL | fn hello(_: impl use<> Sized) {} - | ^^^^^ +LL | fn hello(_: impl Sized + use<>) {} + | ^^^^^ -error: aborting due to 1 previous error; 1 warning emitted +error: aborting due to 1 previous error diff --git a/tests/ui/impl-trait/precise-capturing/bad-lifetimes.rs b/tests/ui/impl-trait/precise-capturing/bad-lifetimes.rs index 623063a8f50..d2d4570c570 100644 --- a/tests/ui/impl-trait/precise-capturing/bad-lifetimes.rs +++ b/tests/ui/impl-trait/precise-capturing/bad-lifetimes.rs @@ -1,14 +1,13 @@ #![feature(precise_capturing)] -//~^ WARN the feature `precise_capturing` is incomplete -fn no_elided_lt() -> impl use<'_> Sized {} +fn no_elided_lt() -> impl Sized + use<'_> {} //~^ ERROR missing lifetime specifier //~| ERROR expected lifetime parameter in `use<...>` precise captures list, found `'_` -fn static_lt() -> impl use<'static> Sized {} +fn static_lt() -> impl Sized + use<'static> {} //~^ ERROR expected lifetime parameter in `use<...>` precise captures list, found `'static` -fn missing_lt() -> impl use<'missing> Sized {} +fn missing_lt() -> impl Sized + use<'missing> {} //~^ ERROR use of undeclared lifetime name `'missing` fn main() {} diff --git a/tests/ui/impl-trait/precise-capturing/bad-lifetimes.stderr b/tests/ui/impl-trait/precise-capturing/bad-lifetimes.stderr index a926362c50c..550996ab5e5 100644 --- a/tests/ui/impl-trait/precise-capturing/bad-lifetimes.stderr +++ b/tests/ui/impl-trait/precise-capturing/bad-lifetimes.stderr @@ -1,45 +1,36 @@ error[E0106]: missing lifetime specifier - --> $DIR/bad-lifetimes.rs:4:31 + --> $DIR/bad-lifetimes.rs:3:39 | -LL | fn no_elided_lt() -> impl use<'_> Sized {} - | ^^ expected named lifetime parameter +LL | fn no_elided_lt() -> impl Sized + use<'_> {} + | ^^ expected named lifetime parameter | = help: this function's return type contains a borrowed value, but there is no value for it to be borrowed from help: consider using the `'static` lifetime, but this is uncommon unless you're returning a borrowed value from a `const` or a `static`, or if you will only have owned values | -LL | fn no_elided_lt() -> impl use<'static> Sized {} - | ~~~~~~~ +LL | fn no_elided_lt() -> impl Sized + use<'static> {} + | ~~~~~~~ error[E0261]: use of undeclared lifetime name `'missing` - --> $DIR/bad-lifetimes.rs:11:29 + --> $DIR/bad-lifetimes.rs:10:37 | -LL | fn missing_lt() -> impl use<'missing> Sized {} - | - ^^^^^^^^ undeclared lifetime +LL | fn missing_lt() -> impl Sized + use<'missing> {} + | - ^^^^^^^^ undeclared lifetime | | | help: consider introducing lifetime `'missing` here: `<'missing>` -warning: the feature `precise_capturing` is incomplete and may not be safe to use and/or cause compiler crashes - --> $DIR/bad-lifetimes.rs:1:12 - | -LL | #![feature(precise_capturing)] - | ^^^^^^^^^^^^^^^^^ - | - = note: see issue #123432 <https://github.com/rust-lang/rust/issues/123432> for more information - = note: `#[warn(incomplete_features)]` on by default - error: expected lifetime parameter in `use<...>` precise captures list, found `'_` - --> $DIR/bad-lifetimes.rs:4:31 + --> $DIR/bad-lifetimes.rs:3:39 | -LL | fn no_elided_lt() -> impl use<'_> Sized {} - | ^^ +LL | fn no_elided_lt() -> impl Sized + use<'_> {} + | ^^ error: expected lifetime parameter in `use<...>` precise captures list, found `'static` - --> $DIR/bad-lifetimes.rs:8:28 + --> $DIR/bad-lifetimes.rs:7:36 | -LL | fn static_lt() -> impl use<'static> Sized {} - | ^^^^^^^ +LL | fn static_lt() -> impl Sized + use<'static> {} + | ^^^^^^^ -error: aborting due to 4 previous errors; 1 warning emitted +error: aborting due to 4 previous errors Some errors have detailed explanations: E0106, E0261. For more information about an error, try `rustc --explain E0106`. diff --git a/tests/ui/impl-trait/precise-capturing/bad-params.rs b/tests/ui/impl-trait/precise-capturing/bad-params.rs index 7970d49bf7c..08eee67c0e5 100644 --- a/tests/ui/impl-trait/precise-capturing/bad-params.rs +++ b/tests/ui/impl-trait/precise-capturing/bad-params.rs @@ -1,19 +1,18 @@ #![feature(precise_capturing)] -//~^ WARN the feature `precise_capturing` is incomplete -fn missing() -> impl use<T> Sized {} +fn missing() -> impl Sized + use<T> {} //~^ ERROR cannot find type `T` in this scope -fn missing_self() -> impl use<Self> Sized {} +fn missing_self() -> impl Sized + use<Self> {} //~^ ERROR cannot find type `Self` in this scope struct MyType; impl MyType { - fn self_is_not_param() -> impl use<Self> Sized {} + fn self_is_not_param() -> impl Sized + use<Self> {} //~^ ERROR `Self` can't be captured in `use<...>` precise captures list, since it is an alias } -fn hello() -> impl use<hello> Sized {} +fn hello() -> impl Sized + use<hello> {} //~^ ERROR expected type or const parameter in `use<...>` precise captures list, found function fn main() {} diff --git a/tests/ui/impl-trait/precise-capturing/bad-params.stderr b/tests/ui/impl-trait/precise-capturing/bad-params.stderr index 27bf05302f9..e104f115aa3 100644 --- a/tests/ui/impl-trait/precise-capturing/bad-params.stderr +++ b/tests/ui/impl-trait/precise-capturing/bad-params.stderr @@ -1,46 +1,37 @@ error[E0412]: cannot find type `T` in this scope - --> $DIR/bad-params.rs:4:26 + --> $DIR/bad-params.rs:3:34 | -LL | fn missing() -> impl use<T> Sized {} - | ^ not found in this scope +LL | fn missing() -> impl Sized + use<T> {} + | ^ not found in this scope | help: you might be missing a type parameter | -LL | fn missing<T>() -> impl use<T> Sized {} +LL | fn missing<T>() -> impl Sized + use<T> {} | +++ error[E0411]: cannot find type `Self` in this scope - --> $DIR/bad-params.rs:7:31 + --> $DIR/bad-params.rs:6:39 | -LL | fn missing_self() -> impl use<Self> Sized {} - | ------------ ^^^^ `Self` is only available in impls, traits, and type definitions +LL | fn missing_self() -> impl Sized + use<Self> {} + | ------------ ^^^^ `Self` is only available in impls, traits, and type definitions | | | `Self` not allowed in a function -warning: the feature `precise_capturing` is incomplete and may not be safe to use and/or cause compiler crashes - --> $DIR/bad-params.rs:1:12 - | -LL | #![feature(precise_capturing)] - | ^^^^^^^^^^^^^^^^^ - | - = note: see issue #123432 <https://github.com/rust-lang/rust/issues/123432> for more information - = note: `#[warn(incomplete_features)]` on by default - error: `Self` can't be captured in `use<...>` precise captures list, since it is an alias - --> $DIR/bad-params.rs:12:40 + --> $DIR/bad-params.rs:11:48 | LL | impl MyType { | ----------- `Self` is not a generic argument, but an alias to the type of the implementation -LL | fn self_is_not_param() -> impl use<Self> Sized {} - | ^^^^ +LL | fn self_is_not_param() -> impl Sized + use<Self> {} + | ^^^^ error: expected type or const parameter in `use<...>` precise captures list, found function - --> $DIR/bad-params.rs:16:24 + --> $DIR/bad-params.rs:15:32 | -LL | fn hello() -> impl use<hello> Sized {} - | ^^^^^ +LL | fn hello() -> impl Sized + use<hello> {} + | ^^^^^ -error: aborting due to 4 previous errors; 1 warning emitted +error: aborting due to 4 previous errors Some errors have detailed explanations: E0411, E0412. For more information about an error, try `rustc --explain E0411`. diff --git a/tests/ui/impl-trait/precise-capturing/capture-parent-arg.rs b/tests/ui/impl-trait/precise-capturing/capture-parent-arg.rs index 35b28d0e6fb..82b953bfed4 100644 --- a/tests/ui/impl-trait/precise-capturing/capture-parent-arg.rs +++ b/tests/ui/impl-trait/precise-capturing/capture-parent-arg.rs @@ -1,5 +1,4 @@ #![feature(precise_capturing)] -//~^ WARN the feature `precise_capturing` is incomplete trait Tr { type Assoc; @@ -13,25 +12,25 @@ impl Tr for W<'_> { // The normal way of capturing `'a`... impl<'a> W<'a> { - fn good1() -> impl use<'a> Into<<W<'a> as Tr>::Assoc> {} + fn good1() -> impl Into<<W<'a> as Tr>::Assoc> + use<'a> {} } // This ensures that we don't error when we capture the *parent* copy of `'a`, // since the opaque captures that rather than the duplicated `'a` lifetime // synthesized from mentioning `'a` directly in the bounds. impl<'a> W<'a> { - fn good2() -> impl use<'a> Into<<Self as Tr>::Assoc> {} + fn good2() -> impl Into<<Self as Tr>::Assoc> + use<'a> {} } // The normal way of capturing `'a`... but not mentioned in the bounds. impl<'a> W<'a> { - fn bad1() -> impl use<> Into<<W<'a> as Tr>::Assoc> {} + fn bad1() -> impl Into<<W<'a> as Tr>::Assoc> + use<> {} //~^ ERROR `impl Trait` captures lifetime parameter, but it is not mentioned in `use<...>` precise captures list } // But also make sure that we error here... impl<'a> W<'a> { - fn bad2() -> impl use<> Into<<Self as Tr>::Assoc> {} + fn bad2() -> impl Into<<Self as Tr>::Assoc> + use<> {} //~^ ERROR `impl Trait` captures lifetime parameter, but it is not mentioned in `use<...>` precise captures list } diff --git a/tests/ui/impl-trait/precise-capturing/capture-parent-arg.stderr b/tests/ui/impl-trait/precise-capturing/capture-parent-arg.stderr index 13aaa999707..b521ee0a902 100644 --- a/tests/ui/impl-trait/precise-capturing/capture-parent-arg.stderr +++ b/tests/ui/impl-trait/precise-capturing/capture-parent-arg.stderr @@ -1,27 +1,18 @@ -warning: the feature `precise_capturing` is incomplete and may not be safe to use and/or cause compiler crashes - --> $DIR/capture-parent-arg.rs:1:12 - | -LL | #![feature(precise_capturing)] - | ^^^^^^^^^^^^^^^^^ - | - = note: see issue #123432 <https://github.com/rust-lang/rust/issues/123432> for more information - = note: `#[warn(incomplete_features)]` on by default - error: `impl Trait` captures lifetime parameter, but it is not mentioned in `use<...>` precise captures list - --> $DIR/capture-parent-arg.rs:28:37 + --> $DIR/capture-parent-arg.rs:27:31 | LL | impl<'a> W<'a> { | -- this lifetime parameter is captured -LL | fn bad1() -> impl use<> Into<<W<'a> as Tr>::Assoc> {} - | -------------------^^---------------- lifetime captured due to being mentioned in the bounds of the `impl Trait` +LL | fn bad1() -> impl Into<<W<'a> as Tr>::Assoc> + use<> {} + | -------------^^------------------------ lifetime captured due to being mentioned in the bounds of the `impl Trait` error: `impl Trait` captures lifetime parameter, but it is not mentioned in `use<...>` precise captures list - --> $DIR/capture-parent-arg.rs:34:18 + --> $DIR/capture-parent-arg.rs:33:18 | LL | impl<'a> W<'a> { | -- this lifetime parameter is captured -LL | fn bad2() -> impl use<> Into<<Self as Tr>::Assoc> {} - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ lifetime captured due to being mentioned in the bounds of the `impl Trait` +LL | fn bad2() -> impl Into<<Self as Tr>::Assoc> + use<> {} + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ lifetime captured due to being mentioned in the bounds of the `impl Trait` -error: aborting due to 2 previous errors; 1 warning emitted +error: aborting due to 2 previous errors diff --git a/tests/ui/impl-trait/precise-capturing/duplicated-use.real.stderr b/tests/ui/impl-trait/precise-capturing/duplicated-use.real.stderr new file mode 100644 index 00000000000..d8edd672b48 --- /dev/null +++ b/tests/ui/impl-trait/precise-capturing/duplicated-use.real.stderr @@ -0,0 +1,8 @@ +error: duplicate `use<...>` precise capturing syntax + --> $DIR/duplicated-use.rs:7:32 + | +LL | fn hello<'a>() -> impl Sized + use<'a> + use<'a> {} + | ^^^^^^^ ------- second `use<...>` here + +error: aborting due to 1 previous error + diff --git a/tests/ui/impl-trait/precise-capturing/duplicated-use.rs b/tests/ui/impl-trait/precise-capturing/duplicated-use.rs new file mode 100644 index 00000000000..bfbdcdbf311 --- /dev/null +++ b/tests/ui/impl-trait/precise-capturing/duplicated-use.rs @@ -0,0 +1,10 @@ +//@ revisions: real pre_expansion +//@[pre_expansion] check-pass + +#![feature(precise_capturing)] + +#[cfg(real)] +fn hello<'a>() -> impl Sized + use<'a> + use<'a> {} +//[real]~^ ERROR duplicate `use<...>` precise capturing syntax + +fn main() {} diff --git a/tests/ui/impl-trait/precise-capturing/dyn-use.rs b/tests/ui/impl-trait/precise-capturing/dyn-use.rs new file mode 100644 index 00000000000..ce7a0f3c7b2 --- /dev/null +++ b/tests/ui/impl-trait/precise-capturing/dyn-use.rs @@ -0,0 +1,4 @@ +#![feature(precise_capturing)] + +fn dyn() -> &'static dyn use<> { &() } +//~^ ERROR expected one of `!`, `(`, `::`, `<`, `where`, or `{`, found keyword `use` diff --git a/tests/ui/impl-trait/precise-capturing/dyn-use.stderr b/tests/ui/impl-trait/precise-capturing/dyn-use.stderr new file mode 100644 index 00000000000..5519633de1f --- /dev/null +++ b/tests/ui/impl-trait/precise-capturing/dyn-use.stderr @@ -0,0 +1,8 @@ +error: expected one of `!`, `(`, `::`, `<`, `where`, or `{`, found keyword `use` + --> $DIR/dyn-use.rs:3:26 + | +LL | fn dyn() -> &'static dyn use<> { &() } + | ^^^ expected one of `!`, `(`, `::`, `<`, `where`, or `{` + +error: aborting due to 1 previous error + diff --git a/tests/ui/impl-trait/precise-capturing/elided.rs b/tests/ui/impl-trait/precise-capturing/elided.rs index de80e8a5d58..34d1ba620dc 100644 --- a/tests/ui/impl-trait/precise-capturing/elided.rs +++ b/tests/ui/impl-trait/precise-capturing/elided.rs @@ -1,8 +1,7 @@ //@ check-pass #![feature(precise_capturing)] -//~^ WARN the feature `precise_capturing` is incomplete -fn elided(x: &()) -> impl use<'_> Sized { x } +fn elided(x: &()) -> impl Sized + use<'_> { x } fn main() {} diff --git a/tests/ui/impl-trait/precise-capturing/elided.stderr b/tests/ui/impl-trait/precise-capturing/elided.stderr deleted file mode 100644 index 38da0828de9..00000000000 --- a/tests/ui/impl-trait/precise-capturing/elided.stderr +++ /dev/null @@ -1,11 +0,0 @@ -warning: the feature `precise_capturing` is incomplete and may not be safe to use and/or cause compiler crashes - --> $DIR/elided.rs:3:12 - | -LL | #![feature(precise_capturing)] - | ^^^^^^^^^^^^^^^^^ - | - = note: see issue #123432 <https://github.com/rust-lang/rust/issues/123432> for more information - = note: `#[warn(incomplete_features)]` on by default - -warning: 1 warning emitted - diff --git a/tests/ui/impl-trait/precise-capturing/forgot-to-capture-const.rs b/tests/ui/impl-trait/precise-capturing/forgot-to-capture-const.rs index 1b604e6c358..26d29e456ea 100644 --- a/tests/ui/impl-trait/precise-capturing/forgot-to-capture-const.rs +++ b/tests/ui/impl-trait/precise-capturing/forgot-to-capture-const.rs @@ -1,7 +1,6 @@ #![feature(precise_capturing)] -//~^ WARN the feature `precise_capturing` is incomplete -fn constant<const C: usize>() -> impl use<> Sized {} +fn constant<const C: usize>() -> impl Sized + use<> {} //~^ ERROR `impl Trait` must mention all const parameters in scope fn main() {} diff --git a/tests/ui/impl-trait/precise-capturing/forgot-to-capture-const.stderr b/tests/ui/impl-trait/precise-capturing/forgot-to-capture-const.stderr index 3f78e7c56b6..989ed136d4c 100644 --- a/tests/ui/impl-trait/precise-capturing/forgot-to-capture-const.stderr +++ b/tests/ui/impl-trait/precise-capturing/forgot-to-capture-const.stderr @@ -1,21 +1,12 @@ -warning: the feature `precise_capturing` is incomplete and may not be safe to use and/or cause compiler crashes - --> $DIR/forgot-to-capture-const.rs:1:12 - | -LL | #![feature(precise_capturing)] - | ^^^^^^^^^^^^^^^^^ - | - = note: see issue #123432 <https://github.com/rust-lang/rust/issues/123432> for more information - = note: `#[warn(incomplete_features)]` on by default - error: `impl Trait` must mention all const parameters in scope in `use<...>` - --> $DIR/forgot-to-capture-const.rs:4:34 + --> $DIR/forgot-to-capture-const.rs:3:34 | -LL | fn constant<const C: usize>() -> impl use<> Sized {} - | -------------- ^^^^^^^^^^^^^^^^ +LL | fn constant<const C: usize>() -> impl Sized + use<> {} + | -------------- ^^^^^^^^^^^^^^^^^^ | | | const parameter is implicitly captured by this `impl Trait` | = note: currently, all const parameters are required to be mentioned in the precise captures list -error: aborting due to 1 previous error; 1 warning emitted +error: aborting due to 1 previous error diff --git a/tests/ui/impl-trait/precise-capturing/forgot-to-capture-lifetime.rs b/tests/ui/impl-trait/precise-capturing/forgot-to-capture-lifetime.rs index cc86bf83107..f18dbca6c5e 100644 --- a/tests/ui/impl-trait/precise-capturing/forgot-to-capture-lifetime.rs +++ b/tests/ui/impl-trait/precise-capturing/forgot-to-capture-lifetime.rs @@ -1,10 +1,9 @@ #![feature(precise_capturing)] -//~^ WARN the feature `precise_capturing` is incomplete -fn lifetime_in_bounds<'a>(x: &'a ()) -> impl use<> Into<&'a ()> { x } +fn lifetime_in_bounds<'a>(x: &'a ()) -> impl Into<&'a ()> + use<> { x } //~^ ERROR `impl Trait` captures lifetime parameter, but it is not mentioned in `use<...>` precise captures list -fn lifetime_in_hidden<'a>(x: &'a ()) -> impl use<> Sized { x } +fn lifetime_in_hidden<'a>(x: &'a ()) -> impl Sized + use<> { x } //~^ ERROR hidden type for `impl Sized` captures lifetime that does not appear in bounds fn main() {} diff --git a/tests/ui/impl-trait/precise-capturing/forgot-to-capture-lifetime.stderr b/tests/ui/impl-trait/precise-capturing/forgot-to-capture-lifetime.stderr index e472c898050..6544837ba83 100644 --- a/tests/ui/impl-trait/precise-capturing/forgot-to-capture-lifetime.stderr +++ b/tests/ui/impl-trait/precise-capturing/forgot-to-capture-lifetime.stderr @@ -1,35 +1,26 @@ -warning: the feature `precise_capturing` is incomplete and may not be safe to use and/or cause compiler crashes - --> $DIR/forgot-to-capture-lifetime.rs:1:12 - | -LL | #![feature(precise_capturing)] - | ^^^^^^^^^^^^^^^^^ - | - = note: see issue #123432 <https://github.com/rust-lang/rust/issues/123432> for more information - = note: `#[warn(incomplete_features)]` on by default - error: `impl Trait` captures lifetime parameter, but it is not mentioned in `use<...>` precise captures list - --> $DIR/forgot-to-capture-lifetime.rs:4:58 + --> $DIR/forgot-to-capture-lifetime.rs:3:52 | -LL | fn lifetime_in_bounds<'a>(x: &'a ()) -> impl use<> Into<&'a ()> { x } - | -- -----------------^^---- +LL | fn lifetime_in_bounds<'a>(x: &'a ()) -> impl Into<&'a ()> + use<> { x } + | -- -----------^^------------ | | | | | lifetime captured due to being mentioned in the bounds of the `impl Trait` | this lifetime parameter is captured error[E0700]: hidden type for `impl Sized` captures lifetime that does not appear in bounds - --> $DIR/forgot-to-capture-lifetime.rs:7:60 + --> $DIR/forgot-to-capture-lifetime.rs:6:62 | -LL | fn lifetime_in_hidden<'a>(x: &'a ()) -> impl use<> Sized { x } - | -- ---------------- ^ +LL | fn lifetime_in_hidden<'a>(x: &'a ()) -> impl Sized + use<> { x } + | -- ------------------ ^ | | | | | opaque type defined here | hidden type `&'a ()` captures the lifetime `'a` as defined here | help: to declare that `impl Sized` captures `'a`, you can add an explicit `'a` lifetime bound | -LL | fn lifetime_in_hidden<'a>(x: &'a ()) -> impl use<> Sized + 'a { x } - | ++++ +LL | fn lifetime_in_hidden<'a>(x: &'a ()) -> impl Sized + use<> + 'a { x } + | ++++ -error: aborting due to 2 previous errors; 1 warning emitted +error: aborting due to 2 previous errors For more information about this error, try `rustc --explain E0700`. diff --git a/tests/ui/impl-trait/precise-capturing/forgot-to-capture-type.rs b/tests/ui/impl-trait/precise-capturing/forgot-to-capture-type.rs index d359ea5e26d..08014985783 100644 --- a/tests/ui/impl-trait/precise-capturing/forgot-to-capture-type.rs +++ b/tests/ui/impl-trait/precise-capturing/forgot-to-capture-type.rs @@ -1,11 +1,10 @@ #![feature(precise_capturing)] -//~^ WARN the feature `precise_capturing` is incomplete -fn type_param<T>() -> impl use<> Sized {} +fn type_param<T>() -> impl Sized + use<> {} //~^ ERROR `impl Trait` must mention all type parameters in scope trait Foo { - fn bar() -> impl use<> Sized; + fn bar() -> impl Sized + use<>; //~^ ERROR `impl Trait` must mention the `Self` type of the trait } diff --git a/tests/ui/impl-trait/precise-capturing/forgot-to-capture-type.stderr b/tests/ui/impl-trait/precise-capturing/forgot-to-capture-type.stderr index 26994d0bdbf..93b44a0c18c 100644 --- a/tests/ui/impl-trait/precise-capturing/forgot-to-capture-type.stderr +++ b/tests/ui/impl-trait/precise-capturing/forgot-to-capture-type.stderr @@ -1,31 +1,22 @@ -warning: the feature `precise_capturing` is incomplete and may not be safe to use and/or cause compiler crashes - --> $DIR/forgot-to-capture-type.rs:1:12 - | -LL | #![feature(precise_capturing)] - | ^^^^^^^^^^^^^^^^^ - | - = note: see issue #123432 <https://github.com/rust-lang/rust/issues/123432> for more information - = note: `#[warn(incomplete_features)]` on by default - error: `impl Trait` must mention all type parameters in scope in `use<...>` - --> $DIR/forgot-to-capture-type.rs:4:23 + --> $DIR/forgot-to-capture-type.rs:3:23 | -LL | fn type_param<T>() -> impl use<> Sized {} - | - ^^^^^^^^^^^^^^^^ +LL | fn type_param<T>() -> impl Sized + use<> {} + | - ^^^^^^^^^^^^^^^^^^ | | | type parameter is implicitly captured by this `impl Trait` | = note: currently, all type parameters are required to be mentioned in the precise captures list error: `impl Trait` must mention the `Self` type of the trait in `use<...>` - --> $DIR/forgot-to-capture-type.rs:8:17 + --> $DIR/forgot-to-capture-type.rs:7:17 | LL | trait Foo { | --------- `Self` type parameter is implicitly captured by this `impl Trait` -LL | fn bar() -> impl use<> Sized; - | ^^^^^^^^^^^^^^^^ +LL | fn bar() -> impl Sized + use<>; + | ^^^^^^^^^^^^^^^^^^ | = note: currently, all type parameters are required to be mentioned in the precise captures list -error: aborting due to 2 previous errors; 1 warning emitted +error: aborting due to 2 previous errors diff --git a/tests/ui/impl-trait/precise-capturing/higher-ranked.rs b/tests/ui/impl-trait/precise-capturing/higher-ranked.rs index 28fb1fa4b9e..21ac19640bc 100644 --- a/tests/ui/impl-trait/precise-capturing/higher-ranked.rs +++ b/tests/ui/impl-trait/precise-capturing/higher-ranked.rs @@ -3,7 +3,6 @@ // Show how precise captures allow us to skip capturing a higher-ranked lifetime #![feature(lifetime_capture_rules_2024, precise_capturing)] -//~^ WARN the feature `precise_capturing` is incomplete trait Trait<'a> { type Item; @@ -13,6 +12,6 @@ impl Trait<'_> for () { type Item = Vec<()>; } -fn hello() -> impl for<'a> Trait<'a, Item = impl use<> IntoIterator> {} +fn hello() -> impl for<'a> Trait<'a, Item = impl IntoIterator + use<>> {} fn main() {} diff --git a/tests/ui/impl-trait/precise-capturing/higher-ranked.stderr b/tests/ui/impl-trait/precise-capturing/higher-ranked.stderr deleted file mode 100644 index e48d6d42af0..00000000000 --- a/tests/ui/impl-trait/precise-capturing/higher-ranked.stderr +++ /dev/null @@ -1,11 +0,0 @@ -warning: the feature `precise_capturing` is incomplete and may not be safe to use and/or cause compiler crashes - --> $DIR/higher-ranked.rs:5:41 - | -LL | #![feature(lifetime_capture_rules_2024, precise_capturing)] - | ^^^^^^^^^^^^^^^^^ - | - = note: see issue #123432 <https://github.com/rust-lang/rust/issues/123432> for more information - = note: `#[warn(incomplete_features)]` on by default - -warning: 1 warning emitted - diff --git a/tests/ui/impl-trait/precise-capturing/illegal-positions.real.stderr b/tests/ui/impl-trait/precise-capturing/illegal-positions.real.stderr new file mode 100644 index 00000000000..2b234bcb6a5 --- /dev/null +++ b/tests/ui/impl-trait/precise-capturing/illegal-positions.real.stderr @@ -0,0 +1,57 @@ +error: `use<...>` precise capturing syntax not allowed in supertrait bounds + --> $DIR/illegal-positions.rs:8:12 + | +LL | trait Foo: use<> { + | ^^^^^ + +error: `use<...>` precise capturing syntax not allowed in bounds + --> $DIR/illegal-positions.rs:10:33 + | +LL | type Assoc: use<> where (): use<>; + | ^^^^^ + +error: `use<...>` precise capturing syntax not allowed in bounds + --> $DIR/illegal-positions.rs:10:17 + | +LL | type Assoc: use<> where (): use<>; + | ^^^^^ + +error: `use<...>` precise capturing syntax not allowed in bounds + --> $DIR/illegal-positions.rs:16:11 + | +LL | fn fun<T: use<>>(_: impl use<>) where (): use<> {} + | ^^^^^ + +error: `use<...>` precise capturing syntax not allowed in bounds + --> $DIR/illegal-positions.rs:16:43 + | +LL | fn fun<T: use<>>(_: impl use<>) where (): use<> {} + | ^^^^^ + +error: at least one trait must be specified + --> $DIR/illegal-positions.rs:16:21 + | +LL | fn fun<T: use<>>(_: impl use<>) where (): use<> {} + | ^^^^^^^^^^ + +error: `use<...>` precise capturing syntax not allowed in `dyn` trait object bounds + --> $DIR/illegal-positions.rs:23:25 + | +LL | fn dynamic() -> Box<dyn use<>> {} + | ^^^^^ + +error: `use<...>` precise capturing syntax not allowed in argument-position `impl Trait` + --> $DIR/illegal-positions.rs:16:26 + | +LL | fn fun<T: use<>>(_: impl use<>) where (): use<> {} + | ^^^^^ + +error[E0224]: at least one trait is required for an object type + --> $DIR/illegal-positions.rs:23:21 + | +LL | fn dynamic() -> Box<dyn use<>> {} + | ^^^^^^^^^ + +error: aborting due to 9 previous errors + +For more information about this error, try `rustc --explain E0224`. diff --git a/tests/ui/impl-trait/precise-capturing/illegal-positions.rs b/tests/ui/impl-trait/precise-capturing/illegal-positions.rs new file mode 100644 index 00000000000..681458e25f8 --- /dev/null +++ b/tests/ui/impl-trait/precise-capturing/illegal-positions.rs @@ -0,0 +1,27 @@ +//@ revisions: real pre_expansion +//@[pre_expansion] check-pass +//@ edition: 2021 + +#![feature(precise_capturing)] + +#[cfg(real)] +trait Foo: use<> { + //[real]~^ ERROR `use<...>` precise capturing syntax not allowed + type Assoc: use<> where (): use<>; + //[real]~^ ERROR `use<...>` precise capturing syntax not allowed + //[real]~| ERROR `use<...>` precise capturing syntax not allowed +} + +#[cfg(real)] +fn fun<T: use<>>(_: impl use<>) where (): use<> {} +//[real]~^ ERROR `use<...>` precise capturing syntax not allowed +//[real]~| ERROR `use<...>` precise capturing syntax not allowed +//[real]~| ERROR `use<...>` precise capturing syntax not allowed +//[real]~| ERROR at least one trait must be specified + +#[cfg(real)] +fn dynamic() -> Box<dyn use<>> {} +//[real]~^ ERROR `use<...>` precise capturing syntax not allowed in `dyn` trait object bounds +//[real]~| ERROR at least one trait is required for an object type [E0224] + +fn main() {} diff --git a/tests/ui/impl-trait/precise-capturing/ordering.rs b/tests/ui/impl-trait/precise-capturing/ordering.rs index 2bace798c57..eb570a120cc 100644 --- a/tests/ui/impl-trait/precise-capturing/ordering.rs +++ b/tests/ui/impl-trait/precise-capturing/ordering.rs @@ -1,16 +1,15 @@ #![feature(precise_capturing)] -//~^ WARN the feature `precise_capturing` is incomplete -fn lt<'a>() -> impl use<'a, 'a> Sized {} +fn lt<'a>() -> impl Sized + use<'a, 'a> {} //~^ ERROR cannot capture parameter `'a` twice -fn ty<T>() -> impl use<T, T> Sized {} +fn ty<T>() -> impl Sized + use<T, T> {} //~^ ERROR cannot capture parameter `T` twice -fn ct<const N: usize>() -> impl use<N, N> Sized {} +fn ct<const N: usize>() -> impl Sized + use<N, N> {} //~^ ERROR cannot capture parameter `N` twice -fn ordering<'a, T>() -> impl use<T, 'a> Sized {} +fn ordering<'a, T>() -> impl Sized + use<T, 'a> {} //~^ ERROR lifetime parameter `'a` must be listed before non-lifetime parameters fn main() {} diff --git a/tests/ui/impl-trait/precise-capturing/ordering.stderr b/tests/ui/impl-trait/precise-capturing/ordering.stderr index 3f545108df5..ecd47159059 100644 --- a/tests/ui/impl-trait/precise-capturing/ordering.stderr +++ b/tests/ui/impl-trait/precise-capturing/ordering.stderr @@ -1,37 +1,28 @@ -warning: the feature `precise_capturing` is incomplete and may not be safe to use and/or cause compiler crashes - --> $DIR/ordering.rs:1:12 - | -LL | #![feature(precise_capturing)] - | ^^^^^^^^^^^^^^^^^ - | - = note: see issue #123432 <https://github.com/rust-lang/rust/issues/123432> for more information - = note: `#[warn(incomplete_features)]` on by default - error: cannot capture parameter `'a` twice - --> $DIR/ordering.rs:4:25 + --> $DIR/ordering.rs:3:33 | -LL | fn lt<'a>() -> impl use<'a, 'a> Sized {} - | ^^ -- parameter captured again here +LL | fn lt<'a>() -> impl Sized + use<'a, 'a> {} + | ^^ -- parameter captured again here error: cannot capture parameter `T` twice - --> $DIR/ordering.rs:7:24 + --> $DIR/ordering.rs:6:32 | -LL | fn ty<T>() -> impl use<T, T> Sized {} - | ^ - parameter captured again here +LL | fn ty<T>() -> impl Sized + use<T, T> {} + | ^ - parameter captured again here error: cannot capture parameter `N` twice - --> $DIR/ordering.rs:10:37 + --> $DIR/ordering.rs:9:45 | -LL | fn ct<const N: usize>() -> impl use<N, N> Sized {} - | ^ - parameter captured again here +LL | fn ct<const N: usize>() -> impl Sized + use<N, N> {} + | ^ - parameter captured again here error: lifetime parameter `'a` must be listed before non-lifetime parameters - --> $DIR/ordering.rs:13:37 + --> $DIR/ordering.rs:12:45 | -LL | fn ordering<'a, T>() -> impl use<T, 'a> Sized {} - | - ^^ - | | - | move the lifetime before this parameter +LL | fn ordering<'a, T>() -> impl Sized + use<T, 'a> {} + | - ^^ + | | + | move the lifetime before this parameter -error: aborting due to 4 previous errors; 1 warning emitted +error: aborting due to 4 previous errors diff --git a/tests/ui/impl-trait/precise-capturing/outlives.rs b/tests/ui/impl-trait/precise-capturing/outlives.rs index 71e6333934e..26ac922b5b9 100644 --- a/tests/ui/impl-trait/precise-capturing/outlives.rs +++ b/tests/ui/impl-trait/precise-capturing/outlives.rs @@ -3,9 +3,8 @@ // Show that precise captures allow us to skip a lifetime param for outlives #![feature(lifetime_capture_rules_2024, precise_capturing)] -//~^ WARN the feature `precise_capturing` is incomplete -fn hello<'a: 'a, 'b: 'b>() -> impl use<'a> Sized { } +fn hello<'a: 'a, 'b: 'b>() -> impl Sized + use<'a> { } fn outlives<'a, T: 'a>(_: T) {} diff --git a/tests/ui/impl-trait/precise-capturing/outlives.stderr b/tests/ui/impl-trait/precise-capturing/outlives.stderr deleted file mode 100644 index 405c09cccd9..00000000000 --- a/tests/ui/impl-trait/precise-capturing/outlives.stderr +++ /dev/null @@ -1,11 +0,0 @@ -warning: the feature `precise_capturing` is incomplete and may not be safe to use and/or cause compiler crashes - --> $DIR/outlives.rs:5:41 - | -LL | #![feature(lifetime_capture_rules_2024, precise_capturing)] - | ^^^^^^^^^^^^^^^^^ - | - = note: see issue #123432 <https://github.com/rust-lang/rust/issues/123432> for more information - = note: `#[warn(incomplete_features)]` on by default - -warning: 1 warning emitted - diff --git a/tests/ui/impl-trait/precise-capturing/overcaptures-2024.fixed b/tests/ui/impl-trait/precise-capturing/overcaptures-2024.fixed index 014ab23e4eb..5ac296a9cbd 100644 --- a/tests/ui/impl-trait/precise-capturing/overcaptures-2024.fixed +++ b/tests/ui/impl-trait/precise-capturing/overcaptures-2024.fixed @@ -4,15 +4,15 @@ #![allow(unused, incomplete_features)] #![deny(impl_trait_overcaptures)] -fn named<'a>(x: &'a i32) -> impl use<> Sized { *x } +fn named<'a>(x: &'a i32) -> impl Sized + use<> { *x } //~^ ERROR `impl Sized` will capture more lifetimes than possibly intended in edition 2024 -fn implicit(x: &i32) -> impl use<> Sized { *x } +fn implicit(x: &i32) -> impl Sized + use<> { *x } //~^ ERROR `impl Sized` will capture more lifetimes than possibly intended in edition 2024 struct W; impl W { - fn hello(&self, x: &i32) -> impl use<'_> Sized + '_ { self } + fn hello(&self, x: &i32) -> impl Sized + '_ + use<'_> { self } //~^ ERROR `impl Sized + '_` will capture more lifetimes than possibly intended in edition 2024 } @@ -23,7 +23,7 @@ impl Higher<'_> for () { type Output = (); } -fn hrtb() -> impl for<'a> Higher<'a, Output = impl use<> Sized> {} +fn hrtb() -> impl for<'a> Higher<'a, Output = impl Sized + use<>> {} //~^ ERROR `impl Sized` will capture more lifetimes than possibly intended in edition 2024 fn main() {} diff --git a/tests/ui/impl-trait/precise-capturing/overcaptures-2024.stderr b/tests/ui/impl-trait/precise-capturing/overcaptures-2024.stderr index 16cb8b7e94b..f8bb7f099af 100644 --- a/tests/ui/impl-trait/precise-capturing/overcaptures-2024.stderr +++ b/tests/ui/impl-trait/precise-capturing/overcaptures-2024.stderr @@ -17,8 +17,8 @@ LL | #![deny(impl_trait_overcaptures)] | ^^^^^^^^^^^^^^^^^^^^^^^ help: use the precise capturing `use<...>` syntax to make the captures explicit | -LL | fn named<'a>(x: &'a i32) -> impl use<> Sized { *x } - | +++++ +LL | fn named<'a>(x: &'a i32) -> impl Sized + use<> { *x } + | +++++++ error: `impl Sized` will capture more lifetimes than possibly intended in edition 2024 --> $DIR/overcaptures-2024.rs:10:25 @@ -34,8 +34,8 @@ LL | fn implicit(x: &i32) -> impl Sized { *x } = note: all lifetimes in scope will be captured by `impl Trait`s in edition 2024 help: use the precise capturing `use<...>` syntax to make the captures explicit | -LL | fn implicit(x: &i32) -> impl use<> Sized { *x } - | +++++ +LL | fn implicit(x: &i32) -> impl Sized + use<> { *x } + | +++++++ error: `impl Sized + '_` will capture more lifetimes than possibly intended in edition 2024 --> $DIR/overcaptures-2024.rs:15:33 @@ -51,8 +51,8 @@ LL | fn hello(&self, x: &i32) -> impl Sized + '_ { self } = note: all lifetimes in scope will be captured by `impl Trait`s in edition 2024 help: use the precise capturing `use<...>` syntax to make the captures explicit | -LL | fn hello(&self, x: &i32) -> impl use<'_> Sized + '_ { self } - | +++++++ +LL | fn hello(&self, x: &i32) -> impl Sized + '_ + use<'_> { self } + | +++++++++ error: `impl Sized` will capture more lifetimes than possibly intended in edition 2024 --> $DIR/overcaptures-2024.rs:26:47 @@ -68,8 +68,8 @@ LL | fn hrtb() -> impl for<'a> Higher<'a, Output = impl Sized> {} = note: all lifetimes in scope will be captured by `impl Trait`s in edition 2024 help: use the precise capturing `use<...>` syntax to make the captures explicit | -LL | fn hrtb() -> impl for<'a> Higher<'a, Output = impl use<> Sized> {} - | +++++ +LL | fn hrtb() -> impl for<'a> Higher<'a, Output = impl Sized + use<>> {} + | +++++++ error: aborting due to 4 previous errors diff --git a/tests/ui/impl-trait/precise-capturing/redundant.rs b/tests/ui/impl-trait/precise-capturing/redundant.rs index 108a4cb64aa..99c128fdc48 100644 --- a/tests/ui/impl-trait/precise-capturing/redundant.rs +++ b/tests/ui/impl-trait/precise-capturing/redundant.rs @@ -2,23 +2,22 @@ //@ check-pass #![feature(precise_capturing)] -//~^ WARN the feature `precise_capturing` is incomplete -fn hello<'a>() -> impl use<'a> Sized {} +fn hello<'a>() -> impl Sized + use<'a> {} //~^ WARN all possible in-scope parameters are already captured struct Inherent; impl Inherent { - fn inherent(&self) -> impl use<'_> Sized {} + fn inherent(&self) -> impl Sized + use<'_> {} //~^ WARN all possible in-scope parameters are already captured } trait Test<'a> { - fn in_trait() -> impl use<'a, Self> Sized; + fn in_trait() -> impl Sized + use<'a, Self>; //~^ WARN all possible in-scope parameters are already captured } impl<'a> Test<'a> for () { - fn in_trait() -> impl use<'a> Sized {} + fn in_trait() -> impl Sized + use<'a> {} //~^ WARN all possible in-scope parameters are already captured } diff --git a/tests/ui/impl-trait/precise-capturing/redundant.stderr b/tests/ui/impl-trait/precise-capturing/redundant.stderr index 325f04d3536..274d9d2375f 100644 --- a/tests/ui/impl-trait/precise-capturing/redundant.stderr +++ b/tests/ui/impl-trait/precise-capturing/redundant.stderr @@ -1,45 +1,36 @@ -warning: the feature `precise_capturing` is incomplete and may not be safe to use and/or cause compiler crashes - --> $DIR/redundant.rs:4:12 - | -LL | #![feature(precise_capturing)] - | ^^^^^^^^^^^^^^^^^ - | - = note: see issue #123432 <https://github.com/rust-lang/rust/issues/123432> for more information - = note: `#[warn(incomplete_features)]` on by default - warning: all possible in-scope parameters are already captured, so `use<...>` syntax is redundant - --> $DIR/redundant.rs:7:19 + --> $DIR/redundant.rs:6:19 | -LL | fn hello<'a>() -> impl use<'a> Sized {} - | ^^^^^-------^^^^^^ - | | - | help: remove the `use<...>` syntax +LL | fn hello<'a>() -> impl Sized + use<'a> {} + | ^^^^^^^^^^^^^------- + | | + | help: remove the `use<...>` syntax | = note: `#[warn(impl_trait_redundant_captures)]` on by default warning: all possible in-scope parameters are already captured, so `use<...>` syntax is redundant - --> $DIR/redundant.rs:12:27 + --> $DIR/redundant.rs:11:27 | -LL | fn inherent(&self) -> impl use<'_> Sized {} - | ^^^^^-------^^^^^^ - | | - | help: remove the `use<...>` syntax +LL | fn inherent(&self) -> impl Sized + use<'_> {} + | ^^^^^^^^^^^^^------- + | | + | help: remove the `use<...>` syntax warning: all possible in-scope parameters are already captured, so `use<...>` syntax is redundant - --> $DIR/redundant.rs:17:22 + --> $DIR/redundant.rs:16:22 | -LL | fn in_trait() -> impl use<'a, Self> Sized; - | ^^^^^-------------^^^^^^ - | | - | help: remove the `use<...>` syntax +LL | fn in_trait() -> impl Sized + use<'a, Self>; + | ^^^^^^^^^^^^^------------- + | | + | help: remove the `use<...>` syntax warning: all possible in-scope parameters are already captured, so `use<...>` syntax is redundant - --> $DIR/redundant.rs:21:22 + --> $DIR/redundant.rs:20:22 | -LL | fn in_trait() -> impl use<'a> Sized {} - | ^^^^^-------^^^^^^ - | | - | help: remove the `use<...>` syntax +LL | fn in_trait() -> impl Sized + use<'a> {} + | ^^^^^^^^^^^^^------- + | | + | help: remove the `use<...>` syntax -warning: 5 warnings emitted +warning: 4 warnings emitted diff --git a/tests/ui/impl-trait/precise-capturing/self-capture.rs b/tests/ui/impl-trait/precise-capturing/self-capture.rs index ecbc388e27b..e0a4a8b658c 100644 --- a/tests/ui/impl-trait/precise-capturing/self-capture.rs +++ b/tests/ui/impl-trait/precise-capturing/self-capture.rs @@ -1,10 +1,9 @@ //@ check-pass #![feature(precise_capturing)] -//~^ WARN the feature `precise_capturing` is incomplete trait Foo { - fn bar<'a>() -> impl use<Self> Sized; + fn bar<'a>() -> impl Sized + use<Self>; } fn main() {} diff --git a/tests/ui/impl-trait/precise-capturing/self-capture.stderr b/tests/ui/impl-trait/precise-capturing/self-capture.stderr deleted file mode 100644 index 5a058c6826d..00000000000 --- a/tests/ui/impl-trait/precise-capturing/self-capture.stderr +++ /dev/null @@ -1,11 +0,0 @@ -warning: the feature `precise_capturing` is incomplete and may not be safe to use and/or cause compiler crashes - --> $DIR/self-capture.rs:3:12 - | -LL | #![feature(precise_capturing)] - | ^^^^^^^^^^^^^^^^^ - | - = note: see issue #123432 <https://github.com/rust-lang/rust/issues/123432> for more information - = note: `#[warn(incomplete_features)]` on by default - -warning: 1 warning emitted - diff --git a/tests/ui/impl-trait/precise-capturing/unexpected-token.rs b/tests/ui/impl-trait/precise-capturing/unexpected-token.rs index 39c8c0def6b..a1089fd7bfc 100644 --- a/tests/ui/impl-trait/precise-capturing/unexpected-token.rs +++ b/tests/ui/impl-trait/precise-capturing/unexpected-token.rs @@ -2,8 +2,7 @@ // token due to a strange interaction between the sequence parsing code and the // param/lifetime parsing code. -fn hello() -> impl use<'a {}> Sized {} +fn hello() -> impl Sized + use<'a {}> {} //~^ ERROR expected one of `,` or `>`, found `{` -//~| ERROR expected item, found `>` fn main() {} diff --git a/tests/ui/impl-trait/precise-capturing/unexpected-token.stderr b/tests/ui/impl-trait/precise-capturing/unexpected-token.stderr index 989c479b248..51e4f0f6775 100644 --- a/tests/ui/impl-trait/precise-capturing/unexpected-token.stderr +++ b/tests/ui/impl-trait/precise-capturing/unexpected-token.stderr @@ -1,16 +1,8 @@ error: expected one of `,` or `>`, found `{` - --> $DIR/unexpected-token.rs:5:27 + --> $DIR/unexpected-token.rs:5:35 | -LL | fn hello() -> impl use<'a {}> Sized {} - | ^ expected one of `,` or `>` +LL | fn hello() -> impl Sized + use<'a {}> {} + | ^ expected one of `,` or `>` -error: expected item, found `>` - --> $DIR/unexpected-token.rs:5:29 - | -LL | fn hello() -> impl use<'a {}> Sized {} - | ^ expected item - | - = note: for a full list of items that can appear in modules, see <https://doc.rust-lang.org/reference/items.html> - -error: aborting due to 2 previous errors +error: aborting due to 1 previous error diff --git a/tests/ui/imports/shadow-glob-module-resolution-3.rs b/tests/ui/imports/shadow-glob-module-resolution-3.rs new file mode 100644 index 00000000000..f5a43373261 --- /dev/null +++ b/tests/ui/imports/shadow-glob-module-resolution-3.rs @@ -0,0 +1,19 @@ +// https://github.com/rust-lang/rust/issues/126389 + +mod a { + pub mod b { + pub mod c {} + } +} + +use a::*; + +use b::c; +//~^ ERROR: unresolved import `b::c` +//~| ERROR: cannot determine resolution for the import +//~| ERROR: cannot determine resolution for the import +use c as b; + +fn c() {} + +fn main() { } diff --git a/tests/ui/imports/shadow-glob-module-resolution-3.stderr b/tests/ui/imports/shadow-glob-module-resolution-3.stderr new file mode 100644 index 00000000000..ab853c71582 --- /dev/null +++ b/tests/ui/imports/shadow-glob-module-resolution-3.stderr @@ -0,0 +1,23 @@ +error: cannot determine resolution for the import + --> $DIR/shadow-glob-module-resolution-3.rs:11:5 + | +LL | use b::c; + | ^^^^ + +error: cannot determine resolution for the import + --> $DIR/shadow-glob-module-resolution-3.rs:11:5 + | +LL | use b::c; + | ^^^^ + | + = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no` + +error[E0432]: unresolved import `b::c` + --> $DIR/shadow-glob-module-resolution-3.rs:11:5 + | +LL | use b::c; + | ^^^^ + +error: aborting due to 3 previous errors + +For more information about this error, try `rustc --explain E0432`. diff --git a/tests/ui/imports/shadow-glob-module-resolution-4.rs b/tests/ui/imports/shadow-glob-module-resolution-4.rs new file mode 100644 index 00000000000..581cdc185d3 --- /dev/null +++ b/tests/ui/imports/shadow-glob-module-resolution-4.rs @@ -0,0 +1,20 @@ +// https://github.com/rust-lang/rust/issues/126376 + +mod a { + pub mod b { + pub trait C {} + } +} + +use a::*; + +use e as b; + +use b::C as e; +//~^ ERROR: unresolved import `b::C` +//~| ERROR: cannot determine resolution for the import +//~| ERROR: cannot determine resolution for the import + +fn e() {} + +fn main() { } diff --git a/tests/ui/imports/shadow-glob-module-resolution-4.stderr b/tests/ui/imports/shadow-glob-module-resolution-4.stderr new file mode 100644 index 00000000000..063beb612b1 --- /dev/null +++ b/tests/ui/imports/shadow-glob-module-resolution-4.stderr @@ -0,0 +1,23 @@ +error: cannot determine resolution for the import + --> $DIR/shadow-glob-module-resolution-4.rs:13:5 + | +LL | use b::C as e; + | ^^^^^^^^^ + +error: cannot determine resolution for the import + --> $DIR/shadow-glob-module-resolution-4.rs:13:5 + | +LL | use b::C as e; + | ^^^^^^^^^ + | + = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no` + +error[E0432]: unresolved import `b::C` + --> $DIR/shadow-glob-module-resolution-4.rs:13:5 + | +LL | use b::C as e; + | ^^^^^^^^^ + +error: aborting due to 3 previous errors + +For more information about this error, try `rustc --explain E0432`. diff --git a/tests/ui/inference/need_type_info/type-alias-indirect.stderr b/tests/ui/inference/need_type_info/type-alias-indirect.stderr index 535c0044aec..5c5b4c149c1 100644 --- a/tests/ui/inference/need_type_info/type-alias-indirect.stderr +++ b/tests/ui/inference/need_type_info/type-alias-indirect.stderr @@ -2,7 +2,7 @@ error[E0282]: type annotations needed --> $DIR/type-alias-indirect.rs:14:5 | LL | IndirectAlias::new(); - | ^^^^^^^^^^^^^ cannot infer type for type parameter `T` declared on the type alias `IndirectAlias` + | ^^^^^^^^^^^^^^^^^^^^ cannot infer type for type parameter `T` declared on the type alias `IndirectAlias` error: aborting due to 1 previous error diff --git a/tests/ui/inference/need_type_info/type-alias.stderr b/tests/ui/inference/need_type_info/type-alias.stderr index 2c39a3f5646..fd9bcf2fe3f 100644 --- a/tests/ui/inference/need_type_info/type-alias.stderr +++ b/tests/ui/inference/need_type_info/type-alias.stderr @@ -2,19 +2,19 @@ error[E0282]: type annotations needed --> $DIR/type-alias.rs:12:5 | LL | DirectAlias::new() - | ^^^^^^^^^^^^^^^^^^ cannot infer type for type parameter `T` + | ^^^^^^^^^^^^^^^^^^ cannot infer type for type parameter `T` declared on the type alias `DirectAlias` error[E0282]: type annotations needed --> $DIR/type-alias.rs:18:5 | LL | IndirectAlias::new(); - | ^^^^^^^^^^^^^ cannot infer type for type parameter `T` declared on the type alias `IndirectAlias` + | ^^^^^^^^^^^^^^^^^^^^ cannot infer type for type parameter `T` declared on the type alias `IndirectAlias` error[E0282]: type annotations needed --> $DIR/type-alias.rs:32:5 | LL | DirectButWithDefaultAlias::new(); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ cannot infer type for type parameter `T` + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ cannot infer type for type parameter `T` declared on the type alias `DirectButWithDefaultAlias` error: aborting due to 3 previous errors diff --git a/tests/ui/instrument-coverage/coverage-options.bad.stderr b/tests/ui/instrument-coverage/coverage-options.bad.stderr index 4a272cf97fb..1a6b30dc832 100644 --- a/tests/ui/instrument-coverage/coverage-options.bad.stderr +++ b/tests/ui/instrument-coverage/coverage-options.bad.stderr @@ -1,2 +1,2 @@ -error: incorrect value `bad` for unstable option `coverage-options` - `block` | `branch` | `condition` | `mcdc` was expected +error: incorrect value `bad` for unstable option `coverage-options` - `block` | `branch` | `condition` | `mcdc` | `no-mir-spans` was expected diff --git a/tests/ui/issues/issue-66706.rs b/tests/ui/issues/issue-66706.rs index 6d1d9f5e3a9..87dc3437a57 100644 --- a/tests/ui/issues/issue-66706.rs +++ b/tests/ui/issues/issue-66706.rs @@ -1,6 +1,6 @@ fn a() { [0; [|_: _ &_| ()].len()] - //~^ ERROR expected `,`, found `&` + //~^ ERROR expected one of `,` or `|`, found `&` //~| ERROR type annotations needed } @@ -11,7 +11,7 @@ fn b() { fn c() { [0; [|&_: _ &_| {}; 0 ].len()] - //~^ ERROR expected `,`, found `&` + //~^ ERROR expected one of `,` or `|`, found `&` //~| ERROR type annotations needed } diff --git a/tests/ui/issues/issue-66706.stderr b/tests/ui/issues/issue-66706.stderr index 0271db754bd..dd1e07589f5 100644 --- a/tests/ui/issues/issue-66706.stderr +++ b/tests/ui/issues/issue-66706.stderr @@ -1,8 +1,8 @@ -error: expected `,`, found `&` +error: expected one of `,` or `|`, found `&` --> $DIR/issue-66706.rs:2:16 | LL | [0; [|_: _ &_| ()].len()] - | -^ expected `,` + | -^ expected one of `,` or `|` | | | help: missing `,` @@ -12,11 +12,11 @@ error: expected identifier, found reserved identifier `_` LL | [0; [|f @ &ref _| {} ; 0 ].len() ]; | ^ expected identifier, found reserved identifier -error: expected `,`, found `&` +error: expected one of `,` or `|`, found `&` --> $DIR/issue-66706.rs:13:17 | LL | [0; [|&_: _ &_| {}; 0 ].len()] - | -^ expected `,` + | -^ expected one of `,` or `|` | | | help: missing `,` diff --git a/tests/ui/lifetimes/refcell-in-tail-expr.edition2021.stderr b/tests/ui/lifetimes/refcell-in-tail-expr.edition2021.stderr new file mode 100644 index 00000000000..858be42d540 --- /dev/null +++ b/tests/ui/lifetimes/refcell-in-tail-expr.edition2021.stderr @@ -0,0 +1,26 @@ +error[E0597]: `cell` does not live long enough + --> $DIR/refcell-in-tail-expr.rs:12:27 + | +LL | let cell = std::cell::RefCell::new(0u8); + | ---- binding `cell` declared here +LL | +LL | if let Ok(mut byte) = cell.try_borrow_mut() { + | ^^^^----------------- + | | + | borrowed value does not live long enough + | a temporary with access to the borrow is created here ... +... +LL | } + | - + | | + | `cell` dropped here while still borrowed + | ... and the borrow might be used here, when that temporary is dropped and runs the destructor for type `Result<RefMut<'_, u8>, BorrowMutError>` + | +help: consider adding semicolon after the expression so its temporaries are dropped sooner, before the local variables declared by the block are dropped + | +LL | }; + | + + +error: aborting due to 1 previous error + +For more information about this error, try `rustc --explain E0597`. diff --git a/tests/ui/lifetimes/refcell-in-tail-expr.rs b/tests/ui/lifetimes/refcell-in-tail-expr.rs new file mode 100644 index 00000000000..b1814c1e327 --- /dev/null +++ b/tests/ui/lifetimes/refcell-in-tail-expr.rs @@ -0,0 +1,16 @@ +//@ revisions: edition2021 edition2024 +//@ [edition2021] edition: 2021 +//@ [edition2024] edition: 2024 +//@ [edition2024] compile-flags: -Zunstable-options +//@ [edition2024] check-pass + +#![cfg_attr(edition2024, feature(shorter_tail_lifetimes))] + +fn main() { + let cell = std::cell::RefCell::new(0u8); + + if let Ok(mut byte) = cell.try_borrow_mut() { + //[edition2021]~^ ERROR: `cell` does not live long enough + *byte = 1; + } +} diff --git a/tests/ui/lifetimes/shorter-tail-expr-lifetime.edition2021.stderr b/tests/ui/lifetimes/shorter-tail-expr-lifetime.edition2021.stderr new file mode 100644 index 00000000000..ad28ae2f80d --- /dev/null +++ b/tests/ui/lifetimes/shorter-tail-expr-lifetime.edition2021.stderr @@ -0,0 +1,26 @@ +error[E0597]: `c` does not live long enough + --> $DIR/shorter-tail-expr-lifetime.rs:10:5 + | +LL | let c = std::cell::RefCell::new(".."); + | - binding `c` declared here +LL | c.borrow().len() + | ^--------- + | | + | borrowed value does not live long enough + | a temporary with access to the borrow is created here ... +LL | } + | - + | | + | `c` dropped here while still borrowed + | ... and the borrow might be used here, when that temporary is dropped and runs the destructor for type `Ref<'_, &str>` + | + = note: the temporary is part of an expression at the end of a block; + consider forcing this temporary to be dropped sooner, before the block's local variables are dropped +help: for example, you could save the expression's value in a new local variable `x` and then make `x` be the expression at the end of the block + | +LL | let x = c.borrow().len(); x + | +++++++ +++ + +error: aborting due to 1 previous error + +For more information about this error, try `rustc --explain E0597`. diff --git a/tests/ui/lifetimes/shorter-tail-expr-lifetime.rs b/tests/ui/lifetimes/shorter-tail-expr-lifetime.rs new file mode 100644 index 00000000000..0392b6c6d9a --- /dev/null +++ b/tests/ui/lifetimes/shorter-tail-expr-lifetime.rs @@ -0,0 +1,15 @@ +//@ revisions: edition2021 edition2024 +//@ [edition2024] compile-flags: -Zunstable-options +//@ [edition2024] edition: 2024 +//@ [edition2024] run-pass + +#![cfg_attr(edition2024, feature(shorter_tail_lifetimes))] + +fn f() -> usize { + let c = std::cell::RefCell::new(".."); + c.borrow().len() //[edition2021]~ ERROR: `c` does not live long enough +} + +fn main() { + let _ = f(); +} diff --git a/tests/ui/lifetimes/tail-expr-in-nested-expr.rs b/tests/ui/lifetimes/tail-expr-in-nested-expr.rs new file mode 100644 index 00000000000..a8989f22f4b --- /dev/null +++ b/tests/ui/lifetimes/tail-expr-in-nested-expr.rs @@ -0,0 +1,9 @@ +//@ edition: 2024 +//@ compile-flags: -Zunstable-options + +#![feature(shorter_tail_lifetimes)] + +fn main() { + let _ = { String::new().as_str() }.len(); + //~^ ERROR temporary value dropped while borrowed +} diff --git a/tests/ui/lifetimes/tail-expr-in-nested-expr.stderr b/tests/ui/lifetimes/tail-expr-in-nested-expr.stderr new file mode 100644 index 00000000000..f699d184bdb --- /dev/null +++ b/tests/ui/lifetimes/tail-expr-in-nested-expr.stderr @@ -0,0 +1,15 @@ +error[E0716]: temporary value dropped while borrowed + --> $DIR/tail-expr-in-nested-expr.rs:7:15 + | +LL | let _ = { String::new().as_str() }.len(); + | ^^^^^^^^^^^^^--------- + | | | + | | temporary value is freed at the end of this statement + | creates a temporary value which is freed while still in use + | borrow later used here + | + = note: consider using a `let` binding to create a longer lived value + +error: aborting due to 1 previous error + +For more information about this error, try `rustc --explain E0716`. diff --git a/tests/ui/lifetimes/tail-expr-lock-poisoning.rs b/tests/ui/lifetimes/tail-expr-lock-poisoning.rs new file mode 100644 index 00000000000..69b8f286d77 --- /dev/null +++ b/tests/ui/lifetimes/tail-expr-lock-poisoning.rs @@ -0,0 +1,29 @@ +//@ revisions: edition2021 edition2024 +//@ ignore-wasm no panic or subprocess support +//@ [edition2024] compile-flags: -Zunstable-options +//@ [edition2024] edition: 2024 +//@ run-pass +#![cfg_attr(edition2024, feature(shorter_tail_lifetimes))] + +use std::sync::Mutex; + +struct PanicOnDrop; +impl Drop for PanicOnDrop { + fn drop(&mut self) { + panic!() + } +} + +fn f(m: &Mutex<i32>) -> i32 { + let _x = PanicOnDrop; + *m.lock().unwrap() +} + +fn main() { + let m = Mutex::new(0); + let _ = std::panic::catch_unwind(|| f(&m)); + #[cfg(edition2024)] + assert!(m.lock().is_ok()); + #[cfg(edition2021)] + assert!(m.lock().is_err()); +} diff --git a/tests/ui/lint/dead-code/tuple-struct-field.rs b/tests/ui/lint/dead-code/tuple-struct-field.rs index d13fe029289..ff3da410500 100644 --- a/tests/ui/lint/dead-code/tuple-struct-field.rs +++ b/tests/ui/lint/dead-code/tuple-struct-field.rs @@ -5,15 +5,20 @@ use std::marker::PhantomData; const LEN: usize = 4; -struct SingleUnused(i32, [u8; LEN], String); -//~^ ERROR: field `1` is never read +struct UnusedAtTheEnd(i32, f32, [u8; LEN], String, u8); +//~^ ERROR:fields `1`, `2`, `3`, and `4` are never read +//~| NOTE: fields in this struct +//~| HELP: consider removing these fields + +struct UnusedJustOneField(i32); +//~^ ERROR: field `0` is never read //~| NOTE: field in this struct -//~| HELP: consider changing the field to be of unit type +//~| HELP: consider removing this field -struct MultipleUnused(i32, f32, String, u8); -//~^ ERROR: fields `0`, `1`, `2`, and `3` are never read +struct UnusedInTheMiddle(i32, f32, String, u8, u32); +//~^ ERROR: fields `1`, `2`, and `4` are never read //~| NOTE: fields in this struct -//~| HELP: consider changing the fields to be of unit type +//~| HELP: consider changing the fields to be of unit type to suppress this warning while preserving the field numbering, or remove the fields struct GoodUnit(()); @@ -23,15 +28,19 @@ struct Void; struct GoodVoid(Void); fn main() { - let w = SingleUnused(42, [0, 1, 2, 3], "abc".to_string()); - let _ = w.0; - let _ = w.2; + let u1 = UnusedAtTheEnd(42, 3.14, [0, 1, 2, 3], "def".to_string(), 4u8); + let _ = u1.0; + + let _ = UnusedJustOneField(42); + + let u2 = UnusedInTheMiddle(42, 3.14, "def".to_string(), 4u8, 5); + let _ = u2.0; + let _ = u2.3; - let m = MultipleUnused(42, 3.14, "def".to_string(), 4u8); let gu = GoodUnit(()); let gp = GoodPhantom(PhantomData); let gv = GoodVoid(Void); - let _ = (gu, gp, gv, m); + let _ = (gu, gp, gv); } diff --git a/tests/ui/lint/dead-code/tuple-struct-field.stderr b/tests/ui/lint/dead-code/tuple-struct-field.stderr index 0154d5489f9..434554d7ae5 100644 --- a/tests/ui/lint/dead-code/tuple-struct-field.stderr +++ b/tests/ui/lint/dead-code/tuple-struct-field.stderr @@ -1,33 +1,40 @@ -error: field `1` is never read - --> $DIR/tuple-struct-field.rs:8:26 +error: fields `1`, `2`, `3`, and `4` are never read + --> $DIR/tuple-struct-field.rs:8:28 | -LL | struct SingleUnused(i32, [u8; LEN], String); - | ------------ ^^^^^^^^^ +LL | struct UnusedAtTheEnd(i32, f32, [u8; LEN], String, u8); + | -------------- ^^^ ^^^^^^^^^ ^^^^^^ ^^ | | - | field in this struct + | fields in this struct | + = help: consider removing these fields note: the lint level is defined here --> $DIR/tuple-struct-field.rs:1:9 | LL | #![deny(dead_code)] | ^^^^^^^^^ -help: consider changing the field to be of unit type to suppress this warning while preserving the field numbering, or remove the field + +error: field `0` is never read + --> $DIR/tuple-struct-field.rs:13:27 + | +LL | struct UnusedJustOneField(i32); + | ------------------ ^^^ + | | + | field in this struct | -LL | struct SingleUnused(i32, (), String); - | ~~ + = help: consider removing this field -error: fields `0`, `1`, `2`, and `3` are never read - --> $DIR/tuple-struct-field.rs:13:23 +error: fields `1`, `2`, and `4` are never read + --> $DIR/tuple-struct-field.rs:18:31 | -LL | struct MultipleUnused(i32, f32, String, u8); - | -------------- ^^^ ^^^ ^^^^^^ ^^ +LL | struct UnusedInTheMiddle(i32, f32, String, u8, u32); + | ----------------- ^^^ ^^^^^^ ^^^ | | | fields in this struct | help: consider changing the fields to be of unit type to suppress this warning while preserving the field numbering, or remove the fields | -LL | struct MultipleUnused((), (), (), ()); - | ~~ ~~ ~~ ~~ +LL | struct UnusedInTheMiddle(i32, (), (), u8, ()); + | ~~ ~~ ~~ -error: aborting due to 2 previous errors +error: aborting due to 3 previous errors diff --git a/tests/ui/nll/issue-52534-1.rs b/tests/ui/nll/issue-52534-1.rs index d9ea3ae42c4..526b81bb2d0 100644 --- a/tests/ui/nll/issue-52534-1.rs +++ b/tests/ui/nll/issue-52534-1.rs @@ -17,14 +17,14 @@ fn foo(x: &u32) -> &u32 { fn baz(x: &u32) -> &&u32 { let x = 22; &&x -//~^ ERROR cannot return value referencing local variable +//~^ ERROR cannot return value referencing local variable `x` //~| ERROR cannot return reference to temporary value } fn foobazbar<'a>(x: u32, y: &'a u32) -> &'a u32 { let x = 22; &x -//~^ ERROR cannot return reference to local variable +//~^ ERROR cannot return reference to local variable `x` } fn foobar<'a>(x: &'a u32) -> &'a u32 { diff --git a/tests/ui/or-patterns/bindings-runpass-2.rs b/tests/ui/or-patterns/bindings-runpass-2.rs index 657d7f1ed18..a9ae9981084 100644 --- a/tests/ui/or-patterns/bindings-runpass-2.rs +++ b/tests/ui/or-patterns/bindings-runpass-2.rs @@ -26,5 +26,6 @@ fn main() { assert_eq!(or_at(Err(7)), 207); assert_eq!(or_at(Err(8)), 8); assert_eq!(or_at(Err(20)), 220); + assert_eq!(or_at(Err(34)), 134); assert_eq!(or_at(Err(50)), 500); } diff --git a/tests/ui/or-patterns/inner-or-pat.or3.stderr b/tests/ui/or-patterns/inner-or-pat.or3.stderr index 10ec7c202e4..5c522a97cce 100644 --- a/tests/ui/or-patterns/inner-or-pat.or3.stderr +++ b/tests/ui/or-patterns/inner-or-pat.or3.stderr @@ -1,5 +1,5 @@ error[E0308]: mismatched types - --> $DIR/inner-or-pat.rs:38:54 + --> $DIR/inner-or-pat.rs:36:54 | LL | match x { | - this expression has type `&str` diff --git a/tests/ui/or-patterns/inner-or-pat.or4.stderr b/tests/ui/or-patterns/inner-or-pat.or4.stderr index 97800161d82..508520c8237 100644 --- a/tests/ui/or-patterns/inner-or-pat.or4.stderr +++ b/tests/ui/or-patterns/inner-or-pat.or4.stderr @@ -1,5 +1,5 @@ error[E0408]: variable `x` is not bound in all patterns - --> $DIR/inner-or-pat.rs:53:37 + --> $DIR/inner-or-pat.rs:51:37 | LL | (x @ "red" | (x @ "blue" | "red")) => { | - ^^^^^ pattern doesn't bind `x` diff --git a/tests/ui/or-patterns/inner-or-pat.rs b/tests/ui/or-patterns/inner-or-pat.rs index ceb0a8b3f79..4d136de0053 100644 --- a/tests/ui/or-patterns/inner-or-pat.rs +++ b/tests/ui/or-patterns/inner-or-pat.rs @@ -1,7 +1,5 @@ -//@ revisions: or1 or2 or3 or4 or5 +//@ revisions: or1 or3 or4 //@ [or1] run-pass -//@ [or2] run-pass -//@ [or5] run-pass #![allow(unreachable_patterns)] #![allow(unused_variables)] diff --git a/tests/ui/or-patterns/issue-70413-no-unreachable-pat-and-guard.rs b/tests/ui/or-patterns/issue-70413-no-unreachable-pat-and-guard.rs index 7d62364a6ae..76dc298a5c8 100644 --- a/tests/ui/or-patterns/issue-70413-no-unreachable-pat-and-guard.rs +++ b/tests/ui/or-patterns/issue-70413-no-unreachable-pat-and-guard.rs @@ -1,21 +1,20 @@ -//@ check-pass +//@ run-pass #![deny(unreachable_patterns)] fn main() { - match (3,42) { - (a,_) | (_,a) if a > 10 => {println!("{}", a)} - _ => () + match (3, 42) { + (a, _) | (_, a) if a > 10 => {} + _ => unreachable!(), } - match Some((3,42)) { - Some((a, _)) | Some((_, a)) if a > 10 => {println!("{}", a)} - _ => () - + match Some((3, 42)) { + Some((a, _)) | Some((_, a)) if a > 10 => {} + _ => unreachable!(), } - match Some((3,42)) { - Some((a, _) | (_, a)) if a > 10 => {println!("{}", a)} - _ => () + match Some((3, 42)) { + Some((a, _) | (_, a)) if a > 10 => {} + _ => unreachable!(), } } diff --git a/tests/ui/or-patterns/search-via-bindings.rs b/tests/ui/or-patterns/search-via-bindings.rs index a760112f1d4..42174bd7cef 100644 --- a/tests/ui/or-patterns/search-via-bindings.rs +++ b/tests/ui/or-patterns/search-via-bindings.rs @@ -42,6 +42,23 @@ fn search_old_style(target: (bool, bool, bool)) -> u32 { } } +// Check that a dummy or-pattern also leads to running the guard multiple times. +fn search_with_dummy(target: (bool, bool)) -> u32 { + let x = ((false, true), (false, true), ()); + let mut guard_count = 0; + match x { + ((a, _) | (_, a), (b, _) | (_, b), _ | _) + if { + guard_count += 1; + (a, b) == target + } => + { + guard_count + } + _ => unreachable!(), + } +} + fn main() { assert_eq!(search((false, false, false)), 1); assert_eq!(search((false, false, true)), 2); @@ -60,4 +77,9 @@ fn main() { assert_eq!(search_old_style((true, false, true)), 6); assert_eq!(search_old_style((true, true, false)), 7); assert_eq!(search_old_style((true, true, true)), 8); + + assert_eq!(search_with_dummy((false, false)), 1); + assert_eq!(search_with_dummy((false, true)), 3); + assert_eq!(search_with_dummy((true, false)), 5); + assert_eq!(search_with_dummy((true, true)), 7); } diff --git a/tests/ui/or-patterns/simplification_subtleties.rs b/tests/ui/or-patterns/simplification_subtleties.rs new file mode 100644 index 00000000000..a932bd531e6 --- /dev/null +++ b/tests/ui/or-patterns/simplification_subtleties.rs @@ -0,0 +1,11 @@ +//@ run-pass + +#[allow(unreachable_patterns)] +fn main() { + // Test that we don't naively sort the two `2`s together and confuse the failure paths. + match (1, true) { + (1 | 2, false | false) => unreachable!(), + (2, _) => unreachable!(), + _ => {} + } +} diff --git a/tests/ui/parser/trait-object-delimiters.rs b/tests/ui/parser/trait-object-delimiters.rs index d6bc629aa11..8f6221c1b94 100644 --- a/tests/ui/parser/trait-object-delimiters.rs +++ b/tests/ui/parser/trait-object-delimiters.rs @@ -8,7 +8,7 @@ fn foo2(_: &dyn (Drop + AsRef<str>)) {} //~ ERROR incorrect parentheses around t fn foo2_no_space(_: &dyn(Drop + AsRef<str>)) {} //~ ERROR incorrect parentheses around trait bounds fn foo3(_: &dyn {Drop + AsRef<str>}) {} //~ ERROR expected parameter name, found `{` -//~^ ERROR expected one of `!`, `(`, `)`, `*`, `,`, `?`, `async`, `const`, `for`, `~`, lifetime, or path, found `{` +//~^ ERROR expected one of `!`, `(`, `)`, `*`, `,`, `?`, `async`, `const`, `for`, `use`, `~`, lifetime, or path, found `{` //~| ERROR at least one trait is required for an object type fn foo4(_: &dyn <Drop + AsRef<str>>) {} //~ ERROR expected identifier, found `<` diff --git a/tests/ui/parser/trait-object-delimiters.stderr b/tests/ui/parser/trait-object-delimiters.stderr index 2b1f8df991f..5f175e86545 100644 --- a/tests/ui/parser/trait-object-delimiters.stderr +++ b/tests/ui/parser/trait-object-delimiters.stderr @@ -34,11 +34,11 @@ error: expected parameter name, found `{` LL | fn foo3(_: &dyn {Drop + AsRef<str>}) {} | ^ expected parameter name -error: expected one of `!`, `(`, `)`, `*`, `,`, `?`, `async`, `const`, `for`, `~`, lifetime, or path, found `{` +error: expected one of `!`, `(`, `)`, `*`, `,`, `?`, `async`, `const`, `for`, `use`, `~`, lifetime, or path, found `{` --> $DIR/trait-object-delimiters.rs:10:17 | LL | fn foo3(_: &dyn {Drop + AsRef<str>}) {} - | -^ expected one of 12 possible tokens + | -^ expected one of 13 possible tokens | | | help: missing `,` diff --git a/tests/crashes/122736.rs b/tests/ui/privacy/no-ice-on-inference-failure.rs index 83b60444c2f..e63b7bff9bc 100644 --- a/tests/crashes/122736.rs +++ b/tests/ui/privacy/no-ice-on-inference-failure.rs @@ -1,9 +1,9 @@ -//@ known-bug: #122736 fn main_ref() { let array = [(); { let mut x = &0; let mut n = 0; while n < 5 { + //~^ ERROR constant evaluation is taking a long time x = &0; } 0 diff --git a/tests/ui/privacy/no-ice-on-inference-failure.stderr b/tests/ui/privacy/no-ice-on-inference-failure.stderr new file mode 100644 index 00000000000..67476e6e218 --- /dev/null +++ b/tests/ui/privacy/no-ice-on-inference-failure.stderr @@ -0,0 +1,27 @@ +error: constant evaluation is taking a long time + --> $DIR/no-ice-on-inference-failure.rs:5:9 + | +LL | / while n < 5 { +LL | | +LL | | x = &0; +LL | | } + | |_________^ + | + = note: this lint makes sure the compiler doesn't get stuck due to infinite loops in const eval. + If your compilation actually takes a long time, you can safely allow the lint. +help: the constant being evaluated + --> $DIR/no-ice-on-inference-failure.rs:2:22 + | +LL | let array = [(); { + | ______________________^ +LL | | let mut x = &0; +LL | | let mut n = 0; +LL | | while n < 5 { +... | +LL | | 0 +LL | | }]; + | |_____^ + = note: `#[deny(long_running_const_eval)]` on by default + +error: aborting due to 1 previous error + diff --git a/tests/ui/return/return-ty-mismatch-note.rs b/tests/ui/return/return-ty-mismatch-note.rs index 352bc2a1637..36d590519fb 100644 --- a/tests/ui/return/return-ty-mismatch-note.rs +++ b/tests/ui/return/return-ty-mismatch-note.rs @@ -1,4 +1,5 @@ -// Checks existence of a note for "a caller chooses ty for ty param" upon return ty mismatch. +// Checks existence or absence of a note for "a caller chooses ty for ty param" upon return ty +// mismatch. fn f<T>() -> (T,) { (0,) //~ ERROR mismatched types @@ -14,6 +15,14 @@ fn h() -> u8 { 0u8 } +// This case was reported in <https://github.com/rust-lang/rust/issues/126547> where it doesn't +// make sense to make the "note caller chooses ty for ty param" note if the found type contains +// the ty param... +fn k<T>(_t: &T) -> T { + _t + //~^ ERROR mismatched types +} + fn main() { f::<()>(); g::<(), ()>; diff --git a/tests/ui/return/return-ty-mismatch-note.stderr b/tests/ui/return/return-ty-mismatch-note.stderr index 135903da5c2..47ef6863063 100644 --- a/tests/ui/return/return-ty-mismatch-note.stderr +++ b/tests/ui/return/return-ty-mismatch-note.stderr @@ -1,5 +1,5 @@ error[E0308]: mismatched types - --> $DIR/return-ty-mismatch-note.rs:4:6 + --> $DIR/return-ty-mismatch-note.rs:5:6 | LL | fn f<T>() -> (T,) { | - expected this type parameter @@ -10,7 +10,7 @@ LL | (0,) found type `{integer}` error[E0308]: mismatched types - --> $DIR/return-ty-mismatch-note.rs:8:6 + --> $DIR/return-ty-mismatch-note.rs:9:6 | LL | fn g<U, V>() -> (U, V) { | - expected this type parameter @@ -21,7 +21,7 @@ LL | (0, "foo") found type `{integer}` error[E0308]: mismatched types - --> $DIR/return-ty-mismatch-note.rs:8:9 + --> $DIR/return-ty-mismatch-note.rs:9:9 | LL | fn g<U, V>() -> (U, V) { | - expected this type parameter @@ -31,6 +31,19 @@ LL | (0, "foo") = note: expected type parameter `V` found reference `&'static str` -error: aborting due to 3 previous errors +error[E0308]: mismatched types + --> $DIR/return-ty-mismatch-note.rs:22:5 + | +LL | fn k<T>(_t: &T) -> T { + | - - expected `T` because of return type + | | + | expected this type parameter +LL | _t + | ^^ expected type parameter `T`, found `&T` + | + = note: expected type parameter `_` + found reference `&_` + +error: aborting due to 4 previous errors For more information about this error, try `rustc --explain E0308`. diff --git a/tests/ui/statics/const_generics.rs b/tests/ui/statics/const_generics.rs new file mode 100644 index 00000000000..70d9b933a76 --- /dev/null +++ b/tests/ui/statics/const_generics.rs @@ -0,0 +1,26 @@ +//! Check that we lose the information that `BAR` points to `FOO` +//! when going through a const generic. +//! This is not an intentional guarantee, it just describes the status quo. + +//@ run-pass +// With optimizations, LLVM will deduplicate the constant `X` whose +// value is `&42` to just be a reference to the static. This is correct, +// but obscures the issue we're trying to show. +//@ revisions: opt noopt +//@[noopt] compile-flags: -Copt-level=0 +//@[opt] compile-flags: -O + +#![feature(const_refs_to_static)] +#![feature(adt_const_params)] +#![allow(incomplete_features)] + +static FOO: usize = 42; +const BAR: &usize = &FOO; +fn foo<const X: &'static usize>() { + // Without optimizations, `X` ends up pointing to a copy of `FOO` instead of `FOO` itself. + assert_eq!(cfg!(opt), std::ptr::eq(X, &FOO)); +} + +fn main() { + foo::<BAR>(); +} diff --git a/tests/ui/suggestions/clone-on-unconstrained-borrowed-type-param.stderr b/tests/ui/suggestions/clone-on-unconstrained-borrowed-type-param.stderr index 2c4be26a82b..afbb9c32d51 100644 --- a/tests/ui/suggestions/clone-on-unconstrained-borrowed-type-param.stderr +++ b/tests/ui/suggestions/clone-on-unconstrained-borrowed-type-param.stderr @@ -10,7 +10,6 @@ LL | t.clone() | = note: expected type parameter `_` found reference `&_` - = note: the caller chooses a type for `T` which can be different from `&T` note: `T` does not implement `Clone`, so `&T` was cloned instead --> $DIR/clone-on-unconstrained-borrowed-type-param.rs:3:5 | diff --git a/tests/ui/suggestions/missing-lifetime-in-assoc-const-type.default.stderr b/tests/ui/suggestions/missing-lifetime-in-assoc-const-type.default.stderr index 24e2e0a0f7a..71ac55bf044 100644 --- a/tests/ui/suggestions/missing-lifetime-in-assoc-const-type.default.stderr +++ b/tests/ui/suggestions/missing-lifetime-in-assoc-const-type.default.stderr @@ -1,57 +1,25 @@ -error[E0106]: missing lifetime specifier - --> $DIR/missing-lifetime-in-assoc-const-type.rs:6:14 - | -LL | const A: &str = ""; - | ^ expected named lifetime parameter - | -help: consider introducing a named lifetime parameter - | -LL ~ trait ZstAssert<'a>: Sized { -LL ~ const A: &'a str = ""; - | - -error[E0106]: missing lifetime specifier +error[E0726]: implicit elided lifetime not allowed here --> $DIR/missing-lifetime-in-assoc-const-type.rs:7:14 | LL | const B: S = S { s: &() }; - | ^ expected named lifetime parameter - | -help: consider introducing a named lifetime parameter - | -LL ~ trait ZstAssert<'a>: Sized { -LL | const A: &str = ""; -LL ~ const B: S<'a> = S { s: &() }; + | ^ expected lifetime parameter | - -error[E0106]: missing lifetime specifier - --> $DIR/missing-lifetime-in-assoc-const-type.rs:8:15 - | -LL | const C: &'_ str = ""; - | ^^ expected named lifetime parameter - | -help: consider introducing a named lifetime parameter - | -LL ~ trait ZstAssert<'a>: Sized { -LL | const A: &str = ""; -LL | const B: S = S { s: &() }; -LL ~ const C: &'a str = ""; +help: indicate the anonymous lifetime | +LL | const B: S<'_> = S { s: &() }; + | ++++ -error[E0106]: missing lifetime specifiers +error[E0726]: implicit elided lifetime not allowed here --> $DIR/missing-lifetime-in-assoc-const-type.rs:9:14 | LL | const D: T = T { a: &(), b: &() }; - | ^ expected 2 lifetime parameters - | -help: consider introducing a named lifetime parameter + | ^ expected lifetime parameters | -LL ~ trait ZstAssert<'a>: Sized { -LL | const A: &str = ""; -LL | const B: S = S { s: &() }; -LL | const C: &'_ str = ""; -LL ~ const D: T<'a, 'a> = T { a: &(), b: &() }; +help: indicate the anonymous lifetimes | +LL | const D: T<'_, '_> = T { a: &(), b: &() }; + | ++++++++ -error: aborting due to 4 previous errors +error: aborting due to 2 previous errors -For more information about this error, try `rustc --explain E0106`. +For more information about this error, try `rustc --explain E0726`. diff --git a/tests/ui/suggestions/missing-lifetime-in-assoc-const-type.generic_const_items.stderr b/tests/ui/suggestions/missing-lifetime-in-assoc-const-type.generic_const_items.stderr index a97ffe7da79..71ac55bf044 100644 --- a/tests/ui/suggestions/missing-lifetime-in-assoc-const-type.generic_const_items.stderr +++ b/tests/ui/suggestions/missing-lifetime-in-assoc-const-type.generic_const_items.stderr @@ -1,47 +1,25 @@ -error[E0106]: missing lifetime specifier - --> $DIR/missing-lifetime-in-assoc-const-type.rs:6:14 - | -LL | const A: &str = ""; - | ^ expected named lifetime parameter - | -help: consider introducing a named lifetime parameter - | -LL | const A<'a>: &'a str = ""; - | ++++ ++ - -error[E0106]: missing lifetime specifier +error[E0726]: implicit elided lifetime not allowed here --> $DIR/missing-lifetime-in-assoc-const-type.rs:7:14 | LL | const B: S = S { s: &() }; - | ^ expected named lifetime parameter - | -help: consider introducing a named lifetime parameter - | -LL | const B<'a>: S<'a> = S { s: &() }; - | ++++ ++++ - -error[E0106]: missing lifetime specifier - --> $DIR/missing-lifetime-in-assoc-const-type.rs:8:15 - | -LL | const C: &'_ str = ""; - | ^^ expected named lifetime parameter + | ^ expected lifetime parameter | -help: consider introducing a named lifetime parameter +help: indicate the anonymous lifetime | -LL | const C<'a>: &'a str = ""; - | ++++ ~~ +LL | const B: S<'_> = S { s: &() }; + | ++++ -error[E0106]: missing lifetime specifiers +error[E0726]: implicit elided lifetime not allowed here --> $DIR/missing-lifetime-in-assoc-const-type.rs:9:14 | LL | const D: T = T { a: &(), b: &() }; - | ^ expected 2 lifetime parameters + | ^ expected lifetime parameters | -help: consider introducing a named lifetime parameter +help: indicate the anonymous lifetimes | -LL | const D<'a>: T<'a, 'a> = T { a: &(), b: &() }; - | ++++ ++++++++ +LL | const D: T<'_, '_> = T { a: &(), b: &() }; + | ++++++++ -error: aborting due to 4 previous errors +error: aborting due to 2 previous errors -For more information about this error, try `rustc --explain E0106`. +For more information about this error, try `rustc --explain E0726`. diff --git a/tests/ui/suggestions/missing-lifetime-in-assoc-const-type.rs b/tests/ui/suggestions/missing-lifetime-in-assoc-const-type.rs index f36a6567e42..a60f0b94587 100644 --- a/tests/ui/suggestions/missing-lifetime-in-assoc-const-type.rs +++ b/tests/ui/suggestions/missing-lifetime-in-assoc-const-type.rs @@ -3,10 +3,10 @@ #![cfg_attr(generic_const_items, feature(generic_const_items), allow(incomplete_features))] trait ZstAssert: Sized { - const A: &str = ""; //~ ERROR missing lifetime specifier - const B: S = S { s: &() }; //~ ERROR missing lifetime specifier - const C: &'_ str = ""; //~ ERROR missing lifetime specifier - const D: T = T { a: &(), b: &() }; //~ ERROR missing lifetime specifier + const A: &str = ""; + const B: S = S { s: &() }; //~ ERROR implicit elided lifetime not allowed here + const C: &'_ str = ""; + const D: T = T { a: &(), b: &() }; //~ ERROR implicit elided lifetime not allowed here } struct S<'a> { diff --git a/tests/ui/suggestions/mut-borrow-needed-by-trait.rs b/tests/ui/suggestions/mut-borrow-needed-by-trait.rs index 66e1e77c905..924bfd82eb8 100644 --- a/tests/ui/suggestions/mut-borrow-needed-by-trait.rs +++ b/tests/ui/suggestions/mut-borrow-needed-by-trait.rs @@ -17,6 +17,7 @@ fn main() { let fp = BufWriter::new(fp); //~^ ERROR the trait bound `&dyn std::io::Write: std::io::Write` is not satisfied //~| ERROR the trait bound `&dyn std::io::Write: std::io::Write` is not satisfied + //~| ERROR the trait bound `&dyn std::io::Write: std::io::Write` is not satisfied writeln!(fp, "hello world").unwrap(); //~ ERROR the method } diff --git a/tests/ui/suggestions/mut-borrow-needed-by-trait.stderr b/tests/ui/suggestions/mut-borrow-needed-by-trait.stderr index 09a9b1d3b34..b2f9150142f 100644 --- a/tests/ui/suggestions/mut-borrow-needed-by-trait.stderr +++ b/tests/ui/suggestions/mut-borrow-needed-by-trait.stderr @@ -14,6 +14,16 @@ error[E0277]: the trait bound `&dyn std::io::Write: std::io::Write` is not satis --> $DIR/mut-borrow-needed-by-trait.rs:17:14 | LL | let fp = BufWriter::new(fp); + | ^^^^^^^^^ the trait `std::io::Write` is not implemented for `&dyn std::io::Write` + | + = note: `std::io::Write` is implemented for `&mut dyn std::io::Write`, but not for `&dyn std::io::Write` +note: required by a bound in `BufWriter` + --> $SRC_DIR/std/src/io/buffered/bufwriter.rs:LL:COL + +error[E0277]: the trait bound `&dyn std::io::Write: std::io::Write` is not satisfied + --> $DIR/mut-borrow-needed-by-trait.rs:17:14 + | +LL | let fp = BufWriter::new(fp); | ^^^^^^^^^^^^^^^^^^ the trait `std::io::Write` is not implemented for `&dyn std::io::Write` | = note: `std::io::Write` is implemented for `&mut dyn std::io::Write`, but not for `&dyn std::io::Write` @@ -21,13 +31,13 @@ note: required by a bound in `BufWriter` --> $SRC_DIR/std/src/io/buffered/bufwriter.rs:LL:COL error[E0599]: the method `write_fmt` exists for struct `BufWriter<&dyn Write>`, but its trait bounds were not satisfied - --> $DIR/mut-borrow-needed-by-trait.rs:21:14 + --> $DIR/mut-borrow-needed-by-trait.rs:22:14 | LL | writeln!(fp, "hello world").unwrap(); | ---------^^---------------- method cannot be called on `BufWriter<&dyn Write>` due to unsatisfied trait bounds | note: must implement `io::Write`, `fmt::Write`, or have a `write_fmt` method - --> $DIR/mut-borrow-needed-by-trait.rs:21:14 + --> $DIR/mut-borrow-needed-by-trait.rs:22:14 | LL | writeln!(fp, "hello world").unwrap(); | ^^ @@ -35,7 +45,7 @@ LL | writeln!(fp, "hello world").unwrap(); `&dyn std::io::Write: std::io::Write` which is required by `BufWriter<&dyn std::io::Write>: std::io::Write` -error: aborting due to 3 previous errors +error: aborting due to 4 previous errors Some errors have detailed explanations: E0277, E0599. For more information about an error, try `rustc --explain E0277`. diff --git a/tests/ui/traits/item-privacy.stderr b/tests/ui/traits/item-privacy.stderr index d313f5af806..fd474fac155 100644 --- a/tests/ui/traits/item-privacy.stderr +++ b/tests/ui/traits/item-privacy.stderr @@ -8,10 +8,7 @@ LL | S.a(); | ^ | = help: items from traits can only be used if the trait is implemented and in scope -help: trait `A` which provides `a` is implemented but not in scope; perhaps you want to import it - | -LL + use method::A; - | + = help: trait `method::A` which provides `a` is implemented but not reachable help: there is a method `b` with a similar name | LL | S.b(); @@ -58,15 +55,12 @@ LL | S::a(&S); | ^ function or associated item not found in `S` | = help: items from traits can only be used if the trait is implemented and in scope + = help: trait `method::A` which provides `a` is implemented but not reachable help: there is an associated constant `B` with a similar name --> $DIR/item-privacy.rs:29:9 | LL | const B: u8 = 0; | ^^^^^^^^^^^ -help: trait `A` which provides `a` is implemented but not in scope; perhaps you want to import it - | -LL + use method::A; - | error[E0599]: no function or associated item named `b` found for struct `S` in the current scope --> $DIR/item-privacy.rs:80:8 @@ -107,10 +101,7 @@ LL | S::A; | ^ associated item not found in `S` | = help: items from traits can only be used if the trait is implemented and in scope -help: trait `A` which provides `A` is implemented but not in scope; perhaps you want to import it - | -LL + use assoc_const::A; - | + = help: trait `assoc_const::A` which provides `A` is implemented but not reachable help: there is an associated constant `B` with a similar name | LL | S::B; diff --git a/tests/ui/traits/next-solver/issue-118950-root-region.stderr b/tests/ui/traits/next-solver/issue-118950-root-region.stderr index 04c44276195..17da1f52479 100644 --- a/tests/ui/traits/next-solver/issue-118950-root-region.stderr +++ b/tests/ui/traits/next-solver/issue-118950-root-region.stderr @@ -25,10 +25,10 @@ help: this trait has no implementations, consider adding one LL | trait ToUnit<'a> { | ^^^^^^^^^^^^^^^^ - WARN rustc_infer::infer::relate::generalize may incompletely handle alias type: AliasTy { args: ['^0.Named(DefId(0:15 ~ issue_118950_root_region[d54f]::{impl#1}::'a), "'a"), ?1t], def_id: DefId(0:8 ~ issue_118950_root_region[d54f]::Assoc), _use_alias_ty_new_instead: () } - WARN rustc_infer::infer::relate::generalize may incompletely handle alias type: AliasTy { args: ['^0.Named(DefId(0:15 ~ issue_118950_root_region[d54f]::{impl#1}::'a), "'a"), ?1t], def_id: DefId(0:8 ~ issue_118950_root_region[d54f]::Assoc), _use_alias_ty_new_instead: () } - WARN rustc_infer::infer::relate::generalize may incompletely handle alias type: AliasTy { args: ['^0.Named(DefId(0:15 ~ issue_118950_root_region[d54f]::{impl#1}::'a), "'a"), ?1t], def_id: DefId(0:8 ~ issue_118950_root_region[d54f]::Assoc), _use_alias_ty_new_instead: () } - WARN rustc_infer::infer::relate::generalize may incompletely handle alias type: AliasTy { args: ['^0.Named(DefId(0:15 ~ issue_118950_root_region[d54f]::{impl#1}::'a), "'a"), ?1t], def_id: DefId(0:8 ~ issue_118950_root_region[d54f]::Assoc), _use_alias_ty_new_instead: () } + WARN rustc_infer::infer::relate::generalize may incompletely handle alias type: AliasTy { args: ['^0.Named(DefId(0:15 ~ issue_118950_root_region[d54f]::{impl#1}::'a), "'a"), ?1t], def_id: DefId(0:8 ~ issue_118950_root_region[d54f]::Assoc) } + WARN rustc_infer::infer::relate::generalize may incompletely handle alias type: AliasTy { args: ['^0.Named(DefId(0:15 ~ issue_118950_root_region[d54f]::{impl#1}::'a), "'a"), ?1t], def_id: DefId(0:8 ~ issue_118950_root_region[d54f]::Assoc) } + WARN rustc_infer::infer::relate::generalize may incompletely handle alias type: AliasTy { args: ['^0.Named(DefId(0:15 ~ issue_118950_root_region[d54f]::{impl#1}::'a), "'a"), ?1t], def_id: DefId(0:8 ~ issue_118950_root_region[d54f]::Assoc) } + WARN rustc_infer::infer::relate::generalize may incompletely handle alias type: AliasTy { args: ['^0.Named(DefId(0:15 ~ issue_118950_root_region[d54f]::{impl#1}::'a), "'a"), ?1t], def_id: DefId(0:8 ~ issue_118950_root_region[d54f]::Assoc) } error[E0119]: conflicting implementations of trait `Overlap<fn(_)>` for type `fn(_)` --> $DIR/issue-118950-root-region.rs:19:1 | diff --git a/tests/ui/transmutability/enums/uninhabited_optimization.rs b/tests/ui/transmutability/enums/uninhabited_optimization.rs index 04a8eb40c8b..c2d5b67ab2c 100644 --- a/tests/ui/transmutability/enums/uninhabited_optimization.rs +++ b/tests/ui/transmutability/enums/uninhabited_optimization.rs @@ -19,8 +19,14 @@ enum SingleUninhabited { Y(Uninhabited), } +enum MultipleUninhabited { + X(u8, Uninhabited), + Y(Uninhabited, u16), +} + fn main() { assert_transmutable::<Uninhabited>(); assert_transmutable::<SingleInhabited>(); assert_transmutable::<SingleUninhabited>(); + assert_transmutable::<MultipleUninhabited>(); } diff --git a/tests/ui/transmutability/uninhabited.rs b/tests/ui/transmutability/uninhabited.rs index b61b110f6a1..7524922c16a 100644 --- a/tests/ui/transmutability/uninhabited.rs +++ b/tests/ui/transmutability/uninhabited.rs @@ -30,7 +30,7 @@ fn void() { } // Non-ZST uninhabited types are, nonetheless, uninhabited. -fn yawning_void() { +fn yawning_void_struct() { enum Void {} struct YawningVoid(Void, u128); @@ -49,6 +49,28 @@ fn yawning_void() { assert::is_maybe_transmutable::<(), Void>(); //~ ERROR: cannot be safely transmuted } +// Non-ZST uninhabited types are, nonetheless, uninhabited. +fn yawning_void_enum() { + enum Void {} + + enum YawningVoid { + A(Void, u128), + } + + const _: () = { + assert!(std::mem::size_of::<YawningVoid>() == std::mem::size_of::<u128>()); + // Just to be sure the above constant actually evaluated: + assert!(false); //~ ERROR: evaluation of constant value failed + }; + + // This transmutation is vacuously acceptable; since one cannot construct a + // `Void`, unsoundness cannot directly arise from transmuting a void into + // anything else. + assert::is_maybe_transmutable::<YawningVoid, u128>(); + + assert::is_maybe_transmutable::<(), Void>(); //~ ERROR: cannot be safely transmuted +} + // References to uninhabited types are, logically, uninhabited, but for layout // purposes are not ZSTs, and aren't treated as uninhabited when they appear in // enum variants. diff --git a/tests/ui/transmutability/uninhabited.stderr b/tests/ui/transmutability/uninhabited.stderr index 60219b0f263..88a98c798fc 100644 --- a/tests/ui/transmutability/uninhabited.stderr +++ b/tests/ui/transmutability/uninhabited.stderr @@ -7,10 +7,18 @@ LL | assert!(false); = note: this error originates in the macro `assert` (in Nightly builds, run with -Z macro-backtrace for more info) error[E0080]: evaluation of constant value failed - --> $DIR/uninhabited.rs:65:9 + --> $DIR/uninhabited.rs:63:9 | LL | assert!(false); - | ^^^^^^^^^^^^^^ the evaluated program panicked at 'assertion failed: false', $DIR/uninhabited.rs:65:9 + | ^^^^^^^^^^^^^^ the evaluated program panicked at 'assertion failed: false', $DIR/uninhabited.rs:63:9 + | + = note: this error originates in the macro `assert` (in Nightly builds, run with -Z macro-backtrace for more info) + +error[E0080]: evaluation of constant value failed + --> $DIR/uninhabited.rs:87:9 + | +LL | assert!(false); + | ^^^^^^^^^^^^^^ the evaluated program panicked at 'assertion failed: false', $DIR/uninhabited.rs:87:9 | = note: this error originates in the macro `assert` (in Nightly builds, run with -Z macro-backtrace for more info) @@ -36,11 +44,33 @@ LL | | } LL | | }> | |__________^ required by this bound in `is_maybe_transmutable` -error[E0277]: `()` cannot be safely transmuted into `yawning_void::Void` +error[E0277]: `()` cannot be safely transmuted into `yawning_void_struct::Void` --> $DIR/uninhabited.rs:49:41 | LL | assert::is_maybe_transmutable::<(), Void>(); - | ^^^^ `yawning_void::Void` is uninhabited + | ^^^^ `yawning_void_struct::Void` is uninhabited + | +note: required by a bound in `is_maybe_transmutable` + --> $DIR/uninhabited.rs:10:14 + | +LL | pub fn is_maybe_transmutable<Src, Dst>() + | --------------------- required by a bound in this function +LL | where +LL | Dst: BikeshedIntrinsicFrom<Src, { + | ______________^ +LL | | Assume { +LL | | alignment: true, +LL | | lifetimes: true, +... | +LL | | } +LL | | }> + | |__________^ required by this bound in `is_maybe_transmutable` + +error[E0277]: `()` cannot be safely transmuted into `yawning_void_enum::Void` + --> $DIR/uninhabited.rs:71:41 + | +LL | assert::is_maybe_transmutable::<(), Void>(); + | ^^^^ `yawning_void_enum::Void` is uninhabited | note: required by a bound in `is_maybe_transmutable` --> $DIR/uninhabited.rs:10:14 @@ -59,7 +89,7 @@ LL | | }> | |__________^ required by this bound in `is_maybe_transmutable` error[E0277]: `u128` cannot be safely transmuted into `DistantVoid` - --> $DIR/uninhabited.rs:70:43 + --> $DIR/uninhabited.rs:92:43 | LL | assert::is_maybe_transmutable::<u128, DistantVoid>(); | ^^^^^^^^^^^ at least one value of `u128` isn't a bit-valid value of `DistantVoid` @@ -80,7 +110,7 @@ LL | | } LL | | }> | |__________^ required by this bound in `is_maybe_transmutable` -error: aborting due to 5 previous errors +error: aborting due to 7 previous errors Some errors have detailed explanations: E0080, E0277. For more information about an error, try `rustc --explain E0080`. diff --git a/tests/ui/type-alias-impl-trait/different_args_considered_equal.rs b/tests/ui/type-alias-impl-trait/different_args_considered_equal.rs new file mode 100644 index 00000000000..8ce471e3956 --- /dev/null +++ b/tests/ui/type-alias-impl-trait/different_args_considered_equal.rs @@ -0,0 +1,14 @@ +#![feature(type_alias_impl_trait)] + +pub type Opaque<'a> = impl Sized; + +fn get_one<'a>(a: *mut &'a str) -> Opaque<'a> { + a +} + +fn get_iter<'a>() -> impl IntoIterator<Item = Opaque<'a>> { + //~^ ERROR: item does not constrain + None::<Opaque<'static>> +} + +fn main() {} diff --git a/tests/ui/type-alias-impl-trait/different_args_considered_equal.stderr b/tests/ui/type-alias-impl-trait/different_args_considered_equal.stderr new file mode 100644 index 00000000000..f27f2234525 --- /dev/null +++ b/tests/ui/type-alias-impl-trait/different_args_considered_equal.stderr @@ -0,0 +1,15 @@ +error: item does not constrain `Opaque::{opaque#0}`, but has it in its signature + --> $DIR/different_args_considered_equal.rs:9:4 + | +LL | fn get_iter<'a>() -> impl IntoIterator<Item = Opaque<'a>> { + | ^^^^^^^^ + | + = note: consider moving the opaque type's declaration and defining uses into a separate module +note: this opaque type is in the signature + --> $DIR/different_args_considered_equal.rs:3:23 + | +LL | pub type Opaque<'a> = impl Sized; + | ^^^^^^^^^^ + +error: aborting due to 1 previous error + diff --git a/tests/ui/type-alias-impl-trait/different_args_considered_equal2.rs b/tests/ui/type-alias-impl-trait/different_args_considered_equal2.rs new file mode 100644 index 00000000000..43dfea97e6d --- /dev/null +++ b/tests/ui/type-alias-impl-trait/different_args_considered_equal2.rs @@ -0,0 +1,14 @@ +#![feature(type_alias_impl_trait)] + +pub type Opaque<'a> = impl Sized; + +fn get_one<'a>(a: *mut &'a str) -> impl IntoIterator<Item = Opaque<'a>> { + if a.is_null() { + Some(a) + } else { + None::<Opaque<'static>> + //~^ ERROR hidden type for `Opaque<'static>` captures lifetime that does not appear in bounds + } +} + +fn main() {} diff --git a/tests/ui/type-alias-impl-trait/different_args_considered_equal2.stderr b/tests/ui/type-alias-impl-trait/different_args_considered_equal2.stderr new file mode 100644 index 00000000000..1104c2c498a --- /dev/null +++ b/tests/ui/type-alias-impl-trait/different_args_considered_equal2.stderr @@ -0,0 +1,20 @@ +error[E0700]: hidden type for `Opaque<'static>` captures lifetime that does not appear in bounds + --> $DIR/different_args_considered_equal2.rs:9:9 + | +LL | pub type Opaque<'a> = impl Sized; + | ---------- opaque type defined here +LL | +LL | fn get_one<'a>(a: *mut &'a str) -> impl IntoIterator<Item = Opaque<'a>> { + | -- hidden type `*mut &'a str` captures the lifetime `'a` as defined here +... +LL | None::<Opaque<'static>> + | ^^^^^^^^^^^^^^^^^^^^^^^ + | +help: to declare that `impl IntoIterator<Item = Opaque<'a>>` captures `'a`, you can add an explicit `'a` lifetime bound + | +LL | fn get_one<'a>(a: *mut &'a str) -> impl IntoIterator<Item = Opaque<'a>> + 'a { + | ++++ + +error: aborting due to 1 previous error + +For more information about this error, try `rustc --explain E0700`. diff --git a/tests/ui/type-alias-impl-trait/different_args_considered_equal3.rs b/tests/ui/type-alias-impl-trait/different_args_considered_equal3.rs new file mode 100644 index 00000000000..ea69175ba31 --- /dev/null +++ b/tests/ui/type-alias-impl-trait/different_args_considered_equal3.rs @@ -0,0 +1,22 @@ +//! Test that we don't allow coercing an opaque type with a non-static +//! lifetime to one with a static lifetime. While `get_iter` looks like +//! it would be doing the opposite, the way we're handling projections +//! makes `Opaque<'a>` the hidden type of `Opaque<'static>`. + +#![feature(type_alias_impl_trait)] + +mod defining_scope { + pub type Opaque<'a> = impl Sized; + + fn get_one<'a>(a: *mut &'a str) -> Opaque<'a> { + a + } +} +use defining_scope::Opaque; + +fn get_iter<'a>() -> impl IntoIterator<Item = Opaque<'a>> { + None::<Opaque<'static>> + //~^ ERROR lifetime may not live long enough +} + +fn main() {} diff --git a/tests/ui/type-alias-impl-trait/different_args_considered_equal3.stderr b/tests/ui/type-alias-impl-trait/different_args_considered_equal3.stderr new file mode 100644 index 00000000000..d8f70e3d778 --- /dev/null +++ b/tests/ui/type-alias-impl-trait/different_args_considered_equal3.stderr @@ -0,0 +1,10 @@ +error: lifetime may not live long enough + --> $DIR/different_args_considered_equal3.rs:18:5 + | +LL | fn get_iter<'a>() -> impl IntoIterator<Item = Opaque<'a>> { + | -- lifetime `'a` defined here +LL | None::<Opaque<'static>> + | ^^^^^^^^^^^^^^^^^^^^^^^ returning this value requires that `'a` must outlive `'static` + +error: aborting due to 1 previous error + diff --git a/tests/ui/type-alias-impl-trait/lazy_subtyping_of_opaques.rs b/tests/ui/type-alias-impl-trait/lazy_subtyping_of_opaques.rs index 72a90287e37..1bc352041a5 100644 --- a/tests/ui/type-alias-impl-trait/lazy_subtyping_of_opaques.rs +++ b/tests/ui/type-alias-impl-trait/lazy_subtyping_of_opaques.rs @@ -7,9 +7,10 @@ type Tait = impl FnOnce() -> (); fn reify_as_tait() -> Thunk<Tait> { + //~^ ERROR: expected a `FnOnce()` closure, found `()` Thunk::new(|cont| cont) //~^ ERROR: mismatched types - //~| ERROR: mismatched types + //~| ERROR: expected a `FnOnce()` closure, found `()` } struct Thunk<F>(F); diff --git a/tests/ui/type-alias-impl-trait/lazy_subtyping_of_opaques.stderr b/tests/ui/type-alias-impl-trait/lazy_subtyping_of_opaques.stderr index 5a35dc27446..7bc2fa1b09e 100644 --- a/tests/ui/type-alias-impl-trait/lazy_subtyping_of_opaques.stderr +++ b/tests/ui/type-alias-impl-trait/lazy_subtyping_of_opaques.stderr @@ -1,26 +1,31 @@ -error[E0308]: mismatched types - --> $DIR/lazy_subtyping_of_opaques.rs:10:23 +error[E0277]: expected a `FnOnce()` closure, found `()` + --> $DIR/lazy_subtyping_of_opaques.rs:11:23 | -LL | type Tait = impl FnOnce() -> (); - | ------------------- the found opaque type -... LL | Thunk::new(|cont| cont) - | ^^^^ expected `()`, found opaque type + | ^^^^ expected an `FnOnce()` closure, found `()` | - = note: expected unit type `()` - found opaque type `Tait` + = help: the trait `FnOnce()` is not implemented for `()` + = note: wrap the `()` in a closure with no arguments: `|| { /* code */ }` -error[E0308]: mismatched types - --> $DIR/lazy_subtyping_of_opaques.rs:10:5 +error[E0277]: expected a `FnOnce()` closure, found `()` + --> $DIR/lazy_subtyping_of_opaques.rs:9:23 | LL | fn reify_as_tait() -> Thunk<Tait> { - | ----------- expected `Thunk<_>` because of return type + | ^^^^^^^^^^^ expected an `FnOnce()` closure, found `()` + | + = help: the trait `FnOnce()` is not implemented for `()` + = note: wrap the `()` in a closure with no arguments: `|| { /* code */ }` + +error[E0308]: mismatched types + --> $DIR/lazy_subtyping_of_opaques.rs:11:5 + | LL | Thunk::new(|cont| cont) | ^^^^^^^^^^^^^^^^^^^^^^^ expected `Thunk<_>`, found `()` | = note: expected struct `Thunk<_>` found unit type `()` -error: aborting due to 2 previous errors +error: aborting due to 3 previous errors -For more information about this error, try `rustc --explain E0308`. +Some errors have detailed explanations: E0277, E0308. +For more information about an error, try `rustc --explain E0277`. |
